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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 6447754ae56e..19b4530e3baf 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 60468f562400..70e8fa09273d 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 9f316c1b2790..7b0abf08a583 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 19b4530e3baf..e70303183c3c 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 70e8fa09273d..b9b21766b730 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e70303183c3c..39a49d4a864a 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 b9b21766b730..77064b0cb821 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 2b00c4afdf97..02643bce5634 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 7c1eb23f0cec..076010708152 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 0b6e682c46d0..3e21a7198656 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 c59065513118..3db39adad79a 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 63e4871e5d8f..760e14ae3bff 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 39a49d4a864a..53e36495fae5 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 77064b0cb821..53f3b08b24cd 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 743d77922bce..64ab19f14f79 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 53e36495fae5..bc3ed249b0fc 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 53f3b08b24cd..8813ec10ca13 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 0ca30894f7c6..98ff010d5b95 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 7957fefda730..48faaf8cd21b 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 3db39adad79a..9c67af8e2089 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index bc3ed249b0fc..5b54ac07fcbd 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 8813ec10ca13..ce9f69bde328 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 48faaf8cd21b..d8283f1ab21a 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5b54ac07fcbd..0741eda78a5e 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 6e18a422d993..214772c8b556 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 d8283f1ab21a..4a08c31b498a 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0741eda78a5e..9a8adc600a57 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 ce9f69bde328..38a9bb6bafb0 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 214772c8b556..f3400d75eba4 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 38a9bb6bafb0..a77ba223af40 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 f3400d75eba4..653da1d3e4df 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(-) (limited to 'sound/pci') diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 7003711f4fcc..7e408908b755 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 a2ac7205d45d..ec88ba881482 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 579b32817836..d106ea52a90d 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 c872e8cab5b7cab0696bcf09c6f03c972edc1c49 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Aug 2008 13:39:01 +0200 Subject: ALSA: Enable SPDIF output on ALC655 Some hardwares with ALC655 codec don't indicate the proper ext id bit for SPDIF output although it supports. Force to enable the bit. Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_patch.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 6e831aff1bd0..2c7cd97d2234 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -2832,6 +2832,8 @@ static int patch_alc655(struct snd_ac97 * ac97) val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ else val |= (1 << 1); /* Pin 47 is spdif input pin */ + /* this seems missing on some hardwares */ + ac97->ext_id |= AC97_EI_SPDIF; } val &= ~(1 << 12); /* vref enable */ snd_ac97_write_cache(ac97, 0x7a, val); -- cgit v1.2.3 From 1083206ff44af4baa03573b4a6bac430d9d70404 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Aug 2008 10:18:39 +0200 Subject: ALSA: ice1724 - Fix TX IRQ lockup MPU TX causes IRQ floods on VT172x devices mysteriously. Disable TX IRQ if the IRQ flood is detected. Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1724.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 1b3f11702713..79a9cd0881f7 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -382,23 +382,25 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) unsigned char status_mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX | VT1724_IRQ_MTPCM; int handled = 0; -#ifdef CONFIG_SND_DEBUG int timeout = 0; -#endif while (1) { status = inb(ICEREG1724(ice, IRQSTAT)); status &= status_mask; if (status == 0) break; -#ifdef CONFIG_SND_DEBUG if (++timeout > 10) { - printk(KERN_ERR - "ice1724: Too long irq loop, status = 0x%x\n", - status); + status = inb(ICEREG1724(ice, IRQSTAT)); + printk(KERN_ERR "ice1724: Too long irq loop, " + "status = 0x%x\n", status); + if (status & VT1724_IRQ_MPU_TX) { + printk(KERN_ERR "ice1724: Disabling MPU_TX\n"); + outb(inb(ICEREG1724(ice, IRQMASK)) & + ~VT1724_IRQ_MPU_TX, + ICEREG1724(ice, IRQMASK)); + } break; } -#endif handled = 1; if (status & VT1724_IRQ_MPU_TX) { spin_lock(&ice->reg_lock); @@ -2351,7 +2353,7 @@ static int __devinit snd_vt1724_create(struct snd_card *card, { struct snd_ice1712 *ice; int err; - unsigned char mask; + /* unsigned char mask; */ static struct snd_device_ops ops = { .dev_free = snd_vt1724_dev_free, }; @@ -2413,8 +2415,10 @@ static int __devinit snd_vt1724_create(struct snd_card *card, } /* unmask used interrupts */ +#if 0 /* these are enabled/disabled dynamically */ mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX; outb(mask, ICEREG1724(ice, IRQMASK)); +#endif /* don't handle FIFO overrun/underruns (just yet), * since they cause machine lockups */ -- cgit v1.2.3 From 18c7109289625106cdc810b20b628cd13b46d6dd Mon Sep 17 00:00:00 2001 From: Vedran Miletic Date: Tue, 21 Oct 2008 17:42:54 +0200 Subject: ALSA: emu10k1: fix device names for Live!/Audigy1/2/4/E-mu * added missing SBxxxx, CTxxxx, PCxxx and MAEMxxxx where they were missing, and fixed some of them which were wrong (according to kx.inf, which is pretty accurate compared to anything out there) * fixed device names to make them more consistent across various cards * fixed order of devices where appropriate Signed-off-by: Vedran Miletic Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 146 ++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 70 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 2f283ea6ad9a..423aa0de1fad 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1292,21 +1292,6 @@ static int snd_emu10k1_dev_free(struct snd_device *device) } static struct snd_emu_chip_details emu_chip_details[] = { - /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/ - /* Tested by James@superbug.co.uk 3rd July 2005 */ - /* DSP: CA0108-IAT - * DAC: CS4382-KQ - * ADC: Philips 1361T - * AC97: STAC9750 - * CA0151: None - */ - {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, - .driver = "Audigy2", .name = "Audigy 2 Value [SB0400]", - .id = "Audigy2", - .emu10k2_chip = 1, - .ca0108_chip = 1, - .spk71 = 1, - .ac97_chip = 1} , /* Audigy4 (Not PRO) SB0610 */ /* Tested by James@superbug.co.uk 4th April 2006 */ /* A_IOCFG bits @@ -1346,20 +1331,37 @@ static struct snd_emu_chip_details emu_chip_details[] = { * CA0151: None */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102, - .driver = "Audigy2", .name = "Audigy 4 [SB0610]", + .driver = "Audigy2", .name = "SB Audigy 4 [SB0610]", .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1, .spk71 = 1, .adc_1361t = 1, /* 24 bit capture instead of 16bit */ .ac97_chip = 1} , + /* Audigy 2 Value AC3 out does not work yet. + * Need to find out how to turn off interpolators. + */ + /* Tested by James@superbug.co.uk 3rd July 2005 */ + /* DSP: CA0108-IAT + * DAC: CS4382-KQ + * ADC: Philips 1361T + * AC97: STAC9750 + * CA0151: None + */ + {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, + .driver = "Audigy2", .name = "SB Audigy 2 Value [SB0400]", + .id = "Audigy2", + .emu10k2_chip = 1, + .ca0108_chip = 1, + .spk71 = 1, + .ac97_chip = 1} , /* Audigy 2 ZS Notebook Cardbus card.*/ /* Tested by James@superbug.co.uk 6th November 2006 */ /* Audio output 7.1/Headphones working. * Digital output working. (AC3 not checked, only PCM) * Audio Mic/Line inputs working. * Digital input not tested. - */ + */ /* DSP: Tina2 * DAC: Wolfson WM8768/WM8568 * ADC: Wolfson WM8775 @@ -1386,7 +1388,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { * */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, - .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", + .driver = "Audigy2", .name = "SB Audigy 2 ZS Notebook [SB0530]", .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1, @@ -1396,7 +1398,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spk71 = 1} , /* Tested by James@superbug.co.uk 4th Nov 2007. */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102, - .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", + .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", .id = "EMU1010", .emu10k2_chip = 1, .ca0108_chip = 1, @@ -1404,47 +1406,50 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spk71 = 1 , .emu_model = EMU_MODEL_EMU1616}, /* Tested by James@superbug.co.uk 4th Nov 2007. */ + /* This is MAEM8960, 0202 is MAEM 8980 */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102, - .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]", + .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM8960]", .id = "EMU1010", .emu10k2_chip = 1, .ca0108_chip = 1, .spk71 = 1, - .emu_model = EMU_MODEL_EMU1010B}, + .emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 new revision */ /* Tested by James@superbug.co.uk 8th July 2005. */ + /* This is MAEM8810, 0202 is MAEM8820 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, - .driver = "Audigy2", .name = "E-mu 1010 [4001]", + .driver = "Audigy2", .name = "E-mu 1010 [MAEM8810]", .id = "EMU1010", .emu10k2_chip = 1, .ca0102_chip = 1, .spk71 = 1, - .emu_model = EMU_MODEL_EMU1010}, /* Emu 1010 */ + .emu_model = EMU_MODEL_EMU1010}, /* EMU 1010 old revision */ /* EMU0404b */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40021102, - .driver = "Audigy2", .name = "E-mu 0404b [4002]", + .driver = "Audigy2", .name = "E-mu 0404b PCI [MAEM8852]", .id = "EMU0404", .emu10k2_chip = 1, .ca0108_chip = 1, .spk71 = 1, - .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */ + .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 new revision */ /* Tested by James@superbug.co.uk 20-3-2007. */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40021102, - .driver = "Audigy2", .name = "E-mu 0404 [4002]", + .driver = "Audigy2", .name = "E-mu 0404 [MAEM8850]", .id = "EMU0404", .emu10k2_chip = 1, .ca0102_chip = 1, .spk71 = 1, .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */ +#endif /* Audigy4 (Not PRO) SB0610 */ - {.vendor = 0x1102, .device = 0x0008, - .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", + {.vendor = 0x1102, .device = 0x0008, + .driver = "Audigy2", .name = "SB Audigy 2 Value [Unknown]", .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1, .ac97_chip = 1} , /* Tested by James@superbug.co.uk 3rd July 2005 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, - .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", + .driver = "Audigy2", .name = "SB Audigy 4 PRO [SB0380]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1457,7 +1462,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { * Just like 0x20021102 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20061102, - .driver = "Audigy2", .name = "Audigy 2 [SB0350b]", + .driver = "Audigy2", .name = "SB Audigy 2 [SB0350b]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1466,7 +1471,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102, - .driver = "Audigy2", .name = "Audigy 2 ZS [SB0350]", + .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0350]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1475,7 +1480,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20011102, - .driver = "Audigy2", .name = "Audigy 2 ZS [2001]", + .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0360]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1492,7 +1497,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { * CA0151: Yes */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10071102, - .driver = "Audigy2", .name = "Audigy 2 [SB0240]", + .driver = "Audigy2", .name = "SB Audigy 2 [SB0240]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1502,7 +1507,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .adc_1361t = 1, /* 24 bit capture instead of 16bit */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, - .driver = "Audigy2", .name = "Audigy 2 EX [1005]", + .driver = "Audigy2", .name = "SB Audigy 2 Platinum EX [SB0280]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1512,7 +1517,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { /* Dell OEM/Creative Labs Audigy 2 ZS */ /* See ALSA bug#1365 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10031102, - .driver = "Audigy2", .name = "Audigy 2 ZS [SB0353]", + .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0353]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1521,7 +1526,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102, - .driver = "Audigy2", .name = "Audigy 2 Platinum [SB0240P]", + .driver = "Audigy2", .name = "SB Audigy 2 Platinum [SB0240P]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1532,7 +1537,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .adc_1361t = 1, /* 24 bit capture instead of 16bit. Fixes ALSA bug#324 */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .revision = 0x04, - .driver = "Audigy2", .name = "Audigy 2 [Unknown]", + .driver = "Audigy2", .name = "SB Audigy 2 [Unknown]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1540,78 +1545,79 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00531102, - .driver = "Audigy", .name = "Audigy 1 [SB0090]", + .driver = "Audigy", .name = "SB Audigy 1 [SB0092]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00521102, - .driver = "Audigy", .name = "Audigy 1 ES [SB0160]", + .driver = "Audigy", .name = "SB Audigy 1 ES [SB0160]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00511102, - .driver = "Audigy", .name = "Audigy 1 [SB0090]", + .driver = "Audigy", .name = "SB Audigy 1 [SB0090]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, - .driver = "Audigy", .name = "Audigy 1 [Unknown]", + .driver = "Audigy", .name = "Audigy 1 [Unknown]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .ac97_chip = 1} , - {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806B1102, - .driver = "EMU10K1", .name = "SBLive! [SB0105]", + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x100a1102, + .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0220]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806b1102, + .driver = "EMU10K1", .name = "SB Live! [SB0105]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , - {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806A1102, - .driver = "EMU10K1", .name = "SBLive! Value [SB0103]", + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806a1102, + .driver = "EMU10K1", .name = "SB Live! Value [SB0103]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80691102, - .driver = "EMU10K1", .name = "SBLive! Value [SB0101]", + .driver = "EMU10K1", .name = "SB Live! Value [SB0101]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , /* Tested by ALSA bug#1680 26th December 2005 */ - /* note: It really has SB0220 written on the card. */ + /* note: It really has SB0220 written on the card, */ + /* but it's SB0228 according to kx.inf */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80661102, - .driver = "EMU10K1", .name = "SB Live 5.1 Dell OEM [SB0220]", + .driver = "EMU10K1", .name = "SB Live! 5.1 Dell OEM [SB0228]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , /* Tested by Thomas Zehetbauer 27th Aug 2005 */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80651102, - .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]", - .id = "Live", - .emu10k1_chip = 1, - .ac97_chip = 1, - .sblive51 = 1} , - {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x100a1102, - .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]", + .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0220]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102, - .driver = "EMU10K1", .name = "SB Live 5.1", + .driver = "EMU10K1", .name = "SB Live! 5.1", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , /* Tested by alsa bugtrack user "hus" bug #1297 12th Aug 2005 */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102, - .driver = "EMU10K1", .name = "SBLive 5.1 [SB0060]", + .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0060]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 2, /* ac97 is optional; both SBLive 5.1 and platinum @@ -1619,78 +1625,78 @@ static struct snd_emu_chip_details emu_chip_details[] = { */ .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4850]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4850]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102, - .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]", + .driver = "EMU10K1", .name = "SB Live! Platinum [CT4760P]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80321102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4871]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4871]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80311102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4831]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4831]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80281102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4870]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4870]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , /* Tested by James@superbug.co.uk 3rd July 2005 */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4832]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4832]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80261102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4830]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4830]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80231102, - .driver = "EMU10K1", .name = "SB PCI512 [CT4790]", + .driver = "EMU10K1", .name = "SB PCI512 [CT4790]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80221102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4780]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4780]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102, - .driver = "EMU10K1", .name = "E-mu APS [4001]", + .driver = "EMU10K1", .name = "E-mu APS [PC545]", .id = "APS", .emu10k1_chip = 1, .ecard = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00211102, - .driver = "EMU10K1", .name = "SBLive! [CT4620]", + .driver = "EMU10K1", .name = "SB Live! [CT4620]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00201102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4670]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4670]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, - .driver = "EMU10K1", .name = "SB Live [Unknown]", + .driver = "EMU10K1", .name = "SB Live! [Unknown]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, -- cgit v1.2.3 From 718a2594b6a8c1c050fea85abbb4932b11105c17 Mon Sep 17 00:00:00 2001 From: Vedran Miletic Date: Tue, 21 Oct 2008 21:31:27 +0200 Subject: ALSA: emu10k1: fix faulty commit 18c71092 Commit 18c7109289625106cdc810b20b628cd13b46d6dd had #endif leftoff from compilation. This patch fixes it. Also, I replaced a misplaced comment by a useful one, that explains why are here #ifdef and #endif added in compilation. Signed-off-by: Vedran Miletic Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 423aa0de1fad..0d7466bbd749 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1439,8 +1439,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .ca0102_chip = 1, .spk71 = 1, .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */ -#endif - /* Audigy4 (Not PRO) SB0610 */ + /* Note that all E-mu cards require kernel 2.6 or newer. */ {.vendor = 0x1102, .device = 0x0008, .driver = "Audigy2", .name = "SB Audigy 2 Value [Unknown]", .id = "Audigy2", -- cgit v1.2.3 From 67679b1fd166da8398e70b7dbffe12cfccf9c7bf Mon Sep 17 00:00:00 2001 From: Vedran Miletic Date: Thu, 23 Oct 2008 18:51:00 +0200 Subject: ALSA: emu10k1: fix coding style for emu10k1_main.c I fixed all of coding style errors and some warnings, now it is down to: checkpatch.pl-0.24 --no-tree --file --strict --terse emu10k1_main.c total: 0 errors, 62 warnings, 7 checks, 2075 lines checked Signed-off-by: Vedran Miletic Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 347 ++++++++++++++++++++------------------- 1 file changed, 182 insertions(+), 165 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 0d7466bbd749..dee7ebabccee 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -69,7 +69,7 @@ MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME); * EMU10K1 init / done *************************************************************************/ -void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int ch) +void snd_emu10k1_voice_init(struct snd_emu10k1 *emu, int ch) { snd_emu10k1_ptr_write(emu, DCYSUSV, ch, 0); snd_emu10k1_ptr_write(emu, IP, ch, 0); @@ -151,9 +151,9 @@ static unsigned int i2c_adc_init[][2] = { { 0x12, 0x32 }, /* ALC Control 3 */ { 0x13, 0x00 }, /* Noise gate control */ { 0x14, 0xa6 }, /* Limiter control */ - { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for Audigy 2 ZS Notebook */ + { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for A2ZS Notebook */ }; - + static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) { unsigned int silent_page; @@ -161,8 +161,8 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) u32 tmp; /* disable audio and lock cache */ - outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, - emu->port + HCFG); + outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | + HCFG_MUTEBUTTONENABLE, emu->port + HCFG); /* reset recording buffers */ snd_emu10k1_ptr_write(emu, MICBS, 0, ADCBS_BUFSIZE_NONE); @@ -179,7 +179,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) snd_emu10k1_ptr_write(emu, SOLEL, 0, 0); snd_emu10k1_ptr_write(emu, SOLEH, 0, 0); - if (emu->audigy){ + if (emu->audigy) { /* set SPDIF bypass mode */ snd_emu10k1_ptr_write(emu, SPBYPASS, 0, SPBYPASS_FORMAT); /* enable rear left + rear right AC97 slots */ @@ -197,12 +197,12 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Hacks for Alice3 to work independent of haP16V driver */ - //Setup SRCMulti_I2S SamplingRate + /* Setup SRCMulti_I2S SamplingRate */ tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp &= 0xfffff1ff; tmp |= (0x2<<9); snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); - + /* Setup SRCSel (Enable Spdif,I2S SRCMulti) */ snd_emu10k1_ptr20_write(emu, SRCSel, 0, 0x14); /* Setup SRCMulti Input Audio Enable */ @@ -217,7 +217,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */ /* Hacks for Alice3 to work independent of haP16V driver */ snd_printk(KERN_INFO "Audigy2 value: Special config.\n"); - //Setup SRCMulti_I2S SamplingRate + /* Setup SRCMulti_I2S SamplingRate */ tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp &= 0xfffff1ff; tmp |= (0x2<<9); @@ -270,13 +270,13 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) size = ARRAY_SIZE(i2c_adc_init); for (n = 0; n < size; n++) snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]); - for (n=0; n < 4; n++) { - emu->i2c_capture_volume[n][0]= 0xcf; - emu->i2c_capture_volume[n][1]= 0xcf; + for (n = 0; n < 4; n++) { + emu->i2c_capture_volume[n][0] = 0xcf; + emu->i2c_capture_volume[n][1] = 0xcf; } } - + snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */ @@ -313,7 +313,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) (emu->model == 0x21 && emu->revision < 6)) outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE, emu->port + HCFG); else - // With on-chip joystick + /* With on-chip joystick */ outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); if (enable_ir) { /* enable IR for SB Live */ @@ -335,9 +335,9 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) outl(reg | HCFG_GPOUT1 | HCFG_GPOUT2, emu->port + HCFG); udelay(100); outl(reg, emu->port + HCFG); - } + } } - + if (emu->card_capabilities->emu_model) { ; /* Disable all access to A_IOCFG for the emu1010 */ } else if (emu->card_capabilities->i2c_adc) { @@ -364,7 +364,7 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); - + if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Unmute Analog now. Set GPO6 to 1 for Apollo. * This has to be done after init ALice3 I2SOut beyond 48KHz. @@ -378,12 +378,12 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) outl(inl(emu->port + A_IOCFG) | 0x0080, emu->port + A_IOCFG); } } - + #if 0 { unsigned int tmp; /* FIXME: the following routine disables LiveDrive-II !! */ - // TOSLink detection + /* TOSLink detection */ emu->tos_link = 0; tmp = inl(emu->port + HCFG); if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) { @@ -400,7 +400,7 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE); } -int snd_emu10k1_done(struct snd_emu10k1 * emu) +int snd_emu10k1_done(struct snd_emu10k1 *emu) { int ch; @@ -495,7 +495,7 @@ int snd_emu10k1_done(struct snd_emu10k1 * emu) #define EC_LAST_PROMFILE_ADDR 0x2f -#define EC_SERIALNUM_ADDR 0x30 /* First word of serial number. The +#define EC_SERIALNUM_ADDR 0x30 /* First word of serial number. The * can be up to 30 characters in length * and is stored as a NULL-terminated * ASCII string. Any unused bytes must be @@ -503,8 +503,8 @@ int snd_emu10k1_done(struct snd_emu10k1 * emu) #define EC_CHECKSUM_ADDR 0x3f /* Location at which checksum is stored */ -/* Most of this stuff is pretty self-evident. According to the hardware - * dudes, we need to leave the ADCCAL bit low in order to avoid a DC +/* Most of this stuff is pretty self-evident. According to the hardware + * dudes, we need to leave the ADCCAL bit low in order to avoid a DC * offset problem. Weird. */ #define EC_RAW_RUN_MODE (EC_DACMUTEN | EC_ADCRSTN | EC_TRIM_MUTEN | \ @@ -523,7 +523,7 @@ int snd_emu10k1_done(struct snd_emu10k1 * emu) * register. */ -static void snd_emu10k1_ecard_write(struct snd_emu10k1 * emu, unsigned int value) +static void snd_emu10k1_ecard_write(struct snd_emu10k1 *emu, unsigned int value) { unsigned short count; unsigned int data; @@ -561,7 +561,7 @@ static void snd_emu10k1_ecard_write(struct snd_emu10k1 * emu, unsigned int value * channel. */ -static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 * emu, +static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 *emu, unsigned short gain) { unsigned int bit; @@ -574,7 +574,7 @@ static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 * emu, for (bit = (1 << 15); bit; bit >>= 1) { unsigned int value; - + value = emu->ecard_ctrl & ~(EC_TRIM_CSN | EC_TRIM_SDATA); if (gain & bit) @@ -589,7 +589,7 @@ static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 * emu, snd_emu10k1_ecard_write(emu, emu->ecard_ctrl); } -static int snd_emu10k1_ecard_init(struct snd_emu10k1 * emu) +static int snd_emu10k1_ecard_init(struct snd_emu10k1 *emu) { unsigned int hc_value; @@ -598,7 +598,7 @@ static int snd_emu10k1_ecard_init(struct snd_emu10k1 * emu) EC_SPDIF0_SELECT(EC_DEFAULT_SPDIF0_SEL) | EC_SPDIF1_SELECT(EC_DEFAULT_SPDIF1_SEL); - /* Step 0: Set the codec type in the hardware control register + /* Step 0: Set the codec type in the hardware control register * and enable audio output */ hc_value = inl(emu->port + HCFG); outl(hc_value | HCFG_AUDIOENABLE | HCFG_CODECFORMAT_I2S, emu->port + HCFG); @@ -629,7 +629,7 @@ static int snd_emu10k1_ecard_init(struct snd_emu10k1 * emu) return 0; } -static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu) +static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu) { unsigned long special_port; unsigned int value; @@ -656,7 +656,7 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu) return 0; } -static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * filename) +static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, const char *filename) { int err; int n, i; @@ -666,11 +666,12 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file unsigned long flags; const struct firmware *fw_entry; - if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) { - snd_printk(KERN_ERR "firmware: %s not found. Err=%d\n",filename, err); + err = request_firmware(&fw_entry, filename, &emu->pci->dev); + if (err != 0) { + snd_printk(KERN_ERR "firmware: %s not found. Err = %d\n", filename, err); return err; } - snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size); + snd_printk(KERN_INFO "firmware size = 0x%zx\n", fw_entry->size); /* The FPGA is a Xilinx Spartan IIE XC2S50E */ /* GPIO7 -> FPGA PGMN @@ -685,13 +686,13 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */ write_post = inl(emu->port + A_IOCFG); udelay(100); /* Allow FPGA memory to clean */ - for(n = 0; n < fw_entry->size; n++) { - value=fw_entry->data[n]; - for(i = 0; i < 8; i++) { + for (n = 0; n < fw_entry->size; n++) { + value = fw_entry->data[n]; + for (i = 0; i < 8; i++) { reg = 0x80; if (value & 0x1) reg = reg | 0x20; - value = value >> 1; + value = value >> 1; outl(reg, emu->port + A_IOCFG); write_post = inl(emu->port + A_IOCFG); outl(reg | 0x40, emu->port + A_IOCFG); @@ -703,14 +704,14 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file write_post = inl(emu->port + A_IOCFG); spin_unlock_irqrestore(&emu->emu_lock, flags); - release_firmware(fw_entry); + release_firmware(fw_entry); return 0; } static int emu1010_firmware_thread(void *data) { - struct snd_emu10k1 * emu = data; - int tmp,tmp2; + struct snd_emu10k1 *emu = data; + int tmp, tmp2; int reg; int err; @@ -719,50 +720,50 @@ static int emu1010_firmware_thread(void *data) msleep_interruptible(1000); if (kthread_should_stop()) break; - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */ - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); /* OPTIONS: Which cards are attached to the EMU */ + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */ + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */ if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) { /* Audio Dock attached */ /* Return to Audio Dock programming mode */ snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK ); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK); if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) { - if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) { + err = snd_emu1010_load_firmware(emu, DOCK_FILENAME); + if (err != 0) continue; - } } else if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010B) { - if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { + err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME); + if (err != 0) continue; - } } else if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { - if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { + err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME); + if (err != 0) continue; - } } - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 ); - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ® ); - snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", reg); /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); - snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", reg); if ((reg & 0x1f) != 0x15) { /* FPGA failed to be programmed */ - snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); + snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", reg); continue; } snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); - snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); - snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 ); - snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2); + snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp); + snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2); + snd_printk("Audio Dock ver:%d.%d\n", tmp, tmp2); /* Sync clocking between 1010 and Dock */ /* Allow DLL to settle */ msleep(10); /* Unmute all. Default is muted after a firmware load */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); } } snd_printk(KERN_INFO "emu1010: firmware thread stopping\n"); @@ -800,10 +801,10 @@ static int emu1010_firmware_thread(void *data) * 16 x 16-bit playback - snd_emu10k1_fx8010_playback_ops * 16 x 32-bit capture - snd_emu10k1_capture_efx_ops */ -static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) +static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) { unsigned int i; - int tmp,tmp2; + int tmp, tmp2; int reg; int err; const char *filename = NULL; @@ -818,7 +819,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) * Lock Tank Memory Cache, * Mute all codecs. */ - outl(0x0005a004, emu->port + HCFG); + outl(0x0005a004, emu->port + HCFG); /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, * Mute all codecs. */ @@ -829,25 +830,25 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) outl(0x0005a000, emu->port + HCFG); /* Disable 48Volt power to Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0); /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */ - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); - snd_printdd("reg1=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); + snd_printdd("reg1 = 0x%x\n", reg); if ((reg & 0x3f) == 0x15) { /* FPGA netlist already present so clear it */ /* Return to programming mode */ - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02 ); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02); } - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); - snd_printdd("reg2=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); + snd_printdd("reg2 = 0x%x\n", reg); if ((reg & 0x3f) == 0x15) { /* FPGA failed to return to programming mode */ snd_printk(KERN_INFO "emu1010: FPGA failed to return to programming mode\n"); return -ENODEV; } - snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg); + snd_printk(KERN_INFO "emu1010: EMU_HANA_ID = 0x%x\n", reg); switch (emu->card_capabilities->emu_model) { case EMU_MODEL_EMU1010: filename = HANA_FILENAME; @@ -876,25 +877,25 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) } /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); if ((reg & 0x3f) != 0x15) { /* FPGA failed to be programmed */ - snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg); + snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n", reg); return -ENODEV; } snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n"); - snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp ); - snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2 ); - snd_printk("Hana ver:%d.%d\n",tmp ,tmp2); + snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp); + snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2); + snd_printk("emu1010: Hana version: %d.%d\n", tmp, tmp2); /* Enable 48Volt power to Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); - snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); - snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp ); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); + snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); + snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp); /* Optical -> ADAT I/O */ /* 0 : SPDIF * 1 : ADAT @@ -904,41 +905,42 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) tmp = 0; tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); - snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp ); - snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); + snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp); /* Set no attenuation on Audio Dock pads. */ - snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00 ); + snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00); emu->emu1010.adc_pads = 0x00; - snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); + snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp); /* Unmute Audio dock DACs, Headphone source DAC-4. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); - snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12); + snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp); /* DAC PADs. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f ); + snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f); emu->emu1010.dac_pads = 0x0f; - snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); - snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); + snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30); + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp); /* SPDIF Format. Set Consumer mode, 24bit, copy enable */ - snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); + snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10); /* MIDI routing */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); /* Unknown. */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); - /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); // IRQ Enable: All on */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); + /* IRQ Enable: Alll on */ + /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); */ /* IRQ Enable: All off */ - snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00 ); + snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); - snd_printk(KERN_INFO "emu1010: Card options3=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); + snd_printk(KERN_INFO "emu1010: Card options3 = 0x%x\n", reg); /* Default WCLK set to 48kHz. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00 ); + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00); /* Word Clock source, Internal 48kHz x1 */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); - //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K); + /* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */ /* Audio Dock LEDs. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12); #if 0 /* For 96kHz */ @@ -992,7 +994,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) * Defaults only, users will set their own values anyways, let's * just copy/paste. */ - + snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_ALICE2_EMU32_8, EMU_SRC_DOCK_MIC_A1); snd_emu1010_fpga_link_dst_src_write(emu, @@ -1037,19 +1039,19 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_ALICE2_EMU32_F, EMU_SRC_HAMOA_ADC_LEFT2); #endif - for (i = 0;i < 0x20; i++ ) { - /* AudioDock Elink <- Silence */ - snd_emu1010_fpga_link_dst_src_write(emu, 0x0100+i, EMU_SRC_SILENCE); + for (i = 0; i < 0x20; i++) { + /* AudioDock Elink <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, 0x0100 + i, EMU_SRC_SILENCE); } - for (i = 0;i < 4; i++) { + for (i = 0; i < 4; i++) { /* Hana SPDIF Out <- Silence */ - snd_emu1010_fpga_link_dst_src_write(emu, 0x0200+i, EMU_SRC_SILENCE); + snd_emu1010_fpga_link_dst_src_write(emu, 0x0200 + i, EMU_SRC_SILENCE); } - for (i = 0;i < 7; i++) { + for (i = 0; i < 7; i++) { /* Hamoa DAC <- Silence */ - snd_emu1010_fpga_link_dst_src_write(emu, 0x0300+i, EMU_SRC_SILENCE); + snd_emu1010_fpga_link_dst_src_write(emu, 0x0300 + i, EMU_SRC_SILENCE); } - for (i = 0;i < 7; i++) { + for (i = 0; i < 7; i++) { /* Hana ADAT Out <- Silence */ snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HANA_ADAT + i, EMU_SRC_SILENCE); } @@ -1065,30 +1067,30 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) EMU_DST_ALICE_I2S2_LEFT, EMU_SRC_DOCK_ADC3_LEFT1); snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_ALICE_I2S2_RIGHT, EMU_SRC_DOCK_ADC3_RIGHT1); - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01 ); // Unmute all + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01); /* Unmute all */ + + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); - /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, * Lock Sound Memory Cache, Lock Tank Memory Cache, * Mute all codecs. */ - outl(0x0000a000, emu->port + HCFG); + outl(0x0000a000, emu->port + HCFG); /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, * Lock Sound Memory Cache, Lock Tank Memory Cache, * Un-Mute all codecs. */ outl(0x0000a001, emu->port + HCFG); - + /* Initial boot complete. Now patches */ - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */ - snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); - snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp); + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); /* MIDI Route */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); /* Unknown */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); /* MIDI Route */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); /* Unknown */ + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp); + snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ /* Start Micro/Audio Dock firmware loader thread */ if (!emu->emu1010.firmware_thread) { @@ -1218,20 +1220,20 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) emu->emu1010.output_source[23] = 28; } /* TEMP: Select SPDIF in/out */ - //snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ + /* snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); */ /* Output spdif */ /* TEMP: Select 48kHz SPDIF out */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x0); /* Default fallback clock 48kHz */ /* Word Clock source, Internal 48kHz x1 */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); - //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K); + /* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */ emu->emu1010.internal_clock = 1; /* 48000 */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);/* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12); /* Set LEDs on Audio Dock */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x1); /* Unmute all */ - //snd_emu1010_fpga_write(emu, 0x7, 0x0); /* Mute all */ - //snd_emu1010_fpga_write(emu, 0x7, 0x1); /* Unmute all */ - //snd_emu1010_fpga_write(emu, 0xe, 0x12); /* Set LEDs on Audio Dock */ + /* snd_emu1010_fpga_write(emu, 0x7, 0x0); */ /* Mute all */ + /* snd_emu1010_fpga_write(emu, 0x7, 0x1); */ /* Unmute all */ + /* snd_emu1010_fpga_write(emu, 0xe, 0x12); */ /* Set LEDs on Audio Dock */ return 0; } @@ -1247,13 +1249,13 @@ static void free_pm_buffer(struct snd_emu10k1 *emu); static int snd_emu10k1_free(struct snd_emu10k1 *emu) { if (emu->port) { /* avoid access to already used hardware */ - snd_emu10k1_fx8010_tram_setup(emu, 0); + snd_emu10k1_fx8010_tram_setup(emu, 0); snd_emu10k1_done(emu); snd_emu10k1_free_efx(emu); - } + } if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) { /* Disable 48Volt power to Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0); } if (emu->emu1010.firmware_thread) kthread_stop(emu->emu1010.firmware_thread); @@ -1278,7 +1280,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) #endif if (emu->port) pci_release_regions(emu->pci); - if (emu->card_capabilities->ca0151_chip) /* P16V */ + if (emu->card_capabilities->ca0151_chip) /* P16V */ snd_p16v_free(emu); pci_disable_device(emu->pci); kfree(emu); @@ -1704,13 +1706,13 @@ static struct snd_emu_chip_details emu_chip_details[] = { }; int __devinit snd_emu10k1_create(struct snd_card *card, - struct pci_dev * pci, + struct pci_dev *pci, unsigned short extin_mask, unsigned short extout_mask, long max_cache_bytes, int enable_ir, uint subsystem, - struct snd_emu10k1 ** remu) + struct snd_emu10k1 **remu) { struct snd_emu10k1 *emu; int idx, err; @@ -1720,11 +1722,12 @@ int __devinit snd_emu10k1_create(struct snd_card *card, static struct snd_device_ops ops = { .dev_free = snd_emu10k1_dev_free, }; - + *remu = NULL; /* enable PCI device */ - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; emu = kzalloc(sizeof(*emu), GFP_KERNEL); @@ -1751,16 +1754,17 @@ int __devinit snd_emu10k1_create(struct snd_card *card, emu->revision = pci->revision; pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model); - snd_printdd("vendor=0x%x, device=0x%x, subsystem_vendor_id=0x%x, subsystem_id=0x%x\n",pci->vendor, pci->device, emu->serial, emu->model); + snd_printdd("vendor = 0x%x, device = 0x%x, subsystem_vendor_id = 0x%x, subsystem_id = 0x%x\n", pci->vendor, pci->device, emu->serial, emu->model); for (c = emu_chip_details; c->vendor; c++) { if (c->vendor == pci->vendor && c->device == pci->device) { if (subsystem) { - if (c->subsystem && (c->subsystem == subsystem) ) { + if (c->subsystem && (c->subsystem == subsystem)) break; - } else continue; + else + continue; } else { - if (c->subsystem && (c->subsystem != emu->serial) ) + if (c->subsystem && (c->subsystem != emu->serial)) continue; if (c->revision && c->revision != emu->revision) continue; @@ -1776,14 +1780,18 @@ int __devinit snd_emu10k1_create(struct snd_card *card, } emu->card_capabilities = c; if (c->subsystem && !subsystem) - snd_printdd("Sound card name=%s\n", c->name); - else if (subsystem) - snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x. Forced to subsytem=0x%x\n", - c->name, pci->vendor, pci->device, emu->serial, c->subsystem); - else - snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x.\n", - c->name, pci->vendor, pci->device, emu->serial); - + snd_printdd("Sound card name = %s\n", c->name); + else if (subsystem) + snd_printdd("Sound card name = %s, " + "vendor = 0x%x, device = 0x%x, subsystem = 0x%x. " + "Forced to subsytem = 0x%x\n", c->name, + pci->vendor, pci->device, emu->serial, c->subsystem); + else + snd_printdd("Sound card name = %s, " + "vendor = 0x%x, device = 0x%x, subsystem = 0x%x.\n", + c->name, pci->vendor, pci->device, + emu->serial); + if (!*card->id && c->id) { int i, n = 0; strlcpy(card->id, c->id, sizeof(card->id)); @@ -1817,7 +1825,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card, else emu->gpr_base = FXGPREGBASE; - if ((err = pci_request_regions(pci, "EMU10K1")) < 0) { + err = pci_request_regions(pci, "EMU10K1"); + if (err < 0) { kfree(emu); pci_disable_device(pci); return err; @@ -1864,21 +1873,25 @@ int __devinit snd_emu10k1_create(struct snd_card *card, emu->enable_ir = enable_ir; if (emu->card_capabilities->ca_cardbus_chip) { - if ((err = snd_emu10k1_cardbus_init(emu)) < 0) + err = snd_emu10k1_cardbus_init(emu); + if (err < 0) goto error; } if (emu->card_capabilities->ecard) { - if ((err = snd_emu10k1_ecard_init(emu)) < 0) + err = snd_emu10k1_ecard_init(emu); + if (err < 0) goto error; } else if (emu->card_capabilities->emu_model) { - if ((err = snd_emu10k1_emu1010_init(emu)) < 0) { - snd_emu10k1_free(emu); - return err; - } + err = snd_emu10k1_emu1010_init(emu); + if (err < 0) { + snd_emu10k1_free(emu); + return err; + } } else { /* 5.1: Enable the additional AC97 Slots. If the emu10k1 version does not support this, it shouldn't do any harm */ - snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); + snd_emu10k1_ptr_write(emu, AC97SLOT, 0, + AC97SLOT_CNTR|AC97SLOT_LFE); } /* initialize TRAM setup */ @@ -1918,7 +1931,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card, snd_emu10k1_synth_alloc(emu, 4096); if (emu->reserved_page) emu->reserved_page->map_locked = 1; - + /* Clear silent pages and set up pointers */ memset(emu->silent_page.area, 0, PAGE_SIZE); silent_page = emu->silent_page.addr << 1; @@ -1931,19 +1944,23 @@ int __devinit snd_emu10k1_create(struct snd_card *card, emu->voices[idx].number = idx; } - if ((err = snd_emu10k1_init(emu, enable_ir, 0)) < 0) + err = snd_emu10k1_init(emu, enable_ir, 0); + if (err < 0) goto error; #ifdef CONFIG_PM - if ((err = alloc_pm_buffer(emu)) < 0) + err = alloc_pm_buffer(emu); + if (err < 0) goto error; #endif /* Initialize the effect engine */ - if ((err = snd_emu10k1_init_efx(emu)) < 0) + err = snd_emu10k1_init_efx(emu); + if (err < 0) goto error; snd_emu10k1_audio_enable(emu); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops)) < 0) + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops); + if (err < 0) goto error; #ifdef CONFIG_PROC_FS @@ -1983,7 +2000,7 @@ static int __devinit alloc_pm_buffer(struct snd_emu10k1 *emu) if (emu->audigy) size += ARRAY_SIZE(saved_regs_audigy); emu->saved_ptr = vmalloc(4 * NUM_G * size); - if (! emu->saved_ptr) + if (!emu->saved_ptr) return -ENOMEM; if (snd_emu10k1_efx_alloc_pm_buffer(emu) < 0) return -ENOMEM; @@ -2028,7 +2045,7 @@ void snd_emu10k1_resume_init(struct snd_emu10k1 *emu) if (emu->card_capabilities->ecard) snd_emu10k1_ecard_init(emu); else if (emu->card_capabilities->emu_model) - snd_emu10k1_emu1010_init(emu); + snd_emu10k1_emu1010_init(emu); else snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); snd_emu10k1_init(emu, emu->enable_ir, 1); -- 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9a8adc600a57..eaa8b5676eae 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 a77ba223af40..c5f91c918d19 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 64ab19f14f79..b36d4d06485d 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d106ea52a90d..c24d22fddd09 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 7b0abf08a583..a13169cc95a2 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 4a08c31b498a..aac569b05599 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d300fc49f7e1..51479fba960e 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 51479fba960e..8477d6d46880 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8477d6d46880..d511ce4b11ad 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d511ce4b11ad..88e54db0582c 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 4074ea21493fe668501bfc7548d10657ca6f14c2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 1 Nov 2008 11:01:50 +0100 Subject: ALSA: ice1724 - Fix IRQ register initialization The IRQMASK register has to be set to zero expclitily at the initialization otherwise you'll get no interrupts properly at later operations. Also, removed the old commented out codes. Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1724.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 79a9cd0881f7..40725dfdc864 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2353,7 +2353,6 @@ static int __devinit snd_vt1724_create(struct snd_card *card, { struct snd_ice1712 *ice; int err; - /* unsigned char mask; */ static struct snd_device_ops ops = { .dev_free = snd_vt1724_dev_free, }; @@ -2414,11 +2413,9 @@ static int __devinit snd_vt1724_create(struct snd_card *card, return -EIO; } - /* unmask used interrupts */ -#if 0 /* these are enabled/disabled dynamically */ - mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX; - outb(mask, ICEREG1724(ice, IRQMASK)); -#endif + /* clear interrupts -- otherwise you'll get irq problems later */ + outb(0, ICEREG1724(ice, IRQMASK)); + /* don't handle FIFO overrun/underruns (just yet), * since they cause machine lockups */ -- 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 --- sound/pci/hda/patch_realtek.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 88e54db0582c..700fc8632c66 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 700fc8632c66..e727e48a48e3 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8991db78fb67..aa9cd142c30a 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index aa9cd142c30a..3e7cda9c3de5 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 (limited to 'sound/pci') diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 7e408908b755..21e9327a0ef4 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 1980c6d207e7..6fb5add1e39a 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 3e7cda9c3de5..45695d608c76 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 dfbcfa88da44..38212c1020a6 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 000000000000..8059102dd862 --- /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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 8059102dd862..3beaf9c1090c 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 --- sound/pci/hda/patch_realtek.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e727e48a48e3..15779d8c7564 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 --- sound/pci/hda/patch_realtek.c | 44 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 15779d8c7564..425b0fc86f7d 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 6834d7ce224a6f6a1dd05da3a867730c40943154 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 5 Nov 2008 17:41:23 +0100 Subject: ALSA: ice1724 - Re-fix IRQ mask initialization The previous IRQ mask initialization was wrong. It must set the bits to be masked. Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1724.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 40725dfdc864..0dfa0540ce2c 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -395,8 +395,8 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) "status = 0x%x\n", status); if (status & VT1724_IRQ_MPU_TX) { printk(KERN_ERR "ice1724: Disabling MPU_TX\n"); - outb(inb(ICEREG1724(ice, IRQMASK)) & - ~VT1724_IRQ_MPU_TX, + outb(inb(ICEREG1724(ice, IRQMASK)) | + VT1724_IRQ_MPU_TX, ICEREG1724(ice, IRQMASK)); } break; @@ -2413,8 +2413,8 @@ static int __devinit snd_vt1724_create(struct snd_card *card, return -EIO; } - /* clear interrupts -- otherwise you'll get irq problems later */ - outb(0, ICEREG1724(ice, IRQMASK)); + /* MPU_RX and TX irq masks are cleared later dynamically */ + outb(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX , ICEREG1724(ice, IRQMASK)); /* don't handle FIFO overrun/underruns (just yet), * since they cause machine lockups -- 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 45695d608c76..810465bac550 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 c5f91c918d19..a73f0eb99283 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 614be2ec806f..bf8e6f94aebc 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index bf8e6f94aebc..f3c447cf67f8 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 425b0fc86f7d..98a02fd1097e 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 810465bac550..f13834ba6b1d 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f13834ba6b1d..6f170b281e85 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 6f170b281e85..06e99c785155 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0f1fa1dac448..017abd01299d 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f3c447cf67f8..3e112df1c0dc 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 06e99c785155..5d5e8012d6a5 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 a73f0eb99283..ee122b009fd4 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 972d4c50fbbb1b9c10293ff90e4e1d45e7fb21ac Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 12 Nov 2008 16:37:48 +0100 Subject: ALSA: hdsp/hdspm: remove card->id from rawmidi device name The card->id (card text identification) can be changed at runtime. It might be confusing to have old text identification in device name. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdsp.c | 2 +- sound/pci/rme9652/hdspm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 736246f98acc..fdd3be5b439d 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -1452,7 +1452,7 @@ static int snd_hdsp_create_midi (struct snd_card *card, struct hdsp *hdsp, int i if (snd_rawmidi_new (card, buf, id, 1, 1, &hdsp->midi[id].rmidi) < 0) return -1; - sprintf (hdsp->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1); + sprintf(hdsp->midi[id].rmidi->name, "HDSP MIDI %d", id+1); hdsp->midi[id].rmidi->private_data = &hdsp->midi[id]; snd_rawmidi_set_ops (hdsp->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdsp_midi_output); diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 98762f909d64..dc5c4baa1e64 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1293,7 +1293,7 @@ static int __devinit snd_hdspm_create_midi (struct snd_card *card, if (err < 0) return err; - sprintf (hdspm->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1); + sprintf(hdspm->midi[id].rmidi->name, "HDSPM MIDI %d", id+1); hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; snd_rawmidi_set_ops(hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, -- 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index ba61575983fd..5603a1acddb1 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 3beaf9c1090c..939b37ba7074 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3e112df1c0dc..f73c13fdd409 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 58d832c3835a..66c12d3e9c79 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 017abd01299d..04e153a77dbc 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6d9c634632d4..1aa3f6cbcb96 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 939b37ba7074..d99cd6297249 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 760e14ae3bff..05182be1c9f0 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index aac569b05599..d7e3a164effe 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 64b6a38fa963..512eb674b743 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 (limited to 'sound/pci') diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 21e9327a0ef4..157a0a6b10ae 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 6fb5add1e39a..6daf5fd9a279 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 000000000000..a69a7e87d26a --- /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 d7e3a164effe..e1b76686672a 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 d99cd6297249..489278d3d773 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index a69a7e87d26a..7fa065cd1d9c 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 e1b76686672a..02ac7321e5e4 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 489278d3d773..c95abc47614f 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 1aa3f6cbcb96..b6cf821434c8 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index b6cf821434c8..bf9a40ee789e 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index bf9a40ee789e..3029f5b1419a 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 04e153a77dbc..b7d34390eff4 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index c95abc47614f..028fce996aa2 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 7fa065cd1d9c..18078de0abcc 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 02ac7321e5e4..0baa9b816ca8 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 028fce996aa2..6b5c3e2cf93b 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 6b5c3e2cf93b..747aa84d0ecd 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 139efe37f3b3..c346c77e3068 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 18078de0abcc..da08ddaef4fc 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 747aa84d0ecd..459b04576de1 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index da08ddaef4fc..1b3ec1e7f268 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 0baa9b816ca8..a1473c6cb4bf 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 459b04576de1..5393f84f6755 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 1b3ec1e7f268..75e9a4014f4e 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 75e9a4014f4e..8e575bb56ff7 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 a1473c6cb4bf..a2d01a9a0b16 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 512eb674b743..d956e9769133 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 8e575bb56ff7..e848c30d9bf7 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index d956e9769133..31b49bdc58f5 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f73c13fdd409..3870ad622da6 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 --- sound/pci/hda/patch_realtek.c | 115 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b7d34390eff4..6ec56c62cb18 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 --- sound/pci/hda/patch_analog.c | 49 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 032cbb4bd985..0cc6be12b8b7 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index e848c30d9bf7..9d3e542d74a5 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 31b49bdc58f5..56cee3a22214 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 9d3e542d74a5..248cddf0ee80 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 248cddf0ee80..d2b7ccca3bb3 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index a2d01a9a0b16..c71505a4f99d 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5d5e8012d6a5..a98ce5b11188 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 ee122b009fd4..a70b181bbace 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 a501c9121649..4fa5189264b7 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index d2b7ccca3bb3..8740e7be8b24 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 c71505a4f99d..bf7ba8b62973 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 5393f84f6755..58aaf06589a8 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(-) (limited to 'sound/pci') diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 157a0a6b10ae..cc6cf89c32e6 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 653da1d3e4df..5868bbc131cd 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 bf7ba8b62973..6f2fe0f9fdd8 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 (limited to 'sound/pci') diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index cc6cf89c32e6..caebf296b62b 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 000000000000..7c60f1a45a8d --- /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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 2eed2c8b98da..1360d54a7d01 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 4fa5189264b7..cf3641f9ebe9 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a98ce5b11188..d56d11ab20a3 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 56cee3a22214..e7f91c44e631 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 58aaf06589a8..e10fa1e3dc9b 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index e10fa1e3dc9b..4a48011ae35b 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 8740e7be8b24..3f10961a17b4 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 4a48011ae35b..fe08bef897cd 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 3f10961a17b4..3c580ae07bd6 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 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 3c580ae07bd6..aa438562efc7 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index aa438562efc7..fcad5ec31773 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index ce34e4dfe985..7cd395a175ef 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 --- sound/pci/hda/patch_realtek.c | 176 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 167 insertions(+), 9 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6ec56c62cb18..f52e271edd57 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3870ad622da6..6462d758e641 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index e7f91c44e631..a2eba4f17e9c 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 09b3f4b1db4d..4b7dda57c0e9 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 93bf5d8753b2e3cc9e8982d551d119a54a31a7ec Mon Sep 17 00:00:00 2001 From: Markus Bollinger Date: Tue, 25 Nov 2008 12:21:05 +0100 Subject: ALSA: pcxhr - add support for pcxhr stereo sound cards - Add support for pcxhr stereo cards - do some clean up Signed-off-by: Markus Bollinger Signed-off-by: Takashi Iwai --- sound/pci/pcxhr/pcxhr_core.c | 291 +++++++++++++++++++++++++++---------------- sound/pci/pcxhr/pcxhr_core.h | 5 +- 2 files changed, 190 insertions(+), 106 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index 7143259cfe34..d5f18226261d 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -132,13 +132,15 @@ static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg, *read = PCXHR_INPB(mgr, reg); if ((*read & mask) == bit) { if (i > 100) - snd_printdd("ATTENTION! check_reg(%x) loopcount=%d\n", + snd_printdd("ATTENTION! check_reg(%x) " + "loopcount=%d\n", reg, i); return 0; } i++; } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_ERR "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=0x%x\n", + snd_printk(KERN_ERR + "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=%x\n", reg, mask, *read); return -EIO; } @@ -159,18 +161,22 @@ static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg, #define PCXHR_IT_TEST_XILINX (0x0000003C | PCXHR_MASK_IT_HF1 | \ PCXHR_MASK_IT_MANAGE_HF5) #define PCXHR_IT_DOWNLOAD_BOOT (0x0000000C | PCXHR_MASK_IT_HF1 | \ - PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT) + PCXHR_MASK_IT_MANAGE_HF5 | \ + PCXHR_MASK_IT_WAIT) #define PCXHR_IT_RESET_BOARD_FUNC (0x0000000C | PCXHR_MASK_IT_HF0 | \ - PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT_EXTRA) + PCXHR_MASK_IT_MANAGE_HF5 | \ + PCXHR_MASK_IT_WAIT_EXTRA) #define PCXHR_IT_DOWNLOAD_DSP (0x0000000C | \ - PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT) + PCXHR_MASK_IT_MANAGE_HF5 | \ + PCXHR_MASK_IT_WAIT) #define PCXHR_IT_DEBUG (0x0000005A | PCXHR_MASK_IT_NO_HF0_HF1) #define PCXHR_IT_RESET_SEMAPHORE (0x0000005C | PCXHR_MASK_IT_NO_HF0_HF1) #define PCXHR_IT_MESSAGE (0x00000074 | PCXHR_MASK_IT_NO_HF0_HF1) #define PCXHR_IT_RESET_CHK (0x00000076 | PCXHR_MASK_IT_NO_HF0_HF1) #define PCXHR_IT_UPDATE_RBUFFER (0x00000078 | PCXHR_MASK_IT_NO_HF0_HF1) -static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atomic) +static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, + unsigned int itdsp, int atomic) { int err; unsigned char reg; @@ -178,17 +184,21 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atom if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) { /* clear hf5 bit */ PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0, - PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & ~PCXHR_MBOX0_HF5); + PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & + ~PCXHR_MBOX0_HF5); } if ((itdsp & PCXHR_MASK_IT_NO_HF0_HF1) == 0) { - reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ; + reg = (PCXHR_ICR_HI08_RREQ | + PCXHR_ICR_HI08_TREQ | + PCXHR_ICR_HI08_HDRQ); if (itdsp & PCXHR_MASK_IT_HF0) reg |= PCXHR_ICR_HI08_HF0; if (itdsp & PCXHR_MASK_IT_HF1) reg |= PCXHR_ICR_HI08_HF1; PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg); } - reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) | PCXHR_CVR_HI08_HC); + reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) | + PCXHR_CVR_HI08_HC); PCXHR_OUTPB(mgr, PCXHR_DSP_CVR, reg); if (itdsp & PCXHR_MASK_IT_WAIT) { if (atomic) @@ -211,10 +221,14 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atom } if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) { /* wait for hf5 bit */ - err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0, PCXHR_MBOX0_HF5, - PCXHR_MBOX0_HF5, PCXHR_TIMEOUT_DSP, ®); + err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0, + PCXHR_MBOX0_HF5, + PCXHR_MBOX0_HF5, + PCXHR_TIMEOUT_DSP, + ®); if (err) { - snd_printk(KERN_ERR "pcxhr_send_it_dsp : TIMEOUT HF5\n"); + snd_printk(KERN_ERR + "pcxhr_send_it_dsp : TIMEOUT HF5\n"); return err; } } @@ -263,7 +277,8 @@ void pcxhr_enable_dsp(struct pcxhr_mgr *mgr) /* * load the xilinx image */ -int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilinx, int second) +int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, + const struct firmware *xilinx, int second) { unsigned int i; unsigned int chipsc; @@ -274,7 +289,9 @@ int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilin /* test first xilinx */ chipsc = PCXHR_INPL(mgr, PCXHR_PLX_CHIPSC); /* REV01 cards do not support the PCXHR_CHIPSC_GPI_USERI bit anymore */ - /* this bit will always be 1; no possibility to test presence of first xilinx */ + /* this bit will always be 1; + * no possibility to test presence of first xilinx + */ if(second) { if ((chipsc & PCXHR_CHIPSC_GPI_USERI) == 0) { snd_printk(KERN_ERR "error loading first xilinx\n"); @@ -290,7 +307,8 @@ int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilin data = *image; mask = 0x80; while (mask) { - chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | PCXHR_CHIPSC_DATA_IN); + chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | + PCXHR_CHIPSC_DATA_IN); if (data & mask) chipsc |= PCXHR_CHIPSC_DATA_IN; PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc); @@ -330,15 +348,20 @@ static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp) data = dsp->data + i; if (i == 0) { /* test data header consistency */ - len = (unsigned int)((data[0]<<16) + (data[1]<<8) + data[2]); - if (len && dsp->size != (len + 2) * 3) + len = (unsigned int)((data[0]<<16) + + (data[1]<<8) + + data[2]); + if (len && (dsp->size != (len + 2) * 3)) return -EINVAL; } /* wait DSP ready for new transfer */ - err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY, - PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, &dummy); + err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, + PCXHR_ISR_HI08_TRDY, + PCXHR_ISR_HI08_TRDY, + PCXHR_TIMEOUT_DSP, &dummy); if (err) { - snd_printk(KERN_ERR "dsp loading error at position %d\n", i); + snd_printk(KERN_ERR + "dsp loading error at position %d\n", i); return err; } /* send host data */ @@ -357,7 +380,8 @@ static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp) /* * load the eeprom image */ -int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, const struct firmware *eeprom) +int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, + const struct firmware *eeprom) { int err; unsigned char reg; @@ -365,7 +389,9 @@ int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, const struct firmware *eepro /* init value of the ICR register */ reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ; if (PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & PCXHR_MBOX0_BOOT_HERE) { - /* no need to load the eeprom binary, but init the HI08 interface */ + /* no need to load the eeprom binary, + * but init the HI08 interface + */ PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg | PCXHR_ICR_HI08_INIT); msleep(PCXHR_WAIT_DEFAULT); PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg); @@ -429,8 +455,10 @@ int pcxhr_load_dsp_binary(struct pcxhr_mgr *mgr, const struct firmware *dsp) if (err) return err; /* wait for chk bit */ - return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK, - PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &dummy); + return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, + PCXHR_ISR_HI08_CHK, + PCXHR_ISR_HI08_CHK, + PCXHR_TIMEOUT_DSP, &dummy); } @@ -443,8 +471,8 @@ struct pcxhr_cmd_info { /* RMH status type */ enum { RMH_SSIZE_FIXED = 0, /* status size fix (st_length = 0..x) */ - RMH_SSIZE_ARG = 1, /* status size given in the LSB byte (used with st_length = 1) */ - RMH_SSIZE_MASK = 2, /* status size given in bitmask (used with st_length = 1) */ + RMH_SSIZE_ARG = 1, /* status size given in the LSB byte */ + RMH_SSIZE_MASK = 2, /* status size given in bitmask */ }; /* @@ -474,7 +502,7 @@ static struct pcxhr_cmd_info pcxhr_dsp_cmds[] = { [CMD_UPDATE_R_BUFFERS] = { 0x840000, 0, RMH_SSIZE_FIXED }, [CMD_FORMAT_STREAM_OUT] = { 0x860000, 0, RMH_SSIZE_FIXED }, [CMD_FORMAT_STREAM_IN] = { 0x870000, 0, RMH_SSIZE_FIXED }, -[CMD_STREAM_SAMPLE_COUNT] = { 0x902000, 2, RMH_SSIZE_FIXED }, /* stat_len = nb_streams * 2 */ +[CMD_STREAM_SAMPLE_COUNT] = { 0x902000, 2, RMH_SSIZE_FIXED }, [CMD_AUDIO_LEVEL_ADJUST] = { 0xc22000, 0, RMH_SSIZE_FIXED }, }; @@ -524,10 +552,13 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) for (i = 0; i < rmh->stat_len; i++) { /* wait for receiver full */ - err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_RXDF, - PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, ®); + err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, + PCXHR_ISR_HI08_RXDF, + PCXHR_ISR_HI08_RXDF, + PCXHR_TIMEOUT_DSP, ®); if (err) { - snd_printk(KERN_ERR "ERROR RMH stat: ISR:RXDF=1 (ISR = %x; i=%d )\n", + snd_printk(KERN_ERR "ERROR RMH stat: " + "ISR:RXDF=1 (ISR = %x; i=%d )\n", reg, i); return err; } @@ -537,10 +568,10 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL); /* need to update rmh->stat_len on the fly ?? */ - if (i==0) { + if (!i) { if (rmh->dsp_stat != RMH_SSIZE_FIXED) { if (rmh->dsp_stat == RMH_SSIZE_ARG) { - rmh->stat_len = (u16)(data & 0x0000ff) + 1; + rmh->stat_len = (data & 0x0000ff) + 1; data &= 0xffff00; } else { /* rmh->dsp_stat == RMH_SSIZE_MASK */ @@ -562,7 +593,8 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) rmh->stat[i] = data; } if (rmh->stat_len > max_stat_len) { - snd_printdd("PCXHR : rmh->stat_len=%x too big\n", rmh->stat_len); + snd_printdd("PCXHR : rmh->stat_len=%x too big\n", + rmh->stat_len); rmh->stat_len = max_stat_len; } return 0; @@ -605,7 +637,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) data &= 0xff7fff; /* MASK_1_WORD_COMMAND */ #ifdef CONFIG_SND_DEBUG_VERBOSE if (rmh->cmd_idx < CMD_LAST_INDEX) - snd_printdd("MSG cmd[0]=%x (%s)\n", data, cmd_names[rmh->cmd_idx]); + snd_printdd("MSG cmd[0]=%x (%s)\n", + data, cmd_names[rmh->cmd_idx]); #endif err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY, @@ -619,8 +652,10 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) if (rmh->cmd_len > 1) { /* send length */ data = rmh->cmd_len - 1; - err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY, - PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, ®); + err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, + PCXHR_ISR_HI08_TRDY, + PCXHR_ISR_HI08_TRDY, + PCXHR_TIMEOUT_DSP, ®); if (err) return err; PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF); @@ -653,8 +688,10 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) /* test status ISR */ if (reg & PCXHR_ISR_HI08_ERR) { /* ERROR, wait for receiver full */ - err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_RXDF, - PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, ®); + err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, + PCXHR_ISR_HI08_RXDF, + PCXHR_ISR_HI08_RXDF, + PCXHR_TIMEOUT_DSP, ®); if (err) { snd_printk(KERN_ERR "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg); return err; @@ -663,7 +700,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) data = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16; data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8; data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL); - snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n", rmh->cmd_idx, data); + snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n", + rmh->cmd_idx, data); err = -EINVAL; } else { /* read the response data */ @@ -732,8 +770,9 @@ int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr) { int start_mask = PCXHR_INPL(mgr, PCXHR_PLX_MBOX2); - /* least segnificant 12 bits are the pipe states for the playback audios */ - /* next 12 bits are the pipe states for the capture audios + /* least segnificant 12 bits are the pipe states + * for the playback audios + * next 12 bits are the pipe states for the capture audios * (PCXHR_PIPE_STATE_CAPTURE_OFFSET) */ start_mask &= 0xffffff; @@ -744,7 +783,8 @@ static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr) #define PCXHR_PIPE_STATE_CAPTURE_OFFSET 12 #define MAX_WAIT_FOR_DSP 20 -static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, int audio_mask, int *retry) +static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, + int audio_mask, int *retry) { struct pcxhr_rmh rmh; int err; @@ -760,17 +800,20 @@ static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, int audio_mask, int * } else { /* can start capture pipe */ pcxhr_set_pipe_cmd_params(&rmh, 1, audio - - PCXHR_PIPE_STATE_CAPTURE_OFFSET, - 0, 0); + PCXHR_PIPE_STATE_CAPTURE_OFFSET, + 0, 0); } err = pcxhr_send_msg(mgr, &rmh); if (err) { snd_printk(KERN_ERR - "error pipe start (CMD_CAN_START_PIPE) err=%x!\n", + "error pipe start " + "(CMD_CAN_START_PIPE) err=%x!\n", err); return err; } - /* if the pipe couldn't be prepaired for start, retry it later */ + /* if the pipe couldn't be prepaired for start, + * retry it later + */ if (rmh.stat[0] == 0) *retry |= (1<= MAX_WAIT_FOR_DSP * 100) { - snd_printk(KERN_ERR "error pipe start/stop (ED_NO_RESPONSE_AT_IRQA)\n"); + snd_printk(KERN_ERR "error pipe start/stop\n"); return -EBUSY; } udelay(10); /* wait 10 microseconds */ @@ -918,7 +967,8 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask, spin_lock_irqsave(&mgr->msg_lock, flags); if ((mgr->io_num_reg_cont & mask) == value) { - snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n", mask, value); + snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n", + mask, value); if (changed) *changed = 0; spin_unlock_irqrestore(&mgr->msg_lock, flags); @@ -971,7 +1021,8 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err, err = ((err >> 12) & 0xfff); if (!err) return 0; - snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n", err_src_name[err_src], + snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n", + err_src_name[err_src], is_capture ? "Record" : "Play", pipe, err); if (err == 0xe01) mgr->async_err_stream_xrun++; @@ -996,6 +1047,13 @@ void pcxhr_msg_tasklet(unsigned long arg) snd_printdd("TASKLET : PCXHR_IRQ_TIME_CODE event occured\n"); if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY) snd_printdd("TASKLET : PCXHR_IRQ_NOTIFY event occured\n"); + if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) { + /* clear events FREQ_CHANGE and TIME_CODE */ + pcxhr_init_rmh(prmh, CMD_TEST_IT); + err = pcxhr_send_msg(mgr, prmh); + snd_printdd("CMD_TEST_IT : err=%x, stat=%x\n", + err, prmh->stat[0]); + } if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) { snd_printdd("TASKLET : PCXHR_IRQ_ASYNC event occured\n"); @@ -1005,18 +1063,22 @@ void pcxhr_msg_tasklet(unsigned long arg) prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS; err = pcxhr_send_msg(mgr, prmh); if (err) - snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n", err); + snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n", + err); i = 1; while (i < prmh->stat_len) { - int nb_audio = (prmh->stat[i] >> FIELD_SIZE) & MASK_FIRST_FIELD; - int nb_stream = (prmh->stat[i] >> (2*FIELD_SIZE)) & MASK_FIRST_FIELD; + int nb_audio = ((prmh->stat[i] >> FIELD_SIZE) & + MASK_FIRST_FIELD); + int nb_stream = ((prmh->stat[i] >> (2*FIELD_SIZE)) & + MASK_FIRST_FIELD); int pipe = prmh->stat[i] & MASK_FIRST_FIELD; int is_capture = prmh->stat[i] & 0x400000; u32 err2; if (prmh->stat[i] & 0x800000) { /* if BIT_END */ snd_printdd("TASKLET : End%sPipe %d\n", - is_capture ? "Record" : "Play", pipe); + is_capture ? "Record" : "Play", + pipe); } i++; err2 = prmh->stat[i] ? prmh->stat[i] : prmh->stat[i+1]; @@ -1062,7 +1124,7 @@ static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr, pcxhr_init_rmh(&rmh, CMD_STREAM_SAMPLE_COUNT); pcxhr_set_pipe_cmd_params(&rmh, stream->pipe->is_capture, stream->pipe->first_audio, 0, stream_mask); - /* rmh.stat_len = 2; */ /* 2 resp data for each stream of the pipe */ + /* rmh.stat_len = 2; */ /* 2 resp data for each stream of the pipe */ err = pcxhr_send_msg(mgr, &rmh); if (err) @@ -1072,18 +1134,21 @@ static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr, hw_sample_count += (u_int64_t)rmh.stat[1]; snd_printdd("stream %c%d : abs samples real(%ld) timer(%ld)\n", - stream->pipe->is_capture ? 'C':'P', stream->substream->number, + stream->pipe->is_capture ? 'C' : 'P', + stream->substream->number, (long unsigned int)hw_sample_count, (long unsigned int)(stream->timer_abs_periods + - stream->timer_period_frag + PCXHR_GRANULARITY)); - + stream->timer_period_frag + + mgr->granularity)); return hw_sample_count; } static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, - struct pcxhr_stream *stream, int samples_to_add) + struct pcxhr_stream *stream, + int samples_to_add) { - if (stream->substream && (stream->status == PCXHR_STREAM_STATUS_RUNNING)) { + if (stream->substream && + (stream->status == PCXHR_STREAM_STATUS_RUNNING)) { u_int64_t new_sample_count; int elapsed = 0; int hardware_read = 0; @@ -1092,20 +1157,22 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, if (samples_to_add < 0) { stream->timer_is_synced = 0; /* add default if no hardware_read possible */ - samples_to_add = PCXHR_GRANULARITY; + samples_to_add = mgr->granularity; } if (!stream->timer_is_synced) { - if (stream->timer_abs_periods != 0 || - stream->timer_period_frag + PCXHR_GRANULARITY >= - runtime->period_size) { - new_sample_count = pcxhr_stream_read_position(mgr, stream); + if ((stream->timer_abs_periods != 0) || + ((stream->timer_period_frag + samples_to_add) >= + runtime->period_size)) { + new_sample_count = + pcxhr_stream_read_position(mgr, stream); hardware_read = 1; - if (new_sample_count >= PCXHR_GRANULARITY_MIN) { - /* sub security offset because of jitter and - * finer granularity of dsp time (MBOX4) + if (new_sample_count >= mgr->granularity) { + /* sub security offset because of + * jitter and finer granularity of + * dsp time (MBOX4) */ - new_sample_count -= PCXHR_GRANULARITY_MIN; + new_sample_count -= mgr->granularity; stream->timer_is_synced = 1; } } @@ -1128,12 +1195,15 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, stream->timer_buf_periods = 0; stream->timer_abs_periods = new_elapse_pos; } - if (new_sample_count >= stream->timer_abs_periods) - stream->timer_period_frag = (u_int32_t)(new_sample_count - - stream->timer_abs_periods); - else - snd_printk(KERN_ERR "ERROR new_sample_count too small ??? %lx\n", + if (new_sample_count >= stream->timer_abs_periods) { + stream->timer_period_frag = + (u_int32_t)(new_sample_count - + stream->timer_abs_periods); + } else { + snd_printk(KERN_ERR + "ERROR new_sample_count too small ??? %ld\n", (long unsigned int)new_sample_count); + } if (elapsed) { spin_unlock(&mgr->lock); @@ -1143,7 +1213,6 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, } } - irqreturn_t pcxhr_interrupt(int irq, void *dev_id) { struct pcxhr_mgr *mgr = dev_id; @@ -1156,7 +1225,8 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS); if (! (reg & PCXHR_IRQCS_ACTIVE_PCIDB)) { spin_unlock(&mgr->lock); - return IRQ_NONE; /* this device did not cause the interrupt */ + /* this device did not cause the interrupt */ + return IRQ_NONE; } /* clear interrupt */ @@ -1167,10 +1237,12 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) if (reg & PCXHR_IRQ_TIMER) { int timer_toggle = reg & PCXHR_IRQ_TIMER; /* is a 24 bit counter */ - int dsp_time_new = PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK; + int dsp_time_new = + PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK; int dsp_time_diff = dsp_time_new - mgr->dsp_time_last; - if (dsp_time_diff < 0 && mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID) { + if ((dsp_time_diff < 0) && + (mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID)) { snd_printdd("ERROR DSP TIME old(%d) new(%d) -> " "resynchronize all streams\n", mgr->dsp_time_last, dsp_time_new); @@ -1178,40 +1250,49 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) } #ifdef CONFIG_SND_DEBUG_VERBOSE if (dsp_time_diff == 0) - snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", dsp_time_new); - else if (dsp_time_diff >= (2*PCXHR_GRANULARITY)) + snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", + dsp_time_new); + else if (dsp_time_diff >= (2*mgr->granularity)) snd_printdd("ERROR DSP TIME TOO BIG old(%d) add(%d)\n", - mgr->dsp_time_last, dsp_time_new - mgr->dsp_time_last); + mgr->dsp_time_last, + dsp_time_new - mgr->dsp_time_last); + else if (dsp_time_diff % mgr->granularity) + snd_printdd("ERROR DSP TIME increased by %d\n", + dsp_time_diff); #endif mgr->dsp_time_last = dsp_time_new; - if (timer_toggle == mgr->timer_toggle) + if (timer_toggle == mgr->timer_toggle) { snd_printdd("ERROR TIMER TOGGLE\n"); + mgr->dsp_time_err++; + } mgr->timer_toggle = timer_toggle; reg &= ~PCXHR_IRQ_TIMER; for (i = 0; i < mgr->num_cards; i++) { chip = mgr->chip[i]; for (j = 0; j < chip->nb_streams_capt; j++) - pcxhr_update_timer_pos(mgr, &chip->capture_stream[j], - dsp_time_diff); + pcxhr_update_timer_pos(mgr, + &chip->capture_stream[j], + dsp_time_diff); } for (i = 0; i < mgr->num_cards; i++) { chip = mgr->chip[i]; for (j = 0; j < chip->nb_streams_play; j++) - pcxhr_update_timer_pos(mgr, &chip->playback_stream[j], - dsp_time_diff); + pcxhr_update_timer_pos(mgr, + &chip->playback_stream[j], + dsp_time_diff); } } /* other irq's handled in the tasklet */ if (reg & PCXHR_IRQ_MASK) { - - /* as we didn't request any notifications, some kind of xrun error - * will probably occured - */ - /* better resynchronize all streams next interrupt : */ - mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; - + if (reg & PCXHR_IRQ_ASYNC) { + /* as we didn't request any async notifications, + * some kind of xrun error will probably occured + */ + /* better resynchronize all streams next interrupt : */ + mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; + } mgr->src_it_dsp = reg; tasklet_hi_schedule(&mgr->msg_taskq); } diff --git a/sound/pci/pcxhr/pcxhr_core.h b/sound/pci/pcxhr/pcxhr_core.h index d9a4ab609875..bbbd66d13a64 100644 --- a/sound/pci/pcxhr/pcxhr_core.h +++ b/sound/pci/pcxhr/pcxhr_core.h @@ -65,7 +65,7 @@ enum { CMD_RESYNC_AUDIO_INPUTS, /* cmd_len = 1 stat_len = 0 */ CMD_GET_DSP_RESOURCES, /* cmd_len = 1 stat_len = 4 */ CMD_SET_TIMER_INTERRUPT, /* cmd_len = 1 stat_len = 0 */ - CMD_RES_PIPE, /* cmd_len = 2 stat_len = 0 */ + CMD_RES_PIPE, /* cmd_len >=2 stat_len = 0 */ CMD_FREE_PIPE, /* cmd_len = 1 stat_len = 0 */ CMD_CONF_PIPE, /* cmd_len = 2 stat_len = 0 */ CMD_STOP_PIPE, /* cmd_len = 1 stat_len = 0 */ @@ -96,6 +96,8 @@ void pcxhr_init_rmh(struct pcxhr_rmh *rmh, int cmd); void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh* rmh, int capture, unsigned int param1, unsigned int param2, unsigned int param3); +#define DSP_EXT_CMD_SET(x) (x->dsp_version > 0x012800) + /* send the rmh */ @@ -110,6 +112,7 @@ int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh); #define IO_NUM_REG_STATUS 5 #define IO_NUM_REG_CUER 10 #define IO_NUM_UER_CHIP_REG 11 +#define IO_NUM_REG_CONFIG_SRC 12 #define IO_NUM_REG_OUT_ANA_LEVEL 20 #define IO_NUM_REG_IN_ANA_LEVEL 21 -- cgit v1.2.3 From 9d948d270010e3552c94281bab75694580ca23e9 Mon Sep 17 00:00:00 2001 From: Markus Bollinger Date: Tue, 25 Nov 2008 12:24:54 +0100 Subject: ALSA: pcxhr - add support for pcxhr stereo sound cards (core change) - Add support for pcxhr stereo cards - minor bugfixes : period and buffer size consraints - fix PLL register values - do some clean up Signed-off-by: Markus Bollinger Signed-off-by: Takashi Iwai --- sound/pci/pcxhr/pcxhr.c | 552 +++++++++++++++++++++++++++++++++--------------- sound/pci/pcxhr/pcxhr.h | 76 ++++--- 2 files changed, 433 insertions(+), 195 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 73de6e989b3d..0327925828d1 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -40,18 +40,20 @@ #include "pcxhr_mixer.h" #include "pcxhr_hwdep.h" #include "pcxhr_core.h" +#include "pcxhr_mix22.h" #define DRIVER_NAME "pcxhr" -MODULE_AUTHOR("Markus Bollinger "); +MODULE_AUTHOR("Markus Bollinger , " + "Marc Titinger "); MODULE_DESCRIPTION("Digigram " DRIVER_NAME " " PCXHR_DRIVER_VERSION_STRING); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Digigram," DRIVER_NAME "}}"); -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static int mono[SNDRV_CARDS]; /* capture in mono only */ +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ +static int mono[SNDRV_CARDS]; /* capture mono only */ module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Digigram " DRIVER_NAME " soundcard"); @@ -67,18 +69,58 @@ enum { PCI_ID_PCX882HR, PCI_ID_VX881HR, PCI_ID_PCX881HR, + PCI_ID_VX882E, + PCI_ID_PCX882E, + PCI_ID_VX881E, + PCI_ID_PCX881E, + PCI_ID_VX1222HR, PCI_ID_PCX1222HR, + PCI_ID_VX1221HR, PCI_ID_PCX1221HR, + PCI_ID_VX1222E, + PCI_ID_PCX1222E, + PCI_ID_VX1221E, + PCI_ID_PCX1221E, + PCI_ID_VX222HR, + PCI_ID_VX222E, + PCI_ID_PCX22HR, + PCI_ID_PCX22E, + PCI_ID_VX222HRMIC, + PCI_ID_VX222E_MIC, + PCI_ID_PCX924HR, + PCI_ID_PCX924E, + PCI_ID_PCX924HRMIC, + PCI_ID_PCX924E_MIC, PCI_ID_LAST }; static struct pci_device_id pcxhr_ids[] = { - { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, }, /* VX882HR */ - { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, }, /* PCX882HR */ - { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, }, /* VX881HR */ - { 0x10b5, 0x9656, 0x1369, 0xb301, 0, 0, PCI_ID_PCX881HR, }, /* PCX881HR */ - { 0x10b5, 0x9656, 0x1369, 0xb501, 0, 0, PCI_ID_PCX1222HR, }, /* PCX1222HR */ - { 0x10b5, 0x9656, 0x1369, 0xb701, 0, 0, PCI_ID_PCX1221HR, }, /* PCX1221HR */ + { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, }, + { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, }, + { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, }, + { 0x10b5, 0x9656, 0x1369, 0xb301, 0, 0, PCI_ID_PCX881HR, }, + { 0x10b5, 0x9056, 0x1369, 0xb021, 0, 0, PCI_ID_VX882E, }, + { 0x10b5, 0x9056, 0x1369, 0xb121, 0, 0, PCI_ID_PCX882E, }, + { 0x10b5, 0x9056, 0x1369, 0xb221, 0, 0, PCI_ID_VX881E, }, + { 0x10b5, 0x9056, 0x1369, 0xb321, 0, 0, PCI_ID_PCX881E, }, + { 0x10b5, 0x9656, 0x1369, 0xb401, 0, 0, PCI_ID_VX1222HR, }, + { 0x10b5, 0x9656, 0x1369, 0xb501, 0, 0, PCI_ID_PCX1222HR, }, + { 0x10b5, 0x9656, 0x1369, 0xb601, 0, 0, PCI_ID_VX1221HR, }, + { 0x10b5, 0x9656, 0x1369, 0xb701, 0, 0, PCI_ID_PCX1221HR, }, + { 0x10b5, 0x9056, 0x1369, 0xb421, 0, 0, PCI_ID_VX1222E, }, + { 0x10b5, 0x9056, 0x1369, 0xb521, 0, 0, PCI_ID_PCX1222E, }, + { 0x10b5, 0x9056, 0x1369, 0xb621, 0, 0, PCI_ID_VX1221E, }, + { 0x10b5, 0x9056, 0x1369, 0xb721, 0, 0, PCI_ID_PCX1221E, }, + { 0x10b5, 0x9056, 0x1369, 0xba01, 0, 0, PCI_ID_VX222HR, }, + { 0x10b5, 0x9056, 0x1369, 0xba21, 0, 0, PCI_ID_VX222E, }, + { 0x10b5, 0x9056, 0x1369, 0xbd01, 0, 0, PCI_ID_PCX22HR, }, + { 0x10b5, 0x9056, 0x1369, 0xbd21, 0, 0, PCI_ID_PCX22E, }, + { 0x10b5, 0x9056, 0x1369, 0xbc01, 0, 0, PCI_ID_VX222HRMIC, }, + { 0x10b5, 0x9056, 0x1369, 0xbc21, 0, 0, PCI_ID_VX222E_MIC, }, + { 0x10b5, 0x9056, 0x1369, 0xbb01, 0, 0, PCI_ID_PCX924HR, }, + { 0x10b5, 0x9056, 0x1369, 0xbb21, 0, 0, PCI_ID_PCX924E, }, + { 0x10b5, 0x9056, 0x1369, 0xbf01, 0, 0, PCI_ID_PCX924HRMIC, }, + { 0x10b5, 0x9056, 0x1369, 0xbf21, 0, 0, PCI_ID_PCX924E_MIC, }, { 0, } }; @@ -88,27 +130,55 @@ struct board_parameters { char* board_name; short playback_chips; short capture_chips; + short fw_file_set; short firmware_num; }; static struct board_parameters pcxhr_board_params[] = { -[PCI_ID_VX882HR] = { "VX882HR", 4, 4, 41, }, -[PCI_ID_PCX882HR] = { "PCX882HR", 4, 4, 41, }, -[PCI_ID_VX881HR] = { "VX881HR", 4, 4, 41, }, -[PCI_ID_PCX881HR] = { "PCX881HR", 4, 4, 41, }, -[PCI_ID_PCX1222HR] = { "PCX1222HR", 6, 1, 42, }, -[PCI_ID_PCX1221HR] = { "PCX1221HR", 6, 1, 42, }, +[PCI_ID_VX882HR] = { "VX882HR", 4, 4, 0, 41 }, +[PCI_ID_PCX882HR] = { "PCX882HR", 4, 4, 0, 41 }, +[PCI_ID_VX881HR] = { "VX881HR", 4, 4, 0, 41 }, +[PCI_ID_PCX881HR] = { "PCX881HR", 4, 4, 0, 41 }, +[PCI_ID_VX882E] = { "VX882e", 4, 4, 1, 41 }, +[PCI_ID_PCX882E] = { "PCX882e", 4, 4, 1, 41 }, +[PCI_ID_VX881E] = { "VX881e", 4, 4, 1, 41 }, +[PCI_ID_PCX881E] = { "PCX881e", 4, 4, 1, 41 }, +[PCI_ID_VX1222HR] = { "VX1222HR", 6, 1, 2, 42 }, +[PCI_ID_PCX1222HR] = { "PCX1222HR", 6, 1, 2, 42 }, +[PCI_ID_VX1221HR] = { "VX1221HR", 6, 1, 2, 42 }, +[PCI_ID_PCX1221HR] = { "PCX1221HR", 6, 1, 2, 42 }, +[PCI_ID_VX1222E] = { "VX1222e", 6, 1, 3, 42 }, +[PCI_ID_PCX1222E] = { "PCX1222e", 6, 1, 3, 42 }, +[PCI_ID_VX1221E] = { "VX1221e", 6, 1, 3, 42 }, +[PCI_ID_PCX1221E] = { "PCX1221e", 6, 1, 3, 42 }, +[PCI_ID_VX222HR] = { "VX222HR", 1, 1, 4, 44 }, +[PCI_ID_VX222E] = { "VX222e", 1, 1, 4, 44 }, +[PCI_ID_PCX22HR] = { "PCX22HR", 1, 0, 4, 44 }, +[PCI_ID_PCX22E] = { "PCX22e", 1, 0, 4, 44 }, +[PCI_ID_VX222HRMIC] = { "VX222HR-Mic", 1, 1, 5, 44 }, +[PCI_ID_VX222E_MIC] = { "VX222e-Mic", 1, 1, 5, 44 }, +[PCI_ID_PCX924HR] = { "PCX924HR", 1, 1, 5, 44 }, +[PCI_ID_PCX924E] = { "PCX924e", 1, 1, 5, 44 }, +[PCI_ID_PCX924HRMIC] = { "PCX924HR-Mic", 1, 1, 5, 44 }, +[PCI_ID_PCX924E_MIC] = { "PCX924e-Mic", 1, 1, 5, 44 }, }; +/* boards without hw AES1 and SRC onboard are all using fw_file_set==4 */ +/* VX222HR, VX222e, PCX22HR and PCX22e */ +#define PCXHR_BOARD_HAS_AES1(x) (x->fw_file_set != 4) +/* some boards do not support 192kHz on digital AES input plugs */ +#define PCXHR_BOARD_AESIN_NO_192K(x) ((x->capture_chips == 0) || \ + (x->fw_file_set == 0) || \ + (x->fw_file_set == 2)) static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg, unsigned int* realfreq) { unsigned int reg; - if (freq < 6900 || freq > 110250) + if (freq < 6900 || freq > 110000) return -EINVAL; - reg = (28224000 * 10) / freq; - reg = (reg + 5) / 10; + reg = (28224000 * 2) / freq; + reg = (reg - 1) / 2; if (reg < 0x200) *pllreg = reg + 0x800; else if (reg < 0x400) @@ -121,7 +191,7 @@ static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg, reg &= ~3; } if (realfreq) - *realfreq = ((28224000 * 10) / reg + 5) / 10; + *realfreq = (28224000 / (reg + 1)); return 0; } @@ -151,11 +221,6 @@ static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg, #define PCXHR_FREQ_AES_3 0x03 #define PCXHR_FREQ_AES_4 0x0d -#define PCXHR_MODIFY_CLOCK_S_BIT 0x04 - -#define PCXHR_IRQ_TIMER_FREQ 92000 -#define PCXHR_IRQ_TIMER_PERIOD 48 - static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate, unsigned int *reg, unsigned int *freq) { @@ -196,19 +261,32 @@ static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate, err = pcxhr_send_msg(mgr, &rmh); if (err < 0) { snd_printk(KERN_ERR - "error CMD_ACCESS_IO_WRITE for PLL register : %x!\n", - err ); + "error CMD_ACCESS_IO_WRITE " + "for PLL register : %x!\n", err); return err; } } break; - case PCXHR_CLOCK_TYPE_WORD_CLOCK : val = PCXHR_FREQ_WORD_CLOCK; break; - case PCXHR_CLOCK_TYPE_AES_SYNC : val = PCXHR_FREQ_SYNC_AES; break; - case PCXHR_CLOCK_TYPE_AES_1 : val = PCXHR_FREQ_AES_1; break; - case PCXHR_CLOCK_TYPE_AES_2 : val = PCXHR_FREQ_AES_2; break; - case PCXHR_CLOCK_TYPE_AES_3 : val = PCXHR_FREQ_AES_3; break; - case PCXHR_CLOCK_TYPE_AES_4 : val = PCXHR_FREQ_AES_4; break; - default : return -EINVAL; + case PCXHR_CLOCK_TYPE_WORD_CLOCK: + val = PCXHR_FREQ_WORD_CLOCK; + break; + case PCXHR_CLOCK_TYPE_AES_SYNC: + val = PCXHR_FREQ_SYNC_AES; + break; + case PCXHR_CLOCK_TYPE_AES_1: + val = PCXHR_FREQ_AES_1; + break; + case PCXHR_CLOCK_TYPE_AES_2: + val = PCXHR_FREQ_AES_2; + break; + case PCXHR_CLOCK_TYPE_AES_3: + val = PCXHR_FREQ_AES_3; + break; + case PCXHR_CLOCK_TYPE_AES_4: + val = PCXHR_FREQ_AES_4; + break; + default: + return -EINVAL; } *reg = val; *freq = realfreq; @@ -216,14 +294,13 @@ static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate, } -int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate) +static int pcxhr_sub_set_clock(struct pcxhr_mgr *mgr, + unsigned int rate, + int *changed) { unsigned int val, realfreq, speed; struct pcxhr_rmh rmh; - int err, changed; - - if (rate == 0) - return 0; /* nothing to do */ + int err; err = pcxhr_get_clock_reg(mgr, rate, &val, &realfreq); if (err) @@ -237,13 +314,17 @@ int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate) else speed = 2; /* quad speed */ if (mgr->codec_speed != speed) { - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* mute outputs */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* mute outputs */ rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; + if (DSP_EXT_CMD_SET(mgr)) { + rmh.cmd[1] = 1; + rmh.cmd_len = 2; + } err = pcxhr_send_msg(mgr, &rmh); if (err) return err; - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set speed ratio */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set speed ratio */ rmh.cmd[0] |= IO_NUM_SPEED_RATIO; rmh.cmd[1] = speed; rmh.cmd_len = 2; @@ -253,25 +334,57 @@ int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate) } /* set the new frequency */ snd_printdd("clock register : set %x\n", val); - err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK, val, &changed); + err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK, + val, changed); if (err) return err; + mgr->sample_rate_real = realfreq; mgr->cur_clock_type = mgr->use_clock_type; /* unmute after codec speed modes */ if (mgr->codec_speed != speed) { - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* unmute outputs */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* unmute outputs */ rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; + if (DSP_EXT_CMD_SET(mgr)) { + rmh.cmd[1] = 1; + rmh.cmd_len = 2; + } err = pcxhr_send_msg(mgr, &rmh); if (err) return err; - mgr->codec_speed = speed; /* save new codec speed */ + mgr->codec_speed = speed; /* save new codec speed */ } + snd_printdd("pcxhr_sub_set_clock to %dHz (realfreq=%d)\n", + rate, realfreq); + return 0; +} + +#define PCXHR_MODIFY_CLOCK_S_BIT 0x04 + +#define PCXHR_IRQ_TIMER_FREQ 92000 +#define PCXHR_IRQ_TIMER_PERIOD 48 + +int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate) +{ + struct pcxhr_rmh rmh; + int err, changed; + + if (rate == 0) + return 0; /* nothing to do */ + + if (mgr->is_hr_stereo) + err = hr222_sub_set_clock(mgr, rate, &changed); + else + err = pcxhr_sub_set_clock(mgr, rate, &changed); + + if (err) + return err; + if (changed) { pcxhr_init_rmh(&rmh, CMD_MODIFY_CLOCK); - rmh.cmd[0] |= PCXHR_MODIFY_CLOCK_S_BIT; /* resync fifos */ + rmh.cmd[0] |= PCXHR_MODIFY_CLOCK_S_BIT; /* resync fifos */ if (rate < PCXHR_IRQ_TIMER_FREQ) rmh.cmd[1] = PCXHR_IRQ_TIMER_PERIOD; else @@ -282,26 +395,39 @@ int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate) if (err) return err; } - snd_printdd("pcxhr_set_clock to %dHz (realfreq=%d)\n", rate, realfreq); return 0; } -int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_type, - int *sample_rate) +static int pcxhr_sub_get_external_clock(struct pcxhr_mgr *mgr, + enum pcxhr_clock_type clock_type, + int *sample_rate) { struct pcxhr_rmh rmh; unsigned char reg; int err, rate; switch (clock_type) { - case PCXHR_CLOCK_TYPE_WORD_CLOCK : reg = REG_STATUS_WORD_CLOCK; break; - case PCXHR_CLOCK_TYPE_AES_SYNC : reg = REG_STATUS_AES_SYNC; break; - case PCXHR_CLOCK_TYPE_AES_1 : reg = REG_STATUS_AES_1; break; - case PCXHR_CLOCK_TYPE_AES_2 : reg = REG_STATUS_AES_2; break; - case PCXHR_CLOCK_TYPE_AES_3 : reg = REG_STATUS_AES_3; break; - case PCXHR_CLOCK_TYPE_AES_4 : reg = REG_STATUS_AES_4; break; - default : return -EINVAL; + case PCXHR_CLOCK_TYPE_WORD_CLOCK: + reg = REG_STATUS_WORD_CLOCK; + break; + case PCXHR_CLOCK_TYPE_AES_SYNC: + reg = REG_STATUS_AES_SYNC; + break; + case PCXHR_CLOCK_TYPE_AES_1: + reg = REG_STATUS_AES_1; + break; + case PCXHR_CLOCK_TYPE_AES_2: + reg = REG_STATUS_AES_2; + break; + case PCXHR_CLOCK_TYPE_AES_3: + reg = REG_STATUS_AES_3; + break; + case PCXHR_CLOCK_TYPE_AES_4: + reg = REG_STATUS_AES_4; + break; + default: + return -EINVAL; } pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); rmh.cmd_len = 2; @@ -311,7 +437,7 @@ int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_ err = pcxhr_send_msg(mgr, &rmh); if (err) return err; - udelay(100); /* wait minimum 2 sample_frames at 32kHz ! */ + udelay(100); /* wait minimum 2 sample_frames at 32kHz ! */ mgr->last_reg_stat = reg; } rmh.cmd[1] = REG_STATUS_CURRENT; @@ -336,6 +462,18 @@ int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_ } +int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, + enum pcxhr_clock_type clock_type, + int *sample_rate) +{ + if (mgr->is_hr_stereo) + return hr222_get_external_clock(mgr, clock_type, + sample_rate); + else + return pcxhr_sub_get_external_clock(mgr, clock_type, + sample_rate); +} + /* * start or stop playback/capture substream */ @@ -350,7 +488,8 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream) start = 1; else { if (stream->status != PCXHR_STREAM_STATUS_SCHEDULE_STOP) { - snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state CANNOT be stopped\n"); + snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state " + "CANNOT be stopped\n"); return -EINVAL; } start = 0; @@ -359,11 +498,12 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream) return -EINVAL; stream->timer_abs_periods = 0; - stream->timer_period_frag = 0; /* reset theoretical stream pos */ + stream->timer_period_frag = 0; /* reset theoretical stream pos */ stream->timer_buf_periods = 0; stream->timer_is_synced = 0; - stream_mask = stream->pipe->is_capture ? 1 : 1<substream->number; + stream_mask = + stream->pipe->is_capture ? 1 : 1<substream->number; pcxhr_init_rmh(&rmh, start ? CMD_START_STREAM : CMD_STOP_STREAM); pcxhr_set_pipe_cmd_params(&rmh, stream->pipe->is_capture, @@ -373,8 +513,10 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream) err = pcxhr_send_msg(chip->mgr, &rmh); if (err) - snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n", err); - stream->status = start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED; + snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n", + err); + stream->status = + start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED; return err; } @@ -399,13 +541,15 @@ static int pcxhr_set_format(struct pcxhr_stream *stream) header = HEADER_FMT_BASE_LIN; break; case SNDRV_PCM_FORMAT_S16_LE: - header = HEADER_FMT_BASE_LIN | HEADER_FMT_16BITS | HEADER_FMT_INTEL; + header = HEADER_FMT_BASE_LIN | + HEADER_FMT_16BITS | HEADER_FMT_INTEL; break; case SNDRV_PCM_FORMAT_S16_BE: header = HEADER_FMT_BASE_LIN | HEADER_FMT_16BITS; break; case SNDRV_PCM_FORMAT_S24_3LE: - header = HEADER_FMT_BASE_LIN | HEADER_FMT_24BITS | HEADER_FMT_INTEL; + header = HEADER_FMT_BASE_LIN | + HEADER_FMT_24BITS | HEADER_FMT_INTEL; break; case SNDRV_PCM_FORMAT_S24_3BE: header = HEADER_FMT_BASE_LIN | HEADER_FMT_24BITS; @@ -414,7 +558,8 @@ static int pcxhr_set_format(struct pcxhr_stream *stream) header = HEADER_FMT_BASE_FLOAT | HEADER_FMT_INTEL; break; default: - snd_printk(KERN_ERR "error pcxhr_set_format() : unknown format\n"); + snd_printk(KERN_ERR + "error pcxhr_set_format() : unknown format\n"); return -EINVAL; } chip = snd_pcm_substream_chip(stream->substream); @@ -432,14 +577,31 @@ static int pcxhr_set_format(struct pcxhr_stream *stream) is_capture = stream->pipe->is_capture; stream_num = is_capture ? 0 : stream->substream->number; - pcxhr_init_rmh(&rmh, is_capture ? CMD_FORMAT_STREAM_IN : CMD_FORMAT_STREAM_OUT); - pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0); - if (is_capture) - rmh.cmd[0] |= 1<<12; + pcxhr_init_rmh(&rmh, is_capture ? + CMD_FORMAT_STREAM_IN : CMD_FORMAT_STREAM_OUT); + pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, + stream_num, 0); + if (is_capture) { + /* bug with old dsp versions: */ + /* bit 12 also sets the format of the playback stream */ + if (DSP_EXT_CMD_SET(chip->mgr)) + rmh.cmd[0] |= 1<<10; + else + rmh.cmd[0] |= 1<<12; + } rmh.cmd[1] = 0; - rmh.cmd[2] = header >> 8; - rmh.cmd[3] = (header & 0xff) << 16; - rmh.cmd_len = 4; + rmh.cmd_len = 2; + if (DSP_EXT_CMD_SET(chip->mgr)) { + /* add channels and set bit 19 if channels>2 */ + rmh.cmd[1] = stream->channels; + if (!is_capture) { + /* playback : add channel mask to command */ + rmh.cmd[2] = (stream->channels == 1) ? 0x01 : 0x03; + rmh.cmd_len = 3; + } + } + rmh.cmd[rmh.cmd_len++] = header >> 8; + rmh.cmd[rmh.cmd_len++] = (header & 0xff) << 16; err = pcxhr_send_msg(chip->mgr, &rmh); if (err) snd_printk(KERN_ERR "ERROR pcxhr_set_format err=%x;\n", err); @@ -456,30 +618,38 @@ static int pcxhr_update_r_buffer(struct pcxhr_stream *stream) is_capture = (subs->stream == SNDRV_PCM_STREAM_CAPTURE); stream_num = is_capture ? 0 : subs->number; - snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : addr(%p) bytes(%zx) subs(%d)\n", + snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : " + "addr(%p) bytes(%zx) subs(%d)\n", is_capture ? 'c' : 'p', chip->chip_idx, (void *)(long)subs->runtime->dma_addr, subs->runtime->dma_bytes, subs->number); pcxhr_init_rmh(&rmh, CMD_UPDATE_R_BUFFERS); - pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0); + pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, + stream_num, 0); /* max buffer size is 2 MByte */ snd_BUG_ON(subs->runtime->dma_bytes >= 0x200000); - rmh.cmd[1] = subs->runtime->dma_bytes * 8; /* size in bits */ - rmh.cmd[2] = subs->runtime->dma_addr >> 24; /* most significant byte */ - rmh.cmd[2] |= 1<<19; /* this is a circular buffer */ - rmh.cmd[3] = subs->runtime->dma_addr & MASK_DSP_WORD; /* least 3 significant bytes */ + /* size in bits */ + rmh.cmd[1] = subs->runtime->dma_bytes * 8; + /* most significant byte */ + rmh.cmd[2] = subs->runtime->dma_addr >> 24; + /* this is a circular buffer */ + rmh.cmd[2] |= 1<<19; + /* least 3 significant bytes */ + rmh.cmd[3] = subs->runtime->dma_addr & MASK_DSP_WORD; rmh.cmd_len = 4; err = pcxhr_send_msg(chip->mgr, &rmh); if (err) - snd_printk(KERN_ERR "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err); + snd_printk(KERN_ERR + "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err); return err; } #if 0 -static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream, snd_pcm_uframes_t *sample_count) +static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream, + snd_pcm_uframes_t *sample_count) { struct pcxhr_rmh rmh; int err; @@ -533,8 +703,8 @@ static void pcxhr_trigger_tasklet(unsigned long arg) for (j = 0; j < chip->nb_streams_play; j++) { if (pcxhr_stream_scheduled_get_pipe(&chip->playback_stream[j], &pipe)) { playback_mask |= (1 << pipe->first_audio); - break; /* add only once, as all playback streams of - * one chip use the same pipe + break; /* add only once, as all playback + * streams of one chip use the same pipe */ } } @@ -545,19 +715,21 @@ static void pcxhr_trigger_tasklet(unsigned long arg) return; } - snd_printdd("pcxhr_trigger_tasklet : playback_mask=%x capture_mask=%x\n", + snd_printdd("pcxhr_trigger_tasklet : " + "playback_mask=%x capture_mask=%x\n", playback_mask, capture_mask); /* synchronous stop of all the pipes concerned */ err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0); if (err) { mutex_unlock(&mgr->setup_mutex); - snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error stop pipes (P%x C%x)\n", + snd_printk(KERN_ERR "pcxhr_trigger_tasklet : " + "error stop pipes (P%x C%x)\n", playback_mask, capture_mask); return; } - /* unfortunately the dsp lost format and buffer info with the stop pipe */ + /* the dsp lost format and buffer info with the stop pipe */ for (i = 0; i < mgr->num_cards; i++) { struct pcxhr_stream *stream; chip = mgr->chip[i]; @@ -596,12 +768,15 @@ static void pcxhr_trigger_tasklet(unsigned long arg) err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1); if (err) { mutex_unlock(&mgr->setup_mutex); - snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error start pipes (P%x C%x)\n", + snd_printk(KERN_ERR "pcxhr_trigger_tasklet : " + "error start pipes (P%x C%x)\n", playback_mask, capture_mask); return; } - /* put the streams into the running state now (increment pointer by interrupt) */ + /* put the streams into the running state now + * (increment pointer by interrupt) + */ spin_lock_irqsave(&mgr->lock, flags); for ( i =0; i < mgr->num_cards; i++) { struct pcxhr_stream *stream; @@ -615,7 +790,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) stream = &chip->playback_stream[j]; if (stream->status == PCXHR_STREAM_STATUS_STARTED) { /* playback will already have advanced ! */ - stream->timer_period_frag += PCXHR_GRANULARITY; + stream->timer_period_frag += mgr->granularity; stream->status = PCXHR_STREAM_STATUS_RUNNING; } } @@ -697,12 +872,14 @@ static int pcxhr_hardware_timer(struct pcxhr_mgr *mgr, int start) pcxhr_init_rmh(&rmh, CMD_SET_TIMER_INTERRUPT); if (start) { - mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; /* last dsp time invalid */ - rmh.cmd[0] |= PCXHR_GRANULARITY; + /* last dsp time invalid */ + mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; + rmh.cmd[0] |= mgr->granularity; } err = pcxhr_send_msg(mgr, &rmh); if (err < 0) - snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n", err); + snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n", + err); return err; } @@ -713,38 +890,16 @@ static int pcxhr_prepare(struct snd_pcm_substream *subs) { struct snd_pcxhr *chip = snd_pcm_substream_chip(subs); struct pcxhr_mgr *mgr = chip->mgr; - /* - struct pcxhr_stream *stream = (pcxhr_stream_t*)subs->runtime->private_data; - */ int err = 0; snd_printdd("pcxhr_prepare : period_size(%lx) periods(%x) buffer_size(%lx)\n", subs->runtime->period_size, subs->runtime->periods, subs->runtime->buffer_size); - /* - if(subs->runtime->period_size <= PCXHR_GRANULARITY) { - snd_printk(KERN_ERR "pcxhr_prepare : error period_size too small (%x)\n", - (unsigned int)subs->runtime->period_size); - return -EINVAL; - } - */ - mutex_lock(&mgr->setup_mutex); do { - /* if the stream was stopped before, format and buffer were reset */ - /* - if(stream->status == PCXHR_STREAM_STATUS_STOPPED) { - err = pcxhr_set_format(stream); - if(err) break; - err = pcxhr_update_r_buffer(stream); - if(err) break; - } - */ - /* only the first stream can choose the sample rate */ - /* the further opened streams will be limited to its frequency (see open) */ /* set the clock only once (first stream) */ if (mgr->sample_rate != subs->runtime->rate) { err = pcxhr_set_clock(mgr, subs->runtime->rate); @@ -787,22 +942,9 @@ static int pcxhr_hw_params(struct snd_pcm_substream *subs, stream->channels = channels; stream->format = format; - /* set the format to the board */ - /* - err = pcxhr_set_format(stream); - if(err) { - mutex_unlock(&mgr->setup_mutex); - return err; - } - */ /* allocate buffer */ err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw)); - /* - if (err > 0) { - err = pcxhr_update_r_buffer(stream); - } - */ mutex_unlock(&mgr->setup_mutex); return err; @@ -820,14 +962,18 @@ static int pcxhr_hw_free(struct snd_pcm_substream *subs) */ static struct snd_pcm_hardware pcxhr_caps = { - .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START | - 0 /*SNDRV_PCM_INFO_PAUSE*/), - .formats = ( SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | - SNDRV_PCM_FMTBIT_FLOAT_LE ), - .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START), + .formats = (SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S24_3BE | + SNDRV_PCM_FMTBIT_FLOAT_LE), + .rates = (SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_8000_192000), .rate_min = 8000, .rate_max = 192000, .channels_min = 1, @@ -847,6 +993,7 @@ static int pcxhr_open(struct snd_pcm_substream *subs) struct pcxhr_mgr *mgr = chip->mgr; struct snd_pcm_runtime *runtime = subs->runtime; struct pcxhr_stream *stream; + int err; mutex_lock(&mgr->setup_mutex); @@ -874,6 +1021,18 @@ static int pcxhr_open(struct snd_pcm_substream *subs) return -EBUSY; } + /* float format support is in some cases buggy on stereo cards */ + if (mgr->is_hr_stereo) + runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_FLOAT_LE; + + /* buffer-size should better be multiple of period-size */ + err = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) { + mutex_unlock(&mgr->setup_mutex); + return err; + } + /* if a sample rate is already used or fixed by external clock, * the stream cannot change */ @@ -889,7 +1048,8 @@ static int pcxhr_open(struct snd_pcm_substream *subs) mutex_unlock(&mgr->setup_mutex); return -EBUSY; } - runtime->hw.rate_min = runtime->hw.rate_max = external_rate; + runtime->hw.rate_min = external_rate; + runtime->hw.rate_max = external_rate; } } @@ -899,9 +1059,11 @@ static int pcxhr_open(struct snd_pcm_substream *subs) runtime->private_data = stream; - snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4); - snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4); - + /* better get a divisor of granularity values (96 or 192) */ + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32); snd_pcm_set_sync(subs); mgr->ref_count_rate++; @@ -919,11 +1081,12 @@ static int pcxhr_close(struct snd_pcm_substream *subs) mutex_lock(&mgr->setup_mutex); - snd_printdd("pcxhr_close chip%d subs%d\n", chip->chip_idx, subs->number); + snd_printdd("pcxhr_close chip%d subs%d\n", + chip->chip_idx, subs->number); /* sample rate released */ if (--mgr->ref_count_rate == 0) { - mgr->sample_rate = 0; /* the sample rate is no more locked */ + mgr->sample_rate = 0; /* the sample rate is no more locked */ pcxhr_hardware_timer(mgr, 0); /* stop the DSP-timer */ } @@ -1016,7 +1179,8 @@ static int pcxhr_chip_dev_free(struct snd_device *device) /* */ -static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card, int idx) +static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, + struct snd_card *card, int idx) { int err; struct snd_pcxhr *chip; @@ -1040,7 +1204,7 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card, if (idx < mgr->capture_chips) { if (mgr->mono_capture) - chip->nb_streams_capt = 2; /* 2 mono streams (left+right) */ + chip->nb_streams_capt = 2; /* 2 mono streams */ else chip->nb_streams_capt = 1; /* or 1 stereo stream */ } @@ -1056,7 +1220,8 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card, } /* proc interface */ -static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) +static void pcxhr_proc_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) { struct snd_pcxhr *chip = entry->private_data; struct pcxhr_mgr *mgr = chip->mgr; @@ -1069,8 +1234,10 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer short ver_maj = (mgr->dsp_version >> 16) & 0xff; short ver_min = (mgr->dsp_version >> 8) & 0xff; short ver_build = mgr->dsp_version & 0xff; - snd_iprintf(buffer, "module version %s\n", PCXHR_DRIVER_VERSION_STRING); - snd_iprintf(buffer, "dsp version %d.%d.%d\n", ver_maj, ver_min, ver_build); + snd_iprintf(buffer, "module version %s\n", + PCXHR_DRIVER_VERSION_STRING); + snd_iprintf(buffer, "dsp version %d.%d.%d\n", + ver_maj, ver_min, ver_build); if (mgr->board_has_analog) snd_iprintf(buffer, "analog io available\n"); else @@ -1084,18 +1251,22 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer if (ref > 0) { if (mgr->sample_rate_real != 0 && mgr->sample_rate_real != 48000) { - ref = (ref * 48000) / mgr->sample_rate_real; - if (mgr->sample_rate_real >= PCXHR_IRQ_TIMER_FREQ) + ref = (ref * 48000) / + mgr->sample_rate_real; + if (mgr->sample_rate_real >= + PCXHR_IRQ_TIMER_FREQ) ref *= 2; } cur = 100 - (100 * cur) / ref; snd_iprintf(buffer, "cpu load %d%%\n", cur); - snd_iprintf(buffer, "buffer pool %d/%d kWords\n", + snd_iprintf(buffer, "buffer pool %d/%d\n", rmh.stat[2], rmh.stat[3]); } } - snd_iprintf(buffer, "dma granularity : %d\n", PCXHR_GRANULARITY); - snd_iprintf(buffer, "dsp time errors : %d\n", mgr->dsp_time_err); + snd_iprintf(buffer, "dma granularity : %d\n", + mgr->granularity); + snd_iprintf(buffer, "dsp time errors : %d\n", + mgr->dsp_time_err); snd_iprintf(buffer, "dsp async pipe xrun errors : %d\n", mgr->async_err_pipe_xrun); snd_iprintf(buffer, "dsp async stream xrun errors : %d\n", @@ -1110,33 +1281,52 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer rmh.cmd_idx = CMD_LAST_INDEX; if( ! pcxhr_send_msg(mgr, &rmh) ) { int i; + if (rmh.stat_len > 8) + rmh.stat_len = 8; for (i = 0; i < rmh.stat_len; i++) - snd_iprintf(buffer, "debug[%02d] = %06x\n", i, rmh.stat[i]); + snd_iprintf(buffer, "debug[%02d] = %06x\n", + i, rmh.stat[i]); } } else snd_iprintf(buffer, "no firmware loaded\n"); snd_iprintf(buffer, "\n"); } -static void pcxhr_proc_sync(struct snd_info_entry *entry, struct snd_info_buffer *buffer) +static void pcxhr_proc_sync(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) { struct snd_pcxhr *chip = entry->private_data; struct pcxhr_mgr *mgr = chip->mgr; - static char *texts[7] = { - "Internal", "Word", "AES Sync", "AES 1", "AES 2", "AES 3", "AES 4" + static const char *textsHR22[3] = { + "Internal", "AES Sync", "AES 1" + }; + static const char *textsPCXHR[7] = { + "Internal", "Word", "AES Sync", + "AES 1", "AES 2", "AES 3", "AES 4" }; + const char **texts; + int max_clock; + if (mgr->is_hr_stereo) { + texts = textsHR22; + max_clock = HR22_CLOCK_TYPE_MAX; + } else { + texts = textsPCXHR; + max_clock = PCXHR_CLOCK_TYPE_MAX; + } snd_iprintf(buffer, "\n%s\n", mgr->longname); - snd_iprintf(buffer, "Current Sample Clock\t: %s\n", texts[mgr->cur_clock_type]); - snd_iprintf(buffer, "Current Sample Rate\t= %d\n", mgr->sample_rate_real); - + snd_iprintf(buffer, "Current Sample Clock\t: %s\n", + texts[mgr->cur_clock_type]); + snd_iprintf(buffer, "Current Sample Rate\t= %d\n", + mgr->sample_rate_real); /* commands available when embedded DSP is running */ if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) { int i, err, sample_rate; - for (i = PCXHR_CLOCK_TYPE_WORD_CLOCK; i< (3 + mgr->capture_chips); i++) { + for (i = 1; i <= max_clock; i++) { err = pcxhr_get_external_clock(mgr, i, &sample_rate); if (err) break; - snd_iprintf(buffer, "%s Clock\t\t= %d\n", texts[i], sample_rate); + snd_iprintf(buffer, "%s Clock\t\t= %d\n", + texts[i], sample_rate); } } else snd_iprintf(buffer, "no firmware loaded\n"); @@ -1194,7 +1384,8 @@ static int pcxhr_free(struct pcxhr_mgr *mgr) /* * probe function - creates the card manager */ -static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +static int __devinit pcxhr_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct pcxhr_mgr *mgr; @@ -1217,7 +1408,8 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id /* check if we can restrict PCI DMA transfers to 32 bits */ if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0) { - snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n"); + snd_printk(KERN_ERR "architecture does not support " + "32bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -1234,11 +1426,25 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id pci_disable_device(pci); return -ENODEV; } - card_name = pcxhr_board_params[pci_id->driver_data].board_name; - mgr->playback_chips = pcxhr_board_params[pci_id->driver_data].playback_chips; - mgr->capture_chips = pcxhr_board_params[pci_id->driver_data].capture_chips; - mgr->firmware_num = pcxhr_board_params[pci_id->driver_data].firmware_num; + card_name = + pcxhr_board_params[pci_id->driver_data].board_name; + mgr->playback_chips = + pcxhr_board_params[pci_id->driver_data].playback_chips; + mgr->capture_chips = + pcxhr_board_params[pci_id->driver_data].capture_chips; + mgr->fw_file_set = + pcxhr_board_params[pci_id->driver_data].fw_file_set; + mgr->firmware_num = + pcxhr_board_params[pci_id->driver_data].firmware_num; mgr->mono_capture = mono[dev]; + mgr->is_hr_stereo = (mgr->playback_chips == 1); + mgr->board_has_aes1 = PCXHR_BOARD_HAS_AES1(mgr); + mgr->board_aes_in_192k = !PCXHR_BOARD_AESIN_NO_192K(mgr); + + if (mgr->is_hr_stereo) + mgr->granularity = PCXHR_GRANULARITY_HR22; + else + mgr->granularity = PCXHR_GRANULARITY; /* resource assignment */ if ((err = pci_request_regions(pci, card_name)) < 0) { @@ -1261,7 +1467,8 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id mgr->irq = pci->irq; sprintf(mgr->shortname, "Digigram %s", card_name); - sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, 0x%lx irq %i", mgr->shortname, + sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, 0x%lx irq %i", + mgr->shortname, mgr->port[0], mgr->port[1], mgr->port[2], mgr->irq); /* ISR spinlock */ @@ -1272,10 +1479,14 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id mutex_init(&mgr->setup_mutex); /* init taslket */ - tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet, (unsigned long) mgr); - tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet, (unsigned long) mgr); + tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet, + (unsigned long) mgr); + tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet, + (unsigned long) mgr); + mgr->prmh = kmalloc(sizeof(*mgr->prmh) + - sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS - PCXHR_SIZE_MAX_STATUS), + sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS - + PCXHR_SIZE_MAX_STATUS), GFP_KERNEL); if (! mgr->prmh) { pcxhr_free(mgr); @@ -1296,7 +1507,8 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id else idx = index[dev] + i; - snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : card_name, i); + snprintf(tmpid, sizeof(tmpid), "%s-%d", + id[dev] ? id[dev] : card_name, i); card = snd_card_new(idx, tmpid, THIS_MODULE, 0); if (! card) { diff --git a/sound/pci/pcxhr/pcxhr.h b/sound/pci/pcxhr/pcxhr.h index 652064787a55..84131a916c92 100644 --- a/sound/pci/pcxhr/pcxhr.h +++ b/sound/pci/pcxhr/pcxhr.h @@ -27,15 +27,18 @@ #include #include -#define PCXHR_DRIVER_VERSION 0x000804 /* 0.8.4 */ -#define PCXHR_DRIVER_VERSION_STRING "0.8.4" /* 0.8.4 */ +#define PCXHR_DRIVER_VERSION 0x000905 /* 0.9.5 */ +#define PCXHR_DRIVER_VERSION_STRING "0.9.5" /* 0.9.5 */ -#define PCXHR_MAX_CARDS 6 -#define PCXHR_PLAYBACK_STREAMS 4 +#define PCXHR_MAX_CARDS 6 +#define PCXHR_PLAYBACK_STREAMS 4 -#define PCXHR_GRANULARITY 96 /* transfer granularity (should be min 96 and multiple of 48) */ -#define PCXHR_GRANULARITY_MIN 96 /* transfer granularity of pipes and the dsp time (MBOX4) */ +#define PCXHR_GRANULARITY 96 /* min 96 and multiple of 48 */ +/* transfer granularity of pipes and the dsp time (MBOX4) */ +#define PCXHR_GRANULARITY_MIN 96 +/* TODO : granularity could be 64 or 128 */ +#define PCXHR_GRANULARITY_HR22 192 /* granularity for stereo cards */ struct snd_pcxhr; struct pcxhr_mgr; @@ -51,6 +54,11 @@ enum pcxhr_clock_type { PCXHR_CLOCK_TYPE_AES_2, PCXHR_CLOCK_TYPE_AES_3, PCXHR_CLOCK_TYPE_AES_4, + PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4, + HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL, + HR22_CLOCK_TYPE_AES_SYNC, + HR22_CLOCK_TYPE_AES_1, + HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1, }; struct pcxhr_mgr { @@ -61,6 +69,8 @@ struct pcxhr_mgr { int irq; + int granularity; + /* card access with 1 mem bar and 2 io bar's */ unsigned long port[3]; @@ -83,11 +93,16 @@ struct pcxhr_mgr { /* hardware interface */ unsigned int dsp_loaded; /* bit flags of loaded dsp indices */ unsigned int dsp_version; /* read from embedded once firmware is loaded */ - int board_has_analog; /* if 0 the board is digital only */ - int mono_capture; /* if 1 the board does mono capture */ - int playback_chips; /* 4 or 6 */ - int capture_chips; /* 4 or 1 */ - int firmware_num; /* 41 or 42 */ + int playback_chips; + int capture_chips; + int fw_file_set; + int firmware_num; + int is_hr_stereo:1; + int board_has_aes1:1; /* if 1 board has AES1 plug and SRC */ + int board_has_analog:1; /* if 0 the board is digital only */ + int board_has_mic:1; /* if 1 the board has microphone input */ + int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */ + int mono_capture:1; /* if 1 the board does mono capture */ struct snd_dma_buffer hostport; @@ -106,6 +121,9 @@ struct pcxhr_mgr { int async_err_stream_xrun; int async_err_pipe_xrun; int async_err_other_last; + + unsigned char xlx_cfg; /* copy of PCXHR_XLX_CFG register */ + unsigned char xlx_selmic; /* copy of PCXHR_XLX_SELMIC register */ }; @@ -155,24 +173,30 @@ struct snd_pcxhr { struct snd_pcm *pcm; /* PCM */ - struct pcxhr_pipe playback_pipe; /* 1 stereo pipe only */ - struct pcxhr_pipe capture_pipe[2]; /* 1 stereo pipe or 2 mono pipes */ + struct pcxhr_pipe playback_pipe; /* 1 stereo pipe only */ + struct pcxhr_pipe capture_pipe[2]; /* 1 stereo or 2 mono pipes */ struct pcxhr_stream playback_stream[PCXHR_PLAYBACK_STREAMS]; - struct pcxhr_stream capture_stream[2]; /* 1 stereo stream or 2 mono streams */ + struct pcxhr_stream capture_stream[2]; /* 1 stereo or 2 mono streams */ int nb_streams_play; int nb_streams_capt; - int analog_playback_active[2]; /* Mixer : Master Playback active (!mute) */ - int analog_playback_volume[2]; /* Mixer : Master Playback Volume */ - int analog_capture_volume[2]; /* Mixer : Master Capture Volume */ - int digital_playback_active[PCXHR_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Active [streams][stereo]*/ - int digital_playback_volume[PCXHR_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Volume [streams][stereo]*/ - int digital_capture_volume[2]; /* Mixer : Digital Capture Volume [stereo] */ - int monitoring_active[2]; /* Mixer : Monitoring Active */ - int monitoring_volume[2]; /* Mixer : Monitoring Volume */ - int audio_capture_source; /* Mixer : Audio Capture Source */ - unsigned char aes_bits[5]; /* Mixer : IEC958_AES bits */ + int analog_playback_active[2]; /* Mixer : Master Playback !mute */ + int analog_playback_volume[2]; /* Mixer : Master Playback Volume */ + int analog_capture_volume[2]; /* Mixer : Master Capture Volume */ + int digital_playback_active[PCXHR_PLAYBACK_STREAMS][2]; + int digital_playback_volume[PCXHR_PLAYBACK_STREAMS][2]; + int digital_capture_volume[2]; /* Mixer : Digital Capture Volume */ + int monitoring_active[2]; /* Mixer : Monitoring Active */ + int monitoring_volume[2]; /* Mixer : Monitoring Volume */ + int audio_capture_source; /* Mixer : Audio Capture Source */ + int mic_volume; /* used by cards with MIC only */ + int mic_boost; /* used by cards with MIC only */ + int mic_active; /* used by cards with MIC only */ + int analog_capture_active; /* used by cards with MIC only */ + int phantom_power; /* used by cards with MIC only */ + + unsigned char aes_bits[5]; /* Mixer : IEC958_AES bits */ }; struct pcxhr_hostport @@ -184,6 +208,8 @@ struct pcxhr_hostport /* exported */ int pcxhr_create_pcm(struct snd_pcxhr *chip); int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate); -int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_type, int *sample_rate); +int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, + enum pcxhr_clock_type clock_type, + int *sample_rate); #endif /* __SOUND_PCXHR_H */ -- cgit v1.2.3 From 7628700e08403618b0b07bd25b6456d8b2d074ef Mon Sep 17 00:00:00 2001 From: Markus Bollinger Date: Tue, 25 Nov 2008 12:28:06 +0100 Subject: ALSA: pcxhr - add support for pcxhr stereo sound cards (firmware support) - Add support for pcxhr stereo cards and their firmware - autorize sound cards without analog IO - do some cleanup Signed-off-by: Markus Bollinger Signed-off-by: Takashi Iwai --- sound/pci/pcxhr/pcxhr_hwdep.c | 148 ++++++++++++++++++++++++++++++------------ 1 file changed, 108 insertions(+), 40 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c index 96640d9c227d..ea50018d785b 100644 --- a/sound/pci/pcxhr/pcxhr_hwdep.c +++ b/sound/pci/pcxhr/pcxhr_hwdep.c @@ -31,6 +31,7 @@ #include "pcxhr_mixer.h" #include "pcxhr_hwdep.h" #include "pcxhr_core.h" +#include "pcxhr_mix22.h" #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) @@ -40,10 +41,10 @@ #endif +static int pcxhr_sub_init(struct pcxhr_mgr *mgr); /* * get basic information and init pcxhr card */ - static int pcxhr_init_board(struct pcxhr_mgr *mgr) { int err; @@ -68,7 +69,7 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr) if ((rmh.stat[0] & MASK_FIRST_FIELD) != mgr->playback_chips * 2) return -EINVAL; /* test 8 or 2 phys in */ - if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) != + if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) < mgr->capture_chips * 2) return -EINVAL; /* test max nb substream per board */ @@ -77,20 +78,34 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr) /* test max nb substream per pipe */ if (((rmh.stat[1] >> 7) & 0x5F) < PCXHR_PLAYBACK_STREAMS) return -EINVAL; + snd_printdd("supported formats : playback=%x capture=%x\n", + rmh.stat[2], rmh.stat[3]); pcxhr_init_rmh(&rmh, CMD_VERSION); /* firmware num for DSP */ rmh.cmd[0] |= mgr->firmware_num; /* transfer granularity in samples (should be multiple of 48) */ - rmh.cmd[1] = (1<<23) + PCXHR_GRANULARITY; + rmh.cmd[1] = (1<<23) + mgr->granularity; rmh.cmd_len = 2; err = pcxhr_send_msg(mgr, &rmh); if (err) return err; - snd_printdd("PCXHR DSP version is %d.%d.%d\n", - (rmh.stat[0]>>16)&0xff, (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff); + snd_printdd("PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff, + (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff); mgr->dsp_version = rmh.stat[0]; + if (mgr->is_hr_stereo) + err = hr222_sub_init(mgr); + else + err = pcxhr_sub_init(mgr); + return err; +} + +static int pcxhr_sub_init(struct pcxhr_mgr *mgr) +{ + int err; + struct pcxhr_rmh rmh; + /* get options */ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); rmh.cmd[0] |= IO_NUM_REG_STATUS; @@ -100,20 +115,22 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr) if (err) return err; - if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) == REG_STATUS_OPT_ANALOG_BOARD) - mgr->board_has_analog = 1; /* analog addon board available */ - else - /* analog addon board not available -> no support for instance */ - return -EINVAL; + if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) == + REG_STATUS_OPT_ANALOG_BOARD) + mgr->board_has_analog = 1; /* analog addon board found */ /* unmute inputs */ err = pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, REG_CONT_UNMUTE_INPUTS, NULL); if (err) return err; - /* unmute outputs */ - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* a write to IO_NUM_REG_MUTE_OUT mutes! */ + /* unmute outputs (a write to IO_NUM_REG_MUTE_OUT mutes!) */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; + if (DSP_EXT_CMD_SET(mgr)) { + rmh.cmd[1] = 1; /* unmute digital plugs */ + rmh.cmd_len = 2; + } err = pcxhr_send_msg(mgr, &rmh); return err; } @@ -124,19 +141,25 @@ void pcxhr_reset_board(struct pcxhr_mgr *mgr) if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) { /* mute outputs */ + if (!mgr->is_hr_stereo) { /* a read to IO_NUM_REG_MUTE_OUT register unmutes! */ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; pcxhr_send_msg(mgr, &rmh); /* mute inputs */ - pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, 0, NULL); + pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, + 0, NULL); + } + /* stereo cards mute with reset of dsp */ } /* reset pcxhr dsp */ - if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX)) + if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX)) pcxhr_reset_dsp(mgr); /* reset second xilinx */ - if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_XLX_COM_INDEX)) + if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_XLX_COM_INDEX)) { pcxhr_reset_xilinx_com(mgr); + mgr->dsp_loaded = 1; + } return; } @@ -144,8 +167,9 @@ void pcxhr_reset_board(struct pcxhr_mgr *mgr) /* * allocate a playback/capture pipe (pcmp0/pcmc0) */ -static int pcxhr_dsp_allocate_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe, - int is_capture, int pin) +static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr, + struct pcxhr_pipe *pipe, + int is_capture, int pin) { int stream_count, audio_count; int err; @@ -161,15 +185,23 @@ static int pcxhr_dsp_allocate_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pi stream_count = PCXHR_PLAYBACK_STREAMS; audio_count = 2; /* always stereo */ } - snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n", pin, is_capture ? 'c' : 'p'); + snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n", + pin, is_capture ? 'c' : 'p'); pipe->is_capture = is_capture; pipe->first_audio = pin; /* define pipe (P_PCM_ONLY_MASK (0x020000) is not necessary) */ pcxhr_init_rmh(&rmh, CMD_RES_PIPE); - pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin, audio_count, stream_count); + pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin, + audio_count, stream_count); + rmh.cmd[1] |= 0x020000; /* add P_PCM_ONLY_MASK */ + if (DSP_EXT_CMD_SET(mgr)) { + /* add channel mask to command */ + rmh.cmd[rmh.cmd_len++] = (audio_count == 1) ? 0x01 : 0x03; + } err = pcxhr_send_msg(mgr, &rmh); if (err < 0) { - snd_printk(KERN_ERR "error pipe allocation (CMD_RES_PIPE) err=%x!\n", err ); + snd_printk(KERN_ERR "error pipe allocation " + "(CMD_RES_PIPE) err=%x!\n", err); return err; } pipe->status = PCXHR_PIPE_DEFINED; @@ -199,10 +231,12 @@ static int pcxhr_dsp_free_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe) snd_printk(KERN_ERR "error stopping pipe!\n"); /* release the pipe */ pcxhr_init_rmh(&rmh, CMD_FREE_PIPE); - pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio, 0, 0); + pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio, + 0, 0); err = pcxhr_send_msg(mgr, &rmh); if (err < 0) - snd_printk(KERN_ERR "error pipe release (CMD_FREE_PIPE) err(%x)\n", err); + snd_printk(KERN_ERR "error pipe release " + "(CMD_FREE_PIPE) err(%x)\n", err); pipe->status = PCXHR_PIPE_UNDEFINED; return err; } @@ -248,15 +282,16 @@ static int pcxhr_start_pipes(struct pcxhr_mgr *mgr) for (i = 0; i < mgr->num_cards; i++) { chip = mgr->chip[i]; if (chip->nb_streams_play) - playback_mask |= (1 << chip->playback_pipe.first_audio); + playback_mask |= 1 << chip->playback_pipe.first_audio; for (j = 0; j < chip->nb_streams_capt; j++) - capture_mask |= (1 << chip->capture_pipe[j].first_audio); + capture_mask |= 1 << chip->capture_pipe[j].first_audio; } return pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1); } -static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, const struct firmware *dsp) +static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, + const struct firmware *dsp) { int err, card_index; @@ -330,22 +365,33 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, const struct firmwar int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) { - static char *fw_files[5] = { - "xi_1_882.dat", - "xc_1_882.dat", - "e321_512.e56", - "b321_512.b56", - "d321_512.d56" + static char *fw_files[][5] = { + [0] = { "xi_1_882.dat", "xc_1_882.dat", + "e321_512.e56", "b321_512.b56", "d321_512.d56" }, + [1] = { "xi_1_882.dat", "xc_882e.dat", + "e321_512.e56", "b882e.b56", "d321_512.d56" }, + [2] = { "xi_1_882.dat", "xc_1222.dat", + "e321_512.e56", "b1222.b56", "d1222.d56" }, + [3] = { "xi_1_882.dat", "xc_1222e.dat", + "e321_512.e56", "b1222e.b56", "d1222.d56" }, + [4] = { NULL, "x1_222hr.dat", + "e924.e56", "b924.b56", "l_1_222.d56" }, + [5] = { NULL, "x1_924hr.dat", + "e924.e56", "b924.b56", "l_1_222.d56" }, }; char path[32]; const struct firmware *fw_entry; int i, err; + int fw_set = mgr->fw_file_set; - for (i = 0; i < ARRAY_SIZE(fw_files); i++) { - sprintf(path, "pcxhr/%s", fw_files[i]); + for (i = 0; i < 5; i++) { + if (!fw_files[fw_set][i]) + continue; + sprintf(path, "pcxhr/%s", fw_files[fw_set][i]); if (request_firmware(&fw_entry, path, &mgr->pci->dev)) { - snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n", path); + snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n", + path); return -ENOENT; } /* fake hwdep dsp record */ @@ -360,10 +406,25 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) MODULE_FIRMWARE("pcxhr/xi_1_882.dat"); MODULE_FIRMWARE("pcxhr/xc_1_882.dat"); +MODULE_FIRMWARE("pcxhr/xc_882e.dat"); MODULE_FIRMWARE("pcxhr/e321_512.e56"); MODULE_FIRMWARE("pcxhr/b321_512.b56"); +MODULE_FIRMWARE("pcxhr/b882e.b56"); MODULE_FIRMWARE("pcxhr/d321_512.d56"); +MODULE_FIRMWARE("pcxhr/xc_1222.dat"); +MODULE_FIRMWARE("pcxhr/xc_1222e.dat"); +MODULE_FIRMWARE("pcxhr/b1222.b56"); +MODULE_FIRMWARE("pcxhr/b1222e.b56"); +MODULE_FIRMWARE("pcxhr/d1222.d56"); + +MODULE_FIRMWARE("pcxhr/x1_222hr.dat"); +MODULE_FIRMWARE("pcxhr/x1_924hr.dat"); +MODULE_FIRMWARE("pcxhr/e924.e56"); +MODULE_FIRMWARE("pcxhr/b924.b56"); +MODULE_FIRMWARE("pcxhr/l_1_222.d56"); + + #else /* old style firmware loading */ /* pcxhr hwdep interface id string */ @@ -373,7 +434,8 @@ MODULE_FIRMWARE("pcxhr/d321_512.d56"); static int pcxhr_hwdep_dsp_status(struct snd_hwdep *hw, struct snd_hwdep_dsp_status *info) { - strcpy(info->id, "pcxhr"); + struct pcxhr_mgr *mgr = hw->private_data; + sprintf(info->id, "pcxhr%d", mgr->fw_file_set); info->num_dsps = PCXHR_FIRMWARE_FILES_MAX_INDEX; if (hw->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) @@ -393,8 +455,8 @@ static int pcxhr_hwdep_dsp_load(struct snd_hwdep *hw, fw.size = dsp->length; fw.data = vmalloc(fw.size); if (! fw.data) { - snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image (%lu bytes)\n", - (unsigned long)fw.size); + snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image " + "(%lu bytes)\n", (unsigned long)fw.size); return -ENOMEM; } if (copy_from_user((void *)fw.data, dsp->image, dsp->length)) { @@ -424,8 +486,11 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) int err; struct snd_hwdep *hw; - /* only create hwdep interface for first cardX (see "index" module parameter)*/ - if ((err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw)) < 0) + /* only create hwdep interface for first cardX + * (see "index" module parameter) + */ + err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw); + if (err < 0) return err; hw->iface = SNDRV_HWDEP_IFACE_PCXHR; @@ -435,10 +500,13 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) hw->ops.dsp_status = pcxhr_hwdep_dsp_status; hw->ops.dsp_load = pcxhr_hwdep_dsp_load; hw->exclusive = 1; + /* stereo cards don't need fw_file_0 -> dsp_loaded = 1 */ + hw->dsp_loaded = mgr->is_hr_stereo ? 1 : 0; mgr->dsp_loaded = 0; sprintf(hw->name, PCXHR_HWDEP_ID); - if ((err = snd_card_register(mgr->chip[0]->card)) < 0) + err = snd_card_register(mgr->chip[0]->card); + if (err < 0) return err; return 0; } -- cgit v1.2.3 From c0193f39f43c79bde6c1c5804f5315f3983152b5 Mon Sep 17 00:00:00 2001 From: Markus Bollinger Date: Tue, 25 Nov 2008 12:37:52 +0100 Subject: ALSA: pcxhr - add support for pcxhr stereo sound cards (mixer part) - add support for pcxhr stereo cards mixer controls - adjust tlv db scales to real dBu values - fix bug with monitoring volume control pcxhr_monitor_vol_put - do some cleanup Signed-off-by: Markus Bollinger Signed-off-by: Takashi Iwai --- sound/pci/pcxhr/Makefile | 2 +- sound/pci/pcxhr/pcxhr_mix22.c | 820 ++++++++++++++++++++++++++++++++++++++++++ sound/pci/pcxhr/pcxhr_mix22.h | 56 +++ sound/pci/pcxhr/pcxhr_mixer.c | 556 +++++++++++++++++++--------- 4 files changed, 1259 insertions(+), 175 deletions(-) create mode 100644 sound/pci/pcxhr/pcxhr_mix22.c create mode 100644 sound/pci/pcxhr/pcxhr_mix22.h (limited to 'sound/pci') diff --git a/sound/pci/pcxhr/Makefile b/sound/pci/pcxhr/Makefile index 10473c05918d..b06128e918ca 100644 --- a/sound/pci/pcxhr/Makefile +++ b/sound/pci/pcxhr/Makefile @@ -1,2 +1,2 @@ -snd-pcxhr-objs := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o +snd-pcxhr-objs := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o pcxhr_mix22.o obj-$(CONFIG_SND_PCXHR) += snd-pcxhr.o diff --git a/sound/pci/pcxhr/pcxhr_mix22.c b/sound/pci/pcxhr/pcxhr_mix22.c new file mode 100644 index 000000000000..ff019126b672 --- /dev/null +++ b/sound/pci/pcxhr/pcxhr_mix22.c @@ -0,0 +1,820 @@ +/* + * Driver for Digigram pcxhr compatible soundcards + * + * mixer interface for stereo cards + * + * Copyright (c) 2004 by Digigram + * + * 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 +#include "pcxhr.h" +#include "pcxhr_core.h" +#include "pcxhr_mix22.h" + + +/* registers used on the DSP and Xilinx (port 2) : HR stereo cards only */ +#define PCXHR_DSP_RESET 0x20 +#define PCXHR_XLX_CFG 0x24 +#define PCXHR_XLX_RUER 0x28 +#define PCXHR_XLX_DATA 0x2C +#define PCXHR_XLX_STATUS 0x30 +#define PCXHR_XLX_LOFREQ 0x34 +#define PCXHR_XLX_HIFREQ 0x38 +#define PCXHR_XLX_CSUER 0x3C +#define PCXHR_XLX_SELMIC 0x40 + +#define PCXHR_DSP 2 + +/* byte access only ! */ +#define PCXHR_INPB(mgr, x) inb((mgr)->port[PCXHR_DSP] + (x)) +#define PCXHR_OUTPB(mgr, x, data) outb((data), (mgr)->port[PCXHR_DSP] + (x)) + + +/* values for PCHR_DSP_RESET register */ +#define PCXHR_DSP_RESET_DSP 0x01 +#define PCXHR_DSP_RESET_MUTE 0x02 +#define PCXHR_DSP_RESET_CODEC 0x08 + +/* values for PCHR_XLX_CFG register */ +#define PCXHR_CFG_SYNCDSP_MASK 0x80 +#define PCXHR_CFG_DEPENDENCY_MASK 0x60 +#define PCXHR_CFG_INDEPENDANT_SEL 0x00 +#define PCXHR_CFG_MASTER_SEL 0x40 +#define PCXHR_CFG_SLAVE_SEL 0x20 +#define PCXHR_CFG_DATA_UER1_SEL_MASK 0x10 /* 0 (UER0), 1(UER1) */ +#define PCXHR_CFG_DATAIN_SEL_MASK 0x08 /* 0 (ana), 1 (UER) */ +#define PCXHR_CFG_SRC_MASK 0x04 /* 0 (Bypass), 1 (SRC Actif) */ +#define PCXHR_CFG_CLOCK_UER1_SEL_MASK 0x02 /* 0 (UER0), 1(UER1) */ +#define PCXHR_CFG_CLOCKIN_SEL_MASK 0x01 /* 0 (internal), 1 (AES/EBU) */ + +/* values for PCHR_XLX_DATA register */ +#define PCXHR_DATA_CODEC 0x80 +#define AKM_POWER_CONTROL_CMD 0xA007 +#define AKM_RESET_ON_CMD 0xA100 +#define AKM_RESET_OFF_CMD 0xA103 +#define AKM_CLOCK_INF_55K_CMD 0xA240 +#define AKM_CLOCK_SUP_55K_CMD 0xA24D +#define AKM_MUTE_CMD 0xA38D +#define AKM_UNMUTE_CMD 0xA30D +#define AKM_LEFT_LEVEL_CMD 0xA600 +#define AKM_RIGHT_LEVEL_CMD 0xA700 + +/* values for PCHR_XLX_STATUS register - READ */ +#define PCXHR_STAT_SRC_LOCK 0x01 +#define PCXHR_STAT_LEVEL_IN 0x02 +#define PCXHR_STAT_MIC_CAPS 0x10 +/* values for PCHR_XLX_STATUS register - WRITE */ +#define PCXHR_STAT_FREQ_SYNC_MASK 0x01 +#define PCXHR_STAT_FREQ_UER1_MASK 0x02 +#define PCXHR_STAT_FREQ_SAVE_MASK 0x80 + +/* values for PCHR_XLX_CSUER register */ +#define PCXHR_SUER1_BIT_U_READ_MASK 0x80 +#define PCXHR_SUER1_BIT_C_READ_MASK 0x40 +#define PCXHR_SUER1_DATA_PRESENT_MASK 0x20 +#define PCXHR_SUER1_CLOCK_PRESENT_MASK 0x10 +#define PCXHR_SUER_BIT_U_READ_MASK 0x08 +#define PCXHR_SUER_BIT_C_READ_MASK 0x04 +#define PCXHR_SUER_DATA_PRESENT_MASK 0x02 +#define PCXHR_SUER_CLOCK_PRESENT_MASK 0x01 + +#define PCXHR_SUER_BIT_U_WRITE_MASK 0x02 +#define PCXHR_SUER_BIT_C_WRITE_MASK 0x01 + +/* values for PCXHR_XLX_SELMIC register - WRITE */ +#define PCXHR_SELMIC_PREAMPLI_OFFSET 2 +#define PCXHR_SELMIC_PREAMPLI_MASK 0x0C +#define PCXHR_SELMIC_PHANTOM_ALIM 0x80 + + +static const unsigned char g_hr222_p_level[] = { + 0x00, /* [000] -49.5 dB: AKM[000] = -1.#INF dB (mute) */ + 0x01, /* [001] -49.0 dB: AKM[001] = -48.131 dB (diff=0.86920 dB) */ + 0x01, /* [002] -48.5 dB: AKM[001] = -48.131 dB (diff=0.36920 dB) */ + 0x01, /* [003] -48.0 dB: AKM[001] = -48.131 dB (diff=0.13080 dB) */ + 0x01, /* [004] -47.5 dB: AKM[001] = -48.131 dB (diff=0.63080 dB) */ + 0x01, /* [005] -46.5 dB: AKM[001] = -48.131 dB (diff=1.63080 dB) */ + 0x01, /* [006] -47.0 dB: AKM[001] = -48.131 dB (diff=1.13080 dB) */ + 0x01, /* [007] -46.0 dB: AKM[001] = -48.131 dB (diff=2.13080 dB) */ + 0x01, /* [008] -45.5 dB: AKM[001] = -48.131 dB (diff=2.63080 dB) */ + 0x02, /* [009] -45.0 dB: AKM[002] = -42.110 dB (diff=2.88980 dB) */ + 0x02, /* [010] -44.5 dB: AKM[002] = -42.110 dB (diff=2.38980 dB) */ + 0x02, /* [011] -44.0 dB: AKM[002] = -42.110 dB (diff=1.88980 dB) */ + 0x02, /* [012] -43.5 dB: AKM[002] = -42.110 dB (diff=1.38980 dB) */ + 0x02, /* [013] -43.0 dB: AKM[002] = -42.110 dB (diff=0.88980 dB) */ + 0x02, /* [014] -42.5 dB: AKM[002] = -42.110 dB (diff=0.38980 dB) */ + 0x02, /* [015] -42.0 dB: AKM[002] = -42.110 dB (diff=0.11020 dB) */ + 0x02, /* [016] -41.5 dB: AKM[002] = -42.110 dB (diff=0.61020 dB) */ + 0x02, /* [017] -41.0 dB: AKM[002] = -42.110 dB (diff=1.11020 dB) */ + 0x02, /* [018] -40.5 dB: AKM[002] = -42.110 dB (diff=1.61020 dB) */ + 0x03, /* [019] -40.0 dB: AKM[003] = -38.588 dB (diff=1.41162 dB) */ + 0x03, /* [020] -39.5 dB: AKM[003] = -38.588 dB (diff=0.91162 dB) */ + 0x03, /* [021] -39.0 dB: AKM[003] = -38.588 dB (diff=0.41162 dB) */ + 0x03, /* [022] -38.5 dB: AKM[003] = -38.588 dB (diff=0.08838 dB) */ + 0x03, /* [023] -38.0 dB: AKM[003] = -38.588 dB (diff=0.58838 dB) */ + 0x03, /* [024] -37.5 dB: AKM[003] = -38.588 dB (diff=1.08838 dB) */ + 0x04, /* [025] -37.0 dB: AKM[004] = -36.090 dB (diff=0.91040 dB) */ + 0x04, /* [026] -36.5 dB: AKM[004] = -36.090 dB (diff=0.41040 dB) */ + 0x04, /* [027] -36.0 dB: AKM[004] = -36.090 dB (diff=0.08960 dB) */ + 0x04, /* [028] -35.5 dB: AKM[004] = -36.090 dB (diff=0.58960 dB) */ + 0x05, /* [029] -35.0 dB: AKM[005] = -34.151 dB (diff=0.84860 dB) */ + 0x05, /* [030] -34.5 dB: AKM[005] = -34.151 dB (diff=0.34860 dB) */ + 0x05, /* [031] -34.0 dB: AKM[005] = -34.151 dB (diff=0.15140 dB) */ + 0x05, /* [032] -33.5 dB: AKM[005] = -34.151 dB (diff=0.65140 dB) */ + 0x06, /* [033] -33.0 dB: AKM[006] = -32.568 dB (diff=0.43222 dB) */ + 0x06, /* [034] -32.5 dB: AKM[006] = -32.568 dB (diff=0.06778 dB) */ + 0x06, /* [035] -32.0 dB: AKM[006] = -32.568 dB (diff=0.56778 dB) */ + 0x07, /* [036] -31.5 dB: AKM[007] = -31.229 dB (diff=0.27116 dB) */ + 0x07, /* [037] -31.0 dB: AKM[007] = -31.229 dB (diff=0.22884 dB) */ + 0x08, /* [038] -30.5 dB: AKM[008] = -30.069 dB (diff=0.43100 dB) */ + 0x08, /* [039] -30.0 dB: AKM[008] = -30.069 dB (diff=0.06900 dB) */ + 0x09, /* [040] -29.5 dB: AKM[009] = -29.046 dB (diff=0.45405 dB) */ + 0x09, /* [041] -29.0 dB: AKM[009] = -29.046 dB (diff=0.04595 dB) */ + 0x0a, /* [042] -28.5 dB: AKM[010] = -28.131 dB (diff=0.36920 dB) */ + 0x0a, /* [043] -28.0 dB: AKM[010] = -28.131 dB (diff=0.13080 dB) */ + 0x0b, /* [044] -27.5 dB: AKM[011] = -27.303 dB (diff=0.19705 dB) */ + 0x0b, /* [045] -27.0 dB: AKM[011] = -27.303 dB (diff=0.30295 dB) */ + 0x0c, /* [046] -26.5 dB: AKM[012] = -26.547 dB (diff=0.04718 dB) */ + 0x0d, /* [047] -26.0 dB: AKM[013] = -25.852 dB (diff=0.14806 dB) */ + 0x0e, /* [048] -25.5 dB: AKM[014] = -25.208 dB (diff=0.29176 dB) */ + 0x0e, /* [049] -25.0 dB: AKM[014] = -25.208 dB (diff=0.20824 dB) */ + 0x0f, /* [050] -24.5 dB: AKM[015] = -24.609 dB (diff=0.10898 dB) */ + 0x10, /* [051] -24.0 dB: AKM[016] = -24.048 dB (diff=0.04840 dB) */ + 0x11, /* [052] -23.5 dB: AKM[017] = -23.522 dB (diff=0.02183 dB) */ + 0x12, /* [053] -23.0 dB: AKM[018] = -23.025 dB (diff=0.02535 dB) */ + 0x13, /* [054] -22.5 dB: AKM[019] = -22.556 dB (diff=0.05573 dB) */ + 0x14, /* [055] -22.0 dB: AKM[020] = -22.110 dB (diff=0.11020 dB) */ + 0x15, /* [056] -21.5 dB: AKM[021] = -21.686 dB (diff=0.18642 dB) */ + 0x17, /* [057] -21.0 dB: AKM[023] = -20.896 dB (diff=0.10375 dB) */ + 0x18, /* [058] -20.5 dB: AKM[024] = -20.527 dB (diff=0.02658 dB) */ + 0x1a, /* [059] -20.0 dB: AKM[026] = -19.831 dB (diff=0.16866 dB) */ + 0x1b, /* [060] -19.5 dB: AKM[027] = -19.504 dB (diff=0.00353 dB) */ + 0x1d, /* [061] -19.0 dB: AKM[029] = -18.883 dB (diff=0.11716 dB) */ + 0x1e, /* [062] -18.5 dB: AKM[030] = -18.588 dB (diff=0.08838 dB) */ + 0x20, /* [063] -18.0 dB: AKM[032] = -18.028 dB (diff=0.02780 dB) */ + 0x22, /* [064] -17.5 dB: AKM[034] = -17.501 dB (diff=0.00123 dB) */ + 0x24, /* [065] -17.0 dB: AKM[036] = -17.005 dB (diff=0.00475 dB) */ + 0x26, /* [066] -16.5 dB: AKM[038] = -16.535 dB (diff=0.03513 dB) */ + 0x28, /* [067] -16.0 dB: AKM[040] = -16.090 dB (diff=0.08960 dB) */ + 0x2b, /* [068] -15.5 dB: AKM[043] = -15.461 dB (diff=0.03857 dB) */ + 0x2d, /* [069] -15.0 dB: AKM[045] = -15.067 dB (diff=0.06655 dB) */ + 0x30, /* [070] -14.5 dB: AKM[048] = -14.506 dB (diff=0.00598 dB) */ + 0x33, /* [071] -14.0 dB: AKM[051] = -13.979 dB (diff=0.02060 dB) */ + 0x36, /* [072] -13.5 dB: AKM[054] = -13.483 dB (diff=0.01707 dB) */ + 0x39, /* [073] -13.0 dB: AKM[057] = -13.013 dB (diff=0.01331 dB) */ + 0x3c, /* [074] -12.5 dB: AKM[060] = -12.568 dB (diff=0.06778 dB) */ + 0x40, /* [075] -12.0 dB: AKM[064] = -12.007 dB (diff=0.00720 dB) */ + 0x44, /* [076] -11.5 dB: AKM[068] = -11.481 dB (diff=0.01937 dB) */ + 0x48, /* [077] -11.0 dB: AKM[072] = -10.984 dB (diff=0.01585 dB) */ + 0x4c, /* [078] -10.5 dB: AKM[076] = -10.515 dB (diff=0.01453 dB) */ + 0x51, /* [079] -10.0 dB: AKM[081] = -9.961 dB (diff=0.03890 dB) */ + 0x55, /* [080] -9.5 dB: AKM[085] = -9.542 dB (diff=0.04243 dB) */ + 0x5a, /* [081] -9.0 dB: AKM[090] = -9.046 dB (diff=0.04595 dB) */ + 0x60, /* [082] -8.5 dB: AKM[096] = -8.485 dB (diff=0.01462 dB) */ + 0x66, /* [083] -8.0 dB: AKM[102] = -7.959 dB (diff=0.04120 dB) */ + 0x6c, /* [084] -7.5 dB: AKM[108] = -7.462 dB (diff=0.03767 dB) */ + 0x72, /* [085] -7.0 dB: AKM[114] = -6.993 dB (diff=0.00729 dB) */ + 0x79, /* [086] -6.5 dB: AKM[121] = -6.475 dB (diff=0.02490 dB) */ + 0x80, /* [087] -6.0 dB: AKM[128] = -5.987 dB (diff=0.01340 dB) */ + 0x87, /* [088] -5.5 dB: AKM[135] = -5.524 dB (diff=0.02413 dB) */ + 0x8f, /* [089] -5.0 dB: AKM[143] = -5.024 dB (diff=0.02408 dB) */ + 0x98, /* [090] -4.5 dB: AKM[152] = -4.494 dB (diff=0.00607 dB) */ + 0xa1, /* [091] -4.0 dB: AKM[161] = -3.994 dB (diff=0.00571 dB) */ + 0xaa, /* [092] -3.5 dB: AKM[170] = -3.522 dB (diff=0.02183 dB) */ + 0xb5, /* [093] -3.0 dB: AKM[181] = -2.977 dB (diff=0.02277 dB) */ + 0xbf, /* [094] -2.5 dB: AKM[191] = -2.510 dB (diff=0.01014 dB) */ + 0xcb, /* [095] -2.0 dB: AKM[203] = -1.981 dB (diff=0.01912 dB) */ + 0xd7, /* [096] -1.5 dB: AKM[215] = -1.482 dB (diff=0.01797 dB) */ + 0xe3, /* [097] -1.0 dB: AKM[227] = -1.010 dB (diff=0.01029 dB) */ + 0xf1, /* [098] -0.5 dB: AKM[241] = -0.490 dB (diff=0.00954 dB) */ + 0xff, /* [099] +0.0 dB: AKM[255] = +0.000 dB (diff=0.00000 dB) */ +}; + + +static void hr222_config_akm(struct pcxhr_mgr *mgr, unsigned short data) +{ + unsigned short mask = 0x8000; + /* activate access to codec registers */ + PCXHR_INPB(mgr, PCXHR_XLX_HIFREQ); + + while (mask) { + PCXHR_OUTPB(mgr, PCXHR_XLX_DATA, + data & mask ? PCXHR_DATA_CODEC : 0); + mask >>= 1; + } + /* termiate access to codec registers */ + PCXHR_INPB(mgr, PCXHR_XLX_RUER); +} + + +static int hr222_set_hw_playback_level(struct pcxhr_mgr *mgr, + int idx, int level) +{ + unsigned short cmd; + if (idx > 1 || + level < 0 || + level >= ARRAY_SIZE(g_hr222_p_level)) + return -EINVAL; + + if (idx == 0) + cmd = AKM_LEFT_LEVEL_CMD; + else + cmd = AKM_RIGHT_LEVEL_CMD; + + /* conversion from PmBoardCodedLevel to AKM nonlinear programming */ + cmd += g_hr222_p_level[level]; + + hr222_config_akm(mgr, cmd); + return 0; +} + + +static int hr222_set_hw_capture_level(struct pcxhr_mgr *mgr, + int level_l, int level_r, int level_mic) +{ + /* program all input levels at the same time */ + unsigned int data; + int i; + + if (!mgr->capture_chips) + return -EINVAL; /* no PCX22 */ + + data = ((level_mic & 0xff) << 24); /* micro is mono, but apply */ + data |= ((level_mic & 0xff) << 16); /* level on both channels */ + data |= ((level_r & 0xff) << 8); /* line input right channel */ + data |= (level_l & 0xff); /* line input left channel */ + + PCXHR_INPB(mgr, PCXHR_XLX_DATA); /* activate input codec */ + /* send 32 bits (4 x 8 bits) */ + for (i = 0; i < 32; i++, data <<= 1) { + PCXHR_OUTPB(mgr, PCXHR_XLX_DATA, + (data & 0x80000000) ? PCXHR_DATA_CODEC : 0); + } + PCXHR_INPB(mgr, PCXHR_XLX_RUER); /* close input level codec */ + return 0; +} + +static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level); + +int hr222_sub_init(struct pcxhr_mgr *mgr) +{ + unsigned char reg; + + mgr->board_has_analog = 1; /* analog always available */ + mgr->xlx_cfg = PCXHR_CFG_SYNCDSP_MASK; + + reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS); + if (reg & PCXHR_STAT_MIC_CAPS) + mgr->board_has_mic = 1; /* microphone available */ + snd_printdd("MIC input available = %d\n", mgr->board_has_mic); + + /* reset codec */ + PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, + PCXHR_DSP_RESET_DSP); + msleep(5); + PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, + PCXHR_DSP_RESET_DSP | + PCXHR_DSP_RESET_MUTE | + PCXHR_DSP_RESET_CODEC); + msleep(5); + + /* config AKM */ + hr222_config_akm(mgr, AKM_POWER_CONTROL_CMD); + hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD); + hr222_config_akm(mgr, AKM_UNMUTE_CMD); + hr222_config_akm(mgr, AKM_RESET_OFF_CMD); + + /* init micro boost */ + hr222_micro_boost(mgr, 0); + + return 0; +} + + +/* calc PLL register */ +/* TODO : there is a very similar fct in pcxhr.c */ +static int hr222_pll_freq_register(unsigned int freq, + unsigned int *pllreg, + unsigned int *realfreq) +{ + unsigned int reg; + + if (freq < 6900 || freq > 219000) + return -EINVAL; + reg = (28224000 * 2) / freq; + reg = (reg - 1) / 2; + if (reg < 0x100) + *pllreg = reg + 0xC00; + else if (reg < 0x200) + *pllreg = reg + 0x800; + else if (reg < 0x400) + *pllreg = reg & 0x1ff; + else if (reg < 0x800) { + *pllreg = ((reg >> 1) & 0x1ff) + 0x200; + reg &= ~1; + } else { + *pllreg = ((reg >> 2) & 0x1ff) + 0x400; + reg &= ~3; + } + if (realfreq) + *realfreq = (28224000 / (reg + 1)); + return 0; +} + +int hr222_sub_set_clock(struct pcxhr_mgr *mgr, + unsigned int rate, + int *changed) +{ + unsigned int speed, pllreg = 0; + int err; + unsigned realfreq = rate; + + switch (mgr->use_clock_type) { + case HR22_CLOCK_TYPE_INTERNAL: + err = hr222_pll_freq_register(rate, &pllreg, &realfreq); + if (err) + return err; + + mgr->xlx_cfg &= ~(PCXHR_CFG_CLOCKIN_SEL_MASK | + PCXHR_CFG_CLOCK_UER1_SEL_MASK); + break; + case HR22_CLOCK_TYPE_AES_SYNC: + mgr->xlx_cfg |= PCXHR_CFG_CLOCKIN_SEL_MASK; + mgr->xlx_cfg &= ~PCXHR_CFG_CLOCK_UER1_SEL_MASK; + break; + case HR22_CLOCK_TYPE_AES_1: + if (!mgr->board_has_aes1) + return -EINVAL; + + mgr->xlx_cfg |= (PCXHR_CFG_CLOCKIN_SEL_MASK | + PCXHR_CFG_CLOCK_UER1_SEL_MASK); + break; + default: + return -EINVAL; + } + hr222_config_akm(mgr, AKM_MUTE_CMD); + + if (mgr->use_clock_type == HR22_CLOCK_TYPE_INTERNAL) { + PCXHR_OUTPB(mgr, PCXHR_XLX_HIFREQ, pllreg >> 8); + PCXHR_OUTPB(mgr, PCXHR_XLX_LOFREQ, pllreg & 0xff); + } + + /* set clock source */ + PCXHR_OUTPB(mgr, PCXHR_XLX_CFG, mgr->xlx_cfg); + + /* codec speed modes */ + speed = rate < 55000 ? 0 : 1; + if (mgr->codec_speed != speed) { + mgr->codec_speed = speed; + if (speed == 0) + hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD); + else + hr222_config_akm(mgr, AKM_CLOCK_SUP_55K_CMD); + } + + mgr->sample_rate_real = realfreq; + mgr->cur_clock_type = mgr->use_clock_type; + + if (changed) + *changed = 1; + + hr222_config_akm(mgr, AKM_UNMUTE_CMD); + + snd_printdd("set_clock to %dHz (realfreq=%d pllreg=%x)\n", + rate, realfreq, pllreg); + return 0; +} + +int hr222_get_external_clock(struct pcxhr_mgr *mgr, + enum pcxhr_clock_type clock_type, + int *sample_rate) +{ + int rate, calc_rate = 0; + unsigned int ticks; + unsigned char mask, reg; + + if (clock_type == HR22_CLOCK_TYPE_AES_SYNC) { + + mask = (PCXHR_SUER_CLOCK_PRESENT_MASK | + PCXHR_SUER_DATA_PRESENT_MASK); + reg = PCXHR_STAT_FREQ_SYNC_MASK; + + } else if (clock_type == HR22_CLOCK_TYPE_AES_1 && mgr->board_has_aes1) { + + mask = (PCXHR_SUER1_CLOCK_PRESENT_MASK | + PCXHR_SUER1_DATA_PRESENT_MASK); + reg = PCXHR_STAT_FREQ_UER1_MASK; + + } else { + snd_printdd("get_external_clock : type %d not supported\n", + clock_type); + return -EINVAL; /* other clocks not supported */ + } + + if ((PCXHR_INPB(mgr, PCXHR_XLX_CSUER) & mask) != mask) { + snd_printdd("get_external_clock(%d) = 0 Hz\n", clock_type); + *sample_rate = 0; + return 0; /* no external clock locked */ + } + + PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* calculate freq */ + + /* save the measured clock frequency */ + reg |= PCXHR_STAT_FREQ_SAVE_MASK; + + if (mgr->last_reg_stat != reg) { + udelay(500); /* wait min 2 cycles of lowest freq (8000) */ + mgr->last_reg_stat = reg; + } + + PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* save */ + + /* get the frequency */ + ticks = (unsigned int)PCXHR_INPB(mgr, PCXHR_XLX_CFG); + ticks = (ticks & 0x03) << 8; + ticks |= (unsigned int)PCXHR_INPB(mgr, PCXHR_DSP_RESET); + + if (ticks != 0) + calc_rate = 28224000 / ticks; + /* rounding */ + if (calc_rate > 184200) + rate = 192000; + else if (calc_rate > 152200) + rate = 176400; + else if (calc_rate > 112000) + rate = 128000; + else if (calc_rate > 92100) + rate = 96000; + else if (calc_rate > 76100) + rate = 88200; + else if (calc_rate > 56000) + rate = 64000; + else if (calc_rate > 46050) + rate = 48000; + else if (calc_rate > 38050) + rate = 44100; + else if (calc_rate > 28000) + rate = 32000; + else if (calc_rate > 23025) + rate = 24000; + else if (calc_rate > 19025) + rate = 22050; + else if (calc_rate > 14000) + rate = 16000; + else if (calc_rate > 11512) + rate = 12000; + else if (calc_rate > 9512) + rate = 11025; + else if (calc_rate > 7000) + rate = 8000; + else + rate = 0; + + snd_printdd("External clock is at %d Hz (measured %d Hz)\n", + rate, calc_rate); + *sample_rate = rate; + return 0; +} + + +int hr222_update_analog_audio_level(struct snd_pcxhr *chip, + int is_capture, int channel) +{ + snd_printdd("hr222_update_analog_audio_level(%s chan=%d)\n", + is_capture ? "capture" : "playback", channel); + if (is_capture) { + int level_l, level_r, level_mic; + /* we have to update all levels */ + if (chip->analog_capture_active) { + level_l = chip->analog_capture_volume[0]; + level_r = chip->analog_capture_volume[1]; + } else { + level_l = HR222_LINE_CAPTURE_LEVEL_MIN; + level_r = HR222_LINE_CAPTURE_LEVEL_MIN; + } + if (chip->mic_active) + level_mic = chip->mic_volume; + else + level_mic = HR222_MICRO_CAPTURE_LEVEL_MIN; + return hr222_set_hw_capture_level(chip->mgr, + level_l, level_r, level_mic); + } else { + int vol; + if (chip->analog_playback_active[channel]) + vol = chip->analog_playback_volume[channel]; + else + vol = HR222_LINE_PLAYBACK_LEVEL_MIN; + return hr222_set_hw_playback_level(chip->mgr, channel, vol); + } +} + + +/*texts[5] = {"Line", "Digital", "Digi+SRC", "Mic", "Line+Mic"}*/ +#define SOURCE_LINE 0 +#define SOURCE_DIGITAL 1 +#define SOURCE_DIGISRC 2 +#define SOURCE_MIC 3 +#define SOURCE_LINEMIC 4 + +int hr222_set_audio_source(struct snd_pcxhr *chip) +{ + int digital = 0; + /* default analog source */ + chip->mgr->xlx_cfg &= ~(PCXHR_CFG_SRC_MASK | + PCXHR_CFG_DATAIN_SEL_MASK | + PCXHR_CFG_DATA_UER1_SEL_MASK); + + if (chip->audio_capture_source == SOURCE_DIGISRC) { + chip->mgr->xlx_cfg |= PCXHR_CFG_SRC_MASK; + digital = 1; + } else { + if (chip->audio_capture_source == SOURCE_DIGITAL) + digital = 1; + } + if (digital) { + chip->mgr->xlx_cfg |= PCXHR_CFG_DATAIN_SEL_MASK; + if (chip->mgr->board_has_aes1) { + /* get data from the AES1 plug */ + chip->mgr->xlx_cfg |= PCXHR_CFG_DATA_UER1_SEL_MASK; + } + /* chip->mic_active = 0; */ + /* chip->analog_capture_active = 0; */ + } else { + int update_lvl = 0; + chip->analog_capture_active = 0; + chip->mic_active = 0; + if (chip->audio_capture_source == SOURCE_LINE || + chip->audio_capture_source == SOURCE_LINEMIC) { + if (chip->analog_capture_active == 0) + update_lvl = 1; + chip->analog_capture_active = 1; + } + if (chip->audio_capture_source == SOURCE_MIC || + chip->audio_capture_source == SOURCE_LINEMIC) { + if (chip->mic_active == 0) + update_lvl = 1; + chip->mic_active = 1; + } + if (update_lvl) { + /* capture: update all 3 mutes/unmutes with one call */ + hr222_update_analog_audio_level(chip, 1, 0); + } + } + /* set the source infos (max 3 bits modified) */ + PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CFG, chip->mgr->xlx_cfg); + return 0; +} + + +int hr222_iec958_capture_byte(struct snd_pcxhr *chip, + int aes_idx, unsigned char *aes_bits) +{ + unsigned char idx = (unsigned char)(aes_idx * 8); + unsigned char temp = 0; + unsigned char mask = chip->mgr->board_has_aes1 ? + PCXHR_SUER1_BIT_C_READ_MASK : PCXHR_SUER_BIT_C_READ_MASK; + int i; + for (i = 0; i < 8; i++) { + PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx++); /* idx < 192 */ + temp <<= 1; + if (PCXHR_INPB(chip->mgr, PCXHR_XLX_CSUER) & mask) + temp |= 1; + } + snd_printdd("read iec958 AES %d byte %d = 0x%x\n", + chip->chip_idx, aes_idx, temp); + *aes_bits = temp; + return 0; +} + + +int hr222_iec958_update_byte(struct snd_pcxhr *chip, + int aes_idx, unsigned char aes_bits) +{ + int i; + unsigned char new_bits = aes_bits; + unsigned char old_bits = chip->aes_bits[aes_idx]; + unsigned char idx = (unsigned char)(aes_idx * 8); + for (i = 0; i < 8; i++) { + if ((old_bits & 0x01) != (new_bits & 0x01)) { + /* idx < 192 */ + PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx); + /* write C and U bit */ + PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CSUER, new_bits&0x01 ? + PCXHR_SUER_BIT_C_WRITE_MASK : 0); + } + idx++; + old_bits >>= 1; + new_bits >>= 1; + } + chip->aes_bits[aes_idx] = aes_bits; + return 0; +} + +static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level) +{ + unsigned char boost_mask; + boost_mask = (unsigned char) (level << PCXHR_SELMIC_PREAMPLI_OFFSET); + if (boost_mask & (~PCXHR_SELMIC_PREAMPLI_MASK)) + return; /* only values form 0 to 3 accepted */ + + mgr->xlx_selmic &= ~PCXHR_SELMIC_PREAMPLI_MASK; + mgr->xlx_selmic |= boost_mask; + + PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic); + + snd_printdd("hr222_micro_boost : set %x\n", boost_mask); +} + +static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power) +{ + if (power) + mgr->xlx_selmic |= PCXHR_SELMIC_PHANTOM_ALIM; + else + mgr->xlx_selmic &= ~PCXHR_SELMIC_PHANTOM_ALIM; + + PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic); + + snd_printdd("hr222_phantom_power : set %d\n", power); +} + + +/* mic level */ +static const DECLARE_TLV_DB_SCALE(db_scale_mic_hr222, -9850, 50, 650); + +static int hr222_mic_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = HR222_MICRO_CAPTURE_LEVEL_MIN; /* -98 dB */ + /* gains from 9 dB to 31.5 dB not recommended; use micboost instead */ + uinfo->value.integer.max = HR222_MICRO_CAPTURE_LEVEL_MAX; /* +7 dB */ + return 0; +} + +static int hr222_mic_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + mutex_lock(&chip->mgr->mixer_mutex); + ucontrol->value.integer.value[0] = chip->mic_volume; + mutex_unlock(&chip->mgr->mixer_mutex); + return 0; +} + +static int hr222_mic_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + int changed = 0; + mutex_lock(&chip->mgr->mixer_mutex); + if (chip->mic_volume != ucontrol->value.integer.value[0]) { + changed = 1; + chip->mic_volume = ucontrol->value.integer.value[0]; + hr222_update_analog_audio_level(chip, 1, 0); + } + mutex_unlock(&chip->mgr->mixer_mutex); + return changed; +} + +static struct snd_kcontrol_new hr222_control_mic_level = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .name = "Mic Capture Volume", + .info = hr222_mic_vol_info, + .get = hr222_mic_vol_get, + .put = hr222_mic_vol_put, + .tlv = { .p = db_scale_mic_hr222 }, +}; + + +/* mic boost level */ +static const DECLARE_TLV_DB_SCALE(db_scale_micboost_hr222, 0, 1800, 5400); + +static int hr222_mic_boost_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; /* 0 dB */ + uinfo->value.integer.max = 3; /* 54 dB */ + return 0; +} + +static int hr222_mic_boost_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + mutex_lock(&chip->mgr->mixer_mutex); + ucontrol->value.integer.value[0] = chip->mic_boost; + mutex_unlock(&chip->mgr->mixer_mutex); + return 0; +} + +static int hr222_mic_boost_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + int changed = 0; + mutex_lock(&chip->mgr->mixer_mutex); + if (chip->mic_boost != ucontrol->value.integer.value[0]) { + changed = 1; + chip->mic_boost = ucontrol->value.integer.value[0]; + hr222_micro_boost(chip->mgr, chip->mic_boost); + } + mutex_unlock(&chip->mgr->mixer_mutex); + return changed; +} + +static struct snd_kcontrol_new hr222_control_mic_boost = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .name = "MicBoost Capture Volume", + .info = hr222_mic_boost_info, + .get = hr222_mic_boost_get, + .put = hr222_mic_boost_put, + .tlv = { .p = db_scale_micboost_hr222 }, +}; + + +/******************* Phantom power switch *******************/ +#define hr222_phantom_power_info snd_ctl_boolean_mono_info + +static int hr222_phantom_power_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + mutex_lock(&chip->mgr->mixer_mutex); + ucontrol->value.integer.value[0] = chip->phantom_power; + mutex_unlock(&chip->mgr->mixer_mutex); + return 0; +} + +static int hr222_phantom_power_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + int power, changed = 0; + + mutex_lock(&chip->mgr->mixer_mutex); + power = !!ucontrol->value.integer.value[0]; + if (chip->phantom_power != power) { + hr222_phantom_power(chip->mgr, power); + chip->phantom_power = power; + changed = 1; + } + mutex_unlock(&chip->mgr->mixer_mutex); + return changed; +} + +static struct snd_kcontrol_new hr222_phantom_power_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Phantom Power Switch", + .info = hr222_phantom_power_info, + .get = hr222_phantom_power_get, + .put = hr222_phantom_power_put, +}; + + +int hr222_add_mic_controls(struct snd_pcxhr *chip) +{ + int err; + if (!chip->mgr->board_has_mic) + return 0; + + /* controls */ + err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_level, + chip)); + if (err < 0) + return err; + + err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_boost, + chip)); + if (err < 0) + return err; + + err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_phantom_power_switch, + chip)); + return err; +} diff --git a/sound/pci/pcxhr/pcxhr_mix22.h b/sound/pci/pcxhr/pcxhr_mix22.h new file mode 100644 index 000000000000..6b318b2f0100 --- /dev/null +++ b/sound/pci/pcxhr/pcxhr_mix22.h @@ -0,0 +1,56 @@ +/* + * Driver for Digigram pcxhr compatible soundcards + * + * low level interface with interrupt ans message handling + * + * Copyright (c) 2004 by Digigram + * + * 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 + */ + +#ifndef __SOUND_PCXHR_MIX22_H +#define __SOUND_PCXHR_MIX22_H + +struct pcxhr_mgr; + +int hr222_sub_init(struct pcxhr_mgr *mgr); +int hr222_sub_set_clock(struct pcxhr_mgr *mgr, unsigned int rate, + int *changed); +int hr222_get_external_clock(struct pcxhr_mgr *mgr, + enum pcxhr_clock_type clock_type, + int *sample_rate); + +#define HR222_LINE_PLAYBACK_LEVEL_MIN 0 /* -25.5 dB */ +#define HR222_LINE_PLAYBACK_ZERO_LEVEL 51 /* 0.0 dB */ +#define HR222_LINE_PLAYBACK_LEVEL_MAX 99 /* +24.0 dB */ + +#define HR222_LINE_CAPTURE_LEVEL_MIN 0 /* -111.5 dB */ +#define HR222_LINE_CAPTURE_ZERO_LEVEL 223 /* 0.0 dB */ +#define HR222_LINE_CAPTURE_LEVEL_MAX 255 /* +16 dB */ +#define HR222_MICRO_CAPTURE_LEVEL_MIN 0 /* -98.5 dB */ +#define HR222_MICRO_CAPTURE_LEVEL_MAX 210 /* +6.5 dB */ + +int hr222_update_analog_audio_level(struct snd_pcxhr *chip, + int is_capture, + int channel); +int hr222_set_audio_source(struct snd_pcxhr *chip); +int hr222_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, + unsigned char *aes_bits); +int hr222_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, + unsigned char aes_bits); + +int hr222_add_mic_controls(struct snd_pcxhr *chip); + +#endif /* __SOUND_PCXHR_MIX22_H */ diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index aabc7bc5321e..2436e374586f 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c @@ -33,20 +33,24 @@ #include #include #include "pcxhr_mixer.h" +#include "pcxhr_mix22.h" +#define PCXHR_LINE_CAPTURE_LEVEL_MIN 0 /* -112.0 dB */ +#define PCXHR_LINE_CAPTURE_LEVEL_MAX 255 /* +15.5 dB */ +#define PCXHR_LINE_CAPTURE_ZERO_LEVEL 224 /* 0.0 dB ( 0 dBu -> 0 dBFS ) */ -#define PCXHR_ANALOG_CAPTURE_LEVEL_MIN 0 /* -96.0 dB */ -#define PCXHR_ANALOG_CAPTURE_LEVEL_MAX 255 /* +31.5 dB */ -#define PCXHR_ANALOG_CAPTURE_ZERO_LEVEL 224 /* +16.0 dB ( +31.5 dB - fix level +15.5 dB ) */ +#define PCXHR_LINE_PLAYBACK_LEVEL_MIN 0 /* -104.0 dB */ +#define PCXHR_LINE_PLAYBACK_LEVEL_MAX 128 /* +24.0 dB */ +#define PCXHR_LINE_PLAYBACK_ZERO_LEVEL 104 /* 0.0 dB ( 0 dBFS -> 0 dBu ) */ -#define PCXHR_ANALOG_PLAYBACK_LEVEL_MIN 0 /* -128.0 dB */ -#define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */ -#define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */ - -static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 3150); +static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -11200, 50, 1550); static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -10400, 100, 2400); -static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) +static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_capture, -11150, 50, 1600); +static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_playback, -2550, 50, 2400); + +static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, + int is_capture, int channel) { int err, vol; struct pcxhr_rmh rmh; @@ -60,15 +64,17 @@ static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_captur if (chip->analog_playback_active[channel]) vol = chip->analog_playback_volume[channel]; else - vol = PCXHR_ANALOG_PLAYBACK_LEVEL_MIN; - rmh.cmd[2] = PCXHR_ANALOG_PLAYBACK_LEVEL_MAX - vol; /* playback analog levels are inversed */ + vol = PCXHR_LINE_PLAYBACK_LEVEL_MIN; + /* playback analog levels are inversed */ + rmh.cmd[2] = PCXHR_LINE_PLAYBACK_LEVEL_MAX - vol; } rmh.cmd[1] = 1 << ((2 * chip->chip_idx) + channel); /* audio mask */ rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); if (err < 0) { - snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d) " - "is_capture(%d) err(%x)\n", chip->chip_idx, is_capture, err); + snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d)" + " is_capture(%d) err(%x)\n", + chip->chip_idx, is_capture, err); return -EINVAL; } return 0; @@ -80,14 +86,34 @@ static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_captur static int pcxhr_analog_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; if (kcontrol->private_value == 0) { /* playback */ - uinfo->value.integer.min = PCXHR_ANALOG_PLAYBACK_LEVEL_MIN; /* -128 dB */ - uinfo->value.integer.max = PCXHR_ANALOG_PLAYBACK_LEVEL_MAX; /* 0 dB */ + if (chip->mgr->is_hr_stereo) { + uinfo->value.integer.min = + HR222_LINE_PLAYBACK_LEVEL_MIN; /* -25 dB */ + uinfo->value.integer.max = + HR222_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */ + } else { + uinfo->value.integer.min = + PCXHR_LINE_PLAYBACK_LEVEL_MIN; /*-104 dB */ + uinfo->value.integer.max = + PCXHR_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */ + } } else { /* capture */ - uinfo->value.integer.min = PCXHR_ANALOG_CAPTURE_LEVEL_MIN; /* -96 dB */ - uinfo->value.integer.max = PCXHR_ANALOG_CAPTURE_LEVEL_MAX; /* 31.5 dB */ + if (chip->mgr->is_hr_stereo) { + uinfo->value.integer.min = + HR222_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */ + uinfo->value.integer.max = + HR222_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */ + } else { + uinfo->value.integer.min = + PCXHR_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */ + uinfo->value.integer.max = + PCXHR_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */ + } } return 0; } @@ -98,11 +124,11 @@ static int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol, struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); mutex_lock(&chip->mgr->mixer_mutex); if (kcontrol->private_value == 0) { /* playback */ - ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; - ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; + ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; + ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; } else { /* capture */ - ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; - ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; + ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; + ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; } mutex_unlock(&chip->mgr->mixer_mutex); return 0; @@ -123,18 +149,35 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, &chip->analog_capture_volume[i] : &chip->analog_playback_volume[i]; if (is_capture) { - if (new_volume < PCXHR_ANALOG_CAPTURE_LEVEL_MIN || - new_volume > PCXHR_ANALOG_CAPTURE_LEVEL_MAX) - continue; + if (chip->mgr->is_hr_stereo) { + if (new_volume < HR222_LINE_CAPTURE_LEVEL_MIN || + new_volume > HR222_LINE_CAPTURE_LEVEL_MAX) + continue; + } else { + if (new_volume < PCXHR_LINE_CAPTURE_LEVEL_MIN || + new_volume > PCXHR_LINE_CAPTURE_LEVEL_MAX) + continue; + } } else { - if (new_volume < PCXHR_ANALOG_PLAYBACK_LEVEL_MIN || - new_volume > PCXHR_ANALOG_PLAYBACK_LEVEL_MAX) - continue; + if (chip->mgr->is_hr_stereo) { + if (new_volume < HR222_LINE_PLAYBACK_LEVEL_MIN || + new_volume > HR222_LINE_PLAYBACK_LEVEL_MAX) + continue; + } else { + if (new_volume < PCXHR_LINE_PLAYBACK_LEVEL_MIN || + new_volume > PCXHR_LINE_PLAYBACK_LEVEL_MAX) + continue; + } } if (*stored_volume != new_volume) { *stored_volume = new_volume; changed = 1; - pcxhr_update_analog_audio_level(chip, is_capture, i); + if (chip->mgr->is_hr_stereo) + hr222_update_analog_audio_level(chip, + is_capture, i); + else + pcxhr_update_analog_audio_level(chip, + is_capture, i); } } mutex_unlock(&chip->mgr->mixer_mutex); @@ -153,6 +196,7 @@ static struct snd_kcontrol_new pcxhr_control_analog_level = { }; /* shared */ + #define pcxhr_sw_info snd_ctl_boolean_stereo_info static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol, @@ -180,7 +224,10 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, !!ucontrol->value.integer.value[i]; changed = 1; /* update playback levels */ - pcxhr_update_analog_audio_level(chip, 0, i); + if (chip->mgr->is_hr_stereo) + hr222_update_analog_audio_level(chip, 0, i); + else + pcxhr_update_analog_audio_level(chip, 0, i); } } mutex_unlock(&chip->mgr->mixer_mutex); @@ -251,7 +298,8 @@ static int pcxhr_update_playback_stream_level(struct snd_pcxhr* chip, int idx) #define VALID_AUDIO_IO_MUTE_LEVEL 0x000004 #define VALID_AUDIO_IO_MUTE_MONITOR_1 0x000008 -static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, int channel) +static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip, + int capture, int channel) { int err; struct pcxhr_rmh rmh; @@ -264,18 +312,20 @@ static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, in pcxhr_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST); /* add channel mask */ - pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, 1 << (channel + pipe->first_audio)); - /* TODO : if mask (3 << pipe->first_audio) is used, left and right channel - * will be programmed to the same params - */ + pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, + 1 << (channel + pipe->first_audio)); + /* TODO : if mask (3 << pipe->first_audio) is used, left and right + * channel will be programmed to the same params */ if (capture) { rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL; - /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled (capture pipe level) */ + /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled + * (capture pipe level) */ rmh.cmd[2] = chip->digital_capture_volume[channel]; } else { - rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | VALID_AUDIO_IO_MUTE_MONITOR_1; - /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL not yet - * handled (playback pipe level) + rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | + VALID_AUDIO_IO_MUTE_MONITOR_1; + /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL + * not yet handled (playback pipe level) */ rmh.cmd[2] = chip->monitoring_volume[channel] << 10; if (chip->monitoring_active[channel] == 0) @@ -284,8 +334,8 @@ static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, in rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); - if(err<0) { - snd_printk(KERN_DEBUG "error update_audio_level card(%d) err(%x)\n", + if (err < 0) { + snd_printk(KERN_DEBUG "error update_audio_level(%d) err=%x\n", chip->chip_idx, err); return -EINVAL; } @@ -309,15 +359,15 @@ static int pcxhr_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ int *stored_volume; int is_capture = kcontrol->private_value; mutex_lock(&chip->mgr->mixer_mutex); - if (is_capture) - stored_volume = chip->digital_capture_volume; /* digital capture */ - else - stored_volume = chip->digital_playback_volume[idx]; /* digital playback */ + if (is_capture) /* digital capture */ + stored_volume = chip->digital_capture_volume; + else /* digital playback */ + stored_volume = chip->digital_playback_volume[idx]; ucontrol->value.integer.value[0] = stored_volume[0]; ucontrol->value.integer.value[1] = stored_volume[1]; mutex_unlock(&chip->mgr->mixer_mutex); @@ -328,7 +378,7 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ int changed = 0; int is_capture = kcontrol->private_value; int *stored_volume; @@ -384,7 +434,8 @@ static int pcxhr_pcm_sw_get(struct snd_kcontrol *kcontrol, return 0; } -static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); int changed = 0; @@ -444,8 +495,8 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, if (chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) { chip->monitoring_volume[i] = - !!ucontrol->value.integer.value[i]; - if(chip->monitoring_active[i]) + ucontrol->value.integer.value[i]; + if (chip->monitoring_active[i]) /* update monitoring volume and mute */ /* do only when monitoring is unmuted */ pcxhr_update_audio_pipe_level(chip, 0, i); @@ -460,7 +511,7 @@ static struct snd_kcontrol_new pcxhr_control_monitor_vol = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), - .name = "Monitoring Volume", + .name = "Monitoring Playback Volume", .info = pcxhr_digital_vol_info, /* shared */ .get = pcxhr_monitor_vol_get, .put = pcxhr_monitor_vol_put, @@ -511,7 +562,7 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new pcxhr_control_monitor_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Monitoring Switch", + .name = "Monitoring Playback Switch", .info = pcxhr_sw_info, /* shared */ .get = pcxhr_monitor_sw_get, .put = pcxhr_monitor_sw_put @@ -533,7 +584,7 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip) struct pcxhr_rmh rmh; unsigned int mask, reg; unsigned int codec; - int err, use_src, changed; + int err, changed; switch (chip->chip_idx) { case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break; @@ -542,13 +593,10 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip) case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break; default: return -EINVAL; } - reg = 0; /* audio source from analog plug */ - use_src = 0; /* do not activate codec SRC */ - if (chip->audio_capture_source != 0) { reg = mask; /* audio source from digital plug */ - if (chip->audio_capture_source == 2) - use_src = 1; + } else { + reg = 0; /* audio source from analog plug */ } /* set the input source */ pcxhr_write_io_num_reg_cont(chip->mgr, mask, reg, &changed); @@ -560,29 +608,61 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip) if (err) return err; } - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set codec SRC on off */ - rmh.cmd_len = 3; - rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; - rmh.cmd[1] = codec; - rmh.cmd[2] = (CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x54); - err = pcxhr_send_msg(chip->mgr, &rmh); - if(err) - return err; - rmh.cmd[2] = (CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x49); - err = pcxhr_send_msg(chip->mgr, &rmh); + if (chip->mgr->board_aes_in_192k) { + int i; + unsigned int src_config = 0xC0; + /* update all src configs with one call */ + for (i = 0; (i < 4) && (i < chip->mgr->capture_chips); i++) { + if (chip->mgr->chip[i]->audio_capture_source == 2) + src_config |= (1 << (3 - i)); + } + /* set codec SRC on off */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); + rmh.cmd_len = 2; + rmh.cmd[0] |= IO_NUM_REG_CONFIG_SRC; + rmh.cmd[1] = src_config; + err = pcxhr_send_msg(chip->mgr, &rmh); + } else { + int use_src = 0; + if (chip->audio_capture_source == 2) + use_src = 1; + /* set codec SRC on off */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); + rmh.cmd_len = 3; + rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; + rmh.cmd[1] = codec; + rmh.cmd[2] = ((CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | + (use_src ? 0x41 : 0x54)); + err = pcxhr_send_msg(chip->mgr, &rmh); + if (err) + return err; + rmh.cmd[2] = ((CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | + (use_src ? 0x41 : 0x49)); + err = pcxhr_send_msg(chip->mgr, &rmh); + } return err; } static int pcxhr_audio_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[3] = {"Analog", "Digital", "Digi+SRC"}; + static const char *texts[5] = { + "Line", "Digital", "Digi+SRC", "Mic", "Line+Mic" + }; + int i; + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + i = 2; /* no SRC, no Mic available */ + if (chip->mgr->board_has_aes1) { + i = 3; /* SRC available */ + if (chip->mgr->board_has_mic) + i = 5; /* Mic and MicroMix available */ + } uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; + uinfo->value.enumerated.items = i; + if (uinfo->value.enumerated.item > (i-1)) + uinfo->value.enumerated.item = i-1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0; @@ -601,13 +681,21 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol, { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); int ret = 0; - - if (ucontrol->value.enumerated.item[0] >= 3) + int i = 2; /* no SRC, no Mic available */ + if (chip->mgr->board_has_aes1) { + i = 3; /* SRC available */ + if (chip->mgr->board_has_mic) + i = 5; /* Mic and MicroMix available */ + } + if (ucontrol->value.enumerated.item[0] >= i) return -EINVAL; mutex_lock(&chip->mgr->mixer_mutex); if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { chip->audio_capture_source = ucontrol->value.enumerated.item[0]; - pcxhr_set_audio_source(chip); + if (chip->mgr->is_hr_stereo) + hr222_set_audio_source(chip); + else + pcxhr_set_audio_source(chip); ret = 1; } mutex_unlock(&chip->mgr->mixer_mutex); @@ -626,25 +714,46 @@ static struct snd_kcontrol_new pcxhr_control_audio_src = { /* * clock type selection * enum pcxhr_clock_type { - * PCXHR_CLOCK_TYPE_INTERNAL = 0, - * PCXHR_CLOCK_TYPE_WORD_CLOCK, - * PCXHR_CLOCK_TYPE_AES_SYNC, - * PCXHR_CLOCK_TYPE_AES_1, - * PCXHR_CLOCK_TYPE_AES_2, - * PCXHR_CLOCK_TYPE_AES_3, - * PCXHR_CLOCK_TYPE_AES_4, - * }; + * PCXHR_CLOCK_TYPE_INTERNAL = 0, + * PCXHR_CLOCK_TYPE_WORD_CLOCK, + * PCXHR_CLOCK_TYPE_AES_SYNC, + * PCXHR_CLOCK_TYPE_AES_1, + * PCXHR_CLOCK_TYPE_AES_2, + * PCXHR_CLOCK_TYPE_AES_3, + * PCXHR_CLOCK_TYPE_AES_4, + * PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4, + * HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL, + * HR22_CLOCK_TYPE_AES_SYNC, + * HR22_CLOCK_TYPE_AES_1, + * HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1, + * }; */ static int pcxhr_clock_type_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[7] = { - "Internal", "WordClock", "AES Sync", "AES 1", "AES 2", "AES 3", "AES 4" + static const char *textsPCXHR[7] = { + "Internal", "WordClock", "AES Sync", + "AES 1", "AES 2", "AES 3", "AES 4" + }; + static const char *textsHR22[3] = { + "Internal", "AES Sync", "AES 1" }; + const char **texts; struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); - int clock_items = 3 + mgr->capture_chips; - + int clock_items = 2; /* at least Internal and AES Sync clock */ + if (mgr->board_has_aes1) { + clock_items += mgr->capture_chips; /* add AES x */ + if (!mgr->is_hr_stereo) + clock_items += 1; /* add word clock */ + } + if (mgr->is_hr_stereo) { + texts = textsHR22; + snd_BUG_ON(clock_items > (HR22_CLOCK_TYPE_MAX+1)); + } else { + texts = textsPCXHR; + snd_BUG_ON(clock_items > (PCXHR_CLOCK_TYPE_MAX+1)); + } uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = clock_items; @@ -667,9 +776,13 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); - unsigned int clock_items = 3 + mgr->capture_chips; int rate, ret = 0; - + unsigned int clock_items = 2; /* at least Internal and AES Sync clock */ + if (mgr->board_has_aes1) { + clock_items += mgr->capture_chips; /* add AES x */ + if (!mgr->is_hr_stereo) + clock_items += 1; /* add word clock */ + } if (ucontrol->value.enumerated.item[0] >= clock_items) return -EINVAL; mutex_lock(&mgr->mixer_mutex); @@ -677,7 +790,8 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, mutex_lock(&mgr->setup_mutex); mgr->use_clock_type = ucontrol->value.enumerated.item[0]; if (mgr->use_clock_type) - pcxhr_get_external_clock(mgr, mgr->use_clock_type, &rate); + pcxhr_get_external_clock(mgr, mgr->use_clock_type, + &rate); else rate = mgr->sample_rate; if (rate) { @@ -686,7 +800,7 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, mgr->sample_rate = rate; } mutex_unlock(&mgr->setup_mutex); - ret = 1; /* return 1 even if the set was not done. ok ? */ + ret = 1; /* return 1 even if the set was not done. ok ? */ } mutex_unlock(&mgr->mixer_mutex); return ret; @@ -747,14 +861,16 @@ static struct snd_kcontrol_new pcxhr_control_clock_rate = { /* * IEC958 status bits */ -static int pcxhr_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +static int pcxhr_iec958_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; uinfo->count = 1; return 0; } -static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char* aes_bits) +static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, + int aes_idx, unsigned char *aes_bits) { int i, err; unsigned char temp; @@ -763,39 +879,61 @@ static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, unsign pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; switch (chip->chip_idx) { - case 0: rmh.cmd[1] = CS8420_01_CS; break; /* use CS8416_01_CS for AES SYNC plug */ + /* instead of CS8420_01_CS use CS8416_01_CS for AES SYNC plug */ + case 0: rmh.cmd[1] = CS8420_01_CS; break; case 1: rmh.cmd[1] = CS8420_23_CS; break; case 2: rmh.cmd[1] = CS8420_45_CS; break; case 3: rmh.cmd[1] = CS8420_67_CS; break; default: return -EINVAL; } - switch (aes_idx) { - case 0: rmh.cmd[2] = CS8420_CSB0; break; /* use CS8416_CSBx for AES SYNC plug */ - case 1: rmh.cmd[2] = CS8420_CSB1; break; - case 2: rmh.cmd[2] = CS8420_CSB2; break; - case 3: rmh.cmd[2] = CS8420_CSB3; break; - case 4: rmh.cmd[2] = CS8420_CSB4; break; - default: return -EINVAL; + if (chip->mgr->board_aes_in_192k) { + switch (aes_idx) { + case 0: rmh.cmd[2] = CS8416_CSB0; break; + case 1: rmh.cmd[2] = CS8416_CSB1; break; + case 2: rmh.cmd[2] = CS8416_CSB2; break; + case 3: rmh.cmd[2] = CS8416_CSB3; break; + case 4: rmh.cmd[2] = CS8416_CSB4; break; + default: return -EINVAL; + } + } else { + switch (aes_idx) { + /* instead of CS8420_CSB0 use CS8416_CSBx for AES SYNC plug */ + case 0: rmh.cmd[2] = CS8420_CSB0; break; + case 1: rmh.cmd[2] = CS8420_CSB1; break; + case 2: rmh.cmd[2] = CS8420_CSB2; break; + case 3: rmh.cmd[2] = CS8420_CSB3; break; + case 4: rmh.cmd[2] = CS8420_CSB4; break; + default: return -EINVAL; + } } - rmh.cmd[1] &= 0x0fffff; /* size and code the chip id for the fpga */ - rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; /* chip signature + map for spi read */ + /* size and code the chip id for the fpga */ + rmh.cmd[1] &= 0x0fffff; + /* chip signature + map for spi read */ + rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); if (err) return err; - temp = 0; - for (i = 0; i < 8; i++) { - /* attention : reversed bit order (not with CS8416_01_CS) */ - temp <<= 1; - if (rmh.stat[1] & (1 << i)) - temp |= 1; + + if (chip->mgr->board_aes_in_192k) { + temp = (unsigned char)rmh.stat[1]; + } else { + temp = 0; + /* reversed bit order (not with CS8416_01_CS) */ + for (i = 0; i < 8; i++) { + temp <<= 1; + if (rmh.stat[1] & (1 << i)) + temp |= 1; + } } - snd_printdd("read iec958 AES %d byte %d = 0x%x\n", chip->chip_idx, aes_idx, temp); + snd_printdd("read iec958 AES %d byte %d = 0x%x\n", + chip->chip_idx, aes_idx, temp); *aes_bits = temp; return 0; } -static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); unsigned char aes_bits; @@ -806,7 +944,12 @@ static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v if (kcontrol->private_value == 0) /* playback */ aes_bits = chip->aes_bits[i]; else { /* capture */ - err = pcxhr_iec958_capture_byte(chip, i, &aes_bits); + if (chip->mgr->is_hr_stereo) + err = hr222_iec958_capture_byte(chip, i, + &aes_bits); + else + err = pcxhr_iec958_capture_byte(chip, i, + &aes_bits); if (err) break; } @@ -825,7 +968,8 @@ static int pcxhr_iec958_mask_get(struct snd_kcontrol *kcontrol, return 0; } -static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char aes_bits) +static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, + int aes_idx, unsigned char aes_bits) { int i, err, cmd; unsigned char new_bits = aes_bits; @@ -834,12 +978,12 @@ static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, unsigne for (i = 0; i < 8; i++) { if ((old_bits & 0x01) != (new_bits & 0x01)) { - cmd = chip->chip_idx & 0x03; /* chip index 0..3 */ - if(chip->chip_idx > 3) + cmd = chip->chip_idx & 0x03; /* chip index 0..3 */ + if (chip->chip_idx > 3) /* new bit used if chip_idx>3 (PCX1222HR) */ cmd |= 1 << 22; - cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */ - cmd |= (new_bits & 0x01) << 23; /* add bit value */ + cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */ + cmd |= (new_bits & 0x01) << 23; /* add bit value */ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); rmh.cmd[0] |= IO_NUM_REG_CUER; rmh.cmd[1] = cmd; @@ -867,7 +1011,12 @@ static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol, mutex_lock(&chip->mgr->mixer_mutex); for (i = 0; i < 5; i++) { if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) { - pcxhr_iec958_update_byte(chip, i, ucontrol->value.iec958.status[i]); + if (chip->mgr->is_hr_stereo) + hr222_iec958_update_byte(chip, i, + ucontrol->value.iec958.status[i]); + else + pcxhr_iec958_update_byte(chip, i, + ucontrol->value.iec958.status[i]); changed = 1; } } @@ -917,29 +1066,53 @@ static void pcxhr_init_audio_levels(struct snd_pcxhr *chip) /* at boot time the digital volumes are unmuted 0dB */ for (j = 0; j < PCXHR_PLAYBACK_STREAMS; j++) { chip->digital_playback_active[j][i] = 1; - chip->digital_playback_volume[j][i] = PCXHR_DIGITAL_ZERO_LEVEL; + chip->digital_playback_volume[j][i] = + PCXHR_DIGITAL_ZERO_LEVEL; } - /* after boot, only two bits are set on the uer interface */ - chip->aes_bits[0] = IEC958_AES0_PROFESSIONAL | IEC958_AES0_PRO_FS_48000; -/* only for test purpose, remove later */ + /* after boot, only two bits are set on the uer + * interface + */ + chip->aes_bits[0] = (IEC958_AES0_PROFESSIONAL | + IEC958_AES0_PRO_FS_48000); #ifdef CONFIG_SND_DEBUG - /* analog volumes for playback (is LEVEL_MIN after boot) */ + /* analog volumes for playback + * (is LEVEL_MIN after boot) + */ chip->analog_playback_active[i] = 1; - chip->analog_playback_volume[i] = PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL; - pcxhr_update_analog_audio_level(chip, 0, i); + if (chip->mgr->is_hr_stereo) + chip->analog_playback_volume[i] = + HR222_LINE_PLAYBACK_ZERO_LEVEL; + else { + chip->analog_playback_volume[i] = + PCXHR_LINE_PLAYBACK_ZERO_LEVEL; + pcxhr_update_analog_audio_level(chip, 0, i); + } #endif -/* test end */ + /* stereo cards need to be initialised after boot */ + if (chip->mgr->is_hr_stereo) + hr222_update_analog_audio_level(chip, 0, i); } if (chip->nb_streams_capt) { /* at boot time the digital volumes are unmuted 0dB */ - chip->digital_capture_volume[i] = PCXHR_DIGITAL_ZERO_LEVEL; -/* only for test purpose, remove later */ + chip->digital_capture_volume[i] = + PCXHR_DIGITAL_ZERO_LEVEL; + chip->analog_capture_active = 1; #ifdef CONFIG_SND_DEBUG - /* analog volumes for playback (is LEVEL_MIN after boot) */ - chip->analog_capture_volume[i] = PCXHR_ANALOG_CAPTURE_ZERO_LEVEL; - pcxhr_update_analog_audio_level(chip, 1, i); + /* analog volumes for playback + * (is LEVEL_MIN after boot) + */ + if (chip->mgr->is_hr_stereo) + chip->analog_capture_volume[i] = + HR222_LINE_CAPTURE_ZERO_LEVEL; + else { + chip->analog_capture_volume[i] = + PCXHR_LINE_CAPTURE_ZERO_LEVEL; + pcxhr_update_analog_audio_level(chip, 1, i); + } #endif -/* test end */ + /* stereo cards need to be initialised after boot */ + if (chip->mgr->is_hr_stereo) + hr222_update_analog_audio_level(chip, 1, i); } } @@ -963,90 +1136,125 @@ int pcxhr_create_mixer(struct pcxhr_mgr *mgr) temp = pcxhr_control_analog_level; temp.name = "Master Playback Volume"; temp.private_value = 0; /* playback */ - temp.tlv.p = db_scale_analog_playback; - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + if (mgr->is_hr_stereo) + temp.tlv.p = db_scale_a_hr222_playback; + else + temp.tlv.p = db_scale_analog_playback; + err = snd_ctl_add(chip->card, + snd_ctl_new1(&temp, chip)); + if (err < 0) return err; + /* output mute controls */ - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_output_switch, - chip))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_output_switch, + chip)); + if (err < 0) return err; - + temp = snd_pcxhr_pcm_vol; temp.name = "PCM Playback Volume"; temp.count = PCXHR_PLAYBACK_STREAMS; temp.private_value = 0; /* playback */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&temp, chip)); + if (err < 0) return err; - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_pcm_switch, - chip))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_pcm_switch, chip)); + if (err < 0) return err; /* IEC958 controls */ - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_playback_iec958_mask, - chip))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_playback_iec958_mask, + chip)); + if (err < 0) return err; - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_playback_iec958, - chip))) < 0) + + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_playback_iec958, + chip)); + if (err < 0) return err; } if (chip->nb_streams_capt) { - /* analog input level control only on first two chips !*/ + /* analog input level control */ temp = pcxhr_control_analog_level; - temp.name = "Master Capture Volume"; + temp.name = "Line Capture Volume"; temp.private_value = 1; /* capture */ - temp.tlv.p = db_scale_analog_capture; - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + if (mgr->is_hr_stereo) + temp.tlv.p = db_scale_a_hr222_capture; + else + temp.tlv.p = db_scale_analog_capture; + + err = snd_ctl_add(chip->card, + snd_ctl_new1(&temp, chip)); + if (err < 0) return err; temp = snd_pcxhr_pcm_vol; temp.name = "PCM Capture Volume"; temp.count = 1; temp.private_value = 1; /* capture */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + + err = snd_ctl_add(chip->card, + snd_ctl_new1(&temp, chip)); + if (err < 0) return err; + /* Audio source */ - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_audio_src, - chip))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_audio_src, chip)); + if (err < 0) return err; + /* IEC958 controls */ - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_capture_iec958_mask, - chip))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_capture_iec958_mask, + chip)); + if (err < 0) return err; - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_capture_iec958, - chip))) < 0) + + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_capture_iec958, + chip)); + if (err < 0) return err; + + if (mgr->is_hr_stereo) { + err = hr222_add_mic_controls(chip); + if (err < 0) + return err; + } } /* monitoring only if playback and capture device available */ if (chip->nb_streams_capt > 0 && chip->nb_streams_play > 0) { /* monitoring */ - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_monitor_vol, - chip))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_monitor_vol, chip)); + if (err < 0) return err; - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_monitor_sw, - chip))) < 0) + + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_monitor_sw, chip)); + if (err < 0) return err; } if (i == 0) { /* clock mode only one control per pcxhr */ - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_clock_type, - mgr))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_clock_type, mgr)); + if (err < 0) return err; - /* non standard control used to scan the external clock presence/frequencies */ - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_clock_rate, - mgr))) < 0) + /* non standard control used to scan + * the external clock presence/frequencies + */ + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_clock_rate, mgr)); + if (err < 0) return err; } -- 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f52e271edd57..4afa0c9b9b6e 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index a2eba4f17e9c..9a8498456e6c 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 53f64eb75ec6..1131c86ad495 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 1131c86ad495..f84874445b50 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 a70b181bbace..e1077df5e882 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 6462d758e641..f13ec4c71f8a 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f84874445b50..052a898a63ba 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 e1077df5e882..4034625b5997 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 f13ec4c71f8a..f17ccd513350 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 052a898a63ba..1cb85b73e19b 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 4034625b5997..9fe0b67bb1e4 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 5868bbc131cd..173af489322f 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4afa0c9b9b6e..9cd2545d988e 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 73f6a12ed187b7e7ac9334d1419ba7bf7ac1be26 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 27 Nov 2008 15:40:40 +0100 Subject: ALSA: sound/pci/mixart/mixart.c: Add missing snd_card_free The function snd_mixart_create creates a link between mgr and card that allows snd_mixart_free to free card as well. But if snd_mixart_create fails, then the link has not been created and card has to be freed explicitly. The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; statement S,S1; position p1,p2,p3; expression E,E1; type T,T1; expression *ptr != NULL; @@ ( if ((x@p1 = snd_card_new(...)) == NULL) S | x@p1 = snd_card_new(...); ) ... when != snd_card_free(...,(T)x,...) when != if (...) { <+... snd_card_free(...,(T)x,...) ...+> } when != true x == NULL || ... when != x = E when != E = (T)x when any ( if (x == NULL || ...) S1 | if@p2 (...) { ... when != snd_card_free(...,(T1)x,...) when != if (...) { <+... snd_card_free(...,(T1)x,...) ...+> } when != x = E1 when != E1 = (T1)x ( return \(0\|<+...x...+>\|ptr\); | return@p3 ...; ) } ) @ script:python @ p1 << r.p1; p3 << r.p3; @@ print "* file: %s snd_card_new: %s return: %s" % (p1[0].file,p1[0].line,p3[0].line) // Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai --- sound/pci/mixart/mixart.c | 4 +++- sound/pci/pcxhr/pcxhr.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 2d0dce649a64..fd9a117f37a4 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1010,7 +1010,7 @@ static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card * .dev_free = snd_mixart_chip_dev_free, }; - mgr->chip[idx] = chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { snd_printk(KERN_ERR "cannot allocate chip\n"); return -ENOMEM; @@ -1025,6 +1025,7 @@ static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card * return err; } + mgr->chip[idx] = chip; snd_card_set_dev(card, &mgr->pci->dev); return 0; @@ -1378,6 +1379,7 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i); if ((err = snd_mixart_create(mgr, card, i)) < 0) { + snd_card_free(card); snd_mixart_free(mgr); return err; } diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 0e06c6c9fcc0..58621206a2b3 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -1024,7 +1024,7 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card, .dev_free = pcxhr_chip_dev_free, }; - mgr->chip[idx] = chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { snd_printk(KERN_ERR "cannot allocate chip\n"); return -ENOMEM; @@ -1050,6 +1050,7 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card, return err; } + mgr->chip[idx] = chip; snd_card_set_dev(card, &mgr->pci->dev); return 0; @@ -1307,6 +1308,7 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i); if ((err = pcxhr_create(mgr, card, i)) < 0) { + snd_card_free(card); pcxhr_free(mgr); return err; } -- 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 (limited to 'sound/pci') diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 7c60f1a45a8d..717040a491b9 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 6daf5fd9a279..50f9d0967251 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 3ecd7e797dee..e6cc9463667a 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 1cb85b73e19b..4aa7b1b72877 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 9fe0b67bb1e4..586ea08b340b 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 98ff010d5b95..65745e96dc70 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 173af489322f..300ab407cf42 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 38212c1020a6..000000000000 --- 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 0cc6be12b8b7..c1918a1a6df9 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 5603a1acddb1..5887b827bb32 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 6ef57fbfb6eb..f3ebe837f2d5 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 076010708152..b20e1cede00b 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 fe08bef897cd..290da562f29b 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 1360d54a7d01..e23de5594b6e 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 9cd2545d988e..ba640d36d648 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 9332b63e406c..43b436c5d01b 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 70181d500536..9e07f44ab28a 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 05182be1c9f0..6e4d01d1d502 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f17ccd513350..8aee322313ed 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 9fe0b67bb1e4..43af18c4a214 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 9a8498456e6c..7b3817985c34 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 9cd2545d988e..698c85625a42 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 43af18c4a214..bbbc83b387d1 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 7b3817985c34..7ca66d654148 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 70181d500536..33170a242009 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 1cb85b73e19b..a867e1e8658a 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 698c85625a42..40b3fcd142a3 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 de04b102bfc9a13e96f0892305b394077ffb6514 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 26 Nov 2008 10:37:23 +0100 Subject: ALSA: oxygen: add Claro halo support Add support for the HT-Omega Claro halo (XT). Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 3 ++- sound/pci/oxygen/oxygen.c | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 7003711f4fcc..611df4b72831 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -208,7 +208,8 @@ config SND_OXYGEN * AuzenTech X-Meridian * Bgears b-Enspirer * Club3D Theatron DTS - * HT-Omega Claro + * HT-Omega Claro (plus) + * HT-Omega Claro halo (XT) * Razer Barracuda AC-1 * Sondigo Inferno diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index b60f6212745a..de999c6d6dd3 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -61,6 +61,7 @@ MODULE_PARM_DESC(enable, "enable card"); enum { MODEL_CMEDIA_REF, /* C-Media's reference design */ MODEL_MERIDIAN, /* AuzenTech X-Meridian */ + MODEL_HALO, /* HT-Omega Claro halo */ }; static struct pci_device_id oxygen_ids[] __devinitdata = { @@ -74,6 +75,7 @@ static struct pci_device_id oxygen_ids[] __devinitdata = { { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CMEDIA_REF }, + { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_HALO }, { } }; MODULE_DEVICE_TABLE(pci, oxygen_ids); @@ -301,6 +303,8 @@ static int generic_probe(struct oxygen *chip, unsigned long driver_data) PLAYBACK_1_TO_SPDIF | CAPTURE_0_FROM_I2S_2 | CAPTURE_1_FROM_SPDIF; + } + if (driver_data == MODEL_MERIDIAN || driver_data == MODEL_HALO) { chip->model.misc_flags = OXYGEN_MISC_MIDI; chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; } -- 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 4aa7b1b72877..2fff0fb77ba2 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index e6cc9463667a..e00421c0d8ba 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 2fff0fb77ba2..004344825e9e 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 586ea08b340b..6612d0f20bc6 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 7c60f1a45a8d..ccf7326a667a 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 33170a242009..068a77ae459e 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 068a77ae459e..14db35a61cfe 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 480cf663e6988b3e79b570b42d2dbdb6c2ba9b94 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 15:28:07 +0100 Subject: ALSA: Fix a compile warning in cs46xx_lib.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a build warning sound/pci/cs46xx/cs46xx_lib.c:3643: warning: unused variable ‘i’ when CONFIG_SND_CS46XX_NEW_DSP=n. Signed-off-by: Takashi Iwai --- sound/pci/cs46xx/cs46xx_lib.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index fb6dc3980257..8ab07aa63652 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -3640,7 +3640,10 @@ int snd_cs46xx_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct snd_cs46xx *chip = card->private_data; - int i, amp_saved; + int amp_saved; +#ifdef CONFIG_SND_CS46XX_NEW_DSP + int i; +#endif pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); -- cgit v1.2.3 From ade9b2fb9bf8114f77eefc70b9042417e62acf72 Mon Sep 17 00:00:00 2001 From: Markus Bollinger Date: Mon, 1 Dec 2008 15:31:06 +0100 Subject: ALSA: pcxhr - change firmware filenames - compatibility issue : change firmware filenames the pcxhr driver version <= 1.0.18a does not work with new firmware > 1.0.17. Keep the old firmware files and add new firmware files with different names Signed-off-by: Markus Bollinger Signed-off-by: Takashi Iwai --- sound/pci/pcxhr/pcxhr_hwdep.c | 62 +++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c index ea50018d785b..592743a298b0 100644 --- a/sound/pci/pcxhr/pcxhr_hwdep.c +++ b/sound/pci/pcxhr/pcxhr_hwdep.c @@ -366,18 +366,18 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) { static char *fw_files[][5] = { - [0] = { "xi_1_882.dat", "xc_1_882.dat", - "e321_512.e56", "b321_512.b56", "d321_512.d56" }, - [1] = { "xi_1_882.dat", "xc_882e.dat", - "e321_512.e56", "b882e.b56", "d321_512.d56" }, - [2] = { "xi_1_882.dat", "xc_1222.dat", - "e321_512.e56", "b1222.b56", "d1222.d56" }, - [3] = { "xi_1_882.dat", "xc_1222e.dat", - "e321_512.e56", "b1222e.b56", "d1222.d56" }, - [4] = { NULL, "x1_222hr.dat", - "e924.e56", "b924.b56", "l_1_222.d56" }, - [5] = { NULL, "x1_924hr.dat", - "e924.e56", "b924.b56", "l_1_222.d56" }, + [0] = { "xlxint.dat", "xlxc882hr.dat", + "dspe882.e56", "dspb882hr.b56", "dspd882.d56" }, + [1] = { "xlxint.dat", "xlxc882e.dat", + "dspe882.e56", "dspb882e.b56", "dspd882.d56" }, + [2] = { "xlxint.dat", "xlxc1222hr.dat", + "dspe882.e56", "dspb1222hr.b56", "dspd1222.d56" }, + [3] = { "xlxint.dat", "xlxc1222e.dat", + "dspe882.e56", "dspb1222e.b56", "dspd1222.d56" }, + [4] = { NULL, "xlxc222.dat", + "dspe924.e56", "dspb924.b56", "dspd222.d56" }, + [5] = { NULL, "xlxc924.dat", + "dspe924.e56", "dspb924.b56", "dspd222.d56" }, }; char path[32]; @@ -404,25 +404,25 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) return 0; } -MODULE_FIRMWARE("pcxhr/xi_1_882.dat"); -MODULE_FIRMWARE("pcxhr/xc_1_882.dat"); -MODULE_FIRMWARE("pcxhr/xc_882e.dat"); -MODULE_FIRMWARE("pcxhr/e321_512.e56"); -MODULE_FIRMWARE("pcxhr/b321_512.b56"); -MODULE_FIRMWARE("pcxhr/b882e.b56"); -MODULE_FIRMWARE("pcxhr/d321_512.d56"); - -MODULE_FIRMWARE("pcxhr/xc_1222.dat"); -MODULE_FIRMWARE("pcxhr/xc_1222e.dat"); -MODULE_FIRMWARE("pcxhr/b1222.b56"); -MODULE_FIRMWARE("pcxhr/b1222e.b56"); -MODULE_FIRMWARE("pcxhr/d1222.d56"); - -MODULE_FIRMWARE("pcxhr/x1_222hr.dat"); -MODULE_FIRMWARE("pcxhr/x1_924hr.dat"); -MODULE_FIRMWARE("pcxhr/e924.e56"); -MODULE_FIRMWARE("pcxhr/b924.b56"); -MODULE_FIRMWARE("pcxhr/l_1_222.d56"); +MODULE_FIRMWARE("pcxhr/xlxint.dat"); +MODULE_FIRMWARE("pcxhr/xlxc882hr.dat"); +MODULE_FIRMWARE("pcxhr/xlxc882e.dat"); +MODULE_FIRMWARE("pcxhr/dspe882.e56"); +MODULE_FIRMWARE("pcxhr/dspb882hr.b56"); +MODULE_FIRMWARE("pcxhr/dspb882e.b56"); +MODULE_FIRMWARE("pcxhr/dspd882.d56"); + +MODULE_FIRMWARE("pcxhr/xlxc1222hr.dat"); +MODULE_FIRMWARE("pcxhr/xlxc1222e.dat"); +MODULE_FIRMWARE("pcxhr/dspb1222hr.b56"); +MODULE_FIRMWARE("pcxhr/dspb1222e.b56"); +MODULE_FIRMWARE("pcxhr/dspd1222.d56"); + +MODULE_FIRMWARE("pcxhr/xlxc222.dat"); +MODULE_FIRMWARE("pcxhr/xlxc924.dat"); +MODULE_FIRMWARE("pcxhr/dspe924.e56"); +MODULE_FIRMWARE("pcxhr/dspb924.b56"); +MODULE_FIRMWARE("pcxhr/dspd222.d56"); #else /* old style firmware loading */ -- cgit v1.2.3 From 1966bbd62ce31cef0cb020a6b4bd852dbc63b40c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Dec 2008 14:54:45 +0000 Subject: ALSA: ac97 - Add WM9715 to AC97 IDs The WM9715 is software compatible with the WM9711 and WM9712. Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index bd510eceff1f..e2b843b4f9d0 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -175,7 +175,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { { 0x574d4C04, 0xffffffff, "WM9704M,WM9704Q", patch_wolfson04, NULL}, { 0x574d4C05, 0xffffffff, "WM9705,WM9710", patch_wolfson05, NULL}, { 0x574d4C09, 0xffffffff, "WM9709", NULL, NULL}, -{ 0x574d4C12, 0xffffffff, "WM9711,WM9712", patch_wolfson11, NULL}, +{ 0x574d4C12, 0xffffffff, "WM9711,WM9712,WM9715", patch_wolfson11, NULL}, { 0x574d4c13, 0xffffffff, "WM9713,WM9714", patch_wolfson13, NULL, AC97_DEFAULT_POWER_OFF}, { 0x594d4800, 0xffffffff, "YMF743", patch_yamaha_ymf743, NULL }, { 0x594d4802, 0xffffffff, "YMF752", NULL, NULL }, -- cgit v1.2.3 From 16950e09cf07b54abb78dd09f8ef3c85c6bdc9de Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Dec 2008 09:31:16 +0100 Subject: ALSA: emu10k1 - Add capture boost mixer switch for Audigy Due to the conversion (drop) from 24bit in the DSP to 16bit in AC97, the maximum capture level on Audigy seems lower than it could be. This patch adds a workaround to enable the artificial capture boost switch. When this switch is on, the whole analog capature level is boost up. However, this results in the lower capture resolution. Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emumixer.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index f34bbfb705f5..b0fb6c917c38 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1639,6 +1639,45 @@ static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata = .put = snd_emu10k1_shared_spdif_put }; +/* workaround for too low volume on Audigy due to 16bit/24bit conversion */ + +#define snd_audigy_capture_boost_info snd_ctl_boolean_mono_info + +static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + + /* FIXME: better to use a cached version */ + val = snd_ac97_read(emu->ac97, AC97_REC_GAIN); + ucontrol->value.integer.value[0] = !!val; + return 0; +} + +static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + + if (ucontrol->value.integer.value[0]) + val = 0x0f0f; + else + val = 0; + return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val); +} + +static struct snd_kcontrol_new snd_audigy_capture_boost __devinitdata = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Capture Boost", + .info = snd_audigy_capture_boost_info, + .get = snd_audigy_capture_boost_get, + .put = snd_audigy_capture_boost_put +}; + + /* */ static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97) @@ -2087,5 +2126,12 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, } } + if (emu->card_capabilities->ac97_chip && emu->audigy) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost, + emu)); + if (err < 0) + return err; + } + return 0; } -- cgit v1.2.3 From 0f620830db0818ebe065b31c33892e8f0622e1b2 Mon Sep 17 00:00:00 2001 From: Peter Gruber Date: Wed, 3 Dec 2008 15:32:15 +0100 Subject: ALSA: Reduce stall detection timeout in riptide.c Reduce the command timeout to 0.5sec. Should be enough to allow a working command interface but removes a RCU stall and slow resume on some revisions where the AC97 revision detection stalls in resume. Signed-off-by: Peter Gruber Signed-off-by: Takashi Iwai --- sound/pci/riptide/riptide.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index e9f0706ed3e4..d0ccfc68c522 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -172,7 +172,7 @@ MODULE_PARM_DESC(opl3_port, "OPL3 port # for Riptide driver."); #define MAX_WRITE_RETRY 10 /* cmd interface limits */ #define MAX_ERROR_COUNT 10 -#define CMDIF_TIMEOUT 500000 +#define CMDIF_TIMEOUT 50000 #define RESET_TRIES 5 #define READ_PORT_ULONG(p) inl((unsigned long)&(p)) -- 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index e23de5594b6e..5e6cc41a559d 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 5e6cc41a559d..0cd53063e62e 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 5da95273c2e63c9607652b5e8dd39808b6992d7c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 24 Nov 2008 14:06:08 +0100 Subject: ALSA: ca0106 - Add power-management support Added the missing PM support for snd-ca0106 driver. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106.h | 15 +- sound/pci/ca0106/ca0106_main.c | 519 +++++++++++++++++++++++----------------- sound/pci/ca0106/ca0106_mixer.c | 182 ++++++++++---- 3 files changed, 450 insertions(+), 266 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 74175fc80c7f..1c14ff424116 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -686,7 +686,7 @@ struct snd_ca0106 { spinlock_t emu_lock; struct snd_ac97 *ac97; - struct snd_pcm *pcm; + struct snd_pcm *pcm[4]; struct snd_ca0106_channel playback_channels[4]; struct snd_ca0106_channel capture_channels[4]; @@ -703,6 +703,11 @@ struct snd_ca0106 { struct snd_ca_midi midi2; u16 spi_dac_reg[16]; + +#ifdef CONFIG_PM +#define NUM_SAVED_VOLUMES 9 + unsigned int saved_vol[NUM_SAVED_VOLUMES]; +#endif }; int snd_ca0106_mixer(struct snd_ca0106 *emu); @@ -721,3 +726,11 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, u32 reg, u32 value); int snd_ca0106_spi_write(struct snd_ca0106 * emu, unsigned int data); + +#ifdef CONFIG_PM +void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip); +void snd_ca0106_mixer_resume(struct snd_ca0106 *chip); +#else +#define snd_ca0106_mixer_suspend(chip) do { } while (0) +#define snd_ca0106_mixer_resume(chip) do { } while (0) +#endif diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 88fbf285d2b7..cea8a7cdb1d5 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -847,15 +847,18 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream, struct snd_pcm_substream *s; u32 basic = 0; u32 extended = 0; - int running=0; + u32 bits; + int running = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - running=1; + case SNDRV_PCM_TRIGGER_RESUME: + running = 1; break; case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: default: - running=0; + running = 0; break; } snd_pcm_group_for_each_entry(s, substream) { @@ -865,22 +868,32 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream, runtime = s->runtime; epcm = runtime->private_data; channel = epcm->channel_id; - //snd_printk("channel=%d\n",channel); + /* snd_printk("channel=%d\n",channel); */ epcm->running = running; - basic |= (0x1<ac97); } +static void ca0106_stop_chip(struct snd_ca0106 *chip); + static int snd_ca0106_free(struct snd_ca0106 *chip) { - if (chip->res_port != NULL) { /* avoid access to already used hardware */ - // disable interrupts - snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); - outl(0, chip->port + INTE); - snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); - udelay(1000); - // disable audio - //outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); - outl(0, chip->port + HCFG); - /* FIXME: We need to stop and DMA transfers here. - * But as I am not sure how yet, we cannot from the dma pages. - * So we can fix: snd-malloc: Memory leak? pages not freed = 8 - */ + if (chip->res_port != NULL) { + /* avoid access to already used hardware */ + ca0106_stop_chip(chip); } if (chip->irq >= 0) free_irq(chip->irq, chip); @@ -1203,15 +1208,14 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct snd_pcm **rpcm) +static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm)) < 0) + err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm); + if (err < 0) return err; pcm->private_data = emu; @@ -1238,7 +1242,6 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct s pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; strcpy(pcm->name, "CA0106"); - emu->pcm = pcm; for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; @@ -1260,8 +1263,7 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct s return err; } - if (rpcm) - *rpcm = pcm; + emu->pcm[device] = pcm; return 0; } @@ -1301,89 +1303,9 @@ static unsigned int i2c_adc_init[][2] = { { 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */ }; -static int __devinit snd_ca0106_create(int dev, struct snd_card *card, - struct pci_dev *pci, - struct snd_ca0106 **rchip) +static void ca0106_init_chip(struct snd_ca0106 *chip) { - struct snd_ca0106 *chip; - struct snd_ca0106_details *c; - int err; int ch; - static struct snd_device_ops ops = { - .dev_free = snd_ca0106_dev_free, - }; - - *rchip = NULL; - - if ((err = pci_enable_device(pci)) < 0) - return err; - if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || - pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { - printk(KERN_ERR "error to set 32bit mask DMA\n"); - pci_disable_device(pci); - return -ENXIO; - } - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - pci_disable_device(pci); - return -ENOMEM; - } - - chip->card = card; - chip->pci = pci; - chip->irq = -1; - - spin_lock_init(&chip->emu_lock); - - chip->port = pci_resource_start(pci, 0); - if ((chip->res_port = request_region(chip->port, 0x20, - "snd_ca0106")) == NULL) { - snd_ca0106_free(chip); - printk(KERN_ERR "cannot allocate the port\n"); - return -EBUSY; - } - - if (request_irq(pci->irq, snd_ca0106_interrupt, - IRQF_SHARED, "snd_ca0106", chip)) { - snd_ca0106_free(chip); - printk(KERN_ERR "cannot grab irq\n"); - return -EBUSY; - } - chip->irq = pci->irq; - - /* This stores the periods table. */ - if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &chip->buffer) < 0) { - snd_ca0106_free(chip); - return -ENOMEM; - } - - pci_set_master(pci); - /* read serial */ - pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); - pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); -#if 1 - printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model, - pci->revision, chip->serial); -#endif - strcpy(card->driver, "CA0106"); - strcpy(card->shortname, "CA0106"); - - for (c = ca0106_chip_details; c->serial; c++) { - if (subsystem[dev]) { - if (c->serial == subsystem[dev]) - break; - } else if (c->serial == chip->serial) - break; - } - chip->details = c; - if (subsystem[dev]) { - printk(KERN_INFO "snd-ca0106: Sound card name=%s, subsystem=0x%x. Forced to subsystem=0x%x\n", - c->name, chip->serial, subsystem[dev]); - } - - sprintf(card->longname, "%s at 0x%lx irq %i", - c->name, chip->port, chip->irq); outl(0, chip->port + INTE); @@ -1401,31 +1323,31 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, * AN = 0 (Audio data) * P = 0 (Consumer) */ - snd_ca0106_ptr_write(chip, SPCS0, 0, - chip->spdif_bits[0] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + chip->spdif_bits[0] = + SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | + SPCS_GENERATIONSTATUS | 0x00001200 | + 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; + snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); /* Only SPCS1 has been tested */ - snd_ca0106_ptr_write(chip, SPCS1, 0, - chip->spdif_bits[1] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); - snd_ca0106_ptr_write(chip, SPCS2, 0, - chip->spdif_bits[2] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); - snd_ca0106_ptr_write(chip, SPCS3, 0, - chip->spdif_bits[3] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + chip->spdif_bits[1] = + SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | + SPCS_GENERATIONSTATUS | 0x00001200 | + 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; + snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1]); + chip->spdif_bits[2] = + SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | + SPCS_GENERATIONSTATUS | 0x00001200 | + 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; + snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2]); + chip->spdif_bits[3] = + SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | + SPCS_GENERATIONSTATUS | 0x00001200 | + 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; + snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3]); snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); @@ -1433,36 +1355,53 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, /* Write 0x8000 to AC97_REC_GAIN to mute it. */ outb(AC97_REC_GAIN, chip->port + AC97ADDRESS); outw(0x8000, chip->port + AC97DATA); -#if 0 +#if 0 /* FIXME: what are these? */ snd_ca0106_ptr_write(chip, SPCS0, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x42, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x43, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x44, 0, 0x2108006); #endif - //snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */ + /* OSS drivers set this. */ + /* snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); */ + /* Analog or Digital output */ snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); - snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ + /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. + * Use 0x000f0000 for surround71 + */ + snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); + chip->spdif_enable = 0; /* Set digital SPDIF output off */ - //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ - //snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */ + /*snd_ca0106_ptr_write(chip, 0x45, 0, 0);*/ /* Analogue out */ + /*snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00);*/ /* Digital out */ + + /* goes to 0x40c80000 when doing SPDIF IN/OUT */ + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); + /* (Mute) CAPTURE feedback into PLAYBACK volume. + * Only lower 16 bits matter. + */ + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); + /* SPDIF IN Volume */ + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); + /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); /* goes to 0x40c80000 when doing SPDIF IN/OUT */ - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); /* (Mute) CAPTURE feedback into PLAYBACK volume. Only lower 16 bits matter. */ - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); /* SPDIF IN Volume */ - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING1, 0, 0x32765410); snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING2, 0, 0x76767676); snd_ca0106_ptr_write(chip, CAPTURE_ROUTING1, 0, 0x32765410); snd_ca0106_ptr_write(chip, CAPTURE_ROUTING2, 0, 0x76767676); - for(ch = 0; ch < 4; ch++) { - snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); /* Only high 16 bits matter */ + + for (ch = 0; ch < 4; ch++) { + /* Only high 16 bits matter */ + snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); snd_ca0106_ptr_write(chip, CAPTURE_VOLUME2, ch, 0x30303030); - //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); /* Mute */ - //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); /* Mute */ - snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */ - snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */ +#if 0 /* Mute */ + snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); + snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); + snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); + snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); +#endif } if (chip->details->i2c_adc == 1) { /* Select MIC, Line in, TAD in, AUX in */ @@ -1481,44 +1420,56 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, chip->capture_source = 3; } - if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ - /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ + if (chip->details->gpio_type == 2) { + /* The SB0438 use GPIO differently. */ + /* FIXME: Still need to find out what the other GPIO bits do. + * E.g. For digital spdif out. + */ outl(0x0, chip->port+GPIO); - //outl(0x00f0e000, chip->port+GPIO); /* Analog */ + /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ outl(0x005f5301, chip->port+GPIO); /* Analog */ - } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ - /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ + } else if (chip->details->gpio_type == 1) { + /* The SB0410 and SB0413 use GPIO differently. */ + /* FIXME: Still need to find out what the other GPIO bits do. + * E.g. For digital spdif out. + */ outl(0x0, chip->port+GPIO); - //outl(0x00f0e000, chip->port+GPIO); /* Analog */ + /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ outl(0x005f5301, chip->port+GPIO); /* Analog */ } else { outl(0x0, chip->port+GPIO); outl(0x005f03a3, chip->port+GPIO); /* Analog */ - //outl(0x005f02a2, chip->port+GPIO); /* SPDIF */ + /* outl(0x005f02a2, chip->port+GPIO); */ /* SPDIF */ } snd_ca0106_intr_enable(chip, 0x105); /* Win2000 uses 0x1e0 */ - //outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); - //outl(0x00001409, chip->port+HCFG); /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ - //outl(0x00000009, chip->port+HCFG); - outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ + /* outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); */ + /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ + /* outl(0x00001409, chip->port+HCFG); */ + /* outl(0x00000009, chip->port+HCFG); */ + /* AC97 2.0, Enable outputs. */ + outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); - if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ + if (chip->details->i2c_adc == 1) { + /* The SB0410 and SB0413 use I2C to control ADC. */ int size, n; size = ARRAY_SIZE(i2c_adc_init); - //snd_printk("I2C:array size=0x%x\n", size); - for (n=0; n < size; n++) { - snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]); - } - for (n=0; n < 4; n++) { - chip->i2c_capture_volume[n][0]= 0xcf; - chip->i2c_capture_volume[n][1]= 0xcf; + /* snd_printk("I2C:array size=0x%x\n", size); */ + for (n = 0; n < size; n++) + snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], + i2c_adc_init[n][1]); + for (n = 0; n < 4; n++) { + chip->i2c_capture_volume[n][0] = 0xcf; + chip->i2c_capture_volume[n][1] = 0xcf; } - chip->i2c_capture_source=2; /* Line in */ - //snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ + chip->i2c_capture_source = 2; /* Line in */ + /* Enable Line-in capture. MIC in currently untested. */ + /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */ } - if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */ + + if (chip->details->spi_dac == 1) { + /* The SB0570 use SPI to control DAC. */ int size, n; size = ARRAY_SIZE(spi_dac_init); @@ -1530,9 +1481,112 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, chip->spi_dac_reg[reg] = spi_dac_init[n]; } } +} + +static void ca0106_stop_chip(struct snd_ca0106 *chip) +{ + /* disable interrupts */ + snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); + outl(0, chip->port + INTE); + snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); + udelay(1000); + /* disable audio */ + /* outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); */ + outl(0, chip->port + HCFG); + /* FIXME: We need to stop and DMA transfers here. + * But as I am not sure how yet, we cannot from the dma pages. + * So we can fix: snd-malloc: Memory leak? pages not freed = 8 + */ +} - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, - chip, &ops)) < 0) { +static int __devinit snd_ca0106_create(int dev, struct snd_card *card, + struct pci_dev *pci, + struct snd_ca0106 **rchip) +{ + struct snd_ca0106 *chip; + struct snd_ca0106_details *c; + int err; + static struct snd_device_ops ops = { + .dev_free = snd_ca0106_dev_free, + }; + + *rchip = NULL; + + err = pci_enable_device(pci); + if (err < 0) + return err; + if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || + pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { + printk(KERN_ERR "error to set 32bit mask DMA\n"); + pci_disable_device(pci); + return -ENXIO; + } + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) { + pci_disable_device(pci); + return -ENOMEM; + } + + chip->card = card; + chip->pci = pci; + chip->irq = -1; + + spin_lock_init(&chip->emu_lock); + + chip->port = pci_resource_start(pci, 0); + chip->res_port = request_region(chip->port, 0x20, "snd_ca0106"); + if (!chip->res_port) { + snd_ca0106_free(chip); + printk(KERN_ERR "cannot allocate the port\n"); + return -EBUSY; + } + + if (request_irq(pci->irq, snd_ca0106_interrupt, + IRQF_SHARED, "snd_ca0106", chip)) { + snd_ca0106_free(chip); + printk(KERN_ERR "cannot grab irq\n"); + return -EBUSY; + } + chip->irq = pci->irq; + + /* This stores the periods table. */ + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + 1024, &chip->buffer) < 0) { + snd_ca0106_free(chip); + return -ENOMEM; + } + + pci_set_master(pci); + /* read serial */ + pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); + pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); + printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", + chip->model, pci->revision, chip->serial); + strcpy(card->driver, "CA0106"); + strcpy(card->shortname, "CA0106"); + + for (c = ca0106_chip_details; c->serial; c++) { + if (subsystem[dev]) { + if (c->serial == subsystem[dev]) + break; + } else if (c->serial == chip->serial) + break; + } + chip->details = c; + if (subsystem[dev]) { + printk(KERN_INFO "snd-ca0106: Sound card name=%s, " + "subsystem=0x%x. Forced to subsystem=0x%x\n", + c->name, chip->serial, subsystem[dev]); + } + + sprintf(card->longname, "%s at 0x%lx irq %i", + c->name, chip->port, chip->irq); + + ca0106_init_chip(chip); + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_ca0106_free(chip); return err; } @@ -1629,7 +1683,7 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, static int dev; struct snd_card *card; struct snd_ca0106 *chip; - int err; + int i, err; if (dev >= SNDRV_CARDS) return -ENODEV; @@ -1642,44 +1696,30 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, if (card == NULL) return -ENOMEM; - if ((err = snd_ca0106_create(dev, card, pci, &chip)) < 0) { - snd_card_free(card); - return err; - } + err = snd_ca0106_create(dev, card, pci, &chip); + if (err < 0) + goto error; - if ((err = snd_ca0106_pcm(chip, 0, NULL)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_ca0106_pcm(chip, 1, NULL)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_ca0106_pcm(chip, 2, NULL)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_ca0106_pcm(chip, 3, NULL)) < 0) { - snd_card_free(card); - return err; - } - if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ - if ((err = snd_ca0106_ac97(chip)) < 0) { - snd_card_free(card); - return err; - } + for (i = 0; i < 4; i++) { + err = snd_ca0106_pcm(chip, i); + if (err < 0) + goto error; } - if ((err = snd_ca0106_mixer(chip)) < 0) { - snd_card_free(card); - return err; + + if (chip->details->ac97 == 1) { + /* The SB0410 and SB0413 do not have an AC97 chip. */ + err = snd_ca0106_ac97(chip); + if (err < 0) + goto error; } + err = snd_ca0106_mixer(chip); + if (err < 0) + goto error; snd_printdd("ca0106: probe for MIDI channel A ..."); - if ((err = snd_ca0106_midi(chip,CA0106_MIDI_CHAN_A)) < 0) { - snd_card_free(card); - snd_printdd(" failed, err=0x%x\n",err); - return err; - } + err = snd_ca0106_midi(chip, CA0106_MIDI_CHAN_A); + if (err < 0) + goto error; snd_printdd(" done.\n"); #ifdef CONFIG_PROC_FS @@ -1688,14 +1728,17 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, snd_card_set_dev(card, &pci->dev); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } + err = snd_card_register(card); + if (err < 0) + goto error; pci_set_drvdata(pci, card); dev++; return 0; + + error: + snd_card_free(card); + return err; } static void __devexit snd_ca0106_remove(struct pci_dev *pci) @@ -1704,6 +1747,52 @@ static void __devexit snd_ca0106_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } +#ifdef CONFIG_PM +static int snd_ca0106_suspend(struct pci_dev *pci, pm_message_t state) +{ + struct snd_card *card = pci_get_drvdata(pci); + struct snd_ca0106 *chip = card->private_data; + int i; + + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + for (i = 0; i < 4; i++) + snd_pcm_suspend_all(chip->pcm[i]); + snd_ac97_suspend(chip->ac97); + snd_ca0106_mixer_suspend(chip); + + ca0106_stop_chip(chip); + + pci_disable_device(pci); + pci_save_state(pci); + pci_set_power_state(pci, pci_choose_state(pci, state)); + return 0; +} + +static int snd_ca0106_resume(struct pci_dev *pci) +{ + struct snd_card *card = pci_get_drvdata(pci); + struct snd_ca0106 *chip = card->private_data; + int i; + + pci_set_power_state(pci, PCI_D0); + pci_restore_state(pci); + pci_enable_device(pci); + pci_set_master(pci); + + ca0106_init_chip(chip); + + snd_ac97_resume(chip->ac97); + snd_ca0106_mixer_resume(chip); + if (chip->details->spi_dac) { + for (i = 0; i < ARRAY_SIZE(chip->spi_dac_reg); i++) + snd_ca0106_spi_write(chip, chip->spi_dac_reg[i]); + } + + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + return 0; +} +#endif + // PCI IDs static struct pci_device_id snd_ca0106_ids[] = { { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Audigy LS or Live 24bit */ @@ -1717,6 +1806,10 @@ static struct pci_driver driver = { .id_table = snd_ca0106_ids, .probe = snd_ca0106_probe, .remove = __devexit_p(snd_ca0106_remove), +#ifdef CONFIG_PM + .suspend = snd_ca0106_suspend, + .resume = snd_ca0106_resume, +#endif }; // initialization of the module diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 3025ed1b6e1e..cccc32cdb943 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -75,6 +75,84 @@ #include "ca0106.h" +static void ca0106_spdif_enable(struct snd_ca0106 *emu) +{ + unsigned int val; + + if (emu->spdif_enable) { + /* Digital */ + snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); + snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); + val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000; + snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); + val = inl(emu->port + GPIO) & ~0x101; + outl(val, emu->port + GPIO); + + } else { + /* Analog */ + snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); + snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); + val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000; + snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); + val = inl(emu->port + GPIO) | 0x101; + outl(val, emu->port + GPIO); + } +} + +static void ca0106_set_capture_source(struct snd_ca0106 *emu) +{ + unsigned int val = emu->capture_source; + unsigned int source, mask; + source = (val << 28) | (val << 24) | (val << 20) | (val << 16); + mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; + snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); +} + +static void ca0106_set_i2c_capture_source(struct snd_ca0106 *emu, + unsigned int val, int force) +{ + unsigned int ngain, ogain; + u32 source; + + snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ + ngain = emu->i2c_capture_volume[val][0]; /* Left */ + ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ + if (force || ngain != ogain) + snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ngain & 0xff); + ngain = emu->i2c_capture_volume[val][1]; /* Right */ + ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ + if (force || ngain != ogain) + snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ngain & 0xff); + source = 1 << val; + snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ + emu->i2c_capture_source = val; +} + +static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu) +{ + u32 tmp; + + if (emu->capture_mic_line_in) { + /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ + tmp = inl(emu->port+GPIO) & ~0x400; + tmp = tmp | 0x400; + outl(tmp, emu->port+GPIO); + /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); */ + } else { + /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ + tmp = inl(emu->port+GPIO) & ~0x400; + outl(tmp, emu->port+GPIO); + /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); */ + } +} + +static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx) +{ + snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_bits[idx]); +} + +/* + */ static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); @@ -95,30 +173,12 @@ static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int val; int change = 0; - u32 mask; val = !!ucontrol->value.integer.value[0]; change = (emu->spdif_enable != val); if (change) { emu->spdif_enable = val; - if (val) { - /* Digital */ - snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); - snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); - snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, - snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000); - mask = inl(emu->port + GPIO) & ~0x101; - outl(mask, emu->port + GPIO); - - } else { - /* Analog */ - snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); - snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); - snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, - snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000); - mask = inl(emu->port + GPIO) | 0x101; - outl(mask, emu->port + GPIO); - } + ca0106_spdif_enable(emu); } return change; } @@ -154,8 +214,6 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol, struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int val; int change = 0; - u32 mask; - u32 source; val = ucontrol->value.enumerated.item[0] ; if (val >= 6) @@ -163,9 +221,7 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol, change = (emu->capture_source != val); if (change) { emu->capture_source = val; - source = (val << 28) | (val << 24) | (val << 20) | (val << 16); - mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; - snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); + ca0106_set_capture_source(emu); } return change; } @@ -200,9 +256,7 @@ static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol, { struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int source_id; - unsigned int ngain, ogain; int change = 0; - u32 source; /* If the capture source has changed, * update the capture volume from the cached value * for the particular source. @@ -212,18 +266,7 @@ static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol, return -EINVAL; change = (emu->i2c_capture_source != source_id); if (change) { - snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ - ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ - ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ - if (ngain != ogain) - snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); - ngain = emu->i2c_capture_volume[source_id][1]; /* Left */ - ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */ - if (ngain != ogain) - snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); - source = 1 << source_id; - snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ - emu->i2c_capture_source = source_id; + ca0106_set_i2c_capture_source(emu, source_id, 0); } return change; } @@ -271,7 +314,6 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int val; int change = 0; - u32 tmp; val = ucontrol->value.enumerated.item[0] ; if (val > 1) @@ -279,18 +321,7 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, change = (emu->capture_mic_line_in != val); if (change) { emu->capture_mic_line_in = val; - if (val) { - //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ - tmp = inl(emu->port+GPIO) & ~0x400; - tmp = tmp | 0x400; - outl(tmp, emu->port+GPIO); - //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); - } else { - //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ - tmp = inl(emu->port+GPIO) & ~0x400; - outl(tmp, emu->port+GPIO); - //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); - } + ca0106_set_capture_mic_line_in(emu); } return change; } @@ -359,8 +390,8 @@ static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol, (ucontrol->value.iec958.status[3] << 24); change = val != emu->spdif_bits[idx]; if (change) { - snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, val); emu->spdif_bits[idx] = val; + ca0106_set_spdif_bits(emu, idx); } return change; } @@ -773,3 +804,50 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) return 0; } +#ifdef CONFIG_PM +struct ca0106_vol_tbl { + unsigned int reg; + unsigned int channel_id; +}; + +static struct ca0106_vol_tbl saved_volumes[NUM_SAVED_VOLUMES] = { + { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2 }, + { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2 }, + { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2 }, + { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2 }, + { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1 }, + { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1 }, + { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1 }, + { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1 }, + { 1, CAPTURE_CONTROL }, +}; + +void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip) +{ + int i; + + /* save volumes */ + for (i = 0; i < NUM_SAVED_VOLUMES; i++) + chip->saved_vol[i] = + snd_ca0106_ptr_read(chip, saved_volumes[i].reg, + saved_volumes[i].channel_id); +} + +void snd_ca0106_mixer_resume(struct snd_ca0106 *chip) +{ + int i; + + for (i = 0; i < NUM_SAVED_VOLUMES; i++) + snd_ca0106_ptr_write(chip, saved_volumes[i].reg, + saved_volumes[i].channel_id, + chip->saved_vol[i]); + + ca0106_spdif_enable(chip); + ca0106_set_capture_source(chip); + ca0106_set_i2c_capture_source(chip, chip->i2c_capture_source, 1); + for (i = 0; i < 4; i++) + ca0106_set_spdif_bits(chip, i); + if (chip->details->i2c_adc) + ca0106_set_capture_mic_line_in(chip); +} +#endif /* CONFIG_PM */ -- 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index f98c7e997877..08170dff75e0 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 08170dff75e0..4c851fd55565 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 35722ec920cb..a06b0538fc90 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 44411e07c2ce1a755a756e10b592cd3ba02f99b3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2008 08:27:19 +0100 Subject: ALSA: ca0106 - Check return value of pci_enable_device() in resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The return value of pci_enable_device() must be checked even in resume callback: sound/pci/ca0106/ca0106_main.c:1779: warning: ignoring return value of ‘pci_enable_device’, declared with attribute warn_unused_result Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index cea8a7cdb1d5..c13aa41a35b4 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1776,7 +1776,12 @@ static int snd_ca0106_resume(struct pci_dev *pci) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); - pci_enable_device(pci); + + if (pci_enable_device(pci) < 0) { + snd_card_disconnect(card); + return -EIO; + } + pci_set_master(pci); ca0106_init_chip(chip); -- 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index c1918a1a6df9..26247cfe749d 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 0bed7b292d68f82316bfb8cd521e16c867689efe Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 5 Nov 2008 17:29:53 -0500 Subject: ALSA: cs5535audio: stick AD1888 bitshift values into a header file We'd like to use the High Pass Filter and V_REFOUT bitshift values elsewhere, so stick them into a ac97_codec.h. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_patch.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 6e831aff1bd0..7ad25f439b50 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -2054,8 +2054,9 @@ static const struct snd_kcontrol_new snd_ac97_ad1888_controls[] = { .get = snd_ac97_ad1888_lohpsel_get, .put = snd_ac97_ad1888_lohpsel_put }, - AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, 2, 1, 1), - AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1), + AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, AC97_AD_VREFD_SHIFT, 1, 1), + AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, + AC97_AD_HPFD_SHIFT, 1, 1), AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -- cgit v1.2.3 From b035ce0f26812292d067fbe2fc9e9d88d5dfcdb4 Mon Sep 17 00:00:00 2001 From: Jaya Kumar Date: Wed, 5 Nov 2008 17:30:08 -0500 Subject: ALSA: cs5535audio: turn off PCM properly if closing the audio device As per , we need to properly turn off the PCM if we're closing the device in order to save power. This also causes the MIC led to turn off properly. Signed-off-by: Jaya Kumar Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio.c | 3 ++- sound/pci/cs5535audio/cs5535audio.h | 1 + sound/pci/cs5535audio/cs5535audio_pcm.c | 12 ++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 1d8b16052535..6c886edd06db 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -159,7 +159,8 @@ static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au) return err; memset(&ac97, 0, sizeof(ac97)); - ac97.scaps = AC97_SCAP_AUDIO|AC97_SCAP_SKIP_MODEM; + ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM + | AC97_SCAP_POWER_SAVE; ac97.private_data = cs5535au; ac97.pci = cs5535au->pci; diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 66bae7664193..57e9c65e6854 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -78,6 +78,7 @@ struct cs5535audio_dma { unsigned int buf_addr, buf_bytes; unsigned int period_bytes, periods; u32 saved_prd; + int pcm_open_flag; }; struct cs5535audio { diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index cdcda87116c3..6aa0c19390d7 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -260,6 +260,9 @@ static int snd_cs5535audio_hw_params(struct snd_pcm_substream *substream, err = cs5535audio_build_dma_packets(cs5535au, dma, substream, params_periods(hw_params), params_period_bytes(hw_params)); + if (!err) + dma->pcm_open_flag = 1; + return err; } @@ -268,6 +271,15 @@ static int snd_cs5535audio_hw_free(struct snd_pcm_substream *substream) struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream); struct cs5535audio_dma *dma = substream->runtime->private_data; + if (dma->pcm_open_flag) { + if (substream == cs5535au->playback_substream) + snd_ac97_update_power(cs5535au->ac97, + AC97_PCM_FRONT_DAC_RATE, 0); + else + snd_ac97_update_power(cs5535au->ac97, + AC97_PCM_LR_ADC_RATE, 0); + dma->pcm_open_flag = 0; + } cs5535audio_clear_dma_packets(cs5535au, dma, substream); return snd_pcm_lib_free_pages(substream); } -- cgit v1.2.3 From b6c52a2cdb58fca918eef9ada5ef3a6cd17a9240 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 5 Nov 2008 17:30:30 -0500 Subject: ALSA: cs5535audio: suspend/resume callbacks are only defined with CONFIG_PM snd_cs5535audio_suspend and snd_cs5535audio_resume are only defined when CONFIG_PM is set; make that clear in the header file. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 57e9c65e6854..1aa1e2bbdf74 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -94,8 +94,11 @@ struct cs5535audio { struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS]; }; +#ifdef CONFIG_PM int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state); int snd_cs5535audio_resume(struct pci_dev *pci); +#endif + int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); #endif /* __SOUND_CS5535AUDIO_H */ -- cgit v1.2.3 From 57d4bf6d8e965404b82b105ae44ddf137bb7b8e6 Mon Sep 17 00:00:00 2001 From: Jaya Kumar Date: Thu, 6 Nov 2008 16:43:34 -0500 Subject: ALSA: cs5535audio: OLPC analog input support This is a 2nd cut at adding support for OLPC analog input. Signed-off-by: Jaya Kumar Signed-off-by: Andres Salomon --- sound/pci/cs5535audio/Makefile | 4 ++ sound/pci/cs5535audio/cs5535audio.c | 7 ++ sound/pci/cs5535audio/cs5535audio.h | 9 +++ sound/pci/cs5535audio/cs5535audio_olpc.c | 113 +++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+) create mode 100644 sound/pci/cs5535audio/cs5535audio_olpc.c (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile index bb3d57e6a3cb..3e41fd39780d 100644 --- a/sound/pci/cs5535audio/Makefile +++ b/sound/pci/cs5535audio/Makefile @@ -5,5 +5,9 @@ snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o +ifdef CONFIG_OLPC +snd-cs5535audio-objs += cs5535audio_olpc.o +endif + # Toplevel Module Dependency obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 6c886edd06db..50333bb9242c 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -171,6 +171,13 @@ static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au) snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk); + /* olpc_quirks is dummied out if not olpc */ + err = olpc_quirks(card, cs5535au->ac97); + if (err < 0) { + snd_printk(KERN_ERR "olpc quirks failed\n"); + return err; + } + return 0; } diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 1aa1e2bbdf74..adcb213eb276 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -92,6 +92,9 @@ struct cs5535audio { struct snd_pcm_substream *playback_substream; struct snd_pcm_substream *capture_substream; struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS]; +#ifdef CONFIG_OLPC + int ec_analog_input_mode; +#endif }; #ifdef CONFIG_PM @@ -99,6 +102,12 @@ int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state); int snd_cs5535audio_resume(struct pci_dev *pci); #endif +#ifdef CONFIG_OLPC +int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97); +#else +#define olpc_quirks(arg, arg2) (0) +#endif + int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); #endif /* __SOUND_CS5535AUDIO_H */ diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c new file mode 100644 index 000000000000..4b72d8662ec9 --- /dev/null +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include +#include +#include "cs5535audio.h" + +/* OLPC has an additional feature on top of regular AD1888 codec +features. This is support for an analog input mode. This is a +2 step process. First, to turn off the AD1888 codec bias voltage +and high pass filter. Second, to tell the embedded controller to +reroute from a capacitive trace to a direct trace using an analog +switch. The *_ec()s are what talk to that controller */ + +static int snd_cs5535audio_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +#define AD1888_VREFOUT_EN_BIT (1 << 2) +#define AD1888_HPF_EN_BIT (1 << 12) +static int snd_cs5535audio_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol); + u16 reg1, reg2; + + /* if either AD1888 VRef Bias and High Pass Filter are enabled + or the EC is not in analog mode then flag as not in analog mode. + No EC command to read current analog state so we cache that. */ + reg1 = snd_ac97_read(cs5535au->ac97, AC97_AD_MISC); + reg2 = snd_ac97_read(cs5535au->ac97, AC97_AD_TEST2); + + if ((reg1 & AD1888_VREFOUT_EN_BIT) && (reg2 & AD1888_HPF_EN_BIT) && + cs5535au->ec_analog_input_mode) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int err; + struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol); + u8 value; + struct snd_ac97 *ac97 = cs5535au->ac97; + + /* value is 1 if analog input is desired */ + value = ucontrol->value.integer.value[0]; + + /* use ec mode as flag to determine if any change needed */ + if (cs5535au->ec_analog_input_mode == value) + return 0; + + /* sets High Z on VREF Bias if 1 */ + if (value) + err = snd_ac97_update_bits(ac97, AC97_AD_MISC, + AD1888_VREFOUT_EN_BIT, AD1888_VREFOUT_EN_BIT); + else + err = snd_ac97_update_bits(ac97, AC97_AD_MISC, + AD1888_VREFOUT_EN_BIT, 0); + if (err < 0) + snd_printk(KERN_ERR "Error updating AD_MISC %d\n", err); + + /* turns off High Pass Filter if 1 */ + if (value) + err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, + AD1888_HPF_EN_BIT, AD1888_HPF_EN_BIT); + else + err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, + AD1888_HPF_EN_BIT, 0); + if (err < 0) + snd_printk(KERN_ERR "Error updating AD_TEST2 %d\n", err); + + if (value) + err = write_ec_command(0x01); /* activate MIC_AC_OFF */ + else + err = write_ec_command(0x02); /* deactivates MIC_AC_OFF */ + + if (err < 0) + snd_printk(KERN_ERR "Error talking to EC %d\n", err); + + cs5535au->ec_analog_input_mode = value; + + return 1; +} + +static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Input Switch", + .info = snd_cs5535audio_ctl_info, + .get = snd_cs5535audio_ctl_get, + .put = snd_cs5535audio_ctl_put, + .private_value = 0 +}; + +int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) +{ + /* setup callback for mixer control that does analog input mode */ + return snd_ctl_add(card, snd_ctl_new1(&snd_cs5535audio_controls, + ac97->private_data)); +} + -- cgit v1.2.3 From c8974be5465b87414fa542cf9cca1a1ba21b8d60 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Thu, 6 Nov 2008 16:43:53 -0500 Subject: ALSA: cs5535audio: Use OLPC/Geode basic infrastructure Use basic infrastructure code; geode_gpio* (rather than indexed i/o EC access), and do an OLPC machine check in olpc_quirk. [dilinger@debian.org: don't return failure in olpc_quirks if !OLPC] [dilinger@debian.org: drop the Signed-off-by: Andres Salomon --- sound/pci/cs5535audio/cs5535audio_olpc.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 4b72d8662ec9..9073fb353f0e 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -1,9 +1,10 @@ -#include #include #include #include #include #include + +#include #include "cs5535audio.h" /* OLPC has an additional feature on top of regular AD1888 codec @@ -81,13 +82,11 @@ static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol, if (err < 0) snd_printk(KERN_ERR "Error updating AD_TEST2 %d\n", err); + /* B2 and newer writes directly to a GPIO pin */ if (value) - err = write_ec_command(0x01); /* activate MIC_AC_OFF */ + geode_gpio_set(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); else - err = write_ec_command(0x02); /* deactivates MIC_AC_OFF */ - - if (err < 0) - snd_printk(KERN_ERR "Error talking to EC %d\n", err); + geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); cs5535au->ec_analog_input_mode = value; @@ -106,6 +105,9 @@ static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata = int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) { + if (!machine_is_olpc()) + return 0; + /* setup callback for mixer control that does analog input mode */ return snd_ctl_add(card, snd_ctl_new1(&snd_cs5535audio_controls, ac97->private_data)); -- cgit v1.2.3 From 3556d18465c6e67c7a8f436428b95671add02f57 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:44:08 -0500 Subject: ALSA: cs5535audio: invert EAPD for OLPC (newer than B3) Fix an audible pop described in . Originally based upon fixes by Mitch Bradley and Chris Ball. Signed-off-by: Andres Salomon --- sound/pci/cs5535audio/cs5535audio.c | 3 +++ sound/pci/cs5535audio/cs5535audio.h | 11 +++++++++-- sound/pci/cs5535audio/cs5535audio_olpc.c | 11 +++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 50333bb9242c..130f10a8d524 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -164,6 +164,9 @@ static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au) ac97.private_data = cs5535au; ac97.pci = cs5535au->pci; + /* set any OLPC-specific scaps */ + olpc_prequirks(card, &ac97); + if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) { snd_printk(KERN_ERR "mixer failed\n"); return err; diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index adcb213eb276..93602cf2858a 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -103,9 +103,16 @@ int snd_cs5535audio_resume(struct pci_dev *pci); #endif #ifdef CONFIG_OLPC -int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97); +void __devinit olpc_prequirks(struct snd_card *card, + struct snd_ac97_template *ac97); +int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97); #else -#define olpc_quirks(arg, arg2) (0) +static inline void olpc_prequirks(struct snd_card *card, + struct snd_ac97_template *ac97) { } +static inline int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) +{ + return 0; +} #endif int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 9073fb353f0e..ff7b68ba6179 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -103,6 +103,17 @@ static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata = .private_value = 0 }; +void __devinit olpc_prequirks(struct snd_card *card, + struct snd_ac97_template *ac97) +{ + if (!machine_is_olpc()) + return; + + /* invert EAPD if on an OLPC B3 or higher */ + if (olpc_board_at_least(olpc_board_pre(0xb3))) + ac97->scaps |= AC97_SCAP_INV_EAPD; +} + int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) { if (!machine_is_olpc()) -- cgit v1.2.3 From b91254e75c3ec4f371ce1849672a95a929d99861 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:46:31 -0500 Subject: ALSA: cs5535audio: drop ec_analog_input flag for OLPC stuff This is no longer necessary, as we're no longer doing indexed i/o commands. Signed-off-by: Andres Salomon --- sound/pci/cs5535audio/cs5535audio.h | 3 --- sound/pci/cs5535audio/cs5535audio_olpc.c | 9 +-------- 2 files changed, 1 insertion(+), 11 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 93602cf2858a..31ecb33ffff9 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -92,9 +92,6 @@ struct cs5535audio { struct snd_pcm_substream *playback_substream; struct snd_pcm_substream *capture_substream; struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS]; -#ifdef CONFIG_OLPC - int ec_analog_input_mode; -#endif }; #ifdef CONFIG_PM diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index ff7b68ba6179..2bd6588b4353 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -38,8 +38,7 @@ static int snd_cs5535audio_ctl_get(struct snd_kcontrol *kcontrol, reg1 = snd_ac97_read(cs5535au->ac97, AC97_AD_MISC); reg2 = snd_ac97_read(cs5535au->ac97, AC97_AD_TEST2); - if ((reg1 & AD1888_VREFOUT_EN_BIT) && (reg2 & AD1888_HPF_EN_BIT) && - cs5535au->ec_analog_input_mode) + if ((reg1 & AD1888_VREFOUT_EN_BIT) && (reg2 & AD1888_HPF_EN_BIT)) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; @@ -58,10 +57,6 @@ static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol, /* value is 1 if analog input is desired */ value = ucontrol->value.integer.value[0]; - /* use ec mode as flag to determine if any change needed */ - if (cs5535au->ec_analog_input_mode == value) - return 0; - /* sets High Z on VREF Bias if 1 */ if (value) err = snd_ac97_update_bits(ac97, AC97_AD_MISC, @@ -88,8 +83,6 @@ static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol, else geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); - cs5535au->ec_analog_input_mode = value; - return 1; } -- cgit v1.2.3 From 1e2232bc70b32f90109d678d1faccf6f50ebba80 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:47:05 -0500 Subject: ALSA: cs5535audio: decouple HPF from V_REFOUT in OLPC code We shouldn't be touching V_REFOUT when we toggle HPF/analog input, so just drop that code. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio_olpc.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 2bd6588b4353..f20e74182725 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -30,18 +30,11 @@ static int snd_cs5535audio_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol); - u16 reg1, reg2; + u8 val; - /* if either AD1888 VRef Bias and High Pass Filter are enabled - or the EC is not in analog mode then flag as not in analog mode. - No EC command to read current analog state so we cache that. */ - reg1 = snd_ac97_read(cs5535au->ac97, AC97_AD_MISC); - reg2 = snd_ac97_read(cs5535au->ac97, AC97_AD_TEST2); - - if ((reg1 & AD1888_VREFOUT_EN_BIT) && (reg2 & AD1888_HPF_EN_BIT)) - ucontrol->value.integer.value[0] = 1; - else - ucontrol->value.integer.value[0] = 0; + val = snd_ac97_read(cs5535au->ac97, AC97_AD_TEST2); + val >>= AC97_AD_HPFD_SHIFT; + ucontrol->value.integer.value[0] = val & 0x1; return 0; } @@ -57,16 +50,6 @@ static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol, /* value is 1 if analog input is desired */ value = ucontrol->value.integer.value[0]; - /* sets High Z on VREF Bias if 1 */ - if (value) - err = snd_ac97_update_bits(ac97, AC97_AD_MISC, - AD1888_VREFOUT_EN_BIT, AD1888_VREFOUT_EN_BIT); - else - err = snd_ac97_update_bits(ac97, AC97_AD_MISC, - AD1888_VREFOUT_EN_BIT, 0); - if (err < 0) - snd_printk(KERN_ERR "Error updating AD_MISC %d\n", err); - /* turns off High Pass Filter if 1 */ if (value) err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, -- cgit v1.2.3 From d6276b78028dfab944dd4a58124aefcc9aa580da Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:49:38 -0500 Subject: ALSA: cs5535audio: create function for setting OLPC's Analog Input mode Clean this stuff up a bit.. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio.h | 2 ++ sound/pci/cs5535audio/cs5535audio_olpc.c | 54 ++++++++++++++------------------ 2 files changed, 26 insertions(+), 30 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 31ecb33ffff9..22737fc9ed03 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -103,6 +103,7 @@ int snd_cs5535audio_resume(struct pci_dev *pci); void __devinit olpc_prequirks(struct snd_card *card, struct snd_ac97_template *ac97); int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97); +void olpc_analog_input(struct snd_ac97 *ac97, int on); #else static inline void olpc_prequirks(struct snd_card *card, struct snd_ac97_template *ac97) { } @@ -110,6 +111,7 @@ static inline int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) { return 0; } +static inline void olpc_analog_input(struct snd_ac97 *ac97, int on) { } #endif int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index f20e74182725..597395e6e358 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -7,12 +7,29 @@ #include #include "cs5535audio.h" -/* OLPC has an additional feature on top of regular AD1888 codec -features. This is support for an analog input mode. This is a -2 step process. First, to turn off the AD1888 codec bias voltage -and high pass filter. Second, to tell the embedded controller to -reroute from a capacitive trace to a direct trace using an analog -switch. The *_ec()s are what talk to that controller */ +/* + * OLPC has an additional feature on top of the regular AD1888 codec features. + * It has an Analog Input mode that is switched into (after disabling the + * High Pass Filter) via GPIO. It is supported on B2 and later models. + */ +void olpc_analog_input(struct snd_ac97 *ac97, int on) +{ + int err; + + /* update the High Pass Filter (via AC97_AD_TEST2) */ + err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, + 1 << AC97_AD_HPFD_SHIFT, on << AC97_AD_HPFD_SHIFT); + if (err < 0) { + snd_printk(KERN_ERR "setting High Pass Filter - %d\n", err); + return; + } + + /* set Analog Input through GPIO */ + if (on) + geode_gpio_set(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); + else + geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); +} static int snd_cs5535audio_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -24,8 +41,6 @@ static int snd_cs5535audio_ctl_info(struct snd_kcontrol *kcontrol, return 0; } -#define AD1888_VREFOUT_EN_BIT (1 << 2) -#define AD1888_HPF_EN_BIT (1 << 12) static int snd_cs5535audio_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -42,30 +57,9 @@ static int snd_cs5535audio_ctl_get(struct snd_kcontrol *kcontrol, static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - int err; struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol); - u8 value; - struct snd_ac97 *ac97 = cs5535au->ac97; - - /* value is 1 if analog input is desired */ - value = ucontrol->value.integer.value[0]; - - /* turns off High Pass Filter if 1 */ - if (value) - err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, - AD1888_HPF_EN_BIT, AD1888_HPF_EN_BIT); - else - err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, - AD1888_HPF_EN_BIT, 0); - if (err < 0) - snd_printk(KERN_ERR "Error updating AD_TEST2 %d\n", err); - - /* B2 and newer writes directly to a GPIO pin */ - if (value) - geode_gpio_set(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); - else - geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); + olpc_analog_input(cs5535au->ac97, ucontrol->value.integer.value[0]); return 1; } -- cgit v1.2.3 From 466ae3055be8665525a5613456fcb387ffef4cb7 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:49:46 -0500 Subject: ALSA: cs5535audio: rename OLPC's analog input control && drop AD1888's HPF Previously, we had two separate controls; there's no need to have AD1888's HPF control, so drop it if we're on an OLPC machine. Also, as per Arjun's request, rename OLPC's Analog Input Switch control to "DC Mode Enable". Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio_olpc.c | 36 +++++++++++++++++++------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 597395e6e358..6c0c0dbeb218 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -31,8 +31,8 @@ void olpc_analog_input(struct snd_ac97 *ac97, int on) geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); } -static int snd_cs5535audio_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +static int olpc_dc_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; @@ -41,35 +41,33 @@ static int snd_cs5535audio_ctl_info(struct snd_kcontrol *kcontrol, return 0; } -static int snd_cs5535audio_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int olpc_dc_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) { - struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol); + struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl); u8 val; val = snd_ac97_read(cs5535au->ac97, AC97_AD_TEST2); val >>= AC97_AD_HPFD_SHIFT; - ucontrol->value.integer.value[0] = val & 0x1; + v->value.integer.value[0] = val & 0x1; return 0; } -static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int olpc_dc_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) { - struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol); + struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl); - olpc_analog_input(cs5535au->ac97, ucontrol->value.integer.value[0]); + olpc_analog_input(cs5535au->ac97, v->value.integer.value[0]); return 1; } static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Input Switch", - .info = snd_cs5535audio_ctl_info, - .get = snd_cs5535audio_ctl_get, - .put = snd_cs5535audio_ctl_put, + .name = "DC Mode Enable", + .info = olpc_dc_info, + .get = olpc_dc_get, + .put = olpc_dc_put, .private_value = 0 }; @@ -86,10 +84,18 @@ void __devinit olpc_prequirks(struct snd_card *card, int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) { + struct snd_ctl_elem_id elem; + if (!machine_is_olpc()) return 0; - /* setup callback for mixer control that does analog input mode */ + /* drop the original AD1888 HPF control */ + memset(&elem, 0, sizeof(elem)); + elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strncpy(elem.name, "High Pass Filter Enable", sizeof(elem.name)); + snd_ctl_remove_id(card, &elem); + + /* add the override for OLPC's HPF */ return snd_ctl_add(card, snd_ctl_new1(&snd_cs5535audio_controls, ac97->private_data)); } -- cgit v1.2.3 From 189d34e747e9540b70227f6682bd680868d90b10 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:49:55 -0500 Subject: ALSA: cs5535audio: check OLPC's Analog Input status vis GPIO Checking the HPF register is irrelevant; HPF is secondary to the AI mode. Instead, check for Analog Input mode via GPIO. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio_olpc.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 6c0c0dbeb218..7f26cfbc8f52 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -43,13 +43,8 @@ static int olpc_dc_info(struct snd_kcontrol *kctl, static int olpc_dc_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) { - struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl); - u8 val; - - val = snd_ac97_read(cs5535au->ac97, AC97_AD_TEST2); - val >>= AC97_AD_HPFD_SHIFT; - v->value.integer.value[0] = val & 0x1; - + v->value.integer.value[0] = geode_gpio_isset(OLPC_GPIO_MIC_AC, + GPIO_OUTPUT_VAL); return 0; } -- cgit v1.2.3 From e463ae1d13ffe4943bb31f47cc6f24415e55a59a Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Thu, 6 Nov 2008 16:50:09 -0500 Subject: ALSA: cs5535audio: enable OLPC's V_REFOUT bias when recording The OLPC has a privacy light hooked up in series with the microphone's V_Ref bias. We want to activate the bias while we are capturing audio. Signed-off-by: Chris Ball Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio_pcm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 6aa0c19390d7..fa2a6b1b81a6 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -363,11 +363,27 @@ static int snd_cs5535audio_capture_open(struct snd_pcm_substream *substream) if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; + +#ifdef CONFIG_OLPC + /* Enable the V_ref bias only while recording. */ + err = snd_ac97_update_bits(cs5535au->ac97, AC97_AD_MISC, + 1 << AC97_AD_VREFD_SHIFT, 0); + if (err < 0) + snd_printk(KERN_ERR "Error updating AD_MISC %d\n", err); +#endif return 0; } static int snd_cs5535audio_capture_close(struct snd_pcm_substream *substream) { + int err; + struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream); + +#ifdef CONFIG_OLPC + /* Disable V_ref bias. */ + err = snd_ac97_update_bits(cs5535au->ac97, AC97_AD_MISC, + 1 << AC97_AD_VREFD_SHIFT, 1 << AC97_AD_VREFD_SHIFT); +#endif return 0; } -- cgit v1.2.3 From bf1e5278354856ac0260d338961560e720147681 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:53:03 -0500 Subject: ALSA: cs5535audio: rename V_REFOUT control to MIC Bias This drops the AD1888 V_REFOUT control, and replaces it with a MIC Bias Enable control. It also moves the MIC bias enabling into a separate function. Signed-off-by: Andres Salomon --- sound/pci/cs5535audio/cs5535audio.h | 16 +++++++ sound/pci/cs5535audio/cs5535audio_olpc.c | 73 ++++++++++++++++++++++++++++++-- sound/pci/cs5535audio/cs5535audio_pcm.c | 17 +------- 3 files changed, 87 insertions(+), 19 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 22737fc9ed03..63190cd723c6 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -104,6 +104,19 @@ void __devinit olpc_prequirks(struct snd_card *card, struct snd_ac97_template *ac97); int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97); void olpc_analog_input(struct snd_ac97 *ac97, int on); +void olpc_mic_bias(struct snd_ac97 *ac97, int on); + +static inline void olpc_capture_open(struct snd_ac97 *ac97) +{ + /* enable MIC Bias for recording */ + olpc_mic_bias(ac97, 1); +} + +static inline void olpc_capture_close(struct snd_ac97 *ac97) +{ + /* disable the MIC Bias (so the recording LED turns off) */ + olpc_mic_bias(ac97, 0); +} #else static inline void olpc_prequirks(struct snd_card *card, struct snd_ac97_template *ac97) { } @@ -112,6 +125,9 @@ static inline int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) return 0; } static inline void olpc_analog_input(struct snd_ac97 *ac97, int on) { } +static inline void olpc_mic_bias(struct snd_ac97 *ac97, int on) { } +static inline void olpc_capture_open(struct snd_ac97 *ac97) { } +static inline void olpc_capture_close(struct snd_ac97 *ac97) { } #endif int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 7f26cfbc8f52..73811e0e8ac7 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -31,6 +31,20 @@ void olpc_analog_input(struct snd_ac97 *ac97, int on) geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); } +/* + * OLPC XO-1's V_REFOUT is a mic bias enable. + */ +void olpc_mic_bias(struct snd_ac97 *ac97, int on) +{ + int err; + + on = on ? 0 : 1; + err = snd_ac97_update_bits(ac97, AC97_AD_MISC, + 1 << AC97_AD_VREFD_SHIFT, on << AC97_AD_VREFD_SHIFT); + if (err < 0) + snd_printk(KERN_ERR "setting MIC Bias - %d\n", err); +} + static int olpc_dc_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { @@ -56,7 +70,36 @@ static int olpc_dc_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) return 1; } -static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata = +static int olpc_mic_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int olpc_mic_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) +{ + struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl); + struct snd_ac97 *ac97 = cs5535au->ac97; + int i; + + i = (snd_ac97_read(ac97, AC97_AD_MISC) >> AC97_AD_VREFD_SHIFT) & 0x1; + v->value.integer.value[0] = i ? 0 : 1; + return 0; +} + +static int olpc_mic_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) +{ + struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl); + + olpc_mic_bias(cs5535au->ac97, v->value.integer.value[0]); + return 1; +} + +static struct snd_kcontrol_new olpc_cs5535audio_ctls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DC Mode Enable", @@ -64,6 +107,15 @@ static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata = .get = olpc_dc_get, .put = olpc_dc_put, .private_value = 0 +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "MIC Bias Enable", + .info = olpc_mic_info, + .get = olpc_mic_get, + .put = olpc_mic_put, + .private_value = 0, +}, }; void __devinit olpc_prequirks(struct snd_card *card, @@ -80,6 +132,7 @@ void __devinit olpc_prequirks(struct snd_card *card, int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) { struct snd_ctl_elem_id elem; + int i, err; if (!machine_is_olpc()) return 0; @@ -90,8 +143,20 @@ int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) strncpy(elem.name, "High Pass Filter Enable", sizeof(elem.name)); snd_ctl_remove_id(card, &elem); - /* add the override for OLPC's HPF */ - return snd_ctl_add(card, snd_ctl_new1(&snd_cs5535audio_controls, - ac97->private_data)); + /* drop the original V_REFOUT control */ + memset(&elem, 0, sizeof(elem)); + elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strncpy(elem.name, "V_REFOUT Enable", sizeof(elem.name)); + snd_ctl_remove_id(card, &elem); + + /* add the OLPC-specific controls */ + for (i = 0; i < ARRAY_SIZE(olpc_cs5535audio_ctls); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&olpc_cs5535audio_ctls[i], + ac97->private_data)); + if (err < 0) + return err; + } + + return 0; } diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index fa2a6b1b81a6..0f48a871f17b 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -363,27 +363,14 @@ static int snd_cs5535audio_capture_open(struct snd_pcm_substream *substream) if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; - -#ifdef CONFIG_OLPC - /* Enable the V_ref bias only while recording. */ - err = snd_ac97_update_bits(cs5535au->ac97, AC97_AD_MISC, - 1 << AC97_AD_VREFD_SHIFT, 0); - if (err < 0) - snd_printk(KERN_ERR "Error updating AD_MISC %d\n", err); -#endif + olpc_capture_open(cs5535au->ac97); return 0; } static int snd_cs5535audio_capture_close(struct snd_pcm_substream *substream) { - int err; struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream); - -#ifdef CONFIG_OLPC - /* Disable V_ref bias. */ - err = snd_ac97_update_bits(cs5535au->ac97, AC97_AD_MISC, - 1 << AC97_AD_VREFD_SHIFT, 1 << AC97_AD_VREFD_SHIFT); -#endif + olpc_capture_close(cs5535au->ac97); return 0; } -- cgit v1.2.3 From 01da02419da827742acd5235467f493206e83574 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:53:11 -0500 Subject: ALSA: cs5535audio: for OLPC, default to Analog Input being off Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 63190cd723c6..777703717a70 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -108,12 +108,16 @@ void olpc_mic_bias(struct snd_ac97 *ac97, int on); static inline void olpc_capture_open(struct snd_ac97 *ac97) { + /* default to Analog Input off */ + olpc_analog_input(ac97, 0); /* enable MIC Bias for recording */ olpc_mic_bias(ac97, 1); } static inline void olpc_capture_close(struct snd_ac97 *ac97) { + /* disable Analog Input */ + olpc_analog_input(ac97, 0); /* disable the MIC Bias (so the recording LED turns off) */ olpc_mic_bias(ac97, 0); } -- cgit v1.2.3 From c8f0eeebc119c401202bc2794bec026d6cfd062e Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:53:19 -0500 Subject: ALSA: cs5535audio: turn off mic bias on OLPCs by default Always turn off mic bias; the MIC LED should never come on when the driver is first loaded. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio_olpc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 73811e0e8ac7..45b24f718d62 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -157,6 +157,8 @@ int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) return err; } + /* turn off the mic by default */ + olpc_mic_bias(ac97, 0); return 0; } -- cgit v1.2.3 From b5ccc57b06b54058879ab3ea548625d9bf88c7fc Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:53:26 -0500 Subject: ALSA: cs5535audio: clean up OLPC code - add copyright info to _olpc.c - minor layout fixes - make Makefile more concise - silence a warning Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/Makefile | 5 +---- sound/pci/cs5535audio/cs5535audio.c | 1 - sound/pci/cs5535audio/cs5535audio_olpc.c | 15 ++++++++++++--- 3 files changed, 13 insertions(+), 8 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile index 3e41fd39780d..ccc642269b9e 100644 --- a/sound/pci/cs5535audio/Makefile +++ b/sound/pci/cs5535audio/Makefile @@ -4,10 +4,7 @@ snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o - -ifdef CONFIG_OLPC -snd-cs5535audio-objs += cs5535audio_olpc.o -endif +snd-cs5535audio-$(CONFIG_OLPC) += cs5535audio_olpc.o # Toplevel Module Dependency obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 130f10a8d524..826e6dec2e97 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -174,7 +174,6 @@ static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au) snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk); - /* olpc_quirks is dummied out if not olpc */ err = olpc_quirks(card, cs5535au->ac97); if (err < 0) { snd_printk(KERN_ERR "olpc quirks failed\n"); diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 45b24f718d62..164f6bdab991 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -1,4 +1,14 @@ -#include +/* + * OLPC XO-1 additional sound features + * + * Copyright © 2006 Jaya Kumar + * Copyright © 2007-2008 Andres Salomon + * + * 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. + */ #include #include #include @@ -106,7 +116,7 @@ static struct snd_kcontrol_new olpc_cs5535audio_ctls[] __devinitdata = { .info = olpc_dc_info, .get = olpc_dc_get, .put = olpc_dc_put, - .private_value = 0 + .private_value = 0, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -161,4 +171,3 @@ int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) olpc_mic_bias(ac97, 0); return 0; } - -- cgit v1.2.3 From 0fb497f5b6ff8da1e9e60afb39835f40d7f043ec Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:53:34 -0500 Subject: ALSA: cs5535audio: ensure MIC Bias/Analog Input bail if not on an OLPC machine Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio_olpc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 164f6bdab991..5c6814335cd7 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -26,6 +26,9 @@ void olpc_analog_input(struct snd_ac97 *ac97, int on) { int err; + if (!machine_is_olpc()) + return; + /* update the High Pass Filter (via AC97_AD_TEST2) */ err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, 1 << AC97_AD_HPFD_SHIFT, on << AC97_AD_HPFD_SHIFT); @@ -48,6 +51,9 @@ void olpc_mic_bias(struct snd_ac97 *ac97, int on) { int err; + if (!machine_is_olpc()) + return; + on = on ? 0 : 1; err = snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << AC97_AD_VREFD_SHIFT, on << AC97_AD_VREFD_SHIFT); -- cgit v1.2.3 From f144b7f6679d9833bd3b94b91e452592b6d0e502 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2008 17:23:24 +0100 Subject: ALSA: cs5535 - Make OLPC-stuff depending on MGEODE_LX The GPIO stuff for OLPC in cs5535audio_olpc.c is implemented only for Geode-LX, and enabled only when CONFIG_MGEODE_LX=y. Without this config option, the driver gets build errors. This patch adds a workaround to make it dependent on CONFIG_MGEODE_LX. Ideally, the OLPC-GPIO stuff should be implemented in a way independent from CPU type selection... Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/Makefile | 2 ++ sound/pci/cs5535audio/cs5535audio.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile index ccc642269b9e..fda7a94c992f 100644 --- a/sound/pci/cs5535audio/Makefile +++ b/sound/pci/cs5535audio/Makefile @@ -4,7 +4,9 @@ snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o +ifdef CONFIG_MGEODE_LX snd-cs5535audio-$(CONFIG_OLPC) += cs5535audio_olpc.o +endif # Toplevel Module Dependency obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 777703717a70..7a298ac662e3 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -99,7 +99,7 @@ int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state); int snd_cs5535audio_resume(struct pci_dev *pci); #endif -#ifdef CONFIG_OLPC +#if defined(CONFIG_OLPC) && defined(CONFIG_MGEODE_LX) void __devinit olpc_prequirks(struct snd_card *card, struct snd_ac97_template *ac97); int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97); -- 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 8aee322313ed..f2337e4eddda 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 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d49d0b698687..f6832e160684 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 0cd53063e62e..0270fda0bda5 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 f649a7145b8b67121e8be0b50f7861755f21aa3b Mon Sep 17 00:00:00 2001 From: Ben Stanley Date: Fri, 12 Dec 2008 09:47:13 +1100 Subject: ALSA: ca0106 Add comments to snd_ca0106_details struct Takashi wrote an email [1] explaining the fields of snd_ca0106_details, so I captured the information into the ca0106.h header file. [1] http://article.gmane.org/gmane.linux.alsa.devel/56783/match=takashi+gpio_type Signed-off-by: Ben Stanley Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 74175fc80c7f..3faccb6ecad9 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -664,10 +664,14 @@ struct snd_ca0106_pcm { struct snd_ca0106_details { u32 serial; char * name; - int ac97; - int gpio_type; - int i2c_adc; - int spi_dac; + int ac97; /* ac97 = 0 -> Select MIC, Line in, TAD in, AUX in. + ac97 = 1 -> Default to AC97 in. */ + int gpio_type; /* gpio_type = 1 -> shared mic-in/line-in + gpio_type = 2 -> shared side-out/line-in. */ + int i2c_adc; /* with i2c_adc=1, the driver adds some capture volume + controls, phone, mic, line-in and aux. */ + int spi_dac; /* spi_dac=1 adds the mute switch for each analog + output, front, rear, etc. */ }; // definition of the chip-specific record -- cgit v1.2.3 From bb1f24bf00a85f666b56a09b7cdbfd221af16c2c Mon Sep 17 00:00:00 2001 From: Ben Stanley Date: Mon, 15 Dec 2008 23:38:12 +1100 Subject: ALSA: ca0106 MSI K8N Diamond MB spi_dac 2->1 This patch removes an inconsistency that became apparent when I documented the fields of snd_ca0106_details. spi_dac is always used in a 'boolean' sense, so this cleanup should make no difference. [Actually, there is one place checking explicitly spi_dac == 1, so this will change the behavior. But, supposing it's rather a typo, I apply this clean-up patch -- tiwai] Signed-off-by: Ben Stanley Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 88fbf285d2b7..6ac19364631b 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -254,7 +254,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = { .name = "MSI K8N Diamond MB", .gpio_type = 2, .i2c_adc = 1, - .spi_dac = 2 } , + .spi_dac = 1 } , /* Shuttle XPC SD31P which has an onboard Creative Labs * Sound Blaster Live! 24-bit EAX * high-definition 7.1 audio processor". -- cgit v1.2.3 From e28d83223a1e5672174dcdc6b73c1be3fa3de877 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 17 Dec 2008 13:48:29 +0100 Subject: ALSA: hda - Fix silent HP output on D975 Some desktops seems to have no HP/mic jack detection on the front panel, which results in the silent output in the recent driver, because the driver mutes the output (to save power) when no plug is detected. This patch adds a new model that disables the jack-detection. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 5dd3e89f620a..d6fa401791c5 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -127,6 +127,7 @@ enum { }; enum { + STAC_D965_REF_NO_JD, /* no jack-detection */ STAC_D965_REF, STAC_D965_3ST, STAC_D965_5ST, @@ -2027,6 +2028,7 @@ static unsigned int dell_3st_pin_configs[14] = { }; static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { + [STAC_D965_REF_NO_JD] = ref927x_pin_configs, [STAC_D965_REF] = ref927x_pin_configs, [STAC_D965_3ST] = d965_3st_pin_configs, [STAC_D965_5ST] = d965_5st_pin_configs, @@ -2035,6 +2037,7 @@ static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { }; static const char *stac927x_models[STAC_927X_MODELS] = { + [STAC_D965_REF_NO_JD] = "ref-no-jd", [STAC_D965_REF] = "ref", [STAC_D965_3ST] = "3stack", [STAC_D965_5ST] = "5stack", @@ -4899,6 +4902,10 @@ static int patch_stac927x(struct hda_codec *codec) */ codec->bus->needs_damn_long_delay = 1; + /* no jack detecion for ref-no-jd model */ + if (spec->board_config == STAC_D965_REF_NO_JD) + spec->hp_detect = 0; + return 0; } -- 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f6832e160684..8459d6ba2055 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 290da562f29b..3564f4e4b74c 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index 5887b827bb32..233e4778bba9 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 6e4d01d1d502..c761394cbe84 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 1f04128a3db7c0f0e8b5d25323eba70ac342f47f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 18 Dec 2008 12:17:55 +0100 Subject: ALSA: hda - Convert from takslet_hi_schedule() to tasklet_schedule() Replace all tasklet_hi_schedule() callers with the normal tasklet_schedule(). The former often causes troubles with RT-kernels, and has actually no merit. Signed-off-by: Takashi Iwai --- sound/pci/es1968.c | 2 +- sound/pci/maestro3.c | 2 +- sound/pci/mixart/mixart_core.c | 2 +- sound/pci/pcxhr/pcxhr.c | 2 +- sound/pci/pcxhr/pcxhr_core.c | 2 +- sound/pci/riptide/riptide.c | 2 +- sound/pci/rme9652/hdsp.c | 2 +- sound/pci/rme9652/hdspm.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 20ee7599600b..e9c3794bbcb8 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -1953,7 +1953,7 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id) outw(inw(chip->io_port + 4) & 1, chip->io_port + 4); if (event & ESM_HWVOL_IRQ) - tasklet_hi_schedule(&chip->hwvol_tq); /* we'll do this later */ + tasklet_schedule(&chip->hwvol_tq); /* we'll do this later */ /* else ack 'em all, i imagine */ outb(0xFF, chip->io_port + 0x1A); diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 9ff3f9e34404..59bbaf8f3e5b 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -1670,7 +1670,7 @@ static irqreturn_t snd_m3_interrupt(int irq, void *dev_id) return IRQ_NONE; if (status & HV_INT_PENDING) - tasklet_hi_schedule(&chip->hwvol_tq); + tasklet_schedule(&chip->hwvol_tq); /* * ack an assp int if its running diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index b9a06c279397..d3350f383966 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c @@ -550,7 +550,7 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg; mgr->msg_fifo_writeptr++; mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE; - tasklet_hi_schedule(&mgr->msg_taskq); + tasklet_schedule(&mgr->msg_taskq); } spin_unlock(&mgr->msg_lock); break; diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 73de6e989b3d..8309d4487722 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -653,7 +653,7 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd) PCXHR_STREAM_STATUS_SCHEDULE_RUN; snd_pcm_trigger_done(s, subs); } - tasklet_hi_schedule(&chip->mgr->trigger_taskq); + tasklet_schedule(&chip->mgr->trigger_taskq); } else { stream = subs->runtime->private_data; snd_printdd("Only one Substream %c %d\n", diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index 7143259cfe34..4a5481f9781f 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -1213,7 +1213,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; mgr->src_it_dsp = reg; - tasklet_hi_schedule(&mgr->msg_taskq); + tasklet_schedule(&mgr->msg_taskq); } #ifdef CONFIG_SND_DEBUG_VERBOSE if (reg & PCXHR_FATAL_DSP_ERR) diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index e9f0706ed3e4..1d0eeb1f506c 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1754,7 +1754,7 @@ snd_riptide_interrupt(int irq, void *dev_id) if (IS_EOBIRQ(cif->hwport) || IS_EOSIRQ(cif->hwport) || IS_EOCIRQ(cif->hwport)) { chip->handled_irqs++; - tasklet_hi_schedule(&chip->riptide_tq); + tasklet_schedule(&chip->riptide_tq); } if (chip->rmidi && IS_MPUIRQ(cif->hwport)) { chip->handled_irqs++; diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 736246f98acc..f87ff0497116 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -3750,7 +3750,7 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id) } } if (hdsp->use_midi_tasklet && schedule) - tasklet_hi_schedule(&hdsp->midi_tasklet); + tasklet_schedule(&hdsp->midi_tasklet); return IRQ_HANDLED; } diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 98762f909d64..d7dd53675ccd 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -3476,7 +3476,7 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) schedule = 1; } if (schedule) - tasklet_hi_schedule(&hdspm->midi_tasklet); + tasklet_schedule(&hdspm->midi_tasklet); return IRQ_HANDLED; } -- cgit v1.2.3 From fa620e97feae731f3d461baaac4da0b127b6fd8e Mon Sep 17 00:00:00 2001 From: Joerg Schirottke Date: Fri, 19 Dec 2008 08:13:49 +0100 Subject: ALSA: hda - Add quirk for Dell Studio 17 Added the matching model=dell-m6 for Dell Studio 17 laptop. Signed-off-by: Joerg Schirottke Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d6fa401791c5..0bb3caecb86c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1641,6 +1641,8 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { "unknown Dell", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x029f, "Dell Studio 1537", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a0, + "Dell Studio 17", STAC_DELL_M6_DMIC), {} /* terminator */ }; -- cgit v1.2.3 From 85f13b673f6a59d29529b2a60b88306c68e7b56c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 08:20:38 +0100 Subject: ALSA: Revert "ALSA: hda: removed unneeded hp_nid references" This reverts commit 07f455f779acfb3eba4921fd1399761559b10fa9. ALSA: hda: removed unneeded hp_nid references Removed unneeded hp_nid references for 92hd73xx codec family. This caused the silent output on some Intel desktops due to missing routing of widget 0x0a and 0x0d. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 0bb3caecb86c..5fcaae676e2a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4259,14 +4259,17 @@ again: switch (spec->multiout.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; }; -- cgit v1.2.3 From 9e43f0de690211cf7153b5f3ec251bc315647ada Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 17 Dec 2008 14:51:01 +0100 Subject: ALSA: hda - Add no-jd model for IDT 92HD73xx Added the model without the jack-detection for some desktops that have really no jack-detection. The recent driver caused regressions regarding the sound output on such machines. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 5fcaae676e2a..d7c622f944f6 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -69,6 +69,7 @@ enum { }; enum { + STAC_92HD73XX_NO_JD, /* no jack-detection */ STAC_92HD73XX_REF, STAC_DELL_M6_AMIC, STAC_DELL_M6_DMIC, @@ -1612,6 +1613,7 @@ static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { }; static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = { + [STAC_92HD73XX_NO_JD] = "no-jd", [STAC_92HD73XX_REF] = "ref", [STAC_DELL_M6_AMIC] = "dell-m6-amic", [STAC_DELL_M6_DMIC] = "dell-m6-dmic", @@ -4359,6 +4361,9 @@ again: return err; } + if (spec->board_config == STAC_92HD73XX_NO_JD) + spec->hp_detect = 0; + codec->patch_ops = stac92xx_patch_ops; return 0; -- 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8459d6ba2055..625fe5984dd6 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 71c3ccfcde16..31662c65e8fd 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 86effd7e12ca63cecfd218717473d606e138e5e1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 12:04:06 +0100 Subject: ALSA: ca0106 - Don't override the values at resume Don't override some values in ca0106_init_chip() at resume. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_main.c | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index c13aa41a35b4..2c71f9b896cd 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1303,9 +1303,10 @@ static unsigned int i2c_adc_init[][2] = { { 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */ }; -static void ca0106_init_chip(struct snd_ca0106 *chip) +static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) { int ch; + unsigned int def_bits; outl(0, chip->port + INTE); @@ -1323,30 +1324,21 @@ static void ca0106_init_chip(struct snd_ca0106 *chip) * AN = 0 (Audio data) * P = 0 (Consumer) */ - chip->spdif_bits[0] = + def_bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; - snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); + if (!resume) { + chip->spdif_bits[0] = def_bits; + chip->spdif_bits[1] = def_bits; + chip->spdif_bits[2] = def_bits; + chip->spdif_bits[3] = def_bits; + } /* Only SPCS1 has been tested */ - chip->spdif_bits[1] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1]); - chip->spdif_bits[2] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; + snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2]); - chip->spdif_bits[3] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3]); snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); @@ -1407,17 +1399,20 @@ static void ca0106_init_chip(struct snd_ca0106 *chip) /* Select MIC, Line in, TAD in, AUX in */ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Default to CAPTURE_SOURCE to i2s in */ - chip->capture_source = 3; + if (!resume) + chip->capture_source = 3; } else if (chip->details->ac97 == 1) { /* Default to AC97 in */ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4); /* Default to CAPTURE_SOURCE to AC97 in */ - chip->capture_source = 4; + if (!resume) + chip->capture_source = 4; } else { /* Select MIC, Line in, TAD in, AUX in */ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Default to Set CAPTURE_SOURCE to i2s in */ - chip->capture_source = 3; + if (!resume) + chip->capture_source = 3; } if (chip->details->gpio_type == 2) { @@ -1583,7 +1578,7 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, sprintf(card->longname, "%s at 0x%lx irq %i", c->name, chip->port, chip->irq); - ca0106_init_chip(chip); + ca0106_init_chip(chip, 0); err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { @@ -1784,7 +1779,7 @@ static int snd_ca0106_resume(struct pci_dev *pci) pci_set_master(pci); - ca0106_init_chip(chip); + ca0106_init_chip(chip, 1); snd_ac97_resume(chip->ac97); snd_ca0106_mixer_resume(chip); -- cgit v1.2.3 From 3d4758299fa6180ff9304634c67ffdd44272c8e8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 12:13:18 +0100 Subject: ALSA: ca0106 - Add IEC958 PCM Stream controls Added "IEC958 PCM Stream" controls for the per-stream IEC958 status bits. Using this instead of "IEC958 Default" is safer since the status bits will be recovered to the default states after closing the PCM stream. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106.h | 3 +- sound/pci/ca0106/ca0106_main.c | 30 +++++++++++---- sound/pci/ca0106/ca0106_mixer.c | 83 ++++++++++++++++++++++++++++++++--------- 3 files changed, 90 insertions(+), 26 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 1c14ff424116..ec0f17ded4e0 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -690,7 +690,8 @@ struct snd_ca0106 { struct snd_ca0106_channel playback_channels[4]; struct snd_ca0106_channel capture_channels[4]; - u32 spdif_bits[4]; /* s/pdif out setup */ + u32 spdif_bits[4]; /* s/pdif out default setup */ + u32 spdif_str_bits[4]; /* s/pdif out per-stream setup */ int spdif_enable; int capture_source; int i2c_capture_source; diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 2c71f9b896cd..c27fd90101d6 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -479,6 +479,15 @@ static const int spi_dacd_bit[] = { [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT, }; +static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) +{ + if (chip->spdif_str_bits[idx] != chip->spdif_bits[idx]) { + chip->spdif_str_bits[idx] = chip->spdif_bits[idx]; + snd_ca0106_ptr_write(chip, SPCS0 + idx, 0, + chip->spdif_str_bits[idx]); + } +} + /* open_playback callback */ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, int channel_id) @@ -524,6 +533,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr if (err < 0) return err; } + + restore_spdif_bits(chip, channel_id); + return 0; } @@ -535,6 +547,8 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream) struct snd_ca0106_pcm *epcm = runtime->private_data; chip->playback_channels[epcm->channel_id].use = 0; + restore_spdif_bits(chip, epcm->channel_id); + if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) { const int reg = spi_dacd_reg[epcm->channel_id]; @@ -1330,16 +1344,16 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; if (!resume) { - chip->spdif_bits[0] = def_bits; - chip->spdif_bits[1] = def_bits; - chip->spdif_bits[2] = def_bits; - chip->spdif_bits[3] = def_bits; + chip->spdif_str_bits[0] = chip->spdif_bits[0] = def_bits; + chip->spdif_str_bits[1] = chip->spdif_bits[1] = def_bits; + chip->spdif_str_bits[2] = chip->spdif_bits[2] = def_bits; + chip->spdif_str_bits[3] = chip->spdif_bits[3] = def_bits; } /* Only SPCS1 has been tested */ - snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1]); - snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); - snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2]); - snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3]); + snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_str_bits[1]); + snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_str_bits[0]); + snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_str_bits[2]); + snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_str_bits[3]); snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index cccc32cdb943..8727881a10b8 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -148,7 +148,7 @@ static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu) static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx) { - snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_bits[idx]); + snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_str_bits[idx]); } /* @@ -353,16 +353,33 @@ static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol, return 0; } -static int snd_ca0106_spdif_get(struct snd_kcontrol *kcontrol, +static void decode_spdif_bits(unsigned char *status, unsigned int bits) +{ + status[0] = (bits >> 0) & 0xff; + status[1] = (bits >> 8) & 0xff; + status[2] = (bits >> 16) & 0xff; + status[3] = (bits >> 24) & 0xff; +} + +static int snd_ca0106_spdif_get_default(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; - ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; - ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; - ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; + decode_spdif_bits(ucontrol->value.iec958.status, + emu->spdif_bits[idx]); + return 0; +} + +static int snd_ca0106_spdif_get_stream(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); + unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + decode_spdif_bits(ucontrol->value.iec958.status, + emu->spdif_str_bits[idx]); return 0; } @@ -376,24 +393,48 @@ static int snd_ca0106_spdif_get_mask(struct snd_kcontrol *kcontrol, return 0; } -static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol, +static unsigned int encode_spdif_bits(unsigned char *status) +{ + return ((unsigned int)status[0] << 0) | + ((unsigned int)status[1] << 8) | + ((unsigned int)status[2] << 16) | + ((unsigned int)status[3] << 24); +} + +static int snd_ca0106_spdif_put_default(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - int change; unsigned int val; - val = (ucontrol->value.iec958.status[0] << 0) | - (ucontrol->value.iec958.status[1] << 8) | - (ucontrol->value.iec958.status[2] << 16) | - (ucontrol->value.iec958.status[3] << 24); - change = val != emu->spdif_bits[idx]; - if (change) { + val = encode_spdif_bits(ucontrol->value.iec958.status); + if (val != emu->spdif_bits[idx]) { emu->spdif_bits[idx] = val; + /* FIXME: this isn't safe, but needed to keep the compatibility + * with older alsa-lib config + */ + emu->spdif_str_bits[idx] = val; ca0106_set_spdif_bits(emu, idx); + return 1; } - return change; + return 0; +} + +static int snd_ca0106_spdif_put_stream(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); + unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + unsigned int val; + + val = encode_spdif_bits(ucontrol->value.iec958.status); + if (val != emu->spdif_str_bits[idx]) { + emu->spdif_str_bits[idx] = val; + ca0106_set_spdif_bits(emu, idx); + return 1; + } + return 0; } static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol, @@ -604,8 +645,16 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), .count = 4, .info = snd_ca0106_spdif_info, - .get = snd_ca0106_spdif_get, - .put = snd_ca0106_spdif_put + .get = snd_ca0106_spdif_get_default, + .put = snd_ca0106_spdif_put_default + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM), + .count = 4, + .info = snd_ca0106_spdif_info, + .get = snd_ca0106_spdif_get_stream, + .put = snd_ca0106_spdif_put_stream }, }; -- cgit v1.2.3 From 8df0f70751dc0e51d0550caee3416339183c5767 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 13:55:17 +0100 Subject: ALSA: ca0106 - Fix typo in resume code The register and channel_id pair were twisted in the pm code... Oh my. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index cccc32cdb943..9845a20f5427 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -806,8 +806,8 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) #ifdef CONFIG_PM struct ca0106_vol_tbl { - unsigned int reg; unsigned int channel_id; + unsigned int reg; }; static struct ca0106_vol_tbl saved_volumes[NUM_SAVED_VOLUMES] = { -- cgit v1.2.3 From 8f55c1e51fbb03998708bdd97d5b6665ab92462d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 14:02:32 +0100 Subject: ALSA: hda - Remove non-working headphone control for Dell laptops The previous commit re-enabled hp_nid setup for IDT92HD73*, but it's unneeded indeed for Dell laptops that have multiple headphones. Setting the extra hp_nid results in a non-working "Headpohne" mixer control. Thus hp_nid should be 0 for these dell models. Also, the automatic addition of hp_nid should check whether it's a dual-HP model or not. For dual-HPs, the pins are already checked by the early workaround. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d7c622f944f6..596ceabd6504 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2903,7 +2903,7 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, } if ((spec->multiout.num_dacs - cfg->line_outs) > 0 && - cfg->hp_outs && !spec->multiout.hp_nid) + 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) { @@ -4307,6 +4307,7 @@ 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) spec->init = dell_m6_core_init; -- 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index b7b419691803..171400216326 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 171400216326..6b7eeba656ed 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 --- sound/pci/hda/hda_codec.c | 12 +++++++----- sound/pci/hda/hda_codec.h | 2 +- sound/pci/hda/hda_intel.c | 11 ++++++++--- 3 files changed, 16 insertions(+), 9 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 625fe5984dd6..e16cf63821ae 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 5587d416229f..729fc7642d7f 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 a26ae8c4cf70..6613b6bef9eb 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6b7eeba656ed..d9a89ced3c89 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d9a89ced3c89..2cadf7c3b71b 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 50232d62cace101e03f8f40ca151b978c0db5a0d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 20 Dec 2008 09:42:09 +0100 Subject: ALSA: ca0106 - Check ac97 availability at PM Check the availability of ac97 at PM suspend/resume callbacks. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 2c71f9b896cd..e01ecd3db324 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1752,7 +1752,8 @@ static int snd_ca0106_suspend(struct pci_dev *pci, pm_message_t state) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < 4; i++) snd_pcm_suspend_all(chip->pcm[i]); - snd_ac97_suspend(chip->ac97); + if (chip->details->ac97) + snd_ac97_suspend(chip->ac97); snd_ca0106_mixer_suspend(chip); ca0106_stop_chip(chip); @@ -1781,7 +1782,8 @@ static int snd_ca0106_resume(struct pci_dev *pci) ca0106_init_chip(chip, 1); - snd_ac97_resume(chip->ac97); + if (chip->details->ac97) + snd_ac97_resume(chip->ac97); snd_ca0106_mixer_resume(chip); if (chip->details->spi_dac) { for (i = 0; i < ARRAY_SIZE(chip->spi_dac_reg); i++) -- cgit v1.2.3 From 72077aa336d0f4c5e3c7014d7471c79bc69873bb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 20 Dec 2008 11:12:51 +0100 Subject: ALSA: ca0106 - Add missing card->private_data initialization Added the missing card->private_data initialization that caused obvious problems at PM. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index e01ecd3db324..7ead6c8a85f1 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1694,6 +1694,7 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, err = snd_ca0106_create(dev, card, pci, &chip); if (err < 0) goto error; + card->private_data = chip; for (i = 0; i < 4; i++) { err = snd_ca0106_pcm(chip, i); -- cgit v1.2.3 From ff75427a7f641c4468610fbda2ccb69218174cd1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 20 Dec 2008 11:20:55 +0100 Subject: ALSA: ca0106 - disable 44.1kHz capture The capture with 44.1kHz on ca0106 seems to cause loud noises on later playbacks, which doesn't support 44.1kHz. A simple fix is to disable 44.1kHz, as the "default" PCM with dsnoop is anyway only with 48kHz. Reference: Novell bnc#447624 https://bugzilla.novell.com/show_bug.cgi?id=447624 Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 88fbf285d2b7..31b5b89fc7bf 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -305,9 +305,15 @@ static struct snd_pcm_hardware snd_ca0106_capture_hw = { SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, +#if 0 /* FIXME: looks like 44.1kHz capture causes noisy output on 48kHz */ .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000), .rate_min = 44100, +#else + .rates = (SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000), + .rate_min = 48000, +#endif /* FIXME */ .rate_max = 192000, .channels_min = 2, .channels_max = 2, -- 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(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 2cadf7c3b71b..e2941cd8aeea 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index e2941cd8aeea..7ee4d4df8932 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(-) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7ee4d4df8932..71d3a773e94b 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 From 574f3c4f5c55e99ea60f71fd98cc54931d4b2eae Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Tue, 23 Dec 2008 16:53:00 -0200 Subject: ALSA: hda - Add missing terminators in patch_sigmatel.c Signed-off-by: Herton Ronaldo Krzesinski Cc: stable@kernel.org Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/pci') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 596ceabd6504..b77f330d2650 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -859,6 +859,7 @@ static struct hda_verb stac92hd83xxx_core_init[] = { /* power state controls amps */ { 0x01, AC_VERB_SET_EAPD, 1 << 2}, + {} }; static struct hda_verb stac92hd71bxx_core_init[] = { @@ -870,6 +871,7 @@ static struct hda_verb stac92hd71bxx_core_init[] = { { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {} }; #define HD_DISABLE_PORTF 2 @@ -1667,6 +1669,7 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD71BXX_REF), + {} /* terminator */ }; static unsigned int ref92hd71bxx_pin_configs[11] = { -- cgit v1.2.3