aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-10-12 11:24:51 -0400
committerTakashi Iwai <tiwai@suse.de>2012-10-17 02:42:00 -0400
commitdcda5806165c155d90b9aa466a1602cf4726012b (patch)
tree2608238090cb39ef41e4950900026fa9434fa4bb
parent9e3d352b3f8be39cab7186fd6213dcd458a29c97 (diff)
ALSA: hda - Add workaround for conflicting IEC958 controls
When both an SPDIF and an HDMI device are created on the same card instance, multiple IEC958 controls are created with indices=0, 1, ... But the alsa-lib configuration can't know which index corresponds actually to which PCM device, and both the SPDIF and the HDMI configurations point to the first IEC958 control wrongly. This patch introduces a (hackish and ugly) workaround: the IEC958 controls for the SPDIF device are re-labeled with device=1 when HDMI coexists. The device=1 corresponds to the actual PCM device for SPDIF, so it's anyway a better representation. In future, HDMI controls should be moved with the corresponding PCM device number, too. Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/hda_codec.c60
-rw-r--r--sound/pci/hda/hda_codec.h1
-rw-r--r--sound/pci/hda/hda_local.h8
-rw-r--r--sound/pci/hda/patch_cirrus.c5
-rw-r--r--sound/pci/hda/patch_hdmi.c7
-rw-r--r--sound/pci/hda/patch_realtek.c7
-rw-r--r--sound/pci/hda/patch_sigmatel.c7
7 files changed, 63 insertions, 32 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index ee958a7d1647..2da787519513 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2166,12 +2166,12 @@ EXPORT_SYMBOL_HDA(snd_hda_set_vmaster_tlv);
2166 2166
2167/* find a mixer control element with the given name */ 2167/* find a mixer control element with the given name */
2168static struct snd_kcontrol * 2168static struct snd_kcontrol *
2169_snd_hda_find_mixer_ctl(struct hda_codec *codec, 2169find_mixer_ctl(struct hda_codec *codec, const char *name, int dev, int idx)
2170 const char *name, int idx)
2171{ 2170{
2172 struct snd_ctl_elem_id id; 2171 struct snd_ctl_elem_id id;
2173 memset(&id, 0, sizeof(id)); 2172 memset(&id, 0, sizeof(id));
2174 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 2173 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2174 id.device = dev;
2175 id.index = idx; 2175 id.index = idx;
2176 if (snd_BUG_ON(strlen(name) >= sizeof(id.name))) 2176 if (snd_BUG_ON(strlen(name) >= sizeof(id.name)))
2177 return NULL; 2177 return NULL;
@@ -2189,15 +2189,16 @@ _snd_hda_find_mixer_ctl(struct hda_codec *codec,
2189struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, 2189struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
2190 const char *name) 2190 const char *name)
2191{ 2191{
2192 return _snd_hda_find_mixer_ctl(codec, name, 0); 2192 return find_mixer_ctl(codec, name, 0, 0);
2193} 2193}
2194EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); 2194EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
2195 2195
2196static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name) 2196static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name,
2197 int dev)
2197{ 2198{
2198 int idx; 2199 int idx;
2199 for (idx = 0; idx < 16; idx++) { /* 16 ctlrs should be large enough */ 2200 for (idx = 0; idx < 16; idx++) { /* 16 ctlrs should be large enough */
2200 if (!_snd_hda_find_mixer_ctl(codec, name, idx)) 2201 if (!find_mixer_ctl(codec, name, dev, idx))
2201 return idx; 2202 return idx;
2202 } 2203 }
2203 return -EBUSY; 2204 return -EBUSY;
@@ -3148,26 +3149,48 @@ static struct snd_kcontrol_new dig_mixes[] = {
3148}; 3149};
3149 3150
3150/** 3151/**
3151 * snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls 3152 * snd_hda_create_dig_out_ctls - create Output SPDIF-related controls
3152 * @codec: the HDA codec 3153 * @codec: the HDA codec
3153 * @nid: audio out widget NID 3154 * @associated_nid: NID that new ctls associated with
3154 * 3155 * @cvt_nid: converter NID
3155 * Creates controls related with the SPDIF output. 3156 * @type: HDA_PCM_TYPE_*
3156 * Called from each patch supporting the SPDIF out. 3157 * Creates controls related with the digital output.
3158 * Called from each patch supporting the digital out.
3157 * 3159 *
3158 * Returns 0 if successful, or a negative error code. 3160 * Returns 0 if successful, or a negative error code.
3159 */ 3161 */
3160int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, 3162int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
3161 hda_nid_t associated_nid, 3163 hda_nid_t associated_nid,
3162 hda_nid_t cvt_nid) 3164 hda_nid_t cvt_nid,
3165 int type)
3163{ 3166{
3164 int err; 3167 int err;
3165 struct snd_kcontrol *kctl; 3168 struct snd_kcontrol *kctl;
3166 struct snd_kcontrol_new *dig_mix; 3169 struct snd_kcontrol_new *dig_mix;
3167 int idx; 3170 int idx, dev = 0;
3171 const int spdif_pcm_dev = 1;
3168 struct hda_spdif_out *spdif; 3172 struct hda_spdif_out *spdif;
3169 3173
3170 idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch"); 3174 if (codec->primary_dig_out_type == HDA_PCM_TYPE_HDMI &&
3175 type == HDA_PCM_TYPE_SPDIF) {
3176 dev = spdif_pcm_dev;
3177 } else if (codec->primary_dig_out_type == HDA_PCM_TYPE_SPDIF &&
3178 type == HDA_PCM_TYPE_HDMI) {
3179 for (idx = 0; idx < codec->spdif_out.used; idx++) {
3180 spdif = snd_array_elem(&codec->spdif_out, idx);
3181 for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
3182 kctl = find_mixer_ctl(codec, dig_mix->name, 0, idx);
3183 if (!kctl)
3184 break;
3185 kctl->id.device = spdif_pcm_dev;
3186 }
3187 }
3188 codec->primary_dig_out_type = HDA_PCM_TYPE_HDMI;
3189 }
3190 if (!codec->primary_dig_out_type)
3191 codec->primary_dig_out_type = type;
3192
3193 idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch", dev);
3171 if (idx < 0) { 3194 if (idx < 0) {
3172 printk(KERN_ERR "hda_codec: too many IEC958 outputs\n"); 3195 printk(KERN_ERR "hda_codec: too many IEC958 outputs\n");
3173 return -EBUSY; 3196 return -EBUSY;
@@ -3177,6 +3200,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
3177 kctl = snd_ctl_new1(dig_mix, codec); 3200 kctl = snd_ctl_new1(dig_mix, codec);
3178 if (!kctl) 3201 if (!kctl)
3179 return -ENOMEM; 3202 return -ENOMEM;
3203 kctl->id.device = dev;
3180 kctl->id.index = idx; 3204 kctl->id.index = idx;
3181 kctl->private_value = codec->spdif_out.used - 1; 3205 kctl->private_value = codec->spdif_out.used - 1;
3182 err = snd_hda_ctl_add(codec, associated_nid, kctl); 3206 err = snd_hda_ctl_add(codec, associated_nid, kctl);
@@ -3189,7 +3213,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
3189 spdif->status = convert_to_spdif_status(spdif->ctls); 3213 spdif->status = convert_to_spdif_status(spdif->ctls);
3190 return 0; 3214 return 0;
3191} 3215}
3192EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls); 3216EXPORT_SYMBOL_HDA(snd_hda_create_dig_out_ctls);
3193 3217
3194/* get the hda_spdif_out entry from the given NID 3218/* get the hda_spdif_out entry from the given NID
3195 * call within spdif_mutex lock 3219 * call within spdif_mutex lock
@@ -3364,7 +3388,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
3364 struct snd_kcontrol_new *dig_mix; 3388 struct snd_kcontrol_new *dig_mix;
3365 int idx; 3389 int idx;
3366 3390
3367 idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch"); 3391 idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch", 0);
3368 if (idx < 0) { 3392 if (idx < 0) {
3369 printk(KERN_ERR "hda_codec: too many IEC958 inputs\n"); 3393 printk(KERN_ERR "hda_codec: too many IEC958 inputs\n");
3370 return -EBUSY; 3394 return -EBUSY;
@@ -4472,7 +4496,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
4472 addr = codec->addr; 4496 addr = codec->addr;
4473 else if (!idx && !knew->index) { 4497 else if (!idx && !knew->index) {
4474 idx = find_empty_mixer_ctl_idx(codec, 4498 idx = find_empty_mixer_ctl_idx(codec,
4475 knew->name); 4499 knew->name, 0);
4476 if (idx <= 0) 4500 if (idx <= 0)
4477 return err; 4501 return err;
4478 } else 4502 } else
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 10a03b049bed..62d4229c7b95 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -836,6 +836,7 @@ struct hda_codec {
836 struct mutex hash_mutex; 836 struct mutex hash_mutex;
837 struct snd_array spdif_out; 837 struct snd_array spdif_out;
838 unsigned int spdif_in_enable; /* SPDIF input enable? */ 838 unsigned int spdif_in_enable; /* SPDIF input enable? */
839 int primary_dig_out_type; /* primary digital out PCM type */
839 const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ 840 const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
840 struct snd_array init_pins; /* initial (BIOS) pin configurations */ 841 struct snd_array init_pins; /* initial (BIOS) pin configurations */
841 struct snd_array driver_pins; /* pin configs set by codec parser */ 842 struct snd_array driver_pins; /* pin configs set by codec parser */
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 09dbdc37f781..8c43198b7f56 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -240,9 +240,11 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag,
240/* 240/*
241 * SPDIF I/O 241 * SPDIF I/O
242 */ 242 */
243int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, 243int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
244 hda_nid_t associated_nid, 244 hda_nid_t associated_nid,
245 hda_nid_t cvt_nid); 245 hda_nid_t cvt_nid, int type);
246#define snd_hda_create_spdif_out_ctls(codec, anid, cnid) \
247 snd_hda_create_dig_out_ctls(codec, anid, cnid, HDA_PCM_TYPE_SPDIF)
246int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); 248int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
247 249
248/* 250/*
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 61a71131711c..a7f8790ae885 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -873,8 +873,9 @@ static int build_digital_output(struct hda_codec *codec)
873 if (!spec->multiout.dig_out_nid) 873 if (!spec->multiout.dig_out_nid)
874 return 0; 874 return 0;
875 875
876 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid, 876 err = snd_hda_create_dig_out_ctls(codec, spec->multiout.dig_out_nid,
877 spec->multiout.dig_out_nid); 877 spec->multiout.dig_out_nid,
878 spec->pcm_rec[1].pcm_type);
878 if (err < 0) 879 if (err < 0)
879 return err; 880 return err;
880 err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); 881 err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 71555cc54db1..39ca1005995d 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1589,9 +1589,10 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
1589 if (err < 0) 1589 if (err < 0)
1590 return err; 1590 return err;
1591 1591
1592 err = snd_hda_create_spdif_out_ctls(codec, 1592 err = snd_hda_create_dig_out_ctls(codec,
1593 per_pin->pin_nid, 1593 per_pin->pin_nid,
1594 per_pin->mux_nids[0]); 1594 per_pin->mux_nids[0],
1595 HDA_PCM_TYPE_HDMI);
1595 if (err < 0) 1596 if (err < 0)
1596 return err; 1597 return err;
1597 snd_hda_spdif_ctls_unassign(codec, pin_idx); 1598 snd_hda_spdif_ctls_unassign(codec, pin_idx);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 8253b4eeb6a1..2d2bb6629988 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -1836,9 +1836,10 @@ static int __alc_build_controls(struct hda_codec *codec)
1836 return err; 1836 return err;
1837 } 1837 }
1838 if (spec->multiout.dig_out_nid) { 1838 if (spec->multiout.dig_out_nid) {
1839 err = snd_hda_create_spdif_out_ctls(codec, 1839 err = snd_hda_create_dig_out_ctls(codec,
1840 spec->multiout.dig_out_nid, 1840 spec->multiout.dig_out_nid,
1841 spec->multiout.dig_out_nid); 1841 spec->multiout.dig_out_nid,
1842 spec->pcm_rec[1].pcm_type);
1842 if (err < 0) 1843 if (err < 0)
1843 return err; 1844 return err;
1844 if (!spec->no_analog) { 1845 if (!spec->no_analog) {
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 770013ff556f..62141650211f 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -1136,9 +1136,10 @@ static int stac92xx_build_controls(struct hda_codec *codec)
1136 } 1136 }
1137 1137
1138 if (spec->multiout.dig_out_nid) { 1138 if (spec->multiout.dig_out_nid) {
1139 err = snd_hda_create_spdif_out_ctls(codec, 1139 err = snd_hda_create_dig_out_ctls(codec,
1140 spec->multiout.dig_out_nid, 1140 spec->multiout.dig_out_nid,
1141 spec->multiout.dig_out_nid); 1141 spec->multiout.dig_out_nid,
1142 spec->autocfg.dig_out_type[0]);
1142 if (err < 0) 1143 if (err < 0)
1143 return err; 1144 return err;
1144 err = snd_hda_create_spdif_share_sw(codec, 1145 err = snd_hda_create_spdif_share_sw(codec,