Skip to content

Commit

Permalink
ALSA: hda - Try to find an empty control index when it's occupied
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
tiwai committed Dec 23, 2010
1 parent 2d7ec12 commit 1afe206
Showing 1 changed file with 34 additions and 23 deletions.
57 changes: 34 additions & 23 deletions sound/pci/hda/hda_codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
}
Expand Down

0 comments on commit 1afe206

Please sign in to comment.