Commit 1afe206a authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Try to find an empty control index when it's occupied

When a mixer control element was already created with the given name,
try to find another index for avoiding conflicts, instead of breaking
with an error.  This makes the driver more robust.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 2d7ec12b
...@@ -1919,6 +1919,16 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, ...@@ -1919,6 +1919,16 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
} }
EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name)
{
int idx;
for (idx = 0; idx < 16; idx++) { /* 16 ctlrs should be large enough */
if (!_snd_hda_find_mixer_ctl(codec, name, idx))
return idx;
}
return -EBUSY;
}
/** /**
* snd_hda_ctl_add - Add a control element and assign to the codec * snd_hda_ctl_add - Add a control element and assign to the codec
* @codec: HD-audio codec * @codec: HD-audio codec
...@@ -2654,8 +2664,6 @@ static struct snd_kcontrol_new dig_mixes[] = { ...@@ -2654,8 +2664,6 @@ static struct snd_kcontrol_new dig_mixes[] = {
{ } /* end */ { } /* end */
}; };
#define SPDIF_MAX_IDX 4 /* 4 instances should be enough to probe */
/** /**
* snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls * snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls
* @codec: the HDA codec * @codec: the HDA codec
...@@ -2673,12 +2681,8 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) ...@@ -2673,12 +2681,8 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
struct snd_kcontrol_new *dig_mix; struct snd_kcontrol_new *dig_mix;
int idx; int idx;
for (idx = 0; idx < SPDIF_MAX_IDX; idx++) { idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch");
if (!_snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch", if (idx < 0) {
idx))
break;
}
if (idx >= SPDIF_MAX_IDX) {
printk(KERN_ERR "hda_codec: too many IEC958 outputs\n"); printk(KERN_ERR "hda_codec: too many IEC958 outputs\n");
return -EBUSY; return -EBUSY;
} }
...@@ -2829,12 +2833,8 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) ...@@ -2829,12 +2833,8 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
struct snd_kcontrol_new *dig_mix; struct snd_kcontrol_new *dig_mix;
int idx; int idx;
for (idx = 0; idx < SPDIF_MAX_IDX; idx++) { idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch");
if (!_snd_hda_find_mixer_ctl(codec, "IEC958 Capture Switch", if (idx < 0) {
idx))
break;
}
if (idx >= SPDIF_MAX_IDX) {
printk(KERN_ERR "hda_codec: too many IEC958 inputs\n"); printk(KERN_ERR "hda_codec: too many IEC958 inputs\n");
return -EBUSY; return -EBUSY;
} }
...@@ -3808,21 +3808,32 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) ...@@ -3808,21 +3808,32 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
for (; knew->name; knew++) { for (; knew->name; knew++) {
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
int addr = 0, idx = 0;
if (knew->iface == -1) /* skip this codec private value */ if (knew->iface == -1) /* skip this codec private value */
continue; continue;
for (;;) {
kctl = snd_ctl_new1(knew, codec); kctl = snd_ctl_new1(knew, codec);
if (!kctl) if (!kctl)
return -ENOMEM; return -ENOMEM;
if (addr > 0)
kctl->id.device = addr;
if (idx > 0)
kctl->id.index = idx;
err = snd_hda_ctl_add(codec, 0, kctl); err = snd_hda_ctl_add(codec, 0, kctl);
if (err < 0) { if (!err)
if (!codec->addr) break;
/* try first with another device index corresponding to
* the codec addr; if it still fails (or it's the
* primary codec), then try another control index
*/
if (!addr && codec->addr)
addr = codec->addr;
else if (!idx && !knew->index) {
idx = find_empty_mixer_ctl_idx(codec,
knew->name);
if (idx <= 0)
return err; return err;
kctl = snd_ctl_new1(knew, codec); } else
if (!kctl)
return -ENOMEM;
kctl->id.device = codec->addr;
err = snd_hda_ctl_add(codec, 0, kctl);
if (err < 0)
return err; return err;
} }
} }
......
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