aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-11-10 06:28:38 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-11-21 17:31:14 -0500
commitfd6f075d1e29791d0e4b42da2e6962665f90de1b (patch)
treef4a93d3b83e901fc167e302567efbaab0ef67ed9 /sound/pci
parent999c1d6bc999d67657033ec780a561aa172c75a9 (diff)
ALSA: hda - Don't add elements of other codecs to vmaster slave
commit aeb4b88ec0a948efce8e3a23a8f964d3560a7308 upstream. When a virtual mater control is created, the driver looks for slave elements from the assigned card instance. But this may include the elements of other codecs when multiple codecs are on the same HD-audio bus. This works at the first time, but it'll give Oops when it's once freed and re-created via reconfig sysfs. This patch changes the element-look-up strategy to limit only to the mixer elements of the same codec. Reported-by: David Henningsson <david.henningsson@canonical.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/hda_codec.c60
1 files changed, 39 insertions, 21 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 45b4a8d70e0..21958518467 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2187,6 +2187,39 @@ int snd_hda_codec_reset(struct hda_codec *codec)
2187 return 0; 2187 return 0;
2188} 2188}
2189 2189
2190typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *);
2191
2192/* apply the function to all matching slave ctls in the mixer list */
2193static int map_slaves(struct hda_codec *codec, const char * const *slaves,
2194 map_slave_func_t func, void *data)
2195{
2196 struct hda_nid_item *items;
2197 const char * const *s;
2198 int i, err;
2199
2200 items = codec->mixers.list;
2201 for (i = 0; i < codec->mixers.used; i++) {
2202 struct snd_kcontrol *sctl = items[i].kctl;
2203 if (!sctl || !sctl->id.name ||
2204 sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER)
2205 continue;
2206 for (s = slaves; *s; s++) {
2207 if (!strcmp(sctl->id.name, *s)) {
2208 err = func(data, sctl);
2209 if (err)
2210 return err;
2211 break;
2212 }
2213 }
2214 }
2215 return 0;
2216}
2217
2218static int check_slave_present(void *data, struct snd_kcontrol *sctl)
2219{
2220 return 1;
2221}
2222
2190/** 2223/**
2191 * snd_hda_add_vmaster - create a virtual master control and add slaves 2224 * snd_hda_add_vmaster - create a virtual master control and add slaves
2192 * @codec: HD-audio codec 2225 * @codec: HD-audio codec
@@ -2207,12 +2240,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
2207 unsigned int *tlv, const char * const *slaves) 2240 unsigned int *tlv, const char * const *slaves)
2208{ 2241{
2209 struct snd_kcontrol *kctl; 2242 struct snd_kcontrol *kctl;
2210 const char * const *s;
2211 int err; 2243 int err;
2212 2244
2213 for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++) 2245 err = map_slaves(codec, slaves, check_slave_present, NULL);
2214 ; 2246 if (err != 1) {
2215 if (!*s) {
2216 snd_printdd("No slave found for %s\n", name); 2247 snd_printdd("No slave found for %s\n", name);
2217 return 0; 2248 return 0;
2218 } 2249 }
@@ -2223,23 +2254,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
2223 if (err < 0) 2254 if (err < 0)
2224 return err; 2255 return err;
2225 2256
2226 for (s = slaves; *s; s++) { 2257 err = map_slaves(codec, slaves, (map_slave_func_t)snd_ctl_add_slave,
2227 struct snd_kcontrol *sctl; 2258 kctl);
2228 int i = 0; 2259 if (err < 0)
2229 for (;;) { 2260 return err;
2230 sctl = _snd_hda_find_mixer_ctl(codec, *s, i);
2231 if (!sctl) {
2232 if (!i)
2233 snd_printdd("Cannot find slave %s, "
2234 "skipped\n", *s);
2235 break;
2236 }
2237 err = snd_ctl_add_slave(kctl, sctl);
2238 if (err < 0)
2239 return err;
2240 i++;
2241 }
2242 }
2243 return 0; 2261 return 0;
2244} 2262}
2245EXPORT_SYMBOL_HDA(snd_hda_add_vmaster); 2263EXPORT_SYMBOL_HDA(snd_hda_add_vmaster);