From 176d5335fe66f379a339b0ab99cc7566e90ff1a9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:44 +0200 Subject: ALSA: hda - Add infrastructure for dynamic stream allocation Added the infrastructure for dynamic stream allocation on HD-audio. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 74 +++++++++++++++++++++++++--- sound/pci/hda/hda_codec.h | 5 +- sound/pci/hda/hda_intel.c | 121 ++++++++++++++-------------------------------- 3 files changed, 105 insertions(+), 95 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 6447754ae56..19b4530e3ba 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2262,6 +2262,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 @@ -2290,10 +2312,24 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec, */ int __devinit 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->patch_ops.build_pcms) continue; @@ -2301,15 +2337,37 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) 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; + 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; - err = set_pcm_default_values(codec, info); - if (err < 0) - return err; + } + cpcm->device = dev_idx[type]; + break; + default: + snd_printk(KERN_WARNING + "Invalid PCM type %d\n", type); + continue; } + num_devs[type]++; + err = snd_hda_attach_pcm(codec, cpcm); + if (err < 0) + return err; } } return 0; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 60468f56240..70e8fa09273 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -542,6 +542,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); @@ -680,7 +682,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 */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 9f316c1b279..7b0abf08a58 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -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 @@ -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 @@ -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; } @@ -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; -- cgit v1.2.3 From b2e1859745b783922533d29e3b03af29378a23f0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:44 +0200 Subject: ALSA: hda - Add generic arrays Added helper functions to handle generic arrays. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 34 ++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_codec.h | 20 ++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 19b4530e3ba..e70303183c3 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3196,3 +3196,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; +} diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 70e8fa09273..b9b21766b73 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -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 */ -- cgit v1.2.3 From 603c40199252f0c3b91fca02fd3283c4f8e55179 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:44 +0200 Subject: ALSA: hda - Use generic array helpers Use generic array helpers to simplify array handling in snd-hda-intel. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 38 +++++-------------- sound/pci/hda/hda_codec.h | 5 +-- sound/pci/hda/patch_analog.c | 56 +++++++++++++-------------- sound/pci/hda/patch_conexant.c | 11 ------ sound/pci/hda/patch_realtek.c | 86 ++++++++++++++++++++---------------------- sound/pci/hda/patch_sigmatel.c | 55 ++++++++++++--------------- sound/pci/hda/patch_via.c | 71 +++++++++++++++------------------- 7 files changed, 132 insertions(+), 190 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e70303183c3..39a49d4a864 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -756,12 +756,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. */ @@ -770,38 +770,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]; @@ -942,10 +922,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; @@ -1779,10 +1759,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; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index b9b21766b73..77064b0cb82 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -657,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 */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 2b00c4afdf9..02643bce563 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -67,8 +67,7 @@ struct ad198x_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; + struct snd_array kctls; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; @@ -154,6 +153,8 @@ static const char *ad_slave_sws[] = { NULL }; +static void ad198x_free_kctls(struct hda_codec *codec); + static int ad198x_build_controls(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; @@ -202,6 +203,7 @@ static int ad198x_build_controls(struct hda_codec *codec) return err; } + ad198x_free_kctls(codec); /* no longer needed */ return 0; } @@ -375,16 +377,27 @@ static int ad198x_build_pcms(struct hda_codec *codec) return 0; } -static void ad198x_free(struct hda_codec *codec) +static void ad198x_free_kctls(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; - unsigned int i; - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); + if (spec->kctls.list) { + struct snd_kcontrol_new *kctl = spec->kctls.list; + int i; + for (i = 0; i < spec->kctls.used; i++) + kfree(kctl[i].name); } + snd_array_free(&spec->kctls); +} + +static void ad198x_free(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + + if (!spec) + return; + + ad198x_free_kctls(codec); kfree(codec->spec); } @@ -2452,9 +2465,6 @@ static struct hda_amp_list ad1988_loopbacks[] = { * Automatic parse of I/O pins from the BIOS configuration */ -#define NUM_CONTROL_ALLOC 32 -#define NUM_VERB_ALLOC 32 - enum { AD_CTL_WIDGET_VOL, AD_CTL_WIDGET_MUTE, @@ -2472,27 +2482,15 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, { struct snd_kcontrol_new *knew; - if (spec->num_kctl_used >= spec->num_kctl_alloc) { - int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; - - knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ - if (! knew) - return -ENOMEM; - if (spec->kctl_alloc) { - memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); - kfree(spec->kctl_alloc); - } - spec->kctl_alloc = knew; - spec->num_kctl_alloc = num; - } - - knew = &spec->kctl_alloc[spec->num_kctl_used]; + snd_array_init(&spec->kctls, sizeof(*knew), 32); + knew = snd_array_new(&spec->kctls); + if (!knew) + return -ENOMEM; *knew = ad1988_control_templates[type]; knew->name = kstrdup(name, GFP_KERNEL); if (! knew->name) return -ENOMEM; knew->private_value = val; - spec->num_kctl_used++; return 0; } @@ -2846,8 +2844,8 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = AD1988_SPDIF_IN; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs; diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 7c1eb23f0ce..07601070815 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -86,8 +86,6 @@ struct conexant_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; @@ -344,15 +342,6 @@ static int conexant_init(struct hda_codec *codec) static void conexant_free(struct hda_codec *codec) { - struct conexant_spec *spec = codec->spec; - unsigned int i; - - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); - } - kfree(codec->spec); } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0b6e682c46d..3e21a719865 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -284,8 +284,7 @@ struct alc_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; + struct snd_array kctls; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; @@ -1590,6 +1589,9 @@ static const char *alc_slave_sws[] = { /* * build control elements */ + +static void alc_free_kctls(struct hda_codec *codec); + static int alc_build_controls(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1636,6 +1638,7 @@ static int alc_build_controls(struct hda_codec *codec) return err; } + alc_free_kctls(codec); /* no longer needed */ return 0; } @@ -2726,19 +2729,27 @@ static int alc_build_pcms(struct hda_codec *codec) return 0; } +static void alc_free_kctls(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (spec->kctls.list) { + struct snd_kcontrol_new *kctl = spec->kctls.list; + int i; + for (i = 0; i < spec->kctls.used; i++) + kfree(kctl[i].name); + } + snd_array_free(&spec->kctls); +} + static void alc_free(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int i; if (!spec) return; - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); - } + alc_free_kctls(codec); kfree(spec); codec->spec = NULL; /* to be sure */ } @@ -3423,9 +3434,6 @@ static struct alc_config_preset alc880_presets[] = { * Automatic parse of I/O pins from the BIOS configuration */ -#define NUM_CONTROL_ALLOC 32 -#define NUM_VERB_ALLOC 32 - enum { ALC_CTL_WIDGET_VOL, ALC_CTL_WIDGET_MUTE, @@ -3443,29 +3451,15 @@ static int add_control(struct alc_spec *spec, int type, const char *name, { struct snd_kcontrol_new *knew; - if (spec->num_kctl_used >= spec->num_kctl_alloc) { - int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; - - /* array + terminator */ - knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); - if (!knew) - return -ENOMEM; - if (spec->kctl_alloc) { - memcpy(knew, spec->kctl_alloc, - sizeof(*knew) * spec->num_kctl_alloc); - kfree(spec->kctl_alloc); - } - spec->kctl_alloc = knew; - spec->num_kctl_alloc = num; - } - - knew = &spec->kctl_alloc[spec->num_kctl_used]; + snd_array_init(&spec->kctls, sizeof(*knew), 32); + knew = snd_array_new(&spec->kctls); + if (!knew) + return -ENOMEM; *knew = alc880_control_templates[type]; knew->name = kstrdup(name, GFP_KERNEL); if (!knew->name) return -ENOMEM; knew->private_value = val; - spec->num_kctl_used++; return 0; } @@ -3789,8 +3783,8 @@ static int alc880_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = ALC880_DIGIN_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs; @@ -5177,7 +5171,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec) err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; - if (!spec->kctl_alloc) + if (!spec->kctls.list) return 0; /* can't find valid BIOS pin config */ err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg); if (err < 0) @@ -5187,8 +5181,8 @@ static int alc260_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC260_DIGOUT_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs; @@ -10256,8 +10250,8 @@ static int alc262_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = ALC262_DIGIN_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs; spec->num_mux_defs = 1; @@ -11387,8 +11381,8 @@ static int alc268_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC268_DIGOUT_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; if (spec->autocfg.speaker_pins[0] != 0x1d) spec->mixers[spec->num_mixers++] = alc268_beep_mixer; @@ -12159,8 +12153,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC269_DIGOUT_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; /* create a beep mixer control if the pin 0x1d isn't assigned */ for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++) @@ -13257,8 +13251,8 @@ static int alc861_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC861_DIGOUT_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs; @@ -14368,8 +14362,8 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->init_verbs[spec->num_init_verbs++] = alc861vd_volume_init_verbs; @@ -16194,8 +16188,8 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index c5906551311..3db39adad79 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -35,7 +35,6 @@ #include "hda_patch.h" #include "hda_beep.h" -#define NUM_CONTROL_ALLOC 32 #define STAC_PWR_EVENT 0x20 #define STAC_HP_EVENT 0x30 #define STAC_VREF_EVENT 0x40 @@ -218,8 +217,7 @@ struct sigmatel_spec { /* dynamic controls and input_mux */ struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; + struct snd_array kctls; struct hda_input_mux private_dimux; struct hda_input_mux private_imux; struct hda_input_mux private_smux; @@ -1233,6 +1231,8 @@ static const char *slave_sws[] = { NULL }; +static void stac92xx_free_kctls(struct hda_codec *codec); + static int stac92xx_build_controls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -1305,6 +1305,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) return err; } + stac92xx_free_kctls(codec); /* no longer needed */ return 0; } @@ -2592,28 +2593,16 @@ static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type, { struct snd_kcontrol_new *knew; - if (spec->num_kctl_used >= spec->num_kctl_alloc) { - int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; - - knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ - if (! knew) - return -ENOMEM; - if (spec->kctl_alloc) { - memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); - kfree(spec->kctl_alloc); - } - spec->kctl_alloc = knew; - spec->num_kctl_alloc = num; - } - - knew = &spec->kctl_alloc[spec->num_kctl_used]; + snd_array_init(&spec->kctls, sizeof(*knew), 32); + knew = snd_array_new(&spec->kctls); + if (!knew) + return -ENOMEM; *knew = stac92xx_control_templates[type]; knew->index = idx; knew->name = kstrdup(name, GFP_KERNEL); if (! knew->name) return -ENOMEM; knew->private_value = val; - spec->num_kctl_used++; return 0; } @@ -3434,8 +3423,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out if (dig_in && spec->autocfg.dig_in_pin) spec->dig_in_nid = dig_in; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->input_mux = &spec->private_imux; spec->dinput_mux = &spec->private_dimux; @@ -3536,8 +3525,8 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = 0x04; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->input_mux = &spec->private_imux; spec->dinput_mux = &spec->private_dimux; @@ -3698,20 +3687,26 @@ static int stac92xx_init(struct hda_codec *codec) return 0; } +static void stac92xx_free_kctls(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + + if (spec->kctls.list) { + struct snd_kcontrol_new *kctl = spec->kctls.list; + int i; + for (i = 0; i < spec->kctls.used; i++) + kfree(kctl[i].name); + } + snd_array_free(&spec->kctls); +} + static void stac92xx_free(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - int i; if (! spec) return; - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); - } - if (spec->bios_pin_configs) kfree(spec->bios_pin_configs); diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 63e4871e5d8..760e14ae3bf 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -53,9 +53,6 @@ #define AMP_VAL_IDX_SHIFT 19 #define AMP_VAL_IDX_MASK (0x0f<<19) -#define NUM_CONTROL_ALLOC 32 -#define NUM_VERB_ALLOC 32 - /* Pin Widget NID */ #define VT1708_HP_NID 0x13 #define VT1708_DIGOUT_NID 0x14 @@ -227,8 +224,7 @@ struct via_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; + struct snd_array kctls; struct hda_input_mux private_imux[2]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; @@ -272,33 +268,31 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, { struct snd_kcontrol_new *knew; - if (spec->num_kctl_used >= spec->num_kctl_alloc) { - int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; - - /* array + terminator */ - knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); - if (!knew) - return -ENOMEM; - if (spec->kctl_alloc) { - memcpy(knew, spec->kctl_alloc, - sizeof(*knew) * spec->num_kctl_alloc); - kfree(spec->kctl_alloc); - } - spec->kctl_alloc = knew; - spec->num_kctl_alloc = num; - } - - knew = &spec->kctl_alloc[spec->num_kctl_used]; + snd_array_init(&spec->kctls, sizeof(*knew), 32); + knew = snd_array_new(&spec->kctls); + if (!knew) + return -ENOMEM; *knew = vt1708_control_templates[type]; knew->name = kstrdup(name, GFP_KERNEL); - if (!knew->name) return -ENOMEM; knew->private_value = val; - spec->num_kctl_used++; return 0; } +static void via_free_kctls(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + + if (spec->kctls.list) { + struct snd_kcontrol_new *kctl = spec->kctls.list; + int i; + for (i = 0; i < spec->kctls.used; i++) + kfree(kctl[i].name); + } + snd_array_free(&spec->kctls); +} + /* create input playback/capture controls for the given pin */ static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin, const char *ctlname, int idx, int mix_nid) @@ -896,6 +890,7 @@ static int via_build_controls(struct hda_codec *codec) if (err < 0) return err; } + via_free_kctls(codec); /* no longer needed */ return 0; } @@ -941,17 +936,11 @@ static int via_build_pcms(struct hda_codec *codec) static void via_free(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - unsigned int i; if (!spec) return; - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); - } - + via_free_kctls(codec); kfree(codec->spec); } @@ -1373,8 +1362,8 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = VT1708_DIGIN_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs; @@ -1846,8 +1835,8 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = VT1709_DIGIN_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->input_mux = &spec->private_imux[0]; @@ -2390,8 +2379,8 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = VT1708B_DIGIN_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->input_mux = &spec->private_imux[0]; @@ -2855,8 +2844,8 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) spec->extra_dig_out_nid = 0x15; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->input_mux = &spec->private_imux[0]; @@ -3174,8 +3163,8 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) spec->extra_dig_out_nid = 0x1B; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->input_mux = &spec->private_imux[0]; -- cgit v1.2.3 From f44ac8378d3d84b912b34f08afaff64182ee1b41 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:45 +0200 Subject: ALSA: hda - Allocate name string of each codec Allocate dynamically the name string of each codec instead of pointing to a static string. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 37 +++++++++++++++++++++++++------------ sound/pci/hda/hda_codec.h | 2 ++ sound/pci/hda/hda_proc.c | 5 ++--- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 39a49d4a864..53e36495fae 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -446,7 +446,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 @@ -481,15 +481,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) { @@ -502,10 +501,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; } /* @@ -575,6 +579,8 @@ static void snd_hda_codec_free(struct hda_codec *codec) 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); } @@ -661,12 +667,19 @@ 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); 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); @@ -2370,11 +2383,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; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 77064b0cb82..53f3b08b24c 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -719,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; diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 743d77922bc..64ab19f14f7 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -511,12 +511,11 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct hda_codec *codec = entry->private_data; - char buf[32]; hda_nid_t nid; int i, nodes; - snd_hda_get_codec_name(codec, buf, sizeof(buf)); - snd_iprintf(buffer, "Codec: %s\n", buf); + snd_iprintf(buffer, "Codec: %s\n", + codec->name ? codec->name : "Not Set"); snd_iprintf(buffer, "Address: %d\n", codec->addr); snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id); snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id); -- cgit v1.2.3 From d13bd412dce23eed8bc35a2499d7d88cb39a1581 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:45 +0200 Subject: ALSA: hda - Manage kcontrol lists Manage all kcontrol elements created in the hda-intel driver. This makes it possible to remove and reconfigure the controls of each codec. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 40 ++++++++++++++++++++++++++++++++++------ sound/pci/hda/hda_codec.h | 2 ++ sound/pci/hda/hda_generic.c | 20 ++++++++++++-------- sound/pci/hda/hda_local.h | 3 +++ sound/pci/hda/patch_sigmatel.c | 2 +- 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 53e36495fae..bc3ed249b0f 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -574,6 +574,7 @@ 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); @@ -622,6 +623,7 @@ 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); #ifdef CONFIG_SND_HDA_POWER_SAVE INIT_DELAYED_WORK(&codec->power_work, hda_power_work); @@ -1090,6 +1092,32 @@ 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); +} + /* 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) @@ -1107,7 +1135,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; @@ -1571,7 +1599,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; } @@ -1615,7 +1643,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)); } @@ -1717,7 +1745,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; } @@ -2440,7 +2468,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; @@ -2448,7 +2476,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; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 53f3b08b24c..8813ec10ca1 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -740,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 */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 0ca30894f7c..98ff010d5b9 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -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) && @@ -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; } @@ -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; } @@ -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? */ @@ -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; } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 7957fefda73..48faaf8cd21 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -393,6 +393,9 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction); int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps); +int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl); +void snd_hda_ctls_clear(struct hda_codec *codec); + /* * hwdep interface */ diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3db39adad79..9c67af8e208 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1250,7 +1250,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) } if (spec->num_dmuxes > 0) { stac_dmux_mixer.count = spec->num_dmuxes; - err = snd_ctl_add(codec->bus->card, + err = snd_hda_ctl_add(codec, snd_ctl_new1(&stac_dmux_mixer, codec)); if (err < 0) return err; -- cgit v1.2.3 From 6c1f45ea89b59ad2cdbfa6779e23d77b274da0a7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:45 +0200 Subject: ALSA: hda - Add codec reconfiguration feature Added the reconfiguration feature of any individual codec. Via the reconfiguration, the old resources are released and the patch is called again to recreate the PCM and mixers in addition to the re-initialization. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 147 +++++++++++++++++++++++++++++++--------------- sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/hda_local.h | 2 + 3 files changed, 103 insertions(+), 47 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index bc3ed249b0f..5b54ac07fcb 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -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; @@ -454,7 +454,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; @@ -624,6 +624,13 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, 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); @@ -672,6 +679,30 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, 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); + +#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; +} + +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); @@ -698,25 +729,9 @@ 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); - 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; + if (!err && codec->patch_ops.unsol_event) + err = init_unsol_queue(codec->bus); + return err; } /** @@ -1118,6 +1133,31 @@ void snd_hda_ctls_clear(struct hda_codec *codec) 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) @@ -1939,23 +1979,30 @@ 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 = 0; - /* fake as if already powered-on */ - hda_keep_power_on(codec); - /* then fire up */ - hda_set_power_state(codec, - codec->afg ? codec->afg : codec->mfg, - AC_PWRST_D0); - /* continue to initialize... */ - if (codec->patch_ops.init) - err = codec->patch_ops.init(codec); - if (!err && codec->patch_ops.build_controls) - err = codec->patch_ops.build_controls(codec); - snd_hda_power_down(codec); + 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); + /* then fire up */ + hda_set_power_state(codec, + codec->afg ? codec->afg : codec->mfg, + AC_PWRST_D0); + /* continue to initialize... */ + if (codec->patch_ops.init) + err = codec->patch_ops.init(codec); + if (!err && codec->patch_ops.build_controls) + err = codec->patch_ops.build_controls(codec); + snd_hda_power_down(codec); + if (err < 0) + return err; return 0; } @@ -2256,8 +2303,8 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static int __devinit set_pcm_default_values(struct hda_codec *codec, - struct hda_pcm_stream *info) +static int set_pcm_default_values(struct hda_codec *codec, + struct hda_pcm_stream *info) { /* query support PCM information from the given NID */ if (info->nid && (!info->rates || !info->formats)) { @@ -2331,7 +2378,7 @@ snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) * * 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" @@ -2352,14 +2399,17 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) list_for_each_entry(codec, &bus->codec_list, list) { unsigned int pcm; int err; - if (!codec->patch_ops.build_pcms) - continue; - err = codec->patch_ops.build_pcms(codec); - if (err < 0) - return 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++) { 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)) { @@ -2367,7 +2417,7 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) "Too many audio devices\n"); continue; } - cpcm->device = audio_idx[num_devs[type]]; + dev = audio_idx[num_devs[type]]; break; case HDA_PCM_TYPE_SPDIF: case HDA_PCM_TYPE_HDMI: @@ -2378,7 +2428,7 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) dev_name[type]); continue; } - cpcm->device = dev_idx[type]; + dev = dev_idx[type]; break; default: snd_printk(KERN_WARNING @@ -2386,9 +2436,12 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) continue; } num_devs[type]++; - err = snd_hda_attach_pcm(codec, cpcm); - if (err < 0) - return err; + if (!cpcm->pcm) { + cpcm->device = dev; + err = snd_hda_attach_pcm(codec, cpcm); + if (err < 0) + return err; + } } } return 0; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 8813ec10ca1..ce9f69bde32 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -823,6 +823,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 diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 48faaf8cd21..d8283f1ab21 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -96,6 +96,8 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, const char *name); int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char **slaves); +void snd_hda_codec_reset(struct hda_codec *codec); +int snd_hda_codec_configure(struct hda_codec *codec); /* amp value bits */ #define HDA_AMP_MUTE 0x80 -- cgit v1.2.3 From d7ffba19ce4c1b153d502a89d829400bf76d6c11 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:46 +0200 Subject: ALSA: hda - Add sysfs entries to hwdep devices Added the sysfs entries to hwdep devices so that the new features like reconfiguration can be done via sysfs. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 17 ++++- sound/pci/hda/hda_hwdep.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_local.h | 5 ++ 3 files changed, 177 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5b54ac07fcb..0741eda78a5 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -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 @@ -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, }; @@ -686,9 +701,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, } 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); diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 6e18a422d99..214772c8b55 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -27,6 +27,7 @@ #include "hda_codec.h" #include "hda_local.h" #include +#include /* * write/read an out-of-bound verb @@ -119,3 +120,159 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec) return 0; } + +/* + * sysfs interface + */ + +static int clear_codec(struct hda_codec *codec) +{ + snd_hda_codec_reset(codec); + return 0; +} + +static int reconfig_codec(struct hda_codec *codec) +{ + int err; + + snd_printk(KERN_INFO "hda-codec: reconfiguring\n"); + snd_hda_codec_reset(codec); + err = snd_hda_codec_configure(codec); + if (err < 0) + return err; + /* rebuild PCMs */ + err = snd_hda_build_pcms(codec->bus); + if (err < 0) + return err; + /* rebuild mixers */ + err = snd_hda_codec_build_controls(codec); + if (err < 0) + return err; + return 0; +} + +/* + * allocate a string at most len chars, and remove the trailing EOL + */ +static char *kstrndup_noeol(const char *src, size_t len) +{ + char *s = kstrndup(src, len, GFP_KERNEL); + char *p; + if (!s) + return NULL; + p = strchr(s, '\n'); + if (p) + *p = 0; + return s; +} + +#define CODEC_INFO_SHOW(type) \ +static ssize_t type##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ + struct hda_codec *codec = hwdep->private_data; \ + return sprintf(buf, "0x%x\n", codec->type); \ +} + +#define CODEC_INFO_STR_SHOW(type) \ +static ssize_t type##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ + struct hda_codec *codec = hwdep->private_data; \ + return sprintf(buf, "%s\n", \ + codec->type ? codec->type : ""); \ +} + +CODEC_INFO_SHOW(vendor_id); +CODEC_INFO_SHOW(subsystem_id); +CODEC_INFO_SHOW(revision_id); +CODEC_INFO_SHOW(afg); +CODEC_INFO_SHOW(mfg); +CODEC_INFO_STR_SHOW(name); +CODEC_INFO_STR_SHOW(modelname); + +#define CODEC_INFO_STORE(type) \ +static ssize_t type##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ + struct hda_codec *codec = hwdep->private_data; \ + char *after; \ + codec->type = simple_strtoul(buf, &after, 0); \ + return count; \ +} + +#define CODEC_INFO_STR_STORE(type) \ +static ssize_t type##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ + struct hda_codec *codec = hwdep->private_data; \ + char *s = kstrndup_noeol(buf, 64); \ + if (!s) \ + return -ENOMEM; \ + kfree(codec->type); \ + codec->type = s; \ + return count; \ +} + +CODEC_INFO_STORE(vendor_id); +CODEC_INFO_STORE(subsystem_id); +CODEC_INFO_STORE(revision_id); +CODEC_INFO_STR_STORE(name); +CODEC_INFO_STR_STORE(modelname); + +#define CODEC_ACTION_STORE(type) \ +static ssize_t type##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ + struct hda_codec *codec = hwdep->private_data; \ + int err = 0; \ + if (*buf) \ + err = type##_codec(codec); \ + return err < 0 ? err : count; \ +} + +CODEC_ACTION_STORE(reconfig); +CODEC_ACTION_STORE(clear); + +#define CODEC_ATTR_RW(type) \ + __ATTR(type, 0644, type##_show, type##_store) +#define CODEC_ATTR_RO(type) \ + __ATTR_RO(type) +#define CODEC_ATTR_WO(type) \ + __ATTR(type, 0200, NULL, type##_store) + +static struct device_attribute codec_attrs[] = { + CODEC_ATTR_RW(vendor_id), + CODEC_ATTR_RW(subsystem_id), + CODEC_ATTR_RW(revision_id), + CODEC_ATTR_RO(afg), + CODEC_ATTR_RO(mfg), + CODEC_ATTR_RW(name), + CODEC_ATTR_RW(modelname), + CODEC_ATTR_WO(reconfig), + CODEC_ATTR_WO(clear), +}; + +/* + * create sysfs files on hwdep directory + */ +int snd_hda_hwdep_add_sysfs(struct hda_codec *codec) +{ + struct snd_hwdep *hwdep = codec->hwdep; + int i; + + for (i = 0; i < ARRAY_SIZE(codec_attrs); i++) + snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, + hwdep->device, &codec_attrs[i]); + return 0; +} diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index d8283f1ab21..4a08c31b498 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -401,7 +401,12 @@ void snd_hda_ctls_clear(struct hda_codec *codec); /* * hwdep interface */ +#ifdef CONFIG_SND_HDA_HWDEP int snd_hda_create_hwdep(struct hda_codec *codec); +int snd_hda_hwdep_add_sysfs(struct hda_codec *codec); +#else +static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; } +#endif /* * power-management -- cgit v1.2.3 From 11aeff082ad9bd00e8475bf1630c3264344d3764 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:46 +0200 Subject: ALSA: hda - Add init_verbs entries This patch enables the additional init verbs for each codec. The verbs can be entered via hwdep sysfs file. These verbs are executed at reconfiguring the codec for non-standard setups like overriding the pin-defcfg. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 13 +++++++++++++ sound/pci/hda/hda_codec.h | 3 +++ sound/pci/hda/hda_hwdep.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0741eda78a5..9a8adc600a5 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1941,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 @@ -1967,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 { @@ -2008,6 +2020,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec) 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); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index ce9f69bde32..38a9bb6bafb 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -751,7 +751,10 @@ 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 */ +#endif /* misc flags */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 214772c8b55..f3400d75eba 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -96,6 +96,17 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) return 0; } +static void clear_hwdep_elements(struct hda_codec *codec) +{ + /* clear init verbs */ + snd_array_free(&codec->init_verbs); +} + +static void hwdep_free(struct snd_hwdep *hwdep) +{ + clear_hwdep_elements(hwdep->private_data); +} + int __devinit snd_hda_create_hwdep(struct hda_codec *codec) { char hwname[16]; @@ -110,6 +121,7 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec) sprintf(hwdep->name, "HDA Codec %d", codec->addr); hwdep->iface = SNDRV_HWDEP_IFACE_HDA; hwdep->private_data = codec; + hwdep->private_free = hwdep_free; hwdep->exclusive = 1; hwdep->ops.open = hda_hwdep_open; @@ -118,6 +130,8 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec) hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat; #endif + snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32); + return 0; } @@ -128,6 +142,7 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec) static int clear_codec(struct hda_codec *codec) { snd_hda_codec_reset(codec); + clear_hwdep_elements(codec); return 0; } @@ -244,6 +259,27 @@ static ssize_t type##_store(struct device *dev, \ CODEC_ACTION_STORE(reconfig); CODEC_ACTION_STORE(clear); +static ssize_t init_verbs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); + struct hda_codec *codec = hwdep->private_data; + char *p; + struct hda_verb verb, *v; + + verb.nid = simple_strtoul(buf, &p, 0); + verb.verb = simple_strtoul(p, &p, 0); + verb.param = simple_strtoul(p, &p, 0); + if (!verb.nid || !verb.verb || !verb.param) + return -EINVAL; + v = snd_array_new(&codec->init_verbs); + if (!v) + return -ENOMEM; + *v = verb; + return count; +} + #define CODEC_ATTR_RW(type) \ __ATTR(type, 0644, type##_show, type##_store) #define CODEC_ATTR_RO(type) \ @@ -259,6 +295,7 @@ static struct device_attribute codec_attrs[] = { CODEC_ATTR_RO(mfg), CODEC_ATTR_RW(name), CODEC_ATTR_RW(modelname), + CODEC_ATTR_WO(init_verbs), CODEC_ATTR_WO(reconfig), CODEC_ATTR_WO(clear), }; -- cgit v1.2.3 From 1e1be4329f2aec6a8ec63737a69258fedf34c55d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:46 +0200 Subject: ALSA: hda - Add hints for reconfig This patch adds the "hints" for reconfiguring codecs. The hints are simply string arrays and can be freely used/parsed by the codec patch. The hints can be input via hwdep sysfs files. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/hda_hwdep.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 38a9bb6bafb..a77ba223af4 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -754,6 +754,7 @@ struct hda_codec { #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 */ diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index f3400d75eba..653da1d3e4d 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "hda_codec.h" #include "hda_local.h" @@ -98,8 +99,16 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) static void clear_hwdep_elements(struct hda_codec *codec) { + char **head; + int i; + /* clear init verbs */ snd_array_free(&codec->init_verbs); + /* clear hints */ + head = codec->hints.list; + for (i = 0; i < codec->hints.used; i++, head++) + kfree(*head); + snd_array_free(&codec->hints); } static void hwdep_free(struct snd_hwdep *hwdep) @@ -131,6 +140,7 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec) #endif snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32); + snd_array_init(&codec->hints, sizeof(char *), 32); return 0; } @@ -280,6 +290,29 @@ static ssize_t init_verbs_store(struct device *dev, return count; } +static ssize_t hints_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); + struct hda_codec *codec = hwdep->private_data; + char *p; + char **hint; + + if (!*buf || isspace(*buf) || *buf == '#' || *buf == '\n') + return count; + p = kstrndup_noeol(buf, 1024); + if (!p) + return -ENOMEM; + hint = snd_array_new(&codec->hints); + if (!hint) { + kfree(p); + return -ENOMEM; + } + *hint = p; + return count; +} + #define CODEC_ATTR_RW(type) \ __ATTR(type, 0644, type##_show, type##_store) #define CODEC_ATTR_RO(type) \ @@ -296,6 +329,7 @@ static struct device_attribute codec_attrs[] = { CODEC_ATTR_RW(name), CODEC_ATTR_RW(modelname), CODEC_ATTR_WO(init_verbs), + CODEC_ATTR_WO(hints), CODEC_ATTR_WO(reconfig), CODEC_ATTR_WO(clear), }; -- cgit v1.2.3 From 45a6ac16c2136e4b902b09bf0b6192b940e8d732 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Wed, 15 Oct 2008 14:45:38 -0400 Subject: ALSA: hda: add support for jack detection on IDT/Sigmatel Added support for jack detection reporting to userspace for IDT/Sigmatel codecs. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 1 + sound/pci/hda/patch_sigmatel.c | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 7003711f4fc..7e408908b75 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -501,6 +501,7 @@ config SND_HDA_INTEL tristate "Intel HD Audio" select SND_PCM select SND_VMASTER + select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for Intel "High Definition Audio" (Azalia) motherboard devices. diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index a2ac7205d45..ec88ba88148 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "hda_codec.h" #include "hda_local.h" #include "hda_patch.h" @@ -216,6 +217,9 @@ struct sigmatel_spec { struct hda_pcm pcm_rec[2]; /* PCM information */ + /* jack detection */ + struct snd_jack *jack; + /* dynamic controls and input_mux */ struct auto_pin_cfg autocfg; unsigned int num_kctl_alloc, num_kctl_used; @@ -3617,7 +3621,7 @@ static int stac92xx_init(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int i; + int i, err; snd_hda_sequence_write(codec, spec->init); @@ -3639,6 +3643,12 @@ static int stac92xx_init(struct hda_codec *codec) stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], AC_PINCTL_OUT_EN); stac92xx_auto_init_hp_out(codec); + /* jack detection */ + err = snd_jack_new(codec->bus->card, + "Headphone Jack", + SND_JACK_HEADPHONE, &spec->jack); + if (err < 0) + return err; /* fake event to set up pins */ codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); } else { @@ -3796,6 +3806,8 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) break; presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); } + snd_jack_report(spec->jack, + presence ? SND_JACK_HEADPHONE : 0); if (presence) { /* disable lineouts, enable hp */ -- cgit v1.2.3 From ebaa0470586eec83627fa03dcd0a1107f54258f8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Oct 2008 16:39:56 +0200 Subject: ALSA: hda - Release jack instance for dynamic reconfigure The jack instance has to be release manually in free callback in patch_sigmatel.c for dynamic reconfiguration. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 579b3281783..d106ea52a90 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3717,6 +3717,9 @@ static void stac92xx_free(struct hda_codec *codec) if (! spec) return; + if (spec->jack) + snd_device_free(codec->bus->card, spec->jack); + if (spec->bios_pin_configs) kfree(spec->bios_pin_configs); -- cgit v1.2.3 From a53ccab3ccac9e8676a683df9822a2daec83ef54 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Sat, 25 Oct 2008 01:05:04 -0400 Subject: ALSA: jack: lineout support to jack abstraction layer This patch introduces support for reporting SW_LINEOUT_INSERT detection events via the jack abstraction layer. Also adds a SND_JACK_LINEOUT define to the input system header. Signed-off-by: Matthew Ranostay Cc: Dmitry Torokhov Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- include/linux/input.h | 1 + include/sound/jack.h | 1 + sound/core/jack.c | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/include/linux/input.h b/include/linux/input.h index a5802c9c81a..7323d2ff515 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -644,6 +644,7 @@ struct input_absinfo { #define SW_RADIO SW_RFKILL_ALL /* deprecated */ #define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_DOCK 0x05 /* set = plugged into dock */ +#define SW_LINEOUT_INSERT 0x06 /* set = inserted */ #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1) diff --git a/include/sound/jack.h b/include/sound/jack.h index b1b2b8b59ad..7cb25f4b50b 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h @@ -35,6 +35,7 @@ enum snd_jack_types { SND_JACK_HEADPHONE = 0x0001, SND_JACK_MICROPHONE = 0x0002, SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE, + SND_JACK_LINEOUT = 0x0004, }; struct snd_jack { diff --git a/sound/core/jack.c b/sound/core/jack.c index 8133a2b173a..c4bb9bad313 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -102,6 +102,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, if (type & SND_JACK_HEADPHONE) input_set_capability(jack->input_dev, EV_SW, SW_HEADPHONE_INSERT); + if (type & SND_JACK_LINEOUT) + input_set_capability(jack->input_dev, EV_SW, + SW_LINEOUT_INSERT); if (type & SND_JACK_MICROPHONE) input_set_capability(jack->input_dev, EV_SW, SW_MICROPHONE_INSERT); @@ -150,6 +153,9 @@ void snd_jack_report(struct snd_jack *jack, int status) if (jack->type & SND_JACK_HEADPHONE) input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT, status & SND_JACK_HEADPHONE); + if (jack->type & SND_JACK_LINEOUT) + input_report_switch(jack->input_dev, SW_LINEOUT_INSERT, + status & SND_JACK_LINEOUT); if (jack->type & SND_JACK_MICROPHONE) input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT, status & SND_JACK_MICROPHONE); -- cgit v1.2.3 From 282cd76ffca781013151344c4b0f9229e9ea3c35 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Sat, 25 Oct 2008 01:05:29 -0400 Subject: ALSA: hda: dynamic jack id This patch duplicates the jack->id pointer with kstrdup() to prevent scoping issues from calling autoprobing functions from the HDA section. Signed-off-by: Matthew Ranostay Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/core/jack.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/core/jack.c b/sound/core/jack.c index c4bb9bad313..438445f77d6 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -34,6 +34,7 @@ static int snd_jack_dev_free(struct snd_device *device) else input_free_device(jack->input_dev); + kfree(jack->id); kfree(jack); return 0; @@ -87,7 +88,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, if (jack == NULL) return -ENOMEM; - jack->id = id; + jack->id = kstrdup(id, GFP_KERNEL); jack->input_dev = input_allocate_device(); if (jack->input_dev == NULL) { -- cgit v1.2.3 From 50a9f7905fb3e6ae25e80ba443a14d878caef0c9 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Sat, 25 Oct 2008 01:05:45 -0400 Subject: ALSA: hda: add snd_hda_get_jack* functions This patch adds snd_hda_get_jack* functions for reporting jack location, device, and connectivity type. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_codec.h | 7 +++++++ sound/pci/hda/hda_proc.c | 39 +++------------------------------------ 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9a8adc600a5..eaa8b5676ea 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -107,6 +107,52 @@ static void hda_keep_power_on(struct hda_codec *codec); static inline void hda_keep_power_on(struct hda_codec *codec) {} #endif +const char *snd_hda_get_jack_location(u32 cfg) +{ + static char *bases[7] = { + "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", + }; + static unsigned char specials_idx[] = { + 0x07, 0x08, + 0x17, 0x18, 0x19, + 0x37, 0x38 + }; + static char *specials[] = { + "Rear Panel", "Drive Bar", + "Riser", "HDMI", "ATAPI", + "Mobile-In", "Mobile-Out" + }; + int i; + cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; + if ((cfg & 0x0f) < 7) + return bases[cfg & 0x0f]; + for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { + if (cfg == specials_idx[i]) + return specials[i]; + } + return "UNKNOWN"; +} + +const char *snd_hda_get_jack_connectivity(u32 cfg) +{ + static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; + + return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; +} + +const char *snd_hda_get_jack_type(u32 cfg) +{ + static char *jack_types[16] = { + "Line Out", "Speaker", "HP Out", "CD", + "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", + "Line In", "Aux", "Mic", "Telephony", + "SPDIF In", "Digitial In", "Reserved", "Other" + }; + + return jack_types[(cfg & AC_DEFCFG_DEVICE) + >> AC_DEFCFG_DEVICE_SHIFT]; +} + /** * snd_hda_codec_read - send a command and get the response * @codec: the HDA codec diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index a77ba223af4..c5f91c918d1 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -859,6 +859,13 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); int snd_hda_resume(struct hda_bus *bus); #endif +/* + * get widget information + */ +const char *snd_hda_get_jack_connectivity(u32 cfg); +const char *snd_hda_get_jack_type(u32 cfg); +const char *snd_hda_get_jack_location(u32 cfg); + /* * power saving */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 64ab19f14f7..b36d4d06485 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -145,32 +145,6 @@ static void print_pcm_caps(struct snd_info_buffer *buffer, print_pcm_formats(buffer, stream); } -static const char *get_jack_location(u32 cfg) -{ - static char *bases[7] = { - "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", - }; - static unsigned char specials_idx[] = { - 0x07, 0x08, - 0x17, 0x18, 0x19, - 0x37, 0x38 - }; - static char *specials[] = { - "Rear Panel", "Drive Bar", - "Riser", "HDMI", "ATAPI", - "Mobile-In", "Mobile-Out" - }; - int i; - cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; - if ((cfg & 0x0f) < 7) - return bases[cfg & 0x0f]; - for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { - if (cfg == specials_idx[i]) - return specials[i]; - } - return "UNKNOWN"; -} - static const char *get_jack_connection(u32 cfg) { static char *names[16] = { @@ -206,13 +180,6 @@ static void print_pin_caps(struct snd_info_buffer *buffer, int *supports_vref) { static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; - static char *jack_types[16] = { - "Line Out", "Speaker", "HP Out", "CD", - "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", - "Line In", "Aux", "Mic", "Telephony", - "SPDIF In", "Digitial In", "Reserved", "Other" - }; - static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; unsigned int caps, val; caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); @@ -274,9 +241,9 @@ static void print_pin_caps(struct snd_info_buffer *buffer, caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], - jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT], - jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3], - get_jack_location(caps)); + snd_hda_get_jack_type(caps), + snd_hda_get_jack_connectivity(caps), + snd_hda_get_jack_location(caps)); snd_iprintf(buffer, " Conn = %s, Color = %s\n", get_jack_connection(caps), get_jack_color(caps)); -- cgit v1.2.3 From 74aeaabc3e452b29bc1b9eac5aa48923569f8a4e Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Sat, 25 Oct 2008 01:06:04 -0400 Subject: ALSA: hda: add support for jack detection on IDT codecs. This patch adds support to the IDT codec families to report jack status to the jack abstraction layer. This required some reorganization in the stac92xx_unsol_event function in which the index value is changed to reporting the nid with the event. Also adds an sigmatel_jack struct to keep track of the nid relation to the jack abstraction layer instance. Also adds functions to set and retrieve data values for each nid, this is used in stac92xx_unsol_event to retrieve the GPIO mask for STAC_VREF_EVENT. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 203 ++++++++++++++++++++++++++++++++++------- 1 file changed, 170 insertions(+), 33 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d106ea52a90..c24d22fddd0 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -36,6 +36,7 @@ #include "hda_patch.h" #include "hda_beep.h" +#define STAC_INSERT_EVENT 0x10 #define STAC_PWR_EVENT 0x20 #define STAC_HP_EVENT 0x30 #define STAC_VREF_EVENT 0x40 @@ -129,6 +130,17 @@ enum { STAC_927X_MODELS }; +struct sigmatel_event { + hda_nid_t nid; + int data; +}; + +struct sigmatel_jack { + hda_nid_t nid; + int type; + struct snd_jack *jack; +}; + struct sigmatel_spec { struct snd_kcontrol_new *mixers[4]; unsigned int num_mixers; @@ -161,6 +173,12 @@ struct sigmatel_spec { hda_nid_t *pwr_nids; hda_nid_t *dac_list; + /* jack detection */ + struct snd_array jacks; + + /* events */ + struct snd_array events; + /* playback */ struct hda_input_mux *mono_mux; struct hda_input_mux *amp_mux; @@ -216,9 +234,6 @@ struct sigmatel_spec { struct hda_pcm pcm_rec[2]; /* PCM information */ - /* jack detection */ - struct snd_jack *jack; - /* dynamic controls and input_mux */ struct auto_pin_cfg autocfg; struct snd_array kctls; @@ -2458,13 +2473,15 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int nid = cfg->hp_pins[cfg->hp_outs - 1]; spec->hp_switch = ucontrol->value.integer.value[0]; /* check to be sure that the ports are upto date with * switch changes */ - codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); + codec->patch_ops.unsol_event(codec, (STAC_HP_EVENT | nid) << 26); return 1; } @@ -2504,7 +2521,8 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ * appropriately according to the pin direction */ if (spec->hp_detect) - codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); + codec->patch_ops.unsol_event(codec, + (STAC_HP_EVENT | nid) << 26); return 1; } @@ -3574,13 +3592,70 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ } +static int stac92xx_add_jack(struct hda_codec *codec, + hda_nid_t nid, int type) +{ + struct sigmatel_spec *spec = codec->spec; + struct sigmatel_jack *jack; + int def_conf = snd_hda_codec_read(codec, nid, + 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + int connectivity = get_defcfg_connect(def_conf); + char name[32]; + + if (connectivity && connectivity != AC_JACK_PORT_FIXED) + return 0; + + snd_array_init(&spec->jacks, sizeof(*jack), 32); + jack = snd_array_new(&spec->jacks); + if (!jack) + return -ENOMEM; + jack->nid = nid; + jack->type = type; + + sprintf(name, "%s at %s %s Jack", + snd_hda_get_jack_type(def_conf), + snd_hda_get_jack_connectivity(def_conf), + snd_hda_get_jack_location(def_conf)); + + return snd_jack_new(codec->bus->card, name, type, &jack->jack); +} + +static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid, + int data) +{ + struct sigmatel_event *event; + + snd_array_init(&spec->events, sizeof(*event), 32); + event = snd_array_new(&spec->events); + if (!event) + return -ENOMEM; + event->nid = nid; + event->data = data; + + return 0; +} + +static int stac92xx_event_data(struct hda_codec *codec, hda_nid_t nid) +{ + struct sigmatel_spec *spec = codec->spec; + struct sigmatel_event *events = spec->events.list; + if (events) { + int i; + for (i = 0; i < spec->events.used; i++) + if (events[i].nid == nid) + return events[i].data; + } + return 0; +} + static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, unsigned int event) { - if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) + if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | event)); + (AC_USRSP_EN | event | nid)); + } } static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) @@ -3623,27 +3698,36 @@ static int stac92xx_init(struct hda_codec *codec) /* set up pins */ if (spec->hp_detect) { /* Enable unsolicited responses on the HP widget */ - for (i = 0; i < cfg->hp_outs; i++) - enable_pin_detect(codec, cfg->hp_pins[i], - STAC_HP_EVENT); + for (i = 0; i < cfg->hp_outs; i++) { + int type = SND_JACK_HEADPHONE; + hda_nid_t nid = cfg->hp_pins[i]; + enable_pin_detect(codec, nid, STAC_HP_EVENT | nid); + /* jack detection */ + if (cfg->hp_outs == i) + type |= SND_JACK_LINEOUT; + err = stac92xx_add_jack(codec, nid, type); + if (err < 0) + return err; + + } /* force to enable the first line-out; the others are set up * in unsol_event */ stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], - AC_PINCTL_OUT_EN); - stac92xx_auto_init_hp_out(codec); - /* jack detection */ - err = snd_jack_new(codec->bus->card, - "Headphone Jack", - SND_JACK_HEADPHONE, &spec->jack); - if (err < 0) - return err; + AC_PINCTL_OUT_EN); /* fake event to set up pins */ - codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); + codec->patch_ops.unsol_event(codec, + (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26); } else { stac92xx_auto_init_multi_out(codec); stac92xx_auto_init_hp_out(codec); } + for (i = 0; i < cfg->line_outs; i++) { + err = stac92xx_add_jack(codec, + cfg->line_out_pins[i], SND_JACK_LINEOUT); + if (err < 0) + return err; + } for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = cfg->input_pins[i]; if (nid) { @@ -3656,6 +3740,11 @@ static int stac92xx_init(struct hda_codec *codec) if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) pinctl |= stac92xx_get_vref(codec, nid); stac92xx_auto_set_pinctl(codec, nid, pinctl); + err = stac92xx_add_jack(codec, nid, + SND_JACK_MICROPHONE); + if (err < 0) + return err; + enable_pin_detect(codec, nid, STAC_INSERT_EVENT | nid); } } for (i = 0; i < spec->num_dmics; i++) @@ -3697,6 +3786,18 @@ static int stac92xx_init(struct hda_codec *codec) return 0; } +static void stac92xx_free_jacks(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + if (spec->jacks.list) { + struct sigmatel_jack *jacks = spec->jacks.list; + int i; + for (i = 0; i < spec->jacks.used; i++) + snd_device_free(codec->bus->card, &jacks[i].jack); + } + snd_array_free(&spec->jacks); +} + static void stac92xx_free_kctls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -3717,11 +3818,10 @@ static void stac92xx_free(struct hda_codec *codec) if (! spec) return; - if (spec->jack) - snd_device_free(codec->bus->card, spec->jack); - if (spec->bios_pin_configs) kfree(spec->bios_pin_configs); + stac92xx_free_jacks(codec); + snd_array_free(&spec->events); kfree(spec); snd_hda_detach_beep_device(codec); @@ -3804,8 +3904,6 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) break; presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); } - snd_jack_report(spec->jack, - presence ? SND_JACK_HEADPHONE : 0); if (presence) { /* disable lineouts, enable hp */ @@ -3862,24 +3960,57 @@ static void stac92xx_pin_sense(struct hda_codec *codec, int idx) /* power down unused output ports */ snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val); -}; +} + +static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) +{ + struct sigmatel_spec *spec = codec->spec; + struct sigmatel_jack *jacks = spec->jacks.list; + + if (jacks) { + int i; + for (i = 0; i < spec->jacks.used; i++) { + if (jacks->nid == nid) { + unsigned int pin_ctl = + snd_hda_codec_read(codec, nid, + 0, AC_VERB_GET_PIN_WIDGET_CONTROL, + 0x00); + int type = jacks->type; + if (type == (SND_JACK_LINEOUT + | SND_JACK_HEADPHONE)) + type = (pin_ctl & AC_PINCTL_HP_EN) + ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT; + snd_jack_report(jacks->jack, + get_hp_pin_presence(codec, nid) + ? type : 0); + } + jacks++; + } + } +} static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) { struct sigmatel_spec *spec = codec->spec; - int idx = res >> 26 & 0x0f; + int event = (res >> 26) & 0x70; + int nid = res >> 26 & 0x0f; - switch ((res >> 26) & 0x70) { + switch (event) { case STAC_HP_EVENT: stac92xx_hp_detect(codec, res); /* fallthru */ + case STAC_INSERT_EVENT: case STAC_PWR_EVENT: - if (spec->num_pwrs > 0) - stac92xx_pin_sense(codec, idx); + if (nid) { + if (spec->num_pwrs > 0) + stac92xx_pin_sense(codec, nid); + stac92xx_report_jack(codec, nid); + } break; case STAC_VREF_EVENT: { int data = snd_hda_codec_read(codec, codec->afg, 0, AC_VERB_GET_GPIO_DATA, 0); + int idx = stac92xx_event_data(codec, nid); /* toggle VREF state based on GPIOx status */ snd_hda_codec_write(codec, codec->afg, 0, 0x7e0, !!(data & (1 << idx))); @@ -4402,8 +4533,11 @@ again: snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | STAC_VREF_EVENT | 0x01)); + AC_VERB_SET_UNSOLICITED_ENABLE, + (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg)); + err = stac92xx_add_event(spec, codec->afg, 0x02); + if (err < 0) + return err; spec->gpio_mask |= 0x02; break; } @@ -4802,8 +4936,11 @@ static int patch_stac9205(struct hda_codec *codec) snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | STAC_HP_EVENT)); + AC_VERB_SET_UNSOLICITED_ENABLE, + (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg)); + err = stac92xx_add_event(spec, codec->afg, 0x01); + if (err < 0) + return err; spec->gpio_dir = 0x0b; spec->eapd_mask = 0x01; -- cgit v1.2.3 From 34c25350acfc792747e861d1e36874abf7e73255 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Oct 2008 11:38:58 +0100 Subject: ALSA: hda - Remove old codec-probe limitation Removed the old workaround to avoid the non-existing codec slot. The current code should work without that workaround. If any, we can add a quirk table. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 7b0abf08a58..a13169cc95a 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1191,21 +1191,12 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = { [AZX_DRIVER_TERA] = 1, }; -/* number of slots to probe as default - * this can be different from azx_max_codecs[] -- e.g. some boards - * report wrongly the non-existing 4th slot availability - */ -static unsigned int azx_default_codecs[AZX_NUM_DRIVERS] __devinitdata = { - [AZX_DRIVER_ICH] = 3, - [AZX_DRIVER_ATI] = 3, -}; - static int __devinit azx_codec_create(struct azx *chip, const char *model, unsigned int codec_probe_mask) { struct hda_bus_template bus_temp; - int c, codecs, audio_codecs, err; - int def_slots, max_slots; + int c, codecs, err; + int max_slots; memset(&bus_temp, 0, sizeof(bus_temp)); bus_temp.private_data = chip; @@ -1225,33 +1216,17 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, if (chip->driver_type == AZX_DRIVER_NVIDIA) chip->bus->needs_damn_long_delay = 1; - codecs = audio_codecs = 0; + codecs = 0; max_slots = azx_max_codecs[chip->driver_type]; if (!max_slots) max_slots = AZX_MAX_CODECS; - def_slots = azx_default_codecs[chip->driver_type]; - if (!def_slots) - def_slots = max_slots; - for (c = 0; c < def_slots; c++) { + for (c = 0; c < max_slots; c++) { if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { struct hda_codec *codec; err = snd_hda_codec_new(chip->bus, c, &codec); if (err < 0) continue; codecs++; - if (codec->afg) - audio_codecs++; - } - } - if (!audio_codecs) { - /* probe additional slots if no codec is found */ - for (; c < max_slots; c++) { - if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { - err = snd_hda_codec_new(chip->bus, c, NULL); - if (err < 0) - continue; - codecs++; - } } } if (!codecs) { -- cgit v1.2.3 From d301fc320f3e673a49200d9ce51036caa9abd768 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 Oct 2008 08:15:30 +0100 Subject: ALSA: hda - Fix indentation in hda_local.h Just cosmetic fixes of spacing that annoyed me. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_local.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 4a08c31b498..aac569b0559 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -366,17 +366,17 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, /* amp values */ #define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) #define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) -#define AMP_OUT_MUTE 0xb080 -#define AMP_OUT_UNMUTE 0xb000 -#define AMP_OUT_ZERO 0xb000 +#define AMP_OUT_MUTE 0xb080 +#define AMP_OUT_UNMUTE 0xb000 +#define AMP_OUT_ZERO 0xb000 /* pinctl values */ #define PIN_IN (AC_PINCTL_IN_EN) -#define PIN_VREFHIZ (AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ) +#define PIN_VREFHIZ (AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ) #define PIN_VREF50 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_50) -#define PIN_VREFGRD (AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD) +#define PIN_VREFGRD (AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD) #define PIN_VREF80 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_80) -#define PIN_VREF100 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_100) -#define PIN_OUT (AC_PINCTL_OUT_EN) +#define PIN_VREF100 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_100) +#define PIN_OUT (AC_PINCTL_OUT_EN) #define PIN_HP (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN) #define PIN_HP_AMP (AC_PINCTL_HP_EN) -- cgit v1.2.3 From d88897eaea53f0fae62d528a24e76b8643082db3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 31 Oct 2008 15:01:37 +0100 Subject: ALSA: hda - Use macros to check array overflow Use macro to add mixer and verb elements to check the possible array overflow. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 113 ++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 60 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d300fc49f7e..51479fba960 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -715,6 +715,22 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, .private_value = nid | (mask<<16) } #endif /* CONFIG_SND_DEBUG */ +/* + */ +static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix) +{ + if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers))) + return; + spec->mixers[spec->num_mixers++] = mix; +} + +static void add_verb(struct alc_spec *spec, const struct hda_verb *verb) +{ + if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs))) + return; + spec->init_verbs[spec->num_init_verbs++] = verb; +} + /* * set up from the preset table */ @@ -724,11 +740,10 @@ static void setup_preset(struct alc_spec *spec, int i; for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) - spec->mixers[spec->num_mixers++] = preset->mixers[i]; + add_mixer(spec, preset->mixers[i]); for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; i++) - spec->init_verbs[spec->num_init_verbs++] = - preset->init_verbs[i]; + add_verb(spec, preset->init_verbs[i]); spec->channel_mode = preset->channel_mode; spec->num_channel_mode = preset->num_channel_mode; @@ -1244,7 +1259,6 @@ static struct snd_kcontrol_new alc880_capture_alt_mixer[] = { .get = alc_mux_enum_get, .put = alc_mux_enum_put, }, - { } /* end */ }; @@ -3893,9 +3907,9 @@ static int alc880_parse_auto_config(struct hda_codec *codec) spec->dig_in_nid = ALC880_DIGIN_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); - spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs; + add_verb(spec, alc880_volume_init_verbs); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; @@ -3974,14 +3988,11 @@ static int patch_alc880(struct hda_codec *codec) if (wcap != AC_WID_AUD_IN) { spec->adc_nids = alc880_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); - spec->mixers[spec->num_mixers] = - alc880_capture_alt_mixer; - spec->num_mixers++; + add_mixer(spec, alc880_capture_alt_mixer); } else { spec->adc_nids = alc880_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); - spec->mixers[spec->num_mixers] = alc880_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc880_capture_mixer); } } @@ -5298,9 +5309,9 @@ static int alc260_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC260_DIGOUT_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); - spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs; + add_verb(spec, alc260_volume_init_verbs); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; @@ -5311,13 +5322,12 @@ static int alc260_parse_auto_config(struct hda_codec *codec) if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { spec->adc_nids = alc260_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt); - spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer; + add_mixer(spec, alc260_capture_alt_mixer); } else { spec->adc_nids = alc260_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); - spec->mixers[spec->num_mixers] = alc260_capture_mixer; + add_mixer(spec, alc260_capture_mixer); } - spec->num_mixers++; store_pin_configs(codec); return 1; @@ -6834,15 +6844,12 @@ static int patch_alc882(struct hda_codec *codec) spec->adc_nids = alc882_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt); spec->capsrc_nids = alc882_capsrc_nids_alt; - spec->mixers[spec->num_mixers] = - alc882_capture_alt_mixer; - spec->num_mixers++; + add_mixer(spec, alc882_capture_alt_mixer); } else { spec->adc_nids = alc882_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids); spec->capsrc_nids = alc882_capsrc_nids; - spec->mixers[spec->num_mixers] = alc882_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc882_capture_mixer); } } @@ -8854,8 +8861,7 @@ static int alc883_parse_auto_config(struct hda_codec *codec) /* hack - override the init verbs */ spec->init_verbs[0] = alc883_auto_init_verbs; - spec->mixers[spec->num_mixers] = alc883_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc883_capture_mixer); return 1; /* config found */ } @@ -10373,9 +10379,9 @@ static int alc262_parse_auto_config(struct hda_codec *codec) spec->dig_in_nid = ALC262_DIGIN_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); - spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs; + add_verb(spec, alc262_volume_init_verbs); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; @@ -10752,15 +10758,12 @@ static int patch_alc262(struct hda_codec *codec) spec->adc_nids = alc262_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt); spec->capsrc_nids = alc262_capsrc_nids_alt; - spec->mixers[spec->num_mixers] = - alc262_capture_alt_mixer; - spec->num_mixers++; + add_mixer(spec, alc262_capture_alt_mixer); } else { spec->adc_nids = alc262_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids); spec->capsrc_nids = alc262_capsrc_nids; - spec->mixers[spec->num_mixers] = alc262_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc262_capture_mixer); } } @@ -11505,12 +11508,12 @@ static int alc268_parse_auto_config(struct hda_codec *codec) spec->multiout.dig_out_nid = ALC268_DIGOUT_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); if (spec->autocfg.speaker_pins[0] != 0x1d) - spec->mixers[spec->num_mixers++] = alc268_beep_mixer; + add_mixer(spec, alc268_beep_mixer); - spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs; + add_verb(spec, alc268_volume_init_verbs); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; @@ -11779,15 +11782,11 @@ static int patch_alc268(struct hda_codec *codec) if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { spec->adc_nids = alc268_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt); - spec->mixers[spec->num_mixers] = - alc268_capture_alt_mixer; - spec->num_mixers++; + add_mixer(spec, alc268_capture_alt_mixer); } else { spec->adc_nids = alc268_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids); - spec->mixers[spec->num_mixers] = - alc268_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc268_capture_mixer); } spec->capsrc_nids = alc268_capsrc_nids; /* set default input source */ @@ -12296,16 +12295,16 @@ static int alc269_parse_auto_config(struct hda_codec *codec) spec->multiout.dig_out_nid = ALC269_DIGOUT_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); /* create a beep mixer control if the pin 0x1d isn't assigned */ for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++) if (spec->autocfg.input_pins[i] == 0x1d) break; if (i >= ARRAY_SIZE(spec->autocfg.input_pins)) - spec->mixers[spec->num_mixers++] = alc269_beep_mixer; + add_mixer(spec, alc269_beep_mixer); - spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs; + add_verb(spec, alc269_init_verbs); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; /* set default input source */ @@ -12317,8 +12316,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - spec->mixers[spec->num_mixers] = alc269_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc269_capture_mixer); store_pin_configs(codec); return 1; @@ -13395,17 +13393,16 @@ static int alc861_parse_auto_config(struct hda_codec *codec) spec->multiout.dig_out_nid = ALC861_DIGOUT_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); - spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs; + add_verb(spec, alc861_auto_init_verbs); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; spec->adc_nids = alc861_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); - spec->mixers[spec->num_mixers] = alc861_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc861_capture_mixer); store_pin_configs(codec); return 1; @@ -14507,10 +14504,9 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); - spec->init_verbs[spec->num_init_verbs++] - = alc861vd_volume_init_verbs; + add_verb(spec, alc861vd_volume_init_verbs); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; @@ -14577,7 +14573,7 @@ static int patch_alc861vd(struct hda_codec *codec) spec->stream_name_analog = "ALC660-VD Analog"; spec->stream_name_digital = "ALC660-VD Digital"; /* always turn on EAPD */ - spec->init_verbs[spec->num_init_verbs++] = alc660vd_eapd_verbs; + add_verb(spec, alc660vd_eapd_verbs); } else { spec->stream_name_analog = "ALC861VD Analog"; spec->stream_name_digital = "ALC861VD Digital"; @@ -14593,8 +14589,7 @@ static int patch_alc861vd(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); spec->capsrc_nids = alc861vd_capsrc_nids; - spec->mixers[spec->num_mixers] = alc861vd_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc861vd_capture_mixer); spec->vmaster_nid = 0x02; @@ -16335,22 +16330,20 @@ static int alc662_parse_auto_config(struct hda_codec *codec) spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; - spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs; + add_verb(spec, alc662_auto_init_verbs); if (codec->vendor_id == 0x10ec0663) - spec->init_verbs[spec->num_init_verbs++] = - alc663_auto_init_verbs; + add_verb(spec, alc663_auto_init_verbs); err = alc_auto_add_mic_boost(codec); if (err < 0) return err; - spec->mixers[spec->num_mixers] = alc662_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc662_capture_mixer); store_pin_configs(codec); return 1; -- cgit v1.2.3 From 54cbc9abe57cf0a36619f394802448c62402599a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 31 Oct 2008 15:24:04 +0100 Subject: ALSA: hda - Unify capture callbacks in realtek codes Unify the capture callbacks in patch_realtek.c. The difference of matrix or mux style is checked via spec->is_mix_capture flag. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 276 +++++++++++++++--------------------------- 1 file changed, 100 insertions(+), 176 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 51479fba960..8477d6d4688 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -268,6 +268,7 @@ struct alc_spec { hda_nid_t *adc_nids; hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ + unsigned char is_mix_capture; /* matrix-style capture (non-mux) */ /* capture source */ unsigned int num_mux_defs; @@ -374,14 +375,38 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; + const struct hda_input_mux *imux = spec->input_mux; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; hda_nid_t nid = spec->capsrc_nids ? spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; - return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol, - nid, &spec->cur_mux[adc_idx]); -} + if (spec->is_mix_capture) { + /* Matrix-mixer style (e.g. ALC882) */ + unsigned int *cur_val = &spec->cur_mux[adc_idx]; + unsigned int i, idx; + + idx = ucontrol->value.enumerated.item[0]; + if (idx >= imux->num_items) + idx = imux->num_items - 1; + if (*cur_val == idx) + return 0; + for (i = 0; i < imux->num_items; i++) { + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); + } + *cur_val = idx; + return 1; + } else { + /* MUX style (e.g. ALC880) */ + unsigned int mux_idx; + mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; + return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], + ucontrol, nid, + &spec->cur_mux[adc_idx]); + } +} /* * channel mode setting @@ -5629,36 +5654,6 @@ static struct hda_input_mux alc882_capture_source = { { "CD", 0x4 }, }, }; -#define alc882_mux_enum_info alc_mux_enum_info -#define alc882_mux_enum_get alc_mux_enum_get - -static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux = spec->input_mux; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - hda_nid_t nid = spec->capsrc_nids ? - spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; - unsigned int *cur_val = &spec->cur_mux[adc_idx]; - unsigned int i, idx; - - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - if (*cur_val == idx) - return 0; - for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, - imux->items[i].index, - HDA_AMP_MUTE, v); - } - *cur_val = idx; - return 1; -} - /* * 2ch mode */ @@ -6341,48 +6336,8 @@ static struct hda_verb alc882_auto_init_verbs[] = { { } }; -/* capture mixer elements */ -static struct snd_kcontrol_new alc882_capture_alt_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, - .put = alc882_mux_enum_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc882_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 3, - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, - .put = alc882_mux_enum_put, - }, - { } /* end */ -}; +#define alc882_capture_alt_mixer alc880_capture_alt_mixer +#define alc882_capture_mixer alc880_capture_mixer #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc882_loopbacks alc880_loopbacks @@ -6835,6 +6790,7 @@ static int patch_alc882(struct hda_codec *codec) spec->stream_digital_playback = &alc882_pcm_digital_playback; spec->stream_digital_capture = &alc882_pcm_digital_capture; + spec->is_mix_capture = 1; /* matrix-style capture */ if (!spec->adc_nids && spec->input_mux) { /* check whether NID 0x07 is valid */ unsigned int wcap = get_wcaps(codec, 0x07); @@ -6958,11 +6914,6 @@ static struct hda_input_mux alc883_asus_eee1601_capture_source = { }, }; -#define alc883_mux_enum_info alc_mux_enum_info -#define alc883_mux_enum_get alc_mux_enum_get -/* ALC883 has the ALC882-type input selection */ -#define alc883_mux_enum_put alc882_mux_enum_put - /* * 2ch mode */ @@ -7125,9 +7076,9 @@ static struct snd_kcontrol_new alc883_base_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7155,9 +7106,9 @@ static struct snd_kcontrol_new alc883_mitac_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7182,9 +7133,9 @@ static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7209,9 +7160,9 @@ static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7241,9 +7192,9 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7277,9 +7228,9 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7316,9 +7267,9 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7353,9 +7304,9 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7386,9 +7337,9 @@ static struct snd_kcontrol_new alc883_tagra_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7414,9 +7365,9 @@ static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7437,9 +7388,9 @@ static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7463,9 +7414,9 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7489,9 +7440,9 @@ static struct snd_kcontrol_new alc883_medion_md2_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7514,9 +7465,9 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7554,9 +7505,9 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7595,9 +7546,9 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -8253,25 +8204,7 @@ static struct hda_verb alc883_auto_init_verbs[] = { }; /* capture mixer elements */ -static struct snd_kcontrol_new alc883_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, - .put = alc882_mux_enum_put, - }, - { } /* end */ -}; +#define alc883_capture_mixer alc880_capture_alt_mixer /* 2 ADC ver */ static struct hda_verb alc888_asus_m90v_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -8947,6 +8880,7 @@ static int patch_alc883(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); spec->adc_nids = alc883_adc_nids; spec->capsrc_nids = alc883_capsrc_nids; + spec->is_mix_capture = 1; /* matrix-style capture */ spec->vmaster_nid = 0x0c; @@ -9967,7 +9901,7 @@ static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol, struct alc_spec *spec = codec->spec; int ret; - ret = alc882_mux_enum_put(kcontrol, ucontrol); + ret = alc_mux_enum_put(kcontrol, ucontrol); if (!ret) return 0; /* reprogram the HP pin as mic or HP according to the input source */ @@ -9984,8 +9918,8 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, .put = alc262_ultra_mux_enum_put, }, { } /* end */ @@ -10748,6 +10682,7 @@ static int patch_alc262(struct hda_codec *codec) spec->stream_digital_playback = &alc262_pcm_digital_playback; spec->stream_digital_capture = &alc262_pcm_digital_capture; + spec->is_mix_capture = 1; if (!spec->adc_nids && spec->input_mux) { /* check whether NID 0x07 is valid */ unsigned int wcap = get_wcaps(codec, 0x07); @@ -11213,10 +11148,6 @@ static struct hda_verb alc268_volume_init_verbs[] = { { } }; -#define alc268_mux_enum_info alc_mux_enum_info -#define alc268_mux_enum_get alc_mux_enum_get -#define alc268_mux_enum_put alc_mux_enum_put - static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), @@ -11228,9 +11159,9 @@ static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc268_mux_enum_info, - .get = alc268_mux_enum_get, - .put = alc268_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -11248,9 +11179,9 @@ static struct snd_kcontrol_new alc268_capture_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc268_mux_enum_info, - .get = alc268_mux_enum_get, - .put = alc268_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -13698,11 +13629,6 @@ static struct hda_input_mux alc861vd_hp_capture_source = { }, }; -#define alc861vd_mux_enum_info alc_mux_enum_info -#define alc861vd_mux_enum_get alc_mux_enum_get -/* ALC861VD has the ALC882-type input selection (but has only one ADC) */ -#define alc861vd_mux_enum_put alc882_mux_enum_put - /* * 2ch mode */ @@ -13760,9 +13686,9 @@ static struct snd_kcontrol_new alc861vd_capture_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc861vd_mux_enum_info, - .get = alc861vd_mux_enum_get, - .put = alc861vd_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -14588,6 +14514,7 @@ static int patch_alc861vd(struct hda_codec *codec) spec->adc_nids = alc861vd_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); spec->capsrc_nids = alc861vd_capsrc_nids; + spec->is_mix_capture = 1; add_mixer(spec, alc861vd_capture_mixer); @@ -14676,10 +14603,6 @@ static struct hda_input_mux alc663_m51va_capture_source = { }, }; -#define alc662_mux_enum_info alc_mux_enum_info -#define alc662_mux_enum_get alc_mux_enum_get -#define alc662_mux_enum_put alc882_mux_enum_put - /* * 2ch mode */ @@ -15277,9 +15200,9 @@ static struct snd_kcontrol_new alc662_capture_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc662_mux_enum_info, - .get = alc662_mux_enum_get, - .put = alc662_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -16420,6 +16343,7 @@ static int patch_alc662(struct hda_codec *codec) spec->adc_nids = alc662_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); spec->capsrc_nids = alc662_capsrc_nids; + spec->is_mix_capture = 1; spec->vmaster_nid = 0x02; -- cgit v1.2.3 From f9e336f65b666b8f1764d17e9b7c21c90748a37e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 31 Oct 2008 16:37:07 +0100 Subject: ALSA: hda - Unify capture mixer creation in realtek codes Unified the capture mixer creation in patch_realtek.c. ALC268 is still an exception since it has no AMP in ADC but in MUX widget. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 744 +++++++++++++----------------------------- 1 file changed, 218 insertions(+), 526 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8477d6d4688..d511ce4b11a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -239,6 +239,7 @@ struct alc_spec { /* codec parameterization */ struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ unsigned int num_mixers; + struct snd_kcontrol_new *cap_mixer; /* capture mixer */ const struct hda_verb *init_verbs[5]; /* initialization verbs * don't forget NULL @@ -323,6 +324,7 @@ struct alc_config_preset { struct snd_kcontrol_new *mixers[5]; /* should be identical size * with spec */ + struct snd_kcontrol_new *cap_mixer; /* capture mixer */ const struct hda_verb *init_verbs[5]; unsigned int num_dacs; hda_nid_t *dac_nids; @@ -766,6 +768,7 @@ static void setup_preset(struct alc_spec *spec, for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) add_mixer(spec, preset->mixers[i]); + spec->cap_mixer = preset->cap_mixer; for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; i++) add_verb(spec, preset->init_verbs[i]); @@ -1244,48 +1247,117 @@ static struct snd_kcontrol_new alc880_three_stack_mixer[] = { }; /* capture mixer elements */ -static struct snd_kcontrol_new alc880_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 3, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; +static int alc_cap_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + int err; -/* capture mixer elements (in case NID 0x07 not available) */ -static struct snd_kcontrol_new alc880_capture_alt_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, -}; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, + HDA_INPUT); + err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); + mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */ + return err; +} + +static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + int err; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, + HDA_INPUT); + err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); + mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */ + return err; +} + +typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol, + getput_call_t func) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + int err; + + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx], + 3, 0, HDA_INPUT); + err = func(kcontrol, ucontrol); + mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */ + return err; +} + +static int alc_cap_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return alc_cap_getput_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_volume_get); +} + +static int alc_cap_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return alc_cap_getput_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_volume_put); +} + +/* capture mixer elements */ +#define alc_cap_sw_info snd_ctl_boolean_stereo_info + +static int alc_cap_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return alc_cap_getput_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_switch_get); +} + +static int alc_cap_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return alc_cap_getput_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_switch_put); +} + +#define DEFINE_CAPMIX(num) \ +static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Capture Switch", \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .count = num, \ + .info = alc_cap_sw_info, \ + .get = alc_cap_sw_get, \ + .put = alc_cap_sw_put, \ + }, \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Capture Volume", \ + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \ + .count = num, \ + .info = alc_cap_vol_info, \ + .get = alc_cap_vol_get, \ + .put = alc_cap_vol_put, \ + .tlv = { .c = alc_cap_vol_tlv }, \ + }, \ + { } /* end */ \ +} + +/* up to three ADCs */ +DEFINE_CAPMIX(1); +DEFINE_CAPMIX(2); +DEFINE_CAPMIX(3); /* @@ -1571,18 +1643,6 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -1690,7 +1750,11 @@ static int alc_build_controls(struct hda_codec *codec) if (err < 0) return err; } - + if (spec->cap_mixer) { + err = snd_hda_add_new_ctls(codec, spec->cap_mixer); + if (err < 0) + return err; + } if (spec->multiout.dig_out_nid) { err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); @@ -3318,6 +3382,8 @@ static struct alc_config_preset alc880_presets[] = { alc880_gpio2_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_dac_nids), .dac_nids = alc880_dac_nids, + .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */ + .num_adc_nids = 1, /* single ADC */ .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), .channel_mode = alc880_2_jack_modes, @@ -3958,6 +4024,17 @@ static void alc880_auto_init(struct hda_codec *codec) * OK, here we have finally the patch for ALC880 */ +static void set_capture_mixer(struct alc_spec *spec) +{ + static struct snd_kcontrol_new *caps[3] = { + alc_capture_mixer1, + alc_capture_mixer2, + alc_capture_mixer3, + }; + if (spec->num_adc_nids > 0 && spec->num_adc_nids < 3) + spec->cap_mixer = caps[spec->num_adc_nids - 1]; +} + static int patch_alc880(struct hda_codec *codec) { struct alc_spec *spec; @@ -4013,13 +4090,12 @@ static int patch_alc880(struct hda_codec *codec) if (wcap != AC_WID_AUD_IN) { spec->adc_nids = alc880_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); - add_mixer(spec, alc880_capture_alt_mixer); } else { spec->adc_nids = alc880_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); - add_mixer(spec, alc880_capture_mixer); } } + set_capture_mixer(spec); spec->vmaster_nid = 0x0c; @@ -4054,11 +4130,6 @@ static hda_nid_t alc260_adc_nids_alt[1] = { 0x05, }; -static hda_nid_t alc260_hp_adc_nids[2] = { - /* ADC1, 0 */ - 0x05, 0x04 -}; - /* NIDs used when simultaneous access to both ADCs makes sense. Note that * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC. */ @@ -4457,45 +4528,6 @@ static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { { } /* end */ }; -/* capture mixer elements */ -static struct snd_kcontrol_new alc260_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc260_capture_alt_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - /* * initialization verbs */ @@ -5312,7 +5344,6 @@ static struct hda_verb alc260_volume_init_verbs[] = { static int alc260_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int wcap; int err; static hda_nid_t alc260_ignore[] = { 0x17, 0 }; @@ -5341,19 +5372,6 @@ static int alc260_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; - /* check whether NID 0x04 is valid */ - wcap = get_wcaps(codec, 0x04); - wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ - if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { - spec->adc_nids = alc260_adc_nids_alt; - spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt); - add_mixer(spec, alc260_capture_alt_mixer); - } else { - spec->adc_nids = alc260_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); - add_mixer(spec, alc260_capture_mixer); - } - store_pin_configs(codec); return 1; } @@ -5423,12 +5441,11 @@ static struct alc_config_preset alc260_presets[] = { [ALC260_BASIC] = { .mixers = { alc260_base_output_mixer, alc260_input_mixer, - alc260_pc_beep_mixer, - alc260_capture_mixer }, + alc260_pc_beep_mixer }, .init_verbs = { alc260_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), .adc_nids = alc260_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, @@ -5436,14 +5453,13 @@ static struct alc_config_preset alc260_presets[] = { }, [ALC260_HP] = { .mixers = { alc260_hp_output_mixer, - alc260_input_mixer, - alc260_capture_alt_mixer }, + alc260_input_mixer }, .init_verbs = { alc260_init_verbs, alc260_hp_unsol_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), - .adc_nids = alc260_hp_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, @@ -5452,14 +5468,13 @@ static struct alc_config_preset alc260_presets[] = { }, [ALC260_HP_DC7600] = { .mixers = { alc260_hp_dc7600_mixer, - alc260_input_mixer, - alc260_capture_alt_mixer }, + alc260_input_mixer }, .init_verbs = { alc260_init_verbs, alc260_hp_dc7600_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), - .adc_nids = alc260_hp_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, @@ -5468,14 +5483,13 @@ static struct alc_config_preset alc260_presets[] = { }, [ALC260_HP_3013] = { .mixers = { alc260_hp_3013_mixer, - alc260_input_mixer, - alc260_capture_alt_mixer }, + alc260_input_mixer }, .init_verbs = { alc260_hp_3013_init_verbs, alc260_hp_3013_unsol_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), - .adc_nids = alc260_hp_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, @@ -5483,8 +5497,7 @@ static struct alc_config_preset alc260_presets[] = { .init_hook = alc260_hp_3013_automute, }, [ALC260_FUJITSU_S702X] = { - .mixers = { alc260_fujitsu_mixer, - alc260_capture_mixer }, + .mixers = { alc260_fujitsu_mixer }, .init_verbs = { alc260_fujitsu_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, @@ -5496,8 +5509,7 @@ static struct alc_config_preset alc260_presets[] = { .input_mux = alc260_fujitsu_capture_sources, }, [ALC260_ACER] = { - .mixers = { alc260_acer_mixer, - alc260_capture_mixer }, + .mixers = { alc260_acer_mixer }, .init_verbs = { alc260_acer_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, @@ -5509,8 +5521,7 @@ static struct alc_config_preset alc260_presets[] = { .input_mux = alc260_acer_capture_sources, }, [ALC260_WILL] = { - .mixers = { alc260_will_mixer, - alc260_capture_mixer }, + .mixers = { alc260_will_mixer }, .init_verbs = { alc260_init_verbs, alc260_will_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, @@ -5522,8 +5533,7 @@ static struct alc_config_preset alc260_presets[] = { .input_mux = &alc260_capture_source, }, [ALC260_REPLACER_672V] = { - .mixers = { alc260_replacer_672v_mixer, - alc260_capture_mixer }, + .mixers = { alc260_replacer_672v_mixer }, .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, @@ -5538,8 +5548,7 @@ static struct alc_config_preset alc260_presets[] = { }, #ifdef CONFIG_SND_DEBUG [ALC260_TEST] = { - .mixers = { alc260_test_mixer, - alc260_capture_mixer }, + .mixers = { alc260_test_mixer }, .init_verbs = { alc260_test_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_test_dac_nids), .dac_nids = alc260_test_dac_nids, @@ -5598,6 +5607,8 @@ static int patch_alc260(struct hda_codec *codec) spec->stream_digital_playback = &alc260_pcm_digital_playback; spec->stream_digital_capture = &alc260_pcm_digital_capture; + set_capture_mixer(spec); + spec->vmaster_nid = 0x08; codec->patch_ops = alc_patch_ops; @@ -6336,9 +6347,6 @@ static struct hda_verb alc882_auto_init_verbs[] = { { } }; -#define alc882_capture_alt_mixer alc880_capture_alt_mixer -#define alc882_capture_mixer alc880_capture_mixer - #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc882_loopbacks alc880_loopbacks #endif @@ -6467,8 +6475,7 @@ static struct alc_config_preset alc882_presets[] = { .init_hook = alc885_imac24_init_hook, }, [ALC882_TARGA] = { - .mixers = { alc882_targa_mixer, alc882_chmode_mixer, - alc882_capture_mixer }, + .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, .init_verbs = { alc882_init_verbs, alc882_targa_verbs}, .num_dacs = ARRAY_SIZE(alc882_dac_nids), .dac_nids = alc882_dac_nids, @@ -6484,8 +6491,7 @@ static struct alc_config_preset alc882_presets[] = { .init_hook = alc882_targa_automute, }, [ALC882_ASUS_A7J] = { - .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer, - alc882_capture_mixer }, + .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs}, .num_dacs = ARRAY_SIZE(alc882_dac_nids), .dac_nids = alc882_dac_nids, @@ -6800,14 +6806,13 @@ static int patch_alc882(struct hda_codec *codec) spec->adc_nids = alc882_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt); spec->capsrc_nids = alc882_capsrc_nids_alt; - add_mixer(spec, alc882_capture_alt_mixer); } else { spec->adc_nids = alc882_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids); spec->capsrc_nids = alc882_capsrc_nids; - add_mixer(spec, alc882_capture_mixer); } } + set_capture_mixer(spec); spec->vmaster_nid = 0x0c; @@ -6846,6 +6851,11 @@ static hda_nid_t alc883_adc_nids[2] = { 0x08, 0x09, }; +static hda_nid_t alc883_adc_nids_alt[1] = { + /* ADC1 */ + 0x08, +}; + static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 }; /* input MUX */ @@ -7067,19 +7077,6 @@ static struct snd_kcontrol_new alc883_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7097,19 +7094,6 @@ static struct snd_kcontrol_new alc883_mitac_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7124,19 +7108,6 @@ static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7151,19 +7122,6 @@ static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7183,19 +7141,6 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7221,17 +7166,6 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7258,19 +7192,6 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7296,18 +7217,6 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7328,19 +7237,6 @@ static struct snd_kcontrol_new alc883_tagra_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7356,19 +7252,6 @@ static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = { HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7381,17 +7264,6 @@ static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7405,19 +7277,6 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7431,19 +7290,6 @@ static struct snd_kcontrol_new alc883_medion_md2_mixer[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7456,19 +7302,6 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7496,19 +7329,6 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7539,6 +7359,10 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol), HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch), { @@ -8203,9 +8027,6 @@ static struct hda_verb alc883_auto_init_verbs[] = { { } }; -/* capture mixer elements */ -#define alc883_capture_mixer alc880_capture_alt_mixer /* 2 ADC ver */ - static struct hda_verb alc888_asus_m90v_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -8485,6 +8306,8 @@ static struct alc_config_preset alc883_presets[] = { .init_verbs = { alc883_init_verbs, alc883_tagra_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, + .adc_nids = alc883_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), .dig_out_nid = ALC883_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, @@ -8525,6 +8348,8 @@ static struct alc_config_preset alc883_presets[] = { alc883_medion_eapd_verbs }, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, + .adc_nids = alc883_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, @@ -8567,6 +8392,8 @@ static struct alc_config_preset alc883_presets[] = { .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, + .adc_nids = alc883_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_lenovo_101e_capture_source, @@ -8663,8 +8490,6 @@ static struct alc_config_preset alc883_presets[] = { .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, .dig_out_nid = ALC883_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .need_dac_fix = 1, @@ -8688,6 +8513,7 @@ static struct alc_config_preset alc883_presets[] = { }, [ALC888_ASUS_EEE1601] = { .mixers = { alc883_asus_eee1601_mixer }, + .cap_mixer = alc883_asus_eee1601_cap_mixer, .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs }, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, @@ -8794,7 +8620,6 @@ static int alc883_parse_auto_config(struct hda_codec *codec) /* hack - override the init verbs */ spec->init_verbs[0] = alc883_auto_init_verbs; - add_mixer(spec, alc883_capture_mixer); return 1; /* config found */ } @@ -8877,10 +8702,15 @@ static int patch_alc883(struct hda_codec *codec) spec->stream_digital_playback = &alc883_pcm_digital_playback; spec->stream_digital_capture = &alc883_pcm_digital_capture; - spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); - spec->adc_nids = alc883_adc_nids; - spec->capsrc_nids = alc883_capsrc_nids; + if (!spec->num_adc_nids) { + spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); + spec->adc_nids = alc883_adc_nids; + } + if (!spec->capsrc_nids) + spec->capsrc_nids = alc883_capsrc_nids; spec->is_mix_capture = 1; /* matrix-style capture */ + if (!spec->cap_mixer) + set_capture_mixer(spec); spec->vmaster_nid = 0x0c; @@ -9371,20 +9201,6 @@ static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -10556,7 +10372,8 @@ static struct alc_config_preset alc262_presets[] = { .init_hook = alc262_hippo_automute, }, [ALC262_ULTRA] = { - .mixers = { alc262_ultra_mixer, alc262_ultra_capture_mixer }, + .mixers = { alc262_ultra_mixer }, + .cap_mixer = alc262_ultra_capture_mixer, .init_verbs = { alc262_ultra_verbs }, .num_dacs = ARRAY_SIZE(alc262_dac_nids), .dac_nids = alc262_dac_nids, @@ -10693,14 +10510,14 @@ static int patch_alc262(struct hda_codec *codec) spec->adc_nids = alc262_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt); spec->capsrc_nids = alc262_capsrc_nids_alt; - add_mixer(spec, alc262_capture_alt_mixer); } else { spec->adc_nids = alc262_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids); spec->capsrc_nids = alc262_capsrc_nids; - add_mixer(spec, alc262_capture_mixer); } } + if (!spec->cap_mixer) + set_capture_mixer(spec); spec->vmaster_nid = 0x0c; @@ -11832,25 +11649,6 @@ static struct snd_kcontrol_new alc269_eeepc_mixer[] = { { } /* end */ }; -/* capture mixer elements */ -static struct snd_kcontrol_new alc269_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - /* capture mixer elements */ static struct snd_kcontrol_new alc269_epc_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), @@ -12247,7 +12045,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - add_mixer(spec, alc269_capture_mixer); + if (!spec->cap_mixer) + set_capture_mixer(spec); store_pin_configs(codec); return 1; @@ -12292,7 +12091,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = { static struct alc_config_preset alc269_presets[] = { [ALC269_BASIC] = { - .mixers = { alc269_base_mixer, alc269_capture_mixer }, + .mixers = { alc269_base_mixer }, .init_verbs = { alc269_init_verbs }, .num_dacs = ARRAY_SIZE(alc269_dac_nids), .dac_nids = alc269_dac_nids, @@ -12314,7 +12113,8 @@ static struct alc_config_preset alc269_presets[] = { .init_hook = alc269_quanta_fl1_init_hook, }, [ALC269_ASUS_EEEPC_P703] = { - .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer }, + .mixers = { alc269_eeepc_mixer }, + .cap_mixer = alc269_epc_capture_mixer, .init_verbs = { alc269_init_verbs, alc269_eeepc_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc269_dac_nids), @@ -12327,7 +12127,8 @@ static struct alc_config_preset alc269_presets[] = { .init_hook = alc269_eeepc_amic_inithook, }, [ALC269_ASUS_EEEPC_P901] = { - .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer}, + .mixers = { alc269_eeepc_mixer }, + .cap_mixer = alc269_epc_capture_mixer, .init_verbs = { alc269_init_verbs, alc269_eeepc_dmic_init_verbs }, .num_dacs = ARRAY_SIZE(alc269_dac_nids), @@ -12393,6 +12194,8 @@ static int patch_alc269(struct hda_codec *codec) spec->adc_nids = alc269_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); spec->capsrc_nids = alc269_capsrc_nids; + if (!spec->cap_mixer) + set_capture_mixer(spec); codec->patch_ops = alc_patch_ops; if (board_config == ALC269_AUTO) @@ -12533,17 +12336,6 @@ static struct snd_kcontrol_new alc861_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - /* Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -12567,17 +12359,6 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - /* Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -12595,18 +12376,6 @@ static struct snd_kcontrol_new alc861_toshiba_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - /*Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ }; @@ -12630,17 +12399,6 @@ static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - /* Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -12672,17 +12430,6 @@ static struct snd_kcontrol_new alc861_asus_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), - /* Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -13214,25 +12961,6 @@ static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec, return 0; } -static struct snd_kcontrol_new alc861_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - static void alc861_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, int dac_idx) @@ -13333,7 +13061,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) spec->adc_nids = alc861_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); - add_mixer(spec, alc861_capture_mixer); + set_capture_mixer(spec); store_pin_configs(codec); return 1; @@ -13674,25 +13402,6 @@ static struct snd_kcontrol_new alc861vd_chmode_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc861vd_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ @@ -14516,7 +14225,7 @@ static int patch_alc861vd(struct hda_codec *codec) spec->capsrc_nids = alc861vd_capsrc_nids; spec->is_mix_capture = 1; - add_mixer(spec, alc861vd_capture_mixer); + set_capture_mixer(spec); spec->vmaster_nid = 0x02; @@ -15188,25 +14897,6 @@ static struct hda_verb alc662_ecs_init_verbs[] = { {} }; -/* capture mixer elements */ -static struct snd_kcontrol_new alc662_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - static struct snd_kcontrol_new alc662_auto_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), @@ -15778,7 +15468,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { static struct alc_config_preset alc662_presets[] = { [ALC662_3ST_2ch_DIG] = { - .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer }, + .mixers = { alc662_3ST_2ch_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15789,8 +15479,7 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_3ST_6ch_DIG] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer, - alc662_capture_mixer }, + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15802,8 +15491,7 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_3ST_6ch] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer, - alc662_capture_mixer }, + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15813,8 +15501,7 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_5ST_DIG] = { - .mixers = { alc662_base_mixer, alc662_chmode_mixer, - alc662_capture_mixer }, + .mixers = { alc662_base_mixer, alc662_chmode_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15825,7 +15512,7 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_LENOVO_101E] = { - .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer }, + .mixers = { alc662_lenovo_101e_mixer }, .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15836,7 +15523,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_lenovo_101e_all_automute, }, [ALC662_ASUS_EEEPC_P701] = { - .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer }, + .mixers = { alc662_eeepc_p701_mixer }, .init_verbs = { alc662_init_verbs, alc662_eeepc_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -15848,7 +15535,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_eeepc_inithook, }, [ALC662_ASUS_EEEPC_EP20] = { - .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer, + .mixers = { alc662_eeepc_ep20_mixer, alc662_chmode_mixer }, .init_verbs = { alc662_init_verbs, alc662_eeepc_ep20_sue_init_verbs }, @@ -15861,7 +15548,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_eeepc_ep20_inithook, }, [ALC662_ECS] = { - .mixers = { alc662_ecs_mixer, alc662_capture_mixer }, + .mixers = { alc662_ecs_mixer }, .init_verbs = { alc662_init_verbs, alc662_ecs_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -15873,7 +15560,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_eeepc_inithook, }, [ALC663_ASUS_M51VA] = { - .mixers = { alc663_m51va_mixer, alc662_capture_mixer}, + .mixers = { alc663_m51va_mixer }, .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15885,7 +15572,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_m51va_inithook, }, [ALC663_ASUS_G71V] = { - .mixers = { alc663_g71v_mixer, alc662_capture_mixer}, + .mixers = { alc663_g71v_mixer }, .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15897,7 +15584,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_g71v_inithook, }, [ALC663_ASUS_H13] = { - .mixers = { alc663_m51va_mixer, alc662_capture_mixer}, + .mixers = { alc663_m51va_mixer }, .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15908,7 +15595,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_m51va_inithook, }, [ALC663_ASUS_G50V] = { - .mixers = { alc663_g50v_mixer, alc662_capture_mixer}, + .mixers = { alc663_g50v_mixer }, .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15920,7 +15607,8 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_g50v_inithook, }, [ALC663_ASUS_MODE1] = { - .mixers = { alc663_m51va_mixer, alc662_auto_capture_mixer }, + .mixers = { alc663_m51va_mixer }, + .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, alc663_21jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -15934,7 +15622,8 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_mode1_inithook, }, [ALC662_ASUS_MODE2] = { - .mixers = { alc662_1bjd_mixer, alc662_auto_capture_mixer }, + .mixers = { alc662_1bjd_mixer }, + .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, alc662_1bjd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -15947,7 +15636,8 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_mode2_inithook, }, [ALC663_ASUS_MODE3] = { - .mixers = { alc663_two_hp_m1_mixer, alc662_auto_capture_mixer }, + .mixers = { alc663_two_hp_m1_mixer }, + .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, alc663_two_hp_amic_m1_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -15961,8 +15651,8 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_mode3_inithook, }, [ALC663_ASUS_MODE4] = { - .mixers = { alc663_asus_21jd_clfe_mixer, - alc662_auto_capture_mixer}, + .mixers = { alc663_asus_21jd_clfe_mixer }, + .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, alc663_21jd_amic_init_verbs}, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -15976,8 +15666,8 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_mode4_inithook, }, [ALC663_ASUS_MODE5] = { - .mixers = { alc663_asus_15jd_clfe_mixer, - alc662_auto_capture_mixer }, + .mixers = { alc663_asus_15jd_clfe_mixer }, + .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, alc663_15jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -15991,7 +15681,8 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_mode5_inithook, }, [ALC663_ASUS_MODE6] = { - .mixers = { alc663_two_hp_m2_mixer, alc662_auto_capture_mixer }, + .mixers = { alc663_two_hp_m2_mixer }, + .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, alc663_two_hp_amic_m2_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -16266,8 +15957,6 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - add_mixer(spec, alc662_capture_mixer); - store_pin_configs(codec); return 1; } @@ -16345,6 +16034,9 @@ static int patch_alc662(struct hda_codec *codec) spec->capsrc_nids = alc662_capsrc_nids; spec->is_mix_capture = 1; + if (!spec->cap_mixer) + set_capture_mixer(spec); + spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; -- cgit v1.2.3 From 3c3e9892a1dacca2ba9e05c196ab1ea99c544360 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 31 Oct 2008 17:48:56 +0100 Subject: ALSA: hda - Re-add input-source control for Realtek Re-added again "Input Source" control that was removed mistakenly in the previous patchset. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d511ce4b11a..88e54db0582 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1351,6 +1351,15 @@ static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ .put = alc_cap_vol_put, \ .tlv = { .c = alc_cap_vol_tlv }, \ }, \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + /* .name = "Capture Source", */ \ + .name = "Input Source", \ + .count = num, \ + .info = alc_mux_enum_info, \ + .get = alc_mux_enum_get, \ + .put = alc_mux_enum_put, \ + }, \ { } /* end */ \ } -- cgit v1.2.3 From 26f5df265f06b8c8fe9f5d0942b7d8df00e5edec Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 3 Nov 2008 17:39:46 +0100 Subject: ALSA: hda - Add ALC299 fujitsu preset model Added a preset model for FSC Amilo with ALC269 codec chip. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 2 ++ sound/pci/hda/patch_realtek.c | 29 ++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index e0e54a27fc1..fa8e9fadfaf 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -857,6 +857,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. quanta Quanta FL1 eeepc-p703 ASUS Eeepc P703 P900A eeepc-p901 ASUS Eeepc P901 S101 + fujitsu FSC Amilo + auto auto-config reading BIOS (default) ALC662/663 3stack-dig 3-stack (2-channel) with SPDIF diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 88e54db0582..700fc8632c6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -130,6 +130,7 @@ enum { ALC269_QUANTA_FL1, ALC269_ASUS_EEEPC_P703, ALC269_ASUS_EEEPC_P901, + ALC269_FUJITSU, ALC269_AUTO, ALC269_MODEL_LAST /* last tag */ }; @@ -1726,6 +1727,7 @@ static const char *alc_slave_vols[] = { "Speaker Playback Volume", "Mono Playback Volume", "Line-Out Playback Volume", + "PCM Playback Volume", NULL, }; @@ -11662,6 +11664,15 @@ static struct snd_kcontrol_new alc269_eeepc_mixer[] = { static struct snd_kcontrol_new alc269_epc_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +/* FSC amilo */ +static struct snd_kcontrol_new alc269_fujitsu_mixer[] = { + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol), { } /* end */ }; @@ -12084,7 +12095,8 @@ static const char *alc269_models[ALC269_MODEL_LAST] = { [ALC269_BASIC] = "basic", [ALC269_QUANTA_FL1] = "quanta", [ALC269_ASUS_EEEPC_P703] = "eeepc-p703", - [ALC269_ASUS_EEEPC_P901] = "eeepc-p901" + [ALC269_ASUS_EEEPC_P901] = "eeepc-p901", + [ALC269_FUJITSU] = "fujitsu" }; static struct snd_pci_quirk alc269_cfg_tbl[] = { @@ -12095,6 +12107,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = { ALC269_ASUS_EEEPC_P901), SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", ALC269_ASUS_EEEPC_P901), + SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), {} }; @@ -12149,6 +12162,20 @@ static struct alc_config_preset alc269_presets[] = { .unsol_event = alc269_eeepc_dmic_unsol_event, .init_hook = alc269_eeepc_dmic_inithook, }, + [ALC269_FUJITSU] = { + .mixers = { alc269_fujitsu_mixer, alc269_beep_mixer }, + .cap_mixer = alc269_epc_capture_mixer, + .init_verbs = { alc269_init_verbs, + alc269_eeepc_dmic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_eeepc_dmic_capture_source, + .unsol_event = alc269_eeepc_dmic_unsol_event, + .init_hook = alc269_eeepc_dmic_inithook, + }, }; static int patch_alc269(struct hda_codec *codec) -- cgit v1.2.3 From 4ef0ef1966dae9e9e29762e4e719af3cfd146ca0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 3 Nov 2008 17:47:49 +0100 Subject: ALSA: hda - Fix missing ADC list in ALC260 auto-probe mode The commit f9e336f65b666b8f1764d17e9b7c21c90748a37e ALSA: hda - Unify capture mixer creation in realtek codes removed the ADC check for ALC260 auto-probe mode accidentally. Re-added to patch_alc260() again. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 700fc8632c6..e727e48a48e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5618,6 +5618,19 @@ static int patch_alc260(struct hda_codec *codec) spec->stream_digital_playback = &alc260_pcm_digital_playback; spec->stream_digital_capture = &alc260_pcm_digital_capture; + if (!spec->adc_nids && spec->input_mux) { + /* check whether NID 0x04 is valid */ + unsigned int wcap = get_wcaps(codec, 0x04); + wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + /* get type */ + if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { + spec->adc_nids = alc260_adc_nids_alt; + spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt); + } else { + spec->adc_nids = alc260_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); + } + } set_capture_mixer(spec); spec->vmaster_nid = 0x08; -- cgit v1.2.3 From b91f080f517cf9dd52023c11127a0ca33190e31a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 Nov 2008 08:43:08 +0100 Subject: ALSA: hda - Fix possible NULL dereference Add NULL-check of the return value of snd_kctl_new1() before accessing it. Also, make a sanity NULL check to snd_BUG_ON() for debugging only. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8991db78fb6..aa9cd142c30 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1697,6 +1697,8 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) } for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { kctl = snd_ctl_new1(dig_mix, codec); + if (!kctl) + return -ENOMEM; kctl->id.index = idx; kctl->private_value = nid; err = snd_hda_ctl_add(codec, kctl); @@ -2412,7 +2414,7 @@ snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) struct hda_pcm_stream *info; int stream, err; - if (!pcm->name) + if (snd_BUG_ON(!pcm->name)) return -EINVAL; for (stream = 0; stream < 2; stream++) { info = &pcm->stream[stream]; -- cgit v1.2.3 From bfc5c26fb692fa7a196108c3b23d9c747d105c00 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 Nov 2008 17:48:39 +0100 Subject: ALSA: hda - Don't create empty PCM streams Due to the hda-reconfiguration patches, the check of empty stream is gone, and this results in an error with the codec setup with empty streams. This patch adds the check again to avoid the error at probing. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index aa9cd142c30..3e7cda9c3de 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2485,6 +2485,11 @@ int snd_hda_build_pcms(struct hda_bus *bus) struct hda_pcm *cpcm = &codec->pcm_info[pcm]; int type = cpcm->pcm_type; int dev; + + if (!cpcm->stream[0].substreams && + !cpcm->stream[1].substreams) + continue; /* no substreams assigned */ + switch (type) { case HDA_PCM_TYPE_AUDIO: if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { -- cgit v1.2.3 From 91504877c50a792412e2043a1c2099f054d7254a Mon Sep 17 00:00:00 2001 From: "Wu, Fengguang" Date: Wed, 5 Nov 2008 11:16:56 +0800 Subject: ALSA: hda - Intel HDMI audio support Add support for Intel G45 integrated HDMI audio codecs. This initial release supports: - 2 channel stereo sound output - report monitor's ELD information Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 8 + sound/pci/hda/Makefile | 1 + sound/pci/hda/hda_codec.c | 3 + sound/pci/hda/hda_patch.h | 2 + sound/pci/hda/patch_intelhdmi.c | 926 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 940 insertions(+) create mode 100644 sound/pci/hda/patch_intelhdmi.c diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 7e408908b75..21e9327a0ef 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -574,6 +574,14 @@ config SND_HDA_CODEC_NVHDMI Say Y here to include NVIDIA HDMI HD-audio codec support in snd-hda-intel driver, such as NVIDIA MCP78 HDMI. +config SND_HDA_CODEC_INTELHDMI + bool "Build INTEL HDMI HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include INTEL HDMI HD-audio codec support in + snd-hda-intel driver, such as Eaglelake integrated HDMI. + config SND_HDA_CODEC_CONEXANT bool "Build Conexant HD-audio codec support" depends on SND_HDA_INTEL diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 1980c6d207e..6fb5add1e39 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -16,5 +16,6 @@ snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_INTELHDMI) += patch_intelhdmi.o obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3e7cda9c3de..45695d608c7 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -97,6 +97,9 @@ static const struct hda_codec_preset *hda_preset_tables[] = { #endif #ifdef CONFIG_SND_HDA_CODEC_NVHDMI snd_hda_preset_nvhdmi, +#endif +#ifdef CONFIG_SND_HDA_CODEC_INTELHDMI + snd_hda_preset_intelhdmi, #endif NULL }; diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index dfbcfa88da4..38212c1020a 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h @@ -20,3 +20,5 @@ extern struct hda_codec_preset snd_hda_preset_conexant[]; extern struct hda_codec_preset snd_hda_preset_via[]; /* NVIDIA HDMI codecs */ extern struct hda_codec_preset snd_hda_preset_nvhdmi[]; +/* INTEL HDMI codecs */ +extern struct hda_codec_preset snd_hda_preset_intelhdmi[]; diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c new file mode 100644 index 00000000000..8059102dd86 --- /dev/null +++ b/sound/pci/hda/patch_intelhdmi.c @@ -0,0 +1,926 @@ +/* + * + * patch_intelhdmi.c - Patch for Intel HDMI codecs + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * Authors: + * Jiang Zhe + * Wu Fengguang + * + * Maintained by: + * Wu Fengguang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include "hda_codec.h" +#include "hda_local.h" +#include "hda_patch.h" + +#define CVT_NID 0x02 /* audio converter */ +#define PIN_NID 0x03 /* HDMI output pin */ + +#define INTEL_HDMI_EVENT_TAG 0x08 + +/* + * CEA Short Audio Descriptor data + */ +struct cea_sad { + int channels; + int format; /* (format == 0) indicates invalid SAD */ + int rates; + int sample_bits; /* for LPCM */ + int max_bitrate; /* for AC3...ATRAC */ + int profile; /* for WMAPRO */ +}; + +#define ELD_FIXED_BYTES 20 +#define ELD_MAX_MNL 16 +#define ELD_MAX_SAD 16 + +/* + * ELD: EDID Like Data + */ +struct sink_eld { + int eld_size; + int baseline_len; + int eld_ver; /* (eld_ver == 0) indicates invalid ELD */ + int cea_edid_ver; + char monitor_name[ELD_MAX_MNL + 1]; + int manufacture_id; + int product_id; + u64 port_id; + int support_hdcp; + int support_ai; + int conn_type; + int aud_synch_delay; + int spk_alloc; + int sad_count; + struct cea_sad sad[ELD_MAX_SAD]; +}; + +struct intel_hdmi_spec { + struct hda_multi_out multiout; + struct hda_pcm pcm_rec; + struct sink_eld sink; +}; + +static struct hda_verb pinout_enable_verb[] = { + {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {} /* terminator */ +}; + +static struct hda_verb pinout_disable_verb[] = { + {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00}, + {} +}; + +static struct hda_verb unsolicited_response_verb[] = { + {PIN_NID, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | + INTEL_HDMI_EVENT_TAG}, + {} +}; + +static struct hda_verb def_chan_map[] = { + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x00}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x11}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x22}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x33}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x44}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x55}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x66}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x77}, + {} +}; + + +struct hdmi_audio_infoframe { + u8 type; /* 0x84 */ + u8 ver; /* 0x01 */ + u8 len; /* 0x0a */ + + u8 checksum; /* PB0 */ + u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ + u8 SS01_SF24; + u8 CXT04; + u8 CA; + u8 LFEPBL01_LSV36_DM_INH7; + u8 reserved[5]; /* PB6 - PB10 */ +}; + +/* + * SS1:SS0 index => sample size + */ +static int cea_sample_sizes[4] = { + 0, /* 0: Refer to Stream Header */ + AC_SUPPCM_BITS_16, /* 1: 16 bits */ + AC_SUPPCM_BITS_20, /* 2: 20 bits */ + AC_SUPPCM_BITS_24, /* 3: 24 bits */ +}; + +/* + * SF2:SF1:SF0 index => sampling frequency + */ +static int cea_sampling_frequencies[8] = { + 0, /* 0: Refer to Stream Header */ + SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ + SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ + SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ + SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ + SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ + SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ + SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ +}; + +enum eld_versions { + ELD_VER_CEA_861D = 2, + ELD_VER_PARTIAL = 31, +}; + +static char *eld_versoin_names[32] = { + "0-reserved", + "1-reserved", + "CEA-861D or below", + "3-reserved", + [4 ... 30] = "reserved", + [31] = "partial" +}; + +enum cea_edid_versions { + CEA_EDID_VER_NONE = 0, + CEA_EDID_VER_CEA861 = 1, + CEA_EDID_VER_CEA861A = 2, + CEA_EDID_VER_CEA861BCD = 3, + CEA_EDID_VER_RESERVED = 4, +}; + +static char *cea_edid_version_names[8] = { + "no CEA EDID Timing Extension block present", + "CEA-861", + "CEA-861-A", + "CEA-861-B, C or D", + "4-reserved", + [5 ... 7] = "reserved" +}; + +/* + * CEA Speaker Allocation data block bits + */ +#define CEA_SA_FLR (0 << 0) +#define CEA_SA_LFE (1 << 1) +#define CEA_SA_FC (1 << 2) +#define CEA_SA_RLR (1 << 3) +#define CEA_SA_RC (1 << 4) +#define CEA_SA_FLRC (1 << 5) +#define CEA_SA_RLRC (1 << 6) +/* the following are not defined in ELD yet */ +#define CEA_SA_FLRW (1 << 7) +#define CEA_SA_FLRH (1 << 8) +#define CEA_SA_TC (1 << 9) +#define CEA_SA_FCH (1 << 10) + +static char *cea_speaker_allocation_names[] = { + /* 0 */ "FL/FR", + /* 1 */ "LFE", + /* 2 */ "FC", + /* 3 */ "RL/RR", + /* 4 */ "RC", + /* 5 */ "FLC/FRC", + /* 6 */ "RLC/RRC", + /* 7 */ "FLW/FRW", + /* 8 */ "FLH/FRH", + /* 9 */ "TC", + /* 10 */ "FCH", +}; + +static char *eld_connection_type_names[4] = { + "HDMI", + "Display Port", + "2-reserved", + "3-reserved" +}; + +enum cea_audio_coding_types { + AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, + AUDIO_CODING_TYPE_LPCM = 1, + AUDIO_CODING_TYPE_AC3 = 2, + AUDIO_CODING_TYPE_MPEG1 = 3, + AUDIO_CODING_TYPE_MP3 = 4, + AUDIO_CODING_TYPE_MPEG2 = 5, + AUDIO_CODING_TYPE_AACLC = 6, + AUDIO_CODING_TYPE_DTS = 7, + AUDIO_CODING_TYPE_ATRAC = 8, + AUDIO_CODING_TYPE_SACD = 9, + AUDIO_CODING_TYPE_EAC3 = 10, + AUDIO_CODING_TYPE_DTS_HD = 11, + AUDIO_CODING_TYPE_MLP = 12, + AUDIO_CODING_TYPE_DST = 13, + AUDIO_CODING_TYPE_WMAPRO = 14, + AUDIO_CODING_TYPE_REF_CXT = 15, + /* also include valid xtypes below */ + AUDIO_CODING_TYPE_HE_AAC = 15, + AUDIO_CODING_TYPE_HE_AAC2 = 16, + AUDIO_CODING_TYPE_MPEG_SURROUND = 17, +}; + +enum cea_audio_coding_xtypes { + AUDIO_CODING_XTYPE_HE_REF_CT = 0, + AUDIO_CODING_XTYPE_HE_AAC = 1, + AUDIO_CODING_XTYPE_HE_AAC2 = 2, + AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, + AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, +}; + +static char *cea_audio_coding_type_names[] = { + /* 0 */ "undefined", + /* 1 */ "LPCM", + /* 2 */ "AC-3", + /* 3 */ "MPEG1", + /* 4 */ "MP3", + /* 5 */ "MPEG2", + /* 6 */ "AAC-LC", + /* 7 */ "DTS", + /* 8 */ "ATRAC", + /* 9 */ "DSD(1-bit audio)", + /* 10 */ "Dolby Digital Plus(E-AC-3/DD+)", + /* 11 */ "DTS-HD", + /* 12 */ "Dolby TrueHD(MLP)", + /* 13 */ "DST", + /* 14 */ "WMAPro", + /* 15 */ "HE-AAC", + /* 16 */ "HE-AACv2", + /* 17 */ "MPEG Surround", +}; + + +/* + * HDMI routines + */ + +static int hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, + AC_DIPSIZE_ELD_BUF); +} + +static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, + int *packet_index, int *byte_index) +{ + int val; + + val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_INDEX, 0); + + *packet_index = val >> 5; + *byte_index = val & 0x1f; +} + +static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid, + int packet_index, int byte_index) +{ + int val; + + val = (packet_index << 5) | (byte_index & 0x1f); + + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); +} + +static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, + unsigned char val) +{ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); +} + +static void hdmi_enable_output(struct hda_codec *codec) +{ + /* Enable pin out and unmute */ + snd_hda_sequence_write(codec, pinout_enable_verb); + if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, PIN_NID, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + + /* Enable Audio InfoFrame Transmission */ + hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); + snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, + AC_DIPXMIT_BEST); +} + +static void hdmi_disable_output(struct hda_codec *codec) +{ + snd_hda_sequence_write(codec, pinout_disable_verb); + if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, PIN_NID, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + /* + * FIXME: noises may arise when playing music after reloading the + * kernel module, until the next X restart or monitor repower. + */ +} + +static int hdmi_get_channel_count(struct hda_codec *codec) +{ + return 1 + snd_hda_codec_read(codec, CVT_NID, 0, + AC_VERB_GET_CVT_CHAN_COUNT, 0); +} + +static void hdmi_set_channel_count(struct hda_codec *codec, int chs) +{ + snd_hda_codec_write(codec, CVT_NID, 0, + AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); + + if (chs != hdmi_get_channel_count(codec)) + snd_printd(KERN_INFO "Channel count expect=%d, real=%d\n", + chs, hdmi_get_channel_count(codec)); +} + +static void hdmi_debug_slot_mapping(struct hda_codec *codec) +{ +#ifdef CONFIG_SND_DEBUG_VERBOSE + int i; + int slot; + + for (i = 0; i < 8; i++) { + slot = snd_hda_codec_read(codec, CVT_NID, 0, + AC_VERB_GET_HDMI_CHAN_SLOT, i); + printk(KERN_DEBUG "ASP channel %d => slot %d\n", + slot >> 4, slot & 0x7); + } +#endif +} + +static void hdmi_setup_channel_mapping(struct hda_codec *codec) +{ + snd_hda_sequence_write(codec, def_chan_map); + hdmi_debug_slot_mapping(codec); +} + + +/* + * ELD(EDID Like Data) routines + */ + +static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); +} + +static void hdmi_debug_present_sense(struct hda_codec *codec) +{ +#ifdef CONFIG_SND_DEBUG_VERBOSE + int eldv; + int present; + + present = hdmi_present_sense(codec, PIN_NID); + eldv = (present & AC_PINSENSE_ELDV); + present = (present & AC_PINSENSE_PRESENCE); + + printk(KERN_INFO "pinp = %d, eldv = %d\n", !!present, !!eldv); +#endif +} + +static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, int byte_index) +{ + unsigned int val; + + val = snd_hda_codec_read(codec, PIN_NID, 0, + AC_VERB_GET_HDMI_ELDD, byte_index); + +#ifdef BE_PARANOID + printk(KERN_INFO "ELD data byte %d: 0x%x\n", byte_index, val); +#endif + + if ((val & AC_ELDD_ELD_VALID) == 0) { + snd_printd(KERN_INFO "Invalid ELD data byte %d\n", + byte_index); + val = 0; + } + + return val & AC_ELDD_ELD_DATA; +} + +static inline unsigned char grab_bits(const unsigned char *buf, + int byte, int lowbit, int bits) +{ + BUG_ON(lowbit > 7); + BUG_ON(bits > 8); + BUG_ON(bits <= 0); + + return (buf[byte] >> lowbit) & ((1 << bits) - 1); +} + +static void hdmi_update_short_audio_desc(struct cea_sad *a, + const unsigned char *buf) +{ + int i; + int val; + + val = grab_bits(buf, 1, 0, 7); + a->rates = 0; + for (i = 0; i < 7; i++) + if (val & (1 << i)) + a->rates |= cea_sampling_frequencies[i + 1]; + + a->channels = grab_bits(buf, 0, 0, 3); + a->channels++; + + a->format = grab_bits(buf, 0, 3, 4); + switch (a->format) { + case AUDIO_CODING_TYPE_REF_STREAM_HEADER: + snd_printd(KERN_INFO + "audio coding type 0 not expected in ELD\n"); + break; + + case AUDIO_CODING_TYPE_LPCM: + val = grab_bits(buf, 2, 0, 3); + a->sample_bits = 0; + for (i = 0; i < 3; i++) + if (val & (1 << i)) + a->sample_bits |= cea_sample_sizes[i + 1]; + break; + + case AUDIO_CODING_TYPE_AC3: + case AUDIO_CODING_TYPE_MPEG1: + case AUDIO_CODING_TYPE_MP3: + case AUDIO_CODING_TYPE_MPEG2: + case AUDIO_CODING_TYPE_AACLC: + case AUDIO_CODING_TYPE_DTS: + case AUDIO_CODING_TYPE_ATRAC: + a->max_bitrate = grab_bits(buf, 2, 0, 8); + a->max_bitrate *= 8000; + break; + + case AUDIO_CODING_TYPE_SACD: + break; + + case AUDIO_CODING_TYPE_EAC3: + break; + + case AUDIO_CODING_TYPE_DTS_HD: + break; + + case AUDIO_CODING_TYPE_MLP: + break; + + case AUDIO_CODING_TYPE_DST: + break; + + case AUDIO_CODING_TYPE_WMAPRO: + a->profile = grab_bits(buf, 2, 0, 3); + break; + + case AUDIO_CODING_TYPE_REF_CXT: + a->format = grab_bits(buf, 2, 3, 5); + if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || + a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { + snd_printd(KERN_INFO + "audio coding xtype %d not expected in ELD\n", + a->format); + a->format = 0; + } else + a->format += AUDIO_CODING_TYPE_HE_AAC - + AUDIO_CODING_XTYPE_HE_AAC; + break; + } +} + +static int hdmi_update_sink_eld(struct hda_codec *codec, + const unsigned char *buf, int size) +{ + struct intel_hdmi_spec *spec = codec->spec; + struct sink_eld *e = &spec->sink; + int mnl; + int i; + + e->eld_ver = grab_bits(buf, 0, 3, 5); + if (e->eld_ver != ELD_VER_CEA_861D && + e->eld_ver != ELD_VER_PARTIAL) { + snd_printd(KERN_INFO "Unknown ELD version %d\n", e->eld_ver); + goto out_fail; + } + + e->eld_size = size; + e->baseline_len = grab_bits(buf, 2, 0, 8); + mnl = grab_bits(buf, 4, 0, 5); + e->cea_edid_ver = grab_bits(buf, 4, 5, 3); + + e->support_hdcp = grab_bits(buf, 5, 0, 1); + e->support_ai = grab_bits(buf, 5, 1, 1); + e->conn_type = grab_bits(buf, 5, 2, 2); + e->sad_count = grab_bits(buf, 5, 4, 4); + + e->aud_synch_delay = grab_bits(buf, 6, 0, 8); + e->spk_alloc = grab_bits(buf, 7, 0, 7); + + e->port_id = get_unaligned_le64(buf + 8); + + /* not specified, but the spec's tendency is little endian */ + e->manufacture_id = get_unaligned_le16(buf + 16); + e->product_id = get_unaligned_le16(buf + 18); + + if (mnl > ELD_MAX_MNL) { + snd_printd(KERN_INFO "MNL is reserved value %d\n", mnl); + goto out_fail; + } else if (ELD_FIXED_BYTES + mnl > size) { + snd_printd(KERN_INFO "out of range MNL %d\n", mnl); + goto out_fail; + } else + strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl); + + for (i = 0; i < e->sad_count; i++) { + if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { + snd_printd(KERN_INFO "out of range SAD %d\n", i); + goto out_fail; + } + hdmi_update_short_audio_desc(e->sad + i, + buf + ELD_FIXED_BYTES + mnl + 3 * i); + } + + return 0; + +out_fail: + e->eld_ver = 0; + return -EINVAL; +} + +static int hdmi_get_eld(struct hda_codec *codec) +{ + int i; + int ret; + int size; + unsigned char *buf; + + i = hdmi_present_sense(codec, PIN_NID) & AC_PINSENSE_ELDV; + if (!i) + return -ENOENT; + + size = hdmi_get_eld_size(codec, PIN_NID); + if (size == 0) { + /* wfg: workaround for ASUS P5E-VM HDMI board */ + snd_printd(KERN_INFO "ELD buf size is 0, force 128\n"); + size = 128; + } + if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { + snd_printd(KERN_INFO "Invalid ELD buf size %d\n", size); + return -ERANGE; + } + + buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (i = 0; i < size; i++) + buf[i] = hdmi_get_eld_byte(codec, i); + + ret = hdmi_update_sink_eld(codec, buf, size); + + kfree(buf); + return ret; +} + +static void hdmi_show_short_audio_desc(struct cea_sad *a) +{ + printk(KERN_INFO "coding type: %s\n", + cea_audio_coding_type_names[a->format]); + printk(KERN_INFO "channels: %d\n", a->channels); + printk(KERN_INFO "sampling frequencies: 0x%x\n", a->rates); + + if (a->format == AUDIO_CODING_TYPE_LPCM) + printk(KERN_INFO "sample bits: 0x%x\n", a->sample_bits); + + if (a->max_bitrate) + printk(KERN_INFO "max bitrate: %d HZ\n", a->max_bitrate); + + if (a->profile) + printk(KERN_INFO "profile: %d\n", a->profile); +} + +static void hdmi_show_eld(struct hda_codec *codec) +{ + int i; + int j; + struct intel_hdmi_spec *spec = codec->spec; + struct sink_eld *e = &spec->sink; + char buf[80]; + + printk(KERN_INFO "ELD buffer size is %d\n", e->eld_size); + printk(KERN_INFO "ELD baseline len is %d*4\n", e->baseline_len); + printk(KERN_INFO "vendor block len is %d\n", + e->eld_size - e->baseline_len * 4 - 4); + printk(KERN_INFO "ELD version is %s\n", + eld_versoin_names[e->eld_ver]); + printk(KERN_INFO "CEA EDID version is %s\n", + cea_edid_version_names[e->cea_edid_ver]); + printk(KERN_INFO "manufacture id is 0x%x\n", e->manufacture_id); + printk(KERN_INFO "product id is 0x%x\n", e->product_id); + printk(KERN_INFO "port id is 0x%llx\n", (long long)e->port_id); + printk(KERN_INFO "HDCP support is %d\n", e->support_hdcp); + printk(KERN_INFO "AI support is %d\n", e->support_ai); + printk(KERN_INFO "SAD count is %d\n", e->sad_count); + printk(KERN_INFO "audio sync delay is %x\n", e->aud_synch_delay); + printk(KERN_INFO "connection type is %s\n", + eld_connection_type_names[e->conn_type]); + printk(KERN_INFO "monitor name is %s\n", e->monitor_name); + + j = 0; + for (i = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { + if (e->spk_alloc & (1 << i)) + j += snprintf(buf + j, sizeof(buf) - j, " %s", + cea_speaker_allocation_names[i]); + } + buf[j] = '\0'; /* necessary when j == 0 */ + printk(KERN_INFO "speaker allocations: (0x%x)%s\n", e->spk_alloc, buf); + + for (i = 0; i < e->sad_count; i++) + hdmi_show_short_audio_desc(e->sad + i); +} + +/* + * Be careful, ELD buf could be totally rubbish! + */ +static void hdmi_parse_eld(struct hda_codec *codec) +{ + hdmi_debug_present_sense(codec); + + if (!hdmi_get_eld(codec)) + hdmi_show_eld(codec); +} + + +/* + * Audio Infoframe routines + */ + +static void hdmi_debug_dip_size(struct hda_codec *codec) +{ +#ifdef CONFIG_SND_DEBUG_VERBOSE + int i; + int size; + + size = hdmi_get_eld_size(codec, PIN_NID); + printk(KERN_DEBUG "ELD buf size is %d\n", size); + + for (i = 0; i < 8; i++) { + size = snd_hda_codec_read(codec, PIN_NID, 0, + AC_VERB_GET_HDMI_DIP_SIZE, i); + printk(KERN_DEBUG "DIP GP[%d] buf size is %d\n", i, size); + } +#endif +} + +static void hdmi_clear_dip_buffers(struct hda_codec *codec) +{ +#ifdef BE_PARANOID + int i, j; + int size; + int pi, bi; + for (i = 0; i < 8; i++) { + size = snd_hda_codec_read(codec, PIN_NID, 0, + AC_VERB_GET_HDMI_DIP_SIZE, i); + if (size == 0) + continue; + + hdmi_set_dip_index(codec, PIN_NID, i, 0x0); + for (j = 1; j < 1000; j++) { + hdmi_write_dip_byte(codec, PIN_NID, 0x0); + hdmi_get_dip_index(codec, PIN_NID, &pi, &bi); + if (pi != i) + snd_printd(KERN_INFO "dip index %d: %d != %d\n", + bi, pi, i); + if (bi == 0) /* byte index wrapped around */ + break; + } + snd_printd(KERN_INFO + "DIP GP[%d] buf reported size=%d, written=%d\n", + i, size, j); + } +#endif +} + +static void hdmi_setup_audio_infoframe(struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hdmi_audio_infoframe audio_infoframe = { + .type = 0x84, + .ver = 0x01, + .len = 0x0a, + .CC02_CT47 = substream->runtime->channels - 1, + }; + u8 *params = (u8 *)&audio_infoframe; + int i; + + hdmi_debug_dip_size(codec); + hdmi_clear_dip_buffers(codec); /* be paranoid */ + + hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); + for (i = 0; i < sizeof(audio_infoframe); i++) + hdmi_write_dip_byte(codec, PIN_NID, params[i]); +} + + +/* + * Unsolicited events + */ + +static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) +{ + int pind = !!(res & AC_UNSOL_RES_PD); + int eldv = !!(res & AC_UNSOL_RES_ELDV); + + printk(KERN_INFO "HDMI intrinsic event: PD=%d ELDV=%d\n", pind, eldv); + + if (pind && eldv) { + hdmi_parse_eld(codec); + /* TODO: do real things about ELD */ + } +} + +static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) +{ + int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; + int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); + int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); + + printk(KERN_INFO "HDMI non-intrinsic event: " + "SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", + subtag, + cp_state, + cp_ready); + + /* who cares? */ + if (cp_state) + ; + if (cp_ready) + ; +} + + +static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) +{ + int tag = res >> AC_UNSOL_RES_TAG_SHIFT; + int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; + + if (tag != INTEL_HDMI_EVENT_TAG) { + snd_printd(KERN_INFO + "Unexpected HDMI unsolicited event tag 0x%x\n", + tag); + return; + } + + if (subtag == 0) + hdmi_intrinsic_event(codec, res); + else + hdmi_non_intrinsic_event(codec, res); +} + +/* + * Callbacks + */ + +static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct intel_hdmi_spec *spec = codec->spec; + + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct intel_hdmi_spec *spec = codec->spec; + + hdmi_disable_output(codec); + + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct intel_hdmi_spec *spec = codec->spec; + + snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, + format, substream); + + hdmi_set_channel_count(codec, substream->runtime->channels); + + /* wfg: channel mapping not supported by DEVCTG */ + hdmi_setup_channel_mapping(codec); + + hdmi_setup_audio_infoframe(codec, substream); + + hdmi_enable_output(codec); + + return 0; +} + +static struct hda_pcm_stream intel_hdmi_pcm_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 8, + .nid = CVT_NID, /* NID to query formats and rates and setup streams */ + .ops = { + .open = intel_hdmi_playback_pcm_open, + .close = intel_hdmi_playback_pcm_close, + .prepare = intel_hdmi_playback_pcm_prepare + }, +}; + +static int intel_hdmi_build_pcms(struct hda_codec *codec) +{ + struct intel_hdmi_spec *spec = codec->spec; + struct hda_pcm *info = &spec->pcm_rec; + + codec->num_pcms = 1; + codec->pcm_info = info; + + info->name = "INTEL HDMI"; + info->pcm_type = HDA_PCM_TYPE_HDMI; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback; + + return 0; +} + +static int intel_hdmi_build_controls(struct hda_codec *codec) +{ + struct intel_hdmi_spec *spec = codec->spec; + int err; + + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); + if (err < 0) + return err; + + return 0; +} + +static int intel_hdmi_init(struct hda_codec *codec) +{ + /* disable audio output as early as possible */ + hdmi_disable_output(codec); + + snd_hda_sequence_write(codec, unsolicited_response_verb); + + return 0; +} + +static void intel_hdmi_free(struct hda_codec *codec) +{ + kfree(codec->spec); +} + +static struct hda_codec_ops intel_hdmi_patch_ops = { + .init = intel_hdmi_init, + .free = intel_hdmi_free, + .build_pcms = intel_hdmi_build_pcms, + .build_controls = intel_hdmi_build_controls, + .unsol_event = intel_hdmi_unsol_event, +}; + +static int patch_intel_hdmi(struct hda_codec *codec) +{ + struct intel_hdmi_spec *spec; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + spec->multiout.num_dacs = 0; /* no analog */ + spec->multiout.max_channels = 8; + spec->multiout.dig_out_nid = CVT_NID; + + codec->spec = spec; + codec->patch_ops = intel_hdmi_patch_ops; + + return 0; +} + +struct hda_codec_preset snd_hda_preset_intelhdmi[] = { + { .id = 0x808629fb, .name = "INTEL G45 DEVCL", .patch = patch_intel_hdmi }, + { .id = 0x80862801, .name = "INTEL G45 DEVBLC", .patch = patch_intel_hdmi }, + { .id = 0x80862802, .name = "INTEL G45 DEVCTG", .patch = patch_intel_hdmi }, + { .id = 0x80862803, .name = "INTEL G45 DEVELK", .patch = patch_intel_hdmi }, + {} /* terminator */ +}; -- cgit v1.2.3 From beb0b9cf78b56b0f30f5defe62b7b9712cd02a50 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 5 Nov 2008 07:58:25 +0100 Subject: ALSA: hda - Fix unused function in patch_intelhdmi.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a proper ifdef to shut out a compile warning: CC [M] sound/pci/hda/patch_intelhdmi.o sound/pci/hda/patch_intelhdmi.c:286: warning: ‘hdmi_get_dip_index’ defined but \ not used Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 8059102dd86..3beaf9c1090 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -281,6 +281,7 @@ static int hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) AC_DIPSIZE_ELD_BUF); } +#ifdef BE_PARANOID static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, int *packet_index, int *byte_index) { @@ -291,6 +292,7 @@ static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, *packet_index = val >> 5; *byte_index = val & 0x1f; } +#endif static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid, int packet_index, int byte_index) -- cgit v1.2.3 From 13c947444f4355293b49f83b809f178393a0a4d9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 5 Nov 2008 08:06:08 +0100 Subject: ALSA: hda - Add ASUS V1Sn support Asus V1s series laptops have an ALC660VD with PCI id: 0x1043, 0x1633. 1.) remove the previous behaviour of mapping that to the ALC861VD_LENOVO device. 2.) add a new ALC660VD_V1S device based on ALC861VD_LENOVO, with an added digital out. Signed-off-by: Tristan Aston Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/hda/patch_realtek.c | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index fa8e9fadfaf..f6594549bf5 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -940,6 +940,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. lenovo Lenovo 3000 C200 dallas Dallas laptops hp HP TX1000 + asus-v1s ASUS V1Sn auto auto-config reading BIOS (default) CMI9880 diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e727e48a48e..15779d8c756 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -153,6 +153,7 @@ enum { enum { ALC660VD_3ST, ALC660VD_3ST_DIG, + ALC660VD_ASUS_V1S, ALC861VD_3ST, ALC861VD_3ST_DIG, ALC861VD_6ST_DIG, @@ -13842,6 +13843,7 @@ static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int re static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { [ALC660VD_3ST] = "3stack-660", [ALC660VD_3ST_DIG] = "3stack-660-digout", + [ALC660VD_ASUS_V1S] = "asus-v1s", [ALC861VD_3ST] = "3stack", [ALC861VD_3ST_DIG] = "3stack-digout", [ALC861VD_6ST_DIG] = "6stack-digout", @@ -13856,7 +13858,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST), - SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S), SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG), SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), @@ -13963,6 +13965,21 @@ static struct alc_config_preset alc861vd_presets[] = { .unsol_event = alc861vd_dallas_unsol_event, .init_hook = alc861vd_dallas_automute, }, + [ALC660VD_ASUS_V1S] = { + .mixers = { alc861vd_lenovo_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs, + alc861vd_eapd_verbs, + alc861vd_lenovo_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + .unsol_event = alc861vd_lenovo_unsol_event, + .init_hook = alc861vd_lenovo_automute, + }, }; /* -- cgit v1.2.3 From c238b4f4038e0e49bb241640610584a088b268b1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 5 Nov 2008 14:57:20 +0100 Subject: ALSA: hda - Split ALC268 acer model There are actually two variants of ALC268 Acer implementation, one with an analog built-in mic (pin 0x19) and another with a digital mic (pin 0x12). Created a new model, acer-dmic, for the latter case now. So far, all known models are assigned to be analog-mic, according to the BIOS setup. If this doesn't match with the actual case, one needs to try model=acer-dmic, and fix the entry to point ALC268_ACER_DMIC if it works. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/hda/patch_realtek.c | 44 +++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index f6594549bf5..3ab5fb1357a 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -844,6 +844,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 3stack 3-stack model toshiba Toshiba A205 acer Acer laptops + acer-dmic Acer laptops with digital-mic acer-aspire Acer Aspire One dell Dell OEM laptops (Vostro 1200) zepto Zepto laptops diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 15779d8c756..425b0fc86f7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -114,6 +114,7 @@ enum { ALC268_3ST, ALC268_TOSHIBA, ALC268_ACER, + ALC268_ACER_DMIC, ALC268_ACER_ASPIRE_ONE, ALC268_DELL, ALC268_ZEPTO, @@ -10714,6 +10715,22 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = { { } }; +static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc268_acer_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), + { } +}; + static struct hda_verb alc268_acer_aspire_one_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -11039,6 +11056,15 @@ static struct hda_input_mux alc268_capture_source = { }; static struct hda_input_mux alc268_acer_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "Line", 0x2 }, + }, +}; + +static struct hda_input_mux alc268_acer_dmic_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -11322,6 +11348,7 @@ static const char *alc268_models[ALC268_MODEL_LAST] = { [ALC268_3ST] = "3stack", [ALC268_TOSHIBA] = "toshiba", [ALC268_ACER] = "acer", + [ALC268_ACER_DMIC] = "acer-dmic", [ALC268_ACER_ASPIRE_ONE] = "acer-aspire", [ALC268_DELL] = "dell", [ALC268_ZEPTO] = "zepto", @@ -11417,6 +11444,23 @@ static struct alc_config_preset alc268_presets[] = { .unsol_event = alc268_acer_unsol_event, .init_hook = alc268_acer_init_hook, }, + [ALC268_ACER_DMIC] = { + .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_acer_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_acer_dmic_capture_source, + .unsol_event = alc268_acer_unsol_event, + .init_hook = alc268_acer_init_hook, + }, [ALC268_ACER_ASPIRE_ONE] = { .mixers = { alc268_acer_aspire_one_mixer, alc268_capture_alt_mixer }, -- cgit v1.2.3 From 33fa35ed0d7e8996cc68cc2ffc21f12b38fa03c1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 6 Nov 2008 16:50:40 +0100 Subject: ALSA: hda - simplify hda_bus ops callbacks The hda_bus ops callback take struct hda_bus pointer. Also, the command callback takes the composed command word, instead of each small bits in arguments. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 62 +++++++++++++++++++++++++++++++++++------------ sound/pci/hda/hda_codec.h | 10 ++++---- sound/pci/hda/hda_intel.c | 61 +++++++++++++++++++++------------------------- 3 files changed, 79 insertions(+), 54 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 45695d608c7..810465bac55 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -157,6 +157,23 @@ const char *snd_hda_get_jack_type(u32 cfg) >> AC_DEFCFG_DEVICE_SHIFT]; } +/* + * Compose a 32bit command word to be sent to the HD-audio controller + */ +static inline unsigned int +make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, + unsigned int verb, unsigned int parm) +{ + u32 val; + + val = (u32)(codec->addr & 0x0f) << 28; + val |= (u32)direct << 27; + val |= (u32)nid << 20; + val |= verb << 8; + val |= parm; + return val; +} + /** * snd_hda_codec_read - send a command and get the response * @codec: the HDA codec @@ -173,14 +190,17 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { + struct hda_bus *bus = codec->bus; unsigned int res; + + res = make_codec_cmd(codec, nid, direct, verb, parm); snd_hda_power_up(codec); - mutex_lock(&codec->bus->cmd_mutex); - if (!codec->bus->ops.command(codec, nid, direct, verb, parm)) - res = codec->bus->ops.get_response(codec); + mutex_lock(&bus->cmd_mutex); + if (!bus->ops.command(bus, res)) + res = bus->ops.get_response(bus); else res = (unsigned int)-1; - mutex_unlock(&codec->bus->cmd_mutex); + mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); return res; } @@ -200,11 +220,15 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { + struct hda_bus *bus = codec->bus; + unsigned int res; int err; + + res = make_codec_cmd(codec, nid, direct, verb, parm); snd_hda_power_up(codec); - mutex_lock(&codec->bus->cmd_mutex); - err = codec->bus->ops.command(codec, nid, direct, verb, parm); - mutex_unlock(&codec->bus->cmd_mutex); + mutex_lock(&bus->cmd_mutex); + err = bus->ops.command(bus, res); + mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); return err; } @@ -1886,10 +1910,14 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { + struct hda_bus *bus = codec->bus; + unsigned int res; int err; + + res = make_codec_cmd(codec, nid, direct, verb, parm); snd_hda_power_up(codec); - mutex_lock(&codec->bus->cmd_mutex); - err = codec->bus->ops.command(codec, nid, direct, verb, parm); + mutex_lock(&bus->cmd_mutex); + err = bus->ops.command(bus, res); if (!err) { struct hda_cache_head *c; u32 key = build_cmd_cache_key(nid, verb); @@ -1897,7 +1925,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, if (c) c->val = parm; } - mutex_unlock(&codec->bus->cmd_mutex); + mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); return err; } @@ -2414,6 +2442,7 @@ static int set_pcm_default_values(struct hda_codec *codec, static int __devinit snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) { + struct hda_bus *bus = codec->bus; struct hda_pcm_stream *info; int stream, err; @@ -2427,7 +2456,7 @@ snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) return err; } } - return codec->bus->ops.attach_pcm(codec, pcm); + return bus->ops.attach_pcm(bus, codec, pcm); } /** @@ -2628,6 +2657,7 @@ static void hda_power_work(struct work_struct *work) { struct hda_codec *codec = container_of(work, struct hda_codec, power_work.work); + struct hda_bus *bus = codec->bus; if (!codec->power_on || codec->power_count) { codec->power_transition = 0; @@ -2635,8 +2665,8 @@ static void hda_power_work(struct work_struct *work) } hda_call_codec_suspend(codec); - if (codec->bus->ops.pm_notify) - codec->bus->ops.pm_notify(codec); + if (bus->ops.pm_notify) + bus->ops.pm_notify(bus); } static void hda_keep_power_on(struct hda_codec *codec) @@ -2647,13 +2677,15 @@ static void hda_keep_power_on(struct hda_codec *codec) void snd_hda_power_up(struct hda_codec *codec) { + struct hda_bus *bus = codec->bus; + codec->power_count++; if (codec->power_on || codec->power_transition) return; codec->power_on = 1; - if (codec->bus->ops.pm_notify) - codec->bus->ops.pm_notify(codec); + if (bus->ops.pm_notify) + bus->ops.pm_notify(bus); hda_call_codec_resume(codec); cancel_delayed_work(&codec->power_work); codec->power_transition = 0; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index c5f91c918d1..a73f0eb9928 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -556,17 +556,17 @@ typedef u16 hda_nid_t; /* bus operators */ struct hda_bus_ops { /* send a single command */ - int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct, - unsigned int verb, unsigned int parm); + int (*command)(struct hda_bus *bus, unsigned int cmd); /* get a response from the last command */ - unsigned int (*get_response)(struct hda_codec *codec); + unsigned int (*get_response)(struct hda_bus *bus); /* 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); + int (*attach_pcm)(struct hda_bus *bus, 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); + void (*pm_notify)(struct hda_bus *bus); #endif }; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 614be2ec806..bf8e6f94aeb 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -527,9 +527,9 @@ static void azx_free_cmd_io(struct azx *chip) } /* send a command */ -static int azx_corb_send_cmd(struct hda_codec *codec, u32 val) +static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) { - struct azx *chip = codec->bus->private_data; + struct azx *chip = bus->private_data; unsigned int wp; /* add command to corb */ @@ -577,9 +577,9 @@ static void azx_update_rirb(struct azx *chip) } /* receive a response */ -static unsigned int azx_rirb_get_response(struct hda_codec *codec) +static unsigned int azx_rirb_get_response(struct hda_bus *bus) { - struct azx *chip = codec->bus->private_data; + struct azx *chip = bus->private_data; unsigned long timeout; again: @@ -596,7 +596,7 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec) } if (time_after(jiffies, timeout)) break; - if (codec->bus->needs_damn_long_delay) + if (bus->needs_damn_long_delay) msleep(2); /* temporary workaround */ else { udelay(10); @@ -646,9 +646,9 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec) */ /* send a command */ -static int azx_single_send_cmd(struct hda_codec *codec, u32 val) +static int azx_single_send_cmd(struct hda_bus *bus, u32 val) { - struct azx *chip = codec->bus->private_data; + struct azx *chip = bus->private_data; int timeout = 50; while (timeout--) { @@ -671,9 +671,9 @@ static int azx_single_send_cmd(struct hda_codec *codec, u32 val) } /* receive a response */ -static unsigned int azx_single_get_response(struct hda_codec *codec) +static unsigned int azx_single_get_response(struct hda_bus *bus) { - struct azx *chip = codec->bus->private_data; + struct azx *chip = bus->private_data; int timeout = 50; while (timeout--) { @@ -696,38 +696,29 @@ static unsigned int azx_single_get_response(struct hda_codec *codec) */ /* send a command */ -static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, - int direct, unsigned int verb, - unsigned int para) +static int azx_send_cmd(struct hda_bus *bus, unsigned int val) { - struct azx *chip = codec->bus->private_data; - u32 val; - - val = (u32)(codec->addr & 0x0f) << 28; - val |= (u32)direct << 27; - val |= (u32)nid << 20; - val |= verb << 8; - val |= para; - chip->last_cmd = val; + struct azx *chip = bus->private_data; + chip->last_cmd = val; if (chip->single_cmd) - return azx_single_send_cmd(codec, val); + return azx_single_send_cmd(bus, val); else - return azx_corb_send_cmd(codec, val); + return azx_corb_send_cmd(bus, val); } /* get a response */ -static unsigned int azx_get_response(struct hda_codec *codec) +static unsigned int azx_get_response(struct hda_bus *bus) { - struct azx *chip = codec->bus->private_data; + struct azx *chip = bus->private_data; if (chip->single_cmd) - return azx_single_get_response(codec); + return azx_single_get_response(bus); else - return azx_rirb_get_response(codec); + return azx_rirb_get_response(bus); } #ifdef CONFIG_SND_HDA_POWER_SAVE -static void azx_power_notify(struct hda_codec *codec); +static void azx_power_notify(struct hda_bus *bus); #endif /* reset codec link */ @@ -1184,7 +1175,8 @@ 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); +static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, + struct hda_pcm *cpcm); /* * Codec initialization @@ -1707,9 +1699,10 @@ static void azx_pcm_free(struct snd_pcm *pcm) } static int -azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm) +azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, + struct hda_pcm *cpcm) { - struct azx *chip = codec->bus->private_data; + struct azx *chip = bus->private_data; struct snd_pcm *pcm; struct azx_pcm *apcm; int pcm_dev = cpcm->device; @@ -1827,13 +1820,13 @@ static void azx_stop_chip(struct azx *chip) #ifdef CONFIG_SND_HDA_POWER_SAVE /* power-up/down the controller */ -static void azx_power_notify(struct hda_codec *codec) +static void azx_power_notify(struct hda_bus *bus) { - struct azx *chip = codec->bus->private_data; + struct azx *chip = bus->private_data; struct hda_codec *c; int power_on = 0; - list_for_each_entry(c, &codec->bus->codec_list, list) { + list_for_each_entry(c, &bus->codec_list, list) { if (c->power_on) { power_on = 1; break; -- cgit v1.2.3 From 6ce4a3bc1b93e8ca50b142b00dd73bfdb5c4a172 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 6 Nov 2008 17:11:10 +0100 Subject: ALSA: hda - Make codec-probing more robust When an error occurs during the codec probing, typically accessing to an non-existing codec slot, the controller chip gets often screwed up and can no longer communicate with the codecs. This patch adds a preparation phase just to probe codec addresses before actually creating codec instances. If any error occurs during this probing phase, the driver resets the controller to recover. This will (hopefully) fix the famous "single_cmd" errors. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index bf8e6f94aeb..f3c447cf67f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -392,6 +392,7 @@ struct azx { unsigned int msi :1; unsigned int irq_pending_warned :1; unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */ + unsigned int probing :1; /* codec probing phase */ /* for debugging */ unsigned int last_cmd; /* last issued command (to sync) */ @@ -624,6 +625,14 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) goto again; } + if (chip->probing) { + /* If this critical timeout happens during the codec probing + * phase, this is likely an access to a non-existing codec + * slot. Better to return an error and reset the system. + */ + return -1; + } + snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " "switching to single_cmd mode: last cmd=0x%08x\n", chip->last_cmd); @@ -1175,8 +1184,28 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) return 0; } +/* + * Probe the given codec address + */ +static int probe_codec(struct azx *chip, int addr) +{ + unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | + (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; + unsigned int res; + + chip->probing = 1; + azx_send_cmd(chip->bus, cmd); + res = azx_get_response(chip->bus); + chip->probing = 0; + if (res == -1) + return -EIO; + snd_printdd("hda_intel: codec #%d probed OK\n", addr); + return 0; +} + static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, struct hda_pcm *cpcm); +static void azx_stop_chip(struct azx *chip); /* * Codec initialization @@ -1216,6 +1245,32 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, max_slots = azx_max_codecs[chip->driver_type]; if (!max_slots) max_slots = AZX_MAX_CODECS; + + /* First try to probe all given codec slots */ + for (c = 0; c < max_slots; c++) { + if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { + if (probe_codec(chip, c) < 0) { + /* Some BIOSen give you wrong codec addresses + * that don't exist + */ + snd_printk(KERN_WARNING + "hda_intel: Codec #%d probe error; " + "disabling it...\n", c); + chip->codec_mask &= ~(1 << c); + /* More badly, accessing to a non-existing + * codec often screws up the controller chip, + * and distrubs the further communications. + * Thus if an error occurs during probing, + * better to reset the controller chip to + * get back to the sanity state. + */ + azx_stop_chip(chip); + azx_init_chip(chip); + } + } + } + + /* Then create codec instances */ for (c = 0; c < max_slots; c++) { if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { struct hda_codec *codec; -- cgit v1.2.3 From 64154835c58a99370c3b7fbf85d2451d6906b3b4 Mon Sep 17 00:00:00 2001 From: Tony Vroon Date: Thu, 6 Nov 2008 15:08:49 +0000 Subject: ALSA: hda - Add lifebook model for Realtek ALC269 The widget layout of the Fujitsu Lifebook S6420 (which is ICH9M-based and uses an ALC269) is similar but not identical to the Lifebook S6410/E8410 (which are ICH8M-based and use an ALC262). It is named lifebook as fujitsu is in use for Amilo machines. This builds on the Quanta FL1 work and supports all analog inputs & outputs that I am aware of. Microphone autoswitch is implemented. The laptop mic port takes precedence over the dock mic port if both happen to have a jack plugged in. This made sense to me as a design decision (imagine a presentation environment with the dock fully wired in and the presenter quickly wanting to override the mic with a headset). There is mention of a digital audio path on the codec graph, so perhaps the headphone socket is dual-function analog/digital. I will follow up with another patch if I can acquire equipment to test this. Signed-off-by: Tony Vroon Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 125 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 425b0fc86f7..98a02fd1097 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -132,6 +132,7 @@ enum { ALC269_ASUS_EEEPC_P703, ALC269_ASUS_EEEPC_P901, ALC269_FUJITSU, + ALC269_LIFEBOOK, ALC269_AUTO, ALC269_MODEL_LAST /* last tag */ }; @@ -11701,6 +11702,31 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { { } }; +static struct snd_kcontrol_new alc269_lifebook_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc268_acer_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT), + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT), + { } +}; + /* bind volumes of both NID 0x0c and 0x0d */ static struct hda_bind_ctls alc269_epc_bind_vol = { .ops = &snd_hda_bind_vol, @@ -11751,6 +11777,20 @@ static struct hda_verb alc269_quanta_fl1_verbs[] = { { } }; +static struct hda_verb alc269_lifebook_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + { } +}; + /* toggle speaker-output according to the hp-jack state */ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) { @@ -11776,6 +11816,37 @@ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) AC_VERB_SET_PROC_COEF, 0x480); } +/* toggle speaker-output according to the hp-jacks state */ +static void alc269_lifebook_speaker_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + /* Check laptop headphone socket */ + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + + /* Check port replicator headphone socket */ + present |= snd_hda_codec_read(codec, 0x1a, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + + bits = present ? AMP_IN_MUTE(0) : 0; + snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, + AMP_IN_MUTE(0), bits); + snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, + AMP_IN_MUTE(0), bits); + + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 0x0c); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, 0x680); + + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 0x0c); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, 0x480); +} + static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec) { unsigned int present; @@ -11786,6 +11857,29 @@ static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec) AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1); } +static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) +{ + unsigned int present_laptop; + unsigned int present_dock; + + present_laptop = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + + present_dock = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + + /* Laptop mic port overrides dock mic port, design decision */ + if (present_dock) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x3); + if (present_laptop) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x0); + if (!present_dock && !present_laptop) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x1); +} + static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, unsigned int res) { @@ -11795,12 +11889,27 @@ static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, alc269_quanta_fl1_mic_automute(codec); } +static void alc269_lifebook_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc269_lifebook_speaker_automute(codec); + if ((res >> 26) == ALC880_MIC_EVENT) + alc269_lifebook_mic_autoswitch(codec); +} + static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) { alc269_quanta_fl1_speaker_automute(codec); alc269_quanta_fl1_mic_automute(codec); } +static void alc269_lifebook_init_hook(struct hda_codec *codec) +{ + alc269_lifebook_speaker_automute(codec); + alc269_lifebook_mic_autoswitch(codec); +} + static struct hda_verb alc269_eeepc_dmic_init_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, @@ -12154,7 +12263,8 @@ static const char *alc269_models[ALC269_MODEL_LAST] = { [ALC269_QUANTA_FL1] = "quanta", [ALC269_ASUS_EEEPC_P703] = "eeepc-p703", [ALC269_ASUS_EEEPC_P901] = "eeepc-p901", - [ALC269_FUJITSU] = "fujitsu" + [ALC269_FUJITSU] = "fujitsu", + [ALC269_LIFEBOOK] = "lifebook" }; static struct snd_pci_quirk alc269_cfg_tbl[] = { @@ -12166,6 +12276,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", ALC269_ASUS_EEEPC_P901), SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), + SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK), {} }; @@ -12234,6 +12345,18 @@ static struct alc_config_preset alc269_presets[] = { .unsol_event = alc269_eeepc_dmic_unsol_event, .init_hook = alc269_eeepc_dmic_inithook, }, + [ALC269_LIFEBOOK] = { + .mixers = { alc269_lifebook_mixer }, + .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + .unsol_event = alc269_lifebook_unsol_event, + .init_hook = alc269_lifebook_init_hook, + }, }; static int patch_alc269(struct hda_codec *codec) -- cgit v1.2.3 From c217429b14708999d6ac5de964c452600e8797d3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Nov 2008 00:23:30 +0100 Subject: ALSA: hda - Add missing NULL check in amp hash allocation Added the missing NULL check from allocator in get_alloc_hash(). Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 810465bac55..f13834ba6b1 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -899,6 +899,8 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, /* add a new hash entry */ info = snd_array_new(&cache->buf); + if (!info) + return NULL; info->key = key; info->val = 0; info->next = cache->hash[idx]; -- cgit v1.2.3 From b910d9ae5b370cf5bf9d6a71028119861b6ea8a4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Nov 2008 00:26:52 +0100 Subject: ALSA: hda - Add max allocation check in array allocator Added a check for max allocation size in snd_array_new() for a debugging purpose. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f13834ba6b1..6f170b281e8 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3399,7 +3399,10 @@ 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); + void *nlist; + if (snd_BUG_ON(num >= 4096)) + return NULL; + nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL); if (!nlist) return NULL; if (array->list) { -- cgit v1.2.3 From ea2da6e898033b9736a26cf588b9ce841a433337 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Nov 2008 00:49:48 +0100 Subject: ALSA: hda - Fix broken hash chain allocation The chaining for amp hash got broken due to the rewrite with snd_array. Fixed now. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 6f170b281e8..06e99c78515 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -901,6 +901,7 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, info = snd_array_new(&cache->buf); if (!info) return NULL; + cur = cache->buf.used - 1; /* the last entry */ info->key = key; info->val = 0; info->next = cache->hash[idx]; -- cgit v1.2.3 From 30cde0aacc5f6786b0c4d4fafaac95eac845b8d7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Nov 2008 14:49:28 +0100 Subject: ALSA: hda - Fix ALC260 hp3013 master switch The master switch doesn't influence on NID 0x15, the headphone jack on HP 3013 model because alc260_hp_master_update() ignores the passed arguments. Also, corrected the wrong arguments of hp3013 (0x10 and 0x15) although this doesn't change any behavior. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0f1fa1dac44..017abd01299 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4272,13 +4272,13 @@ static void alc260_hp_master_update(struct hda_codec *codec, struct alc_spec *spec = codec->spec; unsigned int val = spec->master_sw ? PIN_HP : 0; /* change HP and line-out pins */ - snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); /* mono (speaker) depending on the HP jack sense */ val = (val && !spec->jack_present) ? PIN_OUT : 0; - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); } @@ -4357,7 +4357,7 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { .info = snd_ctl_boolean_mono_info, .get = alc260_hp_master_sw_get, .put = alc260_hp_master_sw_put, - .private_value = (0x10 << 16) | (0x15 << 8) | 0x11 + .private_value = (0x15 << 16) | (0x10 << 8) | 0x11 }, HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), @@ -4410,7 +4410,7 @@ static void alc260_hp_3013_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0); spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; - alc260_hp_master_update(codec, 0x10, 0x15, 0x11); + alc260_hp_master_update(codec, 0x15, 0x10, 0x11); } static void alc260_hp_3013_unsol_event(struct hda_codec *codec, -- cgit v1.2.3 From 0edb94543092535a2c6ef33e7285004168ca73d7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Nov 2008 14:53:09 +0100 Subject: ALSA: hda - Fix probe errors on Dell Studio Desktop BIOS on Dell Studio Desktop tells wrong codec probe masks. This patch gives the preset mask value to avoid invalid access. Reference: Novell bug#440907 https://bugzilla.novell.com/show_bug.cgi?id=440907 Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f3c447cf67f..3e112df1c0d 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2067,6 +2067,8 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = { SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01), SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01), SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01), + /* broken BIOS */ + SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01), {} }; -- cgit v1.2.3 From f43aa025b7de79d6a615ea4c1e6be7e6b1cea538 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 10 Nov 2008 16:24:26 +0100 Subject: ALSA: hda - Fix another cache list management Fix another silly bug in the amp cache list management. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 7 +++---- sound/pci/hda/hda_codec.h | 10 ++++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 06e99c78515..5d5e8012d6a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -887,11 +887,10 @@ 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 = &info_head[cur]; + info = snd_array_elem(&cache->buf, cur); if (info->key == key) return info; cur = info->next; @@ -901,7 +900,7 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, info = snd_array_new(&cache->buf); if (!info) return NULL; - cur = cache->buf.used - 1; /* the last entry */ + cur = snd_array_index(&cache->buf, info); info->key = key; info->val = 0; info->next = cache->hash[idx]; @@ -3414,7 +3413,7 @@ void *snd_array_new(struct snd_array *array) array->list = nlist; array->alloced = num; } - return array->list + (array->used++ * array->elem_size); + return snd_array_elem(array, array->used++); } /* free the given array elements */ diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index a73f0eb9928..ee122b009fd 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -539,6 +539,16 @@ static inline void snd_array_init(struct snd_array *array, unsigned int size, array->alloc_align = align; } +static inline void *snd_array_elem(struct snd_array *array, unsigned int idx) +{ + return array->list + idx * array->elem_size; +} + +static inline unsigned int snd_array_index(struct snd_array *array, void *ptr) +{ + return (unsigned long)(ptr - array->list) / array->elem_size; +} + /* * Structures */ -- cgit v1.2.3 From 3a95cb972bb0eb80dfdb42f11628e6d58bcdde29 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Thu, 13 Nov 2008 10:19:38 +0800 Subject: ALSA: handle SiI1392 HDMI codec in patch_intelhdmi.c Move the handling of SiI1392 HDMI codec from patch_atihdmi.c to patch_intelhdmi.c, which makes our ASUS P5E-VM HDMI board work. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_atihdmi.c | 1 - sound/pci/hda/patch_intelhdmi.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index ba61575983f..5603a1acddb 100644 --- a/sound/pci/hda/patch_atihdmi.c +++ b/sound/pci/hda/patch_atihdmi.c @@ -193,7 +193,6 @@ struct hda_codec_preset snd_hda_preset_atihdmi[] = { { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi }, { .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi }, { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi }, - { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_atihdmi }, { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi }, {} /* terminator */ }; diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 3beaf9c1090..939b37ba707 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -924,5 +924,6 @@ struct hda_codec_preset snd_hda_preset_intelhdmi[] = { { .id = 0x80862801, .name = "INTEL G45 DEVBLC", .patch = patch_intel_hdmi }, { .id = 0x80862802, .name = "INTEL G45 DEVCTG", .patch = patch_intel_hdmi }, { .id = 0x80862803, .name = "INTEL G45 DEVELK", .patch = patch_intel_hdmi }, + { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, {} /* terminator */ }; -- cgit v1.2.3 From c4da29ca08e09ed41a2030c1f7b5860f116573be Mon Sep 17 00:00:00 2001 From: "Yang, Libin" Date: Thu, 13 Nov 2008 11:07:07 +0100 Subject: ALSA: hda - support detecting HD Audio devices with PCI class code The patch uses HD Audio PCI class code to detect AMD HD Audio cards. Signed-off-by: Libin Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3e112df1c0d..f73c13fdd40 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -292,6 +292,8 @@ enum { /* Define VIA HD Audio Device ID*/ #define VIA_HDAC_DEVICE_ID 0x3288 +/* HD Audio class code */ +#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 /* */ @@ -415,6 +417,7 @@ enum { AZX_DRIVER_ULI, AZX_DRIVER_NVIDIA, AZX_DRIVER_TERA, + AZX_DRIVER_GENERIC, AZX_NUM_DRIVERS, /* keep this as last entry */ }; @@ -428,6 +431,7 @@ static char *driver_short_names[] __devinitdata = { [AZX_DRIVER_ULI] = "HDA ULI M5461", [AZX_DRIVER_NVIDIA] = "HDA NVidia", [AZX_DRIVER_TERA] = "HDA Teradici", + [AZX_DRIVER_GENERIC] = "HD-Audio Generic", }; /* @@ -2203,6 +2207,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->playback_streams = ATIHDMI_NUM_PLAYBACK; chip->capture_streams = ATIHDMI_NUM_CAPTURE; break; + case AZX_DRIVER_GENERIC: default: chip->playback_streams = ICH6_NUM_PLAYBACK; chip->capture_streams = ICH6_NUM_CAPTURE; @@ -2427,6 +2432,11 @@ static struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA }, /* Teradici */ { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, + /* AMD Generic, PCI class code and Vendor ID for HD Audio */ + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), + .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, + .class_mask = 0xffffff, + .driver_data = AZX_DRIVER_GENERIC }, { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); -- cgit v1.2.3 From 127e82e3bfaad29e78ff5d4b1c41ab5e2d69c17f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 14 Nov 2008 14:03:33 +0100 Subject: ALSA: hda - Support Headphone and Speaker volumes control on VAIO Split the bound Master control to individual Headphone and Speaker volume controls for VAIO with STAC982x codecs. The Master controls is still created as a vmaster. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 58d832c3835..66c12d3e9c7 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5132,29 +5132,11 @@ static struct hda_verb vaio_ar_init[] = { {} }; -/* bind volumes of both NID 0x02 and 0x05 */ -static struct hda_bind_ctls vaio_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -/* bind volumes of both NID 0x02 and 0x05 */ -static struct hda_bind_ctls vaio_bind_master_sw = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), - 0, - }, -}; - static struct snd_kcontrol_new vaio_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT), /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), @@ -5170,8 +5152,10 @@ static struct snd_kcontrol_new vaio_mixer[] = { }; static struct snd_kcontrol_new vaio_ar_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT), /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), -- cgit v1.2.3 From 3ab909351a3c653a879a35b3342979ac483c0460 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Mon, 17 Nov 2008 09:51:09 +0100 Subject: ALSA: hda: alc883 model for ASUS P5Q-EM boards Add a new alc883 model ALC1200_ASUS_P5Q for ASUS P5Q-EM boards. It is the same as ALC883_6ST_DIG except that the SPDIF digital output nid is 0x10. Tested-by: Andrei Tanas Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 017abd01299..04e153a77db 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -232,6 +232,7 @@ enum { ALC883_3ST_6ch_INTEL, ALC888_ASUS_M90V, ALC888_ASUS_EEE1601, + ALC1200_ASUS_P5Q, ALC883_AUTO, ALC883_MODEL_LAST, }; @@ -6868,6 +6869,8 @@ static int patch_alc882(struct hda_codec *codec) #define ALC883_DIGOUT_NID 0x06 #define ALC883_DIGIN_NID 0x0a +#define ALC1200_DIGOUT_NID 0x10 + static hda_nid_t alc883_dac_nids[4] = { /* front, rear, clfe, rear_surr */ 0x02, 0x03, 0x04, 0x05 @@ -8190,6 +8193,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC883_CLEVO_M720] = "clevo-m720", [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", + [ALC1200_ASUS_P5Q] = "asus-p5q", [ALC883_AUTO] = "auto", }; @@ -8208,6 +8212,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V), SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q), SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601), SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG), SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), @@ -8555,6 +8560,17 @@ static struct alc_config_preset alc883_presets[] = { .unsol_event = alc883_eee1601_unsol_event, .init_hook = alc883_eee1601_inithook, }, + [ALC1200_ASUS_P5Q] = { + .mixers = { alc883_base_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC1200_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), + .channel_mode = alc883_sixstack_modes, + .input_mux = &alc883_capture_source, + }, }; -- cgit v1.2.3 From c0cea0d09d15350c398e2951e7cf4d6f0fc98977 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Sun, 16 Nov 2008 11:42:34 -0500 Subject: ALSA: hda: STAC_DELL_M6 EAPD Add support for EAPD on system suspend and disabling EAPD on headphone jack detection for STAC_DELL_M6 laptops. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6d9c634632d..1aa3f6cbcb9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -147,6 +147,7 @@ struct sigmatel_spec { unsigned int num_mixers; int board_config; + unsigned int eapd_switch: 1; unsigned int surr_switch: 1; unsigned int line_switch: 1; unsigned int mic_switch: 1; @@ -4001,7 +4002,7 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) for (i = 0; i < cfg->speaker_outs; i++) stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], AC_PINCTL_OUT_EN); - if (spec->eapd_mask) + if (spec->eapd_mask && spec->eapd_switch) stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data & ~spec->eapd_mask); @@ -4016,7 +4017,7 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) for (i = 0; i < cfg->speaker_outs; i++) stac92xx_set_pinctl(codec, cfg->speaker_pins[i], AC_PINCTL_OUT_EN); - if (spec->eapd_mask) + if (spec->eapd_mask && spec->eapd_switch) stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data | spec->eapd_mask); @@ -4376,6 +4377,7 @@ again: spec->num_smuxes = 0; spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER]; spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP]; + spec->eapd_switch = 0; spec->num_amps = 1; if (!spec->init) @@ -4407,6 +4409,7 @@ again: default: spec->num_dmics = STAC92HD73XX_NUM_DMICS; spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids); + spec->eapd_switch = 1; } if (spec->board_config > STAC_92HD73XX_REF) { /* GPIO0 High = Enable EAPD */ @@ -4552,7 +4555,13 @@ static int stac92hd71xx_resume(struct hda_codec *codec) static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state) { + struct sigmatel_spec *spec = codec->spec; + stac92hd71xx_set_power_state(codec, AC_PWRST_D3); + if (spec->eapd_mask) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data & + ~spec->eapd_mask); return 0; }; @@ -4942,6 +4951,7 @@ static int patch_stac927x(struct hda_codec *codec) spec->num_pwrs = 0; spec->aloopback_mask = 0x40; spec->aloopback_shift = 0; + spec->eapd_switch = 1; err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); if (!err) { @@ -5022,6 +5032,7 @@ static int patch_stac9205(struct hda_codec *codec) spec->aloopback_mask = 0x40; spec->aloopback_shift = 0; + spec->eapd_switch = 1; spec->multiout.dac_nids = spec->dac_nids; switch (spec->board_config){ -- cgit v1.2.3 From 796359d150356adabb677d708a4e66a09d29d9d8 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Mon, 17 Nov 2008 16:57:33 +0800 Subject: ALSA: hda-intel: reorder HDMI audio enabling sequence Reorder HDMI audio enabling sequence so that 1) the sink knows about the coming audio stream 2) unmute 3) start transferring audio samples The theory is that in the path A=>B=>C, we first make C ready, and then enable B, and lastly allow A to send audio samples. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 939b37ba707..d99cd629724 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -312,16 +312,16 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, static void hdmi_enable_output(struct hda_codec *codec) { - /* Enable pin out and unmute */ - snd_hda_sequence_write(codec, pinout_enable_verb); - if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, PIN_NID, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - /* Enable Audio InfoFrame Transmission */ hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST); + /* Unmute */ + if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, PIN_NID, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + /* Enable pin out */ + snd_hda_sequence_write(codec, pinout_enable_verb); } static void hdmi_disable_output(struct hda_codec *codec) -- cgit v1.2.3 From 2eca83ba9cc6f811f8c63314b22b4bc0532e2207 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Tue, 18 Nov 2008 10:21:55 +0800 Subject: ALSA: hda: remove redundant get_amp_nid() Remove get_amp_nid(): it duplicates the one defined in hda_local.h Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 760e14ae3bf..05182be1c9f 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -142,8 +142,6 @@ enum { AUTO_SEQ_SIDE }; -#define get_amp_nid(kc) ((kc)->private_value & 0xffff) - /* Some VT1708S based boards gets the micboost setting wrong, so we have * to apply some brute-force and re-write the TLV's by software. */ static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag, -- cgit v1.2.3 From 33deeca3bb6a945677d70876ea9d044fc5797eb3 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Tue, 18 Nov 2008 11:47:51 +0800 Subject: ALSA: introduce snd_print_pcm_rates() We want to share some code with print_pcm_rates(), so extract a common routine snd_print_pcm_rates() from it. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_local.h | 3 +++ sound/pci/hda/hda_proc.c | 20 ++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index aac569b0559..d7e3a164eff 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -284,6 +284,9 @@ int snd_hda_codec_proc_new(struct hda_codec *codec); static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } #endif +#define SND_PRINT_RATES_ADVISED_BUFSIZE 80 +void snd_print_pcm_rates(int pcm, char *buf, int buflen); + /* * Misc */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 64b6a38fa96..512eb674b74 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -89,20 +89,28 @@ static void print_amp_vals(struct snd_info_buffer *buffer, snd_iprintf(buffer, "\n"); } -static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) +void snd_print_pcm_rates(int pcm, char *buf, int buflen) { static unsigned int rates[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 384000 }; - int i; + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(rates); i++) + if (pcm & (1 << i)) + j += snprintf(buf + j, buflen - j, " %d", rates[i]); + + buf[j] = '\0'; /* necessary when j == 0 */ +} +static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) +{ + char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; pcm &= AC_SUPPCM_RATES; snd_iprintf(buffer, " rates [0x%x]:", pcm); - for (i = 0; i < ARRAY_SIZE(rates); i++) - if (pcm & (1 << i)) - snd_iprintf(buffer, " %d", rates[i]); - snd_iprintf(buffer, "\n"); + snd_print_pcm_rates(pcm, buf, sizeof(buf)); + snd_iprintf(buffer, "%s\n", buf); } static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) -- cgit v1.2.3 From 7f4a9f43427793bfe4d42e71f42e2b551bcfe354 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Tue, 18 Nov 2008 11:47:52 +0800 Subject: ALSA: create hda_eld.c for ELD routines and proc interface ELD handling routines can be shared by all HDMI codecs, and they are large enough to make a standalone source file. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 4 + sound/pci/hda/Makefile | 1 + sound/pci/hda/hda_eld.c | 454 +++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_local.h | 41 ++++ sound/pci/hda/patch_intelhdmi.c | 480 +--------------------------------------- 5 files changed, 505 insertions(+), 475 deletions(-) create mode 100644 sound/pci/hda/hda_eld.c diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 21e9327a0ef..157a0a6b10a 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -582,6 +582,10 @@ config SND_HDA_CODEC_INTELHDMI Say Y here to include INTEL HDMI HD-audio codec support in snd-hda-intel driver, such as Eaglelake integrated HDMI. +config SND_HDA_ELD + def_bool y + depends on SND_HDA_CODEC_INTELHDMI + config SND_HDA_CODEC_CONEXANT bool "Build Conexant HD-audio codec support" depends on SND_HDA_INTEL diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 6fb5add1e39..6daf5fd9a27 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -4,6 +4,7 @@ snd-hda-intel-y := hda_intel.o # designed to be individual modules snd-hda-intel-y += hda_codec.o snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o +snd-hda-intel-$(CONFIG_SND_HDA_ELD) += hda_eld.o snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c new file mode 100644 index 00000000000..a69a7e87d26 --- /dev/null +++ b/sound/pci/hda/hda_eld.c @@ -0,0 +1,454 @@ +/* + * Generic routines and proc interface for ELD(EDID Like Data) information + * + * Copyright(c) 2008 Intel Corporation. + * + * Authors: + * Wu Fengguang + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include "hda_codec.h" +#include "hda_local.h" + +enum eld_versions { + ELD_VER_CEA_861D = 2, + ELD_VER_PARTIAL = 31, +}; + +static char *eld_versoin_names[32] = { + "reserved", + "reserved", + "CEA-861D or below", + [3 ... 30] = "reserved", + [31] = "partial" +}; + +enum cea_edid_versions { + CEA_EDID_VER_NONE = 0, + CEA_EDID_VER_CEA861 = 1, + CEA_EDID_VER_CEA861A = 2, + CEA_EDID_VER_CEA861BCD = 3, + CEA_EDID_VER_RESERVED = 4, +}; + +static char *cea_edid_version_names[8] = { + "no CEA EDID Timing Extension block present", + "CEA-861", + "CEA-861-A", + "CEA-861-B, C or D", + [4 ... 7] = "reserved" +}; + +static char *cea_speaker_allocation_names[] = { + /* 0 */ "FL/FR", + /* 1 */ "LFE", + /* 2 */ "FC", + /* 3 */ "RL/RR", + /* 4 */ "RC", + /* 5 */ "FLC/FRC", + /* 6 */ "RLC/RRC", + /* 7 */ "FLW/FRW", + /* 8 */ "FLH/FRH", + /* 9 */ "TC", + /* 10 */ "FCH", +}; + +static char *eld_connection_type_names[4] = { + "HDMI", + "Display Port", + "2-reserved", + "3-reserved" +}; + +enum cea_audio_coding_types { + AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, + AUDIO_CODING_TYPE_LPCM = 1, + AUDIO_CODING_TYPE_AC3 = 2, + AUDIO_CODING_TYPE_MPEG1 = 3, + AUDIO_CODING_TYPE_MP3 = 4, + AUDIO_CODING_TYPE_MPEG2 = 5, + AUDIO_CODING_TYPE_AACLC = 6, + AUDIO_CODING_TYPE_DTS = 7, + AUDIO_CODING_TYPE_ATRAC = 8, + AUDIO_CODING_TYPE_SACD = 9, + AUDIO_CODING_TYPE_EAC3 = 10, + AUDIO_CODING_TYPE_DTS_HD = 11, + AUDIO_CODING_TYPE_MLP = 12, + AUDIO_CODING_TYPE_DST = 13, + AUDIO_CODING_TYPE_WMAPRO = 14, + AUDIO_CODING_TYPE_REF_CXT = 15, + /* also include valid xtypes below */ + AUDIO_CODING_TYPE_HE_AAC = 15, + AUDIO_CODING_TYPE_HE_AAC2 = 16, + AUDIO_CODING_TYPE_MPEG_SURROUND = 17, +}; + +enum cea_audio_coding_xtypes { + AUDIO_CODING_XTYPE_HE_REF_CT = 0, + AUDIO_CODING_XTYPE_HE_AAC = 1, + AUDIO_CODING_XTYPE_HE_AAC2 = 2, + AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, + AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, +}; + +static char *cea_audio_coding_type_names[] = { + /* 0 */ "undefined", + /* 1 */ "LPCM", + /* 2 */ "AC-3", + /* 3 */ "MPEG1", + /* 4 */ "MP3", + /* 5 */ "MPEG2", + /* 6 */ "AAC-LC", + /* 7 */ "DTS", + /* 8 */ "ATRAC", + /* 9 */ "DSD (1-bit audio)", + /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)", + /* 11 */ "DTS-HD", + /* 12 */ "MLP (Dolby TrueHD)", + /* 13 */ "DST", + /* 14 */ "WMAPro", + /* 15 */ "HE-AAC", + /* 16 */ "HE-AACv2", + /* 17 */ "MPEG Surround", +}; + +/* + * The following two lists are shared between + * - HDMI audio InfoFrame (source to sink) + * - CEA E-EDID extension (sink to source) + */ + +/* + * SS1:SS0 index => sample size + */ +static int cea_sample_sizes[4] = { + 0, /* 0: Refer to Stream Header */ + AC_SUPPCM_BITS_16, /* 1: 16 bits */ + AC_SUPPCM_BITS_20, /* 2: 20 bits */ + AC_SUPPCM_BITS_24, /* 3: 24 bits */ +}; + +/* + * SF2:SF1:SF0 index => sampling frequency + */ +static int cea_sampling_frequencies[8] = { + 0, /* 0: Refer to Stream Header */ + SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ + SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ + SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ + SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ + SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ + SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ + SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ +}; + +static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid, + int byte_index) +{ + unsigned int val; + + val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_HDMI_ELDD, byte_index); + +#ifdef BE_PARANOID + printk(KERN_INFO "ELD data byte %d: 0x%x\n", byte_index, val); +#endif + + if ((val & AC_ELDD_ELD_VALID) == 0) { + snd_printd(KERN_INFO "Invalid ELD data byte %d\n", + byte_index); + val = 0; + } + + return val & AC_ELDD_ELD_DATA; +} + +#define GRAB_BITS(buf, byte, lowbit, bits) \ +({ \ + BUILD_BUG_ON(lowbit > 7); \ + BUILD_BUG_ON(bits > 8); \ + BUILD_BUG_ON(bits <= 0); \ + \ + (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \ +}) + +static void hdmi_update_short_audio_desc(struct cea_sad *a, + const unsigned char *buf) +{ + int i; + int val; + + val = GRAB_BITS(buf, 1, 0, 7); + a->rates = 0; + for (i = 0; i < 7; i++) + if (val & (1 << i)) + a->rates |= cea_sampling_frequencies[i + 1]; + + a->channels = GRAB_BITS(buf, 0, 0, 3); + a->channels++; + + a->format = GRAB_BITS(buf, 0, 3, 4); + switch (a->format) { + case AUDIO_CODING_TYPE_REF_STREAM_HEADER: + snd_printd(KERN_INFO + "audio coding type 0 not expected in ELD\n"); + break; + + case AUDIO_CODING_TYPE_LPCM: + val = GRAB_BITS(buf, 2, 0, 3); + a->sample_bits = 0; + for (i = 0; i < 3; i++) + if (val & (1 << i)) + a->sample_bits |= cea_sample_sizes[i + 1]; + break; + + case AUDIO_CODING_TYPE_AC3: + case AUDIO_CODING_TYPE_MPEG1: + case AUDIO_CODING_TYPE_MP3: + case AUDIO_CODING_TYPE_MPEG2: + case AUDIO_CODING_TYPE_AACLC: + case AUDIO_CODING_TYPE_DTS: + case AUDIO_CODING_TYPE_ATRAC: + a->max_bitrate = GRAB_BITS(buf, 2, 0, 8); + a->max_bitrate *= 8000; + break; + + case AUDIO_CODING_TYPE_SACD: + break; + + case AUDIO_CODING_TYPE_EAC3: + break; + + case AUDIO_CODING_TYPE_DTS_HD: + break; + + case AUDIO_CODING_TYPE_MLP: + break; + + case AUDIO_CODING_TYPE_DST: + break; + + case AUDIO_CODING_TYPE_WMAPRO: + a->profile = GRAB_BITS(buf, 2, 0, 3); + break; + + case AUDIO_CODING_TYPE_REF_CXT: + a->format = GRAB_BITS(buf, 2, 3, 5); + if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || + a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { + snd_printd(KERN_INFO + "audio coding xtype %d not expected in ELD\n", + a->format); + a->format = 0; + } else + a->format += AUDIO_CODING_TYPE_HE_AAC - + AUDIO_CODING_XTYPE_HE_AAC; + break; + } +} + +/* + * Be careful, ELD buf could be totally rubbish! + */ +static int hdmi_update_sink_eld(struct sink_eld *e, + const unsigned char *buf, int size) +{ + int mnl; + int i; + + e->eld_ver = GRAB_BITS(buf, 0, 3, 5); + if (e->eld_ver != ELD_VER_CEA_861D && + e->eld_ver != ELD_VER_PARTIAL) { + snd_printd(KERN_INFO "Unknown ELD version %d\n", e->eld_ver); + goto out_fail; + } + + e->eld_size = size; + e->baseline_len = GRAB_BITS(buf, 2, 0, 8); + mnl = GRAB_BITS(buf, 4, 0, 5); + e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); + + e->support_hdcp = GRAB_BITS(buf, 5, 0, 1); + e->support_ai = GRAB_BITS(buf, 5, 1, 1); + e->conn_type = GRAB_BITS(buf, 5, 2, 2); + e->sad_count = GRAB_BITS(buf, 5, 4, 4); + + e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2; + e->spk_alloc = GRAB_BITS(buf, 7, 0, 7); + + e->port_id = get_unaligned_le64(buf + 8); + + /* not specified, but the spec's tendency is little endian */ + e->manufacture_id = get_unaligned_le16(buf + 16); + e->product_id = get_unaligned_le16(buf + 18); + + if (mnl > ELD_MAX_MNL) { + snd_printd(KERN_INFO "MNL is reserved value %d\n", mnl); + goto out_fail; + } else if (ELD_FIXED_BYTES + mnl > size) { + snd_printd(KERN_INFO "out of range MNL %d\n", mnl); + goto out_fail; + } else + strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl); + + for (i = 0; i < e->sad_count; i++) { + if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { + snd_printd(KERN_INFO "out of range SAD %d\n", i); + goto out_fail; + } + hdmi_update_short_audio_desc(e->sad + i, + buf + ELD_FIXED_BYTES + mnl + 3 * i); + } + + return 0; + +out_fail: + e->eld_ver = 0; + return -EINVAL; +} + +static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); +} + +static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid) +{ + int eldv; + int present; + + present = hdmi_present_sense(codec, nid); + eldv = (present & AC_PINSENSE_ELDV); + present = (present & AC_PINSENSE_PRESENCE); + +#ifdef CONFIG_SND_DEBUG_VERBOSE + printk(KERN_INFO "pinp = %d, eldv = %d\n", !!present, !!eldv); +#endif + + return eldv && present; +} + +int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, + AC_DIPSIZE_ELD_BUF); +} + +int snd_hdmi_get_eld(struct sink_eld *eld, + struct hda_codec *codec, hda_nid_t nid) +{ + int i; + int ret; + int size; + unsigned char *buf; + + if (!hdmi_eld_valid(codec, nid)) + return -ENOENT; + + size = snd_hdmi_get_eld_size(codec, nid); + if (size == 0) { + /* wfg: workaround for ASUS P5E-VM HDMI board */ + snd_printd(KERN_INFO "ELD buf size is 0, force 128\n"); + size = 128; + } + if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { + snd_printd(KERN_INFO "Invalid ELD buf size %d\n", size); + return -ERANGE; + } + + buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (i = 0; i < size; i++) + buf[i] = hdmi_get_eld_byte(codec, nid, i); + + ret = hdmi_update_sink_eld(eld, buf, size); + + kfree(buf); + return ret; +} + +static void hdmi_show_short_audio_desc(struct cea_sad *a) +{ + char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; + + printk(KERN_INFO "coding type: %s\n", + cea_audio_coding_type_names[a->format]); + printk(KERN_INFO "channels: %d\n", a->channels); + + snd_print_pcm_rates(a->rates, buf, sizeof(buf)); + printk(KERN_INFO "sampling frequencies: %s\n", buf); + + if (a->format == AUDIO_CODING_TYPE_LPCM) + printk(KERN_INFO "sample bits: 0x%x\n", a->sample_bits); + + if (a->max_bitrate) + printk(KERN_INFO "max bitrate: %d\n", a->max_bitrate); + + if (a->profile) + printk(KERN_INFO "profile: %d\n", a->profile); +} + +#define HDMI_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 +static void hdmi_print_channel_allocation(int spk_alloc, char *buf, int buflen) +{ + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { + if (spk_alloc & (1 << i)) + j += snprintf(buf + j, buflen - j, "%s ", + cea_speaker_allocation_names[i]); + } + if (j) + j--; /* skip last space */ + buf[j] = '\0'; /* necessary when j == 0 */ +} + +void snd_hdmi_show_eld(struct sink_eld *e) +{ + int i; + char buf[HDMI_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + + printk(KERN_INFO "ELD buffer size is %d\n", e->eld_size); + printk(KERN_INFO "ELD baseline len is %d*4\n", e->baseline_len); + printk(KERN_INFO "vendor block len is %d\n", + e->eld_size - e->baseline_len * 4 - 4); + printk(KERN_INFO "ELD version is %s\n", + eld_versoin_names[e->eld_ver]); + printk(KERN_INFO "CEA EDID version is %s\n", + cea_edid_version_names[e->cea_edid_ver]); + printk(KERN_INFO "manufacture id is 0x%x\n", e->manufacture_id); + printk(KERN_INFO "product id is 0x%x\n", e->product_id); + printk(KERN_INFO "port id is 0x%llx\n", (long long)e->port_id); + printk(KERN_INFO "HDCP support is %d\n", e->support_hdcp); + printk(KERN_INFO "AI support is %d\n", e->support_ai); + printk(KERN_INFO "SAD count is %d\n", e->sad_count); + printk(KERN_INFO "audio sync delay is %x\n", e->aud_synch_delay); + printk(KERN_INFO "connection type is %s\n", + eld_connection_type_names[e->conn_type]); + printk(KERN_INFO "monitor name is %s\n", e->monitor_name); + + hdmi_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + printk(KERN_INFO "speaker allocations: (0x%x)%s\n", e->spk_alloc, buf); + + for (i = 0; i < e->sad_count; i++) + hdmi_show_short_audio_desc(e->sad + i); +} diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index d7e3a164eff..e1b76686672 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -443,4 +443,45 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) +/* + * CEA Short Audio Descriptor data + */ +struct cea_sad { + int channels; + int format; /* (format == 0) indicates invalid SAD */ + int rates; + int sample_bits; /* for LPCM */ + int max_bitrate; /* for AC3...ATRAC */ + int profile; /* for WMAPRO */ +}; + +#define ELD_FIXED_BYTES 20 +#define ELD_MAX_MNL 16 +#define ELD_MAX_SAD 16 + +/* + * ELD: EDID Like Data + */ +struct sink_eld { + int eld_size; + int baseline_len; + int eld_ver; /* (eld_ver == 0) indicates invalid ELD */ + int cea_edid_ver; + char monitor_name[ELD_MAX_MNL + 1]; + int manufacture_id; + int product_id; + u64 port_id; + int support_hdcp; + int support_ai; + int conn_type; + int aud_synch_delay; + int spk_alloc; + int sad_count; + struct cea_sad sad[ELD_MAX_SAD]; +}; + +int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); +int snd_hdmi_get_eld(struct sink_eld *, struct hda_codec *, hda_nid_t); +void snd_hdmi_show_eld(struct sink_eld *eld); + #endif /* __SOUND_HDA_LOCAL_H */ diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index d99cd629724..489278d3d77 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -30,7 +30,6 @@ #include #include #include -#include #include "hda_codec.h" #include "hda_local.h" #include "hda_patch.h" @@ -40,43 +39,6 @@ #define INTEL_HDMI_EVENT_TAG 0x08 -/* - * CEA Short Audio Descriptor data - */ -struct cea_sad { - int channels; - int format; /* (format == 0) indicates invalid SAD */ - int rates; - int sample_bits; /* for LPCM */ - int max_bitrate; /* for AC3...ATRAC */ - int profile; /* for WMAPRO */ -}; - -#define ELD_FIXED_BYTES 20 -#define ELD_MAX_MNL 16 -#define ELD_MAX_SAD 16 - -/* - * ELD: EDID Like Data - */ -struct sink_eld { - int eld_size; - int baseline_len; - int eld_ver; /* (eld_ver == 0) indicates invalid ELD */ - int cea_edid_ver; - char monitor_name[ELD_MAX_MNL + 1]; - int manufacture_id; - int product_id; - u64 port_id; - int support_hdcp; - int support_ai; - int conn_type; - int aud_synch_delay; - int spk_alloc; - int sad_count; - struct cea_sad sad[ELD_MAX_SAD]; -}; - struct intel_hdmi_spec { struct hda_multi_out multiout; struct hda_pcm pcm_rec; @@ -126,161 +88,10 @@ struct hdmi_audio_infoframe { u8 reserved[5]; /* PB6 - PB10 */ }; -/* - * SS1:SS0 index => sample size - */ -static int cea_sample_sizes[4] = { - 0, /* 0: Refer to Stream Header */ - AC_SUPPCM_BITS_16, /* 1: 16 bits */ - AC_SUPPCM_BITS_20, /* 2: 20 bits */ - AC_SUPPCM_BITS_24, /* 3: 24 bits */ -}; - -/* - * SF2:SF1:SF0 index => sampling frequency - */ -static int cea_sampling_frequencies[8] = { - 0, /* 0: Refer to Stream Header */ - SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ - SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ - SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ - SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ - SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ - SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ - SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ -}; - -enum eld_versions { - ELD_VER_CEA_861D = 2, - ELD_VER_PARTIAL = 31, -}; - -static char *eld_versoin_names[32] = { - "0-reserved", - "1-reserved", - "CEA-861D or below", - "3-reserved", - [4 ... 30] = "reserved", - [31] = "partial" -}; - -enum cea_edid_versions { - CEA_EDID_VER_NONE = 0, - CEA_EDID_VER_CEA861 = 1, - CEA_EDID_VER_CEA861A = 2, - CEA_EDID_VER_CEA861BCD = 3, - CEA_EDID_VER_RESERVED = 4, -}; - -static char *cea_edid_version_names[8] = { - "no CEA EDID Timing Extension block present", - "CEA-861", - "CEA-861-A", - "CEA-861-B, C or D", - "4-reserved", - [5 ... 7] = "reserved" -}; - -/* - * CEA Speaker Allocation data block bits - */ -#define CEA_SA_FLR (0 << 0) -#define CEA_SA_LFE (1 << 1) -#define CEA_SA_FC (1 << 2) -#define CEA_SA_RLR (1 << 3) -#define CEA_SA_RC (1 << 4) -#define CEA_SA_FLRC (1 << 5) -#define CEA_SA_RLRC (1 << 6) -/* the following are not defined in ELD yet */ -#define CEA_SA_FLRW (1 << 7) -#define CEA_SA_FLRH (1 << 8) -#define CEA_SA_TC (1 << 9) -#define CEA_SA_FCH (1 << 10) - -static char *cea_speaker_allocation_names[] = { - /* 0 */ "FL/FR", - /* 1 */ "LFE", - /* 2 */ "FC", - /* 3 */ "RL/RR", - /* 4 */ "RC", - /* 5 */ "FLC/FRC", - /* 6 */ "RLC/RRC", - /* 7 */ "FLW/FRW", - /* 8 */ "FLH/FRH", - /* 9 */ "TC", - /* 10 */ "FCH", -}; - -static char *eld_connection_type_names[4] = { - "HDMI", - "Display Port", - "2-reserved", - "3-reserved" -}; - -enum cea_audio_coding_types { - AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, - AUDIO_CODING_TYPE_LPCM = 1, - AUDIO_CODING_TYPE_AC3 = 2, - AUDIO_CODING_TYPE_MPEG1 = 3, - AUDIO_CODING_TYPE_MP3 = 4, - AUDIO_CODING_TYPE_MPEG2 = 5, - AUDIO_CODING_TYPE_AACLC = 6, - AUDIO_CODING_TYPE_DTS = 7, - AUDIO_CODING_TYPE_ATRAC = 8, - AUDIO_CODING_TYPE_SACD = 9, - AUDIO_CODING_TYPE_EAC3 = 10, - AUDIO_CODING_TYPE_DTS_HD = 11, - AUDIO_CODING_TYPE_MLP = 12, - AUDIO_CODING_TYPE_DST = 13, - AUDIO_CODING_TYPE_WMAPRO = 14, - AUDIO_CODING_TYPE_REF_CXT = 15, - /* also include valid xtypes below */ - AUDIO_CODING_TYPE_HE_AAC = 15, - AUDIO_CODING_TYPE_HE_AAC2 = 16, - AUDIO_CODING_TYPE_MPEG_SURROUND = 17, -}; - -enum cea_audio_coding_xtypes { - AUDIO_CODING_XTYPE_HE_REF_CT = 0, - AUDIO_CODING_XTYPE_HE_AAC = 1, - AUDIO_CODING_XTYPE_HE_AAC2 = 2, - AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, - AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, -}; - -static char *cea_audio_coding_type_names[] = { - /* 0 */ "undefined", - /* 1 */ "LPCM", - /* 2 */ "AC-3", - /* 3 */ "MPEG1", - /* 4 */ "MP3", - /* 5 */ "MPEG2", - /* 6 */ "AAC-LC", - /* 7 */ "DTS", - /* 8 */ "ATRAC", - /* 9 */ "DSD(1-bit audio)", - /* 10 */ "Dolby Digital Plus(E-AC-3/DD+)", - /* 11 */ "DTS-HD", - /* 12 */ "Dolby TrueHD(MLP)", - /* 13 */ "DST", - /* 14 */ "WMAPro", - /* 15 */ "HE-AAC", - /* 16 */ "HE-AACv2", - /* 17 */ "MPEG Surround", -}; - - /* * HDMI routines */ -static int hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) -{ - return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, - AC_DIPSIZE_ELD_BUF); -} - #ifdef BE_PARANOID static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, int *packet_index, int *byte_index) @@ -375,294 +186,13 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec) } -/* - * ELD(EDID Like Data) routines - */ - -static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid) -{ - return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); -} - -static void hdmi_debug_present_sense(struct hda_codec *codec) -{ -#ifdef CONFIG_SND_DEBUG_VERBOSE - int eldv; - int present; - - present = hdmi_present_sense(codec, PIN_NID); - eldv = (present & AC_PINSENSE_ELDV); - present = (present & AC_PINSENSE_PRESENCE); - - printk(KERN_INFO "pinp = %d, eldv = %d\n", !!present, !!eldv); -#endif -} - -static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, int byte_index) -{ - unsigned int val; - - val = snd_hda_codec_read(codec, PIN_NID, 0, - AC_VERB_GET_HDMI_ELDD, byte_index); - -#ifdef BE_PARANOID - printk(KERN_INFO "ELD data byte %d: 0x%x\n", byte_index, val); -#endif - - if ((val & AC_ELDD_ELD_VALID) == 0) { - snd_printd(KERN_INFO "Invalid ELD data byte %d\n", - byte_index); - val = 0; - } - - return val & AC_ELDD_ELD_DATA; -} - -static inline unsigned char grab_bits(const unsigned char *buf, - int byte, int lowbit, int bits) -{ - BUG_ON(lowbit > 7); - BUG_ON(bits > 8); - BUG_ON(bits <= 0); - - return (buf[byte] >> lowbit) & ((1 << bits) - 1); -} - -static void hdmi_update_short_audio_desc(struct cea_sad *a, - const unsigned char *buf) -{ - int i; - int val; - - val = grab_bits(buf, 1, 0, 7); - a->rates = 0; - for (i = 0; i < 7; i++) - if (val & (1 << i)) - a->rates |= cea_sampling_frequencies[i + 1]; - - a->channels = grab_bits(buf, 0, 0, 3); - a->channels++; - - a->format = grab_bits(buf, 0, 3, 4); - switch (a->format) { - case AUDIO_CODING_TYPE_REF_STREAM_HEADER: - snd_printd(KERN_INFO - "audio coding type 0 not expected in ELD\n"); - break; - - case AUDIO_CODING_TYPE_LPCM: - val = grab_bits(buf, 2, 0, 3); - a->sample_bits = 0; - for (i = 0; i < 3; i++) - if (val & (1 << i)) - a->sample_bits |= cea_sample_sizes[i + 1]; - break; - - case AUDIO_CODING_TYPE_AC3: - case AUDIO_CODING_TYPE_MPEG1: - case AUDIO_CODING_TYPE_MP3: - case AUDIO_CODING_TYPE_MPEG2: - case AUDIO_CODING_TYPE_AACLC: - case AUDIO_CODING_TYPE_DTS: - case AUDIO_CODING_TYPE_ATRAC: - a->max_bitrate = grab_bits(buf, 2, 0, 8); - a->max_bitrate *= 8000; - break; - - case AUDIO_CODING_TYPE_SACD: - break; - - case AUDIO_CODING_TYPE_EAC3: - break; - - case AUDIO_CODING_TYPE_DTS_HD: - break; - - case AUDIO_CODING_TYPE_MLP: - break; - - case AUDIO_CODING_TYPE_DST: - break; - - case AUDIO_CODING_TYPE_WMAPRO: - a->profile = grab_bits(buf, 2, 0, 3); - break; - - case AUDIO_CODING_TYPE_REF_CXT: - a->format = grab_bits(buf, 2, 3, 5); - if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || - a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { - snd_printd(KERN_INFO - "audio coding xtype %d not expected in ELD\n", - a->format); - a->format = 0; - } else - a->format += AUDIO_CODING_TYPE_HE_AAC - - AUDIO_CODING_XTYPE_HE_AAC; - break; - } -} - -static int hdmi_update_sink_eld(struct hda_codec *codec, - const unsigned char *buf, int size) -{ - struct intel_hdmi_spec *spec = codec->spec; - struct sink_eld *e = &spec->sink; - int mnl; - int i; - - e->eld_ver = grab_bits(buf, 0, 3, 5); - if (e->eld_ver != ELD_VER_CEA_861D && - e->eld_ver != ELD_VER_PARTIAL) { - snd_printd(KERN_INFO "Unknown ELD version %d\n", e->eld_ver); - goto out_fail; - } - - e->eld_size = size; - e->baseline_len = grab_bits(buf, 2, 0, 8); - mnl = grab_bits(buf, 4, 0, 5); - e->cea_edid_ver = grab_bits(buf, 4, 5, 3); - - e->support_hdcp = grab_bits(buf, 5, 0, 1); - e->support_ai = grab_bits(buf, 5, 1, 1); - e->conn_type = grab_bits(buf, 5, 2, 2); - e->sad_count = grab_bits(buf, 5, 4, 4); - - e->aud_synch_delay = grab_bits(buf, 6, 0, 8); - e->spk_alloc = grab_bits(buf, 7, 0, 7); - - e->port_id = get_unaligned_le64(buf + 8); - - /* not specified, but the spec's tendency is little endian */ - e->manufacture_id = get_unaligned_le16(buf + 16); - e->product_id = get_unaligned_le16(buf + 18); - - if (mnl > ELD_MAX_MNL) { - snd_printd(KERN_INFO "MNL is reserved value %d\n", mnl); - goto out_fail; - } else if (ELD_FIXED_BYTES + mnl > size) { - snd_printd(KERN_INFO "out of range MNL %d\n", mnl); - goto out_fail; - } else - strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl); - - for (i = 0; i < e->sad_count; i++) { - if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { - snd_printd(KERN_INFO "out of range SAD %d\n", i); - goto out_fail; - } - hdmi_update_short_audio_desc(e->sad + i, - buf + ELD_FIXED_BYTES + mnl + 3 * i); - } - - return 0; - -out_fail: - e->eld_ver = 0; - return -EINVAL; -} - -static int hdmi_get_eld(struct hda_codec *codec) -{ - int i; - int ret; - int size; - unsigned char *buf; - - i = hdmi_present_sense(codec, PIN_NID) & AC_PINSENSE_ELDV; - if (!i) - return -ENOENT; - - size = hdmi_get_eld_size(codec, PIN_NID); - if (size == 0) { - /* wfg: workaround for ASUS P5E-VM HDMI board */ - snd_printd(KERN_INFO "ELD buf size is 0, force 128\n"); - size = 128; - } - if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { - snd_printd(KERN_INFO "Invalid ELD buf size %d\n", size); - return -ERANGE; - } - - buf = kmalloc(size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - for (i = 0; i < size; i++) - buf[i] = hdmi_get_eld_byte(codec, i); - - ret = hdmi_update_sink_eld(codec, buf, size); - - kfree(buf); - return ret; -} - -static void hdmi_show_short_audio_desc(struct cea_sad *a) -{ - printk(KERN_INFO "coding type: %s\n", - cea_audio_coding_type_names[a->format]); - printk(KERN_INFO "channels: %d\n", a->channels); - printk(KERN_INFO "sampling frequencies: 0x%x\n", a->rates); - - if (a->format == AUDIO_CODING_TYPE_LPCM) - printk(KERN_INFO "sample bits: 0x%x\n", a->sample_bits); - - if (a->max_bitrate) - printk(KERN_INFO "max bitrate: %d HZ\n", a->max_bitrate); - - if (a->profile) - printk(KERN_INFO "profile: %d\n", a->profile); -} - -static void hdmi_show_eld(struct hda_codec *codec) -{ - int i; - int j; - struct intel_hdmi_spec *spec = codec->spec; - struct sink_eld *e = &spec->sink; - char buf[80]; - - printk(KERN_INFO "ELD buffer size is %d\n", e->eld_size); - printk(KERN_INFO "ELD baseline len is %d*4\n", e->baseline_len); - printk(KERN_INFO "vendor block len is %d\n", - e->eld_size - e->baseline_len * 4 - 4); - printk(KERN_INFO "ELD version is %s\n", - eld_versoin_names[e->eld_ver]); - printk(KERN_INFO "CEA EDID version is %s\n", - cea_edid_version_names[e->cea_edid_ver]); - printk(KERN_INFO "manufacture id is 0x%x\n", e->manufacture_id); - printk(KERN_INFO "product id is 0x%x\n", e->product_id); - printk(KERN_INFO "port id is 0x%llx\n", (long long)e->port_id); - printk(KERN_INFO "HDCP support is %d\n", e->support_hdcp); - printk(KERN_INFO "AI support is %d\n", e->support_ai); - printk(KERN_INFO "SAD count is %d\n", e->sad_count); - printk(KERN_INFO "audio sync delay is %x\n", e->aud_synch_delay); - printk(KERN_INFO "connection type is %s\n", - eld_connection_type_names[e->conn_type]); - printk(KERN_INFO "monitor name is %s\n", e->monitor_name); - - j = 0; - for (i = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { - if (e->spk_alloc & (1 << i)) - j += snprintf(buf + j, sizeof(buf) - j, " %s", - cea_speaker_allocation_names[i]); - } - buf[j] = '\0'; /* necessary when j == 0 */ - printk(KERN_INFO "speaker allocations: (0x%x)%s\n", e->spk_alloc, buf); - - for (i = 0; i < e->sad_count; i++) - hdmi_show_short_audio_desc(e->sad + i); -} - -/* - * Be careful, ELD buf could be totally rubbish! - */ static void hdmi_parse_eld(struct hda_codec *codec) { - hdmi_debug_present_sense(codec); + struct intel_hdmi_spec *spec = codec->spec; + struct sink_eld *eld = &spec->sink; - if (!hdmi_get_eld(codec)) - hdmi_show_eld(codec); + if (!snd_hdmi_get_eld(eld, codec, PIN_NID)) + snd_hdmi_show_eld(eld); } @@ -676,7 +206,7 @@ static void hdmi_debug_dip_size(struct hda_codec *codec) int i; int size; - size = hdmi_get_eld_size(codec, PIN_NID); + size = snd_hdmi_get_eld_size(codec, PIN_NID); printk(KERN_DEBUG "ELD buf size is %d\n", size); for (i = 0; i < 8; i++) { -- cgit v1.2.3 From 5f1e71b1cc2cc788c0f452772e2ce5e7430c40c2 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Tue, 18 Nov 2008 11:47:53 +0800 Subject: ALSA: ELD proc interface for HDMI sinks Create /proc/asound/card/eld# to reflect the audio configurations and capabilities of the attached HDMI sink. Some notes: - Shall we show an empty file if the ELD content is not valid? Well it's not that simple. There could be partially populated ELD, and there may be malformed ELD provided by buggy drivers/monitors. So expose ELD as it is. - The ELD retrieval routines rely on the Intel HDA interface, others are/could be universal and independent ones. - How do we name the proc file? If there are going to be two HDMI pins per codec, then the current naming scheme (eld#) will fail. Luckily the user space dependencies should be minimal, so it would be trivial to do the rename if that happens. - The ELD proc file content is designed to be easy for scripts and human reading. Its lines all have the pattern: \t[\t]* where is a keyword in c language, while could be any contents, including white spaces. could also be a null value. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 74 +++++++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_local.h | 9 +++++ sound/pci/hda/patch_intelhdmi.c | 2 ++ 3 files changed, 85 insertions(+) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index a69a7e87d26..7fa065cd1d9 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -452,3 +452,77 @@ void snd_hdmi_show_eld(struct sink_eld *e) for (i = 0; i < e->sad_count; i++) hdmi_show_short_audio_desc(e->sad + i); } + +#ifdef CONFIG_PROC_FS + +static void hdmi_print_sad_info(int i, struct cea_sad *a, + struct snd_info_buffer *buffer) +{ + char buf[80]; + + snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n", + i, a->format, cea_audio_coding_type_names[a->format]); + snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels); + + snd_print_pcm_rates(a->rates, buf, sizeof(buf)); + snd_iprintf(buffer, "sad%d_sampling_rates\t[0x%x] %s\n", + i, a->rates, buf); + + if (a->format == AUDIO_CODING_TYPE_LPCM) + snd_iprintf(buffer, "sad%d_sample_bits\t0x%x\n", + i, a->sample_bits); + + if (a->max_bitrate) + snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n", + i, a->max_bitrate); + + if (a->profile) + snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile); +} + +static void hdmi_print_eld_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct sink_eld *e = entry->private_data; + char buf[HDMI_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + int i; + + snd_iprintf(buffer, "monitor name\t\t%s\n", e->monitor_name); + snd_iprintf(buffer, "connection_type\t\t%s\n", + eld_connection_type_names[e->conn_type]); + snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver, + eld_versoin_names[e->eld_ver]); + snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver, + cea_edid_version_names[e->cea_edid_ver]); + snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id); + snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id); + snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id); + snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp); + snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai); + snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); + + hdmi_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + snd_iprintf(buffer, "speakers\t\t[0x%x] %s\n", e->spk_alloc, buf); + + snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); + + for (i = 0; i < e->sad_count; i++) + hdmi_print_sad_info(i, e->sad + i, buffer); +} + +int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld) +{ + char name[32]; + struct snd_info_entry *entry; + int err; + + snprintf(name, sizeof(name), "eld#%d", codec->addr); + err = snd_card_proc_new(codec->bus->card, name, &entry); + if (err < 0) + return err; + + snd_info_set_text_ops(entry, eld, hdmi_print_eld_info); + return 0; +} + +#endif diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index e1b76686672..02ac7321e5e 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -484,4 +484,13 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); int snd_hdmi_get_eld(struct sink_eld *, struct hda_codec *, hda_nid_t); void snd_hdmi_show_eld(struct sink_eld *eld); +#ifdef CONFIG_PROC_FS +int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld); +#else +inline int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld) +{ + return 0; +} +#endif + #endif /* __SOUND_HDA_LOCAL_H */ diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 489278d3d77..c95abc47614 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -446,6 +446,8 @@ static int patch_intel_hdmi(struct hda_codec *codec) codec->spec = spec; codec->patch_ops = intel_hdmi_patch_ops; + snd_hda_eld_proc_new(codec, &spec->sink); + return 0; } -- cgit v1.2.3 From e4973e1e5a42072ce88736ba0e39e4b8fc6c3c44 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2008 09:32:42 +0100 Subject: ALSA: hda - Create jack detection elements in build_controls The jack detection input elements should be created in build_controls callback instead of init callback because init can be called multiple times by suspend/resume and power-saving. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 59 ++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 1aa3f6cbcb9..b6cf821434c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1249,10 +1249,13 @@ static const char *slave_sws[] = { }; static void stac92xx_free_kctls(struct hda_codec *codec); +static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type); static int stac92xx_build_controls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t nid; int err; int i; @@ -1323,6 +1326,36 @@ static int stac92xx_build_controls(struct hda_codec *codec) } stac92xx_free_kctls(codec); /* no longer needed */ + + /* create jack input elements */ + if (spec->hp_detect) { + for (i = 0; i < cfg->hp_outs; i++) { + int type = SND_JACK_HEADPHONE; + nid = cfg->hp_pins[i]; + /* jack detection */ + if (cfg->hp_outs == i) + type |= SND_JACK_LINEOUT; + err = stac92xx_add_jack(codec, nid, type); + if (err < 0) + return err; + } + } + for (i = 0; i < cfg->line_outs; i++) { + err = stac92xx_add_jack(codec, cfg->line_out_pins[i], + SND_JACK_LINEOUT); + if (err < 0) + return err; + } + for (i = 0; i < AUTO_PIN_LAST; i++) { + nid = cfg->input_pins[i]; + if (nid) { + err = stac92xx_add_jack(codec, nid, + SND_JACK_MICROPHONE); + if (err < 0) + return err; + } + } + return 0; } @@ -3658,6 +3691,7 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type) { +#ifdef CONFIG_SND_JACK struct sigmatel_spec *spec = codec->spec; struct sigmatel_jack *jack; int def_conf = snd_hda_codec_read(codec, nid, @@ -3681,6 +3715,9 @@ static int stac92xx_add_jack(struct hda_codec *codec, snd_hda_get_jack_location(def_conf)); return snd_jack_new(codec->bus->card, name, type, &jack->jack); +#else + return 0; +#endif } static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid, @@ -3748,7 +3785,7 @@ static int stac92xx_init(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; + int i; snd_hda_sequence_write(codec, spec->init); @@ -3762,16 +3799,8 @@ static int stac92xx_init(struct hda_codec *codec) if (spec->hp_detect) { /* Enable unsolicited responses on the HP widget */ for (i = 0; i < cfg->hp_outs; i++) { - int type = SND_JACK_HEADPHONE; hda_nid_t nid = cfg->hp_pins[i]; enable_pin_detect(codec, nid, STAC_HP_EVENT | nid); - /* jack detection */ - if (cfg->hp_outs == i) - type |= SND_JACK_LINEOUT; - err = stac92xx_add_jack(codec, nid, type); - if (err < 0) - return err; - } /* force to enable the first line-out; the others are set up * in unsol_event @@ -3785,12 +3814,6 @@ static int stac92xx_init(struct hda_codec *codec) stac92xx_auto_init_multi_out(codec); stac92xx_auto_init_hp_out(codec); } - for (i = 0; i < cfg->line_outs; i++) { - err = stac92xx_add_jack(codec, - cfg->line_out_pins[i], SND_JACK_LINEOUT); - if (err < 0) - return err; - } for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = cfg->input_pins[i]; if (nid) { @@ -3807,10 +3830,6 @@ static int stac92xx_init(struct hda_codec *codec) } pinctl |= AC_PINCTL_IN_EN; stac92xx_auto_set_pinctl(codec, nid, pinctl); - err = stac92xx_add_jack(codec, nid, - SND_JACK_MICROPHONE); - if (err < 0) - return err; enable_pin_detect(codec, nid, STAC_INSERT_EVENT | nid); } } @@ -3855,6 +3874,7 @@ static int stac92xx_init(struct hda_codec *codec) static void stac92xx_free_jacks(struct hda_codec *codec) { +#ifdef CONFIG_SND_JACK struct sigmatel_spec *spec = codec->spec; if (spec->jacks.list) { struct sigmatel_jack *jacks = spec->jacks.list; @@ -3863,6 +3883,7 @@ static void stac92xx_free_jacks(struct hda_codec *codec) snd_device_free(codec->bus->card, &jacks[i].jack); } snd_array_free(&spec->jacks); +#endif } static void stac92xx_free_kctls(struct hda_codec *codec) -- cgit v1.2.3 From 2c885878c1b29293f04cfb4a5bd285c969148a8b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2008 09:36:55 +0100 Subject: ALSA: hda - Use init callback in stac92xx_resume() Call the init callback and remove duplicated codes in stac92xx_resume(). This also fixes the missing initialization such as digital I/O pins. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index b6cf821434c..bf9a40ee789 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4142,17 +4142,13 @@ static int stac92xx_resume(struct hda_codec *codec) struct sigmatel_spec *spec = codec->spec; stac92xx_set_config_regs(codec); - snd_hda_sequence_write(codec, spec->init); - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data); + stac92xx_init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); - /* power down inactive DACs */ - if (spec->dac_list) - stac92xx_power_down(codec); - /* invoke unsolicited event to reset the HP state */ + /* fake event to set up pins again to override cached values */ if (spec->hp_detect) - codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); + codec->patch_ops.unsol_event(codec, + (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26); return 0; } #endif -- cgit v1.2.3 From af9f341a94482594ac28cb5b07c655b458bfe84e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2008 10:38:56 +0100 Subject: ALSA: hda - Fix restore of pin configs at resume for STAC/IDT codecs Fixed the restore of pin configs at resume for some STAC/IDT codec models. These models set explicitly the pin configs after the default init configs, and these aren't restored properly at resume. This patch introduces two changes: - Allocate always pin_configs array in stac_spec so that the driver can overwrite the value freely - Introduce stac_change_pin_config() to change the pin config value Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 178 ++++++++++++++++++++++------------------- 1 file changed, 96 insertions(+), 82 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index bf9a40ee789..3029f5b1419 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -210,7 +210,6 @@ struct sigmatel_spec { hda_nid_t *pin_nids; unsigned int num_pins; unsigned int *pin_configs; - unsigned int *bios_pin_configs; /* codec specific stuff */ struct hda_verb *init; @@ -2219,12 +2218,11 @@ static int stac92xx_save_bios_config_regs(struct hda_codec *codec) int i; struct sigmatel_spec *spec = codec->spec; - if (! spec->bios_pin_configs) { - spec->bios_pin_configs = kcalloc(spec->num_pins, - sizeof(*spec->bios_pin_configs), GFP_KERNEL); - if (! spec->bios_pin_configs) - return -ENOMEM; - } + kfree(spec->pin_configs); + spec->pin_configs = kcalloc(spec->num_pins, sizeof(*spec->pin_configs), + GFP_KERNEL); + if (!spec->pin_configs) + return -ENOMEM; for (i = 0; i < spec->num_pins; i++) { hda_nid_t nid = spec->pin_nids[i]; @@ -2234,7 +2232,7 @@ static int stac92xx_save_bios_config_regs(struct hda_codec *codec) AC_VERB_GET_CONFIG_DEFAULT, 0x00); snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n", nid, pin_cfg); - spec->bios_pin_configs[i] = pin_cfg; + spec->pin_configs[i] = pin_cfg; } return 0; @@ -2276,6 +2274,39 @@ static void stac92xx_set_config_regs(struct hda_codec *codec) spec->pin_configs[i]); } +static int stac_save_pin_cfgs(struct hda_codec *codec, unsigned int *pins) +{ + struct sigmatel_spec *spec = codec->spec; + + if (!pins) + return stac92xx_save_bios_config_regs(codec); + + kfree(spec->pin_configs); + spec->pin_configs = kmemdup(pins, + spec->num_pins * sizeof(*pins), + GFP_KERNEL); + if (!spec->pin_configs) + return -ENOMEM; + + stac92xx_set_config_regs(codec); + return 0; +} + +static void stac_change_pin_config(struct hda_codec *codec, hda_nid_t nid, + unsigned int cfg) +{ + struct sigmatel_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_pins; i++) { + if (spec->pin_nids[i] == nid) { + spec->pin_configs[i] = cfg; + stac92xx_set_config_reg(codec, nid, cfg); + break; + } + } +} + /* * Analog playback callbacks */ @@ -3906,8 +3937,7 @@ static void stac92xx_free(struct hda_codec *codec) if (! spec) return; - if (spec->bios_pin_configs) - kfree(spec->bios_pin_configs); + kfree(spec->pin_configs); stac92xx_free_jacks(codec); snd_array_free(&spec->events); @@ -4182,14 +4212,12 @@ static int patch_stac9200(struct hda_codec *codec) if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac9200_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac9200_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->multiout.max_channels = 2; @@ -4245,14 +4273,12 @@ static int patch_stac925x(struct hda_codec *codec) snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x," "using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else if (stac925x_brd_tbl[spec->board_config] != NULL){ - spec->pin_configs = stac925x_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac925x_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->multiout.max_channels = 2; @@ -4334,14 +4360,12 @@ again: snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD73XX, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac92hd73xx_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a, @@ -4517,14 +4541,12 @@ again: snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD83XXX, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac92hd83xxx_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } err = stac92xx_parse_auto_config(codec, 0x1d, 0); @@ -4631,14 +4653,12 @@ again: snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD71BXX, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac92hd71bxx_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } switch (codec->vendor_id) { @@ -4680,7 +4700,7 @@ again: /* disable VSW */ spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; - stac92xx_set_config_reg(codec, 0xf, 0x40f000f0); + stac_change_pin_config(codec, 0xf, 0x40f000f0); break; case 0x111d7603: /* 6 Port with Analog Mixer */ if ((codec->revision_id & 0xf) == 1) { @@ -4729,7 +4749,7 @@ again: spec->num_dmuxes = 0; /* enable internal microphone */ - stac92xx_set_config_reg(codec, 0x0e, 0x01813040); + stac_change_pin_config(codec, 0x0e, 0x01813040); stac92xx_auto_set_pinctl(codec, 0x0e, AC_PINCTL_IN_EN | AC_PINCTL_VREF_80); break; @@ -4824,14 +4844,12 @@ static int patch_stac922x(struct hda_codec *codec) snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " "using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else if (stac922x_brd_tbl[spec->board_config] != NULL) { - spec->pin_configs = stac922x_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac922x_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->adc_nids = stac922x_adc_nids; @@ -4894,14 +4912,12 @@ static int patch_stac927x(struct hda_codec *codec) snd_printdd(KERN_INFO "hda_codec: Unknown model for" "STAC927x, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac927x_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac927x_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->digbeep_nid = 0x23; @@ -4931,15 +4947,15 @@ static int patch_stac927x(struct hda_codec *codec) case 0x10280209: case 0x1028022e: /* correct the device field to SPDIF out */ - stac92xx_set_config_reg(codec, 0x21, 0x01442070); + stac_change_pin_config(codec, 0x21, 0x01442070); break; }; /* configure the analog microphone on some laptops */ - stac92xx_set_config_reg(codec, 0x0c, 0x90a79130); + stac_change_pin_config(codec, 0x0c, 0x90a79130); /* correct the front output jack as a hp out */ - stac92xx_set_config_reg(codec, 0x0f, 0x0227011f); + stac_change_pin_config(codec, 0x0f, 0x0227011f); /* correct the front input jack as a mic */ - stac92xx_set_config_reg(codec, 0x0e, 0x02a79130); + stac_change_pin_config(codec, 0x0e, 0x02a79130); /* fallthru */ case STAC_DELL_3ST: /* GPIO2 High = Enable EAPD */ @@ -5021,14 +5037,12 @@ static int patch_stac9205(struct hda_codec *codec) if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac9205_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac9205_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->digbeep_nid = 0x23; @@ -5055,8 +5069,8 @@ static int patch_stac9205(struct hda_codec *codec) switch (spec->board_config){ case STAC_9205_DELL_M43: /* Enable SPDIF in/out */ - stac92xx_set_config_reg(codec, 0x1f, 0x01441030); - stac92xx_set_config_reg(codec, 0x20, 0x1c410030); + stac_change_pin_config(codec, 0x1f, 0x01441030); + stac_change_pin_config(codec, 0x20, 0x1c410030); /* Enable unsol response for GPIO4/Dock HP connection */ snd_hda_codec_write(codec, codec->afg, 0, -- cgit v1.2.3 From cd896c331dd442c43cd9e23de3f1a4f3c111c292 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2008 12:36:33 +0100 Subject: ALSA: hda - Allow multiple imux for matrix-type mixers of ALC codecs Allow the multiple imux instances for matrix-type mixers like ALC882. So far, only ALC260 used this feature, but other codecs may need a similar stuff. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 04e153a77db..b7d34390eff 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -382,11 +382,15 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux = spec->input_mux; + const struct hda_input_mux *imux; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + unsigned int mux_idx; hda_nid_t nid = spec->capsrc_nids ? spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; + mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; + imux = &spec->input_mux[mux_idx]; + if (spec->is_mix_capture) { /* Matrix-mixer style (e.g. ALC882) */ unsigned int *cur_val = &spec->cur_mux[adc_idx]; @@ -407,10 +411,7 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, return 1; } else { /* MUX style (e.g. ALC880) */ - unsigned int mux_idx; - mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; - return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], - ucontrol, nid, + return snd_hda_input_mux_put(codec, imux, ucontrol, nid, &spec->cur_mux[adc_idx]); } } -- cgit v1.2.3 From 5457a98039cebf20b564b5c3d73a50615e2b2696 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 08:56:15 +0800 Subject: ALSA: hda: make standalone hdmi_fill_audio_infoframe() code refactor: make a standalone function hdmi_fill_audio_infoframe(). Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index c95abc47614..028fce996aa 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -246,24 +246,31 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec) #endif } +static void hdmi_fill_audio_infoframe(struct hda_codec *codec, + struct hdmi_audio_infoframe *ai) +{ + u8 *params = (u8 *)ai; + int i; + + hdmi_debug_dip_size(codec); + hdmi_clear_dip_buffers(codec); /* be paranoid */ + + hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); + for (i = 0; i < sizeof(ai); i++) + hdmi_write_dip_byte(codec, PIN_NID, params[i]); +} + static void hdmi_setup_audio_infoframe(struct hda_codec *codec, struct snd_pcm_substream *substream) { - struct hdmi_audio_infoframe audio_infoframe = { + struct hdmi_audio_infoframe ai = { .type = 0x84, .ver = 0x01, .len = 0x0a, .CC02_CT47 = substream->runtime->channels - 1, }; - u8 *params = (u8 *)&audio_infoframe; - int i; - - hdmi_debug_dip_size(codec); - hdmi_clear_dip_buffers(codec); /* be paranoid */ - hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); - for (i = 0; i < sizeof(audio_infoframe); i++) - hdmi_write_dip_byte(codec, PIN_NID, params[i]); + hdmi_fill_audio_infoframe(codec, &ai); } -- cgit v1.2.3 From 903b21d8b7bb49d3438abdd7b9d4145511e1cba2 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 08:56:16 +0800 Subject: ALSA: hda: make global snd_print_channel_allocation() code refactor: make a global function snd_print_channel_allocation(). Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 11 +++++------ sound/pci/hda/hda_local.h | 3 +++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 7fa065cd1d9..18078de0abc 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -407,8 +407,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) printk(KERN_INFO "profile: %d\n", a->profile); } -#define HDMI_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 -static void hdmi_print_channel_allocation(int spk_alloc, char *buf, int buflen) +void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) { int i, j; @@ -425,7 +424,7 @@ static void hdmi_print_channel_allocation(int spk_alloc, char *buf, int buflen) void snd_hdmi_show_eld(struct sink_eld *e) { int i; - char buf[HDMI_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; printk(KERN_INFO "ELD buffer size is %d\n", e->eld_size); printk(KERN_INFO "ELD baseline len is %d*4\n", e->baseline_len); @@ -446,7 +445,7 @@ void snd_hdmi_show_eld(struct sink_eld *e) eld_connection_type_names[e->conn_type]); printk(KERN_INFO "monitor name is %s\n", e->monitor_name); - hdmi_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); printk(KERN_INFO "speaker allocations: (0x%x)%s\n", e->spk_alloc, buf); for (i = 0; i < e->sad_count; i++) @@ -484,7 +483,7 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct sink_eld *e = entry->private_data; - char buf[HDMI_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; int i; snd_iprintf(buffer, "monitor name\t\t%s\n", e->monitor_name); @@ -501,7 +500,7 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai); snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); - hdmi_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); snd_iprintf(buffer, "speakers\t\t[0x%x] %s\n", e->spk_alloc, buf); snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 02ac7321e5e..0baa9b816ca 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -493,4 +493,7 @@ inline int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld) } #endif +#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 +void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen); + #endif /* __SOUND_HDA_LOCAL_H */ -- cgit v1.2.3 From 698544de8a31a7cadc26c27cbaa69ae82dd4f86c Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 08:56:17 +0800 Subject: ALSA: hda: HDMI channel allocations for audio infoframe To play a 3+ channels LPCM/DSD stream via HDMI, - HDMI sink must tell HDMI source about its speaker placements (via ELD, speaker-allocation field) - HDMI source must tell the HDMI sink about channel allocation (via audio infoframe, channel-allocation field) (related docs: HDMI 1.3a spec section 7.4, CEA-861-D section 7.5.3 and 6.6) This patch attempts to set the CA(channel-allocation) byte in the audio infoframe according to - the number of channels in the current stream - the speakers attached to the HDMI sink A channel_allocations[] line must meet the following two criteria to be considered as a valid candidate for CA: 1) its number of allocated channels = substream->runtime->channels 2) its speakers are a subset of the available ones on the sink side If there are multiple candidates, the first one is selected. This simple policy shall cheat the sink into playing music, but may direct data to the wrong speakers. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 205 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 028fce996aa..6b5c3e2cf93 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -88,6 +88,132 @@ struct hdmi_audio_infoframe { u8 reserved[5]; /* PB6 - PB10 */ }; +/* + * CEA speaker placement: + * + * FLH FCH FRH + * FLW FL FLC FC FRC FR FRW + * + * LFE + * TC + * + * RL RLC RC RRC RR + * + * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to + * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC. + */ +enum cea_speaker_placement { + FL = (1 << 0), /* Front Left */ + FC = (1 << 1), /* Front Center */ + FR = (1 << 2), /* Front Right */ + FLC = (1 << 3), /* Front Left Center */ + FRC = (1 << 4), /* Front Right Center */ + RL = (1 << 5), /* Rear Left */ + RC = (1 << 6), /* Rear Center */ + RR = (1 << 7), /* Rear Right */ + RLC = (1 << 8), /* Rear Left Center */ + RRC = (1 << 9), /* Rear Right Center */ + LFE = (1 << 10), /* Low Frequency Effect */ + FLW = (1 << 11), /* Front Left Wide */ + FRW = (1 << 12), /* Front Right Wide */ + FLH = (1 << 13), /* Front Left High */ + FCH = (1 << 14), /* Front Center High */ + FRH = (1 << 15), /* Front Right High */ + TC = (1 << 16), /* Top Center */ +}; + +/* + * ELD SA bits in the CEA Speaker Allocation data block + */ +static int eld_speaker_allocation_bits[] = { + [0] = FL | FR, + [1] = LFE, + [2] = FC, + [3] = RL | RR, + [4] = RC, + [5] = FLC | FRC, + [6] = RLC | RRC, + /* the following are not defined in ELD yet */ + [7] = FLW | FRW, + [8] = FLH | FRH, + [9] = TC, + [10] = FCH, +}; + +struct cea_channel_speaker_allocation { + int ca_index; + int speakers[8]; + + /* derived values, just for convenience */ + int channels; + int spk_mask; +}; + +/* + * This is an ordered list! + * + * The preceding ones have better chances to be selected by + * hdmi_setup_channel_allocation(). + */ +static struct cea_channel_speaker_allocation channel_allocations[] = { +/* channel: 8 7 6 5 4 3 2 1 */ +{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, + /* 2.1 */ +{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } }, + /* dolby surround */ +{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } }, +{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } }, +{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } }, +{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } }, +{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } }, +{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } }, +{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } }, + /* 5.1 */ +{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } }, + /* 6.1 */ +{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } }, + /* 7.1 */ +{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } }, +{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } }, +{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } }, +{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } }, +{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } }, +{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } }, +{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } }, +{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } }, +{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, +}; + /* * HDMI routines */ @@ -260,6 +386,81 @@ static void hdmi_fill_audio_infoframe(struct hda_codec *codec, hdmi_write_dip_byte(codec, PIN_NID, params[i]); } +/* + * Compute derived values in channel_allocations[]. + */ +static void init_channel_allocations(void) +{ + int i, j; + struct cea_channel_speaker_allocation *p; + + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + p = channel_allocations + i; + p->channels = 0; + p->spk_mask = 0; + for (j = 0; j < ARRAY_SIZE(p->speakers); j++) + if (p->speakers[j]) { + p->channels++; + p->spk_mask |= p->speakers[j]; + } + } +} + +/* + * The transformation takes two steps: + * + * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask + * spk_mask => (channel_allocations[]) => ai->CA + * + * TODO: it could select the wrong CA from multiple candidates. +*/ +static int hdmi_setup_channel_allocation(struct hda_codec *codec, + struct hdmi_audio_infoframe *ai) +{ + struct intel_hdmi_spec *spec = codec->spec; + struct sink_eld *eld = &spec->sink; + int i; + int spk_mask = 0; + int channels = 1 + (ai->CC02_CT47 & 0x7); + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + + /* + * CA defaults to 0 for basic stereo audio + */ + if (!eld->eld_ver) + return 0; + if (!eld->spk_alloc) + return 0; + if (channels <= 2) + return 0; + + /* + * expand ELD's speaker allocation mask + * + * ELD tells the speaker mask in a compact(paired) form, + * expand ELD's notions to match the ones used by audio infoframe. + */ + for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { + if (eld->spk_alloc & (1 << i)) + spk_mask |= eld_speaker_allocation_bits[i]; + } + + /* search for the first working match in the CA table */ + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + if (channels == channel_allocations[i].channels && + (spk_mask & channel_allocations[i].spk_mask) == + channel_allocations[i].spk_mask) { + ai->CA = channel_allocations[i].ca_index; + return 0; + } + } + + snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); + snd_printd(KERN_INFO "failed to setup channel allocation: %d of %s\n", + channels, buf); + return -1; +} + static void hdmi_setup_audio_infoframe(struct hda_codec *codec, struct snd_pcm_substream *substream) { @@ -270,6 +471,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, .CC02_CT47 = substream->runtime->channels - 1, }; + hdmi_setup_channel_allocation(codec, &ai); + hdmi_fill_audio_infoframe(codec, &ai); } @@ -455,6 +658,8 @@ static int patch_intel_hdmi(struct hda_codec *codec) snd_hda_eld_proc_new(codec, &spec->sink); + init_channel_allocations(); + return 0; } -- cgit v1.2.3 From 9c8641e8ee438273079337c86f4d739fbfdd8b33 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 08:56:18 +0800 Subject: ALSA: hda: HDMI channel mapping cleanups Refactor the channel mapping code for consistent naming and make it more informed about channel allocations. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 6b5c3e2cf93..747aa84d0ec 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -290,7 +290,7 @@ static void hdmi_set_channel_count(struct hda_codec *codec, int chs) chs, hdmi_get_channel_count(codec)); } -static void hdmi_debug_slot_mapping(struct hda_codec *codec) +static void hdmi_debug_channel_mapping(struct hda_codec *codec) { #ifdef CONFIG_SND_DEBUG_VERBOSE int i; @@ -305,13 +305,6 @@ static void hdmi_debug_slot_mapping(struct hda_codec *codec) #endif } -static void hdmi_setup_channel_mapping(struct hda_codec *codec) -{ - snd_hda_sequence_write(codec, def_chan_map); - hdmi_debug_slot_mapping(codec); -} - - static void hdmi_parse_eld(struct hda_codec *codec) { struct intel_hdmi_spec *spec = codec->spec; @@ -461,6 +454,22 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, return -1; } +static void hdmi_setup_channel_mapping(struct hda_codec *codec, + struct hdmi_audio_infoframe *ai) +{ + if (!ai->CA) + return; + + /* + * TODO: adjust channel mapping if necessary + * ALSA sequence is front/surr/clfe/side? + */ + + snd_hda_sequence_write(codec, def_chan_map); + hdmi_debug_channel_mapping(codec); +} + + static void hdmi_setup_audio_infoframe(struct hda_codec *codec, struct snd_pcm_substream *substream) { @@ -472,6 +481,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, }; hdmi_setup_channel_allocation(codec, &ai); + hdmi_setup_channel_mapping(codec, &ai); hdmi_fill_audio_infoframe(codec, &ai); } @@ -569,9 +579,6 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, hdmi_set_channel_count(codec, substream->runtime->channels); - /* wfg: channel mapping not supported by DEVCTG */ - hdmi_setup_channel_mapping(codec); - hdmi_setup_audio_infoframe(codec, substream); hdmi_enable_output(codec); -- cgit v1.2.3 From c6798d2bd1805e32a92ba8db168ec51cdbb534b0 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Tue, 18 Nov 2008 20:54:17 -0500 Subject: ALSA: hda: EAPD mute on suspend Moved support for EAPD mute on suspend from stac92hd71xx_suspend to the generic stac92xx_suspend function. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 139efe37f3b..c346c77e306 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4185,6 +4185,16 @@ static int stac92xx_resume(struct hda_codec *codec) (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26); return 0; } + +static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) +{ + struct sigmatel_spec *spec = codec->spec; + if (spec->eapd_mask) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data & + ~spec->eapd_mask); + return 0; +} #endif static struct hda_codec_ops stac92xx_patch_ops = { @@ -4194,6 +4204,7 @@ static struct hda_codec_ops stac92xx_patch_ops = { .free = stac92xx_free, .unsol_event = stac92xx_unsol_event, #ifdef SND_HDA_NEEDS_RESUME + .suspend = stac92xx_suspend, .resume = stac92xx_resume, #endif }; @@ -4598,14 +4609,8 @@ static int stac92hd71xx_resume(struct hda_codec *codec) static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state) { - struct sigmatel_spec *spec = codec->spec; - stac92hd71xx_set_power_state(codec, AC_PWRST_D3); - if (spec->eapd_mask) - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data & - ~spec->eapd_mask); - return 0; + return stac92xx_suspend(codec, state); }; #endif @@ -4617,8 +4622,8 @@ static struct hda_codec_ops stac92hd71bxx_patch_ops = { .free = stac92xx_free, .unsol_event = stac92xx_unsol_event, #ifdef SND_HDA_NEEDS_RESUME - .resume = stac92hd71xx_resume, .suspend = stac92hd71xx_suspend, + .resume = stac92hd71xx_resume, #endif }; -- cgit v1.2.3 From 4e19c58f27af67735d64d9af0b184181cea7ca63 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 15:13:59 +0800 Subject: ALSA: hda: minor code cleanups Some minor code cleanups. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 2 +- sound/pci/hda/patch_intelhdmi.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 18078de0abc..da08ddaef4f 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -132,7 +132,7 @@ static char *cea_audio_coding_type_names[] = { /* * The following two lists are shared between * - HDMI audio InfoFrame (source to sink) - * - CEA E-EDID extension (sink to source) + * - CEA E-EDID Extension (sink to source) */ /* diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 747aa84d0ec..459b04576de 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -85,7 +85,7 @@ struct hdmi_audio_infoframe { u8 CXT04; u8 CA; u8 LFEPBL01_LSV36_DM_INH7; - u8 reserved[5]; /* PB6 - PB10 */ + u8 reserved[5]; /* PB6 - PB10 */ }; /* @@ -160,7 +160,7 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { { .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, /* 2.1 */ { .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } }, - /* dolby surround */ + /* Dolby Surround */ { .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } }, { .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } }, { .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } }, @@ -287,7 +287,7 @@ static void hdmi_set_channel_count(struct hda_codec *codec, int chs) if (chs != hdmi_get_channel_count(codec)) snd_printd(KERN_INFO "Channel count expect=%d, real=%d\n", - chs, hdmi_get_channel_count(codec)); + chs, hdmi_get_channel_count(codec)); } static void hdmi_debug_channel_mapping(struct hda_codec *codec) @@ -300,7 +300,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec) slot = snd_hda_codec_read(codec, CVT_NID, 0, AC_VERB_GET_HDMI_CHAN_SLOT, i); printk(KERN_DEBUG "ASP channel %d => slot %d\n", - slot >> 4, slot & 0x7); + slot >> 4, slot & 0x7); } #endif } @@ -316,7 +316,7 @@ static void hdmi_parse_eld(struct hda_codec *codec) /* - * Audio Infoframe routines + * Audio InfoFrame routines */ static void hdmi_debug_dip_size(struct hda_codec *codec) @@ -547,8 +547,8 @@ static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) */ static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) + struct hda_codec *codec, + struct snd_pcm_substream *substream) { struct intel_hdmi_spec *spec = codec->spec; @@ -556,8 +556,8 @@ static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo, } static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) + struct hda_codec *codec, + struct snd_pcm_substream *substream) { struct intel_hdmi_spec *spec = codec->spec; -- cgit v1.2.3 From 5b87ebb7a79455358c1910f2896112ac0fa0d0fa Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 15:14:00 +0800 Subject: ALSA: hda: rename sink_eld to hdmi_eld Rename struct sink_eld to hdmi_eld. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 14 +++++++------- sound/pci/hda/hda_local.h | 10 +++++----- sound/pci/hda/patch_intelhdmi.c | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index da08ddaef4f..1b3ec1e7f26 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -267,8 +267,8 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, /* * Be careful, ELD buf could be totally rubbish! */ -static int hdmi_update_sink_eld(struct sink_eld *e, - const unsigned char *buf, int size) +static int hdmi_update_eld(struct hdmi_eld *e, + const unsigned char *buf, int size) { int mnl; int i; @@ -351,7 +351,7 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) AC_DIPSIZE_ELD_BUF); } -int snd_hdmi_get_eld(struct sink_eld *eld, +int snd_hdmi_get_eld(struct hdmi_eld *eld, struct hda_codec *codec, hda_nid_t nid) { int i; @@ -380,7 +380,7 @@ int snd_hdmi_get_eld(struct sink_eld *eld, for (i = 0; i < size; i++) buf[i] = hdmi_get_eld_byte(codec, nid, i); - ret = hdmi_update_sink_eld(eld, buf, size); + ret = hdmi_update_eld(eld, buf, size); kfree(buf); return ret; @@ -421,7 +421,7 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } -void snd_hdmi_show_eld(struct sink_eld *e) +void snd_hdmi_show_eld(struct hdmi_eld *e) { int i; char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; @@ -482,7 +482,7 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a, static void hdmi_print_eld_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct sink_eld *e = entry->private_data; + struct hdmi_eld *e = entry->private_data; char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; int i; @@ -509,7 +509,7 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, hdmi_print_sad_info(i, e->sad + i, buffer); } -int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld) +int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) { char name[32]; struct snd_info_entry *entry; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 0baa9b816ca..a1473c6cb4b 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -462,7 +462,7 @@ struct cea_sad { /* * ELD: EDID Like Data */ -struct sink_eld { +struct hdmi_eld { int eld_size; int baseline_len; int eld_ver; /* (eld_ver == 0) indicates invalid ELD */ @@ -481,13 +481,13 @@ struct sink_eld { }; int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); -int snd_hdmi_get_eld(struct sink_eld *, struct hda_codec *, hda_nid_t); -void snd_hdmi_show_eld(struct sink_eld *eld); +int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t); +void snd_hdmi_show_eld(struct hdmi_eld *eld); #ifdef CONFIG_PROC_FS -int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld); +int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld); #else -inline int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld) +inline int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) { return 0; } diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 459b04576de..5393f84f675 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -42,7 +42,7 @@ struct intel_hdmi_spec { struct hda_multi_out multiout; struct hda_pcm pcm_rec; - struct sink_eld sink; + struct hdmi_eld sink_eld; }; static struct hda_verb pinout_enable_verb[] = { @@ -308,7 +308,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec) static void hdmi_parse_eld(struct hda_codec *codec) { struct intel_hdmi_spec *spec = codec->spec; - struct sink_eld *eld = &spec->sink; + struct hdmi_eld *eld = &spec->sink_eld; if (!snd_hdmi_get_eld(eld, codec, PIN_NID)) snd_hdmi_show_eld(eld); @@ -411,7 +411,7 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, struct hdmi_audio_infoframe *ai) { struct intel_hdmi_spec *spec = codec->spec; - struct sink_eld *eld = &spec->sink; + struct hdmi_eld *eld = &spec->sink_eld; int i; int spk_mask = 0; int channels = 1 + (ai->CC02_CT47 & 0x7); @@ -663,7 +663,7 @@ static int patch_intel_hdmi(struct hda_codec *codec) codec->spec = spec; codec->patch_ops = intel_hdmi_patch_ops; - snd_hda_eld_proc_new(codec, &spec->sink); + snd_hda_eld_proc_new(codec, &spec->sink_eld); init_channel_allocations(); -- cgit v1.2.3 From 06f69d17a90ced7d74ff12ce69b7b101aed4ffd9 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 15:14:01 +0800 Subject: ALSA: hda: minor output message cleanups Some minor user visible message cleanups. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 1b3ec1e7f26..75e9a4014f4 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -118,7 +118,7 @@ static char *cea_audio_coding_type_names[] = { /* 6 */ "AAC-LC", /* 7 */ "DTS", /* 8 */ "ATRAC", - /* 9 */ "DSD (1-bit audio)", + /* 9 */ "DSD (One Bit Audio)", /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)", /* 11 */ "DTS-HD", /* 12 */ "MLP (Dolby TrueHD)", @@ -395,7 +395,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) printk(KERN_INFO "channels: %d\n", a->channels); snd_print_pcm_rates(a->rates, buf, sizeof(buf)); - printk(KERN_INFO "sampling frequencies: %s\n", buf); + printk(KERN_INFO "sampling rates: %s\n", buf); if (a->format == AUDIO_CODING_TYPE_LPCM) printk(KERN_INFO "sample bits: 0x%x\n", a->sample_bits); @@ -413,11 +413,9 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { if (spk_alloc & (1 << i)) - j += snprintf(buf + j, buflen - j, "%s ", + j += snprintf(buf + j, buflen - j, " %s", cea_speaker_allocation_names[i]); } - if (j) - j--; /* skip last space */ buf[j] = '\0'; /* necessary when j == 0 */ } @@ -464,11 +462,10 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a, snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels); snd_print_pcm_rates(a->rates, buf, sizeof(buf)); - snd_iprintf(buffer, "sad%d_sampling_rates\t[0x%x] %s\n", - i, a->rates, buf); + snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf); if (a->format == AUDIO_CODING_TYPE_LPCM) - snd_iprintf(buffer, "sad%d_sample_bits\t0x%x\n", + snd_iprintf(buffer, "sad%d_bits\t\t0x%x\n", i, a->sample_bits); if (a->max_bitrate) @@ -501,7 +498,7 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - snd_iprintf(buffer, "speakers\t\t[0x%x] %s\n", e->spk_alloc, buf); + snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf); snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); -- cgit v1.2.3 From d39b4352f2356bde9d4dae8591d4c8022360922f Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 15:14:02 +0800 Subject: ALSA: hda: make global snd_print_pcm_bits() Introduce a global function snd_print_pcm_bits() and use it in the ELD code. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 10 ++++++---- sound/pci/hda/hda_local.h | 3 +++ sound/pci/hda/hda_proc.c | 22 ++++++++++++++++------ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 75e9a4014f4..8e575bb56ff 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -455,7 +455,7 @@ void snd_hdmi_show_eld(struct hdmi_eld *e) static void hdmi_print_sad_info(int i, struct cea_sad *a, struct snd_info_buffer *buffer) { - char buf[80]; + char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n", i, a->format, cea_audio_coding_type_names[a->format]); @@ -464,9 +464,11 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a, snd_print_pcm_rates(a->rates, buf, sizeof(buf)); snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf); - if (a->format == AUDIO_CODING_TYPE_LPCM) - snd_iprintf(buffer, "sad%d_bits\t\t0x%x\n", - i, a->sample_bits); + if (a->format == AUDIO_CODING_TYPE_LPCM) { + snd_print_pcm_bits(a->sample_bits, buf, sizeof(buf)); + snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n", + i, a->sample_bits, buf); + } if (a->max_bitrate) snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n", diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index a1473c6cb4b..a2d01a9a0b1 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -287,6 +287,9 @@ static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } #define SND_PRINT_RATES_ADVISED_BUFSIZE 80 void snd_print_pcm_rates(int pcm, char *buf, int buflen); +#define SND_PRINT_BITS_ADVISED_BUFSIZE 16 +void snd_print_pcm_bits(int pcm, char *buf, int buflen); + /* * Misc */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 512eb674b74..d956e976913 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -107,23 +107,33 @@ void snd_print_pcm_rates(int pcm, char *buf, int buflen) static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) { char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; + pcm &= AC_SUPPCM_RATES; snd_iprintf(buffer, " rates [0x%x]:", pcm); snd_print_pcm_rates(pcm, buf, sizeof(buf)); snd_iprintf(buffer, "%s\n", buf); } -static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) +void snd_print_pcm_bits(int pcm, char *buf, int buflen) { static unsigned int bits[] = { 8, 16, 20, 24, 32 }; - int i; + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) + if (pcm & (1 << i)) + j += snprintf(buf + j, buflen - j, " %d", bits[i]); + + buf[j] = '\0'; /* necessary when j == 0 */ +} + +static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) +{ + char buf[SND_PRINT_BITS_ADVISED_BUFSIZE]; pcm = (pcm >> 16) & 0xff; snd_iprintf(buffer, " bits [0x%x]:", pcm); - for (i = 0; i < ARRAY_SIZE(bits); i++) - if (pcm & (1 << i)) - snd_iprintf(buffer, " %d", bits[i]); - snd_iprintf(buffer, "\n"); + snd_print_pcm_bits(pcm, buf, sizeof(buf)); + snd_iprintf(buffer, "%s\n", buf); } static void print_pcm_formats(struct snd_info_buffer *buffer, -- cgit v1.2.3 From ae8cb4caa34af20311fcf5ef248afc54407aa9a8 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 15:14:03 +0800 Subject: ALSA: hda: compact ELD output messages Strip out some ELD printk messages that end user won't care, and make the output compact. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 56 +++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 8e575bb56ff..e848c30d9bf 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -389,22 +389,27 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, static void hdmi_show_short_audio_desc(struct cea_sad *a) { char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; + char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits ="; - printk(KERN_INFO "coding type: %s\n", - cea_audio_coding_type_names[a->format]); - printk(KERN_INFO "channels: %d\n", a->channels); + if (!a->format) + return; snd_print_pcm_rates(a->rates, buf, sizeof(buf)); - printk(KERN_INFO "sampling rates: %s\n", buf); if (a->format == AUDIO_CODING_TYPE_LPCM) - printk(KERN_INFO "sample bits: 0x%x\n", a->sample_bits); - - if (a->max_bitrate) - printk(KERN_INFO "max bitrate: %d\n", a->max_bitrate); - - if (a->profile) - printk(KERN_INFO "profile: %d\n", a->profile); + snd_print_pcm_rates(a->sample_bits, buf2 + 8, sizeof(buf2 - 8)); + else if (a->max_bitrate) + snprintf(buf2, sizeof(buf2), + ", max bitrate = %d", a->max_bitrate); + else + buf2[0] = '\0'; + + printk(KERN_INFO "supports coding type %s:" + " channels = %d, rates =%s%s\n", + cea_audio_coding_type_names[a->format], + a->channels, + buf, + buf2); } void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) @@ -422,29 +427,16 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) void snd_hdmi_show_eld(struct hdmi_eld *e) { int i; - char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - printk(KERN_INFO "ELD buffer size is %d\n", e->eld_size); - printk(KERN_INFO "ELD baseline len is %d*4\n", e->baseline_len); - printk(KERN_INFO "vendor block len is %d\n", - e->eld_size - e->baseline_len * 4 - 4); - printk(KERN_INFO "ELD version is %s\n", - eld_versoin_names[e->eld_ver]); - printk(KERN_INFO "CEA EDID version is %s\n", - cea_edid_version_names[e->cea_edid_ver]); - printk(KERN_INFO "manufacture id is 0x%x\n", e->manufacture_id); - printk(KERN_INFO "product id is 0x%x\n", e->product_id); - printk(KERN_INFO "port id is 0x%llx\n", (long long)e->port_id); - printk(KERN_INFO "HDCP support is %d\n", e->support_hdcp); - printk(KERN_INFO "AI support is %d\n", e->support_ai); - printk(KERN_INFO "SAD count is %d\n", e->sad_count); - printk(KERN_INFO "audio sync delay is %x\n", e->aud_synch_delay); - printk(KERN_INFO "connection type is %s\n", - eld_connection_type_names[e->conn_type]); - printk(KERN_INFO "monitor name is %s\n", e->monitor_name); + printk(KERN_INFO "detected monitor %s at connection type %s\n", + e->monitor_name, + eld_connection_type_names[e->conn_type]); - snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - printk(KERN_INFO "speaker allocations: (0x%x)%s\n", e->spk_alloc, buf); + if (e->spk_alloc) { + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + printk(KERN_INFO "available speakers:%s\n", buf); + } for (i = 0; i < e->sad_count; i++) hdmi_show_short_audio_desc(e->sad + i); -- cgit v1.2.3 From 8563964617a6685d790448d9d7e45b49be90a448 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 19 Nov 2008 14:14:50 +0100 Subject: ALSA: hda - Show missing GPIO unsol bits The GPIO unsolicited event bits are read but not shown in the proc file. Let's fix it. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_proc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index d956e976913..31b49bdc58f 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -485,12 +485,13 @@ static void print_gpio(struct snd_info_buffer *buffer, for (i = 0; i < max; ++i) snd_iprintf(buffer, " IO[%d]: enable=%d, dir=%d, wake=%d, " - "sticky=%d, data=%d\n", i, + "sticky=%d, data=%d, unsol=%d\n", i, (enable & (1< Date: Thu, 20 Nov 2008 09:24:52 +0800 Subject: ALSA: azx_probe() cleanup Replace 5 free-and-return-err blocks with goto-out-free ones. This makes the main logic more outstanding. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f73c13fdd40..3870ad622da 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2317,40 +2317,30 @@ static int __devinit azx_probe(struct pci_dev *pci, } err = azx_create(card, pci, dev, pci_id->driver_data, &chip); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto out_free; card->private_data = chip; /* create codec instances */ err = azx_codec_create(chip, model[dev], probe_mask[dev]); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto out_free; /* create PCM streams */ err = snd_hda_build_pcms(chip->bus); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto out_free; /* create mixer controls */ err = azx_mixer_create(chip); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto out_free; snd_card_set_dev(card, &pci->dev); err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto out_free; pci_set_drvdata(pci, card); chip->running = 1; @@ -2359,6 +2349,9 @@ static int __devinit azx_probe(struct pci_dev *pci, dev++; return err; +out_free: + snd_card_free(card); + return err; } static void __devexit azx_remove(struct pci_dev *pci) -- cgit v1.2.3 From 5b2d1ecac2a79b9438aed731557b8912564cedfd Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Tue, 18 Nov 2008 22:21:57 +0800 Subject: ALSA: hda: Added Realtek ALC888 model entry for Acer Aspire 4930G laptop Added Realtek ALC888 model entry for the Acer Aspire 4930G laptop that fixes the following features: - internal microphone - heaphone jack sense - channel mode Signed-off-by: Vincent Petry Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/hda/patch_realtek.c | 115 ++++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 3ab5fb1357a..010aa66ab92 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -903,6 +903,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 6stack-dig-demo 6-jack digital for Intel demo board acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) acer-aspire Acer Aspire 9810 + acer-aspire-4930g Acer Aspire 4930G medion Medion Laptops medion-md2 Medion MD2 targa-dig Targa/MSI diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b7d34390eff..6ec56c62cb1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -216,6 +216,7 @@ enum { ALC883_TARGA_2ch_DIG, ALC883_ACER, ALC883_ACER_ASPIRE, + ALC888_ACER_ASPIRE_4930G, ALC883_MEDION, ALC883_MEDION_MD2, ALC883_LAPTOP_EAPD, @@ -1154,6 +1155,90 @@ static void alc_fix_pincfg(struct hda_codec *codec, } } +/* + * ALC888 Acer Aspire 4930G model + */ + +static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Unselect Front Mic by default in input mixer 3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, +/* enable unsolicited event fpr HP jack */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +/* Connect Internal HP to front */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect HP out to front */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } +}; + +static struct hda_input_mux alc888_acer_aspire_4930g_capture_source[2] = { + /* Front mic only available on one ADC */ + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Front Mic", 0xb }, + }, + }, + { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, + } +}; + +static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + { } /* end */ +}; + +static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec) +{ + unsigned int present; + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + /* Toggle the internal HP PIN (regular muting doesn't work) */ + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + (present ? 0x0 : PIN_OUT)); +} + +static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if (res >> 26 == ALC880_HP_EVENT) + alc888_acer_aspire_4930g_automute(codec); +} + /* * ALC880 3-stack model * @@ -6887,8 +6972,15 @@ static hda_nid_t alc883_adc_nids_alt[1] = { 0x08, }; +static hda_nid_t alc883_adc_nids_rev[2] = { + /* ADC2-1 */ + 0x09, 0x08 +}; + static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 }; +static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 }; + /* input MUX */ /* FIXME: should be a matrix-type input source selection */ @@ -8180,6 +8272,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", [ALC883_ACER] = "acer", [ALC883_ACER_ASPIRE] = "acer-aspire", + [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g", [ALC883_MEDION] = "medion", [ALC883_MEDION_MD2] = "medion-md2", [ALC883_LAPTOP_EAPD] = "laptop-eapd", @@ -8205,6 +8298,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G", + ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */ SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), @@ -8376,6 +8471,26 @@ static struct alc_config_preset alc883_presets[] = { .unsol_event = alc883_acer_aspire_unsol_event, .init_hook = alc883_acer_aspire_automute, }, + [ALC888_ACER_ASPIRE_4930G] = { + .mixers = { alc888_acer_aspire_4930g_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, + alc888_acer_aspire_4930g_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .num_mux_defs = + ARRAY_SIZE(alc888_acer_aspire_4930g_capture_source), + .input_mux = alc888_acer_aspire_4930g_capture_source, + .unsol_event = alc888_acer_aspire_4930g_unsol_event, + .init_hook = alc888_acer_aspire_4930g_automute, + }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, alc883_chmode_mixer }, -- cgit v1.2.3 From 1725b82a6e2721612a3572d0336f51f1f1c3cf54 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 02:25:48 +0100 Subject: ALSA: hda - make laptop-eapd model back for AD1986A The changes specific for Samsung laptops seem unapplicable to other hardware models like ASUS. The mic inputs are lost on such hardware by the change 5d5d5f43f1b835c375de9bd270cce030d16e2871. This patch adds back the old laptop-eapd model, and create a new model "samsung" for the new one specific to Samsung laptops with automatic mic selection feature. Reference: kernel bugzilla #12070 http://bugzilla.kernel.org/show_bug.cgi?id=12070 Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 3 +- sound/pci/hda/patch_analog.c | 49 +++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 010aa66ab92..e55081fdc8a 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -984,9 +984,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 6stack 6-jack, separate surrounds (default) 3stack 3-stack, shared surrounds laptop 2-channel only (FSC V2060, Samsung M50) - laptop-eapd 2-channel with EAPD (Samsung R65, ASUS A6J) + laptop-eapd 2-channel with EAPD (ASUS A6J) laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) ultra 2-channel with EAPD (Samsung Ultra tablet PC) + samsung 2-channel with EAPD (Samsung R65) AD1988/AD1988B/AD1989A/AD1989B 6stack 6-jack diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 032cbb4bd98..0cc6be12b8b 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -638,6 +638,36 @@ static struct hda_input_mux ad1986a_automic_capture_source = { }; static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { + HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), + HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), + HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "External Amplifier", + .info = ad198x_eapd_info, + .get = ad198x_eapd_get, + .put = ad198x_eapd_put, + .private_value = 0x1b | (1 << 8), /* port-D, inversed */ + }, + { } /* end */ +}; + +static struct snd_kcontrol_new ad1986a_samsung_mixers[] = { HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -930,6 +960,7 @@ enum { AD1986A_LAPTOP_EAPD, AD1986A_LAPTOP_AUTOMUTE, AD1986A_ULTRA, + AD1986A_SAMSUNG, AD1986A_MODELS }; @@ -940,6 +971,7 @@ static const char *ad1986a_models[AD1986A_MODELS] = { [AD1986A_LAPTOP_EAPD] = "laptop-eapd", [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", [AD1986A_ULTRA] = "ultra", + [AD1986A_SAMSUNG] = "samsung", }; static struct snd_pci_quirk ad1986a_cfg_tbl[] = { @@ -962,9 +994,9 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = { SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD), SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_SAMSUNG), + SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_SAMSUNG), + SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_SAMSUNG), SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), @@ -1046,6 +1078,17 @@ static int patch_ad1986a(struct hda_codec *codec) break; case AD1986A_LAPTOP_EAPD: spec->mixers[0] = ad1986a_laptop_eapd_mixers; + spec->num_init_verbs = 2; + spec->init_verbs[1] = ad1986a_eapd_init_verbs; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = ad1986a_laptop_dac_nids; + if (!is_jack_available(codec, 0x25)) + spec->multiout.dig_out_nid = 0; + spec->input_mux = &ad1986a_laptop_eapd_capture_source; + break; + case AD1986A_SAMSUNG: + spec->mixers[0] = ad1986a_samsung_mixers; spec->num_init_verbs = 3; spec->init_verbs[1] = ad1986a_eapd_init_verbs; spec->init_verbs[2] = ad1986a_automic_verbs; -- cgit v1.2.3 From 218b5ffc0d3fa852624e67a1bb2528ca29274d6e Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 21 Nov 2008 09:42:59 +0800 Subject: ALSA: hda - properly print ELD sample bits Fix bugs on printing the ELD sample bits. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 2 +- sound/pci/hda/hda_proc.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index e848c30d9bf..9d3e542d74a 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -397,7 +397,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) snd_print_pcm_rates(a->rates, buf, sizeof(buf)); if (a->format == AUDIO_CODING_TYPE_LPCM) - snd_print_pcm_rates(a->sample_bits, buf2 + 8, sizeof(buf2 - 8)); + snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8)); else if (a->max_bitrate) snprintf(buf2, sizeof(buf2), ", max bitrate = %d", a->max_bitrate); diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 31b49bdc58f..56cee3a2221 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -120,7 +120,7 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen) int i, j; for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) - if (pcm & (1 << i)) + if (pcm & (AC_SUPPCM_BITS_8 << i)) j += snprintf(buf + j, buflen - j, " %d", bits[i]); buf[j] = '\0'; /* necessary when j == 0 */ @@ -130,7 +130,6 @@ static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) { char buf[SND_PRINT_BITS_ADVISED_BUFSIZE]; - pcm = (pcm >> 16) & 0xff; snd_iprintf(buffer, " bits [0x%x]:", pcm); snd_print_pcm_bits(pcm, buf, sizeof(buf)); snd_iprintf(buffer, "%s\n", buf); -- cgit v1.2.3 From db742104704cfb047732aa66451c608382da3aee Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 21 Nov 2008 12:34:05 +0800 Subject: ALSA: hda: modify monitor name to be consistent with other ELD proc items Rename "monitor name" to "monitor_name" to conform with the keyword style. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 9d3e542d74a..248cddf0ee8 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -477,7 +477,7 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; int i; - snd_iprintf(buffer, "monitor name\t\t%s\n", e->monitor_name); + snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); snd_iprintf(buffer, "connection_type\t\t%s\n", eld_connection_type_names[e->conn_type]); snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver, -- cgit v1.2.3 From acdda7915eb5dae20b6e43b8b772b712b1ed32c3 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 21 Nov 2008 11:41:50 +0800 Subject: ALSA: hda - support writing to the ELD proc file Allow users to fix quicks of ELD ROMs by writing new values to the ELD proc interface. The format is one or more lines of "name hex_value". Users can add/remove/modify up to 32 SAD(Short Audio Descriptor) entries. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 248cddf0ee8..d2b7ccca3bb 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -500,6 +500,59 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, hdmi_print_sad_info(i, e->sad + i, buffer); } +static void hdmi_write_eld_item(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct hdmi_eld *e = entry->private_data; + char line[64]; + char name[64]; + char *sname; + long long val; + int n; + + while (!snd_info_get_line(buffer, line, sizeof(line))) { + if (sscanf(line, "%s %llx", name, &val) != 2) + continue; + if (!strcmp(name, "connection_type")) + e->conn_type = val; + else if (!strcmp(name, "port_id")) + e->port_id = val; + else if (!strcmp(name, "support_hdcp")) + e->support_hdcp = val; + else if (!strcmp(name, "support_ai")) + e->support_ai = val; + else if (!strcmp(name, "audio_sync_delay")) + e->aud_synch_delay = val; + else if (!strcmp(name, "speakers")) + e->spk_alloc = val; + else if (!strcmp(name, "sad_count")) + e->sad_count = val; + else if (!strncmp(name, "sad", 3)) { + sname = name + 4; + n = name[3] - '0'; + if (name[4] >= '0' && name[4] <= '9') { + sname++; + n = 10 * n + name[4] - '0'; + } + if (n < 0 || n > 31) /* double the CEA limit */ + continue; + if (!strcmp(sname, "_coding_type")) + e->sad[n].format = val; + else if (!strcmp(sname, "_channels")) + e->sad[n].channels = val; + else if (!strcmp(sname, "_rates")) + e->sad[n].rates = val; + else if (!strcmp(sname, "_bits")) + e->sad[n].sample_bits = val; + else if (!strcmp(sname, "_max_bitrate")) + e->sad[n].max_bitrate = val; + if (n >= e->sad_count) + e->sad_count = n + 1; + } + } +} + + int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) { char name[32]; @@ -512,6 +565,9 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) return err; snd_info_set_text_ops(entry, eld, hdmi_print_eld_info); + entry->c.text.write = hdmi_write_eld_item; + entry->mode |= S_IWUSR; + return 0; } -- cgit v1.2.3 From 0623536ca3e8fd7cb8b7468b0fd4d61d80f0b6ea Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 08:54:54 +0100 Subject: ALSA: hda - Add missing static for snd_hda_eld_proc_new() inline funciton Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_local.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index a2d01a9a0b1..c71505a4f99 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -490,7 +490,8 @@ void snd_hdmi_show_eld(struct hdmi_eld *eld); #ifdef CONFIG_PROC_FS int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld); #else -inline int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) +static inline int snd_hda_eld_proc_new(struct hda_codec *codec, + struct hdmi_eld *eld) { return 0; } -- cgit v1.2.3 From b94d3539de59ec6481e38f83c455324fd3aeabc1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 09:08:06 +0100 Subject: ALSA: hda - Fix double free of jack instances The jack instances created in patch_sigmatel.c may be double-freed. The device management code checks the invalid element, and thus there is no real breakage, but it spews annoying warning messages. But, we can't simply remove the release calls of these jack instances because they have to be freed when the codec is re-configured. Now, a new flag, bus->shutdown is introduced to indicate that the bus is really being unloaded, i.e. the objects managed by the device manager will be automatically deleted. We release these objects only when this flag isn't set. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 + sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/patch_sigmatel.c | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5d5e8012d6a..a98ce5b1118 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -464,6 +464,7 @@ static int snd_hda_bus_free(struct hda_bus *bus) static int snd_hda_bus_dev_free(struct snd_device *device) { struct hda_bus *bus = device->device_data; + bus->shutdown = 1; return snd_hda_bus_free(bus); } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index ee122b009fd..a70b181bbac 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -617,6 +617,7 @@ struct hda_bus { /* misc op flags */ unsigned int needs_damn_long_delay :1; + unsigned int shutdown :1; /* being unloaded */ }; /* diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index a501c912164..4fa5189264b 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3921,8 +3921,9 @@ static int stac92xx_init(struct hda_codec *codec) static void stac92xx_free_jacks(struct hda_codec *codec) { #ifdef CONFIG_SND_JACK + /* free jack instances manually when clearing/reconfiguring */ struct sigmatel_spec *spec = codec->spec; - if (spec->jacks.list) { + if (!codec->bus->shutdown && spec->jacks.list) { struct sigmatel_jack *jacks = spec->jacks.list; int i; for (i = 0; i < spec->jacks.used; i++) -- cgit v1.2.3 From f208dba97f2f3ff2fbcbe771195061e2a0dac870 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 09:11:50 +0100 Subject: ALSA: hda - Release ELD proc file Release ELD proc file when reconfigured so that no leak occurs. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 11 ++++++++++- sound/pci/hda/hda_local.h | 8 ++++++++ sound/pci/hda/patch_intelhdmi.c | 5 ++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index d2b7ccca3bb..8740e7be8b2 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -567,8 +567,17 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) snd_info_set_text_ops(entry, eld, hdmi_print_eld_info); entry->c.text.write = hdmi_write_eld_item; entry->mode |= S_IWUSR; + eld->proc_entry = entry; return 0; } -#endif +void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) +{ + if (!codec->bus->shutdown && eld->proc_entry) { + snd_device_free(codec->bus->card, eld->proc_entry); + eld->proc_entry = NULL; + } +} + +#endif /* CONFIG_PROC_FS */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index c71505a4f99..bf7ba8b6297 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -481,6 +481,9 @@ struct hdmi_eld { int spk_alloc; int sad_count; struct cea_sad sad[ELD_MAX_SAD]; +#ifdef CONFIG_PROC_FS + struct snd_info_entry *proc_entry; +#endif }; int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); @@ -489,12 +492,17 @@ void snd_hdmi_show_eld(struct hdmi_eld *eld); #ifdef CONFIG_PROC_FS int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld); +void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld); #else static inline int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) { return 0; } +static inline void snd_hda_eld_proc_free(struct hda_codec *codec, + struct hdmi_eld *eld) +{ +} #endif #define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 5393f84f675..58aaf06589a 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -637,7 +637,10 @@ static int intel_hdmi_init(struct hda_codec *codec) static void intel_hdmi_free(struct hda_codec *codec) { - kfree(codec->spec); + struct intel_hdmi_spec *spec = codec->spec; + + snd_hda_eld_proc_free(codec, &spec->sink_eld); + kfree(spec); } static struct hda_codec_ops intel_hdmi_patch_ops = { -- cgit v1.2.3 From e7ee058cac89ec2f2c0c9ab0ec92a3776c182642 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 09:26:20 +0100 Subject: ALSA: hda - Make CONFIG_SND_HDA_RECONFIG for codec reconfiguration Make the codec re-configuration feature selectable via Kconfig, CONFIG_SND_HDA_RECONFIG. Also mark it as experimental (as it really is). Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 9 +++++++++ sound/pci/hda/hda_hwdep.c | 4 ++++ sound/pci/hda/hda_local.h | 10 +++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 157a0a6b10a..cc6cf89c32e 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -518,6 +518,15 @@ config SND_HDA_HWDEP This interface can be used for out-of-band communication with codecs for debugging purposes. +config SND_HDA_RECONFIG + bool "Allow dynamic codec reconfiguration (EXPERIMENTAL)" + depends on SND_HDA_HWDEP && EXPERIMENTAL + help + Say Y here to enable the HD-audio codec re-configuration feature. + This adds the sysfs interfaces to allow user to clear the whole + codec configuration, change the codec setup, add extra verbs, + and re-configure the codec dynamically. + config SND_HDA_INPUT_BEEP bool "Support digital beep via input layer" depends on SND_HDA_INTEL diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 653da1d3e4d..5868bbc131c 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -145,6 +145,8 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec) return 0; } +#ifdef CONFIG_SND_HDA_RECONFIG + /* * sysfs interface */ @@ -347,3 +349,5 @@ int snd_hda_hwdep_add_sysfs(struct hda_codec *codec) hwdep->device, &codec_attrs[i]); return 0; } + +#endif /* CONFIG_SND_HDA_RECONFIG */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index bf7ba8b6297..6f2fe0f9fdd 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -409,11 +409,19 @@ void snd_hda_ctls_clear(struct hda_codec *codec); */ #ifdef CONFIG_SND_HDA_HWDEP int snd_hda_create_hwdep(struct hda_codec *codec); -int snd_hda_hwdep_add_sysfs(struct hda_codec *codec); #else static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; } #endif +#ifdef CONFIG_SND_HDA_RECONFIG +int snd_hda_hwdep_add_sysfs(struct hda_codec *codec); +#else +static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec) +{ + return 0; +} +#endif + /* * power-management */ -- cgit v1.2.3 From 11b444d5627d87beb55029601cf8d2c9fa9324fd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 09:32:40 +0100 Subject: ALSA: hda - Move HD-audio Kconfig items to sound/pci/hda/Kconfig Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 146 +------------------------------------------------- sound/pci/hda/Kconfig | 139 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 145 deletions(-) create mode 100644 sound/pci/hda/Kconfig diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index cc6cf89c32e..caebf296b62 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -497,151 +497,7 @@ config SND_FM801_TEA575X depends on SND_FM801_TEA575X_BOOL default SND_FM801 -config SND_HDA_INTEL - tristate "Intel HD Audio" - select SND_PCM - select SND_VMASTER - select SND_JACK if INPUT=y || INPUT=SND - help - Say Y here to include support for Intel "High Definition - Audio" (Azalia) motherboard devices. - - To compile this driver as a module, choose M here: the module - will be called snd-hda-intel. - -config SND_HDA_HWDEP - bool "Build hwdep interface for HD-audio driver" - depends on SND_HDA_INTEL - select SND_HWDEP - help - Say Y here to build a hwdep interface for HD-audio driver. - This interface can be used for out-of-band communication - with codecs for debugging purposes. - -config SND_HDA_RECONFIG - bool "Allow dynamic codec reconfiguration (EXPERIMENTAL)" - depends on SND_HDA_HWDEP && EXPERIMENTAL - help - Say Y here to enable the HD-audio codec re-configuration feature. - This adds the sysfs interfaces to allow user to clear the whole - codec configuration, change the codec setup, add extra verbs, - and re-configure the codec dynamically. - -config SND_HDA_INPUT_BEEP - bool "Support digital beep via input layer" - depends on SND_HDA_INTEL - depends on INPUT=y || INPUT=SND_HDA_INTEL - help - Say Y here to build a digital beep interface for HD-audio - driver. This interface is used to generate digital beeps. - -config SND_HDA_CODEC_REALTEK - bool "Build Realtek HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include Realtek HD-audio codec support in - snd-hda-intel driver, such as ALC880. - -config SND_HDA_CODEC_ANALOG - bool "Build Analog Device HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include Analog Device HD-audio codec support in - snd-hda-intel driver, such as AD1986A. - -config SND_HDA_CODEC_SIGMATEL - bool "Build IDT/Sigmatel HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include IDT (Sigmatel) HD-audio codec support in - snd-hda-intel driver, such as STAC9200. - -config SND_HDA_CODEC_VIA - bool "Build VIA HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include VIA HD-audio codec support in - snd-hda-intel driver, such as VT1708. - -config SND_HDA_CODEC_ATIHDMI - bool "Build ATI HDMI HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include ATI HDMI HD-audio codec support in - snd-hda-intel driver, such as ATI RS600 HDMI. - -config SND_HDA_CODEC_NVHDMI - bool "Build NVIDIA HDMI HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include NVIDIA HDMI HD-audio codec support in - snd-hda-intel driver, such as NVIDIA MCP78 HDMI. - -config SND_HDA_CODEC_INTELHDMI - bool "Build INTEL HDMI HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include INTEL HDMI HD-audio codec support in - snd-hda-intel driver, such as Eaglelake integrated HDMI. - -config SND_HDA_ELD - def_bool y - depends on SND_HDA_CODEC_INTELHDMI - -config SND_HDA_CODEC_CONEXANT - bool "Build Conexant HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include Conexant HD-audio codec support in - snd-hda-intel driver, such as CX20549. - -config SND_HDA_CODEC_CMEDIA - bool "Build C-Media HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include C-Media HD-audio codec support in - snd-hda-intel driver, such as CMI9880. - -config SND_HDA_CODEC_SI3054 - bool "Build Silicon Labs 3054 HD-modem codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include Silicon Labs 3054 HD-modem codec - (and compatibles) support in snd-hda-intel driver. - -config SND_HDA_GENERIC - bool "Enable generic HD-audio codec parser" - depends on SND_HDA_INTEL - default y - help - Say Y here to enable the generic HD-audio codec parser - in snd-hda-intel driver. - -config SND_HDA_POWER_SAVE - bool "Aggressive power-saving on HD-audio" - depends on SND_HDA_INTEL && EXPERIMENTAL - help - Say Y here to enable more aggressive power-saving mode on - HD-audio driver. The power-saving timeout can be configured - via power_save option or over sysfs on-the-fly. - -config SND_HDA_POWER_SAVE_DEFAULT - int "Default time-out for HD-audio power-save mode" - depends on SND_HDA_POWER_SAVE - default 0 - help - The default time-out value in seconds for HD-audio automatic - power-save mode. 0 means to disable the power-save mode. +source "sound/pci/hda/Kconfig" config SND_HDSP tristate "RME Hammerfall DSP Audio" diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig new file mode 100644 index 00000000000..7c60f1a45a8 --- /dev/null +++ b/sound/pci/hda/Kconfig @@ -0,0 +1,139 @@ +menuconfig SND_HDA_INTEL + tristate "Intel HD Audio" + select SND_PCM + select SND_VMASTER + select SND_JACK if INPUT=y || INPUT=SND + help + Say Y here to include support for Intel "High Definition + Audio" (Azalia) and its compatible devices. + + This option enables the HD-audio controller. Don't forget + to choose the appropriate codec options below. + + To compile this driver as a module, choose M here: the module + will be called snd-hda-intel. + +if SND_HDA_INTEL + +config SND_HDA_HWDEP + bool "Build hwdep interface for HD-audio driver" + select SND_HWDEP + help + Say Y here to build a hwdep interface for HD-audio driver. + This interface can be used for out-of-band communication + with codecs for debugging purposes. + +config SND_HDA_RECONFIG + bool "Allow dynamic codec reconfiguration (EXPERIMENTAL)" + depends on SND_HDA_HWDEP && EXPERIMENTAL + help + Say Y here to enable the HD-audio codec re-configuration feature. + This adds the sysfs interfaces to allow user to clear the whole + codec configuration, change the codec setup, add extra verbs, + and re-configure the codec dynamically. + +config SND_HDA_INPUT_BEEP + bool "Support digital beep via input layer" + depends on INPUT=y || INPUT=SND_HDA_INTEL + help + Say Y here to build a digital beep interface for HD-audio + driver. This interface is used to generate digital beeps. + +config SND_HDA_CODEC_REALTEK + bool "Build Realtek HD-audio codec support" + default y + help + Say Y here to include Realtek HD-audio codec support in + snd-hda-intel driver, such as ALC880. + +config SND_HDA_CODEC_ANALOG + bool "Build Analog Device HD-audio codec support" + default y + help + Say Y here to include Analog Device HD-audio codec support in + snd-hda-intel driver, such as AD1986A. + +config SND_HDA_CODEC_SIGMATEL + bool "Build IDT/Sigmatel HD-audio codec support" + default y + help + Say Y here to include IDT (Sigmatel) HD-audio codec support in + snd-hda-intel driver, such as STAC9200. + +config SND_HDA_CODEC_VIA + bool "Build VIA HD-audio codec support" + default y + help + Say Y here to include VIA HD-audio codec support in + snd-hda-intel driver, such as VT1708. + +config SND_HDA_CODEC_ATIHDMI + bool "Build ATI HDMI HD-audio codec support" + default y + help + Say Y here to include ATI HDMI HD-audio codec support in + snd-hda-intel driver, such as ATI RS600 HDMI. + +config SND_HDA_CODEC_NVHDMI + bool "Build NVIDIA HDMI HD-audio codec support" + default y + help + Say Y here to include NVIDIA HDMI HD-audio codec support in + snd-hda-intel driver, such as NVIDIA MCP78 HDMI. + +config SND_HDA_CODEC_INTELHDMI + bool "Build INTEL HDMI HD-audio codec support" + default y + help + Say Y here to include INTEL HDMI HD-audio codec support in + snd-hda-intel driver, such as Eaglelake integrated HDMI. + +config SND_HDA_ELD + def_bool y + depends on SND_HDA_CODEC_INTELHDMI + +config SND_HDA_CODEC_CONEXANT + bool "Build Conexant HD-audio codec support" + default y + help + Say Y here to include Conexant HD-audio codec support in + snd-hda-intel driver, such as CX20549. + +config SND_HDA_CODEC_CMEDIA + bool "Build C-Media HD-audio codec support" + default y + help + Say Y here to include C-Media HD-audio codec support in + snd-hda-intel driver, such as CMI9880. + +config SND_HDA_CODEC_SI3054 + bool "Build Silicon Labs 3054 HD-modem codec support" + default y + help + Say Y here to include Silicon Labs 3054 HD-modem codec + (and compatibles) support in snd-hda-intel driver. + +config SND_HDA_GENERIC + bool "Enable generic HD-audio codec parser" + default y + help + Say Y here to enable the generic HD-audio codec parser + in snd-hda-intel driver. + +config SND_HDA_POWER_SAVE + bool "Aggressive power-saving on HD-audio" + depends on EXPERIMENTAL + help + Say Y here to enable more aggressive power-saving mode on + HD-audio driver. The power-saving timeout can be configured + via power_save option or over sysfs on-the-fly. + +config SND_HDA_POWER_SAVE_DEFAULT + int "Default time-out for HD-audio power-save mode" + depends on SND_HDA_POWER_SAVE + default 0 + help + The default time-out value in seconds for HD-audio automatic + power-save mode. 0 means to disable the power-save mode. + +endif -- cgit v1.2.3 From 42e81c991a71909929f8d0cdcdf8ced68799388a Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Fri, 21 Nov 2008 16:03:24 +0100 Subject: ALSA: hda - fix sparse warning Fix the following sparse warning: sound/pci/hda/patch_nvhdmi.c:161:25: warning: symbol 'snd_hda_preset_nvhdmi' was not declared. Should it be static? Signed-off-by: Hannes Eder Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_nvhdmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 2eed2c8b98d..1360d54a7d0 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -28,6 +28,7 @@ #include #include "hda_codec.h" #include "hda_local.h" +#include "hda_patch.h" struct nvhdmi_spec { struct hda_multi_out multiout; -- cgit v1.2.3 From d6752a532c700927fc7586cdd086391bfc50eaa9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 18:01:44 +0100 Subject: ALSA: hda - mark Dell studio 1535 quirk Fixed the quirk string for Dell studio 1535 (the product name wasn't published at the time the patch was made). Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 4fa5189264b..cf3641f9ebe 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1667,7 +1667,7 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD73XX_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254, - "unknown Dell", STAC_DELL_M6), + "Dell Studio 1535", STAC_DELL_M6), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255, "unknown Dell", STAC_DELL_M6), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256, -- cgit v1.2.3 From b20222667d371bb9ddeadd47d18072efcab3f6d2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 21:24:03 +0100 Subject: ALSA: hda - Fix build without CONFIG_PROC_FS snd_print_pcm_rates() and snd_print_pcm_bits() are used by both hda_proc.c and hda_eld.c, thus they have to be defined in the common place. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 30 ++++++++++++++++++++++++++++++ sound/pci/hda/hda_proc.c | 27 --------------------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a98ce5b1118..d56d11ab20a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3425,3 +3425,33 @@ void snd_array_free(struct snd_array *array) array->alloced = 0; array->list = NULL; } + +/* + * used by hda_proc.c and hda_eld.c + */ +void snd_print_pcm_rates(int pcm, char *buf, int buflen) +{ + static unsigned int rates[] = { + 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, + 96000, 176400, 192000, 384000 + }; + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(rates); i++) + if (pcm & (1 << i)) + j += snprintf(buf + j, buflen - j, " %d", rates[i]); + + buf[j] = '\0'; /* necessary when j == 0 */ +} + +void snd_print_pcm_bits(int pcm, char *buf, int buflen) +{ + static unsigned int bits[] = { 8, 16, 20, 24, 32 }; + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) + if (pcm & (AC_SUPPCM_BITS_8 << i)) + j += snprintf(buf + j, buflen - j, " %d", bits[i]); + + buf[j] = '\0'; /* necessary when j == 0 */ +} diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 56cee3a2221..e7f91c44e63 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -89,21 +89,6 @@ static void print_amp_vals(struct snd_info_buffer *buffer, snd_iprintf(buffer, "\n"); } -void snd_print_pcm_rates(int pcm, char *buf, int buflen) -{ - static unsigned int rates[] = { - 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, - 96000, 176400, 192000, 384000 - }; - int i, j; - - for (i = 0, j = 0; i < ARRAY_SIZE(rates); i++) - if (pcm & (1 << i)) - j += snprintf(buf + j, buflen - j, " %d", rates[i]); - - buf[j] = '\0'; /* necessary when j == 0 */ -} - static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) { char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; @@ -114,18 +99,6 @@ static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) snd_iprintf(buffer, "%s\n", buf); } -void snd_print_pcm_bits(int pcm, char *buf, int buflen) -{ - static unsigned int bits[] = { 8, 16, 20, 24, 32 }; - int i, j; - - for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) - if (pcm & (AC_SUPPCM_BITS_8 << i)) - j += snprintf(buf + j, buflen - j, " %d", bits[i]); - - buf[j] = '\0'; /* necessary when j == 0 */ -} - static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) { char buf[SND_PRINT_BITS_ADVISED_BUFSIZE]; -- cgit v1.2.3 From b83923a3931a43df7397a7491f0c9d9b9d46624a Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 22 Nov 2008 09:40:51 +0800 Subject: ALSA: hda - minor HDMI code cleanups Some minor code cleanups. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 58aaf06589a..e10fa1e3dc9 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -431,7 +431,7 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, * expand ELD's speaker allocation mask * * ELD tells the speaker mask in a compact(paired) form, - * expand ELD's notions to match the ones used by audio infoframe. + * expand ELD's notions to match the ones used by Audio InfoFrame. */ for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { if (eld->spk_alloc & (1 << i)) @@ -592,8 +592,8 @@ static struct hda_pcm_stream intel_hdmi_pcm_playback = { .channels_max = 8, .nid = CVT_NID, /* NID to query formats and rates and setup streams */ .ops = { - .open = intel_hdmi_playback_pcm_open, - .close = intel_hdmi_playback_pcm_close, + .open = intel_hdmi_playback_pcm_open, + .close = intel_hdmi_playback_pcm_close, .prepare = intel_hdmi_playback_pcm_prepare }, }; -- cgit v1.2.3 From cc02b83c904592ce8714787094256a9bf8e24b6f Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 22 Nov 2008 09:40:52 +0800 Subject: ALSA: hda - report selected CA index for Audio InfoFrame Print some CA selecting info, which could be valuable for debugging when something goes wrong. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index e10fa1e3dc9..4a48011ae35 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -444,14 +444,16 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, (spk_mask & channel_allocations[i].spk_mask) == channel_allocations[i].spk_mask) { ai->CA = channel_allocations[i].ca_index; - return 0; + break; } } snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); - snd_printd(KERN_INFO "failed to setup channel allocation: %d of %s\n", - channels, buf); - return -1; + snd_printdd(KERN_INFO + "HDMI: select CA 0x%x for %d-channel allocation: %s\n", + ai->CA, channels, buf); + + return ai->CA; } static void hdmi_setup_channel_mapping(struct hda_codec *codec, -- cgit v1.2.3 From 03284c8f23440479de79e8cbf368085ea872884e Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 22 Nov 2008 09:40:53 +0800 Subject: ALSA: hda - make HDMI messages more user friendly - make some messages more user friendly - add message prefix "HDMI:" to indicate the problem's domain (also easier to do `dmesg | grep HDMI` ;-) Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 30 ++++++++++++++++-------------- sound/pci/hda/patch_intelhdmi.c | 32 ++++++++++++++++---------------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 8740e7be8b2..3f10961a17b 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -168,11 +168,11 @@ static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid, AC_VERB_GET_HDMI_ELDD, byte_index); #ifdef BE_PARANOID - printk(KERN_INFO "ELD data byte %d: 0x%x\n", byte_index, val); + printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val); #endif if ((val & AC_ELDD_ELD_VALID) == 0) { - snd_printd(KERN_INFO "Invalid ELD data byte %d\n", + snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n", byte_index); val = 0; } @@ -208,7 +208,7 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, switch (a->format) { case AUDIO_CODING_TYPE_REF_STREAM_HEADER: snd_printd(KERN_INFO - "audio coding type 0 not expected in ELD\n"); + "HDMI: audio coding type 0 not expected\n"); break; case AUDIO_CODING_TYPE_LPCM: @@ -254,7 +254,7 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { snd_printd(KERN_INFO - "audio coding xtype %d not expected in ELD\n", + "HDMI: audio coding xtype %d not expected\n", a->format); a->format = 0; } else @@ -276,7 +276,8 @@ static int hdmi_update_eld(struct hdmi_eld *e, e->eld_ver = GRAB_BITS(buf, 0, 3, 5); if (e->eld_ver != ELD_VER_CEA_861D && e->eld_ver != ELD_VER_PARTIAL) { - snd_printd(KERN_INFO "Unknown ELD version %d\n", e->eld_ver); + snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n", + e->eld_ver); goto out_fail; } @@ -300,17 +301,17 @@ static int hdmi_update_eld(struct hdmi_eld *e, e->product_id = get_unaligned_le16(buf + 18); if (mnl > ELD_MAX_MNL) { - snd_printd(KERN_INFO "MNL is reserved value %d\n", mnl); + snd_printd(KERN_INFO "HDMI: MNL is reserved value %d\n", mnl); goto out_fail; } else if (ELD_FIXED_BYTES + mnl > size) { - snd_printd(KERN_INFO "out of range MNL %d\n", mnl); + snd_printd(KERN_INFO "HDMI: out of range MNL %d\n", mnl); goto out_fail; } else strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl); for (i = 0; i < e->sad_count; i++) { if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { - snd_printd(KERN_INFO "out of range SAD %d\n", i); + snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i); goto out_fail; } hdmi_update_short_audio_desc(e->sad + i, @@ -339,7 +340,8 @@ static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid) present = (present & AC_PINSENSE_PRESENCE); #ifdef CONFIG_SND_DEBUG_VERBOSE - printk(KERN_INFO "pinp = %d, eldv = %d\n", !!present, !!eldv); + printk(KERN_INFO "HDMI: sink_present = %d, eld_valid = %d\n", + !!present, !!eldv); #endif return eldv && present; @@ -365,11 +367,11 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, size = snd_hdmi_get_eld_size(codec, nid); if (size == 0) { /* wfg: workaround for ASUS P5E-VM HDMI board */ - snd_printd(KERN_INFO "ELD buf size is 0, force 128\n"); + snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n"); size = 128; } if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { - snd_printd(KERN_INFO "Invalid ELD buf size %d\n", size); + snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size); return -ERANGE; } @@ -404,7 +406,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) else buf2[0] = '\0'; - printk(KERN_INFO "supports coding type %s:" + printk(KERN_INFO "HDMI: supports coding type %s:" " channels = %d, rates =%s%s\n", cea_audio_coding_type_names[a->format], a->channels, @@ -428,14 +430,14 @@ void snd_hdmi_show_eld(struct hdmi_eld *e) { int i; - printk(KERN_INFO "detected monitor %s at connection type %s\n", + printk(KERN_INFO "HDMI: detected monitor %s at connection type %s\n", e->monitor_name, eld_connection_type_names[e->conn_type]); if (e->spk_alloc) { char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - printk(KERN_INFO "available speakers:%s\n", buf); + printk(KERN_INFO "HDMI: available speakers:%s\n", buf); } for (i = 0; i < e->sad_count; i++) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 4a48011ae35..fe08bef897c 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -286,7 +286,7 @@ static void hdmi_set_channel_count(struct hda_codec *codec, int chs) AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); if (chs != hdmi_get_channel_count(codec)) - snd_printd(KERN_INFO "Channel count expect=%d, real=%d\n", + snd_printd(KERN_INFO "HDMI channel count: expect %d, get %d\n", chs, hdmi_get_channel_count(codec)); } @@ -299,7 +299,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec) for (i = 0; i < 8; i++) { slot = snd_hda_codec_read(codec, CVT_NID, 0, AC_VERB_GET_HDMI_CHAN_SLOT, i); - printk(KERN_DEBUG "ASP channel %d => slot %d\n", + printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", slot >> 4, slot & 0x7); } #endif @@ -326,12 +326,12 @@ static void hdmi_debug_dip_size(struct hda_codec *codec) int size; size = snd_hdmi_get_eld_size(codec, PIN_NID); - printk(KERN_DEBUG "ELD buf size is %d\n", size); + printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size); for (i = 0; i < 8; i++) { size = snd_hda_codec_read(codec, PIN_NID, 0, AC_VERB_GET_HDMI_DIP_SIZE, i); - printk(KERN_DEBUG "DIP GP[%d] buf size is %d\n", i, size); + printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size); } #endif } @@ -359,8 +359,8 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec) break; } snd_printd(KERN_INFO - "DIP GP[%d] buf reported size=%d, written=%d\n", - i, size, j); + "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n", + i, size, j); } #endif } @@ -498,7 +498,9 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) int pind = !!(res & AC_UNSOL_RES_PD); int eldv = !!(res & AC_UNSOL_RES_ELDV); - printk(KERN_INFO "HDMI intrinsic event: PD=%d ELDV=%d\n", pind, eldv); + printk(KERN_INFO + "HDMI hot plug event: Presence_Detect=%d ELD_Valid=%d\n", + pind, eldv); if (pind && eldv) { hdmi_parse_eld(codec); @@ -512,13 +514,13 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); - printk(KERN_INFO "HDMI non-intrinsic event: " - "SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", - subtag, - cp_state, - cp_ready); + printk(KERN_INFO + "HDMI content protection event: SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", + subtag, + cp_state, + cp_ready); - /* who cares? */ + /* TODO */ if (cp_state) ; if (cp_ready) @@ -532,9 +534,7 @@ static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; if (tag != INTEL_HDMI_EVENT_TAG) { - snd_printd(KERN_INFO - "Unexpected HDMI unsolicited event tag 0x%x\n", - tag); + snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); return; } -- cgit v1.2.3 From acb05993881005cdaf5f8291491b4edcb8f60ef3 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 22 Nov 2008 09:40:54 +0800 Subject: ALSA: hda - ELD proc interface write updates - rename ELD proc write routine to hdmi_write_eld_info() - support modifying WMAPro's profile Write to some ELD fields (monitor_name, manufacture_id, product_id, eld_version, edid_version) are deliberately not supported, since that won't correct wrong behaviors and only leads to confusions. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 3f10961a17b..3c580ae07bd 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -502,7 +502,7 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, hdmi_print_sad_info(i, e->sad + i, buffer); } -static void hdmi_write_eld_item(struct snd_info_entry *entry, +static void hdmi_write_eld_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct hdmi_eld *e = entry->private_data; @@ -515,6 +515,11 @@ static void hdmi_write_eld_item(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%s %llx", name, &val) != 2) continue; + /* + * We don't allow modification to these fields: + * monitor_name manufacture_id product_id + * eld_version edid_version + */ if (!strcmp(name, "connection_type")) e->conn_type = val; else if (!strcmp(name, "port_id")) @@ -548,6 +553,8 @@ static void hdmi_write_eld_item(struct snd_info_entry *entry, e->sad[n].sample_bits = val; else if (!strcmp(sname, "_max_bitrate")) e->sad[n].max_bitrate = val; + else if (!strcmp(sname, "_profile")) + e->sad[n].profile = val; if (n >= e->sad_count) e->sad_count = n + 1; } @@ -567,7 +574,7 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) return err; snd_info_set_text_ops(entry, eld, hdmi_print_eld_info); - entry->c.text.write = hdmi_write_eld_item; + entry->c.text.write = hdmi_write_eld_info; entry->mode |= S_IWUSR; eld->proc_entry = entry; -- cgit v1.2.3 From a5fcf89eff2372b50f2d47fbb3e1f3090f044ee3 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 22 Nov 2008 09:40:55 +0800 Subject: ALSA: hda - document the ELD proc interface Describe what ELD proc interface provides and how to fix incorrect values. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/Procfile.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt index f738b296440..bba2dbb79d8 100644 --- a/Documentation/sound/alsa/Procfile.txt +++ b/Documentation/sound/alsa/Procfile.txt @@ -153,6 +153,16 @@ card*/codec#* Shows the general codec information and the attribute of each widget node. +card*/eld#* + Available for HDMI or DisplayPort interfaces. + Shows ELD(EDID Like Data) info retrieved from the attached HDMI sink, + and describes its audio capabilities and configurations. + + Some ELD fields may be modified by doing `echo name hex_value > eld#*`. + Only do this if you are sure the HDMI sink provided value is wrong. + And if that makes your HDMI audio work, please report to us so that we + can fix it in future kernel releases. + Sequencer Information --------------------- -- cgit v1.2.3 From 9415e1c418b33bf9b8d8903fb98876ec72673e3f Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 22 Nov 2008 09:40:56 +0800 Subject: ALSA: hda - fix DisplayPort naming DisplayPort is a digital display interface standard put forth by the Video Electronics Standards Association (VESA). It defines a new license-free, royalty-free, digital audio/video interconnect, intended to be used primarily between a computer and its display monitor, or a computer and a home-theater system. - From Wikipedia, the free encyclopedia Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 3c580ae07bd..aa438562efc 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -72,7 +72,7 @@ static char *cea_speaker_allocation_names[] = { static char *eld_connection_type_names[4] = { "HDMI", - "Display Port", + "DisplayPort", "2-reserved", "3-reserved" }; -- cgit v1.2.3 From 4805286bffa9d7b85223ab2038f08b4b6322a176 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 22 Nov 2008 09:40:57 +0800 Subject: ALSA: hda - fix build warning when CONFIG_PROC_FS=n Fix "defined but not used" build warning by moving eld_versoin_names[] and cea_edid_version_names[] into hdmi_print_eld_info(). Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index aa438562efc..fcad5ec3177 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -32,14 +32,6 @@ enum eld_versions { ELD_VER_PARTIAL = 31, }; -static char *eld_versoin_names[32] = { - "reserved", - "reserved", - "CEA-861D or below", - [3 ... 30] = "reserved", - [31] = "partial" -}; - enum cea_edid_versions { CEA_EDID_VER_NONE = 0, CEA_EDID_VER_CEA861 = 1, @@ -48,14 +40,6 @@ enum cea_edid_versions { CEA_EDID_VER_RESERVED = 4, }; -static char *cea_edid_version_names[8] = { - "no CEA EDID Timing Extension block present", - "CEA-861", - "CEA-861-A", - "CEA-861-B, C or D", - [4 ... 7] = "reserved" -}; - static char *cea_speaker_allocation_names[] = { /* 0 */ "FL/FR", /* 1 */ "LFE", @@ -478,6 +462,20 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, struct hdmi_eld *e = entry->private_data; char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; int i; + static char *eld_versoin_names[32] = { + "reserved", + "reserved", + "CEA-861D or below", + [3 ... 30] = "reserved", + [31] = "partial" + }; + static char *cea_edid_version_names[8] = { + "no CEA EDID Timing Extension block present", + "CEA-861", + "CEA-861-A", + "CEA-861-B, C or D", + [4 ... 7] = "reserved" + }; snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); snd_iprintf(buffer, "connection_type\t\t%s\n", -- cgit v1.2.3 From a9cb5c90539dd618029884701760fe79b9b83102 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 24 Nov 2008 07:51:11 +0100 Subject: ALSA: hda - No 'Headphone as Line-out' swich without line-outs STAC/IDT driver creates "Headphone as Line-Out" switch even if there is no line-out pins on the machine. For devices only with headpohnes and speaker-outs, this switch shouldn't be created. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index ce34e4dfe98..7cd395a175e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2962,7 +2962,7 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, cfg->hp_outs && !spec->multiout.hp_nid) spec->multiout.hp_nid = nid; - if (cfg->hp_outs > 1) { + if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) { err = stac92xx_add_control(spec, STAC_CTL_WIDGET_HP_SWITCH, "Headphone as Line Out Switch", -- cgit v1.2.3 From ef8ef5fb1027b56f867d4b913cf52bfdc610d2a7 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Sun, 23 Nov 2008 11:31:41 +0800 Subject: ALSA: hda: Added an ALC888 model entry for Fujitsu-Siemens Amilo Xa3530 This patch fixes the bug 0004240: ALC888 - Intel HDA - Headphone Controlling. It is made against the 2008-11-23 snapshot. Added Realtek ALC888 model entry for the Fujitsu-Siemens Amilo Xa3530 laptop. It has 4 jacks: HP out, Mic-in, Line-in and Line-out/Side/SPDIF (this one is on the laptop side, the other ones are on the rear). Model detection works. Headphone jack sense works now. Front mic works now, was same as Acer Aspire 4930G. Added channel mode from 2 to 8 channels. In 2ch and 4ch modes, the front is also sent to the Line-out/side jack for convenience instead of just muting the Line-out/side jack like other models do. When using the Mic-in jack as CLFE, the sound is very low (bug?). To work it around, in 6ch mode the CLFE channel is duplicated to the Line-out/side jack because this one has a better amp. Cc: manu@frogged.de Signed-off-by: Vincent Petry Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/hda/patch_realtek.c | 176 ++++++++++++++++++++++-- 2 files changed, 168 insertions(+), 9 deletions(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 1b7e36af0f0..93624e7b4f0 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -919,6 +919,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. mitac Mitac 8252D clevo-m720 Clevo M720 laptop series fujitsu-pi2515 Fujitsu AMILO Pi2515 + fujitsu-xa3530 Fujitsu AMILO XA3530 3stack-6ch-intel Intel DG33* boards auto auto-config reading BIOS (default) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6ec56c62cb1..f52e271edd5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -230,6 +230,7 @@ enum { ALC883_MITAC, ALC883_CLEVO_M720, ALC883_FUJITSU_PI2515, + ALC888_FUJITSU_XA3530, ALC883_3ST_6ch_INTEL, ALC888_ASUS_M90V, ALC888_ASUS_EEE1601, @@ -1155,6 +1156,141 @@ static void alc_fix_pincfg(struct hda_codec *codec, } } +/* + * ALC888 + */ + +/* + * 2ch mode + */ +static struct hda_verb alc888_4ST_ch2_intel_init[] = { +/* Mic-in jack as mic in */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +/* Line-in jack as Line in */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +/* Line-Out as Front */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } /* end */ +}; + +/* + * 4ch mode + */ +static struct hda_verb alc888_4ST_ch4_intel_init[] = { +/* Mic-in jack as mic in */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +/* Line-in jack as Surround */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-Out as Front */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } /* end */ +}; + +/* + * 6ch mode + */ +static struct hda_verb alc888_4ST_ch6_intel_init[] = { +/* Mic-in jack as CLFE */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-in jack as Surround */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + { } /* end */ +}; + +/* + * 8ch mode + */ +static struct hda_verb alc888_4ST_ch8_intel_init[] = { +/* Mic-in jack as CLFE */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-in jack as Surround */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-Out as Side */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + { } /* end */ +}; + +static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = { + { 2, alc888_4ST_ch2_intel_init }, + { 4, alc888_4ST_ch4_intel_init }, + { 6, alc888_4ST_ch6_intel_init }, + { 8, alc888_4ST_ch8_intel_init }, +}; + +/* + * ALC888 Fujitsu Siemens Amillo xa3530 + */ + +static struct hda_verb alc888_fujitsu_xa3530_verbs[] = { +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Connect Internal HP to Front */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect Bass HP to Front */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect Line-Out side jack (SPDIF) to Side */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, +/* Connect Mic jack to CLFE */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, +/* Connect Line-in jack to Surround */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, +/* Connect HP out jack to Front */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Enable unsolicited event for HP jack and Line-out jack */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {} +}; + +static void alc888_fujitsu_xa3530_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned int bits; + /* Line out presence */ + present = snd_hda_codec_read(codec, 0x17, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + /* HP out presence */ + present = present || snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + /* Toggle internal speakers muting */ + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + /* Toggle internal bass muting */ + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} + +static void alc888_fujitsu_xa3530_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if (res >> 26 == ALC880_HP_EVENT) + alc888_fujitsu_xa3530_automute(codec); +} + + /* * ALC888 Acer Aspire 4930G model */ @@ -1164,7 +1300,7 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Unselect Front Mic by default in input mixer 3 */ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, -/* enable unsolicited event fpr HP jack */ +/* Enable unsolicited event for HP jack */ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, /* Connect Internal HP to front */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -1177,7 +1313,7 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { { } }; -static struct hda_input_mux alc888_acer_aspire_4930g_capture_source[2] = { +static struct hda_input_mux alc888_2_capture_sources[2] = { /* Front mic only available on one ADC */ { .num_items = 4, @@ -1198,7 +1334,7 @@ static struct hda_input_mux alc888_acer_aspire_4930g_capture_source[2] = { } }; -static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { +static struct snd_kcontrol_new alc888_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -1225,11 +1361,12 @@ static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec) { unsigned int present; + unsigned int bits; present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - /* Toggle the internal HP PIN (regular muting doesn't work) */ - snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - (present ? 0x0 : PIN_OUT)); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec, @@ -8286,6 +8423,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC883_MITAC] = "mitac", [ALC883_CLEVO_M720] = "clevo-m720", [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", + [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530", [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", [ALC1200_ASUS_P5Q] = "asus-p5q", [ALC883_AUTO] = "auto", @@ -8346,6 +8484,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515), + SND_PCI_QUIRK(0x1734, 0x113d, "Fujitsu AMILO Xa3530", + ALC888_FUJITSU_XA3530), SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch), SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763), SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), @@ -8472,7 +8612,7 @@ static struct alc_config_preset alc883_presets[] = { .init_hook = alc883_acer_aspire_automute, }, [ALC888_ACER_ASPIRE_4930G] = { - .mixers = { alc888_acer_aspire_4930g_mixer, + .mixers = { alc888_base_mixer, alc883_chmode_mixer }, .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, alc888_acer_aspire_4930g_verbs }, @@ -8486,8 +8626,8 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_6ch_modes, .need_dac_fix = 1, .num_mux_defs = - ARRAY_SIZE(alc888_acer_aspire_4930g_capture_source), - .input_mux = alc888_acer_aspire_4930g_capture_source, + ARRAY_SIZE(alc888_2_capture_sources), + .input_mux = alc888_2_capture_sources, .unsol_event = alc888_acer_aspire_4930g_unsol_event, .init_hook = alc888_acer_aspire_4930g_automute, }, @@ -8634,6 +8774,24 @@ static struct alc_config_preset alc883_presets[] = { .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event, .init_hook = alc883_2ch_fujitsu_pi2515_automute, }, + [ALC888_FUJITSU_XA3530] = { + .mixers = { alc888_base_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, + alc888_fujitsu_xa3530_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes), + .channel_mode = alc888_4ST_8ch_intel_modes, + .num_mux_defs = + ARRAY_SIZE(alc888_2_capture_sources), + .input_mux = alc888_2_capture_sources, + .unsol_event = alc888_fujitsu_xa3530_unsol_event, + .init_hook = alc888_fujitsu_xa3530_automute, + }, [ALC888_LENOVO_SKY] = { .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs}, -- cgit v1.2.3 From ef1681d82f4bc2d9e023519f0bedb86519d10c43 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 24 Nov 2008 17:29:28 +0100 Subject: ALSA: hda - Add probe_mask quirk for Medion MD96630 Medion MD96630 has ALC268 codec on slot#2 although it's not used for any purpose. This codec conflicts with the primiary codec ALC888 on slot#0, and gives mixer errors. This patch adds a corresponding entry to probe_mask blacklist. Reference: Novell bnc#412528 https://bugzilla.novell.com/show_bug.cgi?id=412528 Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3870ad622da..6462d758e64 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2073,6 +2073,8 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = { SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01), /* broken BIOS */ SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01), + /* including bogus ALC268 in slot#2 that conflicts with ALC888 */ + SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01), {} }; -- cgit v1.2.3 From 82894b6f6f109722070d4d78730fe50cdaba9443 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Nov 2008 11:42:54 +0100 Subject: ALSA: hda - Fix proc pcm rate bits Show only the relevant bits in the PCM rate bits as in the earlier version. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index e7f91c44e63..a2eba4f17e9 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -103,7 +103,7 @@ static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) { char buf[SND_PRINT_BITS_ADVISED_BUFSIZE]; - snd_iprintf(buffer, " bits [0x%x]:", pcm); + snd_iprintf(buffer, " bits [0x%x]:", (pcm & AC_SUPPCM_RATES) >> 16); snd_print_pcm_bits(pcm, buf, sizeof(buf)); snd_iprintf(buffer, "%s\n", buf); } -- cgit v1.2.3 From c6e4c66613c2bb040e53bb04006c277992cc8f4b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Nov 2008 11:58:19 +0100 Subject: ALSA: hda - Assign unsol tags dynamically in patch_sigmatel.c Since we need to handle many unsolicited events assigned to different widgets, allocate the event dynamically using the existing events array, and use the tag appropriately instead of combination of fixed number and widget nid. (Note that widget nid can be over 4 bits!) Also, replaced the call of unsol_event handler with a dedicated function to be more readable. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 159 ++++++++++++++++++++++++++--------------- 1 file changed, 101 insertions(+), 58 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 09b3f4b1db4..4b7dda57c0e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -36,10 +36,12 @@ #include "hda_patch.h" #include "hda_beep.h" -#define STAC_VREF_EVENT 0x00 -#define STAC_INSERT_EVENT 0x10 -#define STAC_PWR_EVENT 0x20 -#define STAC_HP_EVENT 0x30 +enum { + STAC_VREF_EVENT = 1, + STAC_INSERT_EVENT, + STAC_PWR_EVENT, + STAC_HP_EVENT, +}; enum { STAC_REF, @@ -134,6 +136,8 @@ enum { struct sigmatel_event { hda_nid_t nid; + unsigned char type; + unsigned char tag; int data; }; @@ -2549,6 +2553,9 @@ static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol, return 0; } +static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, + unsigned char type); + static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2561,7 +2568,7 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, /* check to be sure that the ports are upto date with * switch changes */ - codec->patch_ops.unsol_event(codec, (STAC_HP_EVENT | nid) << 26); + stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); return 1; } @@ -2601,8 +2608,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ * appropriately according to the pin direction */ if (spec->hp_detect) - codec->patch_ops.unsol_event(codec, - (STAC_HP_EVENT | nid) << 26); + stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); return 1; } @@ -3768,8 +3774,8 @@ static int stac92xx_add_jack(struct hda_codec *codec, #endif } -static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid, - int data) +static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid, + unsigned char type, int data) { struct sigmatel_event *event; @@ -3778,32 +3784,59 @@ static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid, if (!event) return -ENOMEM; event->nid = nid; + event->type = type; + event->tag = spec->events.used; event->data = data; - return 0; + return event->tag; } -static int stac92xx_event_data(struct hda_codec *codec, hda_nid_t nid) +static struct sigmatel_event *stac_get_event(struct hda_codec *codec, + hda_nid_t nid, unsigned char type) { struct sigmatel_spec *spec = codec->spec; - struct sigmatel_event *events = spec->events.list; - if (events) { - int i; - for (i = 0; i < spec->events.used; i++) - if (events[i].nid == nid) - return events[i].data; + struct sigmatel_event *event = spec->events.list; + int i; + + for (i = 0; i < spec->events.used; i++, event++) { + if (event->nid == nid && event->type == type) + return event; } - return 0; + return NULL; } -static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, - unsigned int event) +static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec, + unsigned char tag) { - if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | event | nid)); + struct sigmatel_spec *spec = codec->spec; + struct sigmatel_event *event = spec->events.list; + int i; + + for (i = 0; i < spec->events.used; i++, event++) { + if (event->tag == tag) + return event; } + return NULL; +} + +static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, + unsigned int type) +{ + struct sigmatel_event *event; + int tag; + + if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) + return; + event = stac_get_event(codec, nid, type); + if (event) + tag = event->tag; + else + tag = stac_add_event(codec->spec, nid, type, 0); + if (tag < 0) + return; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | tag); } static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) @@ -3862,7 +3895,7 @@ static int stac92xx_init(struct hda_codec *codec) /* Enable unsolicited responses on the HP widget */ for (i = 0; i < cfg->hp_outs; i++) { hda_nid_t nid = cfg->hp_pins[i]; - enable_pin_detect(codec, nid, STAC_HP_EVENT | nid); + enable_pin_detect(codec, nid, STAC_HP_EVENT); } /* force to enable the first line-out; the others are set up * in unsol_event @@ -3870,8 +3903,8 @@ static int stac92xx_init(struct hda_codec *codec) stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], AC_PINCTL_OUT_EN); /* fake event to set up pins */ - codec->patch_ops.unsol_event(codec, - (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26); + stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], + STAC_HP_EVENT); } else { stac92xx_auto_init_multi_out(codec); stac92xx_auto_init_hp_out(codec); @@ -3892,7 +3925,7 @@ static int stac92xx_init(struct hda_codec *codec) } pinctl |= AC_PINCTL_IN_EN; stac92xx_auto_set_pinctl(codec, nid, pinctl); - enable_pin_detect(codec, nid, STAC_INSERT_EVENT | nid); + enable_pin_detect(codec, nid, STAC_INSERT_EVENT); } } for (i = 0; i < spec->num_dmics; i++) @@ -3907,7 +3940,6 @@ static int stac92xx_init(struct hda_codec *codec) for (i = 0; i < spec->num_pwrs; i++) { hda_nid_t nid = spec->pwr_nids[i]; int pinctl, def_conf; - int event = STAC_PWR_EVENT; if (is_nid_hp_pin(cfg, nid) && spec->hp_detect) continue; /* already has an unsol event */ @@ -3930,8 +3962,8 @@ static int stac92xx_init(struct hda_codec *codec) stac_toggle_power_map(codec, nid, 1); continue; } - enable_pin_detect(codec, spec->pwr_nids[i], event | i); - codec->patch_ops.unsol_event(codec, (event | i) << 26); + enable_pin_detect(codec, nid, STAC_PWR_EVENT); + stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT); } if (spec->dac_list) stac92xx_power_down(codec); @@ -4059,7 +4091,7 @@ static int no_hp_sensing(struct sigmatel_spec *spec, int i) return 0; } -static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) +static void stac92xx_hp_detect(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; @@ -4182,33 +4214,43 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) } } +static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, + unsigned char type) +{ + struct sigmatel_event *event = stac_get_event(codec, nid, type); + if (!event) + return; + codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26); +} + static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) { struct sigmatel_spec *spec = codec->spec; - int event = (res >> 26) & 0x70; - int nid = res >> 26 & 0x0f; + struct sigmatel_event *event; + int tag, data; - switch (event) { + tag = (res >> 26) & 0x7f; + event = stac_get_event_from_tag(codec, tag); + if (!event) + return; + + switch (event->type) { case STAC_HP_EVENT: - stac92xx_hp_detect(codec, res); + stac92xx_hp_detect(codec); /* fallthru */ case STAC_INSERT_EVENT: case STAC_PWR_EVENT: - if (nid) { - if (spec->num_pwrs > 0) - stac92xx_pin_sense(codec, nid); - stac92xx_report_jack(codec, nid); - } + if (spec->num_pwrs > 0) + stac92xx_pin_sense(codec, event->nid); + stac92xx_report_jack(codec, event->nid); break; - case STAC_VREF_EVENT: { - int data = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0); - int idx = stac92xx_event_data(codec, nid); + case STAC_VREF_EVENT: + data = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DATA, 0); /* toggle VREF state based on GPIOx status */ snd_hda_codec_write(codec, codec->afg, 0, 0x7e0, - !!(data & (1 << idx))); + !!(data & (1 << event->data))); break; - } } } @@ -4223,8 +4265,8 @@ static int stac92xx_resume(struct hda_codec *codec) snd_hda_codec_resume_cache(codec); /* fake event to set up pins again to override cached values */ if (spec->hp_detect) - codec->patch_ops.unsol_event(codec, - (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26); + stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], + STAC_HP_EVENT); return 0; } @@ -4732,14 +4774,15 @@ again: switch (spec->board_config) { case STAC_HP_M4: /* Enable VREF power saving on GPIO1 detect */ + err = stac_add_event(spec, codec->afg, + STAC_VREF_EVENT, 0x02); + if (err < 0) + return err; snd_hda_codec_write_cache(codec, codec->afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); snd_hda_codec_write_cache(codec, codec->afg, 0, AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg)); - err = stac92xx_add_event(spec, codec->afg, 0x02); - if (err < 0) - return err; + AC_USRSP_EN | err); spec->gpio_mask |= 0x02; break; } @@ -5131,14 +5174,14 @@ static int patch_stac9205(struct hda_codec *codec) stac_change_pin_config(codec, 0x20, 0x1c410030); /* Enable unsol response for GPIO4/Dock HP connection */ + err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01); + if (err < 0) + return err; snd_hda_codec_write_cache(codec, codec->afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg)); - err = stac92xx_add_event(spec, codec->afg, 0x01); - if (err < 0) - return err; + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | err); spec->gpio_dir = 0x0b; spec->eapd_mask = 0x01; -- cgit v1.2.3 From ee09543c866559e1ffb4f5c38533f2bedd725acd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Nov 2008 15:03:38 +0100 Subject: ALSA: hda - Add quirk for MSI 7260 mobo Added preset model=targa-dig for MSI 7260 mobo. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f52e271edd5..4afa0c9b9b6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8473,6 +8473,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG), SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), -- cgit v1.2.3 From b0e6481a9ae9e8c80b5d956980767ecad35c95c1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Nov 2008 16:07:01 +0100 Subject: ALSA: hda - Really fix bits value in proc output The fix in 82894b6f6f109722070d4d78730fe50cdaba9443 resulted in zero due to wrong mask and bit shifts. Now fixed really. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index a2eba4f17e9..9a8498456e6 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -103,7 +103,7 @@ static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) { char buf[SND_PRINT_BITS_ADVISED_BUFSIZE]; - snd_iprintf(buffer, " bits [0x%x]:", (pcm & AC_SUPPCM_RATES) >> 16); + snd_iprintf(buffer, " bits [0x%x]:", (pcm >> 16) & 0xff); snd_print_pcm_bits(pcm, buf, sizeof(buf)); snd_iprintf(buffer, "%s\n", buf); } -- cgit v1.2.3 From 4f199629b0fba95fd5caecbf35ed68417d9a9b7a Mon Sep 17 00:00:00 2001 From: Qinghuang Feng Date: Tue, 25 Nov 2008 23:24:49 +0800 Subject: ALSA: sound/pci/hda/hda_codec.c: cleanup kernel-doc There is no argument named @state in snd_hda_resume, remove its' comment. Signed-off-by: Qinghuang Feng Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 53f64eb75ec..1131c86ad49 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3358,7 +3358,6 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) /** * snd_hda_resume - resume the codecs * @bus: the HDA bus - * @state: resume state * * Returns 0 if successful. * -- cgit v1.2.3 From 986862bdf17655d012f9b0654925dccdcc4183c9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Nov 2008 12:40:13 +0100 Subject: ALSA: hda - make some functions static Minor clean ups: move snd_hda_codecs_inuse() into hda_intel.c and make static. Also, make snd_hda_query_supported_pcm() static as it's used only in hda_codec.c. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 14 +------------- sound/pci/hda/hda_codec.h | 4 ---- sound/pci/hda/hda_intel.c | 13 +++++++++++++ 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 1131c86ad49..f84874445b5 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2218,7 +2218,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, * * Returns 0 if successful, otherwise a negative error code. */ -int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, +static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, u32 *ratesp, u64 *formatsp, unsigned int *bpsp) { int i; @@ -3374,18 +3374,6 @@ int snd_hda_resume(struct hda_bus *bus) } return 0; } -#ifdef CONFIG_SND_HDA_POWER_SAVE -int snd_hda_codecs_inuse(struct hda_bus *bus) -{ - struct hda_codec *codec; - - list_for_each_entry(codec, &bus->codec_list, list) { - if (snd_hda_codec_needs_resume(codec)) - return 1; - } - return 0; -} -#endif #endif /* diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index a70b181bbac..e1077df5e88 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -852,8 +852,6 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, unsigned int channels, unsigned int format, unsigned int maxbps); -int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, - u32 *ratesp, u64 *formatsp, unsigned int *bpsp); int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, unsigned int format); @@ -884,12 +882,10 @@ const char *snd_hda_get_jack_location(u32 cfg); void snd_hda_power_up(struct hda_codec *codec); void snd_hda_power_down(struct hda_codec *codec); #define snd_hda_codec_needs_resume(codec) codec->power_count -int snd_hda_codecs_inuse(struct hda_bus *bus); #else static inline void snd_hda_power_up(struct hda_codec *codec) {} static inline void snd_hda_power_down(struct hda_codec *codec) {} #define snd_hda_codec_needs_resume(codec) 1 -#define snd_hda_codecs_inuse(bus) 1 #endif #endif /* __SOUND_HDA_CODEC_H */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 6462d758e64..f13ec4c71f8 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1896,6 +1896,19 @@ static void azx_power_notify(struct hda_bus *bus) else if (chip->running && power_save_controller) azx_stop_chip(chip); } + +static int snd_hda_codecs_inuse(struct hda_bus *bus) +{ + struct hda_codec *codec; + + list_for_each_entry(codec, &bus->codec_list, list) { + if (snd_hda_codec_needs_resume(codec)) + return 1; + } + return 0; +} +#else /* !CONFIG_SND_HDA_POWER_SAVE */ +#define snd_hda_codecs_inuse(bus) 1 #endif /* CONFIG_SND_HDA_POWER_SAVE */ #ifdef CONFIG_PM -- cgit v1.2.3 From fee2fba3586f78762ecc5f432dfd3602765a31b3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Nov 2008 12:43:28 +0100 Subject: ALSA: hda - Move power_save option to hda_intel.c Move power_save option into hda_intel.c, and make a field in hda_bus, instead of keeping module parameters in separate files. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 16 ++++++---------- sound/pci/hda/hda_codec.h | 2 ++ sound/pci/hda/hda_intel.c | 6 +++++- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f84874445b5..052a898a63b 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -33,14 +33,6 @@ #include #include "hda_patch.h" /* codec presets */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -/* define this option here to hide as static */ -static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; -module_param(power_save, int, 0644); -MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " - "(in second, 0 = disable)."); -#endif - /* * vendor / preset table */ @@ -519,6 +511,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, bus->private_data = temp->private_data; bus->pci = temp->pci; bus->modelname = temp->modelname; + bus->power_save = temp->power_save; bus->ops = temp->ops; mutex_init(&bus->cmd_mutex); @@ -2694,15 +2687,18 @@ void snd_hda_power_up(struct hda_codec *codec) codec->power_transition = 0; } +#define power_save(codec) \ + ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) + void snd_hda_power_down(struct hda_codec *codec) { --codec->power_count; if (!codec->power_on || codec->power_count || codec->power_transition) return; - if (power_save) { + if (power_save(codec)) { codec->power_transition = 1; /* avoid reentrance */ schedule_delayed_work(&codec->power_work, - msecs_to_jiffies(power_save * 1000)); + msecs_to_jiffies(power_save(codec) * 1000)); } } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index e1077df5e88..4034625b599 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -585,6 +585,7 @@ struct hda_bus_template { void *private_data; struct pci_dev *pci; const char *modelname; + int *power_save; struct hda_bus_ops ops; }; @@ -601,6 +602,7 @@ struct hda_bus { void *private_data; struct pci_dev *pci; const char *modelname; + int *power_save; struct hda_bus_ops ops; /* codec linked list */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f13ec4c71f8..f17ccd51335 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -83,7 +83,10 @@ module_param(enable_msi, int, 0444); MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); #ifdef CONFIG_SND_HDA_POWER_SAVE -/* power_save option is defined in hda_codec.c */ +static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; +module_param(power_save, int, 0644); +MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " + "(in second, 0 = disable)."); /* reset the HD-audio controller in power save mode. * this may give more power-saving, but will take longer time to @@ -1230,6 +1233,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, memset(&bus_temp, 0, sizeof(bus_temp)); bus_temp.private_data = chip; bus_temp.modelname = model; + bus_temp.power_save = &power_save; bus_temp.pci = chip->pci; bus_temp.ops.command = azx_send_cmd; bus_temp.ops.get_response = azx_get_response; -- cgit v1.2.3 From 529bd6c4a63f8468fd66f63fdc22d7070439b3cd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Nov 2008 14:17:01 +0100 Subject: ALSA: hda - Fix PCM reconfigure The reconfiguration of PCM affected all PCM streams on the bus, but this this should be done rather only for the target codec. This patch does the following: - introduce bitmap indicating the PCM device usages on a hda_bus - refactor the PCM build functions - fix __devinit prefix in some fucntions - add a proper ifdef around HDA-reconfig-specific functions Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 162 ++++++++++++++++++++++++++-------------------- sound/pci/hda/hda_codec.h | 4 ++ sound/pci/hda/hda_hwdep.c | 2 +- 3 files changed, 98 insertions(+), 70 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 052a898a63b..1cb85b73e19 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1206,6 +1206,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) return 0; } +#ifdef CONFIG_SND_HDA_RECONFIG /* Clear all controls assigned to the given codec */ void snd_hda_ctls_clear(struct hda_codec *codec) { @@ -1227,9 +1228,12 @@ void snd_hda_codec_reset(struct hda_codec *codec) snd_hda_ctls_clear(codec); /* relase PCMs */ for (i = 0; i < codec->num_pcms; i++) { - if (codec->pcm_info[i].pcm) + if (codec->pcm_info[i].pcm) { snd_device_free(codec->bus->card, codec->pcm_info[i].pcm); + clear_bit(codec->pcm_info[i].device, + codec->bus->pcm_dev_bits); + } } if (codec->patch_ops.free) codec->patch_ops.free(codec); @@ -1240,6 +1244,7 @@ void snd_hda_codec_reset(struct hda_codec *codec) codec->pcm_info = NULL; codec->preset = NULL; } +#endif /* CONFIG_SND_HDA_RECONFIG */ /* create a virtual master control and add slaves */ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, @@ -2432,11 +2437,59 @@ static int set_pcm_default_values(struct hda_codec *codec, return 0; } +/* + * get the empty PCM device number to assign + */ +static int get_empty_pcm_device(struct hda_bus *bus, int type) +{ + 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 }; + int i, dev; + + switch (type) { + case HDA_PCM_TYPE_AUDIO: + for (i = 0; i < ARRAY_SIZE(audio_idx); i++) { + dev = audio_idx[i]; + if (!test_bit(dev, bus->pcm_dev_bits)) + break; + } + if (i >= ARRAY_SIZE(audio_idx)) { + snd_printk(KERN_WARNING "Too many audio devices\n"); + return -EAGAIN; + } + break; + case HDA_PCM_TYPE_SPDIF: + case HDA_PCM_TYPE_HDMI: + case HDA_PCM_TYPE_MODEM: + dev = dev_idx[type]; + if (test_bit(dev, bus->pcm_dev_bits)) { + snd_printk(KERN_WARNING "%s already defined\n", + dev_name[type]); + return -EAGAIN; + } + break; + default: + snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); + return -EINVAL; + } + set_bit(dev, bus->pcm_dev_bits); + return dev; +} + /* * attach a new PCM stream */ -static int __devinit -snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) +static int snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) { struct hda_bus *bus = codec->bus; struct hda_pcm_stream *info; @@ -2455,6 +2508,39 @@ snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) return bus->ops.attach_pcm(bus, codec, pcm); } +/* assign all PCMs of the given codec */ +int snd_hda_codec_build_pcms(struct hda_codec *codec) +{ + unsigned int pcm; + int err; + + if (!codec->num_pcms) { + if (!codec->patch_ops.build_pcms) + return 0; + err = codec->patch_ops.build_pcms(codec); + if (err < 0) + return err; + } + for (pcm = 0; pcm < codec->num_pcms; pcm++) { + struct hda_pcm *cpcm = &codec->pcm_info[pcm]; + int dev; + + if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) + return 0; /* no substreams assigned */ + + if (!cpcm->pcm) { + dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type); + if (dev < 0) + return 0; + cpcm->device = dev; + err = snd_hda_attach_pcm(codec, cpcm); + if (err < 0) + return err; + } + } + return 0; +} + /** * snd_hda_build_pcms - build PCM information * @bus: the BUS @@ -2481,76 +2567,14 @@ snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) * * This function returns 0 if successfull, or a negative error code. */ -int snd_hda_build_pcms(struct hda_bus *bus) +int __devinit 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; - 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++) { - struct hda_pcm *cpcm = &codec->pcm_info[pcm]; - int type = cpcm->pcm_type; - int dev; - - if (!cpcm->stream[0].substreams && - !cpcm->stream[1].substreams) - continue; /* no substreams assigned */ - - 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; - } - 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; - } - } + int err = snd_hda_codec_build_pcms(codec); + if (err < 0) + return err; } return 0; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 4034625b599..9fe0b67bb1e 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -617,6 +617,9 @@ struct hda_bus { struct snd_info_entry *proc; + /* assigned PCMs */ + DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES); + /* misc op flags */ unsigned int needs_damn_long_delay :1; unsigned int shutdown :1; /* being unloaded */ @@ -846,6 +849,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec); * PCM */ int snd_hda_build_pcms(struct hda_bus *bus); +int snd_hda_codec_build_pcms(struct hda_codec *codec); void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, int channel_id, int format); diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 5868bbc131c..173af489322 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -168,7 +168,7 @@ static int reconfig_codec(struct hda_codec *codec) if (err < 0) return err; /* rebuild PCMs */ - err = snd_hda_build_pcms(codec->bus); + err = snd_hda_codec_build_pcms(codec); if (err < 0) return err; /* rebuild mixers */ -- cgit v1.2.3 From 30d72e9f614e7bd76e28d4d92bd54d90a96905bb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Nov 2008 15:25:34 +0100 Subject: ALSA: hda - Fix creation of automatic capture mixers Fixed a wrong boundary check of num_adc_nids in set_capture_mixer() in patch_realtek.c. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4afa0c9b9b6..9cd2545d988 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4269,7 +4269,7 @@ static void set_capture_mixer(struct alc_spec *spec) alc_capture_mixer2, alc_capture_mixer3, }; - if (spec->num_adc_nids > 0 && spec->num_adc_nids < 3) + if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) spec->cap_mixer = caps[spec->num_adc_nids - 1]; } -- cgit v1.2.3 From 1289e9e8b42f973f2ab39e5f4f2239ff826c27e9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Nov 2008 15:47:11 +0100 Subject: ALSA: hda - Modularize HD-audio driver Split the monolithc HD-audio driver into several pieces: - snd-hda-intel HD-audio PCI controller driver; loaded via udev - snd-hda-codec HD-audio codec bus driver - snd-hda-codec-* Specific HD-audio codec drivers When built as modules, snd-hda-codec (that is invoked by snd-hda-intel) looks up the codec vendor ID and loads the corresponding codec module automatically via request_module(). When built in a kernel, each codec drivers are statically hooked up before probing the PCI. This patch adds appropriate EXPORT_SYMBOL_GPL()'s and the module information for each driver, and driver-linking codes between codec-bus and codec drivers. TODO: - Avoid EXPORT_SYMBOL*() when built-in kernel - Restore __devinit appropriately depending on the condition Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 50 +++++++++++ sound/pci/hda/Makefile | 77 ++++++++++++----- sound/pci/hda/hda_beep.c | 2 + sound/pci/hda/hda_codec.c | 187 ++++++++++++++++++++++++++++++---------- sound/pci/hda/hda_codec.h | 11 +++ sound/pci/hda/hda_generic.c | 1 + sound/pci/hda/hda_hwdep.c | 2 +- sound/pci/hda/hda_patch.h | 24 ------ sound/pci/hda/patch_analog.c | 26 +++++- sound/pci/hda/patch_atihdmi.c | 31 ++++++- sound/pci/hda/patch_cmedia.c | 27 +++++- sound/pci/hda/patch_conexant.c | 28 +++++- sound/pci/hda/patch_intelhdmi.c | 30 ++++++- sound/pci/hda/patch_nvhdmi.c | 27 +++++- sound/pci/hda/patch_realtek.c | 26 +++++- sound/pci/hda/patch_si3054.c | 35 +++++++- sound/pci/hda/patch_sigmatel.c | 27 +++++- sound/pci/hda/patch_via.c | 26 +++++- 18 files changed, 528 insertions(+), 109 deletions(-) delete mode 100644 sound/pci/hda/hda_patch.h diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 7c60f1a45a8..717040a491b 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -46,6 +46,11 @@ config SND_HDA_CODEC_REALTEK Say Y here to include Realtek HD-audio codec support in snd-hda-intel driver, such as ALC880. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-realtek. + This module is automatically loaded at probing. + config SND_HDA_CODEC_ANALOG bool "Build Analog Device HD-audio codec support" default y @@ -53,6 +58,11 @@ config SND_HDA_CODEC_ANALOG Say Y here to include Analog Device HD-audio codec support in snd-hda-intel driver, such as AD1986A. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-analog. + This module is automatically loaded at probing. + config SND_HDA_CODEC_SIGMATEL bool "Build IDT/Sigmatel HD-audio codec support" default y @@ -60,6 +70,11 @@ config SND_HDA_CODEC_SIGMATEL Say Y here to include IDT (Sigmatel) HD-audio codec support in snd-hda-intel driver, such as STAC9200. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-idt. + This module is automatically loaded at probing. + config SND_HDA_CODEC_VIA bool "Build VIA HD-audio codec support" default y @@ -67,6 +82,11 @@ config SND_HDA_CODEC_VIA Say Y here to include VIA HD-audio codec support in snd-hda-intel driver, such as VT1708. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-via. + This module is automatically loaded at probing. + config SND_HDA_CODEC_ATIHDMI bool "Build ATI HDMI HD-audio codec support" default y @@ -74,6 +94,11 @@ config SND_HDA_CODEC_ATIHDMI Say Y here to include ATI HDMI HD-audio codec support in snd-hda-intel driver, such as ATI RS600 HDMI. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-atihdmi. + This module is automatically loaded at probing. + config SND_HDA_CODEC_NVHDMI bool "Build NVIDIA HDMI HD-audio codec support" default y @@ -81,6 +106,11 @@ config SND_HDA_CODEC_NVHDMI Say Y here to include NVIDIA HDMI HD-audio codec support in snd-hda-intel driver, such as NVIDIA MCP78 HDMI. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-nvhdmi. + This module is automatically loaded at probing. + config SND_HDA_CODEC_INTELHDMI bool "Build INTEL HDMI HD-audio codec support" default y @@ -88,6 +118,11 @@ config SND_HDA_CODEC_INTELHDMI Say Y here to include INTEL HDMI HD-audio codec support in snd-hda-intel driver, such as Eaglelake integrated HDMI. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-intelhdmi. + This module is automatically loaded at probing. + config SND_HDA_ELD def_bool y depends on SND_HDA_CODEC_INTELHDMI @@ -99,6 +134,11 @@ config SND_HDA_CODEC_CONEXANT Say Y here to include Conexant HD-audio codec support in snd-hda-intel driver, such as CX20549. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-conexant. + This module is automatically loaded at probing. + config SND_HDA_CODEC_CMEDIA bool "Build C-Media HD-audio codec support" default y @@ -106,6 +146,11 @@ config SND_HDA_CODEC_CMEDIA Say Y here to include C-Media HD-audio codec support in snd-hda-intel driver, such as CMI9880. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-cmedia. + This module is automatically loaded at probing. + config SND_HDA_CODEC_SI3054 bool "Build Silicon Labs 3054 HD-modem codec support" default y @@ -113,6 +158,11 @@ config SND_HDA_CODEC_SI3054 Say Y here to include Silicon Labs 3054 HD-modem codec (and compatibles) support in snd-hda-intel driver. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-si3054. + This module is automatically loaded at probing. + config SND_HDA_GENERIC bool "Enable generic HD-audio codec parser" default y diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 6daf5fd9a27..50f9d096725 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,22 +1,59 @@ -snd-hda-intel-y := hda_intel.o -# since snd-hda-intel is the only driver using hda-codec, -# merge it into a single module although it was originally -# designed to be individual modules -snd-hda-intel-y += hda_codec.o -snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o -snd-hda-intel-$(CONFIG_SND_HDA_ELD) += hda_eld.o -snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o -snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o -snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_REALTEK) += patch_realtek.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CMEDIA) += patch_cmedia.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ANALOG) += patch_analog.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += patch_sigmatel.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SI3054) += patch_si3054.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_INTELHDMI) += patch_intelhdmi.o +snd-hda-intel-objs := hda_intel.o +snd-hda-codec-y := hda_codec.o +snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o +snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o +# snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o +snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o +snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o + +snd-hda-codec-realtek-objs := patch_realtek.o +snd-hda-codec-cmedia-objs := patch_cmedia.o +snd-hda-codec-analog-objs := patch_analog.o +snd-hda-codec-idt-objs := patch_sigmatel.o +snd-hda-codec-si3054-objs := patch_si3054.o +snd-hda-codec-atihdmi-objs := patch_atihdmi.o +snd-hda-codec-conexant-objs := patch_conexant.o +snd-hda-codec-via-objs := patch_via.o +snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o +snd-hda-codec-intelhdmi-objs := patch_intelhdmi.o hda_eld.o + +# common driver +obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o + +# codec drivers (note: CONFIG_SND_HDA_CODEC_XXX are booleans) +ifdef CONFIG_SND_HDA_CODEC_REALTEK +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-realtek.o +endif +ifdef CONFIG_SND_HDA_CODEC_CMEDIA +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cmedia.o +endif +ifdef CONFIG_SND_HDA_CODEC_ANALOG +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-analog.o +endif +ifdef CONFIG_SND_HDA_CODEC_SIGMATEL +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-idt.o +endif +ifdef CONFIG_SND_HDA_CODEC_SI3054 +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o +endif +ifdef CONFIG_SND_HDA_CODEC_ATIHDMI +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o +endif +ifdef CONFIG_SND_HDA_CODEC_CONEXANT +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o +endif +ifdef CONFIG_SND_HDA_CODEC_VIA +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o +endif +ifdef CONFIG_SND_HDA_CODEC_NVHDMI +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-nvhdmi.o +endif +ifdef CONFIG_SND_HDA_CODEC_INTELHDMI +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-intelhdmi.o +endif + +# this must be the last entry after codec drivers; +# otherwise the codec patches won't be hooked before the PCI probe +# when built in kernel obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 3ecd7e797de..e6cc9463667 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -128,6 +128,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device); void snd_hda_detach_beep_device(struct hda_codec *codec) { @@ -140,3 +141,4 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) kfree(beep); } } +EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 1cb85b73e19..4aa7b1b7287 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -31,7 +31,6 @@ #include #include "hda_local.h" #include -#include "hda_patch.h" /* codec presets */ /* * vendor / preset table @@ -62,39 +61,26 @@ static struct hda_vendor_id hda_vendor_ids[] = { {} /* terminator */ }; -static const struct hda_codec_preset *hda_preset_tables[] = { -#ifdef CONFIG_SND_HDA_CODEC_REALTEK - snd_hda_preset_realtek, -#endif -#ifdef CONFIG_SND_HDA_CODEC_CMEDIA - snd_hda_preset_cmedia, -#endif -#ifdef CONFIG_SND_HDA_CODEC_ANALOG - snd_hda_preset_analog, -#endif -#ifdef CONFIG_SND_HDA_CODEC_SIGMATEL - snd_hda_preset_sigmatel, -#endif -#ifdef CONFIG_SND_HDA_CODEC_SI3054 - snd_hda_preset_si3054, -#endif -#ifdef CONFIG_SND_HDA_CODEC_ATIHDMI - snd_hda_preset_atihdmi, -#endif -#ifdef CONFIG_SND_HDA_CODEC_CONEXANT - snd_hda_preset_conexant, -#endif -#ifdef CONFIG_SND_HDA_CODEC_VIA - snd_hda_preset_via, -#endif -#ifdef CONFIG_SND_HDA_CODEC_NVHDMI - snd_hda_preset_nvhdmi, -#endif -#ifdef CONFIG_SND_HDA_CODEC_INTELHDMI - snd_hda_preset_intelhdmi, -#endif - NULL -}; +static DEFINE_MUTEX(preset_mutex); +static LIST_HEAD(hda_preset_tables); + +int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset) +{ + mutex_lock(&preset_mutex); + list_add_tail(&preset->list, &hda_preset_tables); + mutex_unlock(&preset_mutex); + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset); + +int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) +{ + mutex_lock(&preset_mutex); + list_del(&preset->list); + mutex_unlock(&preset_mutex); + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_delete_codec_preset); #ifdef CONFIG_SND_HDA_POWER_SAVE static void hda_power_work(struct work_struct *work); @@ -128,6 +114,7 @@ const char *snd_hda_get_jack_location(u32 cfg) } return "UNKNOWN"; } +EXPORT_SYMBOL_GPL(snd_hda_get_jack_location); const char *snd_hda_get_jack_connectivity(u32 cfg) { @@ -135,6 +122,7 @@ const char *snd_hda_get_jack_connectivity(u32 cfg) return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; } +EXPORT_SYMBOL_GPL(snd_hda_get_jack_connectivity); const char *snd_hda_get_jack_type(u32 cfg) { @@ -148,6 +136,7 @@ const char *snd_hda_get_jack_type(u32 cfg) return jack_types[(cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT]; } +EXPORT_SYMBOL_GPL(snd_hda_get_jack_type); /* * Compose a 32bit command word to be sent to the HD-audio controller @@ -196,6 +185,7 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, snd_hda_power_down(codec); return res; } +EXPORT_SYMBOL_GPL(snd_hda_codec_read); /** * snd_hda_codec_write - send a single command without waiting for response @@ -224,6 +214,7 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, snd_hda_power_down(codec); return err; } +EXPORT_SYMBOL_GPL(snd_hda_codec_write); /** * snd_hda_sequence_write - sequence writes @@ -238,6 +229,7 @@ void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq) for (; seq->nid; seq++) snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param); } +EXPORT_SYMBOL_GPL(snd_hda_sequence_write); /** * snd_hda_get_sub_nodes - get the range of sub nodes @@ -259,6 +251,7 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, *start_id = (parm >> 16) & 0x7fff; return (int)(parm & 0x7fff); } +EXPORT_SYMBOL_GPL(snd_hda_get_sub_nodes); /** * snd_hda_get_connections - get connection list @@ -347,6 +340,7 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, } return conns; } +EXPORT_SYMBOL_GPL(snd_hda_get_connections); /** @@ -381,6 +375,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) return 0; } +EXPORT_SYMBOL_GPL(snd_hda_queue_unsol_event); /* * process queued unsolicited events @@ -482,7 +477,7 @@ static int snd_hda_bus_dev_register(struct snd_device *device) * * Returns 0 if successful, or a negative error code. */ -int __devinit snd_hda_bus_new(struct snd_card *card, +int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, struct hda_bus **busp) { @@ -526,6 +521,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, *busp = bus; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_bus_new); #ifdef CONFIG_SND_HDA_GENERIC #define is_generic_config(codec) \ @@ -534,19 +530,33 @@ int __devinit snd_hda_bus_new(struct snd_card *card, #define is_generic_config(codec) 0 #endif +#ifdef CONFIG_SND_HDA_INTEL_MODULE +#define HDA_MODREQ_MAX_COUNT 2 /* two request_modules()'s */ +#else +#define HDA_MODREQ_MAX_COUNT 0 +#endif + /* * find a matching codec preset */ static const struct hda_codec_preset * find_codec_preset(struct hda_codec *codec) { - const struct hda_codec_preset **tbl, *preset; + struct hda_codec_preset_list *tbl; + const struct hda_codec_preset *preset; + int mod_requested = 0; if (is_generic_config(codec)) return NULL; /* use the generic parser */ - for (tbl = hda_preset_tables; *tbl; tbl++) { - for (preset = *tbl; preset->id; preset++) { + again: + mutex_lock(&preset_mutex); + list_for_each_entry(tbl, &hda_preset_tables, list) { + if (!try_module_get(tbl->owner)) { + snd_printk(KERN_ERR "hda_codec: cannot module_get\n"); + continue; + } + for (preset = tbl->preset; preset->id; preset++) { u32 mask = preset->mask; if (preset->afg && preset->afg != codec->afg) continue; @@ -556,9 +566,27 @@ find_codec_preset(struct hda_codec *codec) mask = ~0; if (preset->id == (codec->vendor_id & mask) && (!preset->rev || - preset->rev == codec->revision_id)) + preset->rev == codec->revision_id)) { + mutex_unlock(&preset_mutex); + codec->owner = tbl->owner; return preset; + } } + module_put(tbl->owner); + } + mutex_unlock(&preset_mutex); + + if (mod_requested < HDA_MODREQ_MAX_COUNT) { + char name[32]; + if (!mod_requested) + snprintf(name, sizeof(name), "snd-hda-codec-id:%08x", + codec->vendor_id); + else + snprintf(name, sizeof(name), "snd-hda-codec-id:%04x*", + (codec->vendor_id >> 16) & 0xffff); + request_module(name); + mod_requested++; + goto again; } return NULL; } @@ -598,7 +626,7 @@ static int get_codec_name(struct hda_codec *codec) /* * look for an AFG and MFG nodes */ -static void __devinit setup_fg_nodes(struct hda_codec *codec) +static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec) { int i, total_nodes; hda_nid_t nid; @@ -661,6 +689,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); + module_put(codec->owner); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); kfree(codec->name); @@ -677,7 +706,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) * * Returns 0 if successful, or a negative error code. */ -int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, +int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, struct hda_codec **codecp) { struct hda_codec *codec; @@ -779,6 +808,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, *codecp = codec; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_codec_new); int snd_hda_codec_configure(struct hda_codec *codec) { @@ -838,6 +868,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, msleep(1); snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format); } +EXPORT_SYMBOL_GPL(snd_hda_codec_setup_stream); void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) { @@ -851,6 +882,7 @@ void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); #endif } +EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup_stream); /* * amp access functions @@ -862,7 +894,7 @@ void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) /* initialize the hash table */ -static void __devinit init_hda_cache(struct hda_cache_rec *cache, +static void /*__devinit*/ init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size) { memset(cache, 0, sizeof(*cache)); @@ -932,6 +964,7 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) } return info->amp_caps; } +EXPORT_SYMBOL_GPL(query_amp_caps); int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps) @@ -945,6 +978,7 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, info->head.val |= INFO_AMP_CAPS; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps); /* * read the current volume to info @@ -998,6 +1032,7 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, return 0; return get_vol_mute(codec, info, nid, ch, direction, index); } +EXPORT_SYMBOL_GPL(snd_hda_codec_amp_read); /* * update the AMP value, mask = bit mask to set, val = the value @@ -1017,6 +1052,7 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, put_vol_mute(codec, info, nid, ch, direction, idx, val); return 1; } +EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update); /* * update the AMP stereo with the same mask and value @@ -1030,6 +1066,7 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, idx, mask, val); return ret; } +EXPORT_SYMBOL_GPL(snd_hda_codec_amp_stereo); #ifdef SND_HDA_NEEDS_RESUME /* resume the all amp commands from the cache */ @@ -1055,6 +1092,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) } } } +EXPORT_SYMBOL_GPL(snd_hda_codec_resume_amp); #endif /* SND_HDA_NEEDS_RESUME */ /* volume */ @@ -1082,6 +1120,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.max = caps; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_info); int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1101,6 +1140,7 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, & HDA_AMP_VOLMASK; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_get); int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1125,6 +1165,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, snd_hda_power_down(codec); return change; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put); int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *_tlv) @@ -1151,6 +1192,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, return -EFAULT; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_tlv); /* * set (static) TLV for virtual master volume; recalculated as max 0dB @@ -1170,6 +1212,7 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, tlv[2] = -nums * step; tlv[3] = step; } +EXPORT_SYMBOL_GPL(snd_hda_set_vmaster_tlv); /* find a mixer control element with the given name */ static struct snd_kcontrol * @@ -1189,6 +1232,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, { return _snd_hda_find_mixer_ctl(codec, name, 0); } +EXPORT_SYMBOL_GPL(snd_hda_find_mixer_ctl); /* Add a control element and assign to the codec */ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) @@ -1205,6 +1249,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) *knewp = kctl; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_ctl_add); #ifdef CONFIG_SND_HDA_RECONFIG /* Clear all controls assigned to the given codec */ @@ -1243,6 +1288,8 @@ void snd_hda_codec_reset(struct hda_codec *codec) codec->num_pcms = 0; codec->pcm_info = NULL; codec->preset = NULL; + module_put(codec->owner); + codec->owner = NULL; } #endif /* CONFIG_SND_HDA_RECONFIG */ @@ -1281,6 +1328,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_add_vmaster); /* switch */ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, @@ -1294,6 +1342,7 @@ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.max = 1; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_info); int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1313,6 +1362,7 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, HDA_AMP_MUTE) ? 0 : 1; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get); int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1343,6 +1393,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, snd_hda_power_down(codec); return change; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put); /* * bound volume controls @@ -1368,6 +1419,7 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_get); int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1391,6 +1443,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err < 0 ? err : change; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_put); /* * generic bound volume/swtich controls @@ -1410,6 +1463,7 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_info); int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1426,6 +1480,7 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_get); int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1448,6 +1503,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err < 0 ? err : change; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_put); int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv) @@ -1464,6 +1520,7 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, mutex_unlock(&codec->spdif_mutex); return err; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_tlv); struct hda_ctl_ops snd_hda_bind_vol = { .info = snd_hda_mixer_amp_volume_info, @@ -1471,6 +1528,7 @@ struct hda_ctl_ops snd_hda_bind_vol = { .put = snd_hda_mixer_amp_volume_put, .tlv = snd_hda_mixer_amp_tlv }; +EXPORT_SYMBOL_GPL(snd_hda_bind_vol); struct hda_ctl_ops snd_hda_bind_sw = { .info = snd_hda_mixer_amp_switch_info, @@ -1478,6 +1536,7 @@ struct hda_ctl_ops snd_hda_bind_sw = { .put = snd_hda_mixer_amp_switch_put, .tlv = snd_hda_mixer_amp_tlv }; +EXPORT_SYMBOL_GPL(snd_hda_bind_sw); /* * SPDIF out controls @@ -1739,6 +1798,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_create_spdif_out_ctls); /* * SPDIF sharing with analog output @@ -1776,6 +1836,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec, return snd_hda_ctl_add(codec, snd_ctl_new1(&spdif_share_sw, mout)); } +EXPORT_SYMBOL_GPL(snd_hda_create_spdif_share_sw); /* * SPDIF input @@ -1885,6 +1946,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) AC_DIG1_ENABLE; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_create_spdif_in_ctls); #ifdef SND_HDA_NEEDS_RESUME /* @@ -1930,6 +1992,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, snd_hda_power_down(codec); return err; } +EXPORT_SYMBOL_GPL(snd_hda_codec_write_cache); /* resume the all commands from the cache */ void snd_hda_codec_resume_cache(struct hda_codec *codec) @@ -1945,6 +2008,7 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec) get_cmd_cache_cmd(key), buffer->val); } } +EXPORT_SYMBOL_GPL(snd_hda_codec_resume_cache); /** * snd_hda_sequence_write_cache - sequence writes with caching @@ -1962,6 +2026,7 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, seq->param); } +EXPORT_SYMBOL_GPL(snd_hda_sequence_write_cache); #endif /* SND_HDA_NEEDS_RESUME */ /* @@ -2080,7 +2145,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) * * Returns 0 if successful, otherwise a negative error code. */ -int __devinit snd_hda_build_controls(struct hda_bus *bus) +int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus) { struct hda_codec *codec; @@ -2091,6 +2156,7 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_build_controls); int snd_hda_codec_build_controls(struct hda_codec *codec) { @@ -2202,6 +2268,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, return val; } +EXPORT_SYMBOL_GPL(snd_hda_calc_stream_format); /** * snd_hda_query_supported_pcm - query the supported PCM rates and formats @@ -2381,6 +2448,7 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, return 1; } +EXPORT_SYMBOL_GPL(snd_hda_is_supported_format); /* * PCM stuff @@ -2578,6 +2646,7 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_build_pcms); /** * snd_hda_check_board_config - compare the current codec with the config table @@ -2633,6 +2702,7 @@ int snd_hda_check_board_config(struct hda_codec *codec, } return -1; } +EXPORT_SYMBOL_GPL(snd_hda_check_board_config); /** * snd_hda_add_new_ctls - create controls from the array @@ -2668,6 +2738,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls); #ifdef CONFIG_SND_HDA_POWER_SAVE static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, @@ -2710,6 +2781,10 @@ void snd_hda_power_up(struct hda_codec *codec) cancel_delayed_work(&codec->power_work); codec->power_transition = 0; } +EXPORT_SYMBOL_GPL(snd_hda_power_up); + +#define power_save(codec) \ + ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) #define power_save(codec) \ ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) @@ -2725,6 +2800,7 @@ void snd_hda_power_down(struct hda_codec *codec) msecs_to_jiffies(power_save(codec) * 1000)); } } +EXPORT_SYMBOL_GPL(snd_hda_power_down); int snd_hda_check_amp_list_power(struct hda_codec *codec, struct hda_loopback_check *check, @@ -2761,6 +2837,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power); #endif /* @@ -2780,6 +2857,7 @@ int snd_hda_ch_mode_info(struct hda_codec *codec, chmode[uinfo->value.enumerated.item].channels); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info); int snd_hda_ch_mode_get(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, @@ -2797,6 +2875,7 @@ int snd_hda_ch_mode_get(struct hda_codec *codec, } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get); int snd_hda_ch_mode_put(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, @@ -2817,6 +2896,7 @@ int snd_hda_ch_mode_put(struct hda_codec *codec, snd_hda_sequence_write_cache(codec, chmode[mode].sequence); return 1; } +EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put); /* * input MUX helper @@ -2837,6 +2917,7 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux, strcpy(uinfo->value.enumerated.name, imux->items[index].label); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_input_mux_info); int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, @@ -2858,6 +2939,7 @@ int snd_hda_input_mux_put(struct hda_codec *codec, *cur_val = idx; return 1; } +EXPORT_SYMBOL_GPL(snd_hda_input_mux_put); /* @@ -2910,6 +2992,7 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_open); int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, struct hda_multi_out *mout, @@ -2922,6 +3005,7 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare); /* * release the digital out @@ -2934,6 +3018,7 @@ int snd_hda_multi_out_dig_close(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_close); /* * set up more restrictions for analog out @@ -2973,6 +3058,7 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec, return snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); } +EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_open); /* * set up the i/o for analog out @@ -3031,6 +3117,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_prepare); /* * clean up the setting for analog out @@ -3057,6 +3144,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_cleanup); /* * Helper for automatic pin configuration @@ -3342,11 +3430,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, return 0; } +EXPORT_SYMBOL_GPL(snd_hda_parse_pin_def_config); /* labels for input pins */ const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = { "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" }; +EXPORT_SYMBOL_GPL(auto_pin_cfg_labels); #ifdef CONFIG_PM @@ -3374,6 +3464,7 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_suspend); /** * snd_hda_resume - resume the codecs @@ -3394,7 +3485,8 @@ int snd_hda_resume(struct hda_bus *bus) } return 0; } -#endif +EXPORT_SYMBOL_GPL(snd_hda_resume); +#endif /* CONFIG_PM */ /* * generic arrays @@ -3423,6 +3515,7 @@ void *snd_array_new(struct snd_array *array) } return snd_array_elem(array, array->used++); } +EXPORT_SYMBOL_GPL(snd_array_new); /* free the given array elements */ void snd_array_free(struct snd_array *array) @@ -3432,6 +3525,7 @@ void snd_array_free(struct snd_array *array) array->alloced = 0; array->list = NULL; } +EXPORT_SYMBOL_GPL(snd_array_free); /* * used by hda_proc.c and hda_eld.c @@ -3450,6 +3544,7 @@ void snd_print_pcm_rates(int pcm, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } +EXPORT_SYMBOL_GPL(snd_print_pcm_rates); void snd_print_pcm_bits(int pcm, char *buf, int buflen) { @@ -3462,3 +3557,7 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } +EXPORT_SYMBOL_GPL(snd_print_pcm_bits); + +MODULE_DESCRIPTION("HDA codec core"); +MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 9fe0b67bb1e..586ea08b340 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -642,6 +642,16 @@ struct hda_codec_preset { int (*patch)(struct hda_codec *codec); }; +struct hda_codec_preset_list { + const struct hda_codec_preset *preset; + struct module *owner; + struct list_head list; +}; + +/* initial hook */ +int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset); +int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset); + /* ops set by the preset patch */ struct hda_codec_ops { int (*build_controls)(struct hda_codec *codec); @@ -735,6 +745,7 @@ struct hda_codec { /* detected preset */ const struct hda_codec_preset *preset; + struct module *owner; const char *name; /* codec name */ const char *modelname; /* model name for preset */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 98ff010d5b9..65745e96dc7 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -1101,3 +1101,4 @@ int snd_hda_parse_generic_codec(struct hda_codec *codec) snd_hda_generic_free(codec); return err; } +EXPORT_SYMBOL(snd_hda_parse_generic_codec); diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 173af489322..300ab407cf4 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -116,7 +116,7 @@ static void hwdep_free(struct snd_hwdep *hwdep) clear_hwdep_elements(hwdep->private_data); } -int __devinit snd_hda_create_hwdep(struct hda_codec *codec) +int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) { char hwname[16]; struct snd_hwdep *hwdep; diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h deleted file mode 100644 index 38212c1020a..00000000000 --- a/sound/pci/hda/hda_patch.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * HDA Patches - included by hda_codec.c - */ - -/* Realtek codecs */ -extern struct hda_codec_preset snd_hda_preset_realtek[]; -/* C-Media codecs */ -extern struct hda_codec_preset snd_hda_preset_cmedia[]; -/* Analog Devices codecs */ -extern struct hda_codec_preset snd_hda_preset_analog[]; -/* SigmaTel codecs */ -extern struct hda_codec_preset snd_hda_preset_sigmatel[]; -/* SiLabs 3054/3055 modem codecs */ -extern struct hda_codec_preset snd_hda_preset_si3054[]; -/* ATI HDMI codecs */ -extern struct hda_codec_preset snd_hda_preset_atihdmi[]; -/* Conexant audio codec */ -extern struct hda_codec_preset snd_hda_preset_conexant[]; -/* VIA codecs */ -extern struct hda_codec_preset snd_hda_preset_via[]; -/* NVIDIA HDMI codecs */ -extern struct hda_codec_preset snd_hda_preset_nvhdmi[]; -/* INTEL HDMI codecs */ -extern struct hda_codec_preset snd_hda_preset_intelhdmi[]; diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 0cc6be12b8b..c1918a1a6df 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -27,7 +27,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" struct ad198x_spec { struct snd_kcontrol_new *mixers[5]; @@ -4308,7 +4307,7 @@ static int patch_ad1882(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_analog[] = { +static struct hda_codec_preset snd_hda_preset_analog[] = { { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a }, { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a }, @@ -4326,3 +4325,26 @@ struct hda_codec_preset snd_hda_preset_analog[] = { { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:11d4*"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Analog Devices HD-audio codec"); + +static struct hda_codec_preset_list analog_list = { + .preset = snd_hda_preset_analog, + .owner = THIS_MODULE, +}; + +static int __init patch_analog_init(void) +{ + return snd_hda_add_codec_preset(&analog_list); +} + +static void __exit patch_analog_exit(void) +{ + snd_hda_delete_codec_preset(&analog_list); +} + +module_init(patch_analog_init) +module_exit(patch_analog_exit) diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index 5603a1acddb..5887b827bb3 100644 --- a/sound/pci/hda/patch_atihdmi.c +++ b/sound/pci/hda/patch_atihdmi.c @@ -27,7 +27,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" struct atihdmi_spec { struct hda_multi_out multiout; @@ -187,7 +186,7 @@ static int patch_atihdmi(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_atihdmi[] = { +static struct hda_codec_preset snd_hda_preset_atihdmi[] = { { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi }, @@ -196,3 +195,31 @@ struct hda_codec_preset snd_hda_preset_atihdmi[] = { { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:1002793c"); +MODULE_ALIAS("snd-hda-codec-id:10027919"); +MODULE_ALIAS("snd-hda-codec-id:1002791a"); +MODULE_ALIAS("snd-hda-codec-id:1002aa01"); +MODULE_ALIAS("snd-hda-codec-id:10951390"); +MODULE_ALIAS("snd-hda-codec-id:17e80047"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ATI HDMI HD-audio codec"); + +static struct hda_codec_preset_list atihdmi_list = { + .preset = snd_hda_preset_atihdmi, + .owner = THIS_MODULE, +}; + +static int __init patch_atihdmi_init(void) +{ + return snd_hda_add_codec_preset(&atihdmi_list); +} + +static void __exit patch_atihdmi_exit(void) +{ + snd_hda_delete_codec_preset(&atihdmi_list); +} + +module_init(patch_atihdmi_init) +module_exit(patch_atihdmi_exit) diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 6ef57fbfb6e..f3ebe837f2d 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -28,7 +28,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" #define NUM_PINS 11 @@ -736,8 +735,32 @@ static int patch_cmi9880(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_cmedia[] = { +static struct hda_codec_preset snd_hda_preset_cmedia[] = { { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 }, { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:13f69880"); +MODULE_ALIAS("snd-hda-codec-id:434d4980"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("C-Media HD-audio codec"); + +static struct hda_codec_preset_list cmedia_list = { + .preset = snd_hda_preset_cmedia, + .owner = THIS_MODULE, +}; + +static int __init patch_cmedia_init(void) +{ + return snd_hda_add_codec_preset(&cmedia_list); +} + +static void __exit patch_cmedia_exit(void) +{ + snd_hda_delete_codec_preset(&cmedia_list); +} + +module_init(patch_cmedia_init) +module_exit(patch_cmedia_exit) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 07601070815..b20e1cede00 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -27,7 +27,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" #define CXT_PIN_DIR_IN 0x00 #define CXT_PIN_DIR_OUT 0x01 @@ -1771,7 +1770,7 @@ static int patch_cxt5051(struct hda_codec *codec) /* */ -struct hda_codec_preset snd_hda_preset_conexant[] = { +static struct hda_codec_preset snd_hda_preset_conexant[] = { { .id = 0x14f15045, .name = "CX20549 (Venice)", .patch = patch_cxt5045 }, { .id = 0x14f15047, .name = "CX20551 (Waikiki)", @@ -1780,3 +1779,28 @@ struct hda_codec_preset snd_hda_preset_conexant[] = { .patch = patch_cxt5051 }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:14f15045"); +MODULE_ALIAS("snd-hda-codec-id:14f15047"); +MODULE_ALIAS("snd-hda-codec-id:14f15051"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Conexant HD-audio codec"); + +static struct hda_codec_preset_list conexant_list = { + .preset = snd_hda_preset_conexant, + .owner = THIS_MODULE, +}; + +static int __init patch_conexant_init(void) +{ + return snd_hda_add_codec_preset(&conexant_list); +} + +static void __exit patch_conexant_exit(void) +{ + snd_hda_delete_codec_preset(&conexant_list); +} + +module_init(patch_conexant_init) +module_exit(patch_conexant_exit) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index fe08bef897c..290da562f29 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -32,7 +32,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" #define CVT_NID 0x02 /* audio converter */ #define PIN_NID 0x03 /* HDMI output pin */ @@ -675,7 +674,7 @@ static int patch_intel_hdmi(struct hda_codec *codec) return 0; } -struct hda_codec_preset snd_hda_preset_intelhdmi[] = { +static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { { .id = 0x808629fb, .name = "INTEL G45 DEVCL", .patch = patch_intel_hdmi }, { .id = 0x80862801, .name = "INTEL G45 DEVBLC", .patch = patch_intel_hdmi }, { .id = 0x80862802, .name = "INTEL G45 DEVCTG", .patch = patch_intel_hdmi }, @@ -683,3 +682,30 @@ struct hda_codec_preset snd_hda_preset_intelhdmi[] = { { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:808629fb"); +MODULE_ALIAS("snd-hda-codec-id:80862801"); +MODULE_ALIAS("snd-hda-codec-id:80862802"); +MODULE_ALIAS("snd-hda-codec-id:80862803"); +MODULE_ALIAS("snd-hda-codec-id:10951392"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Intel HDMI HD-audio codec"); + +static struct hda_codec_preset_list intel_list = { + .preset = snd_hda_preset_intelhdmi, + .owner = THIS_MODULE, +}; + +static int __init patch_intelhdmi_init(void) +{ + return snd_hda_add_codec_preset(&intel_list); +} + +static void __exit patch_intelhdmi_exit(void) +{ + snd_hda_delete_codec_preset(&intel_list); +} + +module_init(patch_intelhdmi_init) +module_exit(patch_intelhdmi_exit) diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 1360d54a7d0..e23de5594b6 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -28,7 +28,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" struct nvhdmi_spec { struct hda_multi_out multiout; @@ -159,8 +158,32 @@ static int patch_nvhdmi(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_nvhdmi[] = { +static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { { .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi }, { .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:10de0002"); +MODULE_ALIAS("snd-hda-codec-id:10de0007"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec"); + +static struct hda_codec_preset_list nvhdmi_list = { + .preset = snd_hda_preset_nvhdmi, + .owner = THIS_MODULE, +}; + +static int __init patch_nvhdmi_init(void) +{ + return snd_hda_add_codec_preset(&nvhdmi_list); +} + +static void __exit patch_nvhdmi_exit(void) +{ + snd_hda_delete_codec_preset(&nvhdmi_list); +} + +module_init(patch_nvhdmi_init) +module_exit(patch_nvhdmi_exit) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9cd2545d988..ba640d36d64 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -30,7 +30,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" #define ALC880_FRONT_EVENT 0x01 #define ALC880_DCVOL_EVENT 0x02 @@ -16579,7 +16578,7 @@ static int patch_alc662(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_realtek[] = { +static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 }, @@ -16611,3 +16610,26 @@ struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:10ec*"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek HD-audio codec"); + +static struct hda_codec_preset_list realtek_list = { + .preset = snd_hda_preset_realtek, + .owner = THIS_MODULE, +}; + +static int __init patch_realtek_init(void) +{ + return snd_hda_add_codec_preset(&realtek_list); +} + +static void __exit patch_realtek_exit(void) +{ + snd_hda_delete_codec_preset(&realtek_list); +} + +module_init(patch_realtek_init) +module_exit(patch_realtek_exit) diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 9332b63e406..43b436c5d01 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -28,7 +28,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" /* si3054 verbs */ #define SI3054_VERB_READ_NODE 0x900 @@ -283,7 +282,7 @@ static int patch_si3054(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_si3054[] = { +static struct hda_codec_preset snd_hda_preset_si3054[] = { { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, @@ -301,3 +300,35 @@ struct hda_codec_preset snd_hda_preset_si3054[] = { {} }; +MODULE_ALIAS("snd-hda-codec-id:163c3055"); +MODULE_ALIAS("snd-hda-codec-id:163c3155"); +MODULE_ALIAS("snd-hda-codec-id:11c13026"); +MODULE_ALIAS("snd-hda-codec-id:11c13055"); +MODULE_ALIAS("snd-hda-codec-id:11c13155"); +MODULE_ALIAS("snd-hda-codec-id:10573055"); +MODULE_ALIAS("snd-hda-codec-id:10573057"); +MODULE_ALIAS("snd-hda-codec-id:10573155"); +MODULE_ALIAS("snd-hda-codec-id:11063288"); +MODULE_ALIAS("snd-hda-codec-id:15433155"); +MODULE_ALIAS("snd-hda-codec-id:18540018"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Si3054 HD-audio modem codec"); + +static struct hda_codec_preset_list si3054_list = { + .preset = snd_hda_preset_si3054, + .owner = THIS_MODULE, +}; + +static int __init patch_si3054_init(void) +{ + return snd_hda_add_codec_preset(&si3054_list); +} + +static void __exit patch_si3054_exit(void) +{ + snd_hda_delete_codec_preset(&si3054_list); +} + +module_init(patch_si3054_init) +module_exit(patch_si3054_exit) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 70181d50053..9e07f44ab28 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -33,7 +33,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" #include "hda_beep.h" enum { @@ -5455,7 +5454,7 @@ static int patch_stac9872(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_sigmatel[] = { +static struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 }, { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x }, { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x }, @@ -5519,3 +5518,27 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:8384*"); +MODULE_ALIAS("snd-hda-codec-id:111d*"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec"); + +static struct hda_codec_preset_list sigmatel_list = { + .preset = snd_hda_preset_sigmatel, + .owner = THIS_MODULE, +}; + +static int __init patch_sigmatel_init(void) +{ + return snd_hda_add_codec_preset(&sigmatel_list); +} + +static void __exit patch_sigmatel_exit(void) +{ + snd_hda_delete_codec_preset(&sigmatel_list); +} + +module_init(patch_sigmatel_init) +module_exit(patch_sigmatel_exit) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 05182be1c9f..6e4d01d1d50 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -47,7 +47,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" /* amp values */ #define AMP_VAL_IDX_SHIFT 19 @@ -3249,7 +3248,7 @@ static int patch_vt1702(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_via[] = { +static struct hda_codec_preset snd_hda_preset_via[] = { { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708}, { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708}, { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708}, @@ -3320,3 +3319,26 @@ struct hda_codec_preset snd_hda_preset_via[] = { .patch = patch_vt1702}, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:1106*"); + +static struct hda_codec_preset_list via_list = { + .preset = snd_hda_preset_via, + .owner = THIS_MODULE, +}; + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("VIA HD-audio codec"); + +static int __init patch_via_init(void) +{ + return snd_hda_add_codec_preset(&via_list); +} + +static void __exit patch_via_exit(void) +{ + snd_hda_delete_codec_preset(&via_list); +} + +module_init(patch_via_init) +module_exit(patch_via_exit) -- cgit v1.2.3 From 11cd41b893895c76a8f9bee9467f4b0869b5eeb3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 07:22:18 +0100 Subject: ALSA: hda - Fix build error with CONFIG_SND_HDA_POWER_SAVE Moved power_save field initialization inside a proper ifdef to fix a build error without CONFIG_SND_HDA_POWER_SAVE. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f17ccd51335..8aee322313e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1233,12 +1233,12 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, memset(&bus_temp, 0, sizeof(bus_temp)); bus_temp.private_data = chip; bus_temp.modelname = model; - bus_temp.power_save = &power_save; 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.power_save = &power_save; bus_temp.ops.pm_notify = azx_power_notify; #endif -- cgit v1.2.3 From daead538e9d8efe61d7d2bd12993c8d961b0abd6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 12:55:36 +0100 Subject: ALSA: hda - Add codec-specific proc hook Added a hook for proc outputs of codec-specific stuff. Moved realtek-specific coeff output into patch_realtek.c as well. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 4 ++++ sound/pci/hda/hda_proc.c | 16 ++-------------- sound/pci/hda/patch_realtek.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 9fe0b67bb1e..43af18c4a21 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -784,6 +784,10 @@ struct hda_codec { int power_count; /* current (global) power refcount */ struct delayed_work power_work; /* delayed task for powerdown */ #endif + + /* codec-specific additional proc output */ + void (*proc_widget_hook)(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid); }; /* direction */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 9a8498456e6..7b3817985c3 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -414,17 +414,6 @@ static void print_conn_list(struct snd_info_buffer *buffer, } } -static void print_realtek_coef(struct snd_info_buffer *buffer, - struct hda_codec *codec, hda_nid_t nid) -{ - int coeff = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PROC_COEF, 0); - snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff); - coeff = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_COEF_INDEX, 0); - snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff); -} - static void print_gpio(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) { @@ -606,9 +595,8 @@ static void print_codec_info(struct snd_info_entry *entry, if (wid_caps & AC_WCAP_PROC_WID) print_proc_caps(buffer, codec, nid); - /* NID 0x20 == Realtek Define Registers */ - if (codec->vendor_id == 0x10ec && nid == 0x20) - print_realtek_coef(buffer, codec, nid); + if (codec->proc_widget_hook) + codec->proc_widget_hook(buffer, codec, nid); } snd_hda_power_down(codec); } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9cd2545d988..698c85625a4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -766,6 +766,27 @@ static void add_verb(struct alc_spec *spec, const struct hda_verb *verb) spec->init_verbs[spec->num_init_verbs++] = verb; } +#ifdef CONFIG_PROC_FS +/* + * hook for proc + */ +static void print_realtek_coef(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + int coeff; + + if (nid != 0x20) + return; + coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0); + snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff); + coeff = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_COEF_INDEX, 0); + snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff); +} +#else +#define print_realtek_coef NULL +#endif + /* * set up from the preset table */ @@ -4344,6 +4365,7 @@ static int patch_alc880(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc880_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -5869,6 +5891,7 @@ static int patch_alc260(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc260_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -7074,6 +7097,7 @@ static int patch_alc882(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc882_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -9042,6 +9066,7 @@ static int patch_alc883(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc883_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -10848,6 +10873,7 @@ static int patch_alc262(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc262_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -11913,6 +11939,8 @@ static int patch_alc268(struct hda_codec *codec) if (board_config == ALC268_AUTO) spec->init_hook = alc268_auto_init; + codec->proc_widget_hook = print_realtek_coef; + return 0; } @@ -12714,6 +12742,7 @@ static int patch_alc269(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc269_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -13802,6 +13831,7 @@ static int patch_alc861(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc861_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -14763,6 +14793,7 @@ static int patch_alc861vd(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc861vd_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -16572,6 +16603,7 @@ static int patch_alc662(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc662_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } -- cgit v1.2.3 From bb40abe223ace0b6f29e8433d3936dac664178b5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 12:57:38 +0100 Subject: ALSA: hda - Remove unused proc entry in hda_bus struct Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 43af18c4a21..bbbc83b387d 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -615,8 +615,6 @@ struct hda_bus { /* unsolicited event queue */ struct hda_bus_unsolicited *unsol; - struct snd_info_entry *proc; - /* assigned PCMs */ DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES); -- cgit v1.2.3 From 2d34e1b3bb991a99322fb55681d1e73ada3de35c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 14:35:16 +0100 Subject: ALSA: hda - Add IDT/STAC-specific proc output Added power-map and analog-loopback information to proc output for IDT/STAC codecs. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_proc.c | 2 ++ sound/pci/hda/patch_sigmatel.c | 56 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 7b3817985c3..7ca66d65414 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -493,6 +493,8 @@ static void print_codec_info(struct snd_info_entry *entry, } print_gpio(buffer, codec, codec->afg); + if (codec->proc_widget_hook) + codec->proc_widget_hook(buffer, codec, codec->afg); for (i = 0; i < nodes; i++, nid++) { unsigned int wid_caps = diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 70181d50053..33170a24200 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4262,6 +4262,52 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) } } +#ifdef CONFIG_PROC_FS +static void stac92hd_proc_hook(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + if (nid == codec->afg) + snd_iprintf(buffer, "Power-Map: 0x%02x\n", + snd_hda_codec_read(codec, nid, 0, 0x0fec, 0x0)); +} + +static void analog_loop_proc_hook(struct snd_info_buffer *buffer, + struct hda_codec *codec, + unsigned int verb) +{ + snd_iprintf(buffer, "Analog Loopback: 0x%02x\n", + snd_hda_codec_read(codec, codec->afg, 0, verb, 0)); +} + +/* stac92hd71bxx, stac92hd73xx */ +static void stac92hd7x_proc_hook(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + stac92hd_proc_hook(buffer, codec, nid); + if (nid == codec->afg) + analog_loop_proc_hook(buffer, codec, 0xfa0); +} + +static void stac9205_proc_hook(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + if (nid == codec->afg) + analog_loop_proc_hook(buffer, codec, 0xfe0); +} + +static void stac927x_proc_hook(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + if (nid == codec->afg) + analog_loop_proc_hook(buffer, codec, 0xfeb); +} +#else +#define stac92hd_proc_hook NULL +#define stac92hd7x_proc_hook NULL +#define stac9205_proc_hook NULL +#define stac927x_proc_hook NULL +#endif + #ifdef SND_HDA_NEEDS_RESUME static int stac92xx_resume(struct hda_codec *codec) { @@ -4585,6 +4631,8 @@ again: codec->patch_ops = stac92xx_patch_ops; + codec->proc_widget_hook = stac92hd7x_proc_hook; + return 0; } @@ -4671,6 +4719,8 @@ again: codec->patch_ops = stac92xx_patch_ops; + codec->proc_widget_hook = stac92hd_proc_hook; + return 0; } @@ -4889,6 +4939,8 @@ again: return err; } + codec->proc_widget_hook = stac92hd7x_proc_hook; + return 0; }; @@ -5109,6 +5161,8 @@ static int patch_stac927x(struct hda_codec *codec) codec->patch_ops = stac92xx_patch_ops; + codec->proc_widget_hook = stac927x_proc_hook; + /* * !!FIXME!! * The STAC927x seem to require fairly long delays for certain @@ -5224,6 +5278,8 @@ static int patch_stac9205(struct hda_codec *codec) codec->patch_ops = stac92xx_patch_ops; + codec->proc_widget_hook = stac9205_proc_hook; + return 0; } -- cgit v1.2.3 From 56d17712d54d3aa3d6ef930123d692351d33217c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 14:36:23 +0100 Subject: ALSA: hda - Clear codec->proc_widget_hook at reset Clear the remaining pointer at snd_hda_codec_reset() to avoid Oops. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 1cb85b73e19..a867e1e8658 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1237,6 +1237,7 @@ void snd_hda_codec_reset(struct hda_codec *codec) } if (codec->patch_ops.free) codec->patch_ops.free(codec); + codec->proc_widget_hook = NULL; codec->spec = NULL; free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); -- cgit v1.2.3 From 57a5ef483b6290a9f22d4c52baca051c1e755f3a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 14:46:28 +0100 Subject: ALSA: hda - Add quirk for Sony VAIO VGN-SR19XN Added model=sony-assamd for Sony VAIO VGN-SR19XN with ALC262 codec. Reference: Novell bnc#450080 https://bugzilla.novell.com/show_bug.cgi?id=450080 Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 698c85625a4..40b3fcd142a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10559,6 +10559,8 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), + SND_PCI_QUIRK(0x104d, 0x9033, "Sony VAIO VGN-SR19XN", + ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", ALC262_TOSHIBA_RX1), SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06), -- cgit v1.2.3 From 645f10c1ac7f733b224eaf97634edf9b20e2370e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 15:07:37 +0100 Subject: ALSA: hda - Check MODULE instead of CONFIG_SND_HDA_INTEL_MODULE Checking MODULE is more generic. Also a cosmetic comment change. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 4aa7b1b7287..2fff0fb77ba 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -530,10 +530,10 @@ EXPORT_SYMBOL_GPL(snd_hda_bus_new); #define is_generic_config(codec) 0 #endif -#ifdef CONFIG_SND_HDA_INTEL_MODULE +#ifdef MODULE #define HDA_MODREQ_MAX_COUNT 2 /* two request_modules()'s */ #else -#define HDA_MODREQ_MAX_COUNT 0 +#define HDA_MODREQ_MAX_COUNT 0 /* all presets are statically linked */ #endif /* -- cgit v1.2.3 From ff7a3267368634e368ebaac68d5e3abf129edd1d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 15:17:06 +0100 Subject: ALSA: hda - Don't export symbols when built-in kernel The global functions in hda_codec.c and other core parts are only for HD-audio codec and controller drivers. When the HD-audio driver is built in kernel, all stuff have to be statically linked, thus we don't need any exports. This patch introduces a conditional macro to do export only when needed. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 4 +- sound/pci/hda/hda_codec.c | 148 +++++++++++++++++++++++----------------------- sound/pci/hda/hda_codec.h | 15 +++++ 3 files changed, 91 insertions(+), 76 deletions(-) diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index e6cc9463667..e00421c0d8b 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -128,7 +128,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device); +EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device); void snd_hda_detach_beep_device(struct hda_codec *codec) { @@ -141,4 +141,4 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) kfree(beep); } } -EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device); +EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 2fff0fb77ba..004344825e9 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -71,7 +71,7 @@ int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset) mutex_unlock(&preset_mutex); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset); +EXPORT_SYMBOL_HDA(snd_hda_add_codec_preset); int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) { @@ -80,7 +80,7 @@ int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) mutex_unlock(&preset_mutex); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_delete_codec_preset); +EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset); #ifdef CONFIG_SND_HDA_POWER_SAVE static void hda_power_work(struct work_struct *work); @@ -114,7 +114,7 @@ const char *snd_hda_get_jack_location(u32 cfg) } return "UNKNOWN"; } -EXPORT_SYMBOL_GPL(snd_hda_get_jack_location); +EXPORT_SYMBOL_HDA(snd_hda_get_jack_location); const char *snd_hda_get_jack_connectivity(u32 cfg) { @@ -122,7 +122,7 @@ const char *snd_hda_get_jack_connectivity(u32 cfg) return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; } -EXPORT_SYMBOL_GPL(snd_hda_get_jack_connectivity); +EXPORT_SYMBOL_HDA(snd_hda_get_jack_connectivity); const char *snd_hda_get_jack_type(u32 cfg) { @@ -136,7 +136,7 @@ const char *snd_hda_get_jack_type(u32 cfg) return jack_types[(cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT]; } -EXPORT_SYMBOL_GPL(snd_hda_get_jack_type); +EXPORT_SYMBOL_HDA(snd_hda_get_jack_type); /* * Compose a 32bit command word to be sent to the HD-audio controller @@ -185,7 +185,7 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, snd_hda_power_down(codec); return res; } -EXPORT_SYMBOL_GPL(snd_hda_codec_read); +EXPORT_SYMBOL_HDA(snd_hda_codec_read); /** * snd_hda_codec_write - send a single command without waiting for response @@ -214,7 +214,7 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, snd_hda_power_down(codec); return err; } -EXPORT_SYMBOL_GPL(snd_hda_codec_write); +EXPORT_SYMBOL_HDA(snd_hda_codec_write); /** * snd_hda_sequence_write - sequence writes @@ -229,7 +229,7 @@ void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq) for (; seq->nid; seq++) snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param); } -EXPORT_SYMBOL_GPL(snd_hda_sequence_write); +EXPORT_SYMBOL_HDA(snd_hda_sequence_write); /** * snd_hda_get_sub_nodes - get the range of sub nodes @@ -251,7 +251,7 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, *start_id = (parm >> 16) & 0x7fff; return (int)(parm & 0x7fff); } -EXPORT_SYMBOL_GPL(snd_hda_get_sub_nodes); +EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); /** * snd_hda_get_connections - get connection list @@ -340,7 +340,7 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, } return conns; } -EXPORT_SYMBOL_GPL(snd_hda_get_connections); +EXPORT_SYMBOL_HDA(snd_hda_get_connections); /** @@ -375,7 +375,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) return 0; } -EXPORT_SYMBOL_GPL(snd_hda_queue_unsol_event); +EXPORT_SYMBOL_HDA(snd_hda_queue_unsol_event); /* * process queued unsolicited events @@ -521,7 +521,7 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, *busp = bus; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_bus_new); +EXPORT_SYMBOL_HDA(snd_hda_bus_new); #ifdef CONFIG_SND_HDA_GENERIC #define is_generic_config(codec) \ @@ -808,7 +808,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr *codecp = codec; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_codec_new); +EXPORT_SYMBOL_HDA(snd_hda_codec_new); int snd_hda_codec_configure(struct hda_codec *codec) { @@ -868,7 +868,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, msleep(1); snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format); } -EXPORT_SYMBOL_GPL(snd_hda_codec_setup_stream); +EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream); void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) { @@ -882,7 +882,7 @@ void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); #endif } -EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup_stream); +EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); /* * amp access functions @@ -964,7 +964,7 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) } return info->amp_caps; } -EXPORT_SYMBOL_GPL(query_amp_caps); +EXPORT_SYMBOL_HDA(query_amp_caps); int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps) @@ -978,7 +978,7 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, info->head.val |= INFO_AMP_CAPS; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps); +EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); /* * read the current volume to info @@ -1032,7 +1032,7 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, return 0; return get_vol_mute(codec, info, nid, ch, direction, index); } -EXPORT_SYMBOL_GPL(snd_hda_codec_amp_read); +EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read); /* * update the AMP value, mask = bit mask to set, val = the value @@ -1052,7 +1052,7 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, put_vol_mute(codec, info, nid, ch, direction, idx, val); return 1; } -EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update); +EXPORT_SYMBOL_HDA(snd_hda_codec_amp_update); /* * update the AMP stereo with the same mask and value @@ -1066,7 +1066,7 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, idx, mask, val); return ret; } -EXPORT_SYMBOL_GPL(snd_hda_codec_amp_stereo); +EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo); #ifdef SND_HDA_NEEDS_RESUME /* resume the all amp commands from the cache */ @@ -1092,7 +1092,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) } } } -EXPORT_SYMBOL_GPL(snd_hda_codec_resume_amp); +EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); #endif /* SND_HDA_NEEDS_RESUME */ /* volume */ @@ -1120,7 +1120,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.max = caps; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_info); +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1140,7 +1140,7 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, & HDA_AMP_VOLMASK; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_get); +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get); int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1165,7 +1165,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, snd_hda_power_down(codec); return change; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put); +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_put); int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *_tlv) @@ -1192,7 +1192,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, return -EFAULT; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_tlv); +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_tlv); /* * set (static) TLV for virtual master volume; recalculated as max 0dB @@ -1212,7 +1212,7 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, tlv[2] = -nums * step; tlv[3] = step; } -EXPORT_SYMBOL_GPL(snd_hda_set_vmaster_tlv); +EXPORT_SYMBOL_HDA(snd_hda_set_vmaster_tlv); /* find a mixer control element with the given name */ static struct snd_kcontrol * @@ -1232,7 +1232,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, { return _snd_hda_find_mixer_ctl(codec, name, 0); } -EXPORT_SYMBOL_GPL(snd_hda_find_mixer_ctl); +EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); /* Add a control element and assign to the codec */ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) @@ -1249,7 +1249,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) *knewp = kctl; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_ctl_add); +EXPORT_SYMBOL_HDA(snd_hda_ctl_add); #ifdef CONFIG_SND_HDA_RECONFIG /* Clear all controls assigned to the given codec */ @@ -1328,7 +1328,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_add_vmaster); +EXPORT_SYMBOL_HDA(snd_hda_add_vmaster); /* switch */ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, @@ -1342,7 +1342,7 @@ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.max = 1; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_info); +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_info); int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1362,7 +1362,7 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, HDA_AMP_MUTE) ? 0 : 1; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get); +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_get); int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1393,7 +1393,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, snd_hda_power_down(codec); return change; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put); +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put); /* * bound volume controls @@ -1419,7 +1419,7 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_get); +EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get); int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1443,7 +1443,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err < 0 ? err : change; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_put); +EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put); /* * generic bound volume/swtich controls @@ -1463,7 +1463,7 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_info); +EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info); int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1480,7 +1480,7 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_get); +EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get); int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1503,7 +1503,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err < 0 ? err : change; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_put); +EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put); int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv) @@ -1520,7 +1520,7 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, mutex_unlock(&codec->spdif_mutex); return err; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_tlv); +EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv); struct hda_ctl_ops snd_hda_bind_vol = { .info = snd_hda_mixer_amp_volume_info, @@ -1528,7 +1528,7 @@ struct hda_ctl_ops snd_hda_bind_vol = { .put = snd_hda_mixer_amp_volume_put, .tlv = snd_hda_mixer_amp_tlv }; -EXPORT_SYMBOL_GPL(snd_hda_bind_vol); +EXPORT_SYMBOL_HDA(snd_hda_bind_vol); struct hda_ctl_ops snd_hda_bind_sw = { .info = snd_hda_mixer_amp_switch_info, @@ -1536,7 +1536,7 @@ struct hda_ctl_ops snd_hda_bind_sw = { .put = snd_hda_mixer_amp_switch_put, .tlv = snd_hda_mixer_amp_tlv }; -EXPORT_SYMBOL_GPL(snd_hda_bind_sw); +EXPORT_SYMBOL_HDA(snd_hda_bind_sw); /* * SPDIF out controls @@ -1798,7 +1798,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_create_spdif_out_ctls); +EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls); /* * SPDIF sharing with analog output @@ -1836,7 +1836,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec, return snd_hda_ctl_add(codec, snd_ctl_new1(&spdif_share_sw, mout)); } -EXPORT_SYMBOL_GPL(snd_hda_create_spdif_share_sw); +EXPORT_SYMBOL_HDA(snd_hda_create_spdif_share_sw); /* * SPDIF input @@ -1946,7 +1946,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) AC_DIG1_ENABLE; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_create_spdif_in_ctls); +EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); #ifdef SND_HDA_NEEDS_RESUME /* @@ -1992,7 +1992,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, snd_hda_power_down(codec); return err; } -EXPORT_SYMBOL_GPL(snd_hda_codec_write_cache); +EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); /* resume the all commands from the cache */ void snd_hda_codec_resume_cache(struct hda_codec *codec) @@ -2008,7 +2008,7 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec) get_cmd_cache_cmd(key), buffer->val); } } -EXPORT_SYMBOL_GPL(snd_hda_codec_resume_cache); +EXPORT_SYMBOL_HDA(snd_hda_codec_resume_cache); /** * snd_hda_sequence_write_cache - sequence writes with caching @@ -2026,7 +2026,7 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, seq->param); } -EXPORT_SYMBOL_GPL(snd_hda_sequence_write_cache); +EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache); #endif /* SND_HDA_NEEDS_RESUME */ /* @@ -2156,7 +2156,7 @@ int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus) } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_build_controls); +EXPORT_SYMBOL_HDA(snd_hda_build_controls); int snd_hda_codec_build_controls(struct hda_codec *codec) { @@ -2268,7 +2268,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, return val; } -EXPORT_SYMBOL_GPL(snd_hda_calc_stream_format); +EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); /** * snd_hda_query_supported_pcm - query the supported PCM rates and formats @@ -2448,7 +2448,7 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, return 1; } -EXPORT_SYMBOL_GPL(snd_hda_is_supported_format); +EXPORT_SYMBOL_HDA(snd_hda_is_supported_format); /* * PCM stuff @@ -2646,7 +2646,7 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_build_pcms); +EXPORT_SYMBOL_HDA(snd_hda_build_pcms); /** * snd_hda_check_board_config - compare the current codec with the config table @@ -2702,7 +2702,7 @@ int snd_hda_check_board_config(struct hda_codec *codec, } return -1; } -EXPORT_SYMBOL_GPL(snd_hda_check_board_config); +EXPORT_SYMBOL_HDA(snd_hda_check_board_config); /** * snd_hda_add_new_ctls - create controls from the array @@ -2738,7 +2738,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls); +EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); #ifdef CONFIG_SND_HDA_POWER_SAVE static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, @@ -2781,7 +2781,7 @@ void snd_hda_power_up(struct hda_codec *codec) cancel_delayed_work(&codec->power_work); codec->power_transition = 0; } -EXPORT_SYMBOL_GPL(snd_hda_power_up); +EXPORT_SYMBOL_HDA(snd_hda_power_up); #define power_save(codec) \ ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) @@ -2800,7 +2800,7 @@ void snd_hda_power_down(struct hda_codec *codec) msecs_to_jiffies(power_save(codec) * 1000)); } } -EXPORT_SYMBOL_GPL(snd_hda_power_down); +EXPORT_SYMBOL_HDA(snd_hda_power_down); int snd_hda_check_amp_list_power(struct hda_codec *codec, struct hda_loopback_check *check, @@ -2837,7 +2837,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power); +EXPORT_SYMBOL_HDA(snd_hda_check_amp_list_power); #endif /* @@ -2857,7 +2857,7 @@ int snd_hda_ch_mode_info(struct hda_codec *codec, chmode[uinfo->value.enumerated.item].channels); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info); +EXPORT_SYMBOL_HDA(snd_hda_ch_mode_info); int snd_hda_ch_mode_get(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, @@ -2875,7 +2875,7 @@ int snd_hda_ch_mode_get(struct hda_codec *codec, } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get); +EXPORT_SYMBOL_HDA(snd_hda_ch_mode_get); int snd_hda_ch_mode_put(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, @@ -2896,7 +2896,7 @@ int snd_hda_ch_mode_put(struct hda_codec *codec, snd_hda_sequence_write_cache(codec, chmode[mode].sequence); return 1; } -EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put); +EXPORT_SYMBOL_HDA(snd_hda_ch_mode_put); /* * input MUX helper @@ -2917,7 +2917,7 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux, strcpy(uinfo->value.enumerated.name, imux->items[index].label); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_input_mux_info); +EXPORT_SYMBOL_HDA(snd_hda_input_mux_info); int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, @@ -2939,7 +2939,7 @@ int snd_hda_input_mux_put(struct hda_codec *codec, *cur_val = idx; return 1; } -EXPORT_SYMBOL_GPL(snd_hda_input_mux_put); +EXPORT_SYMBOL_HDA(snd_hda_input_mux_put); /* @@ -2992,7 +2992,7 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_open); +EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_open); int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, struct hda_multi_out *mout, @@ -3005,7 +3005,7 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare); +EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_prepare); /* * release the digital out @@ -3018,7 +3018,7 @@ int snd_hda_multi_out_dig_close(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_close); +EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_close); /* * set up more restrictions for analog out @@ -3058,7 +3058,7 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec, return snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); } -EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_open); +EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_open); /* * set up the i/o for analog out @@ -3117,7 +3117,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_prepare); +EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare); /* * clean up the setting for analog out @@ -3144,7 +3144,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_cleanup); +EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup); /* * Helper for automatic pin configuration @@ -3430,13 +3430,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, return 0; } -EXPORT_SYMBOL_GPL(snd_hda_parse_pin_def_config); +EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config); /* labels for input pins */ const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = { "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" }; -EXPORT_SYMBOL_GPL(auto_pin_cfg_labels); +EXPORT_SYMBOL_HDA(auto_pin_cfg_labels); #ifdef CONFIG_PM @@ -3464,7 +3464,7 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_suspend); +EXPORT_SYMBOL_HDA(snd_hda_suspend); /** * snd_hda_resume - resume the codecs @@ -3485,7 +3485,7 @@ int snd_hda_resume(struct hda_bus *bus) } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_resume); +EXPORT_SYMBOL_HDA(snd_hda_resume); #endif /* CONFIG_PM */ /* @@ -3515,7 +3515,7 @@ void *snd_array_new(struct snd_array *array) } return snd_array_elem(array, array->used++); } -EXPORT_SYMBOL_GPL(snd_array_new); +EXPORT_SYMBOL_HDA(snd_array_new); /* free the given array elements */ void snd_array_free(struct snd_array *array) @@ -3525,7 +3525,7 @@ void snd_array_free(struct snd_array *array) array->alloced = 0; array->list = NULL; } -EXPORT_SYMBOL_GPL(snd_array_free); +EXPORT_SYMBOL_HDA(snd_array_free); /* * used by hda_proc.c and hda_eld.c @@ -3544,7 +3544,7 @@ void snd_print_pcm_rates(int pcm, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } -EXPORT_SYMBOL_GPL(snd_print_pcm_rates); +EXPORT_SYMBOL_HDA(snd_print_pcm_rates); void snd_print_pcm_bits(int pcm, char *buf, int buflen) { @@ -3557,7 +3557,7 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } -EXPORT_SYMBOL_GPL(snd_print_pcm_bits); +EXPORT_SYMBOL_HDA(snd_print_pcm_bits); MODULE_DESCRIPTION("HDA codec core"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 586ea08b340..6612d0f20bc 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -905,4 +905,19 @@ static inline void snd_hda_power_down(struct hda_codec *codec) {} #define snd_hda_codec_needs_resume(codec) 1 #endif +/* + * Codec modularization + */ + +/* Export symbols only for communication with codec drivers; + * When built in kernel, all HD-audio drivers are supposed to be statically + * linked to the kernel. Thus, the symbols don't have to (or shouldn't) be + * exported unless it's built as a module. + */ +#ifdef MODULE +#define EXPORT_SYMBOL_HDA(sym) EXPORT_SYMBOL_GPL(sym) +#else +#define EXPORT_SYMBOL_HDA(sym) +#endif + #endif /* __SOUND_HDA_CODEC_H */ -- cgit v1.2.3 From 36adba1fc79851949c4792f2e9b4d0dddbc6d5e4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 15:27:11 +0100 Subject: ALSA: hda - Remove EXPERIMENTAL from CONFIG_SND_HDA_POWER_SAVE It's mature enough now. Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 7c60f1a45a8..ccf7326a667 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -122,7 +122,6 @@ config SND_HDA_GENERIC config SND_HDA_POWER_SAVE bool "Aggressive power-saving on HD-audio" - depends on EXPERIMENTAL help Say Y here to enable more aggressive power-saving mode on HD-audio driver. The power-saving timeout can be configured -- cgit v1.2.3 From c9b46f9144b8dce6c12aec08f34a908aedd28b37 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 11:42:09 +0100 Subject: ALSA: hda - Use amp cache for SPDIF mute controls in patch_sigmatel.c The amp switch of SPDIF outputs have to be cached in the amp cache instead of codec cache. Otherwise it conflicts with the IEC958 playback switch control in hda_codec.c. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 33170a24200..068a77ae459 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -590,12 +590,12 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol, else nid = codec->slave_dig_outs[smux_idx - 1]; if (spec->cur_smux[smux_idx] == smux->num_items - 1) - val = AMP_OUT_MUTE; + val = HDA_AMP_MUTE; else - val = AMP_OUT_UNMUTE; + val = 0; /* un/mute SPDIF out */ - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, val); + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, val); } return 0; } -- cgit v1.2.3 From 8c2f767bf3c4a7932898e657c6b12a2234cd2eca Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 11:54:35 +0100 Subject: ALSA: hda - Remove unnecessary caches for power states in patch_sigmatel.c The power-state changes in patch_sigmatel.c are accessed via *_cached() but they shouldn't be really cached. Fixed to the normal write. Also, stac92hd71xx_suspend and resume are no longer necessary as the power-state changes are handled properly in the common routine. Removed these hacks now. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 62 ++++-------------------------------------- 1 file changed, 6 insertions(+), 56 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 068a77ae459..14db35a61cf 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2413,7 +2413,7 @@ static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo, if (spec->powerdown_adcs) { msleep(40); - snd_hda_codec_write_cache(codec, nid, 0, + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0); } snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); @@ -2429,7 +2429,7 @@ static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, snd_hda_codec_cleanup_stream(codec, nid); if (spec->powerdown_adcs) - snd_hda_codec_write_cache(codec, nid, 0, + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); return 0; } @@ -3866,7 +3866,7 @@ static void stac92xx_power_down(struct hda_codec *codec) for (dac = spec->dac_list; *dac; dac++) if (!is_in_dac_nids(spec, *dac) && spec->multiout.hp_nid != *dac) - snd_hda_codec_write_cache(codec, *dac, 0, + snd_hda_codec_write(codec, *dac, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); } @@ -3885,7 +3885,7 @@ static int stac92xx_init(struct hda_codec *codec) /* power down adcs initially */ if (spec->powerdown_adcs) for (i = 0; i < spec->num_adcs; i++) - snd_hda_codec_write_cache(codec, + snd_hda_codec_write(codec, spec->adc_nids[i], 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); @@ -4724,48 +4724,6 @@ again: return 0; } -#ifdef SND_HDA_NEEDS_RESUME -static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr) -{ - struct sigmatel_spec *spec = codec->spec; - int i; - snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_POWER_STATE, pwr); - - msleep(1); - for (i = 0; i < spec->num_adcs; i++) { - snd_hda_codec_write_cache(codec, - spec->adc_nids[i], 0, - AC_VERB_SET_POWER_STATE, pwr); - } -}; - -static int stac92hd71xx_resume(struct hda_codec *codec) -{ - stac92hd71xx_set_power_state(codec, AC_PWRST_D0); - return stac92xx_resume(codec); -} - -static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state) -{ - stac92hd71xx_set_power_state(codec, AC_PWRST_D3); - return stac92xx_suspend(codec, state); -}; - -#endif - -static struct hda_codec_ops stac92hd71bxx_patch_ops = { - .build_controls = stac92xx_build_controls, - .build_pcms = stac92xx_build_pcms, - .init = stac92xx_init, - .free = stac92xx_free, - .unsol_event = stac92xx_unsol_event, -#ifdef SND_HDA_NEEDS_RESUME - .suspend = stac92hd71xx_suspend, - .resume = stac92hd71xx_resume, -#endif -}; - static struct hda_input_mux stac92hd71bxx_dmux = { .num_items = 4, .items = { @@ -4842,12 +4800,8 @@ again: break; } if ((codec->revision_id & 0xf) == 0 || - (codec->revision_id & 0xf) == 1) { -#ifdef SND_HDA_NEEDS_RESUME - codec->patch_ops = stac92hd71bxx_patch_ops; -#endif + (codec->revision_id & 0xf) == 1) spec->stream_delay = 40; /* 40 milliseconds */ - } /* no output amps */ spec->num_pwrs = 0; @@ -4859,12 +4813,8 @@ again: stac_change_pin_config(codec, 0xf, 0x40f000f0); break; case 0x111d7603: /* 6 Port with Analog Mixer */ - if ((codec->revision_id & 0xf) == 1) { -#ifdef SND_HDA_NEEDS_RESUME - codec->patch_ops = stac92hd71bxx_patch_ops; -#endif + if ((codec->revision_id & 0xf) == 1) spec->stream_delay = 40; /* 40 milliseconds */ - } /* no output amps */ spec->num_pwrs = 0; -- cgit v1.2.3 From a7fe49bf01dd64b3c73ad0e172f68bd03c813d65 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 3 Dec 2008 18:26:35 +0100 Subject: ALSA: Add more documentation about HD-audio driver The file can be converted to PDF via asciidoc. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 535 ++++++++++++++++++++++++++++++++++ 1 file changed, 535 insertions(+) create mode 100644 Documentation/sound/alsa/HD-Audio.txt diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt new file mode 100644 index 00000000000..e758f24017b --- /dev/null +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -0,0 +1,535 @@ +MORE NOTES ON HD-AUDIO DRIVER +============================= + Takashi Iwai + + +GENERAL +------- + +HD-audio is the new standard on-board audio component on modern PCs +after AC97. Although Linux has been supporting HD-audio since long +time ago, there are often problems with new machines. A part of the +problem is broken BIOS, and rest is the driver implementation. This +document explains the trouble-shooting and debugging methods for the +HD-audio hardware. + +The HD-audio component consists of two parts: the controller chip and +the codec chips on the HD-audio bus. Linux provides a single driver +for all controllers, snd-hda-intel. Since the HD-audio controllers +are supposed to be compatible, the single snd-hda-driver should work +in most cases. But, not surprisingly, there are known bugs and issues +specific to each controller type. The snd-hda-intel driver has a +bunch of workarounds for these as described below. + +A controller may have multiple codecs. Usually you have one audio +codec and optionally one modem codec. In some cases, there can be +multiple audio codecs, e.g. for analog and digital outputs, but the +driver might not work properly. + +The snd-hda-intel driver has several different codec parsers depending +on the codec. It has a generic parser as a fallback, but this +functionality is fairly limited until now. Instead of the generic +parser, usually the codec-specific parser (coded in patch_*.c) is used +for the codec-specific implementations. The details about the +codec-specific problems are explained in the later sections. + +If you are interested in the deep debugging of HD-audio, read the +HD-audio specification at first. The specification is found on +Intel's web page, for example: + +- http://www.intel.com/standards/hdaudio/ + + +HD-AUDIO CONTROLLER +------------------- + +DMA-Position Problem +~~~~~~~~~~~~~~~~~~~~ +The most common problem of the controller is the inaccurate DMA +pointer reporting. The DMA pointer for playback and capture can be +read in two ways, either via a LPIB register or via a position-buffer +map. As default the driver tries to reads from the io-mapped +position-buffer, and falls back to LPIB if it appears unupdated. +However, this detection isn't perfect on some devices. In such a +case, you can change the default method via `position_fix` option. + +`position_fix=1` means to use LPIB method explicitly. +`position_fix=2` means to use the position-buffer. 0 is the default +value, the automatic check. If you get a problem of repeated sounds, +this option might help. + +In addition to that, every controller is known to be broken regarding +the wake-up timing. It wakes up a few samples before actually +processing the data on the buffer. This caused a lot of problems, for +example, with ALSA dmix or JACK. Since 2.6.27 kernel, the driver puts +an artificial delay to the wake up timing. This delay is controlled +via `bdl_pos_adj` option. + +When `bdl_pos_adj` is a negative value (as default), it's assigned to +an appropriate value depending on the controller chip. For Intel +chip, it'd be 1 while it'd be 32 for others. Usually this works. +Only in case it doesn't work and you get warning messages, you should +change to other values. + + +Codec-Probing Problem +~~~~~~~~~~~~~~~~~~~~~ +A less often but a more severe problem is the codec probing. When +BIOS reports the available codec slots wrongly, the driver gets +confused and tries to access the non-existing codec slot. This often +results in the total screw-up, and destruct the further communication +with the codec chips. The symptom appears usually as the error +message like: +------------------------------------------------------------------------ + hda_intel: azx_get_response timeout, switching to polling mode: \ + last cmd=0x12345678 + hda_intel: azx_get_response timeout, switching to single_cmd mode: \ + last cmd=0x12345678 +------------------------------------------------------------------------ + +The first line is a warning, and this is usually relatively harmless. +It means that the codec response isn't notified via an IRQ. The +driver uses explicit polling method to read the response. It gives +very slight CPU overhead, but you'd unlikely notice it. + +The second line is, however, a fatal error. If this happens, usually +it means that something is really wrong. Most likely you are +accessing a non-existing codec slot. + +Thus, if the second error message appears, try to narrow the probed +codec slots via `probe_mask` option. It's a bitmask, and each bit +corresponding to the codec slot. For example, to probe only the +first slot, pass `probe_mask=1`. For the first and the third slots, +pass `probe_mask=5` (where 5 = 1 | 4), and so on. + +Since 2.6.29 kernel, the driver has a more robust probing method, so +this error might happen rarely, though. + + +Interrupt Handling +~~~~~~~~~~~~~~~~~~ +In rare but some cases, the interrupt isn't properly handled as +default. You would notice this by the DMA transfer error reported by +ALSA PCM core, for example. Using MSI might help in such a case. +Pass `enable_msi=1` option for enabling MSI. + + +HD-AUDIO CODEC +-------------- + +Model Option +~~~~~~~~~~~~ +The most common problems with the HD-audio driver is the unsupported +codec features or the mismatched device configuration. Most of +codec-specific code has several preset models, either to override the +BIOS setup or to provide more comprehensive features. + +The driver checks PCI SSID and looks through the static configuration +table until any matching entry is found. If you have a new machine, +you may see a message like below: +------------------------------------------------------------------------ + hda_codec: Unknown model for ALC880, trying auto-probe from BIOS... +------------------------------------------------------------------------ +Even if you such a message, DON'T PANIC. Take a deep breath (and keep +your towel). First of all, it's an informational message, no warning, +no error. This means that the PCI SSID of your device isn't listed in +the known preset model list. But, this doesn't mean that the driver +is broken. Many codec-driver provides the automatic configuration +based on the BIOS setup. + +The HD-audio codec has usually "pin" widgets, and BIOS sets the default +configuration of each pin, which indicates the location, the +connection type, the jack color, etc. The HD-audio driver can guess +the right connection judging from these default configuration values. +However -- some codec support codes, such as patch_analog.c, don't +support the automatic probing (yet as of 2.6.28). And, BIOS is often, +yes, pretty often broken. It sets up wrong values and screws up the +driver. + +The preset model is provided basically to override such a situation. +When the matching preset model is found in the list, the driver +assumes the static configuration of that preset and builds the mixer +and PCM based on the static information. Thus, if you have a newer +machine with a slightly different PCI SSID from the existing one, you +may have a good chance to re-use the same model. You can pass the +`model` option to specify the preset model instead of PCI SSID +look-up. + +What `model` option values are available depends on the codec chip. +Check your codec chip from the codec proc file (see "Codec Proc-File" +section below). It will show the vendor/product name of your codec +chip. Then, see Documentation/sound/alsa/ALSA-Configuration.txt file. +In the section of HD-audio driver, you can find a list of codecs and +`model` options belonging to each codec. For example, for Realtek +ALC262 codec chip, pass `model=ultra` for devices that are compatible +with Samsung Q1 Ultra. + +Thus, the first thing you can do for any brand-new, unsupported +HD-audio hardware is to check HD-audio codec and several different +`model` option values. If you have a luck, some of them might suit +with your device well. + +Some codecs such as ALC880 have a special model option `model=test`. +This configures the driver to provide as many mixer controls as +possible for every single pin feature except for the unsolicited +events (and maybe some other specials). Adjust each mixer element and +try the I/O in the way of trial-and-error until figuring out the whole +I/O pin mappings. + +Note that `model=generic` has a special meaning. It means to use the +generic parser regardless of the codec. Usually the codec-specific +parser is much better than the generic parser (as now). Thus this +option is more about the debugging purpose. + + +Speaker and Headphone Output +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +One of the most frequent (and obvious) bugs with HD-audio is the +silent output from either or both of a built-in speaker and a +headphone jack. In general, you should try a headphone output at +first. A speaker output often requires more additional controls like +the amplifier. Thus a headphone output has a slightly better chance. + +Before making a bug report, double-check whether the mixer is set up +correctly. The recent version of snd-hda-intel driver provides mostly +"Master" volume control as well as "Front" volume. In addition, there +are individual "Headphone" and "Speaker" controls. + +Ditto for the speaker output. There can be "External Amplifier" +switch on some codecs. Turn on this if present. + +Another related problem is the automatic mute of speaker output by +headphone plugging. This feature is implemented in most cases, but +not on every preset model or codec-support code. + +In anyway, try a different model option if you have such a problem. +Some other models may match better and give you more matching +functionality. If none of the available models works, send a bug +report. See the bug report section for details. + +If you are masochistic enough to debug the driver problem, note the +following: + +- The speaker (and the headphone, too) output often requires the + external amplifier. This can be set usually via EAPD verb or a + certain GPIO. If the codec pin supports EAPD, you have a better + chance via SET_EAPD_BTL verb (0x70c). On others, GPIO pin (mostly + it's either GPIO0 or GPIO1) can turn on/off EAPD. +- Some Realtek codecs require special vendor-specific coefficients to + turn on the amplifier. See patch_realtek.c. +- IDT codecs may have extra power-enable/disable controls on each + analog pin. See patch_sigmatel.c. +- Very rare but some devices don't accept the pin-detection verb until + triggered. Issuing GET_PIN_SENSE verb (0xf09) may result in the + codec-communication stall. Some examples are found in + patch_realtek.c. + + +Capture Problems +~~~~~~~~~~~~~~~~ +The capture problems are often missing setups of mixers. Thus, before +submitting a bug report, make sure that you set up the mixer +correctly. For example, both "Capture Volume" and "Capture Switch" +have to be set properly in addition to the right "Capture Source" or +"Input Source" selection. Some devices have "Mic Boost" volume or +switch. + +When the PCM device is opened via "default" PCM (without pulse-audio +plugin), you'll likely have "Digital Capture Volume" control as well. +This is provided for the extra gain/attenuation of the signal in +software, especially for the inputs without the hardware volume +control such as digital microphones. Unless really needed, this +should be set to exactly 50%, corresponding to 0dB. When you use "hw" +PCM, i.e., a raw access PCM, this control will have no influence, +though. + +It's known that some codecs / devices have fairly bad analog circuits, +and the recorded sound contains a certain DC-offset. This is no bug +of the driver. + +Most of modern laptops have no analog CD-input connection. Thus, the +recording from CD input won't work in many cases although the driver +provides it as the capture source. + +The automatic switching of the built-in and external mic per plugging +is implemented on some codec models but not on every model. Partly +because of my laziness but mostly lack of testers. Feel free to +submit the improvement patch to the author. + + +Direct Debugging +~~~~~~~~~~~~~~~~ +If no model option gives you a better result, and you are a touch guy +to fight again the evil, try debugging via hitting the raw HD-audio +codec verbs to the device. Some tools are available: hda-emu and +hda-analyzer. The detailed description is found in the sections +below. You'd need to enable hwdep for using these tools. See "Kernel +Configuration". + + +OTHER ISSUES +------------ + +Kernel Configuration +~~~~~~~~~~~~~~~~~~~~ +In general, I recommend you to enable the sound debug option, +`CONFIG_SND_DEBUG=y`, no matter whether you are debugging or not. +This enables snd_printd() macro and others, and you'll get additional +kernel messages at probing. + +In addition, you can enable `CONFIG_SND_DEBUG_VERBOSE=y`. But this +will give you far more messages. Thus turn this on only when you are +sure to want it. + +Don't forget to turn on the appropriate `CONFIG_SND_HDA_CODEC_*` +options. Note that each of them corresponds to the codec chip, not +the controller chip. Thus, even if lspci shows the Nvidia controller, +you may choose the option for other vendors. If you are unsure, just +choose all yes. + +`CONFIG_SND_HDA_HWDEP` is a useful option for debugging the driver. +When this is enabled, the driver creates hardware-dependent devices +(one per each codec), and you have a raw access to the device via +hda-verb program. For example, `hwC0D2` will be created for the card +0 codec slot #2. For debug tools such as hda-verb and hda-analyzer, +the hwdep device has to be enabled. Thus, turn this on always. + +`CONFIG_SND_HDA_RECONFIG` is a new option, and this depends on the +hwdep option above. When enabled, you'll have some sysfs files under +the corresponding hwdep directory. See "HD-audio reconfiguration" +section below. + +`CONFIG_SND_HDA_POWER_SAVE` option enables the power-saving feature. +See "Power-saving" section below. + + +Codec Proc-File +~~~~~~~~~~~~~~~ +The codec proc-file is a treasure-chest for debugging HD-audio. +It shows most of useful information of each codec widget. + +The proc file is located in /proc/asound/card*/codec#*, one file per +each codec slot. You can know the codec vendor, product id and +names, the type of each widget, capabilities and so on. +This file, however, doesn't show the jack sensing state, so far. This +is because the jack-sensing might be depending on the trigger state. + +This file will be picked up by the debug tools, and also it can be fed +to the emulator as the primary codec information. See the debug tools +section below. + +This proc file can be also used to check whether the generic parser is +used. When the generic parser is used, the vendor/product ID name +will appear as "Realtek ID 0262", instead of "Realtek ALC262". + + +HD-Audio Reconfiguration +~~~~~~~~~~~~~~~~~~~~~~~~ +This is an experimental feature to allow you re-configure the HD-audio +codec dynamically without reloading the driver. The following sysfs +files are available under each codec-hwdep device directory (e.g. +/sys/class/sound/hwC0D0): + +vendor_id:: + Shows the 32bit codec vendor-id hex number. You can change the + vendor-id value by writing to this file. +subsystem_id:: + Shows the 32bit codec subsystem-id hex number. You can change the + subsystem-id value by writing to this file. +revision_id:: + Shows the 32bit codec revision-id hex number. You can change the + revision-id value by writing to this file. +afg:: + Shows the AFG ID. This is read-only. +mfg:: + Shows the MFG ID. This is read-only. +name:: + Shows the codec name string. Can be changed by writing to this + file. +modelname:: + Shows the currently set `model` option. Can be changed by writing + to this file. +init_verbs:: + The extra verbs to execute at initialization. You can add a verb by + writing to this file. Pass tree numbers, nid, verb and parameter. +hints:: + Shows hint strings for codec parsers for any use. Right now it's + not used. +reconfig:: + Triggers the codec re-configuration. When any value is written to + this file, the driver re-initialize and parses the codec tree + again. All the changes done by the sysfs entries above are taken + into account. +clear:: + Resets the codec, removes the mixer elements and PCM stuff of the + specified codec, and clear all init verbs and hints. + + +Power-Saving +~~~~~~~~~~~~ +The power-saving is a kind of auto-suspend of the device. When the +device is inactive for a certain time, the device is automatically +turned off to save the power. The time to go down is specified via +`power_save` module option, and this option can be changed dynamically +via sysfs. + +The power-saving won't work when the analog loopback is enabled on +some codecs. Make sure that you mute all unneeded signal routes when +you want the power-saving. + +The power-saving feature might cause audible click noises at each +power-down/up depending on the device. Some of them might be +solvable, but some are hard, I'm afraid. Some distros such as +openSUSE enables the power-saving feature automatically when the power +cable is unplugged. Thus, if you hear noises, suspect first the +power-saving. See /sys/modules/snd_hda_intel/parameters/power_save to +check the current value. If it's non-zero, the feature is turned on. + + +Sending a Bug Report +~~~~~~~~~~~~~~~~~~~~ +If any model or module options don't work for your device, it's time +to send a bug report to the developers. Give the following in your +bug report: + +- Hardware vendor, product and model names +- Kernel version (and ALSA-driver version if you built externally) +- `alsa-info.sh` output; run with `--no-upload` option. See the + section below about alsa-info + +If it's a regression, at best, send alsa-info outputs of both working +and non-working kernels. This is really helpful because we can +compare the codec registers directly. + +Send a bug report either the followings: + +kernel-bugzilla:: + http://bugme.linux-foundation.org/ +alsa-devel ML:: + alsa-devel@alsa-project.org + + +DEBUG TOOLS +----------- + +This section describes some tools available for debugging HD-audio +problems. + +alsa-info +~~~~~~~~~ +The script `alsa-info.sh` is a very useful tool to gather the audio +device information. You can fetch the latest version from: + +- http://www.alsa-project.org/alsa-info.sh + +Run this script as root, and it will gather the important information +such as the module lists, module parameters, proc file contents +including the codec proc files, mixer outputs and the control +elements. As default, it will store the information onto a web server +on alsa-project.org. But, if you send a bug report, it'd be better to +run with `--no-upload` option, and attach the generated file. + +There are some other useful options. See `--help` option output for +details. + + +hda-verb +~~~~~~~~ +hda-verb is a tiny program that allows you to access the HD-audio +codec directly. It executes a HD-audio codec verb directly. +This program accesses the hwdep device, thus you need to enable the +kernel config `CONFIG_SND_HDA_HWDEP=y` beforehand. + +The hda-verb program takes four arguments: the hwdep device file, the +widget NID, the verb and the parameter. When you access to the codec +on the slot 2 of the card 0, pass /dev/snd/hwC0D2 to the first +argument, typically. (However, the real path name depends on the +system.) + +The second parameter is the widget number-id to access. The third +parameter can be either a hex/digit number or a string corresponding +to a verb. Similarly, the last parameter is the value to write, or +can be a string for the parameter type. + +------------------------------------------------------------------------ + % hda-verb /dev/snd/hwC0D0 0x12 0x701 2 + nid = 0x12, verb = 0x701, param = 0x2 + value = 0x0 + + % hda-verb /dev/snd/hwC0D0 0x0 PARAMETERS VENDOR_ID + nid = 0x0, verb = 0xf00, param = 0x0 + value = 0x10ec0262 + + % hda-verb /dev/snd/hwC0D0 2 set_a 0xb080 + nid = 0x2, verb = 0x300, param = 0xb080 + value = 0x0 +------------------------------------------------------------------------ + +Although you can issue any verbs with this program, the driver state +won't be always updated. For example, the volume values are usually +cached in the driver, and thus changing the widget amp value directly +via hda-verb won't change the mixer value. + +The hda-verb program is found in the ftp directory: + +- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/ + +Also a git repository is available: + +- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/hda-verb.git + +See README file in the tarball for more details about hda-verb +program. + + +hda-analyzer +~~~~~~~~~~~~ +hda-analyzer provides a graphical interface to access the raw HD-audio +control, based on pyGTK2 binding. It's a more powerful version of +hda-verb. The program gives you a easy-to-use GUI stuff for showing +the widget information and adjusting the amp values, as well as the +proc-compatible output. + +The hda-analyzer is a part of alsa.git repository in +alsa-project.org: + +- http://git.alsa-project.org/?p=alsa.git;a=tree;f=hda-analyzer + + +hda-emu +~~~~~~~ +hda-emu is a HD-audio emulator. The main purpose of this program is +to debug an HD-audio codec without the real hardware. Thus, it +doesn't emulate the behavior with the real audio I/O, but it just +dumps the codec register changes and the ALSA-driver internal changes +at probing and operating the HD-audio driver. + +The program requires a codec proc-file to simulate. Get a proc file +for the target codec beforehand, or pick up an example codec from the +codec proc collections in the tarball. Then, run the program with the +proc file, and the hda-emu program will start parsing the codec file +and simulates the HD-audio driver: + +------------------------------------------------------------------------ + % hda-emu codecs/stac9200-dell-d820-laptop + # Parsing.. + hda_codec: Unknown model for STAC9200, using BIOS defaults + hda_codec: pin nid 08 bios pin config 40c003fa + .... +------------------------------------------------------------------------ + +The program gives you only a very dumb command-line interface. You +can get a proc-file dump at the current state, get a list of control +(mixer) elements, set/get the control element value, simulate the PCM +operation, the jack plugging simulation, etc. + +The package is found in: + +- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/ + +A git repository is available: + +- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/hda-emu.git + +See README file in the tarball for more details about hda-emu +program. -- cgit v1.2.3 From e5f73435683122612742eb17252a6854b28f2511 Mon Sep 17 00:00:00 2001 From: Scott Waye Date: Thu, 4 Dec 2008 07:43:18 +0100 Subject: ALSA: hda - Add MCP67 HDMI support Added id for MCP67 HDMI codec. Signed-off-by: Scott Waye Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_nvhdmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index e23de5594b6..5e6cc41a559 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -161,6 +161,7 @@ static int patch_nvhdmi(struct hda_codec *codec) static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { { .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi }, { .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de0067, .name = "NVIDIA MCP67 HDMI", .patch = patch_nvhdmi }, {} /* terminator */ }; -- cgit v1.2.3 From 4151d154efc2eb1e48b0950e93660691426dd23f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Dec 2008 07:49:15 +0100 Subject: ALSA: hda - Add forgotten module alias for Nvidia MCP67 HDMI Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_nvhdmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 5e6cc41a559..0cd53063e62 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -167,6 +167,7 @@ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { MODULE_ALIAS("snd-hda-codec-id:10de0002"); MODULE_ALIAS("snd-hda-codec-id:10de0007"); +MODULE_ALIAS("snd-hda-codec-id:10de0067"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec"); -- cgit v1.2.3 From 4e7c4d7b6d980264194c2aecbbb1e1e4c7302b63 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Dec 2008 10:25:37 +0100 Subject: ALSA: hda - Add reference to HD-Audio.txt in ALSA-Configuration.txt Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 3cd2ad95817..3f2bdd533c3 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -778,6 +778,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. specify a certain model in such a case. There are different models depending on the codec chip. + See Documentation/sound/alsa/HD-Audio.txt for some details. + Model name Description ---------- ----------- ALC880 -- cgit v1.2.3 From e6e3ea25b1679b55728a8a470a50a8fff61e8a45 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 5 Dec 2008 12:54:56 +0100 Subject: ALSA: hda - Fix pin-detection in patch_sigmatel.c The pin-detection function used in patch_sigmatel.c shouldn't be specific to HP pin because it's used for input pins in general, too. This patch fixes the detection function, removes the HP check from it and moves to stac92xx_hp_detect(). Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index f98c7e99787..08170dff75e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4061,20 +4061,13 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, pin_ctl & ~flag); } -static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid) +static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) { if (!nid) return 0; if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00) - & (1 << 31)) { - unsigned int pinctl; - pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (pinctl & AC_PINCTL_IN_EN) - return 0; /* mic- or line-input */ - else - return 1; /* HP-output */ - } + & (1 << 31)) + return 1; return 0; } @@ -4114,7 +4107,14 @@ static void stac92xx_hp_detect(struct hda_codec *codec) break; if (no_hp_sensing(spec, i)) continue; - presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); + presence = get_pin_presence(codec, cfg->hp_pins[i]); + if (presence) { + unsigned int pinctl; + pinctl = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (pinctl & AC_PINCTL_IN_EN) + presence = 0; /* mic- or line-input */ + } } if (presence) { @@ -4191,7 +4191,7 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid) { - stac_toggle_power_map(codec, nid, get_hp_pin_presence(codec, nid)); + stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid)); } static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) @@ -4213,7 +4213,7 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) type = (pin_ctl & AC_PINCTL_HP_EN) ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT; snd_jack_report(jacks->jack, - get_hp_pin_presence(codec, nid) + get_pin_presence(codec, nid) ? type : 0); } jacks++; @@ -5349,7 +5349,7 @@ static int stac9872_vaio_init(struct hda_codec *codec) static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res) { - if (get_hp_pin_presence(codec, 0x0a)) { + if (get_pin_presence(codec, 0x0a)) { stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); } else { -- cgit v1.2.3 From 12dde4c6d6e9092cf63094e84dc1fe4e505dd6d0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 5 Dec 2008 13:09:27 +0100 Subject: ALSA: hda - Proper power-map toggling for input pins The current code overrides the event type on input pins always to PWR_EVENT. Although this still works (PWR_EVENT and INSERT_EVENT are handled samely), it'd be better to avoid such overrides. Also, currently the unsol events are registered even for fixed pins which will never raise the pin-detection event. This patch fixes both issues. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 08170dff75e..4c851fd5556 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3915,24 +3915,36 @@ static int stac92xx_init(struct hda_codec *codec) } else { stac92xx_auto_init_multi_out(codec); stac92xx_auto_init_hp_out(codec); + for (i = 0; i < cfg->hp_outs; i++) + stac_toggle_power_map(codec, cfg->hp_pins[i], 1); } for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = cfg->input_pins[i]; if (nid) { - unsigned int pinctl; + unsigned int pinctl, conf; if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) { /* for mic pins, force to initialize */ pinctl = stac92xx_get_vref(codec, nid); + pinctl |= AC_PINCTL_IN_EN; + stac92xx_auto_set_pinctl(codec, nid, pinctl); } else { pinctl = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); /* if PINCTL already set then skip */ - if (pinctl & AC_PINCTL_IN_EN) - continue; + if (!(pinctl & AC_PINCTL_IN_EN)) { + pinctl |= AC_PINCTL_IN_EN; + stac92xx_auto_set_pinctl(codec, nid, + pinctl); + } + } + conf = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) { + enable_pin_detect(codec, nid, + STAC_INSERT_EVENT); + stac_issue_unsol_event(codec, nid, + STAC_INSERT_EVENT); } - pinctl |= AC_PINCTL_IN_EN; - stac92xx_auto_set_pinctl(codec, nid, pinctl); - enable_pin_detect(codec, nid, STAC_INSERT_EVENT); } } for (i = 0; i < spec->num_dmics; i++) @@ -3969,8 +3981,10 @@ static int stac92xx_init(struct hda_codec *codec) stac_toggle_power_map(codec, nid, 1); continue; } - enable_pin_detect(codec, nid, STAC_PWR_EVENT); - stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT); + if (!stac_get_event(codec, nid, STAC_INSERT_EVENT)) { + enable_pin_detect(codec, nid, STAC_PWR_EVENT); + stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT); + } } if (spec->dac_list) stac92xx_power_down(codec); -- cgit v1.2.3 From 32e176c14d7a425b681ef003c9061001ddb7fc7b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 6 Dec 2008 15:09:08 +0100 Subject: Sound: hda - Restore PCI configuration space with interrupts off Move the restoration of the standard PCI configuration registers in the snd_hda_intel driver to a ->resume_early() callback executed with interrupts disabled, since doing that with interrupts enabled may lead to problems in some cases. This patch addresses the regression from 2.6.26 tracked as http://bugzilla.kernel.org/show_bug.cgi?id=12121 . Signed-off-by: Rafael J. Wysocki Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 35722ec920c..a06b0538fc9 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1951,13 +1951,16 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) return 0; } +static int azx_resume_early(struct pci_dev *pci) +{ + return pci_restore_state(pci); +} + static int azx_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct azx *chip = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); if (pci_enable_device(pci) < 0) { printk(KERN_ERR "hda-intel: pci_enable_device failed, " "disabling device\n"); @@ -2465,6 +2468,7 @@ static struct pci_driver driver = { .remove = __devexit_p(azx_remove), #ifdef CONFIG_PM .suspend = azx_suspend, + .resume_early = azx_resume_early, .resume = azx_resume, #endif }; -- cgit v1.2.3 From 30bc4481de890e97dc001ee123761d89638cbc50 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 9 Dec 2008 08:23:45 +0100 Subject: ALSA: Updates about bug-reporting in ALSA-Configuration.txt Updated the information about bug-reporting for HD-audio. Mentioned alsa-info.sh and kernel bugzilla. Removed ALSA BTS address not to flood the unhandled reports any more. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 3f2bdd533c3..1c7334a3054 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1091,8 +1091,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. "codec-patch". It's sometimes good for testing and debugging. If the default configuration doesn't work and one of the above - matches with your device, report it together with the PCI - subsystem ID (output of "lspci -nv") to ALSA BTS or alsa-devel + matches with your device, report it together with alsa-info.sh + output (with --no-upload option) to kernel bugzilla or alsa-devel ML (see the section "Links and Addresses"). power_save and power_save_controller options are for power-saving @@ -2409,8 +2409,11 @@ Links and Addresses ALSA project homepage http://www.alsa-project.org - ALSA Bug Tracking System - https://bugtrack.alsa-project.org/bugs/ + Kernel Bugzilla + http://bugzilla.kernel.org/ ALSA Developers ML mailto:alsa-devel@alsa-project.org + + alsa-info.sh script + http://www.alsa-project.org/alsa-info.sh -- cgit v1.2.3 From d2afbe78a2922929ad44882d3583d938b9949a30 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2008 09:28:15 +0100 Subject: ALSA: hda - Update documentation Minor typo-fixes and improvements on HD-Audio.txt. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 159 ++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 76 deletions(-) diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index e758f24017b..ca8187de52d 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -9,22 +9,25 @@ GENERAL HD-audio is the new standard on-board audio component on modern PCs after AC97. Although Linux has been supporting HD-audio since long time ago, there are often problems with new machines. A part of the -problem is broken BIOS, and rest is the driver implementation. This -document explains the trouble-shooting and debugging methods for the -HD-audio hardware. +problem is broken BIOS, and the rest is the driver implementation. +This document explains the brief trouble-shooting and debugging +methods for the HD-audio hardware. The HD-audio component consists of two parts: the controller chip and the codec chips on the HD-audio bus. Linux provides a single driver -for all controllers, snd-hda-intel. Since the HD-audio controllers -are supposed to be compatible, the single snd-hda-driver should work -in most cases. But, not surprisingly, there are known bugs and issues -specific to each controller type. The snd-hda-intel driver has a -bunch of workarounds for these as described below. +for all controllers, snd-hda-intel. Although the driver name contains +a word of a well-known harware vendor, it's not specific to it but for +all controller chips by other companies. Since the HD-audio +controllers are supposed to be compatible, the single snd-hda-driver +should work in most cases. But, not surprisingly, there are known +bugs and issues specific to each controller type. The snd-hda-intel +driver has a bunch of workarounds for these as described below. A controller may have multiple codecs. Usually you have one audio -codec and optionally one modem codec. In some cases, there can be -multiple audio codecs, e.g. for analog and digital outputs, but the -driver might not work properly. +codec and optionally one modem codec. In theory, there might be +multiple audio codecs, e.g. for analog and digital outputs, and the +driver might not work properly because of conflict of mixer elements. +This should be fixed in future if such hardware really exists. The snd-hda-intel driver has several different codec parsers depending on the codec. It has a generic parser as a fallback, but this @@ -48,15 +51,16 @@ DMA-Position Problem The most common problem of the controller is the inaccurate DMA pointer reporting. The DMA pointer for playback and capture can be read in two ways, either via a LPIB register or via a position-buffer -map. As default the driver tries to reads from the io-mapped -position-buffer, and falls back to LPIB if it appears unupdated. -However, this detection isn't perfect on some devices. In such a -case, you can change the default method via `position_fix` option. +map. As default the driver tries to read from the io-mapped +position-buffer, and falls back to LPIB if the position-buffer appears +dead. However, this detection isn't perfect on some devices. In such +a case, you can change the default method via `position_fix` option. `position_fix=1` means to use LPIB method explicitly. `position_fix=2` means to use the position-buffer. 0 is the default -value, the automatic check. If you get a problem of repeated sounds, -this option might help. +value, the automatic check and fallback to LPIB as described in the +above. If you get a problem of repeated sounds, this option might +help. In addition to that, every controller is known to be broken regarding the wake-up timing. It wakes up a few samples before actually @@ -67,9 +71,9 @@ via `bdl_pos_adj` option. When `bdl_pos_adj` is a negative value (as default), it's assigned to an appropriate value depending on the controller chip. For Intel -chip, it'd be 1 while it'd be 32 for others. Usually this works. +chips, it'd be 1 while it'd be 32 for others. Usually this works. Only in case it doesn't work and you get warning messages, you should -change to other values. +change this parameter to other values. Codec-Probing Problem @@ -77,13 +81,13 @@ Codec-Probing Problem A less often but a more severe problem is the codec probing. When BIOS reports the available codec slots wrongly, the driver gets confused and tries to access the non-existing codec slot. This often -results in the total screw-up, and destruct the further communication -with the codec chips. The symptom appears usually as the error -message like: +results in the total screw-up, and destructs the further communication +with the codec chips. The symptom appears usually as error messages +like: ------------------------------------------------------------------------ - hda_intel: azx_get_response timeout, switching to polling mode: \ + hda_intel: azx_get_response timeout, switching to polling mode: last cmd=0x12345678 - hda_intel: azx_get_response timeout, switching to single_cmd mode: \ + hda_intel: azx_get_response timeout, switching to single_cmd mode: last cmd=0x12345678 ------------------------------------------------------------------------ @@ -98,9 +102,9 @@ accessing a non-existing codec slot. Thus, if the second error message appears, try to narrow the probed codec slots via `probe_mask` option. It's a bitmask, and each bit -corresponding to the codec slot. For example, to probe only the -first slot, pass `probe_mask=1`. For the first and the third slots, -pass `probe_mask=5` (where 5 = 1 | 4), and so on. +corresponds to the codec slot. For example, to probe only the first +slot, pass `probe_mask=1`. For the first and the third slots, pass +`probe_mask=5` (where 5 = 1 | 4), and so on. Since 2.6.29 kernel, the driver has a more robust probing method, so this error might happen rarely, though. @@ -119,10 +123,10 @@ HD-AUDIO CODEC Model Option ~~~~~~~~~~~~ -The most common problems with the HD-audio driver is the unsupported -codec features or the mismatched device configuration. Most of -codec-specific code has several preset models, either to override the -BIOS setup or to provide more comprehensive features. +The most common problem regarding the HD-audio driver is the +unsupported codec features or the mismatched device configuration. +Most of codec-specific code has several preset models, either to +override the BIOS setup or to provide more comprehensive features. The driver checks PCI SSID and looks through the static configuration table until any matching entry is found. If you have a new machine, @@ -130,44 +134,44 @@ you may see a message like below: ------------------------------------------------------------------------ hda_codec: Unknown model for ALC880, trying auto-probe from BIOS... ------------------------------------------------------------------------ -Even if you such a message, DON'T PANIC. Take a deep breath (and keep -your towel). First of all, it's an informational message, no warning, -no error. This means that the PCI SSID of your device isn't listed in -the known preset model list. But, this doesn't mean that the driver -is broken. Many codec-driver provides the automatic configuration -based on the BIOS setup. +Even if you see such a message, DON'T PANIC. Take a deep breath and +keep your towel. First of all, it's an informational message, no +warning, no error. This means that the PCI SSID of your device isn't +listed in the known preset model (white-)list. But, this doesn't mean +that the driver is broken. Many codec-drivers provide the automatic +configuration mechanism based on the BIOS setup. The HD-audio codec has usually "pin" widgets, and BIOS sets the default configuration of each pin, which indicates the location, the connection type, the jack color, etc. The HD-audio driver can guess the right connection judging from these default configuration values. -However -- some codec support codes, such as patch_analog.c, don't +However -- some codec-support codes, such as patch_analog.c, don't support the automatic probing (yet as of 2.6.28). And, BIOS is often, yes, pretty often broken. It sets up wrong values and screws up the driver. -The preset model is provided basically to override such a situation. -When the matching preset model is found in the list, the driver +The preset model is provided basically to overcome such a situation. +When the matching preset model is found in the white-list, the driver assumes the static configuration of that preset and builds the mixer -and PCM based on the static information. Thus, if you have a newer -machine with a slightly different PCI SSID from the existing one, you -may have a good chance to re-use the same model. You can pass the -`model` option to specify the preset model instead of PCI SSID -look-up. +elements and PCM streams based on the static information. Thus, if +you have a newer machine with a slightly different PCI SSID from the +existing one, you may have a good chance to re-use the same model. +You can pass the `model` option to specify the preset model instead of +PCI SSID look-up. What `model` option values are available depends on the codec chip. Check your codec chip from the codec proc file (see "Codec Proc-File" section below). It will show the vendor/product name of your codec -chip. Then, see Documentation/sound/alsa/ALSA-Configuration.txt file. -In the section of HD-audio driver, you can find a list of codecs and -`model` options belonging to each codec. For example, for Realtek +chip. Then, see Documentation/sound/alsa/ALSA-Configuration.txt +file, the section of HD-audio driver. You can find a list of codecs +and `model` options belonging to each codec. For example, for Realtek ALC262 codec chip, pass `model=ultra` for devices that are compatible with Samsung Q1 Ultra. -Thus, the first thing you can do for any brand-new, unsupported -HD-audio hardware is to check HD-audio codec and several different -`model` option values. If you have a luck, some of them might suit -with your device well. +Thus, the first thing you can do for any brand-new, unsupported and +non-working HD-audio hardware is to check HD-audio codec and several +different `model` option values. If you have a luck, some of them +might suit with your device well. Some codecs such as ALC880 have a special model option `model=test`. This configures the driver to provide as many mixer controls as @@ -188,12 +192,14 @@ One of the most frequent (and obvious) bugs with HD-audio is the silent output from either or both of a built-in speaker and a headphone jack. In general, you should try a headphone output at first. A speaker output often requires more additional controls like -the amplifier. Thus a headphone output has a slightly better chance. +the external amplifier bits. Thus a headphone output has a slightly +better chance. Before making a bug report, double-check whether the mixer is set up correctly. The recent version of snd-hda-intel driver provides mostly -"Master" volume control as well as "Front" volume. In addition, there -are individual "Headphone" and "Speaker" controls. +"Master" volume control as well as "Front" volume (where Front +indicates the front-channels). In addition, there can be individual +"Headphone" and "Speaker" controls. Ditto for the speaker output. There can be "External Amplifier" switch on some codecs. Turn on this if present. @@ -214,7 +220,7 @@ following: external amplifier. This can be set usually via EAPD verb or a certain GPIO. If the codec pin supports EAPD, you have a better chance via SET_EAPD_BTL verb (0x70c). On others, GPIO pin (mostly - it's either GPIO0 or GPIO1) can turn on/off EAPD. + it's either GPIO0 or GPIO1) may turn on/off EAPD. - Some Realtek codecs require special vendor-specific coefficients to turn on the amplifier. See patch_realtek.c. - IDT codecs may have extra power-enable/disable controls on each @@ -227,29 +233,29 @@ following: Capture Problems ~~~~~~~~~~~~~~~~ -The capture problems are often missing setups of mixers. Thus, before -submitting a bug report, make sure that you set up the mixer -correctly. For example, both "Capture Volume" and "Capture Switch" -have to be set properly in addition to the right "Capture Source" or -"Input Source" selection. Some devices have "Mic Boost" volume or -switch. +The capture problems are often because of missing setups of mixers. +Thus, before submitting a bug report, make sure that you set up the +mixer correctly. For example, both "Capture Volume" and "Capture +Switch" have to be set properly in addition to the right "Capture +Source" or "Input Source" selection. Some devices have "Mic Boost" +volume or switch. When the PCM device is opened via "default" PCM (without pulse-audio plugin), you'll likely have "Digital Capture Volume" control as well. This is provided for the extra gain/attenuation of the signal in software, especially for the inputs without the hardware volume control such as digital microphones. Unless really needed, this -should be set to exactly 50%, corresponding to 0dB. When you use "hw" -PCM, i.e., a raw access PCM, this control will have no influence, -though. +should be set to exactly 50%, corresponding to 0dB -- neither extra +gain nor attenuation. When you use "hw" PCM, i.e., a raw access PCM, +this control will have no influence, though. It's known that some codecs / devices have fairly bad analog circuits, and the recorded sound contains a certain DC-offset. This is no bug of the driver. -Most of modern laptops have no analog CD-input connection. Thus, the +Most of modern laptops have no analog CD-input connection. Thus, the recording from CD input won't work in many cases although the driver -provides it as the capture source. +provides it as the capture source. Use CDDA instead. The automatic switching of the built-in and external mic per plugging is implemented on some codec models but not on every model. Partly @@ -264,7 +270,7 @@ to fight again the evil, try debugging via hitting the raw HD-audio codec verbs to the device. Some tools are available: hda-emu and hda-analyzer. The detailed description is found in the sections below. You'd need to enable hwdep for using these tools. See "Kernel -Configuration". +Configuration" section. OTHER ISSUES @@ -284,15 +290,16 @@ sure to want it. Don't forget to turn on the appropriate `CONFIG_SND_HDA_CODEC_*` options. Note that each of them corresponds to the codec chip, not the controller chip. Thus, even if lspci shows the Nvidia controller, -you may choose the option for other vendors. If you are unsure, just -choose all yes. +you may need to choose the option for other vendors. If you are +unsure, just select all yes. `CONFIG_SND_HDA_HWDEP` is a useful option for debugging the driver. When this is enabled, the driver creates hardware-dependent devices (one per each codec), and you have a raw access to the device via -hda-verb program. For example, `hwC0D2` will be created for the card -0 codec slot #2. For debug tools such as hda-verb and hda-analyzer, -the hwdep device has to be enabled. Thus, turn this on always. +these device files. For example, `hwC0D2` will be created for the +codec slot #2 of the first card (#0). For debug-tools such as +hda-verb and hda-analyzer, the hwdep device has to be enabled. +Thus, it'd be better to turn this on always. `CONFIG_SND_HDA_RECONFIG` is a new option, and this depends on the hwdep option above. When enabled, you'll have some sysfs files under @@ -436,7 +443,7 @@ details. hda-verb ~~~~~~~~ hda-verb is a tiny program that allows you to access the HD-audio -codec directly. It executes a HD-audio codec verb directly. +codec directly. You can execute a raw HD-audio codec verb with this. This program accesses the hwdep device, thus you need to enable the kernel config `CONFIG_SND_HDA_HWDEP=y` beforehand. @@ -486,7 +493,7 @@ hda-analyzer ~~~~~~~~~~~~ hda-analyzer provides a graphical interface to access the raw HD-audio control, based on pyGTK2 binding. It's a more powerful version of -hda-verb. The program gives you a easy-to-use GUI stuff for showing +hda-verb. The program gives you an easy-to-use GUI stuff for showing the widget information and adjusting the amp values, as well as the proc-compatible output. @@ -498,7 +505,7 @@ alsa-project.org: hda-emu ~~~~~~~ -hda-emu is a HD-audio emulator. The main purpose of this program is +hda-emu is an HD-audio emulator. The main purpose of this program is to debug an HD-audio codec without the real hardware. Thus, it doesn't emulate the behavior with the real audio I/O, but it just dumps the codec register changes and the ALSA-driver internal changes -- cgit v1.2.3 From 11d518e07d700eeb5bcec36bfd5f501e405230dd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2008 10:37:33 +0100 Subject: ALSA: hda - Add quirk for HP6730B laptop Added model=laptop for HP 6730B laptop with AD1984A codec. Reference: Novell bnc#457909 https://bugzilla.novell.com/show_bug.cgi?id=457909 Signed-off-by: Takashi Iwai Cc: stable@kernel.org --- sound/pci/hda/patch_analog.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index c1918a1a6df..26247cfe749 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -3901,6 +3901,7 @@ static const char *ad1884a_models[AD1884A_MODELS] = { static struct snd_pci_quirk ad1884a_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP), SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP), SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP), SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), -- cgit v1.2.3 From 623b9f6738dee0394398564a74fdabbff00f506f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Dec 2008 07:44:18 +0100 Subject: ALSA: hda - Update HD-Audio.txt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed typos and added a section about codecgraph. Thanks to Vedran Miletić and Daniel T Chen for suggestions. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index ca8187de52d..ee9117eee1a 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -266,7 +266,7 @@ submit the improvement patch to the author. Direct Debugging ~~~~~~~~~~~~~~~~ If no model option gives you a better result, and you are a touch guy -to fight again the evil, try debugging via hitting the raw HD-audio +to fight against evil, try debugging via hitting the raw HD-audio codec verbs to the device. Some tools are available: hda-emu and hda-analyzer. The detailed description is found in the sections below. You'd need to enable hwdep for using these tools. See "Kernel @@ -389,7 +389,7 @@ power-down/up depending on the device. Some of them might be solvable, but some are hard, I'm afraid. Some distros such as openSUSE enables the power-saving feature automatically when the power cable is unplugged. Thus, if you hear noises, suspect first the -power-saving. See /sys/modules/snd_hda_intel/parameters/power_save to +power-saving. See /sys/module/snd_hda_intel/parameters/power_save to check the current value. If it's non-zero, the feature is turned on. @@ -503,6 +503,19 @@ alsa-project.org: - http://git.alsa-project.org/?p=alsa.git;a=tree;f=hda-analyzer +Codecgraph +~~~~~~~~~~ +Codecgraph is a utility program to generate a graph and visualizes the +codec-node connection of a codec chip. It's especially useful when +you analyze or debug a codec without a proper datasheet. The program +parses the given codec proc file and converts to SVG via graphiz +program. + +The tarball and GIT trees are found in the web page at: + +- http://helllabs.org/codecgraph/ + + hda-emu ~~~~~~~ hda-emu is an HD-audio emulator. The main purpose of this program is -- cgit v1.2.3 From 5c0b9bec460c348d2ee5a800c288e5d0e8fcda66 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Dec 2008 11:47:17 +0100 Subject: ALSA: hda - Fix a compile warning when CONFIG_PM=n MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed the compile warning regarding the unused function when built with CONFIG_PM=n: sound/pci/hda/hda_intel.c:1905: warning: ‘snd_hda_codecs_inuse’ defined but not used snd_hda_codecs_inuse() is used only in the resume callback. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 8aee322313e..f2337e4eddd 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1900,6 +1900,12 @@ static void azx_power_notify(struct hda_bus *bus) else if (chip->running && power_save_controller) azx_stop_chip(chip); } +#endif /* CONFIG_SND_HDA_POWER_SAVE */ + +#ifdef CONFIG_PM +/* + * power management + */ static int snd_hda_codecs_inuse(struct hda_bus *bus) { @@ -1911,14 +1917,7 @@ static int snd_hda_codecs_inuse(struct hda_bus *bus) } return 0; } -#else /* !CONFIG_SND_HDA_POWER_SAVE */ -#define snd_hda_codecs_inuse(bus) 1 -#endif /* CONFIG_SND_HDA_POWER_SAVE */ -#ifdef CONFIG_PM -/* - * power management - */ static int azx_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); -- cgit v1.2.3 From f8bbd06b17f16984328398cdecdf9302ef9bb0bf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Dec 2008 13:12:59 +0100 Subject: ALSA: hda - Fix another typo in HD-Audio.txt --- Documentation/sound/alsa/HD-Audio.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index ee9117eee1a..2e4d031ea1f 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -265,7 +265,7 @@ submit the improvement patch to the author. Direct Debugging ~~~~~~~~~~~~~~~~ -If no model option gives you a better result, and you are a touch guy +If no model option gives you a better result, and you are a tough guy to fight against evil, try debugging via hitting the raw HD-audio codec verbs to the device. Some tools are available: hda-emu and hda-analyzer. The detailed description is found in the sections -- cgit v1.2.3 From 132bb7c0efe82fc976b06d557f5d63536cb9fdaa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Dec 2008 15:39:52 +0100 Subject: ALSA: hda - Add development tree URLs in HD-audio.txt Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 2e4d031ea1f..642a2b01254 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -393,6 +393,28 @@ power-saving. See /sys/module/snd_hda_intel/parameters/power_save to check the current value. If it's non-zero, the feature is turned on. +Development Tree +~~~~~~~~~~~~~~~~ +The latest development codes for HD-audio are found on sound git tree: + +- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git + +The master branch or for-next branches can be used as the main +development branches in general while the HD-audio specific patches +are committed in topic/hda branch. + +If you are using the latest Linus tree, it'd be better to pull the +above GIT tree onto it. If you are using the older kernels, an easy +way to try the latest ALSA code is to build from the snapshot +tarball. There are daily tarballs and the latest snapshot tarball. +All can be built just like normal alsa-driver release packages, that +is, installed via the usual spells: configure, make and make +install(-modules). See INSTALL in the package. The snapshot tarballs +are found at: + +- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/snapshot/ + + Sending a Bug Report ~~~~~~~~~~~~~~~~~~~~ If any model or module options don't work for your device, it's time -- cgit v1.2.3 From 31117b78ee843622cbc4c7c17c97be417c766385 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 16 Dec 2008 14:43:21 +0100 Subject: ALSA: hda - Add Nvidia vendor id string Added Nvidia (0x10de) to the vendor id list. Cleaned up the codec name strings accordingly. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 + sound/pci/hda/patch_nvhdmi.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d49d0b69868..f6832e16068 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -46,6 +46,7 @@ static struct hda_vendor_id hda_vendor_ids[] = { { 0x1002, "ATI" }, { 0x1057, "Motorola" }, { 0x1095, "Silicon Image" }, + { 0x10de, "Nvidia" }, { 0x10ec, "Realtek" }, { 0x1106, "VIA" }, { 0x111d, "IDT" }, diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 0cd53063e62..0270fda0bda 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -159,9 +159,9 @@ static int patch_nvhdmi(struct hda_codec *codec) * patch entries */ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { - { .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi }, - { .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi }, - { .id = 0x10de0067, .name = "NVIDIA MCP67 HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi }, {} /* terminator */ }; -- cgit v1.2.3 From 74c611334ff131f2b87c7634314bde9e7fd98653 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 18 Dec 2008 09:11:33 +0100 Subject: ALSA: hda - Add Intel vendor id string Added Intel codec vendor id string (0x8086). Also fixed Intel-HDMI codec name strings, too. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 + sound/pci/hda/patch_intelhdmi.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f6832e16068..8459d6ba205 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -58,6 +58,7 @@ static struct hda_vendor_id hda_vendor_ids[] = { { 0x1854, "LG" }, { 0x1aec, "Wolfson Microelectronics" }, { 0x434d, "C-Media" }, + { 0x8086, "Intel" }, { 0x8384, "SigmaTel" }, {} /* terminator */ }; diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 290da562f29..3564f4e4b74 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -675,10 +675,10 @@ static int patch_intel_hdmi(struct hda_codec *codec) } static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { - { .id = 0x808629fb, .name = "INTEL G45 DEVCL", .patch = patch_intel_hdmi }, - { .id = 0x80862801, .name = "INTEL G45 DEVBLC", .patch = patch_intel_hdmi }, - { .id = 0x80862802, .name = "INTEL G45 DEVCTG", .patch = patch_intel_hdmi }, - { .id = 0x80862803, .name = "INTEL G45 DEVELK", .patch = patch_intel_hdmi }, + { .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi }, + { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, + { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, + { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, {} /* terminator */ }; -- cgit v1.2.3 From 3218c178b41b420cb7e0d120c7a137a3969242e5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 18 Dec 2008 09:17:56 +0100 Subject: ALSA: hda - Remove duplicated strings from codec name Remove codec vendor names from the codec name strings. The vendor name is already given from the vendor name table, so displayed doubly. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_atihdmi.c | 8 ++--- sound/pci/hda/patch_via.c | 72 +++++++++++++++++++++---------------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index 5887b827bb3..233e4778bba 100644 --- a/sound/pci/hda/patch_atihdmi.c +++ b/sound/pci/hda/patch_atihdmi.c @@ -187,10 +187,10 @@ static int patch_atihdmi(struct hda_codec *codec) * patch entries */ static struct hda_codec_preset snd_hda_preset_atihdmi[] = { - { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, - { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, - { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi }, - { .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi }, + { .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi }, + { .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi }, + { .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi }, + { .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi }, { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi }, { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi }, {} /* terminator */ diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 6e4d01d1d50..c761394cbe8 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -3249,73 +3249,73 @@ static int patch_vt1702(struct hda_codec *codec) * patch entries */ static struct hda_codec_preset snd_hda_preset_via[] = { - { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708}, - { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708}, - { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708}, - { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708}, - { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", + { .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708}, + { .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708}, + { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708}, + { .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708}, + { .id = 0x1106e710, .name = "VT1709 10-Ch", .patch = patch_vt1709_10ch}, - { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", + { .id = 0x1106e711, .name = "VT1709 10-Ch", .patch = patch_vt1709_10ch}, - { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", + { .id = 0x1106e712, .name = "VT1709 10-Ch", .patch = patch_vt1709_10ch}, - { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", + { .id = 0x1106e713, .name = "VT1709 10-Ch", .patch = patch_vt1709_10ch}, - { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", + { .id = 0x1106e714, .name = "VT1709 6-Ch", .patch = patch_vt1709_6ch}, - { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", + { .id = 0x1106e715, .name = "VT1709 6-Ch", .patch = patch_vt1709_6ch}, - { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", + { .id = 0x1106e716, .name = "VT1709 6-Ch", .patch = patch_vt1709_6ch}, - { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", + { .id = 0x1106e717, .name = "VT1709 6-Ch", .patch = patch_vt1709_6ch}, - { .id = 0x1106E720, .name = "VIA VT1708B 8-Ch", + { .id = 0x1106e720, .name = "VT1708B 8-Ch", .patch = patch_vt1708B_8ch}, - { .id = 0x1106E721, .name = "VIA VT1708B 8-Ch", + { .id = 0x1106e721, .name = "VT1708B 8-Ch", .patch = patch_vt1708B_8ch}, - { .id = 0x1106E722, .name = "VIA VT1708B 8-Ch", + { .id = 0x1106e722, .name = "VT1708B 8-Ch", .patch = patch_vt1708B_8ch}, - { .id = 0x1106E723, .name = "VIA VT1708B 8-Ch", + { .id = 0x1106e723, .name = "VT1708B 8-Ch", .patch = patch_vt1708B_8ch}, - { .id = 0x1106E724, .name = "VIA VT1708B 4-Ch", + { .id = 0x1106e724, .name = "VT1708B 4-Ch", .patch = patch_vt1708B_4ch}, - { .id = 0x1106E725, .name = "VIA VT1708B 4-Ch", + { .id = 0x1106e725, .name = "VT1708B 4-Ch", .patch = patch_vt1708B_4ch}, - { .id = 0x1106E726, .name = "VIA VT1708B 4-Ch", + { .id = 0x1106e726, .name = "VT1708B 4-Ch", .patch = patch_vt1708B_4ch}, - { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch", + { .id = 0x1106e727, .name = "VT1708B 4-Ch", .patch = patch_vt1708B_4ch}, - { .id = 0x11060397, .name = "VIA VT1708S", + { .id = 0x11060397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11061397, .name = "VIA VT1708S", + { .id = 0x11061397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11062397, .name = "VIA VT1708S", + { .id = 0x11062397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11063397, .name = "VIA VT1708S", + { .id = 0x11063397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11064397, .name = "VIA VT1708S", + { .id = 0x11064397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11065397, .name = "VIA VT1708S", + { .id = 0x11065397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11066397, .name = "VIA VT1708S", + { .id = 0x11066397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11067397, .name = "VIA VT1708S", + { .id = 0x11067397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11060398, .name = "VIA VT1702", + { .id = 0x11060398, .name = "VT1702", .patch = patch_vt1702}, - { .id = 0x11061398, .name = "VIA VT1702", + { .id = 0x11061398, .name = "VT1702", .patch = patch_vt1702}, - { .id = 0x11062398, .name = "VIA VT1702", + { .id = 0x11062398, .name = "VT1702", .patch = patch_vt1702}, - { .id = 0x11063398, .name = "VIA VT1702", + { .id = 0x11063398, .name = "VT1702", .patch = patch_vt1702}, - { .id = 0x11064398, .name = "VIA VT1702", + { .id = 0x11064398, .name = "VT1702", .patch = patch_vt1702}, - { .id = 0x11065398, .name = "VIA VT1702", + { .id = 0x11065398, .name = "VT1702", .patch = patch_vt1702}, - { .id = 0x11066398, .name = "VIA VT1702", + { .id = 0x11066398, .name = "VT1702", .patch = patch_vt1702}, - { .id = 0x11067398, .name = "VIA VT1702", + { .id = 0x11067398, .name = "VT1702", .patch = patch_vt1702}, {} /* terminator */ }; -- cgit v1.2.3 From cae51176c1082ecb59706056910f8a217d433981 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 08:36:53 +0100 Subject: ALSA: split HD-audio model list to HD-Audio-Models.txt Split the list of model option values to a separate file, HD-Audio-Models.txt, from ALSA-Configuration.txt. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 323 +--------------------- Documentation/sound/alsa/HD-Audio-Models.txt | 348 ++++++++++++++++++++++++ 2 files changed, 353 insertions(+), 318 deletions(-) create mode 100644 Documentation/sound/alsa/HD-Audio-Models.txt diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index d5b6b117103..a4f3a22caba 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -772,328 +772,15 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. This module supports multiple cards and autoprobe. + See Documentation/sound/alsa/HD-Audio.txt for more details about + HD-audio driver. + Each codec may have a model table for different configurations. If your machine isn't listed there, the default (usually minimal) configuration is set up. You can pass "model=" option to specify a certain model in such a case. There are different - models depending on the codec chip. - - See Documentation/sound/alsa/HD-Audio.txt for some details. - - Model name Description - ---------- ----------- - ALC880 - 3stack 3-jack in back and a headphone out - 3stack-digout 3-jack in back, a HP out and a SPDIF out - 5stack 5-jack in back, 2-jack in front - 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out - 6stack 6-jack in back, 2-jack in front - 6stack-digout 6-jack with a SPDIF out - w810 3-jack - z71v 3-jack (HP shared SPDIF) - asus 3-jack (ASUS Mobo) - asus-w1v ASUS W1V - asus-dig ASUS with SPDIF out - asus-dig2 ASUS with SPDIF out (using GPIO2) - uniwill 3-jack - fujitsu Fujitsu Laptops (Pi1536) - F1734 2-jack - lg LG laptop (m1 express dual) - lg-lw LG LW20/LW25 laptop - tcl TCL S700 - clevo Clevo laptops (m520G, m665n) - medion Medion Rim 2150 - test for testing/debugging purpose, almost all controls can be - adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - auto auto-config reading BIOS (default) - - ALC260 - hp HP machines - hp-3013 HP machines (3013-variant) - hp-dc7600 HP DC7600 - fujitsu Fujitsu S7020 - acer Acer TravelMate - will Will laptops (PB V7900) - replacer Replacer 672V - basic fixed pin assignment (old default model) - test for testing/debugging purpose, almost all controls can - adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - auto auto-config reading BIOS (default) - - ALC262 - fujitsu Fujitsu Laptop - hp-bpc HP xw4400/6400/8400/9400 laptops - hp-bpc-d7000 HP BPC D7000 - hp-tc-t5735 HP Thin Client T5735 - hp-rp5700 HP RP5700 - benq Benq ED8 - benq-t31 Benq T31 - hippo Hippo (ATI) with jack detection, Sony UX-90s - hippo_1 Hippo (Benq) with jack detection - sony-assamd Sony ASSAMD - toshiba-s06 Toshiba S06 - toshiba-rx1 Toshiba RX1 - ultra Samsung Q1 Ultra Vista model - lenovo-3000 Lenovo 3000 y410 - nec NEC Versa S9100 - basic fixed pin assignment w/o SPDIF - auto auto-config reading BIOS (default) - - ALC267/268 - quanta-il1 Quanta IL1 mini-notebook - 3stack 3-stack model - toshiba Toshiba A205 - acer Acer laptops - acer-dmic Acer laptops with digital-mic - acer-aspire Acer Aspire One - dell Dell OEM laptops (Vostro 1200) - zepto Zepto laptops - test for testing/debugging purpose, almost all controls can - adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - auto auto-config reading BIOS (default) - - ALC269 - basic Basic preset - quanta Quanta FL1 - eeepc-p703 ASUS Eeepc P703 P900A - eeepc-p901 ASUS Eeepc P901 S101 - fujitsu FSC Amilo - auto auto-config reading BIOS (default) - - ALC662/663 - 3stack-dig 3-stack (2-channel) with SPDIF - 3stack-6ch 3-stack (6-channel) - 3stack-6ch-dig 3-stack (6-channel) with SPDIF - 6stack-dig 6-stack with SPDIF - lenovo-101e Lenovo laptop - eeepc-p701 ASUS Eeepc P701 - eeepc-ep20 ASUS Eeepc EP20 - ecs ECS/Foxconn mobo - m51va ASUS M51VA - g71v ASUS G71V - h13 ASUS H13 - g50v ASUS G50V - asus-mode1 ASUS - asus-mode2 ASUS - asus-mode3 ASUS - asus-mode4 ASUS - asus-mode5 ASUS - asus-mode6 ASUS - auto auto-config reading BIOS (default) - - ALC882/885 - 3stack-dig 3-jack with SPDIF I/O - 6stack-dig 6-jack digital with SPDIF I/O - arima Arima W820Di1 - targa Targa T8, MSI-1049 T8 - asus-a7j ASUS A7J - asus-a7m ASUS A7M - macpro MacPro support - mbp3 Macbook Pro rev3 - imac24 iMac 24'' with jack detection - w2jc ASUS W2JC - auto auto-config reading BIOS (default) - - ALC883/888 - 3stack-dig 3-jack with SPDIF I/O - 6stack-dig 6-jack digital with SPDIF I/O - 3stack-6ch 3-jack 6-channel - 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O - 6stack-dig-demo 6-jack digital for Intel demo board - acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) - acer-aspire Acer Aspire 9810 - acer-aspire-4930g Acer Aspire 4930G - medion Medion Laptops - medion-md2 Medion MD2 - targa-dig Targa/MSI - targa-2ch-dig Targs/MSI with 2-channel - laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) - lenovo-101e Lenovo 101E - lenovo-nb0763 Lenovo NB0763 - lenovo-ms7195-dig Lenovo MS7195 - lenovo-sky Lenovo Sky - haier-w66 Haier W66 - 3stack-hp HP machines with 3stack (Lucknow, Samba boards) - 6stack-dell Dell machines with 6stack (Inspiron 530) - mitac Mitac 8252D - clevo-m720 Clevo M720 laptop series - fujitsu-pi2515 Fujitsu AMILO Pi2515 - fujitsu-xa3530 Fujitsu AMILO XA3530 - 3stack-6ch-intel Intel DG33* boards - auto auto-config reading BIOS (default) - - ALC861/660 - 3stack 3-jack - 3stack-dig 3-jack with SPDIF I/O - 6stack-dig 6-jack with SPDIF I/O - 3stack-660 3-jack (for ALC660) - uniwill-m31 Uniwill M31 laptop - toshiba Toshiba laptop support - asus Asus laptop support - asus-laptop ASUS F2/F3 laptops - auto auto-config reading BIOS (default) - - ALC861VD/660VD - 3stack 3-jack - 3stack-dig 3-jack with SPDIF OUT - 6stack-dig 6-jack with SPDIF OUT - 3stack-660 3-jack (for ALC660VD) - 3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD) - lenovo Lenovo 3000 C200 - dallas Dallas laptops - hp HP TX1000 - asus-v1s ASUS V1Sn - auto auto-config reading BIOS (default) - - CMI9880 - minimal 3-jack in back - min_fp 3-jack in back, 2-jack in front - full 6-jack in back, 2-jack in front - full_dig 6-jack in back, 2-jack in front, SPDIF I/O - allout 5-jack in back, 2-jack in front, SPDIF out - auto auto-config reading BIOS (default) - - AD1882 / AD1882A - 3stack 3-stack mode (default) - 6stack 6-stack mode - - AD1884A / AD1883 / AD1984A / AD1984B - desktop 3-stack desktop (default) - laptop laptop with HP jack sensing - mobile mobile devices with HP jack sensing - thinkpad Lenovo Thinkpad X300 - - AD1884 - N/A - - AD1981 - basic 3-jack (default) - hp HP nx6320 - thinkpad Lenovo Thinkpad T60/X60/Z60 - toshiba Toshiba U205 - - AD1983 - N/A - - AD1984 - basic default configuration - thinkpad Lenovo Thinkpad T61/X61 - dell Dell T3400 - - AD1986A - 6stack 6-jack, separate surrounds (default) - 3stack 3-stack, shared surrounds - laptop 2-channel only (FSC V2060, Samsung M50) - laptop-eapd 2-channel with EAPD (ASUS A6J) - laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) - ultra 2-channel with EAPD (Samsung Ultra tablet PC) - samsung 2-channel with EAPD (Samsung R65) - - AD1988/AD1988B/AD1989A/AD1989B - 6stack 6-jack - 6stack-dig ditto with SPDIF - 3stack 3-jack - 3stack-dig ditto with SPDIF - laptop 3-jack with hp-jack automute - laptop-dig ditto with SPDIF - auto auto-config reading BIOS (default) - - Conexant 5045 - laptop-hpsense Laptop with HP sense (old model laptop) - laptop-micsense Laptop with Mic sense (old model fujitsu) - laptop-hpmicsense Laptop with HP and Mic senses - benq Benq R55E - test for testing/debugging purpose, almost all controls - can be adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - - Conexant 5047 - laptop Basic Laptop config - laptop-hp Laptop config for some HP models (subdevice 30A5) - laptop-eapd Laptop config with EAPD support - test for testing/debugging purpose, almost all controls - can be adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - - Conexant 5051 - laptop Basic Laptop config (default) - hp HP Spartan laptop - - STAC9200 - ref Reference board - dell-d21 Dell (unknown) - dell-d22 Dell (unknown) - dell-d23 Dell (unknown) - dell-m21 Dell Inspiron 630m, Dell Inspiron 640m - dell-m22 Dell Latitude D620, Dell Latitude D820 - dell-m23 Dell XPS M1710, Dell Precision M90 - dell-m24 Dell Latitude 120L - dell-m25 Dell Inspiron E1505n - dell-m26 Dell Inspiron 1501 - dell-m27 Dell Inspiron E1705/9400 - gateway Gateway laptops with EAPD control - panasonic Panasonic CF-74 - - STAC9205/9254 - ref Reference board - dell-m42 Dell (unknown) - dell-m43 Dell Precision - dell-m44 Dell Inspiron - - STAC9220/9221 - ref Reference board - 3stack D945 3stack - 5stack D945 5stack + SPDIF - intel-mac-v1 Intel Mac Type 1 - intel-mac-v2 Intel Mac Type 2 - intel-mac-v3 Intel Mac Type 3 - intel-mac-v4 Intel Mac Type 4 - intel-mac-v5 Intel Mac Type 5 - intel-mac-auto Intel Mac (detect type according to subsystem id) - macmini Intel Mac Mini (equivalent with type 3) - macbook Intel Mac Book (eq. type 5) - macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3) - macbook-pro Intel Mac Book Pro 2nd generation (eq. type 3) - imac-intel Intel iMac (eq. type 2) - imac-intel-20 Intel iMac (newer version) (eq. type 3) - dell-d81 Dell (unknown) - dell-d82 Dell (unknown) - dell-m81 Dell (unknown) - dell-m82 Dell XPS M1210 - - STAC9202/9250/9251 - ref Reference board, base config - m2-2 Some Gateway MX series laptops - m6 Some Gateway NX series laptops - pa6 Gateway NX860 series - - STAC9227/9228/9229/927x - ref Reference board - ref-no-jd Reference board without HP/Mic jack detection - 3stack D965 3stack - 5stack D965 5stack + SPDIF - dell-3stack Dell Dimension E520 - dell-bios Fixes with Dell BIOS setup - - STAC92HD71B* - ref Reference board - dell-m4-1 Dell desktops - dell-m4-2 Dell desktops - dell-m4-3 Dell desktops - - STAC92HD73* - ref Reference board - no-jd BIOS setup but without jack-detection - dell-m6-amic Dell desktops/laptops with analog mics - dell-m6-dmic Dell desktops/laptops with digital mics - dell-m6 Dell desktops/laptops with both type of mics - - STAC9872 - vaio Setup for VAIO FE550G/SZ110 - vaio-ar Setup for VAIO AR + models depending on the codec chip. The list of available models + is found in HD-Audio-Models.txt The model name "genric" is treated as a special case. When this model is given, the driver uses the generic codec parser without diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt new file mode 100644 index 00000000000..4b7ac21ea9e --- /dev/null +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -0,0 +1,348 @@ + Model name Description + ---------- ----------- +ALC880 +====== + 3stack 3-jack in back and a headphone out + 3stack-digout 3-jack in back, a HP out and a SPDIF out + 5stack 5-jack in back, 2-jack in front + 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out + 6stack 6-jack in back, 2-jack in front + 6stack-digout 6-jack with a SPDIF out + w810 3-jack + z71v 3-jack (HP shared SPDIF) + asus 3-jack (ASUS Mobo) + asus-w1v ASUS W1V + asus-dig ASUS with SPDIF out + asus-dig2 ASUS with SPDIF out (using GPIO2) + uniwill 3-jack + fujitsu Fujitsu Laptops (Pi1536) + F1734 2-jack + lg LG laptop (m1 express dual) + lg-lw LG LW20/LW25 laptop + tcl TCL S700 + clevo Clevo laptops (m520G, m665n) + medion Medion Rim 2150 + test for testing/debugging purpose, almost all controls can be + adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + auto auto-config reading BIOS (default) + +ALC260 +====== + hp HP machines + hp-3013 HP machines (3013-variant) + hp-dc7600 HP DC7600 + fujitsu Fujitsu S7020 + acer Acer TravelMate + will Will laptops (PB V7900) + replacer Replacer 672V + basic fixed pin assignment (old default model) + test for testing/debugging purpose, almost all controls can + adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + auto auto-config reading BIOS (default) + +ALC262 +====== + fujitsu Fujitsu Laptop + hp-bpc HP xw4400/6400/8400/9400 laptops + hp-bpc-d7000 HP BPC D7000 + hp-tc-t5735 HP Thin Client T5735 + hp-rp5700 HP RP5700 + benq Benq ED8 + benq-t31 Benq T31 + hippo Hippo (ATI) with jack detection, Sony UX-90s + hippo_1 Hippo (Benq) with jack detection + sony-assamd Sony ASSAMD + toshiba-s06 Toshiba S06 + toshiba-rx1 Toshiba RX1 + ultra Samsung Q1 Ultra Vista model + lenovo-3000 Lenovo 3000 y410 + nec NEC Versa S9100 + basic fixed pin assignment w/o SPDIF + auto auto-config reading BIOS (default) + +ALC267/268 +========== + quanta-il1 Quanta IL1 mini-notebook + 3stack 3-stack model + toshiba Toshiba A205 + acer Acer laptops + acer-dmic Acer laptops with digital-mic + acer-aspire Acer Aspire One + dell Dell OEM laptops (Vostro 1200) + zepto Zepto laptops + test for testing/debugging purpose, almost all controls can + adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + auto auto-config reading BIOS (default) + +ALC269 +====== + basic Basic preset + quanta Quanta FL1 + eeepc-p703 ASUS Eeepc P703 P900A + eeepc-p901 ASUS Eeepc P901 S101 + fujitsu FSC Amilo + auto auto-config reading BIOS (default) + +ALC662/663 +========== + 3stack-dig 3-stack (2-channel) with SPDIF + 3stack-6ch 3-stack (6-channel) + 3stack-6ch-dig 3-stack (6-channel) with SPDIF + 6stack-dig 6-stack with SPDIF + lenovo-101e Lenovo laptop + eeepc-p701 ASUS Eeepc P701 + eeepc-ep20 ASUS Eeepc EP20 + ecs ECS/Foxconn mobo + m51va ASUS M51VA + g71v ASUS G71V + h13 ASUS H13 + g50v ASUS G50V + asus-mode1 ASUS + asus-mode2 ASUS + asus-mode3 ASUS + asus-mode4 ASUS + asus-mode5 ASUS + asus-mode6 ASUS + auto auto-config reading BIOS (default) + +ALC882/885 +========== + 3stack-dig 3-jack with SPDIF I/O + 6stack-dig 6-jack digital with SPDIF I/O + arima Arima W820Di1 + targa Targa T8, MSI-1049 T8 + asus-a7j ASUS A7J + asus-a7m ASUS A7M + macpro MacPro support + mbp3 Macbook Pro rev3 + imac24 iMac 24'' with jack detection + w2jc ASUS W2JC + auto auto-config reading BIOS (default) + +ALC883/888 +========== + 3stack-dig 3-jack with SPDIF I/O + 6stack-dig 6-jack digital with SPDIF I/O + 3stack-6ch 3-jack 6-channel + 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O + 6stack-dig-demo 6-jack digital for Intel demo board + acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) + acer-aspire Acer Aspire 9810 + acer-aspire-4930g Acer Aspire 4930G + medion Medion Laptops + medion-md2 Medion MD2 + targa-dig Targa/MSI + targa-2ch-dig Targs/MSI with 2-channel + laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) + lenovo-101e Lenovo 101E + lenovo-nb0763 Lenovo NB0763 + lenovo-ms7195-dig Lenovo MS7195 + lenovo-sky Lenovo Sky + haier-w66 Haier W66 + 3stack-hp HP machines with 3stack (Lucknow, Samba boards) + 6stack-dell Dell machines with 6stack (Inspiron 530) + mitac Mitac 8252D + clevo-m720 Clevo M720 laptop series + fujitsu-pi2515 Fujitsu AMILO Pi2515 + fujitsu-xa3530 Fujitsu AMILO XA3530 + 3stack-6ch-intel Intel DG33* boards + auto auto-config reading BIOS (default) + +ALC861/660 +========== + 3stack 3-jack + 3stack-dig 3-jack with SPDIF I/O + 6stack-dig 6-jack with SPDIF I/O + 3stack-660 3-jack (for ALC660) + uniwill-m31 Uniwill M31 laptop + toshiba Toshiba laptop support + asus Asus laptop support + asus-laptop ASUS F2/F3 laptops + auto auto-config reading BIOS (default) + +ALC861VD/660VD +============== + 3stack 3-jack + 3stack-dig 3-jack with SPDIF OUT + 6stack-dig 6-jack with SPDIF OUT + 3stack-660 3-jack (for ALC660VD) + 3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD) + lenovo Lenovo 3000 C200 + dallas Dallas laptops + hp HP TX1000 + asus-v1s ASUS V1Sn + auto auto-config reading BIOS (default) + +CMI9880 +======= + minimal 3-jack in back + min_fp 3-jack in back, 2-jack in front + full 6-jack in back, 2-jack in front + full_dig 6-jack in back, 2-jack in front, SPDIF I/O + allout 5-jack in back, 2-jack in front, SPDIF out + auto auto-config reading BIOS (default) + +AD1882 / AD1882A +================ + 3stack 3-stack mode (default) + 6stack 6-stack mode + +AD1884A / AD1883 / AD1984A / AD1984B +==================================== + desktop 3-stack desktop (default) + laptop laptop with HP jack sensing + mobile mobile devices with HP jack sensing + thinkpad Lenovo Thinkpad X300 + +AD1884 +====== + N/A + +AD1981 +====== + basic 3-jack (default) + hp HP nx6320 + thinkpad Lenovo Thinkpad T60/X60/Z60 + toshiba Toshiba U205 + +AD1983 +====== + N/A + +AD1984 +====== + basic default configuration + thinkpad Lenovo Thinkpad T61/X61 + dell Dell T3400 + +AD1986A +======= + 6stack 6-jack, separate surrounds (default) + 3stack 3-stack, shared surrounds + laptop 2-channel only (FSC V2060, Samsung M50) + laptop-eapd 2-channel with EAPD (ASUS A6J) + laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) + ultra 2-channel with EAPD (Samsung Ultra tablet PC) + samsung 2-channel with EAPD (Samsung R65) + +AD1988/AD1988B/AD1989A/AD1989B +============================== + 6stack 6-jack + 6stack-dig ditto with SPDIF + 3stack 3-jack + 3stack-dig ditto with SPDIF + laptop 3-jack with hp-jack automute + laptop-dig ditto with SPDIF + auto auto-config reading BIOS (default) + +Conexant 5045 +============= + laptop-hpsense Laptop with HP sense (old model laptop) + laptop-micsense Laptop with Mic sense (old model fujitsu) + laptop-hpmicsense Laptop with HP and Mic senses + benq Benq R55E + test for testing/debugging purpose, almost all controls + can be adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + +Conexant 5047 +============= + laptop Basic Laptop config + laptop-hp Laptop config for some HP models (subdevice 30A5) + laptop-eapd Laptop config with EAPD support + test for testing/debugging purpose, almost all controls + can be adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + +Conexant 5051 +============= + laptop Basic Laptop config (default) + hp HP Spartan laptop + +STAC9200 +======== + ref Reference board + dell-d21 Dell (unknown) + dell-d22 Dell (unknown) + dell-d23 Dell (unknown) + dell-m21 Dell Inspiron 630m, Dell Inspiron 640m + dell-m22 Dell Latitude D620, Dell Latitude D820 + dell-m23 Dell XPS M1710, Dell Precision M90 + dell-m24 Dell Latitude 120L + dell-m25 Dell Inspiron E1505n + dell-m26 Dell Inspiron 1501 + dell-m27 Dell Inspiron E1705/9400 + gateway Gateway laptops with EAPD control + panasonic Panasonic CF-74 + +STAC9205/9254 +============= + ref Reference board + dell-m42 Dell (unknown) + dell-m43 Dell Precision + dell-m44 Dell Inspiron + +STAC9220/9221 +============= + ref Reference board + 3stack D945 3stack + 5stack D945 5stack + SPDIF + intel-mac-v1 Intel Mac Type 1 + intel-mac-v2 Intel Mac Type 2 + intel-mac-v3 Intel Mac Type 3 + intel-mac-v4 Intel Mac Type 4 + intel-mac-v5 Intel Mac Type 5 + intel-mac-auto Intel Mac (detect type according to subsystem id) + macmini Intel Mac Mini (equivalent with type 3) + macbook Intel Mac Book (eq. type 5) + macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3) + macbook-pro Intel Mac Book Pro 2nd generation (eq. type 3) + imac-intel Intel iMac (eq. type 2) + imac-intel-20 Intel iMac (newer version) (eq. type 3) + dell-d81 Dell (unknown) + dell-d82 Dell (unknown) + dell-m81 Dell (unknown) + dell-m82 Dell XPS M1210 + +STAC9202/9250/9251 +================== + ref Reference board, base config + m2-2 Some Gateway MX series laptops + m6 Some Gateway NX series laptops + pa6 Gateway NX860 series + +STAC9227/9228/9229/927x +======================= + ref Reference board + ref-no-jd Reference board without HP/Mic jack detection + 3stack D965 3stack + 5stack D965 5stack + SPDIF + dell-3stack Dell Dimension E520 + dell-bios Fixes with Dell BIOS setup + +STAC92HD71B* +============ + ref Reference board + dell-m4-1 Dell desktops + dell-m4-2 Dell desktops + dell-m4-3 Dell desktops + +STAC92HD73* +=========== + ref Reference board + no-jd BIOS setup but without jack-detection + dell-m6-amic Dell desktops/laptops with analog mics + dell-m6-dmic Dell desktops/laptops with digital mics + dell-m6 Dell desktops/laptops with both type of mics + +STAC92HD83* +=========== + ref Reference board + +STAC9872 +======== + vaio Setup for VAIO FE550G/SZ110 + vaio-ar Setup for VAIO AR -- cgit v1.2.3 From 827057f5c12f5e10dc0279596db940aa6ddf8d9b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 10:12:02 +0100 Subject: ALSA: hda - Add missing initializations of amp and verb caches The re-initializations of codec amp and verb caches are missing at reconfig, which may cause Oops occasionally. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8459d6ba205..625fe5984dd 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1288,6 +1288,8 @@ void snd_hda_codec_reset(struct hda_codec *codec) codec->spec = NULL; free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); + init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); + init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); codec->num_pcms = 0; codec->pcm_info = NULL; codec->preset = NULL; -- cgit v1.2.3 From 4f2d23e1c3fe0abaf87fead3033c6cc3671b4d1c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 10:14:13 +0100 Subject: ALSA: hda - Use snd_hda_ctl_add() in patch_sigmatel.c Fixed the call of snd_ctl_add() by replacing with snd_hda_ctl_add() so that this mixer element can be tracked for re-configuration. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 71c3ccfcde1..31662c65e8f 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1293,7 +1293,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) spec->spdif_mute = 1; } stac_smux_mixer.count = spec->num_smuxes; - err = snd_ctl_add(codec->bus->card, + err = snd_hda_ctl_add(codec, snd_ctl_new1(&stac_smux_mixer, codec)); if (err < 0) return err; -- cgit v1.2.3 From 692f90421d3716ef0d0f120d9d2c9684009a4a01 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 12:44:46 +0100 Subject: ALSA: hda - Fix HD-Audio.txt reference of model list The model list is now in HD-Audio-Models.txt. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 642a2b01254..8d68fff7183 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -162,8 +162,8 @@ PCI SSID look-up. What `model` option values are available depends on the codec chip. Check your codec chip from the codec proc file (see "Codec Proc-File" section below). It will show the vendor/product name of your codec -chip. Then, see Documentation/sound/alsa/ALSA-Configuration.txt -file, the section of HD-audio driver. You can find a list of codecs +chip. Then, see Documentation/sound/alsa/HD-Audio-Modelstxt file, +the section of HD-audio driver. You can find a list of codecs and `model` options belonging to each codec. For example, for Realtek ALC262 codec chip, pass `model=ultra` for devices that are compatible with Samsung Q1 Ultra. -- cgit v1.2.3 From c21ca4a872697aeda4fe91bf9b6cc8380c62827c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 09:26:08 +0100 Subject: ALSA: hda - Rework on STAC/IDT auto-configuration code The current auto-configuration code has several problems especially for the new IDT codecs, e.g. wrong assignment of pins and DACs or coupled volume for speaker and headphone. This patch is a fairly large rewrite of the auto-configuration code. Some remaks - mic_switch and line_switch contain NIDs instead of bool - dac_list isn't fixed for IDT 92HD* codecs now, they are all probed - extra HP and speakers are stored in extra_dacs[]. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 467 ++++++++++++++++++----------------------- 1 file changed, 204 insertions(+), 263 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index b7b41969180..17140021632 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -157,8 +157,6 @@ struct sigmatel_spec { int board_config; unsigned int eapd_switch: 1; unsigned int surr_switch: 1; - unsigned int line_switch: 1; - unsigned int mic_switch: 1; unsigned int alt_switch: 1; unsigned int hp_detect: 1; unsigned int spdif_mute: 1; @@ -195,6 +193,8 @@ struct sigmatel_spec { unsigned int cur_mmux; struct hda_multi_out multiout; hda_nid_t dac_nids[5]; + hda_nid_t hp_dacs[5]; + hda_nid_t speaker_dacs[5]; /* capture */ hda_nid_t *adc_nids; @@ -238,7 +238,9 @@ struct sigmatel_spec { /* i/o switches */ unsigned int io_switch[2]; unsigned int clfe_swap; - unsigned int hp_switch; /* NID of HP as line-out */ + hda_nid_t line_switch; /* shared line-in for input and output */ + hda_nid_t mic_switch; /* shared mic-in for input and output */ + hda_nid_t hp_switch; /* NID of HP as line-out */ unsigned int aloopback; struct hda_pcm pcm_rec[2]; /* PCM information */ @@ -289,9 +291,6 @@ static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { }; #define STAC92HD73_DAC_COUNT 5 -static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = { - 0x15, 0x16, 0x17, 0x18, 0x19, -}; static hda_nid_t stac92hd73xx_mux_nids[4] = { 0x28, 0x29, 0x2a, 0x2b, @@ -310,11 +309,7 @@ static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = { 0x11, 0x12, 0 }; -#define STAC92HD81_DAC_COUNT 2 #define STAC92HD83_DAC_COUNT 3 -static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = { - 0x13, 0x14, 0x22, -}; static hda_nid_t stac92hd83xxx_dmux_nids[2] = { 0x17, 0x18, @@ -356,10 +351,6 @@ static hda_nid_t stac92hd71bxx_smux_nids[2] = { 0x24, 0x25, }; -static hda_nid_t stac92hd71bxx_dac_nids[1] = { - 0x10, /*0x11, */ -}; - #define STAC92HD71BXX_NUM_DMICS 2 static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = { 0x18, 0x19, 0 @@ -761,10 +752,6 @@ static struct hda_verb stac9200_eapd_init[] = { static struct hda_verb stac92hd73xx_6ch_core_init[] = { /* set master volume and direct control */ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* setup audio connections */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00}, - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02}, /* setup adcs to point to mixer */ { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, @@ -783,10 +770,6 @@ static struct hda_verb dell_eq_core_init[] = { /* set master volume to max value without distortion * and direct control */ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec}, - /* setup audio connections */ - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, - { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02}, - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01}, /* setup adcs to point to mixer */ { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, @@ -800,10 +783,6 @@ static struct hda_verb dell_eq_core_init[] = { static struct hda_verb dell_m6_core_init[] = { { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* setup audio connections */ - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, - { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02}, /* setup adcs to point to mixer */ { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, @@ -818,13 +797,6 @@ static struct hda_verb dell_m6_core_init[] = { static struct hda_verb stac92hd73xx_8ch_core_init[] = { /* set master volume and direct control */ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* setup audio connections */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00}, - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* connect hp ports to dac3 */ - { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03}, - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03}, /* setup adcs to point to mixer */ { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, @@ -842,15 +814,8 @@ static struct hda_verb stac92hd73xx_8ch_core_init[] = { static struct hda_verb stac92hd73xx_10ch_core_init[] = { /* set master volume and direct control */ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* setup audio connections */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 }, /* dac3 is connected to import3 mux */ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f}, - /* connect hp ports to dac4 */ - { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04}, - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04}, /* setup adcs to point to mixer */ { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, @@ -881,8 +846,6 @@ static struct hda_verb stac92hd83xxx_core_init[] = { static struct hda_verb stac92hd71bxx_core_init[] = { /* set master volume and direct control */ { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* connect headphone jack to dac1 */ - { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -901,8 +864,6 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = { /* set master volume and direct control */ { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* connect headphone jack to dac1 */ - { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* unmute right and left channels for nodes 0x0a, 0xd */ { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -2747,70 +2708,53 @@ static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type, return stac92xx_add_control_idx(spec, type, 0, name, val); } -/* flag inputs as additional dynamic lineouts */ -static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg) +/* check whether the line-input can be used as line-out */ +static hda_nid_t check_line_out_switch(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - unsigned int wcaps, wtype; - int i, num_dacs = 0; - - /* use the wcaps cache to count all DACs available for line-outs */ - for (i = 0; i < codec->num_nodes; i++) { - wcaps = codec->wcaps[i]; - wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t nid; + unsigned int pincap; - if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) - num_dacs++; - } + if (cfg->line_out_type != AUTO_PIN_LINE_OUT) + return 0; + nid = cfg->input_pins[AUTO_PIN_LINE]; + pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); + if (pincap & AC_PINCAP_OUT) + return nid; + return 0; +} - snd_printdd("%s: total dac count=%d\n", __func__, num_dacs); - - switch (cfg->line_outs) { - case 3: - /* add line-in as side */ - if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_LINE]; - spec->line_switch = 1; - cfg->line_outs++; - } - break; - case 2: - /* add line-in as clfe and mic as side */ - if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_LINE]; - spec->line_switch = 1; - cfg->line_outs++; - } - if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_MIC]; - spec->mic_switch = 1; - cfg->line_outs++; - } - break; - case 1: - /* add line-in as surr and mic as clfe */ - if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_LINE]; - spec->line_switch = 1; - cfg->line_outs++; - } - if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_MIC]; - spec->mic_switch = 1; - cfg->line_outs++; +/* check whether the mic-input can be used as line-out */ +static hda_nid_t check_mic_out_switch(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int def_conf, pincap; + unsigned int mic_pin; + + if (cfg->line_out_type != AUTO_PIN_LINE_OUT) + return 0; + mic_pin = AUTO_PIN_MIC; + for (;;) { + hda_nid_t nid = cfg->input_pins[mic_pin]; + def_conf = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + /* some laptops have an internal analog microphone + * which can't be used as a output */ + if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) { + pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); + if (pincap & AC_PINCAP_OUT) + return nid; } - break; + if (mic_pin == AUTO_PIN_MIC) + mic_pin = AUTO_PIN_FRONT_MIC; + else + break; } - return 0; } - static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) { int i; @@ -2823,6 +2767,52 @@ static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) return 0; } +static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) +{ + int i; + if (is_in_dac_nids(spec, nid)) + return 1; + for (i = 0; i < spec->autocfg.hp_outs; i++) + if (spec->hp_dacs[i] == nid) + return 1; + for (i = 0; i < spec->autocfg.speaker_outs; i++) + if (spec->speaker_dacs[i] == nid) + return 1; + return 0; +} + +static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid) +{ + struct sigmatel_spec *spec = codec->spec; + int j, conn_len; + hda_nid_t conn[HDA_MAX_CONNECTIONS]; + unsigned int wcaps, wtype; + + conn_len = snd_hda_get_connections(codec, nid, conn, + HDA_MAX_CONNECTIONS); + for (j = 0; j < conn_len; j++) { + wcaps = snd_hda_param_read(codec, conn[j], + AC_PAR_AUDIO_WIDGET_CAP); + wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + /* we check only analog outputs */ + if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL)) + continue; + /* if this route has a free DAC, assign it */ + if (!check_all_dac_nids(spec, conn[j])) { + if (conn_len > 1) { + /* select this DAC in the pin's input mux */ + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, j); + } + return conn[j]; + } + } + return 0; +} + +static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid); +static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid); + /* * Fill in the dac_nids table from the parsed pin configuration * This function only works when every pin in line_out_pins[] @@ -2830,31 +2820,17 @@ static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) * codecs are not connected directly to a DAC, such as the 9200 * and 9202/925x. For those, dac_nids[] must be hard-coded. */ -static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, - struct auto_pin_cfg *cfg) +static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - int i, j, conn_len = 0; - hda_nid_t nid, conn[HDA_MAX_CONNECTIONS]; - unsigned int wcaps, wtype; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + hda_nid_t nid, dac; for (i = 0; i < cfg->line_outs; i++) { nid = cfg->line_out_pins[i]; - conn_len = snd_hda_get_connections(codec, nid, conn, - HDA_MAX_CONNECTIONS); - for (j = 0; j < conn_len; j++) { - wcaps = snd_hda_param_read(codec, conn[j], - AC_PAR_AUDIO_WIDGET_CAP); - wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (wtype != AC_WID_AUD_OUT || - (wcaps & AC_WCAP_DIGITAL)) - continue; - /* conn[j] is a DAC routed to this line-out */ - if (!is_in_dac_nids(spec, conn[j])) - break; - } - - if (j == conn_len) { + dac = get_unassigned_dac(codec, nid); + if (!dac) { if (spec->multiout.num_dacs > 0) { /* we have already working output pins, * so let's drop the broken ones again @@ -2868,24 +2844,64 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, __func__, nid); return -ENODEV; } + add_spec_dacs(spec, dac); + } - spec->multiout.dac_nids[i] = conn[j]; - spec->multiout.num_dacs++; - if (conn_len > 1) { - /* select this DAC in the pin's input mux */ - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, j); + /* add line-in as output */ + nid = check_line_out_switch(codec); + if (nid) { + dac = get_unassigned_dac(codec, nid); + if (dac) { + snd_printdd("STAC: Add line-in 0x%x as output %d\n", + nid, cfg->line_outs); + cfg->line_out_pins[cfg->line_outs] = nid; + cfg->line_outs++; + spec->line_switch = nid; + add_spec_dacs(spec, dac); + } + } + /* add mic as output */ + nid = check_mic_out_switch(codec); + if (nid) { + dac = get_unassigned_dac(codec, nid); + if (dac) { + snd_printdd("STAC: Add mic-in 0x%x as output %d\n", + nid, cfg->line_outs); + cfg->line_out_pins[cfg->line_outs] = nid; + cfg->line_outs++; + spec->mic_switch = nid; + add_spec_dacs(spec, dac); + } + } + for (i = 0; i < cfg->hp_outs; i++) { + nid = cfg->hp_pins[i]; + dac = get_unassigned_dac(codec, nid); + if (dac) { + if (!spec->multiout.hp_nid) + spec->multiout.hp_nid = dac; + else + add_spec_extra_dacs(spec, dac); } + spec->hp_dacs[i] = dac; } - snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + for (i = 0; i < cfg->speaker_outs; i++) { + nid = cfg->speaker_pins[i]; + dac = get_unassigned_dac(codec, nid); + if (dac) + add_spec_extra_dacs(spec, dac); + spec->speaker_dacs[i] = dac; + } + + snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", spec->multiout.num_dacs, spec->multiout.dac_nids[0], spec->multiout.dac_nids[1], spec->multiout.dac_nids[2], spec->multiout.dac_nids[3], spec->multiout.dac_nids[4]); + return 0; } @@ -2910,9 +2926,7 @@ static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_ static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) { - if (!spec->multiout.hp_nid) - spec->multiout.hp_nid = nid; - else if (spec->multiout.num_dacs > 4) { + if (spec->multiout.num_dacs > 4) { printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid); return 1; } else { @@ -2922,13 +2936,17 @@ static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) return 0; } -static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) +static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid) { - if (is_in_dac_nids(spec, nid)) - return 1; - if (spec->multiout.hp_nid == nid) - return 1; - return 0; + int i; + for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) { + if (!spec->multiout.extra_out_nid[i]) { + spec->multiout.extra_out_nid[i] = nid; + return 0; + } + } + printk(KERN_WARNING "stac92xx: No space for extra DAC 0x%x\n", nid); + return 1; } /* add playback controls from the parsed DAC table */ @@ -2944,13 +2962,8 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, struct sigmatel_spec *spec = codec->spec; unsigned int wid_caps, pincap; - - for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) { - if (!spec->multiout.dac_nids[i]) - continue; - + for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) { nid = spec->multiout.dac_nids[i]; - if (i == 2) { /* Center/LFE */ err = create_controls(spec, "Center", nid, 1); @@ -2978,10 +2991,6 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, } } - if ((spec->multiout.num_dacs - cfg->line_outs) > 0 && - cfg->hp_outs == 1 && !spec->multiout.hp_nid) - spec->multiout.hp_nid = nid; - if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) { err = stac92xx_add_control(spec, STAC_CTL_WIDGET_HP_SWITCH, @@ -2992,45 +3001,19 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, } if (spec->line_switch) { - nid = cfg->input_pins[AUTO_PIN_LINE]; - pincap = snd_hda_param_read(codec, nid, - AC_PAR_PIN_CAP); - if (pincap & AC_PINCAP_OUT) { - err = stac92xx_add_control(spec, - STAC_CTL_WIDGET_IO_SWITCH, - "Line In as Output Switch", nid << 8); - if (err < 0) - return err; - } + err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, + "Line In as Output Switch", + spec->line_switch << 8); + if (err < 0) + return err; } if (spec->mic_switch) { - unsigned int def_conf; - unsigned int mic_pin = AUTO_PIN_MIC; -again: - nid = cfg->input_pins[mic_pin]; - def_conf = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); - /* some laptops have an internal analog microphone - * which can't be used as a output */ - if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) { - pincap = snd_hda_param_read(codec, nid, - AC_PAR_PIN_CAP); - if (pincap & AC_PINCAP_OUT) { - err = stac92xx_add_control(spec, - STAC_CTL_WIDGET_IO_SWITCH, - "Mic as Output Switch", (nid << 8) | 1); - nid = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONNECT_LIST, 0) & 0xff; - if (!check_in_dac_nids(spec, nid)) - add_spec_dacs(spec, nid); - if (err < 0) - return err; - } - } else if (mic_pin == AUTO_PIN_MIC) { - mic_pin = AUTO_PIN_FRONT_MIC; - goto again; - } + err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, + "Mic as Output Switch", + (spec->mic_switch << 8) | 1); + if (err < 0) + return err; } return 0; @@ -3042,55 +3025,39 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, { struct sigmatel_spec *spec = codec->spec; hda_nid_t nid; - int i, old_num_dacs, err; + int i, err, nums; - old_num_dacs = spec->multiout.num_dacs; + nums = 0; for (i = 0; i < cfg->hp_outs; i++) { + static const char *pfxs[] = { + "Headphone", "Headphone2", "Headphone3", + }; unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]); if (wid_caps & AC_WCAP_UNSOL_CAP) spec->hp_detect = 1; - nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, - AC_VERB_GET_CONNECT_LIST, 0) & 0xff; - if (check_in_dac_nids(spec, nid)) - nid = 0; - if (! nid) + if (nums >= ARRAY_SIZE(pfxs)) continue; - add_spec_dacs(spec, nid); - } - for (i = 0; i < cfg->speaker_outs; i++) { - nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0, - AC_VERB_GET_CONNECT_LIST, 0) & 0xff; - if (check_in_dac_nids(spec, nid)) - nid = 0; - if (! nid) - continue; - add_spec_dacs(spec, nid); - } - for (i = 0; i < cfg->line_outs; i++) { - nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0, - AC_VERB_GET_CONNECT_LIST, 0) & 0xff; - if (check_in_dac_nids(spec, nid)) - nid = 0; - if (! nid) + nid = spec->hp_dacs[i]; + if (!nid) continue; - add_spec_dacs(spec, nid); + err = create_controls(spec, pfxs[nums++], nid, 3); + if (err < 0) + return err; } - for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) { + nums = 0; + for (i = 0; i < cfg->speaker_outs; i++) { static const char *pfxs[] = { "Speaker", "External Speaker", "Speaker2", }; - err = create_controls(spec, pfxs[i - old_num_dacs], - spec->multiout.dac_nids[i], 3); - if (err < 0) - return err; - } - if (spec->multiout.hp_nid) { - err = create_controls(spec, "Headphone", - spec->multiout.hp_nid, 3); + if (nums >= ARRAY_SIZE(pfxs)) + continue; + nid = spec->speaker_dacs[i]; + if (!nid) + continue; + err = create_controls(spec, pfxs[nums++], nid, 3); if (err < 0) return err; } - return 0; } @@ -3428,7 +3395,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out { struct sigmatel_spec *spec = codec->spec; int err; - int hp_speaker_swap = 0; if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, @@ -3446,13 +3412,15 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out * speaker_outs so that the following routines can handle * HP pins as primary outputs. */ + snd_printdd("stac92xx: Enabling multi-HPs workaround\n"); memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins, sizeof(spec->autocfg.line_out_pins)); spec->autocfg.speaker_outs = spec->autocfg.line_outs; memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins, sizeof(spec->autocfg.hp_pins)); spec->autocfg.line_outs = spec->autocfg.hp_outs; - hp_speaker_swap = 1; + spec->autocfg.line_out_type = AUTO_PIN_HP_OUT; + spec->autocfg.hp_outs = 0; } if (spec->autocfg.mono_out_pin) { int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) & @@ -3504,11 +3472,11 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out AC_PINCTL_OUT_EN); } - if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) - return err; - if (spec->multiout.num_dacs == 0) - if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) + if (!spec->multiout.num_dacs) { + err = stac92xx_auto_fill_dac_nids(codec); + if (err < 0) return err; + } err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg); @@ -3546,19 +3514,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out } #endif - if (hp_speaker_swap == 1) { - /* Restore the hp_outs and line_outs */ - memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins, - sizeof(spec->autocfg.line_out_pins)); - spec->autocfg.hp_outs = spec->autocfg.line_outs; - memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins, - sizeof(spec->autocfg.speaker_pins)); - spec->autocfg.line_outs = spec->autocfg.speaker_outs; - memset(spec->autocfg.speaker_pins, 0, - sizeof(spec->autocfg.speaker_pins)); - spec->autocfg.speaker_outs = 0; - } - err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); if (err < 0) @@ -3870,8 +3825,7 @@ static void stac92xx_power_down(struct hda_codec *codec) /* power down inactive DACs */ hda_nid_t *dac; for (dac = spec->dac_list; *dac; dac++) - if (!is_in_dac_nids(spec, *dac) && - spec->multiout.hp_nid != *dac) + if (!check_all_dac_nids(spec, *dac)) snd_hda_codec_write(codec, *dac, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); } @@ -4055,10 +4009,7 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, */ struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - if ((nid == cfg->input_pins[AUTO_PIN_LINE] && - spec->line_switch) || - (nid == cfg->input_pins[AUTO_PIN_MIC] && - spec->mic_switch)) + if (nid == spec->line_switch || nid == spec->mic_switch) return; } @@ -4100,11 +4051,9 @@ static int no_hp_sensing(struct sigmatel_spec *spec, int i) struct auto_pin_cfg *cfg = &spec->autocfg; /* ignore sensing of shared line and mic jacks */ - if (spec->line_switch && - cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE]) + if (cfg->hp_pins[i] == spec->line_switch) return 1; - if (spec->mic_switch && - cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC]) + if (cfg->hp_pins[i] == spec->mic_switch) return 1; /* ignore if the pin is set as line-out */ if (cfg->hp_pins[i] == spec->hp_switch) @@ -4515,6 +4464,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec) struct sigmatel_spec *spec; hda_nid_t conn[STAC92HD73_DAC_COUNT + 2]; int err = 0; + int num_dacs; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -4541,33 +4491,29 @@ again: return err; } - spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a, + num_dacs = snd_hda_get_connections(codec, 0x0a, conn, STAC92HD73_DAC_COUNT + 2) - 1; - if (spec->multiout.num_dacs < 0) { + if (num_dacs < 3 || num_dacs > 5) { printk(KERN_WARNING "hda_codec: Could not determine " "number of channels defaulting to DAC count\n"); - spec->multiout.num_dacs = STAC92HD73_DAC_COUNT; + num_dacs = STAC92HD73_DAC_COUNT; } - - switch (spec->multiout.num_dacs) { + switch (num_dacs) { case 0x3: /* 6 Channel */ - spec->multiout.hp_nid = 0x17; spec->mixer = stac92hd73xx_6ch_mixer; spec->init = stac92hd73xx_6ch_core_init; break; case 0x4: /* 8 Channel */ - spec->multiout.hp_nid = 0x18; spec->mixer = stac92hd73xx_8ch_mixer; spec->init = stac92hd73xx_8ch_core_init; break; case 0x5: /* 10 Channel */ - spec->multiout.hp_nid = 0x19; spec->mixer = stac92hd73xx_10ch_mixer; spec->init = stac92hd73xx_10ch_core_init; - }; + } + spec->multiout.dac_nids = spec->dac_nids; - spec->multiout.dac_nids = stac92hd73xx_dac_nids; spec->aloopback_mask = 0x01; spec->aloopback_shift = 8; @@ -4598,9 +4544,8 @@ again: spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP]; spec->eapd_switch = 0; spec->num_amps = 1; - spec->multiout.hp_nid = 0; /* dual HPs */ - if (!spec->init) + if (spec->board_config != STAC_DELL_EQ) spec->init = dell_m6_core_init; switch (spec->board_config) { case STAC_DELL_M6_AMIC: /* Analog Mics */ @@ -4691,17 +4636,15 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) spec->pwr_nids = stac92hd83xxx_pwr_nids; spec->pwr_mapping = stac92hd83xxx_pwr_mapping; spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); - spec->multiout.dac_nids = stac92hd83xxx_dac_nids; + spec->multiout.dac_nids = spec->dac_nids; spec->init = stac92hd83xxx_core_init; switch (codec->vendor_id) { case 0x111d7605: - spec->multiout.num_dacs = STAC92HD81_DAC_COUNT; break; default: spec->num_pwrs--; spec->init++; /* switch to config #2 */ - spec->multiout.num_dacs = STAC92HD83_DAC_COUNT; } spec->mixer = stac92hd83xxx_mixer; @@ -4892,9 +4835,7 @@ again: spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); }; - spec->multiout.num_dacs = 1; - spec->multiout.hp_nid = 0x11; - spec->multiout.dac_nids = stac92hd71bxx_dac_nids; + spec->multiout.dac_nids = spec->dac_nids; if (spec->dinput_mux) spec->private_dimux.num_items += spec->num_dmics - -- cgit v1.2.3 From 766245348db4b047a9b53548b5b893cd5115decc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 10:09:47 +0100 Subject: ALSA: hda - Use more distinct name for a unique volume in STAC/IDT When the line_out has only one DAC and it's unique (i.e. not shared by other outputs), assign a more reasonable and distinct mixer name such as "Headphone" or "Speaker". Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 17140021632..6b7eeba656e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2949,17 +2949,30 @@ static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid) return 1; } +static int is_unique_dac(struct sigmatel_spec *spec, hda_nid_t nid) +{ + int i; + + if (spec->autocfg.line_outs != 1) + return 0; + if (spec->multiout.hp_nid == nid) + return 0; + for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) + if (spec->multiout.extra_out_nid[i] == nid) + return 0; + return 1; +} + /* add playback controls from the parsed DAC table */ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { + struct sigmatel_spec *spec = codec->spec; static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; hda_nid_t nid = 0; - int i, err; - - struct sigmatel_spec *spec = codec->spec; + int i, err, num_dacs; unsigned int wid_caps, pincap; for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) { @@ -2985,7 +2998,19 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, } } else { - err = create_controls(spec, chname[i], nid, 3); + const char *name = chname[i]; + /* if it's a single DAC, assign a better name */ + if (!i && is_unique_dac(spec, nid)) { + switch (cfg->line_out_type) { + case AUTO_PIN_HP_OUT: + name = "Headphone"; + break; + case AUTO_PIN_SPEAKER_OUT: + name = "Speaker"; + break; + } + } + err = create_controls(spec, name, nid, 3); if (err < 0) return err; } -- cgit v1.2.3 From d4d9cd0338892e7f0d65f8a110473d175535cd5d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 15:19:11 +0100 Subject: ALSA: hda - Add probe_only option Added probe_only module option to hd-audio driver. This option specifies whether the driver creates and initializes the codec-parser after probing. When this option is set, the driver skips the codec parsing and initialization but gives you proc and other accesses. It's useful to see the initial codec state for debugging. The default of this value is off, so the default behavior is as same as before. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 2 ++ sound/pci/hda/hda_codec.c | 12 +++++++----- sound/pci/hda/hda_codec.h | 2 +- sound/pci/hda/hda_intel.c | 11 ++++++++--- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index a4f3a22caba..ee45454c50b 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -757,6 +757,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. model - force the model name position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF) probe_mask - Bitmask to probe codecs (default = -1, meaning all slots) + probe_only - Only probing and no codec initialization (default=off); + Useful to check the initial codec status for debugging bdl_pos_adj - Specifies the DMA IRQ timing delay in samples. Passing -1 will make the driver to choose the appropriate value based on the controller chip. diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 625fe5984dd..e16cf63821a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -709,7 +709,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) * Returns 0 if successful, or a negative error code. */ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, - struct hda_codec **codecp) + int do_init, struct hda_codec **codecp) { struct hda_codec *codec; char component[31]; @@ -793,10 +793,12 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr 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; + if (do_init) { + err = snd_hda_codec_configure(codec); + if (err < 0) { + snd_hda_codec_free(codec); + return err; + } } snd_hda_codec_proc_new(codec); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 5587d416229..729fc7642d7 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -811,7 +811,7 @@ enum { int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, struct hda_bus **busp); int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, - struct hda_codec **codecp); + int do_init, struct hda_codec **codecp); /* * low level functions diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index a26ae8c4cf7..6613b6bef9e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -58,6 +58,7 @@ static char *model[SNDRV_CARDS]; static int position_fix[SNDRV_CARDS]; static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; +static int probe_only[SNDRV_CARDS]; static int single_cmd; static int enable_msi; @@ -76,6 +77,8 @@ module_param_array(bdl_pos_adj, int, NULL, 0644); MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); module_param_array(probe_mask, int, NULL, 0444); MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); +module_param_array(probe_only, bool, NULL, 0444); +MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization."); module_param(single_cmd, bool, 0444); MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " "(for debugging only)."); @@ -1224,7 +1227,8 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = { }; static int __devinit azx_codec_create(struct azx *chip, const char *model, - unsigned int codec_probe_mask) + unsigned int codec_probe_mask, + int no_init) { struct hda_bus_template bus_temp; int c, codecs, err; @@ -1282,7 +1286,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, for (c = 0; c < max_slots; c++) { if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { struct hda_codec *codec; - err = snd_hda_codec_new(chip->bus, c, &codec); + err = snd_hda_codec_new(chip->bus, c, !no_init, &codec); if (err < 0) continue; codecs++; @@ -2340,7 +2344,8 @@ static int __devinit azx_probe(struct pci_dev *pci, card->private_data = chip; /* create codec instances */ - err = azx_codec_create(chip, model[dev], probe_mask[dev]); + err = azx_codec_create(chip, model[dev], probe_mask[dev], + probe_only[dev]); if (err < 0) goto out_free; -- cgit v1.2.3 From 9158923228822c08ed3116bfe21472261a05a725 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 15:59:40 +0100 Subject: ALSA: hda - Fix unused variable warnings in patch_sigmatel.c Fixed "unused varible" warnings in patch_sigmatel.c that have been introduced by the last changes. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6b7eeba656e..d9a89ced3c8 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2972,8 +2972,8 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, "Front", "Surround", NULL /*CLFE*/, "Side" }; hda_nid_t nid = 0; - int i, err, num_dacs; - unsigned int wid_caps, pincap; + int i, err; + unsigned int wid_caps; for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) { nid = spec->multiout.dac_nids[i]; @@ -4033,7 +4033,6 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, * "xxx as Output" mixer switch */ struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; if (nid == spec->line_switch || nid == spec->mic_switch) return; } -- cgit v1.2.3 From eb63212868c348cc6d3ec6929d7d98f7d29493e9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 16:39:48 +0100 Subject: ALSA: hda - Power up always when no jack detection is available When no jack detection is available, the pins should be always turned on since it can't be turned on/off dynamically via unsol events. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d9a89ced3c8..2cadf7c3b71 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3946,7 +3946,13 @@ static int stac92xx_init(struct hda_codec *codec) hda_nid_t nid = spec->pwr_nids[i]; int pinctl, def_conf; - if (is_nid_hp_pin(cfg, nid) && spec->hp_detect) + /* power on when no jack detection is available */ + if (!spec->hp_detect) { + stac_toggle_power_map(codec, nid, 1); + continue; + } + + if (is_nid_hp_pin(cfg, nid)) continue; /* already has an unsol event */ pinctl = snd_hda_codec_read(codec, nid, 0, @@ -3955,8 +3961,10 @@ static int stac92xx_init(struct hda_codec *codec) * any attempts on powering down a input port cause the * referenced VREF to act quirky. */ - if (pinctl & AC_PINCTL_IN_EN) + if (pinctl & AC_PINCTL_IN_EN) { + stac_toggle_power_map(codec, nid, 1); continue; + } def_conf = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); def_conf = get_defcfg_connect(def_conf); -- cgit v1.2.3 From 69dfaefee4a2dfdfee3488a306403fe1e51f0be5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 20 Dec 2008 16:57:50 +0100 Subject: ALSA: hda - Add quirk for another HP dv7 Added the model=hp-m4 quirk for another HP dv7 (103c:30fc) with IDT 92HD71b* codec. Reference: Novell bnc#461108 https://bugzilla.novell.com/show_bug.cgi?id=461108 Cc: stable@kernel.org Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 2cadf7c3b71..e2941cd8aee 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1731,6 +1731,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { "HP dv5", STAC_HP_M4), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4, "HP dv7", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc, + "HP dv7", STAC_HP_M4), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a, "unknown HP", STAC_HP_M4), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, -- cgit v1.2.3 From f8ccbf65afde5df81a6238b9dc92868fbbd397f7 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Sat, 20 Dec 2008 17:36:28 -0500 Subject: ALSA: hda: dinput_mux check Add check to determine if dinput_mux is set by any of patch_stac*() functions, otherwise a invalid pointer my be referenced causing gibberish to mixer values. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index e2941cd8aee..7ee4d4df893 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3589,7 +3589,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->input_mux = &spec->private_imux; - spec->dinput_mux = &spec->private_dimux; + if (!spec->dinput_mux) + spec->dinput_mux = &spec->private_dimux; spec->sinput_mux = &spec->private_smux; spec->mono_mux = &spec->private_mono_mux; spec->amp_mux = &spec->private_amp_mux; -- cgit v1.2.3 From 74b7ff48a93f44198ac03cc4e628d713f53d4668 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Sat, 20 Dec 2008 17:47:24 -0500 Subject: ALSA: hda: fix incorrect mixer index values for 92hd83xx Fixed incorrect mixer index values for 92hd83xx codec's audio input mixer. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7ee4d4df893..71d3a773e94 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1063,21 +1063,21 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = { HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT), - HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT), + HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x4, HDA_INPUT), + HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x4, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x2, HDA_INPUT), + HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x2, HDA_INPUT), /* - HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x1, HDA_INPUT), */ { } /* end */ }; -- cgit v1.2.3