Commit aeb4b88e authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Don't add elements of other codecs to vmaster slave

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: default avatarDavid Henningsson <david.henningsson@canonical.com>
Cc: <stable@kernel.org>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 7fb4f392
...@@ -2331,6 +2331,39 @@ int snd_hda_codec_reset(struct hda_codec *codec) ...@@ -2331,6 +2331,39 @@ int snd_hda_codec_reset(struct hda_codec *codec)
return 0; return 0;
} }
typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *);
/* apply the function to all matching slave ctls in the mixer list */
static int map_slaves(struct hda_codec *codec, const char * const *slaves,
map_slave_func_t func, void *data)
{
struct hda_nid_item *items;
const char * const *s;
int i, err;
items = codec->mixers.list;
for (i = 0; i < codec->mixers.used; i++) {
struct snd_kcontrol *sctl = items[i].kctl;
if (!sctl || !sctl->id.name ||
sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER)
continue;
for (s = slaves; *s; s++) {
if (!strcmp(sctl->id.name, *s)) {
err = func(data, sctl);
if (err)
return err;
break;
}
}
}
return 0;
}
static int check_slave_present(void *data, struct snd_kcontrol *sctl)
{
return 1;
}
/** /**
* snd_hda_add_vmaster - create a virtual master control and add slaves * snd_hda_add_vmaster - create a virtual master control and add slaves
* @codec: HD-audio codec * @codec: HD-audio codec
...@@ -2351,12 +2384,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, ...@@ -2351,12 +2384,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char * const *slaves) unsigned int *tlv, const char * const *slaves)
{ {
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
const char * const *s;
int err; int err;
for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++) err = map_slaves(codec, slaves, check_slave_present, NULL);
; if (err != 1) {
if (!*s) {
snd_printdd("No slave found for %s\n", name); snd_printdd("No slave found for %s\n", name);
return 0; return 0;
} }
...@@ -2367,23 +2398,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, ...@@ -2367,23 +2398,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
if (err < 0) if (err < 0)
return err; return err;
for (s = slaves; *s; s++) { err = map_slaves(codec, slaves, (map_slave_func_t)snd_ctl_add_slave,
struct snd_kcontrol *sctl; kctl);
int i = 0;
for (;;) {
sctl = _snd_hda_find_mixer_ctl(codec, *s, i);
if (!sctl) {
if (!i)
snd_printdd("Cannot find slave %s, "
"skipped\n", *s);
break;
}
err = snd_ctl_add_slave(kctl, sctl);
if (err < 0) if (err < 0)
return err; return err;
i++;
}
}
return 0; return 0;
} }
EXPORT_SYMBOL_HDA(snd_hda_add_vmaster); EXPORT_SYMBOL_HDA(snd_hda_add_vmaster);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment