aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_codec.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-02-12 11:02:41 -0500
committerTakashi Iwai <tiwai@suse.de>2013-02-12 11:09:19 -0500
commitea9b43addc4d90ca5b029f47f85ca152320a1e8d (patch)
tree58c8b75cd440b48d71acea7cafc9e6e8689f9aa1 /sound/pci/hda/hda_codec.c
parent9958922a320d6ee9e9f96b30110bc3765b3e8299 (diff)
ALSA: hda - Fix broken workaround for HDMI/SPDIF conflicts
The commit [dcda58061: ALSA: hda - Add workaround for conflicting IEC958 controls] introduced a workaround for cards that have both SPDIF and HDMI devices for giving device=1 to SPDIF control elements. It turned out, however, that this workaround doesn't work well - - The workaround checks only conflicts in a single codec, but SPDIF and HDMI are provided by multiple codecs in many cases, and - ALSA mixer abstraction doesn't care about the device number in ctl elements, thus you'll get errors from amixer such as % amixer scontrols -c 0 ALSA lib simple_none.c:1551:(simple_add1) helem (MIXER,'IEC958 Playback Switch',0,1,0) appears twice or more amixer: Mixer hw:0 load error: Invalid argument This patch fixes the previous broken workaround. Instead of changing the device number of SPDIF ctl elements, shift the element indices of such controls up to 16. Also, the conflict check is performed over all codecs found on the bus. HDMI devices will be put to dev=0,index=0 as before. Only the conflicting SPDIF device is moved to a different place. The new place of SPDIF device is supposed by the updated alsa-lib HDA-Intel.conf, respectively. Reported-by: Stephan Raue <stephan@openelec.tv> Reported-by: Anssi Hannula <anssi.hannula@iki.fi> Cc: <stable@vger.kernel.org> [v3.8] Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r--sound/pci/hda/hda_codec.c43
1 files changed, 21 insertions, 22 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index e80f83568291..04b57383e8cb 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2332,11 +2332,12 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
2332EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); 2332EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
2333 2333
2334static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name, 2334static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name,
2335 int dev) 2335 int start_idx)
2336{ 2336{
2337 int idx; 2337 int i, idx;
2338 for (idx = 0; idx < 16; idx++) { /* 16 ctlrs should be large enough */ 2338 /* 16 ctlrs should be large enough */
2339 if (!find_mixer_ctl(codec, name, dev, idx)) 2339 for (i = 0, idx = start_idx; i < 16; i++, idx++) {
2340 if (!find_mixer_ctl(codec, name, 0, idx))
2340 return idx; 2341 return idx;
2341 } 2342 }
2342 return -EBUSY; 2343 return -EBUSY;
@@ -3305,30 +3306,29 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
3305 int err; 3306 int err;
3306 struct snd_kcontrol *kctl; 3307 struct snd_kcontrol *kctl;
3307 struct snd_kcontrol_new *dig_mix; 3308 struct snd_kcontrol_new *dig_mix;
3308 int idx, dev = 0; 3309 int idx = 0;
3309 const int spdif_pcm_dev = 1; 3310 const int spdif_index = 16;
3310 struct hda_spdif_out *spdif; 3311 struct hda_spdif_out *spdif;
3312 struct hda_bus *bus = codec->bus;
3311 3313
3312 if (codec->primary_dig_out_type == HDA_PCM_TYPE_HDMI && 3314 if (bus->primary_dig_out_type == HDA_PCM_TYPE_HDMI &&
3313 type == HDA_PCM_TYPE_SPDIF) { 3315 type == HDA_PCM_TYPE_SPDIF) {
3314 dev = spdif_pcm_dev; 3316 idx = spdif_index;
3315 } else if (codec->primary_dig_out_type == HDA_PCM_TYPE_SPDIF && 3317 } else if (bus->primary_dig_out_type == HDA_PCM_TYPE_SPDIF &&
3316 type == HDA_PCM_TYPE_HDMI) { 3318 type == HDA_PCM_TYPE_HDMI) {
3317 for (idx = 0; idx < codec->spdif_out.used; idx++) { 3319 /* suppose a single SPDIF device */
3318 spdif = snd_array_elem(&codec->spdif_out, idx); 3320 for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
3319 for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { 3321 kctl = find_mixer_ctl(codec, dig_mix->name, 0, 0);
3320 kctl = find_mixer_ctl(codec, dig_mix->name, 0, idx); 3322 if (!kctl)
3321 if (!kctl) 3323 break;
3322 break; 3324 kctl->id.index = spdif_index;
3323 kctl->id.device = spdif_pcm_dev;
3324 }
3325 } 3325 }
3326 codec->primary_dig_out_type = HDA_PCM_TYPE_HDMI; 3326 bus->primary_dig_out_type = HDA_PCM_TYPE_HDMI;
3327 } 3327 }
3328 if (!codec->primary_dig_out_type) 3328 if (!bus->primary_dig_out_type)
3329 codec->primary_dig_out_type = type; 3329 bus->primary_dig_out_type = type;
3330 3330
3331 idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch", dev); 3331 idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch", idx);
3332 if (idx < 0) { 3332 if (idx < 0) {
3333 printk(KERN_ERR "hda_codec: too many IEC958 outputs\n"); 3333 printk(KERN_ERR "hda_codec: too many IEC958 outputs\n");
3334 return -EBUSY; 3334 return -EBUSY;
@@ -3338,7 +3338,6 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
3338 kctl = snd_ctl_new1(dig_mix, codec); 3338 kctl = snd_ctl_new1(dig_mix, codec);
3339 if (!kctl) 3339 if (!kctl)
3340 return -ENOMEM; 3340 return -ENOMEM;
3341 kctl->id.device = dev;
3342 kctl->id.index = idx; 3341 kctl->id.index = idx;
3343 kctl->private_value = codec->spdif_out.used - 1; 3342 kctl->private_value = codec->spdif_out.used - 1;
3344 err = snd_hda_ctl_add(codec, associated_nid, kctl); 3343 err = snd_hda_ctl_add(codec, associated_nid, kctl);