Loading sound/pci/hda/hda_codec.c +287 −95 Original line number Diff line number Diff line Loading @@ -344,7 +344,7 @@ static void process_unsol_events(struct work_struct *work) /* * initialize unsolicited queue */ static int __devinit init_unsol_queue(struct hda_bus *bus) static int init_unsol_queue(struct hda_bus *bus) { struct hda_bus_unsolicited *unsol; Loading Loading @@ -393,6 +393,20 @@ static int snd_hda_bus_dev_free(struct snd_device *device) return snd_hda_bus_free(bus); } #ifdef CONFIG_SND_HDA_HWDEP static int snd_hda_bus_dev_register(struct snd_device *device) { struct hda_bus *bus = device->device_data; struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { snd_hda_hwdep_add_sysfs(codec); } return 0; } #else #define snd_hda_bus_dev_register NULL #endif /** * snd_hda_bus_new - create a HDA bus * @card: the card entry Loading @@ -408,6 +422,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, struct hda_bus *bus; int err; static struct snd_device_ops dev_ops = { .dev_register = snd_hda_bus_dev_register, .dev_free = snd_hda_bus_dev_free, }; Loading Loading @@ -446,7 +461,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, #ifdef CONFIG_SND_HDA_GENERIC #define is_generic_config(codec) \ (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) (codec->modelname && !strcmp(codec->modelname, "generic")) #else #define is_generic_config(codec) 0 #endif Loading @@ -454,7 +469,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, /* * find a matching codec preset */ static const struct hda_codec_preset __devinit * static const struct hda_codec_preset * find_codec_preset(struct hda_codec *codec) { const struct hda_codec_preset **tbl, *preset; Loading @@ -481,15 +496,14 @@ find_codec_preset(struct hda_codec *codec) } /* * snd_hda_get_codec_name - store the codec name * get_codec_name - store the codec name */ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen) static int get_codec_name(struct hda_codec *codec) { const struct hda_vendor_id *c; const char *vendor = NULL; u16 vendor_id = codec->vendor_id >> 16; char tmp[16]; char tmp[16], name[32]; for (c = hda_vendor_ids; c->id; c++) { if (c->id == vendor_id) { Loading @@ -502,10 +516,15 @@ void snd_hda_get_codec_name(struct hda_codec *codec, vendor = tmp; } if (codec->preset && codec->preset->name) snprintf(name, namelen, "%s %s", vendor, codec->preset->name); snprintf(name, sizeof(name), "%s %s", vendor, codec->preset->name); else snprintf(name, namelen, "%s ID %x", vendor, snprintf(name, sizeof(name), "%s ID %x", vendor, codec->vendor_id & 0xffff); codec->name = kstrdup(name, GFP_KERNEL); if (!codec->name) return -ENOMEM; return 0; } /* Loading Loading @@ -570,11 +589,14 @@ static void snd_hda_codec_free(struct hda_codec *codec) flush_scheduled_work(); #endif list_del(&codec->list); snd_array_free(&codec->mixers); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); kfree(codec->name); kfree(codec->modelname); kfree(codec->wcaps); kfree(codec); } Loading Loading @@ -616,6 +638,14 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, mutex_init(&codec->spdif_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); if (!codec->modelname) { snd_hda_codec_free(codec); return -ENODEV; } } #ifdef CONFIG_SND_HDA_POWER_SAVE INIT_DELAYED_WORK(&codec->power_work, hda_power_work); Loading Loading @@ -661,12 +691,41 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_SUBSYSTEM_ID, 0); } if (bus->modelname) codec->modelname = kstrdup(bus->modelname, GFP_KERNEL); err = snd_hda_codec_configure(codec); if (err < 0) { snd_hda_codec_free(codec); return err; } snd_hda_codec_proc_new(codec); snd_hda_create_hwdep(codec); sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); snd_component_add(codec->bus->card, component); if (codecp) *codecp = codec; return 0; } int snd_hda_codec_configure(struct hda_codec *codec) { int err; codec->preset = find_codec_preset(codec); if (!codec->name) { err = get_codec_name(codec); if (err < 0) return err; } /* audio codec should override the mixer name */ if (codec->afg || !*bus->card->mixername) snd_hda_get_codec_name(codec, bus->card->mixername, sizeof(bus->card->mixername)); if (codec->afg || !*codec->bus->card->mixername) strlcpy(codec->bus->card->mixername, codec->name, sizeof(codec->bus->card->mixername)); if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); Loading @@ -683,27 +742,11 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, printk(KERN_ERR "hda-codec: No codec parser is available\n"); patched: if (err < 0) { snd_hda_codec_free(codec); if (!err && codec->patch_ops.unsol_event) err = init_unsol_queue(codec->bus); return err; } if (codec->patch_ops.unsol_event) init_unsol_queue(bus); snd_hda_codec_proc_new(codec); #ifdef CONFIG_SND_HDA_HWDEP snd_hda_create_hwdep(codec); #endif sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); snd_component_add(codec->bus->card, component); if (codecp) *codecp = codec; return 0; } /** * snd_hda_codec_setup_stream - set up the codec for streaming * @codec: the CODEC to set up Loading Loading @@ -756,12 +799,12 @@ static void __devinit init_hda_cache(struct hda_cache_rec *cache, { memset(cache, 0, sizeof(*cache)); memset(cache->hash, 0xff, sizeof(cache->hash)); cache->record_size = record_size; snd_array_init(&cache->buf, record_size, 64); } static void free_hda_cache(struct hda_cache_rec *cache) { kfree(cache->buffer); snd_array_free(&cache->buf); } /* query the hash. allocate an entry if not found. */ Loading @@ -770,38 +813,18 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, { u16 idx = key % (u16)ARRAY_SIZE(cache->hash); u16 cur = cache->hash[idx]; struct hda_cache_head *info_head = cache->buf.list; struct hda_cache_head *info; while (cur != 0xffff) { info = (struct hda_cache_head *)(cache->buffer + cur * cache->record_size); info = &info_head[cur]; if (info->key == key) return info; cur = info->next; } /* add a new hash entry */ if (cache->num_entries >= cache->size) { /* reallocate the array */ unsigned int new_size = cache->size + 64; void *new_buffer; new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL); if (!new_buffer) { snd_printk(KERN_ERR "hda_codec: " "can't malloc amp_info\n"); return NULL; } if (cache->buffer) { memcpy(new_buffer, cache->buffer, cache->size * cache->record_size); kfree(cache->buffer); } cache->size = new_size; cache->buffer = new_buffer; } cur = cache->num_entries++; info = (struct hda_cache_head *)(cache->buffer + cur * cache->record_size); info = snd_array_new(&cache->buf); info->key = key; info->val = 0; info->next = cache->hash[idx]; Loading Loading @@ -942,10 +965,10 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, /* resume the all amp commands from the cache */ void snd_hda_codec_resume_amp(struct hda_codec *codec) { struct hda_amp_info *buffer = codec->amp_cache.buffer; struct hda_amp_info *buffer = codec->amp_cache.buf.list; int i; for (i = 0; i < codec->amp_cache.size; i++, buffer++) { for (i = 0; i < codec->amp_cache.buf.used; i++, buffer++) { u32 key = buffer->head.key; hda_nid_t nid; unsigned int idx, dir, ch; Loading Loading @@ -1097,6 +1120,57 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, return _snd_hda_find_mixer_ctl(codec, name, 0); } /* Add a control element and assign to the codec */ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) { int err; struct snd_kcontrol **knewp; err = snd_ctl_add(codec->bus->card, kctl); if (err < 0) return err; knewp = snd_array_new(&codec->mixers); if (!knewp) return -ENOMEM; *knewp = kctl; return 0; } /* Clear all controls assigned to the given codec */ void snd_hda_ctls_clear(struct hda_codec *codec) { int i; struct snd_kcontrol **kctls = codec->mixers.list; for (i = 0; i < codec->mixers.used; i++) snd_ctl_remove(codec->bus->card, kctls[i]); snd_array_free(&codec->mixers); } void snd_hda_codec_reset(struct hda_codec *codec) { int i; #ifdef CONFIG_SND_HDA_POWER_SAVE cancel_delayed_work(&codec->power_work); flush_scheduled_work(); #endif snd_hda_ctls_clear(codec); /* relase PCMs */ for (i = 0; i < codec->num_pcms; i++) { if (codec->pcm_info[i].pcm) snd_device_free(codec->bus->card, codec->pcm_info[i].pcm); } if (codec->patch_ops.free) codec->patch_ops.free(codec); codec->spec = NULL; free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); codec->num_pcms = 0; codec->pcm_info = NULL; codec->preset = NULL; } /* create a virtual master control and add slaves */ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char **slaves) Loading @@ -1114,7 +1188,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, kctl = snd_ctl_make_virtual_master(name, tlv); if (!kctl) return -ENOMEM; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) return err; Loading Loading @@ -1578,7 +1652,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) kctl = snd_ctl_new1(dig_mix, codec); kctl->id.index = idx; kctl->private_value = nid; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) return err; } Loading Loading @@ -1622,7 +1696,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec, if (!mout->dig_out_nid) return 0; /* ATTENTION: here mout is passed as private_data, instead of codec */ return snd_ctl_add(codec->bus->card, return snd_hda_ctl_add(codec, snd_ctl_new1(&spdif_share_sw, mout)); } Loading Loading @@ -1724,7 +1798,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { kctl = snd_ctl_new1(dig_mix, codec); kctl->private_value = nid; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) return err; } Loading Loading @@ -1779,10 +1853,10 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, /* resume the all commands from the cache */ void snd_hda_codec_resume_cache(struct hda_codec *codec) { struct hda_cache_head *buffer = codec->cmd_cache.buffer; struct hda_cache_head *buffer = codec->cmd_cache.buf.list; int i; for (i = 0; i < codec->cmd_cache.size; i++, buffer++) { for (i = 0; i < codec->cmd_cache.buf.used; i++, buffer++) { u32 key = buffer->key; if (!key) continue; Loading Loading @@ -1867,6 +1941,17 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, } } #ifdef CONFIG_SND_HDA_HWDEP /* execute additional init verbs */ static void hda_exec_init_verbs(struct hda_codec *codec) { if (codec->init_verbs.list) snd_hda_sequence_write(codec, codec->init_verbs.list); } #else static inline void hda_exec_init_verbs(struct hda_codec *codec) {} #endif #ifdef SND_HDA_NEEDS_RESUME /* * call suspend and power-down; used both from PM and power-save Loading @@ -1893,6 +1978,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); hda_exec_init_verbs(codec); if (codec->patch_ops.resume) codec->patch_ops.resume(codec); else { Loading @@ -1918,6 +2004,15 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { int err = snd_hda_codec_build_controls(codec); if (err < 0) return err; } return 0; } int snd_hda_codec_build_controls(struct hda_codec *codec) { int err = 0; /* fake as if already powered-on */ hda_keep_power_on(codec); Loading @@ -1925,6 +2020,7 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); hda_exec_init_verbs(codec); /* continue to initialize... */ if (codec->patch_ops.init) err = codec->patch_ops.init(codec); Loading @@ -1933,8 +2029,6 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) snd_hda_power_down(codec); if (err < 0) return err; } return 0; } Loading Loading @@ -2235,7 +2329,7 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo, return 0; } static int __devinit set_pcm_default_values(struct hda_codec *codec, static int set_pcm_default_values(struct hda_codec *codec, struct hda_pcm_stream *info) { /* query support PCM information from the given NID */ Loading @@ -2262,6 +2356,28 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec, return 0; } /* * attach a new PCM stream */ static int __devinit snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) { struct hda_pcm_stream *info; int stream, err; if (!pcm->name) return -EINVAL; for (stream = 0; stream < 2; stream++) { info = &pcm->stream[stream]; if (info->substreams) { err = set_pcm_default_values(codec, info); if (err < 0) return err; } } return codec->bus->ops.attach_pcm(codec, pcm); } /** * snd_hda_build_pcms - build PCM information * @bus: the BUS Loading @@ -2288,25 +2404,67 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec, * * This function returns 0 if successfull, or a negative error code. */ int __devinit snd_hda_build_pcms(struct hda_bus *bus) int snd_hda_build_pcms(struct hda_bus *bus) { static const char *dev_name[HDA_PCM_NTYPES] = { "Audio", "SPDIF", "HDMI", "Modem" }; /* starting device index for each PCM type */ static int dev_idx[HDA_PCM_NTYPES] = { [HDA_PCM_TYPE_AUDIO] = 0, [HDA_PCM_TYPE_SPDIF] = 1, [HDA_PCM_TYPE_HDMI] = 3, [HDA_PCM_TYPE_MODEM] = 6 }; /* normal audio device indices; not linear to keep compatibility */ static int audio_idx[4] = { 0, 2, 4, 5 }; struct hda_codec *codec; int num_devs[HDA_PCM_NTYPES]; memset(num_devs, 0, sizeof(num_devs)); list_for_each_entry(codec, &bus->codec_list, list) { unsigned int pcm, s; unsigned int pcm; int err; if (!codec->num_pcms) { if (!codec->patch_ops.build_pcms) continue; err = codec->patch_ops.build_pcms(codec); if (err < 0) return err; } for (pcm = 0; pcm < codec->num_pcms; pcm++) { for (s = 0; s < 2; s++) { struct hda_pcm_stream *info; info = &codec->pcm_info[pcm].stream[s]; if (!info->substreams) struct hda_pcm *cpcm = &codec->pcm_info[pcm]; int type = cpcm->pcm_type; int dev; switch (type) { case HDA_PCM_TYPE_AUDIO: if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { snd_printk(KERN_WARNING "Too many audio devices\n"); continue; err = set_pcm_default_values(codec, info); } dev = audio_idx[num_devs[type]]; break; case HDA_PCM_TYPE_SPDIF: case HDA_PCM_TYPE_HDMI: case HDA_PCM_TYPE_MODEM: if (num_devs[type]) { snd_printk(KERN_WARNING "%s already defined\n", dev_name[type]); continue; } dev = dev_idx[type]; break; default: snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); continue; } num_devs[type]++; if (!cpcm->pcm) { cpcm->device = dev; err = snd_hda_attach_pcm(codec, cpcm); if (err < 0) return err; } Loading @@ -2332,11 +2490,11 @@ int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, const char **models, const struct snd_pci_quirk *tbl) { if (codec->bus->modelname && models) { if (codec->modelname && models) { int i; for (i = 0; i < num_configs; i++) { if (models[i] && !strcmp(codec->bus->modelname, models[i])) { !strcmp(codec->modelname, models[i])) { snd_printd(KERN_INFO "hda_codec: model '%s' is " "selected\n", models[i]); return i; Loading Loading @@ -2389,7 +2547,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) kctl = snd_ctl_new1(knew, codec); if (!kctl) return -ENOMEM; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) { if (!codec->addr) return err; Loading @@ -2397,7 +2555,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) if (!kctl) return -ENOMEM; kctl->id.device = codec->addr; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) return err; } Loading Loading @@ -3138,3 +3296,37 @@ int snd_hda_codecs_inuse(struct hda_bus *bus) } #endif #endif /* * generic arrays */ /* get a new element from the given array * if it exceeds the pre-allocated array size, re-allocate the array */ void *snd_array_new(struct snd_array *array) { if (array->used >= array->alloced) { int num = array->alloced + array->alloc_align; void *nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL); if (!nlist) return NULL; if (array->list) { memcpy(nlist, array->list, array->elem_size * array->alloced); kfree(array->list); } array->list = nlist; array->alloced = num; } return array->list + (array->used++ * array->elem_size); } /* free the given array elements */ void snd_array_free(struct snd_array *array) { kfree(array->list); array->used = 0; array->alloced = 0; array->list = NULL; } sound/pci/hda/hda_codec.h +34 −5 Original line number Diff line number Diff line Loading @@ -519,6 +519,26 @@ enum { /* max. codec address */ #define HDA_MAX_CODEC_ADDRESS 0x0f /* * generic arrays */ struct snd_array { unsigned int used; unsigned int alloced; unsigned int elem_size; unsigned int alloc_align; void *list; }; void *snd_array_new(struct snd_array *array); void snd_array_free(struct snd_array *array); static inline void snd_array_init(struct snd_array *array, unsigned int size, unsigned int align) { array->elem_size = size; array->alloc_align = align; } /* * Structures */ Loading @@ -542,6 +562,8 @@ struct hda_bus_ops { unsigned int (*get_response)(struct hda_codec *codec); /* free the private data */ void (*private_free)(struct hda_bus *); /* attach a PCM stream */ int (*attach_pcm)(struct hda_codec *codec, struct hda_pcm *pcm); #ifdef CONFIG_SND_HDA_POWER_SAVE /* notify power-up/down from codec to controller */ void (*pm_notify)(struct hda_codec *codec); Loading Loading @@ -635,10 +657,7 @@ struct hda_amp_info { struct hda_cache_rec { u16 hash[64]; /* hash table for index */ unsigned int num_entries; /* number of assigned entries */ unsigned int size; /* allocated size */ unsigned int record_size; /* record size (including header) */ void *buffer; /* hash table entries */ struct snd_array buf; /* record entries */ }; /* PCM callbacks */ Loading Loading @@ -680,7 +699,8 @@ struct hda_pcm { char *name; struct hda_pcm_stream stream[2]; unsigned int pcm_type; /* HDA_PCM_TYPE_XXX */ int device; /* assigned device number */ int device; /* device number to assign */ struct snd_pcm *pcm; /* assigned PCM instance */ }; /* codec information */ Loading @@ -699,6 +719,8 @@ struct hda_codec { /* detected preset */ const struct hda_codec_preset *preset; const char *name; /* codec name */ const char *modelname; /* model name for preset */ /* set by patch */ struct hda_codec_ops patch_ops; Loading @@ -718,6 +740,8 @@ struct hda_codec { hda_nid_t start_nid; u32 *wcaps; struct snd_array mixers; /* list of assigned mixer elements */ struct hda_cache_rec amp_cache; /* cache for amp access */ struct hda_cache_rec cmd_cache; /* cache for other commands */ Loading @@ -727,7 +751,11 @@ struct hda_codec { unsigned int spdif_in_enable; /* SPDIF input enable? */ hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ #ifdef CONFIG_SND_HDA_HWDEP struct snd_hwdep *hwdep; /* assigned hwdep device */ struct snd_array init_verbs; /* additional init verbs */ struct snd_array hints; /* additional hints */ #endif /* misc flags */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each Loading Loading @@ -799,6 +827,7 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec); * Mixer */ int snd_hda_build_controls(struct hda_bus *bus); int snd_hda_codec_build_controls(struct hda_codec *codec); /* * PCM Loading sound/pci/hda/hda_generic.c +12 −8 Original line number Diff line number Diff line Loading @@ -723,7 +723,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, if (is_loopback) add_input_loopback(codec, node->nid, HDA_INPUT, index); snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); if (err < 0) return err; created = 1; } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && Loading @@ -732,7 +733,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, if (is_loopback) add_input_loopback(codec, node->nid, HDA_OUTPUT, 0); snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); if (err < 0) return err; created = 1; } Loading @@ -745,14 +747,16 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) { knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT); snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); if (err < 0) return err; created = 1; } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) { knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT); snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); if (err < 0) return err; created = 1; } Loading Loading @@ -849,8 +853,8 @@ static int build_input_controls(struct hda_codec *codec) } /* create input MUX if multiple sources are available */ if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&cap_sel, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec)); if (err < 0) return err; /* no volume control? */ Loading @@ -867,8 +871,8 @@ static int build_input_controls(struct hda_codec *codec) HDA_CODEC_VOLUME(name, adc_node->nid, spec->input_mux.items[i].index, HDA_INPUT); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); if (err < 0) return err; } Loading sound/pci/hda/hda_hwdep.c +228 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes sound/pci/hda/hda_intel.c +35 −86 Original line number Diff line number Diff line Loading @@ -1180,6 +1180,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) return 0; } static int azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm); /* * Codec initialization Loading Loading @@ -1212,6 +1213,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, bus_temp.pci = chip->pci; bus_temp.ops.command = azx_send_cmd; bus_temp.ops.get_response = azx_get_response; bus_temp.ops.attach_pcm = azx_attach_pcm_stream; #ifdef CONFIG_SND_HDA_POWER_SAVE bus_temp.ops.pm_notify = azx_power_notify; #endif Loading Loading @@ -1718,111 +1720,58 @@ static struct snd_pcm_ops azx_pcm_ops = { static void azx_pcm_free(struct snd_pcm *pcm) { kfree(pcm->private_data); struct azx_pcm *apcm = pcm->private_data; if (apcm) { apcm->chip->pcm[pcm->device] = NULL; kfree(apcm); } } static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, struct hda_pcm *cpcm) static int azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm) { int err; struct azx *chip = codec->bus->private_data; struct snd_pcm *pcm; struct azx_pcm *apcm; int pcm_dev = cpcm->device; int s, err; /* if no substreams are defined for both playback and capture, * it's just a placeholder. ignore it. */ if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) return 0; if (snd_BUG_ON(!cpcm->name)) if (pcm_dev >= AZX_MAX_PCMS) { snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n", pcm_dev); return -EINVAL; err = snd_pcm_new(chip->card, cpcm->name, cpcm->device, cpcm->stream[0].substreams, cpcm->stream[1].substreams, } if (chip->pcm[pcm_dev]) { snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev); return -EBUSY; } err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams, cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams, &pcm); if (err < 0) return err; strcpy(pcm->name, cpcm->name); apcm = kmalloc(sizeof(*apcm), GFP_KERNEL); apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); if (apcm == NULL) return -ENOMEM; apcm->chip = chip; apcm->codec = codec; apcm->hinfo[0] = &cpcm->stream[0]; apcm->hinfo[1] = &cpcm->stream[1]; pcm->private_data = apcm; pcm->private_free = azx_pcm_free; if (cpcm->stream[0].substreams) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops); if (cpcm->stream[1].substreams) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM) pcm->dev_class = SNDRV_PCM_CLASS_MODEM; chip->pcm[pcm_dev] = pcm; cpcm->pcm = pcm; for (s = 0; s < 2; s++) { apcm->hinfo[s] = &cpcm->stream[s]; if (cpcm->stream[s].substreams) snd_pcm_set_ops(pcm, s, &azx_pcm_ops); } /* buffer pre-allocation */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 1024 * 64, 32 * 1024 * 1024); chip->pcm[cpcm->device] = pcm; return 0; } static int __devinit azx_pcm_create(struct azx *chip) { static const char *dev_name[HDA_PCM_NTYPES] = { "Audio", "SPDIF", "HDMI", "Modem" }; /* starting device index for each PCM type */ static int dev_idx[HDA_PCM_NTYPES] = { [HDA_PCM_TYPE_AUDIO] = 0, [HDA_PCM_TYPE_SPDIF] = 1, [HDA_PCM_TYPE_HDMI] = 3, [HDA_PCM_TYPE_MODEM] = 6 }; /* normal audio device indices; not linear to keep compatibility */ static int audio_idx[4] = { 0, 2, 4, 5 }; struct hda_codec *codec; int c, err; int num_devs[HDA_PCM_NTYPES]; err = snd_hda_build_pcms(chip->bus); if (err < 0) return err; /* create audio PCMs */ memset(num_devs, 0, sizeof(num_devs)); list_for_each_entry(codec, &chip->bus->codec_list, list) { for (c = 0; c < codec->num_pcms; c++) { struct hda_pcm *cpcm = &codec->pcm_info[c]; int type = cpcm->pcm_type; switch (type) { case HDA_PCM_TYPE_AUDIO: if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { snd_printk(KERN_WARNING "Too many audio devices\n"); continue; } cpcm->device = audio_idx[num_devs[type]]; break; case HDA_PCM_TYPE_SPDIF: case HDA_PCM_TYPE_HDMI: case HDA_PCM_TYPE_MODEM: if (num_devs[type]) { snd_printk(KERN_WARNING "%s already defined\n", dev_name[type]); continue; } cpcm->device = dev_idx[type]; break; default: snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); continue; } num_devs[type]++; err = create_codec_pcm(chip, codec, cpcm); if (err < 0) return err; } } return 0; } Loading Loading @@ -2324,7 +2273,7 @@ static int __devinit azx_probe(struct pci_dev *pci, } /* create PCM streams */ err = azx_pcm_create(chip); err = snd_hda_build_pcms(chip->bus); if (err < 0) { snd_card_free(card); return err; Loading Loading
sound/pci/hda/hda_codec.c +287 −95 Original line number Diff line number Diff line Loading @@ -344,7 +344,7 @@ static void process_unsol_events(struct work_struct *work) /* * initialize unsolicited queue */ static int __devinit init_unsol_queue(struct hda_bus *bus) static int init_unsol_queue(struct hda_bus *bus) { struct hda_bus_unsolicited *unsol; Loading Loading @@ -393,6 +393,20 @@ static int snd_hda_bus_dev_free(struct snd_device *device) return snd_hda_bus_free(bus); } #ifdef CONFIG_SND_HDA_HWDEP static int snd_hda_bus_dev_register(struct snd_device *device) { struct hda_bus *bus = device->device_data; struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { snd_hda_hwdep_add_sysfs(codec); } return 0; } #else #define snd_hda_bus_dev_register NULL #endif /** * snd_hda_bus_new - create a HDA bus * @card: the card entry Loading @@ -408,6 +422,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, struct hda_bus *bus; int err; static struct snd_device_ops dev_ops = { .dev_register = snd_hda_bus_dev_register, .dev_free = snd_hda_bus_dev_free, }; Loading Loading @@ -446,7 +461,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, #ifdef CONFIG_SND_HDA_GENERIC #define is_generic_config(codec) \ (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) (codec->modelname && !strcmp(codec->modelname, "generic")) #else #define is_generic_config(codec) 0 #endif Loading @@ -454,7 +469,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, /* * find a matching codec preset */ static const struct hda_codec_preset __devinit * static const struct hda_codec_preset * find_codec_preset(struct hda_codec *codec) { const struct hda_codec_preset **tbl, *preset; Loading @@ -481,15 +496,14 @@ find_codec_preset(struct hda_codec *codec) } /* * snd_hda_get_codec_name - store the codec name * get_codec_name - store the codec name */ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen) static int get_codec_name(struct hda_codec *codec) { const struct hda_vendor_id *c; const char *vendor = NULL; u16 vendor_id = codec->vendor_id >> 16; char tmp[16]; char tmp[16], name[32]; for (c = hda_vendor_ids; c->id; c++) { if (c->id == vendor_id) { Loading @@ -502,10 +516,15 @@ void snd_hda_get_codec_name(struct hda_codec *codec, vendor = tmp; } if (codec->preset && codec->preset->name) snprintf(name, namelen, "%s %s", vendor, codec->preset->name); snprintf(name, sizeof(name), "%s %s", vendor, codec->preset->name); else snprintf(name, namelen, "%s ID %x", vendor, snprintf(name, sizeof(name), "%s ID %x", vendor, codec->vendor_id & 0xffff); codec->name = kstrdup(name, GFP_KERNEL); if (!codec->name) return -ENOMEM; return 0; } /* Loading Loading @@ -570,11 +589,14 @@ static void snd_hda_codec_free(struct hda_codec *codec) flush_scheduled_work(); #endif list_del(&codec->list); snd_array_free(&codec->mixers); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); kfree(codec->name); kfree(codec->modelname); kfree(codec->wcaps); kfree(codec); } Loading Loading @@ -616,6 +638,14 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, mutex_init(&codec->spdif_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); if (!codec->modelname) { snd_hda_codec_free(codec); return -ENODEV; } } #ifdef CONFIG_SND_HDA_POWER_SAVE INIT_DELAYED_WORK(&codec->power_work, hda_power_work); Loading Loading @@ -661,12 +691,41 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_SUBSYSTEM_ID, 0); } if (bus->modelname) codec->modelname = kstrdup(bus->modelname, GFP_KERNEL); err = snd_hda_codec_configure(codec); if (err < 0) { snd_hda_codec_free(codec); return err; } snd_hda_codec_proc_new(codec); snd_hda_create_hwdep(codec); sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); snd_component_add(codec->bus->card, component); if (codecp) *codecp = codec; return 0; } int snd_hda_codec_configure(struct hda_codec *codec) { int err; codec->preset = find_codec_preset(codec); if (!codec->name) { err = get_codec_name(codec); if (err < 0) return err; } /* audio codec should override the mixer name */ if (codec->afg || !*bus->card->mixername) snd_hda_get_codec_name(codec, bus->card->mixername, sizeof(bus->card->mixername)); if (codec->afg || !*codec->bus->card->mixername) strlcpy(codec->bus->card->mixername, codec->name, sizeof(codec->bus->card->mixername)); if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); Loading @@ -683,27 +742,11 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, printk(KERN_ERR "hda-codec: No codec parser is available\n"); patched: if (err < 0) { snd_hda_codec_free(codec); if (!err && codec->patch_ops.unsol_event) err = init_unsol_queue(codec->bus); return err; } if (codec->patch_ops.unsol_event) init_unsol_queue(bus); snd_hda_codec_proc_new(codec); #ifdef CONFIG_SND_HDA_HWDEP snd_hda_create_hwdep(codec); #endif sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); snd_component_add(codec->bus->card, component); if (codecp) *codecp = codec; return 0; } /** * snd_hda_codec_setup_stream - set up the codec for streaming * @codec: the CODEC to set up Loading Loading @@ -756,12 +799,12 @@ static void __devinit init_hda_cache(struct hda_cache_rec *cache, { memset(cache, 0, sizeof(*cache)); memset(cache->hash, 0xff, sizeof(cache->hash)); cache->record_size = record_size; snd_array_init(&cache->buf, record_size, 64); } static void free_hda_cache(struct hda_cache_rec *cache) { kfree(cache->buffer); snd_array_free(&cache->buf); } /* query the hash. allocate an entry if not found. */ Loading @@ -770,38 +813,18 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, { u16 idx = key % (u16)ARRAY_SIZE(cache->hash); u16 cur = cache->hash[idx]; struct hda_cache_head *info_head = cache->buf.list; struct hda_cache_head *info; while (cur != 0xffff) { info = (struct hda_cache_head *)(cache->buffer + cur * cache->record_size); info = &info_head[cur]; if (info->key == key) return info; cur = info->next; } /* add a new hash entry */ if (cache->num_entries >= cache->size) { /* reallocate the array */ unsigned int new_size = cache->size + 64; void *new_buffer; new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL); if (!new_buffer) { snd_printk(KERN_ERR "hda_codec: " "can't malloc amp_info\n"); return NULL; } if (cache->buffer) { memcpy(new_buffer, cache->buffer, cache->size * cache->record_size); kfree(cache->buffer); } cache->size = new_size; cache->buffer = new_buffer; } cur = cache->num_entries++; info = (struct hda_cache_head *)(cache->buffer + cur * cache->record_size); info = snd_array_new(&cache->buf); info->key = key; info->val = 0; info->next = cache->hash[idx]; Loading Loading @@ -942,10 +965,10 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, /* resume the all amp commands from the cache */ void snd_hda_codec_resume_amp(struct hda_codec *codec) { struct hda_amp_info *buffer = codec->amp_cache.buffer; struct hda_amp_info *buffer = codec->amp_cache.buf.list; int i; for (i = 0; i < codec->amp_cache.size; i++, buffer++) { for (i = 0; i < codec->amp_cache.buf.used; i++, buffer++) { u32 key = buffer->head.key; hda_nid_t nid; unsigned int idx, dir, ch; Loading Loading @@ -1097,6 +1120,57 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, return _snd_hda_find_mixer_ctl(codec, name, 0); } /* Add a control element and assign to the codec */ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) { int err; struct snd_kcontrol **knewp; err = snd_ctl_add(codec->bus->card, kctl); if (err < 0) return err; knewp = snd_array_new(&codec->mixers); if (!knewp) return -ENOMEM; *knewp = kctl; return 0; } /* Clear all controls assigned to the given codec */ void snd_hda_ctls_clear(struct hda_codec *codec) { int i; struct snd_kcontrol **kctls = codec->mixers.list; for (i = 0; i < codec->mixers.used; i++) snd_ctl_remove(codec->bus->card, kctls[i]); snd_array_free(&codec->mixers); } void snd_hda_codec_reset(struct hda_codec *codec) { int i; #ifdef CONFIG_SND_HDA_POWER_SAVE cancel_delayed_work(&codec->power_work); flush_scheduled_work(); #endif snd_hda_ctls_clear(codec); /* relase PCMs */ for (i = 0; i < codec->num_pcms; i++) { if (codec->pcm_info[i].pcm) snd_device_free(codec->bus->card, codec->pcm_info[i].pcm); } if (codec->patch_ops.free) codec->patch_ops.free(codec); codec->spec = NULL; free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); codec->num_pcms = 0; codec->pcm_info = NULL; codec->preset = NULL; } /* create a virtual master control and add slaves */ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char **slaves) Loading @@ -1114,7 +1188,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, kctl = snd_ctl_make_virtual_master(name, tlv); if (!kctl) return -ENOMEM; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) return err; Loading Loading @@ -1578,7 +1652,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) kctl = snd_ctl_new1(dig_mix, codec); kctl->id.index = idx; kctl->private_value = nid; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) return err; } Loading Loading @@ -1622,7 +1696,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec, if (!mout->dig_out_nid) return 0; /* ATTENTION: here mout is passed as private_data, instead of codec */ return snd_ctl_add(codec->bus->card, return snd_hda_ctl_add(codec, snd_ctl_new1(&spdif_share_sw, mout)); } Loading Loading @@ -1724,7 +1798,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { kctl = snd_ctl_new1(dig_mix, codec); kctl->private_value = nid; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) return err; } Loading Loading @@ -1779,10 +1853,10 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, /* resume the all commands from the cache */ void snd_hda_codec_resume_cache(struct hda_codec *codec) { struct hda_cache_head *buffer = codec->cmd_cache.buffer; struct hda_cache_head *buffer = codec->cmd_cache.buf.list; int i; for (i = 0; i < codec->cmd_cache.size; i++, buffer++) { for (i = 0; i < codec->cmd_cache.buf.used; i++, buffer++) { u32 key = buffer->key; if (!key) continue; Loading Loading @@ -1867,6 +1941,17 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, } } #ifdef CONFIG_SND_HDA_HWDEP /* execute additional init verbs */ static void hda_exec_init_verbs(struct hda_codec *codec) { if (codec->init_verbs.list) snd_hda_sequence_write(codec, codec->init_verbs.list); } #else static inline void hda_exec_init_verbs(struct hda_codec *codec) {} #endif #ifdef SND_HDA_NEEDS_RESUME /* * call suspend and power-down; used both from PM and power-save Loading @@ -1893,6 +1978,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); hda_exec_init_verbs(codec); if (codec->patch_ops.resume) codec->patch_ops.resume(codec); else { Loading @@ -1918,6 +2004,15 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { int err = snd_hda_codec_build_controls(codec); if (err < 0) return err; } return 0; } int snd_hda_codec_build_controls(struct hda_codec *codec) { int err = 0; /* fake as if already powered-on */ hda_keep_power_on(codec); Loading @@ -1925,6 +2020,7 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); hda_exec_init_verbs(codec); /* continue to initialize... */ if (codec->patch_ops.init) err = codec->patch_ops.init(codec); Loading @@ -1933,8 +2029,6 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) snd_hda_power_down(codec); if (err < 0) return err; } return 0; } Loading Loading @@ -2235,7 +2329,7 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo, return 0; } static int __devinit set_pcm_default_values(struct hda_codec *codec, static int set_pcm_default_values(struct hda_codec *codec, struct hda_pcm_stream *info) { /* query support PCM information from the given NID */ Loading @@ -2262,6 +2356,28 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec, return 0; } /* * attach a new PCM stream */ static int __devinit snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) { struct hda_pcm_stream *info; int stream, err; if (!pcm->name) return -EINVAL; for (stream = 0; stream < 2; stream++) { info = &pcm->stream[stream]; if (info->substreams) { err = set_pcm_default_values(codec, info); if (err < 0) return err; } } return codec->bus->ops.attach_pcm(codec, pcm); } /** * snd_hda_build_pcms - build PCM information * @bus: the BUS Loading @@ -2288,25 +2404,67 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec, * * This function returns 0 if successfull, or a negative error code. */ int __devinit snd_hda_build_pcms(struct hda_bus *bus) int snd_hda_build_pcms(struct hda_bus *bus) { static const char *dev_name[HDA_PCM_NTYPES] = { "Audio", "SPDIF", "HDMI", "Modem" }; /* starting device index for each PCM type */ static int dev_idx[HDA_PCM_NTYPES] = { [HDA_PCM_TYPE_AUDIO] = 0, [HDA_PCM_TYPE_SPDIF] = 1, [HDA_PCM_TYPE_HDMI] = 3, [HDA_PCM_TYPE_MODEM] = 6 }; /* normal audio device indices; not linear to keep compatibility */ static int audio_idx[4] = { 0, 2, 4, 5 }; struct hda_codec *codec; int num_devs[HDA_PCM_NTYPES]; memset(num_devs, 0, sizeof(num_devs)); list_for_each_entry(codec, &bus->codec_list, list) { unsigned int pcm, s; unsigned int pcm; int err; if (!codec->num_pcms) { if (!codec->patch_ops.build_pcms) continue; err = codec->patch_ops.build_pcms(codec); if (err < 0) return err; } for (pcm = 0; pcm < codec->num_pcms; pcm++) { for (s = 0; s < 2; s++) { struct hda_pcm_stream *info; info = &codec->pcm_info[pcm].stream[s]; if (!info->substreams) struct hda_pcm *cpcm = &codec->pcm_info[pcm]; int type = cpcm->pcm_type; int dev; switch (type) { case HDA_PCM_TYPE_AUDIO: if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { snd_printk(KERN_WARNING "Too many audio devices\n"); continue; err = set_pcm_default_values(codec, info); } dev = audio_idx[num_devs[type]]; break; case HDA_PCM_TYPE_SPDIF: case HDA_PCM_TYPE_HDMI: case HDA_PCM_TYPE_MODEM: if (num_devs[type]) { snd_printk(KERN_WARNING "%s already defined\n", dev_name[type]); continue; } dev = dev_idx[type]; break; default: snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); continue; } num_devs[type]++; if (!cpcm->pcm) { cpcm->device = dev; err = snd_hda_attach_pcm(codec, cpcm); if (err < 0) return err; } Loading @@ -2332,11 +2490,11 @@ int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, const char **models, const struct snd_pci_quirk *tbl) { if (codec->bus->modelname && models) { if (codec->modelname && models) { int i; for (i = 0; i < num_configs; i++) { if (models[i] && !strcmp(codec->bus->modelname, models[i])) { !strcmp(codec->modelname, models[i])) { snd_printd(KERN_INFO "hda_codec: model '%s' is " "selected\n", models[i]); return i; Loading Loading @@ -2389,7 +2547,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) kctl = snd_ctl_new1(knew, codec); if (!kctl) return -ENOMEM; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) { if (!codec->addr) return err; Loading @@ -2397,7 +2555,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) if (!kctl) return -ENOMEM; kctl->id.device = codec->addr; err = snd_ctl_add(codec->bus->card, kctl); err = snd_hda_ctl_add(codec, kctl); if (err < 0) return err; } Loading Loading @@ -3138,3 +3296,37 @@ int snd_hda_codecs_inuse(struct hda_bus *bus) } #endif #endif /* * generic arrays */ /* get a new element from the given array * if it exceeds the pre-allocated array size, re-allocate the array */ void *snd_array_new(struct snd_array *array) { if (array->used >= array->alloced) { int num = array->alloced + array->alloc_align; void *nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL); if (!nlist) return NULL; if (array->list) { memcpy(nlist, array->list, array->elem_size * array->alloced); kfree(array->list); } array->list = nlist; array->alloced = num; } return array->list + (array->used++ * array->elem_size); } /* free the given array elements */ void snd_array_free(struct snd_array *array) { kfree(array->list); array->used = 0; array->alloced = 0; array->list = NULL; }
sound/pci/hda/hda_codec.h +34 −5 Original line number Diff line number Diff line Loading @@ -519,6 +519,26 @@ enum { /* max. codec address */ #define HDA_MAX_CODEC_ADDRESS 0x0f /* * generic arrays */ struct snd_array { unsigned int used; unsigned int alloced; unsigned int elem_size; unsigned int alloc_align; void *list; }; void *snd_array_new(struct snd_array *array); void snd_array_free(struct snd_array *array); static inline void snd_array_init(struct snd_array *array, unsigned int size, unsigned int align) { array->elem_size = size; array->alloc_align = align; } /* * Structures */ Loading @@ -542,6 +562,8 @@ struct hda_bus_ops { unsigned int (*get_response)(struct hda_codec *codec); /* free the private data */ void (*private_free)(struct hda_bus *); /* attach a PCM stream */ int (*attach_pcm)(struct hda_codec *codec, struct hda_pcm *pcm); #ifdef CONFIG_SND_HDA_POWER_SAVE /* notify power-up/down from codec to controller */ void (*pm_notify)(struct hda_codec *codec); Loading Loading @@ -635,10 +657,7 @@ struct hda_amp_info { struct hda_cache_rec { u16 hash[64]; /* hash table for index */ unsigned int num_entries; /* number of assigned entries */ unsigned int size; /* allocated size */ unsigned int record_size; /* record size (including header) */ void *buffer; /* hash table entries */ struct snd_array buf; /* record entries */ }; /* PCM callbacks */ Loading Loading @@ -680,7 +699,8 @@ struct hda_pcm { char *name; struct hda_pcm_stream stream[2]; unsigned int pcm_type; /* HDA_PCM_TYPE_XXX */ int device; /* assigned device number */ int device; /* device number to assign */ struct snd_pcm *pcm; /* assigned PCM instance */ }; /* codec information */ Loading @@ -699,6 +719,8 @@ struct hda_codec { /* detected preset */ const struct hda_codec_preset *preset; const char *name; /* codec name */ const char *modelname; /* model name for preset */ /* set by patch */ struct hda_codec_ops patch_ops; Loading @@ -718,6 +740,8 @@ struct hda_codec { hda_nid_t start_nid; u32 *wcaps; struct snd_array mixers; /* list of assigned mixer elements */ struct hda_cache_rec amp_cache; /* cache for amp access */ struct hda_cache_rec cmd_cache; /* cache for other commands */ Loading @@ -727,7 +751,11 @@ struct hda_codec { unsigned int spdif_in_enable; /* SPDIF input enable? */ hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ #ifdef CONFIG_SND_HDA_HWDEP struct snd_hwdep *hwdep; /* assigned hwdep device */ struct snd_array init_verbs; /* additional init verbs */ struct snd_array hints; /* additional hints */ #endif /* misc flags */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each Loading Loading @@ -799,6 +827,7 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec); * Mixer */ int snd_hda_build_controls(struct hda_bus *bus); int snd_hda_codec_build_controls(struct hda_codec *codec); /* * PCM Loading
sound/pci/hda/hda_generic.c +12 −8 Original line number Diff line number Diff line Loading @@ -723,7 +723,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, if (is_loopback) add_input_loopback(codec, node->nid, HDA_INPUT, index); snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); if (err < 0) return err; created = 1; } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && Loading @@ -732,7 +733,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, if (is_loopback) add_input_loopback(codec, node->nid, HDA_OUTPUT, 0); snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); if (err < 0) return err; created = 1; } Loading @@ -745,14 +747,16 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) { knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT); snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); if (err < 0) return err; created = 1; } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) { knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT); snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); if (err < 0) return err; created = 1; } Loading Loading @@ -849,8 +853,8 @@ static int build_input_controls(struct hda_codec *codec) } /* create input MUX if multiple sources are available */ if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&cap_sel, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec)); if (err < 0) return err; /* no volume control? */ Loading @@ -867,8 +871,8 @@ static int build_input_controls(struct hda_codec *codec) HDA_CODEC_VOLUME(name, adc_node->nid, spec->input_mux.items[i].index, HDA_INPUT); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); if (err < 0) return err; } Loading
sound/pci/hda/hda_hwdep.c +228 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes
sound/pci/hda/hda_intel.c +35 −86 Original line number Diff line number Diff line Loading @@ -1180,6 +1180,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) return 0; } static int azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm); /* * Codec initialization Loading Loading @@ -1212,6 +1213,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, bus_temp.pci = chip->pci; bus_temp.ops.command = azx_send_cmd; bus_temp.ops.get_response = azx_get_response; bus_temp.ops.attach_pcm = azx_attach_pcm_stream; #ifdef CONFIG_SND_HDA_POWER_SAVE bus_temp.ops.pm_notify = azx_power_notify; #endif Loading Loading @@ -1718,111 +1720,58 @@ static struct snd_pcm_ops azx_pcm_ops = { static void azx_pcm_free(struct snd_pcm *pcm) { kfree(pcm->private_data); struct azx_pcm *apcm = pcm->private_data; if (apcm) { apcm->chip->pcm[pcm->device] = NULL; kfree(apcm); } } static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, struct hda_pcm *cpcm) static int azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm) { int err; struct azx *chip = codec->bus->private_data; struct snd_pcm *pcm; struct azx_pcm *apcm; int pcm_dev = cpcm->device; int s, err; /* if no substreams are defined for both playback and capture, * it's just a placeholder. ignore it. */ if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) return 0; if (snd_BUG_ON(!cpcm->name)) if (pcm_dev >= AZX_MAX_PCMS) { snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n", pcm_dev); return -EINVAL; err = snd_pcm_new(chip->card, cpcm->name, cpcm->device, cpcm->stream[0].substreams, cpcm->stream[1].substreams, } if (chip->pcm[pcm_dev]) { snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev); return -EBUSY; } err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams, cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams, &pcm); if (err < 0) return err; strcpy(pcm->name, cpcm->name); apcm = kmalloc(sizeof(*apcm), GFP_KERNEL); apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); if (apcm == NULL) return -ENOMEM; apcm->chip = chip; apcm->codec = codec; apcm->hinfo[0] = &cpcm->stream[0]; apcm->hinfo[1] = &cpcm->stream[1]; pcm->private_data = apcm; pcm->private_free = azx_pcm_free; if (cpcm->stream[0].substreams) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops); if (cpcm->stream[1].substreams) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM) pcm->dev_class = SNDRV_PCM_CLASS_MODEM; chip->pcm[pcm_dev] = pcm; cpcm->pcm = pcm; for (s = 0; s < 2; s++) { apcm->hinfo[s] = &cpcm->stream[s]; if (cpcm->stream[s].substreams) snd_pcm_set_ops(pcm, s, &azx_pcm_ops); } /* buffer pre-allocation */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 1024 * 64, 32 * 1024 * 1024); chip->pcm[cpcm->device] = pcm; return 0; } static int __devinit azx_pcm_create(struct azx *chip) { static const char *dev_name[HDA_PCM_NTYPES] = { "Audio", "SPDIF", "HDMI", "Modem" }; /* starting device index for each PCM type */ static int dev_idx[HDA_PCM_NTYPES] = { [HDA_PCM_TYPE_AUDIO] = 0, [HDA_PCM_TYPE_SPDIF] = 1, [HDA_PCM_TYPE_HDMI] = 3, [HDA_PCM_TYPE_MODEM] = 6 }; /* normal audio device indices; not linear to keep compatibility */ static int audio_idx[4] = { 0, 2, 4, 5 }; struct hda_codec *codec; int c, err; int num_devs[HDA_PCM_NTYPES]; err = snd_hda_build_pcms(chip->bus); if (err < 0) return err; /* create audio PCMs */ memset(num_devs, 0, sizeof(num_devs)); list_for_each_entry(codec, &chip->bus->codec_list, list) { for (c = 0; c < codec->num_pcms; c++) { struct hda_pcm *cpcm = &codec->pcm_info[c]; int type = cpcm->pcm_type; switch (type) { case HDA_PCM_TYPE_AUDIO: if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { snd_printk(KERN_WARNING "Too many audio devices\n"); continue; } cpcm->device = audio_idx[num_devs[type]]; break; case HDA_PCM_TYPE_SPDIF: case HDA_PCM_TYPE_HDMI: case HDA_PCM_TYPE_MODEM: if (num_devs[type]) { snd_printk(KERN_WARNING "%s already defined\n", dev_name[type]); continue; } cpcm->device = dev_idx[type]; break; default: snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); continue; } num_devs[type]++; err = create_codec_pcm(chip, codec, cpcm); if (err < 0) return err; } } return 0; } Loading Loading @@ -2324,7 +2273,7 @@ static int __devinit azx_probe(struct pci_dev *pci, } /* create PCM streams */ err = azx_pcm_create(chip); err = snd_hda_build_pcms(chip->bus); if (err < 0) { snd_card_free(card); return err; Loading