diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-10-12 11:24:51 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-10-17 02:42:00 -0400 |
commit | dcda5806165c155d90b9aa466a1602cf4726012b (patch) | |
tree | 2608238090cb39ef41e4950900026fa9434fa4bb | |
parent | 9e3d352b3f8be39cab7186fd6213dcd458a29c97 (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.c | 60 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 1 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 8 | ||||
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 5 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 7 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 7 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 7 |
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 */ |
2168 | static struct snd_kcontrol * | 2168 | static struct snd_kcontrol * |
2169 | _snd_hda_find_mixer_ctl(struct hda_codec *codec, | 2169 | find_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, | |||
2189 | struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | 2189 | struct 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 | } |
2194 | EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); | 2194 | EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); |
2195 | 2195 | ||
2196 | static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name) | 2196 | static 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 | */ |
3160 | int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, | 3162 | int 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 | } |
3192 | EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls); | 3216 | EXPORT_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 | */ |
243 | int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, | 243 | int 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) | ||
246 | int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); | 248 | int 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, |