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: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2010-12-23 10:17:52 +01:00
parent 2d7ec12b90
commit 1afe206ab6
1 changed files with 34 additions and 23 deletions

View File

@ -1919,6 +1919,16 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
}
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
* @codec: HD-audio codec
@ -2654,8 +2664,6 @@ static struct snd_kcontrol_new dig_mixes[] = {
{ } /* end */
};
#define SPDIF_MAX_IDX 4 /* 4 instances should be enough to probe */
/**
* snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls
* @codec: the HDA codec
@ -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;
int idx;
for (idx = 0; idx < SPDIF_MAX_IDX; idx++) {
if (!_snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch",
idx))
break;
}
if (idx >= SPDIF_MAX_IDX) {
idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch");
if (idx < 0) {
printk(KERN_ERR "hda_codec: too many IEC958 outputs\n");
return -EBUSY;
}
@ -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;
int idx;
for (idx = 0; idx < SPDIF_MAX_IDX; idx++) {
if (!_snd_hda_find_mixer_ctl(codec, "IEC958 Capture Switch",
idx))
break;
}
if (idx >= SPDIF_MAX_IDX) {
idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch");
if (idx < 0) {
printk(KERN_ERR "hda_codec: too many IEC958 inputs\n");
return -EBUSY;
}
@ -3808,21 +3808,32 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
for (; knew->name; knew++) {
struct snd_kcontrol *kctl;
int addr = 0, idx = 0;
if (knew->iface == -1) /* skip this codec private value */
continue;
kctl = snd_ctl_new1(knew, codec);
if (!kctl)
return -ENOMEM;
err = snd_hda_ctl_add(codec, 0, kctl);
if (err < 0) {
if (!codec->addr)
return err;
for (;;) {
kctl = snd_ctl_new1(knew, codec);
if (!kctl)
return -ENOMEM;
kctl->id.device = codec->addr;
if (addr > 0)
kctl->id.device = addr;
if (idx > 0)
kctl->id.index = idx;
err = snd_hda_ctl_add(codec, 0, kctl);
if (err < 0)
if (!err)
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;
} else
return err;
}
}