ALSA: hda - Manage kcontrol lists
Manage all kcontrol elements created in the hda-intel driver.
This makes it possible to remove and reconfigure the controls
of each codec.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 53e3649..bc3ed24 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -574,6 +574,7 @@
flush_scheduled_work();
#endif
list_del(&codec->list);
+ snd_array_free(&codec->mixers);
codec->bus->caddr_tbl[codec->addr] = NULL;
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
@@ -622,6 +623,7 @@
mutex_init(&codec->spdif_mutex);
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
+ snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32);
#ifdef CONFIG_SND_HDA_POWER_SAVE
INIT_DELAYED_WORK(&codec->power_work, hda_power_work);
@@ -1090,6 +1092,32 @@
return _snd_hda_find_mixer_ctl(codec, name, 0);
}
+/* Add a control element and assign to the codec */
+int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl)
+{
+ int err;
+ struct snd_kcontrol **knewp;
+
+ err = snd_ctl_add(codec->bus->card, kctl);
+ if (err < 0)
+ return err;
+ knewp = snd_array_new(&codec->mixers);
+ if (!knewp)
+ return -ENOMEM;
+ *knewp = kctl;
+ return 0;
+}
+
+/* Clear all controls assigned to the given codec */
+void snd_hda_ctls_clear(struct hda_codec *codec)
+{
+ int i;
+ struct snd_kcontrol **kctls = codec->mixers.list;
+ for (i = 0; i < codec->mixers.used; i++)
+ snd_ctl_remove(codec->bus->card, kctls[i]);
+ snd_array_free(&codec->mixers);
+}
+
/* create a virtual master control and add slaves */
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char **slaves)
@@ -1107,7 +1135,7 @@
kctl = snd_ctl_make_virtual_master(name, tlv);
if (!kctl)
return -ENOMEM;
- err = snd_ctl_add(codec->bus->card, kctl);
+ err = snd_hda_ctl_add(codec, kctl);
if (err < 0)
return err;
@@ -1571,7 +1599,7 @@
kctl = snd_ctl_new1(dig_mix, codec);
kctl->id.index = idx;
kctl->private_value = nid;
- err = snd_ctl_add(codec->bus->card, kctl);
+ err = snd_hda_ctl_add(codec, kctl);
if (err < 0)
return err;
}
@@ -1615,7 +1643,7 @@
if (!mout->dig_out_nid)
return 0;
/* ATTENTION: here mout is passed as private_data, instead of codec */
- return snd_ctl_add(codec->bus->card,
+ return snd_hda_ctl_add(codec,
snd_ctl_new1(&spdif_share_sw, mout));
}
@@ -1717,7 +1745,7 @@
for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) {
kctl = snd_ctl_new1(dig_mix, codec);
kctl->private_value = nid;
- err = snd_ctl_add(codec->bus->card, kctl);
+ err = snd_hda_ctl_add(codec, kctl);
if (err < 0)
return err;
}
@@ -2440,7 +2468,7 @@
kctl = snd_ctl_new1(knew, codec);
if (!kctl)
return -ENOMEM;
- err = snd_ctl_add(codec->bus->card, kctl);
+ err = snd_hda_ctl_add(codec, kctl);
if (err < 0) {
if (!codec->addr)
return err;
@@ -2448,7 +2476,7 @@
if (!kctl)
return -ENOMEM;
kctl->id.device = codec->addr;
- err = snd_ctl_add(codec->bus->card, kctl);
+ err = snd_hda_ctl_add(codec, kctl);
if (err < 0)
return err;
}
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 53f3b08..8813ec1 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -740,6 +740,8 @@
hda_nid_t start_nid;
u32 *wcaps;
+ struct snd_array mixers; /* list of assigned mixer elements */
+
struct hda_cache_rec amp_cache; /* cache for amp access */
struct hda_cache_rec cmd_cache; /* cache for other commands */
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 0ca3089..98ff010 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -723,7 +723,8 @@
if (is_loopback)
add_input_loopback(codec, node->nid, HDA_INPUT, index);
snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
- if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+ err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+ if (err < 0)
return err;
created = 1;
} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
@@ -732,7 +733,8 @@
if (is_loopback)
add_input_loopback(codec, node->nid, HDA_OUTPUT, 0);
snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
- if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+ err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+ if (err < 0)
return err;
created = 1;
}
@@ -745,14 +747,16 @@
(node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) {
knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT);
snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
- if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+ err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+ if (err < 0)
return err;
created = 1;
} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
(node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) {
knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT);
snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
- if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0)
+ err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+ if (err < 0)
return err;
created = 1;
}
@@ -849,8 +853,8 @@
}
/* create input MUX if multiple sources are available */
- if ((err = snd_ctl_add(codec->bus->card,
- snd_ctl_new1(&cap_sel, codec))) < 0)
+ err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec));
+ if (err < 0)
return err;
/* no volume control? */
@@ -867,8 +871,8 @@
HDA_CODEC_VOLUME(name, adc_node->nid,
spec->input_mux.items[i].index,
HDA_INPUT);
- if ((err = snd_ctl_add(codec->bus->card,
- snd_ctl_new1(&knew, codec))) < 0)
+ err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+ if (err < 0)
return err;
}
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 7957fef..48faaf8 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -393,6 +393,9 @@
int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int caps);
+int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl);
+void snd_hda_ctls_clear(struct hda_codec *codec);
+
/*
* hwdep interface
*/
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 3db39ad..9c67af8 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -1250,7 +1250,7 @@
}
if (spec->num_dmuxes > 0) {
stac_dmux_mixer.count = spec->num_dmuxes;
- err = snd_ctl_add(codec->bus->card,
+ err = snd_hda_ctl_add(codec,
snd_ctl_new1(&stac_dmux_mixer, codec));
if (err < 0)
return err;