mutex_init(&codec->control_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);
+       snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 60);
        snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
        snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
        if (codec->bus->modelname) {
 EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
 
 /* Add a control element and assign to the codec */
-int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl)
+int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
+                   struct snd_kcontrol *kctl)
 {
        int err;
-       struct snd_kcontrol **knewp;
+       struct hda_nid_item *item;
 
        err = snd_ctl_add(codec->bus->card, kctl);
        if (err < 0)
                return err;
-       knewp = snd_array_new(&codec->mixers);
-       if (!knewp)
+       item = snd_array_new(&codec->mixers);
+       if (!item)
                return -ENOMEM;
-       *knewp = kctl;
+       item->kctl = kctl;
+       item->nid = nid;
        return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_ctl_add);
 void snd_hda_ctls_clear(struct hda_codec *codec)
 {
        int i;
-       struct snd_kcontrol **kctls = codec->mixers.list;
+       struct hda_nid_item *items = codec->mixers.list;
        for (i = 0; i < codec->mixers.used; i++)
-               snd_ctl_remove(codec->bus->card, kctls[i]);
+               snd_ctl_remove(codec->bus->card, items[i].kctl);
        snd_array_free(&codec->mixers);
 }
 
        kctl = snd_ctl_make_virtual_master(name, tlv);
        if (!kctl)
                return -ENOMEM;
-       err = snd_hda_ctl_add(codec, kctl);
+       err = snd_hda_ctl_add(codec, 0, kctl);
        if (err < 0)
                return err;
        
                        return -ENOMEM;
                kctl->id.index = idx;
                kctl->private_value = nid;
-               err = snd_hda_ctl_add(codec, kctl);
+               err = snd_hda_ctl_add(codec, nid, kctl);
                if (err < 0)
                        return err;
        }
        if (!mout->dig_out_nid)
                return 0;
        /* ATTENTION: here mout is passed as private_data, instead of codec */
-       return snd_hda_ctl_add(codec,
-                          snd_ctl_new1(&spdif_share_sw, mout));
+       return snd_hda_ctl_add(codec, mout->dig_out_nid,
+                             snd_ctl_new1(&spdif_share_sw, mout));
 }
 EXPORT_SYMBOL_HDA(snd_hda_create_spdif_share_sw);
 
                if (!kctl)
                        return -ENOMEM;
                kctl->private_value = nid;
-               err = snd_hda_ctl_add(codec, kctl);
+               err = snd_hda_ctl_add(codec, nid, kctl);
                if (err < 0)
                        return err;
        }
                kctl = snd_ctl_new1(knew, codec);
                if (!kctl)
                        return -ENOMEM;
-               err = snd_hda_ctl_add(codec, kctl);
+               err = snd_hda_ctl_add(codec, 0, kctl);
                if (err < 0) {
                        if (!codec->addr)
                                return err;
                        if (!kctl)
                                return -ENOMEM;
                        kctl->id.device = codec->addr;
-                       err = snd_hda_ctl_add(codec, kctl);
+                       err = snd_hda_ctl_add(codec, 0, kctl);
                        if (err < 0)
                                return err;
                }
 
                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);
-               err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+               err = snd_hda_ctl_add(codec, node->nid,
+                                       snd_ctl_new1(&knew, codec));
                if (err < 0)
                        return err;
                created = 1;
                if (is_loopback)
                        add_input_loopback(codec, node->nid, HDA_OUTPUT, 0);
                snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
-               err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+               err = snd_hda_ctl_add(codec, node->nid,
+                                       snd_ctl_new1(&knew, codec));
                if (err < 0)
                        return err;
                created = 1;
            (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);
-               err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+               err = snd_hda_ctl_add(codec, node->nid,
+                                       snd_ctl_new1(&knew, codec));
                if (err < 0)
                        return err;
                created = 1;
                   (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);
-               err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+               err = snd_hda_ctl_add(codec, node->nid,
+                                       snd_ctl_new1(&knew, codec));
                if (err < 0)
                        return err;
                created = 1;
        }
 
        /* create input MUX if multiple sources are available */
-       err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec));
+       err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&cap_sel, codec));
        if (err < 0)
                return err;
 
                        HDA_CODEC_VOLUME(name, adc_node->nid,
                                         spec->input_mux.items[i].index,
                                         HDA_INPUT);
-               err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+               err = snd_hda_ctl_add(codec, adc_node->nid,
+                                       snd_ctl_new1(&knew, codec));
                if (err < 0)
                        return err;
        }
 
                              unsigned int caps);
 u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
 
-int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl);
+struct hda_nid_item {
+       struct snd_kcontrol *kctl;
+       hda_nid_t nid;
+};
+
+int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
+                   struct snd_kcontrol *kctl);
 void snd_hda_ctls_clear(struct hda_codec *codec);
 
 /*
  * AMP control callbacks
  */
 /* retrieve parameters from private_value */
-#define get_amp_nid(kc)                ((kc)->private_value & 0xffff)
+#define get_amp_nid_(pv)       ((pv) & 0xffff)
+#define get_amp_nid(kc)                get_amp_nid_((kc)->private_value)
 #define get_amp_channels(kc)   (((kc)->private_value >> 16) & 0x3)
 #define get_amp_direction(kc)  (((kc)->private_value >> 18) & 0x1)
 #define get_amp_index(kc)      (((kc)->private_value >> 19) & 0xf)
 
                return "UNKNOWN Widget";
 }
 
+static void print_nid_mixers(struct snd_info_buffer *buffer,
+                            struct hda_codec *codec, hda_nid_t nid)
+{
+       int i;
+       struct hda_nid_item *items = codec->mixers.list;
+       struct snd_kcontrol *kctl;
+       for (i = 0; i < codec->mixers.used; i++) {
+               if (items[i].nid == nid) {
+                       kctl = items[i].kctl;
+                       snd_iprintf(buffer,
+                         "  Control: name=\"%s\", index=%i, device=%i\n",
+                         kctl->id.name, kctl->id.index, kctl->id.device);
+               }
+       }
+}
+
+static void print_nid_pcms(struct snd_info_buffer *buffer,
+                          struct hda_codec *codec, hda_nid_t nid)
+{
+       int pcm, type;
+       struct hda_pcm *cpcm;
+       for (pcm = 0; pcm < codec->num_pcms; pcm++) {
+               cpcm = &codec->pcm_info[pcm];
+               for (type = 0; type < 2; type++) {
+                       if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL)
+                               continue;
+                       snd_iprintf(buffer, "  Device: name=\"%s\", "
+                                   "type=\"%s\", device=%i\n",
+                                   cpcm->name,
+                                   snd_hda_pcm_type_name[cpcm->pcm_type],
+                                   cpcm->pcm->device);
+               }
+       }
+}
+
 static void print_amp_caps(struct snd_info_buffer *buffer,
                           struct hda_codec *codec, hda_nid_t nid, int dir)
 {
                           struct hda_codec *codec, hda_nid_t nid,
                           unsigned int wid_type)
 {
-       int pcm, conv;
-       for (pcm = 0; pcm < codec->num_pcms; pcm++) {
-               int type;
-               struct hda_pcm *cpcm = &codec->pcm_info[pcm];
-               for (type = 0; type < 2; type++) {
-                       if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL)
-                               continue;
-                       snd_iprintf(buffer, "  Device: name=\"%s\", "
-                                   "type=\"%s\", device=%i\n",
-                                   cpcm->name,
-                                   snd_hda_pcm_type_name[cpcm->pcm_type],
-                                   cpcm->pcm->device);
-               }
-       }
-       conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
+       int conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
        snd_iprintf(buffer,
                    "  Converter: stream=%d, channel=%d\n",
                    (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT,
                            (data & (1<<i)) ? 1 : 0,
                            (unsol & (1<<i)) ? 1 : 0);
        /* FIXME: add GPO and GPI pin information */
+       print_nid_mixers(buffer, codec, nid);
 }
 
 static void print_codec_info(struct snd_info_entry *entry,
                        snd_iprintf(buffer, " CP");
                snd_iprintf(buffer, "\n");
 
+               print_nid_mixers(buffer, codec, nid);
+               print_nid_pcms(buffer, codec, nid);
+
                /* volume knob is a special widget that always have connection
                 * list
                 */
 
                        if (!kctl)
                                return -ENOMEM;
                        kctl->private_value = spec->beep_amp;
-                       err = snd_hda_ctl_add(codec, kctl);
+                       err = snd_hda_ctl_add(codec,
+                                               get_amp_nid_(spec->beep_amp),
+                                               kctl);
                        if (err < 0)
                                return err;
                }
 
        struct snd_kcontrol_new knew =
                HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type);
        sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
-       return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
 }
 
 static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
        struct snd_kcontrol_new knew =
                HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type);
        sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]);
-       return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
+       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
 }
 
 #define add_out_switch(codec, nid, pfx)        _add_switch(codec, nid, pfx, 3, 0)
 
        knew.private_value = pval;
        snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]);
        *kctlp = snd_ctl_new1(&knew, codec);
-       return snd_hda_ctl_add(codec, *kctlp);
+       return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp);
 }
 
 static int add_volume(struct hda_codec *codec, const char *name,
        knew.private_value = pval;
        snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]);
        *kctlp = snd_ctl_new1(&knew, codec);
-       return snd_hda_ctl_add(codec, *kctlp);
+       return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp);
 }
 
 static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
 
        spec->vmaster_sw =
                snd_ctl_make_virtual_master("Master Playback Switch", NULL);
-       err = snd_hda_ctl_add(codec, spec->vmaster_sw);
+       err = snd_hda_ctl_add(codec, dac, spec->vmaster_sw);
        if (err < 0)
                return err;
 
        snd_hda_set_vmaster_tlv(codec, dac, HDA_OUTPUT, tlv);
        spec->vmaster_vol =
                snd_ctl_make_virtual_master("Master Playback Volume", tlv);
-       err = snd_hda_ctl_add(codec, spec->vmaster_vol);
+       err = snd_hda_ctl_add(codec, dac, spec->vmaster_vol);
        if (err < 0)
                return err;
        return 0;
                if (!kctl)
                        return -ENOMEM;
                kctl->private_value = (long)spec->capture_bind[i];
-               err = snd_hda_ctl_add(codec, kctl);
+               err = snd_hda_ctl_add(codec, 0, kctl);
                if (err < 0)
                        return err;
        }
        
        if (spec->num_inputs > 1 && !spec->mic_detect) {
-               err = snd_hda_ctl_add(codec,
+               err = snd_hda_ctl_add(codec, 0,
                                      snd_ctl_new1(&cs_capture_source, codec));
                if (err < 0)
                        return err;
 
                        if (!kctl)
                                return -ENOMEM;
                        kctl->private_value = spec->beep_amp;
-                       err = snd_hda_ctl_add(codec, kctl);
+                       err = snd_hda_ctl_add(codec,
+                                       get_amp_nid_(spec->beep_amp), kctl);
                        if (err < 0)
                                return err;
                }
 
        if (!spec->auto_mic && spec->num_dmuxes > 0 &&
            snd_hda_get_bool_hint(codec, "separate_dmux") == 1) {
                stac_dmux_mixer.count = spec->num_dmuxes;
-               err = snd_hda_ctl_add(codec,
+               err = snd_hda_ctl_add(codec, 0,
                                  snd_ctl_new1(&stac_dmux_mixer, codec));
                if (err < 0)
                        return err;
                        spec->spdif_mute = 1;
                }
                stac_smux_mixer.count = spec->num_smuxes;
-               err = snd_hda_ctl_add(codec,
+               err = snd_hda_ctl_add(codec, 0,
                                  snd_ctl_new1(&stac_smux_mixer, codec));
                if (err < 0)
                        return err;