ALSA: hda - Manage kcontrol lists
authorTakashi Iwai <tiwai@suse.de>
Wed, 30 Jul 2008 13:01:45 +0000 (15:01 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 13 Oct 2008 00:43:01 +0000 (02:43 +0200)
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>
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_local.h
sound/pci/hda/patch_sigmatel.c

index 53e36495fae52815ec4b29e44058d7b26f87cb5d..bc3ed249b0fced1e5130c3b2bc46ba8a02bcd8b7 100644 (file)
@@ -574,6 +574,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
        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 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
        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 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
        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 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
        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 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
                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 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
        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 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
        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 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
                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 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
                        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;
                }
index 53f3b08b24cdfc778ffcbcfb5b9f29f4367c6ac2..8813ec10ca136f03438a51e2b92103f43bbe4071 100644 (file)
@@ -740,6 +740,8 @@ struct hda_codec {
        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 */
 
index 0ca30894f7c6fcf750ea46b3f009325388f7ecbb..98ff010d5b95c7467791140ff003f13e46212740 100644 (file)
@@ -723,7 +723,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
                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 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
                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 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
            (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 @@ static int build_input_controls(struct hda_codec *codec)
        }
 
        /* 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 @@ static int build_input_controls(struct hda_codec *codec)
                        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;
        }
 
index 7957fefda730ca05da03160362688ae90119db98..48faaf8cd21b599fc4560e956394790b1295c4c0 100644 (file)
@@ -393,6 +393,9 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
 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
  */
index 3db39adad79a6f42790e1dda2b86664d9f7a0898..9c67af8e2089c7984f2d20d453c1c81bdedce7f3 100644 (file)
@@ -1250,7 +1250,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
        }
        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;