Merge branch 'fix/hda' into topic/hda
diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c
index 661205c..af888a0 100644
--- a/sound/isa/gus/gus_mem.c
+++ b/sound/isa/gus/gus_mem.c
@@ -127,7 +127,8 @@
 	    !share_id[2] && !share_id[3])
 		return NULL;
 	for (block = alloc->first; block; block = block->next)
-		if (!memcmp(share_id, block->share_id, sizeof(share_id)))
+		if (!memcmp(share_id, block->share_id,
+				sizeof(block->share_id)))
 			return block;
 	return NULL;
 }
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 9cfdb77..c848ec0 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -931,6 +931,7 @@
 #endif
 	list_del(&codec->list);
 	snd_array_free(&codec->mixers);
+	snd_array_free(&codec->nids);
 	codec->bus->caddr_tbl[codec->addr] = NULL;
 	if (codec->patch_ops.free)
 		codec->patch_ops.free(codec);
@@ -985,7 +986,8 @@
 	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 hda_nid_item), 60);
+	snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
+	snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32);
 	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) {
@@ -1706,7 +1708,7 @@
 EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
 
 /**
- * snd_hda_ctl-add - Add a control element and assign to the codec
+ * snd_hda_ctl_add - Add a control element and assign to the codec
  * @codec: HD-audio codec
  * @nid: corresponding NID (optional)
  * @kctl: the control element to assign
@@ -1721,19 +1723,25 @@
  *
  * snd_hda_ctl_add() checks the control subdev id field whether
  * #HDA_SUBDEV_NID_FLAG bit is set.  If set (and @nid is zero), the lower
- * bits value is taken as the NID to assign.
+ * bits value is taken as the NID to assign. The #HDA_NID_ITEM_AMP bit
+ * specifies if kctl->private_value is a HDA amplifier value.
  */
 int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
 		    struct snd_kcontrol *kctl)
 {
 	int err;
+	unsigned short flags = 0;
 	struct hda_nid_item *item;
 
-	if (kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) {
+	if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) {
+		flags |= HDA_NID_ITEM_AMP;
 		if (nid == 0)
-			nid = kctl->id.subdevice & 0xffff;
-		kctl->id.subdevice = 0;
+			nid = get_amp_nid_(kctl->private_value);
 	}
+	if ((kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) != 0 && nid == 0)
+		nid = kctl->id.subdevice & 0xffff;
+	if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG))
+		kctl->id.subdevice = 0;
 	err = snd_ctl_add(codec->bus->card, kctl);
 	if (err < 0)
 		return err;
@@ -1742,11 +1750,41 @@
 		return -ENOMEM;
 	item->kctl = kctl;
 	item->nid = nid;
+	item->flags = flags;
 	return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_ctl_add);
 
 /**
+ * snd_hda_add_nid - Assign a NID to a control element
+ * @codec: HD-audio codec
+ * @nid: corresponding NID (optional)
+ * @kctl: the control element to assign
+ * @index: index to kctl
+ *
+ * Add the given control element to an array inside the codec instance.
+ * This function is used when #snd_hda_ctl_add cannot be used for 1:1
+ * NID:KCTL mapping - for example "Capture Source" selector.
+ */
+int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
+		    unsigned int index, hda_nid_t nid)
+{
+	struct hda_nid_item *item;
+
+	if (nid > 0) {
+		item = snd_array_new(&codec->nids);
+		if (!item)
+			return -ENOMEM;
+		item->kctl = kctl;
+		item->index = index;
+		item->nid = nid;
+		return 0;
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_add_nid);
+
+/**
  * snd_hda_ctls_clear - Clear all controls assigned to the given codec
  * @codec: HD-audio codec
  */
@@ -1757,6 +1795,7 @@
 	for (i = 0; i < codec->mixers.used; i++)
 		snd_ctl_remove(codec->bus->card, items[i].kctl);
 	snd_array_free(&codec->mixers);
+	snd_array_free(&codec->nids);
 }
 
 /* pseudo device locking
@@ -3476,6 +3515,8 @@
 
 	for (; knew->name; knew++) {
 		struct snd_kcontrol *kctl;
+		if (knew->iface == -1)	/* skip this codec private value */
+			continue;
 		kctl = snd_ctl_new1(knew, codec);
 		if (!kctl)
 			return -ENOMEM;
@@ -3496,6 +3537,32 @@
 }
 EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);
 
+/**
+ * snd_hda_add_nids - assign nids to controls from the array
+ * @codec: the HDA codec
+ * @kctl: struct snd_kcontrol
+ * @index: index to kctl
+ * @nids: the array of hda_nid_t
+ * @size: count of hda_nid_t items
+ *
+ * This helper function assigns NIDs in the given array to a control element.
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl,
+		     unsigned int index, hda_nid_t *nids, unsigned int size)
+{
+	int err;
+
+	for ( ; size > 0; size--, nids++) {
+		err = snd_hda_add_nid(codec, kctl, index, *nids);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_add_nids);
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
 				unsigned int power_state);
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 1d541b7..0d08ad5 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -789,6 +789,7 @@
 	u32 *wcaps;
 
 	struct snd_array mixers;	/* list of assigned mixer elements */
+	struct snd_array nids;		/* list of mapped 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 092c6a7..5ea2128 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -861,7 +861,8 @@
 	}
 
 	/* create input MUX if multiple sources are available */
-	err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&cap_sel, codec));
+	err = snd_hda_ctl_add(codec, spec->adc_node->nid,
+			      snd_ctl_new1(&cap_sel, codec));
 	if (err < 0)
 		return err;
 
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index ff8ad46..d258569 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -2695,32 +2695,10 @@
 	/* ULI M5461 */
 	{ PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI },
 	/* NVIDIA MCP */
-	{ PCI_DEVICE(0x10de, 0x026c), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0371), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x03e4), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x03f0), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x044a), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x044b), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x055c), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x055d), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0590), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0774), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0775), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0776), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0777), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x07fc), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x07fd), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0ac0), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0be2), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0be3), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0be4), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA },
-	{ PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
+	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
+	  .class_mask = 0xffffff,
+	  .driver_data = AZX_DRIVER_NVIDIA },
 	/* Teradici */
 	{ PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
 	/* Creative X-Fi (CA0110-IBG) */
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 5778ae8..d505d05 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -31,6 +31,7 @@
  * in snd_hda_ctl_add(), so that this value won't appear in the outside.
  */
 #define HDA_SUBDEV_NID_FLAG	(1U << 31)
+#define HDA_SUBDEV_AMP_FLAG	(1U << 30)
 
 /*
  * for mixer controls
@@ -42,7 +43,7 @@
 /* mono volume with index (index=0,1,...) (channel=1,2) */
 #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx,  \
-	  .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
+	  .subdevice = HDA_SUBDEV_AMP_FLAG, \
 	  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
 	  	    SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
 	  	    SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
@@ -63,7 +64,7 @@
 /* mono mute switch with index (index=0,1,...) (channel=1,2) */
 #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
-	  .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
+	  .subdevice = HDA_SUBDEV_AMP_FLAG, \
 	  .info = snd_hda_mixer_amp_switch_info, \
 	  .get = snd_hda_mixer_amp_switch_get, \
 	  .put = snd_hda_mixer_amp_switch_put, \
@@ -81,7 +82,7 @@
 /* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */
 #define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
-	  .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
+	  .subdevice = HDA_SUBDEV_AMP_FLAG, \
 	  .info = snd_hda_mixer_amp_switch_info, \
 	  .get = snd_hda_mixer_amp_switch_get, \
 	  .put = snd_hda_mixer_amp_switch_put_beep, \
@@ -342,6 +343,8 @@
                                const struct snd_pci_quirk *tbl);
 int snd_hda_add_new_ctls(struct hda_codec *codec,
 			 struct snd_kcontrol_new *knew);
+int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl,
+		     unsigned int index, hda_nid_t *nids, unsigned int size);
 
 /*
  * unsolicited event handler
@@ -464,13 +467,20 @@
 u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
 int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
 
+/* flags for hda_nid_item */
+#define HDA_NID_ITEM_AMP	(1<<0)
+
 struct hda_nid_item {
 	struct snd_kcontrol *kctl;
+	unsigned int index;
 	hda_nid_t nid;
+	unsigned short flags;
 };
 
 int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
 		    struct snd_kcontrol *kctl);
+int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
+		    unsigned int index, hda_nid_t nid);
 void snd_hda_ctls_clear(struct hda_codec *codec);
 
 /*
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index c9afc04..f97d35d 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -61,18 +61,29 @@
 		return "UNKNOWN Widget";
 }
 
-static void print_nid_mixers(struct snd_info_buffer *buffer,
-			     struct hda_codec *codec, hda_nid_t nid)
+static void print_nid_array(struct snd_info_buffer *buffer,
+			    struct hda_codec *codec, hda_nid_t nid,
+			    struct snd_array *array)
 {
 	int i;
-	struct hda_nid_item *items = codec->mixers.list;
+	struct hda_nid_item *items = array->list, *item;
 	struct snd_kcontrol *kctl;
-	for (i = 0; i < codec->mixers.used; i++) {
-		if (items[i].nid == nid) {
-			kctl = items[i].kctl;
+	for (i = 0; i < array->used; i++) {
+		item = &items[i];
+		if (item->nid == nid) {
+			kctl = item->kctl;
 			snd_iprintf(buffer,
 			  "  Control: name=\"%s\", index=%i, device=%i\n",
-			  kctl->id.name, kctl->id.index, kctl->id.device);
+			  kctl->id.name, kctl->id.index + item->index,
+			  kctl->id.device);
+			if (item->flags & HDA_NID_ITEM_AMP)
+				snd_iprintf(buffer,
+				  "    ControlAmp: chs=%lu, dir=%s, "
+				  "idx=%lu, ofs=%lu\n",
+				  get_amp_channels(kctl),
+				  get_amp_direction(kctl) ? "Out" : "In",
+				  get_amp_index(kctl),
+				  get_amp_offset(kctl));
 		}
 	}
 }
@@ -528,7 +539,8 @@
 			    (data & (1<<i)) ? 1 : 0,
 			    (unsol & (1<<i)) ? 1 : 0);
 	/* FIXME: add GPO and GPI pin information */
-	print_nid_mixers(buffer, codec, nid);
+	print_nid_array(buffer, codec, nid, &codec->mixers);
+	print_nid_array(buffer, codec, nid, &codec->nids);
 }
 
 static void print_codec_info(struct snd_info_entry *entry,
@@ -608,7 +620,8 @@
 			snd_iprintf(buffer, " CP");
 		snd_iprintf(buffer, "\n");
 
-		print_nid_mixers(buffer, codec, nid);
+		print_nid_array(buffer, codec, nid, &codec->mixers);
+		print_nid_array(buffer, codec, nid, &codec->nids);
 		print_nid_pcms(buffer, codec, nid);
 
 		/* volume knob is a special widget that always have connection
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 1a36137..92b72d4 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -174,6 +174,7 @@
 static int ad198x_build_controls(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec = codec->spec;
+	struct snd_kcontrol *kctl;
 	unsigned int i;
 	int err;
 
@@ -208,9 +209,7 @@
 			if (!kctl)
 				return -ENOMEM;
 			kctl->private_value = spec->beep_amp;
-			err = snd_hda_ctl_add(codec,
-						get_amp_nid_(spec->beep_amp),
-						kctl);
+			err = snd_hda_ctl_add(codec, 0, kctl);
 			if (err < 0)
 				return err;
 		}
@@ -239,6 +238,28 @@
 	}
 
 	ad198x_free_kctls(codec); /* no longer needed */
+
+	/* assign Capture Source enums to NID */
+	kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
+	if (!kctl)
+		kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
+	for (i = 0; kctl && i < kctl->count; i++) {
+		err = snd_hda_add_nids(codec, kctl, i, spec->capsrc_nids,
+				       spec->input_mux->num_items);
+		if (err < 0)
+			return err;
+	}
+
+	/* assign IEC958 enums to NID */
+	kctl = snd_hda_find_mixer_ctl(codec,
+			SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
+	if (kctl) {
+		err = snd_hda_add_nid(codec, kctl, 0,
+				      spec->multiout.dig_out_nid);
+		if (err < 0)
+			return err;
+	}
+
 	return 0;
 }
 
@@ -701,6 +722,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "External Amplifier",
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
 		.info = ad198x_eapd_info,
 		.get = ad198x_eapd_get,
 		.put = ad198x_eapd_put,
@@ -808,6 +830,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
+		.subdevice = HDA_SUBDEV_AMP_FLAG,
 		.info = snd_hda_mixer_amp_switch_info,
 		.get = snd_hda_mixer_amp_switch_get,
 		.put = ad1986a_hp_master_sw_put,
@@ -1608,6 +1631,7 @@
 	HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
 		.name = "Master Playback Switch",
 		.info = ad198x_eapd_info,
 		.get = ad198x_eapd_get,
@@ -2129,6 +2153,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "External Amplifier",
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
 		.info = ad198x_eapd_info,
 		.get = ad198x_eapd_get,
 		.put = ad198x_eapd_put,
@@ -2250,6 +2275,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "IEC958 Playback Source",
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
 		.info = ad1988_spdif_playback_source_info,
 		.get = ad1988_spdif_playback_source_get,
 		.put = ad1988_spdif_playback_source_put,
@@ -2582,7 +2608,7 @@
 	if (! knew->name)
 		return -ENOMEM;
 	if (get_amp_nid_(val))
-		knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
+		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
 	knew->private_value = val;
 	return 0;
 }
@@ -3736,6 +3762,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
+		.subdevice = HDA_SUBDEV_AMP_FLAG,
 		.info = snd_hda_mixer_amp_switch_info,
 		.get = snd_hda_mixer_amp_switch_get,
 		.put = ad1884a_mobile_master_sw_put,
@@ -3764,6 +3791,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
+		.subdevice = HDA_SUBDEV_AMP_FLAG,
 		.info = snd_hda_mixer_amp_switch_info,
 		.get = snd_hda_mixer_amp_switch_get,
 		.put = ad1884a_mobile_master_sw_put,
@@ -4105,6 +4133,7 @@
 /*	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.subdevice = HDA_SUBDEV_AMP_FLAG,
 		.name = "Master Playback Switch",
 		.info = snd_hda_mixer_amp_switch_info,
 		.get = snd_hda_mixer_amp_switch_get,
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index fe0423c..093cfbb 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -501,7 +501,8 @@
 	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, get_amp_nid_(pval), *kctlp);
+	(*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG;
+	return snd_hda_ctl_add(codec, 0, *kctlp);
 }
 
 static int add_volume(struct hda_codec *codec, const char *name,
@@ -514,7 +515,8 @@
 	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, get_amp_nid_(pval), *kctlp);
+	(*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG;
+	return snd_hda_ctl_add(codec, 0, *kctlp);
 }
 
 static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
@@ -760,6 +762,10 @@
 		err = snd_hda_ctl_add(codec, 0, kctl);
 		if (err < 0)
 			return err;
+		err = snd_hda_add_nids(codec, kctl, 0, spec->adc_nid,
+				       spec->num_inputs);
+		if (err < 0)
+			return err;
 	}
 	
 	if (spec->num_inputs > 1 && !spec->mic_detect) {
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index a45c116..cc1c223 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -315,7 +315,8 @@
 static int cmi9880_build_controls(struct hda_codec *codec)
 {
 	struct cmi_spec *spec = codec->spec;
-	int err;
+	struct snd_kcontrol *kctl;
+	int i, err;
 
 	err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer);
 	if (err < 0)
@@ -340,6 +341,15 @@
 		if (err < 0)
 			return err;
 	}
+
+	/* assign Capture Source enums to NID */
+	kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
+	for (i = 0; kctl && i < kctl->count; i++) {
+		err = snd_hda_add_nids(codec, kctl, i, spec->adc_nids,
+				       spec->input_mux->num_items);
+		if (err < 0)
+			return err;
+	}
 	return 0;
 }
 
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index c578c28..947785f 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -2187,6 +2187,7 @@
 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
 				  SNDRV_CTL_ELEM_ACCESS_TLV_READ |
 				  SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+		.subdevice = HDA_SUBDEV_AMP_FLAG,
 		.info = snd_hda_mixer_amp_volume_info,
 		.get = snd_hda_mixer_amp_volume_get,
 		.put = snd_hda_mixer_amp_volume_put,
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 0877bae..e7cdc6a 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -633,6 +633,7 @@
 
 #define ALC_PIN_MODE(xname, nid, dir) \
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+	  .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
 	  .info = alc_pin_mode_info, \
 	  .get = alc_pin_mode_get, \
 	  .put = alc_pin_mode_put, \
@@ -684,6 +685,7 @@
 }
 #define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+	  .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
 	  .info = alc_gpio_data_info, \
 	  .get = alc_gpio_data_get, \
 	  .put = alc_gpio_data_put, \
@@ -738,6 +740,7 @@
 }
 #define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+	  .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
 	  .info = alc_spdif_ctrl_info, \
 	  .get = alc_spdif_ctrl_get, \
 	  .put = alc_spdif_ctrl_put, \
@@ -791,6 +794,7 @@
 
 #define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+	  .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
 	  .info = alc_eapd_ctrl_info, \
 	  .get = alc_eapd_ctrl_get, \
 	  .put = alc_eapd_ctrl_put, \
@@ -2443,6 +2447,15 @@
  * build control elements
  */
 
+#define NID_MAPPING		(-1)
+
+#define SUBDEV_SPEAKER_		(0 << 6)
+#define SUBDEV_HP_		(1 << 6)
+#define SUBDEV_LINE_		(2 << 6)
+#define SUBDEV_SPEAKER(x)	(SUBDEV_SPEAKER_ | ((x) & 0x3f))
+#define SUBDEV_HP(x)		(SUBDEV_HP_ | ((x) & 0x3f))
+#define SUBDEV_LINE(x)		(SUBDEV_LINE_ | ((x) & 0x3f))
+
 static void alc_free_kctls(struct hda_codec *codec);
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
@@ -2457,8 +2470,11 @@
 static int alc_build_controls(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	int err;
-	int i;
+	struct snd_kcontrol *kctl;
+	struct snd_kcontrol_new *knew;
+	int i, j, err;
+	unsigned int u;
+	hda_nid_t nid;
 
 	for (i = 0; i < spec->num_mixers; i++) {
 		err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
@@ -2499,8 +2515,7 @@
 			if (!kctl)
 				return -ENOMEM;
 			kctl->private_value = spec->beep_amp;
-			err = snd_hda_ctl_add(codec,
-					get_amp_nid_(spec->beep_amp), kctl);
+			err = snd_hda_ctl_add(codec, 0, kctl);
 			if (err < 0)
 				return err;
 		}
@@ -2527,6 +2542,76 @@
 	}
 
 	alc_free_kctls(codec); /* no longer needed */
+
+	/* assign Capture Source enums to NID */
+	kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
+	if (!kctl)
+		kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
+	for (i = 0; kctl && i < kctl->count; i++) {
+		hda_nid_t *nids = spec->capsrc_nids;
+		if (!nids)
+			nids = spec->adc_nids;
+		err = snd_hda_add_nids(codec, kctl, i, nids,
+				       spec->input_mux->num_items);
+		if (err < 0)
+			return err;
+	}
+	if (spec->cap_mixer) {
+		const char *kname = kctl ? kctl->id.name : NULL;
+		for (knew = spec->cap_mixer; knew->name; knew++) {
+			if (kname && strcmp(knew->name, kname) == 0)
+				continue;
+			kctl = snd_hda_find_mixer_ctl(codec, knew->name);
+			for (i = 0; kctl && i < kctl->count; i++) {
+				err = snd_hda_add_nid(codec, kctl, i,
+						      spec->adc_nids[i]);
+				if (err < 0)
+					return err;
+			}
+		}
+	}
+
+	/* other nid->control mapping */
+	for (i = 0; i < spec->num_mixers; i++) {
+		for (knew = spec->mixers[i]; knew->name; knew++) {
+			if (knew->iface != NID_MAPPING)
+				continue;
+			kctl = snd_hda_find_mixer_ctl(codec, knew->name);
+			if (kctl == NULL)
+				continue;
+			u = knew->subdevice;
+			for (j = 0; j < 4; j++, u >>= 8) {
+				nid = u & 0x3f;
+				if (nid == 0)
+					continue;
+				switch (u & 0xc0) {
+				case SUBDEV_SPEAKER_:
+					nid = spec->autocfg.speaker_pins[nid];
+					break;
+				case SUBDEV_LINE_:
+					nid = spec->autocfg.line_out_pins[nid];
+					break;
+				case SUBDEV_HP_:
+					nid = spec->autocfg.hp_pins[nid];
+					break;
+				default:
+					continue;
+				}
+				err = snd_hda_add_nid(codec, kctl, 0, nid);
+				if (err < 0)
+					return err;
+			}
+			u = knew->private_value;
+			for (j = 0; j < 4; j++, u >>= 8) {
+				nid = u & 0xff;
+				if (nid == 0)
+					continue;
+				err = snd_hda_add_nid(codec, kctl, 0, nid);
+				if (err < 0)
+					return err;
+			}
+		}
+	}
 	return 0;
 }
 
@@ -3832,6 +3917,7 @@
 #define PIN_CTL_TEST(xname,nid) {			\
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	\
 			.name = xname,		       \
+			.subdevice = HDA_SUBDEV_NID_FLAG | nid, \
 			.info = alc_test_pin_ctl_info, \
 			.get = alc_test_pin_ctl_get,   \
 			.put = alc_test_pin_ctl_put,   \
@@ -3841,6 +3927,7 @@
 #define PIN_SRC_TEST(xname,nid) {			\
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	\
 			.name = xname,		       \
+			.subdevice = HDA_SUBDEV_NID_FLAG | nid, \
 			.info = alc_test_pin_src_info, \
 			.get = alc_test_pin_src_get,   \
 			.put = alc_test_pin_src_put,   \
@@ -4380,7 +4467,7 @@
 	if (!knew->name)
 		return -ENOMEM;
 	if (get_amp_nid_(val))
-		knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
+		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
 	knew->private_value = val;
 	return 0;
 }
@@ -5131,6 +5218,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
 		.info = snd_ctl_boolean_mono_info,
 		.get = alc260_hp_master_sw_get,
 		.put = alc260_hp_master_sw_put,
@@ -5169,6 +5257,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
+		.subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
 		.info = snd_ctl_boolean_mono_info,
 		.get = alc260_hp_master_sw_get,
 		.put = alc260_hp_master_sw_put,
@@ -10248,8 +10337,14 @@
 		.info = snd_ctl_boolean_mono_info,		\
 		.get = alc262_hp_master_sw_get,			\
 		.put = alc262_hp_master_sw_put,			\
+	}, \
+	{							\
+		.iface = NID_MAPPING,				\
+		.name = "Master Playback Switch",		\
+		.private_value = 0x15 | (0x16 << 8) | (0x1b << 16),	\
 	}
 
+
 static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
 	ALC262_HP_MASTER_SWITCH,
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
@@ -10407,6 +10502,12 @@
 		.info = snd_ctl_boolean_mono_info,		\
 		.get = alc262_hippo_master_sw_get,		\
 		.put = alc262_hippo_master_sw_put,		\
+	},							\
+	{							\
+		.iface = NID_MAPPING,				\
+		.name = "Master Playback Switch",		\
+		.subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
+			     (SUBDEV_SPEAKER(0) << 16), \
 	}
 
 static struct snd_kcontrol_new alc262_hippo_mixer[] = {
@@ -10887,11 +10988,17 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
+		.subdevice = HDA_SUBDEV_AMP_FLAG,
 		.info = snd_hda_mixer_amp_switch_info,
 		.get = snd_hda_mixer_amp_switch_get,
 		.put = alc262_fujitsu_master_sw_put,
 		.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 	},
+	{
+		.iface = NID_MAPPING,
+		.name = "Master Playback Switch",
+		.private_value = 0x1b,
+	},
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
@@ -10922,6 +11029,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
+		.subdevice = HDA_SUBDEV_AMP_FLAG,
 		.info = snd_hda_mixer_amp_switch_info,
 		.get = snd_hda_mixer_amp_switch_get,
 		.put = alc262_lenovo_3000_master_sw_put,
@@ -11076,6 +11184,11 @@
 		.get = alc_mux_enum_get,
 		.put = alc262_ultra_mux_enum_put,
 	},
+	{
+		.iface = NID_MAPPING,
+		.name = "Capture Source",
+		.private_value = 0x15,
+	},
 	{ } /* end */
 };
 
@@ -12094,6 +12207,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
+		.subdevice = HDA_SUBDEV_AMP_FLAG,
 		.info = snd_hda_mixer_amp_switch_info,
 		.get = snd_hda_mixer_amp_switch_get,
 		.put = alc268_acer_master_sw_put,
@@ -12109,6 +12223,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
+		.subdevice = HDA_SUBDEV_AMP_FLAG,
 		.info = snd_hda_mixer_amp_switch_info,
 		.get = snd_hda_mixer_amp_switch_get,
 		.put = alc268_acer_master_sw_put,
@@ -12126,6 +12241,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
+		.subdevice = HDA_SUBDEV_AMP_FLAG,
 		.info = snd_hda_mixer_amp_switch_info,
 		.get = snd_hda_mixer_amp_switch_get,
 		.put = alc268_acer_master_sw_put,
@@ -13078,6 +13194,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
+		.subdevice = HDA_SUBDEV_AMP_FLAG,
 		.info = snd_hda_mixer_amp_switch_info,
 		.get = snd_hda_mixer_amp_switch_get,
 		.put = alc268_acer_master_sw_put,
@@ -13098,6 +13215,7 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Master Playback Switch",
+		.subdevice = HDA_SUBDEV_AMP_FLAG,
 		.info = snd_hda_mixer_amp_switch_info,
 		.get = snd_hda_mixer_amp_switch_get,
 		.put = alc268_acer_master_sw_put,
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index 43b436c..f419ee8 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -122,6 +122,7 @@
 #define SI3054_KCONTROL(kname,reg,mask) { \
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
 	.name = kname, \
+	.subdevice = HDA_SUBDEV_NID_FLAG | reg, \
 	.info = si3054_switch_info, \
 	.get  = si3054_switch_get, \
 	.put  = si3054_switch_put, \
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 417fb22..2f08b43 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -2685,7 +2685,7 @@
 stac_control_new(struct sigmatel_spec *spec,
 		 struct snd_kcontrol_new *ktemp,
 		 const char *name,
-		 hda_nid_t nid)
+		 unsigned int subdev)
 {
 	struct snd_kcontrol_new *knew;
 
@@ -2701,8 +2701,7 @@
 		spec->kctls.alloced--;
 		return NULL;
 	}
-	if (nid)
-		knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
+	knew->subdevice = subdev;
 	return knew;
 }
 
@@ -2712,7 +2711,7 @@
 				     unsigned long val)
 {
 	struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name,
-							 get_amp_nid_(val));
+							 HDA_SUBDEV_AMP_FLAG);
 	if (!knew)
 		return -ENOMEM;
 	knew->index = idx;
@@ -5404,6 +5403,54 @@
 		return 0;
 }
 
+/* HP dv7 bass switch - GPIO5 */
+#define stac_hp_bass_gpio_info	snd_ctl_boolean_mono_info
+static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20);
+	return 0;
+}
+
+static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	unsigned int gpio_data;
+
+	gpio_data = (spec->gpio_data & ~0x20) |
+		(ucontrol->value.integer.value[0] ? 0x20 : 0);
+	if (gpio_data == spec->gpio_data)
+		return 0;
+	spec->gpio_data = gpio_data;
+	stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
+	return 1;
+}
+
+static struct snd_kcontrol_new stac_hp_bass_sw_ctrl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.info = stac_hp_bass_gpio_info,
+	.get = stac_hp_bass_gpio_get,
+	.put = stac_hp_bass_gpio_put,
+};
+
+static int stac_add_hp_bass_switch(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+
+	if (!stac_control_new(spec, &stac_hp_bass_sw_ctrl,
+			      "Bass Speaker Playback Switch", 0))
+		return -ENOMEM;
+
+	spec->gpio_mask |= 0x20;
+	spec->gpio_dir |= 0x20;
+	spec->gpio_data |= 0x20;
+	return 0;
+}
+
 static int patch_stac92hd71bxx(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
@@ -5644,6 +5691,15 @@
 		return err;
 	}
 
+	/* enable bass on HP dv7 */
+	if (spec->board_config == STAC_HP_DV5) {
+		unsigned int cap;
+		cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP);
+		cap &= AC_GPIO_IO_COUNT;
+		if (cap >= 6)
+			stac_add_hp_bass_switch(codec);
+	}
+
 	codec->proc_widget_hook = stac92hd7x_proc_hook;
 
 	return 0;
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index b70e26a..de4839e 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -54,6 +54,8 @@
 #include "hda_codec.h"
 #include "hda_local.h"
 
+#define NID_MAPPING		(-1)
+
 /* amp values */
 #define AMP_VAL_IDX_SHIFT	19
 #define AMP_VAL_IDX_MASK	(0x0f<<19)
@@ -157,6 +159,19 @@
 #endif
 };
 
+static struct via_spec * via_new_spec(struct hda_codec *codec)
+{
+	struct via_spec *spec;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return NULL;
+
+	codec->spec = spec;
+	spec->codec = codec;
+	return spec;
+}
+
 static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
 {
 	u32 vendor_id = codec->vendor_id;
@@ -443,11 +458,27 @@
 	if (!knew->name)
 		return -ENOMEM;
 	if (get_amp_nid_(val))
-		knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val);
+		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
 	knew->private_value = val;
 	return 0;
 }
 
+static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec,
+						struct snd_kcontrol_new *tmpl)
+{
+	struct snd_kcontrol_new *knew;
+
+	snd_array_init(&spec->kctls, sizeof(*knew), 32);
+	knew = snd_array_new(&spec->kctls);
+	if (!knew)
+		return NULL;
+	*knew = *tmpl;
+	knew->name = kstrdup(tmpl->name, GFP_KERNEL);
+	if (!knew->name)
+		return NULL;
+	return 0;
+}
+
 static void via_free_kctls(struct hda_codec *codec)
 {
 	struct via_spec *spec = codec->spec;
@@ -1088,24 +1119,9 @@
 				  struct snd_ctl_elem_value *ucontrol)
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct via_spec *spec = codec->spec;
-	hda_nid_t nid;
+	hda_nid_t nid = kcontrol->private_value;
 	unsigned int pinsel;
 
-	switch (spec->codec_type) {
-	case VT1718S:
-		nid = 0x34;
-		break;
-	case VT2002P:
-		nid = 0x35;
-		break;
-	case VT1812:
-		nid = 0x3d;
-		break;
-	default:
-		nid = spec->autocfg.hp_pins[0];
-		break;
-	}
 	/* use !! to translate conn sel 2 for VT1718S */
 	pinsel = !!snd_hda_codec_read(codec, nid, 0,
 				      AC_VERB_GET_CONNECT_SEL,
@@ -1127,29 +1143,24 @@
 	}
 }
 
+static hda_nid_t side_mute_channel(struct via_spec *spec)
+{
+	switch (spec->codec_type) {
+	case VT1708:		return 0x1b;
+	case VT1709_10CH:	return 0x29;
+	case VT1708B_8CH:	/* fall thru */
+	case VT1708S:		return 0x27;
+	default:		return 0;
+	}
+}
+
 static int update_side_mute_status(struct hda_codec *codec)
 {
 	/* mute side channel */
 	struct via_spec *spec = codec->spec;
 	unsigned int parm = spec->hp_independent_mode
 		? AMP_OUT_MUTE : AMP_OUT_UNMUTE;
-	hda_nid_t sw3;
-
-	switch (spec->codec_type) {
-	case VT1708:
-		sw3 = 0x1b;
-		break;
-	case VT1709_10CH:
-		sw3 = 0x29;
-		break;
-	case VT1708B_8CH:
-	case VT1708S:
-		sw3 = 0x27;
-		break;
-	default:
-		sw3 = 0;
-		break;
-	}
+	hda_nid_t sw3 = side_mute_channel(spec);
 
 	if (sw3)
 		snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE,
@@ -1162,28 +1173,11 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct via_spec *spec = codec->spec;
-	hda_nid_t nid = spec->autocfg.hp_pins[0];
+	hda_nid_t nid = kcontrol->private_value;
 	unsigned int pinsel = ucontrol->value.enumerated.item[0];
 	/* Get Independent Mode index of headphone pin widget */
 	spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
 		? 1 : 0;
-
-	switch (spec->codec_type) {
-	case VT1718S:
-		nid = 0x34;
-		pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */
-		spec->multiout.num_dacs = 4;
-		break;
-	case VT2002P:
-		nid = 0x35;
-		break;
-	case VT1812:
-		nid = 0x3d;
-		break;
-	default:
-		nid = spec->autocfg.hp_pins[0];
-		break;
-	}
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel);
 
 	if (spec->multiout.hp_nid && spec->multiout.hp_nid
@@ -1207,18 +1201,55 @@
 	return 0;
 }
 
-static struct snd_kcontrol_new via_hp_mixer[] = {
+static struct snd_kcontrol_new via_hp_mixer[2] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Independent HP",
-		.count = 1,
 		.info = via_independent_hp_info,
 		.get = via_independent_hp_get,
 		.put = via_independent_hp_put,
 	},
-	{ } /* end */
+	{
+		.iface = NID_MAPPING,
+		.name = "Independent HP",
+	},
 };
 
+static int via_hp_build(struct via_spec *spec)
+{
+	struct snd_kcontrol_new *knew;
+	hda_nid_t nid;
+
+	knew = via_clone_control(spec, &via_hp_mixer[0]);
+	if (knew == NULL)
+		return -ENOMEM;
+
+	switch (spec->codec_type) {
+	case VT1718S:
+		nid = 0x34;
+		break;
+	case VT2002P:
+		nid = 0x35;
+		break;
+	case VT1812:
+		nid = 0x3d;
+		break;
+	default:
+		nid = spec->autocfg.hp_pins[0];
+		break;
+	}
+
+	knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
+	knew->private_value = nid;
+
+	knew = via_clone_control(spec, &via_hp_mixer[1]);
+	if (knew == NULL)
+		return -ENOMEM;
+	knew->subdevice = side_mute_channel(spec);
+
+	return 0;
+}
+
 static void notify_aa_path_ctls(struct hda_codec *codec)
 {
 	int i;
@@ -1376,7 +1407,7 @@
 	return 1;
 }
 
-static struct snd_kcontrol_new via_smart51_mixer[] = {
+static struct snd_kcontrol_new via_smart51_mixer[2] = {
 	{
 	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	 .name = "Smart 5.1",
@@ -1385,9 +1416,36 @@
 	 .get = via_smart51_get,
 	 .put = via_smart51_put,
 	 },
-	{}			/* end */
+	{
+	 .iface = NID_MAPPING,
+	 .name = "Smart 5.1",
+	}
 };
 
+static int via_smart51_build(struct via_spec *spec)
+{
+	struct snd_kcontrol_new *knew;
+	int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
+	hda_nid_t nid;
+	int i;
+
+	knew = via_clone_control(spec, &via_smart51_mixer[0]);
+	if (knew == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(index); i++) {
+		nid = spec->autocfg.input_pins[index[i]];
+		if (nid) {
+			knew = via_clone_control(spec, &via_smart51_mixer[1]);
+			if (knew == NULL)
+				return -ENOMEM;
+			knew->subdevice = nid;
+		}
+	}
+
+	return 0;
+}
+
 /* capture mixer elements */
 static struct snd_kcontrol_new vt1708_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
@@ -1819,8 +1877,9 @@
 static int via_build_controls(struct hda_codec *codec)
 {
 	struct via_spec *spec = codec->spec;
-	int err;
-	int i;
+	struct snd_kcontrol *kctl;
+	struct snd_kcontrol_new *knew;
+	int err, i;
 
 	for (i = 0; i < spec->num_mixers; i++) {
 		err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
@@ -1845,6 +1904,28 @@
 			return err;
 	}
 
+	/* assign Capture Source enums to NID */
+	kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
+	for (i = 0; kctl && i < kctl->count; i++) {
+		err = snd_hda_add_nids(codec, kctl, i, spec->mux_nids,
+				       spec->input_mux->num_items);
+		if (err < 0)
+			return err;
+	}
+
+	/* other nid->control mapping */
+	for (i = 0; i < spec->num_mixers; i++) {
+		for (knew = spec->mixers[i]; knew->name; knew++) {
+			if (knew->iface != NID_MAPPING)
+				continue;
+			kctl = snd_hda_find_mixer_ctl(codec, knew->name);
+			if (kctl == NULL)
+				continue;
+			err = snd_hda_add_nid(codec, kctl, 0,
+					      knew->subdevice);
+		}
+	}
+
 	/* init power states */
 	set_jack_power_state(codec);
 	analog_low_current_mode(codec, 1);
@@ -2481,9 +2562,9 @@
 	spec->input_mux = &spec->private_imux[0];
 
 	if (spec->hp_mux)
-		spec->mixers[spec->num_mixers++] = via_hp_mixer;
+		via_hp_build(spec);
 
-	spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+	via_smart51_build(spec);
 	return 1;
 }
 
@@ -2554,12 +2635,10 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	spec = via_new_spec(codec);
 	if (spec == NULL)
 		return -ENOMEM;
 
-	codec->spec = spec;
-
 	/* automatic parse from the BIOS config */
 	err = vt1708_parse_auto_config(codec);
 	if (err < 0) {
@@ -2597,7 +2676,6 @@
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	spec->loopback.amplist = vt1708_loopbacks;
 #endif
-	spec->codec = codec;
 	INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state);
 	return 0;
 }
@@ -3010,9 +3088,9 @@
 	spec->input_mux = &spec->private_imux[0];
 
 	if (spec->hp_mux)
-		spec->mixers[spec->num_mixers++] = via_hp_mixer;
+		via_hp_build(spec);
 
-	spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+	via_smart51_build(spec);
 	return 1;
 }
 
@@ -3032,12 +3110,10 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	spec = via_new_spec(codec);
 	if (spec == NULL)
 		return -ENOMEM;
 
-	codec->spec = spec;
-
 	err = vt1709_parse_auto_config(codec);
 	if (err < 0) {
 		via_free(codec);
@@ -3126,12 +3202,10 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	spec = via_new_spec(codec);
 	if (spec == NULL)
 		return -ENOMEM;
 
-	codec->spec = spec;
-
 	err = vt1709_parse_auto_config(codec);
 	if (err < 0) {
 		via_free(codec);
@@ -3581,9 +3655,9 @@
 	spec->input_mux = &spec->private_imux[0];
 
 	if (spec->hp_mux)
-		spec->mixers[spec->num_mixers++] = via_hp_mixer;
+		via_hp_build(spec);
 
-	spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+	via_smart51_build(spec);
 	return 1;
 }
 
@@ -3605,12 +3679,10 @@
 	if (get_codec_type(codec) == VT1708BCE)
 		return patch_vt1708S(codec);
 	/* create a codec specific record */
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	spec = via_new_spec(codec);
 	if (spec == NULL)
 		return -ENOMEM;
 
-	codec->spec = spec;
-
 	/* automatic parse from the BIOS config */
 	err = vt1708B_parse_auto_config(codec);
 	if (err < 0) {
@@ -3657,12 +3729,10 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	spec = via_new_spec(codec);
 	if (spec == NULL)
 		return -ENOMEM;
 
-	codec->spec = spec;
-
 	/* automatic parse from the BIOS config */
 	err = vt1708B_parse_auto_config(codec);
 	if (err < 0) {
@@ -4071,9 +4141,9 @@
 	spec->input_mux = &spec->private_imux[0];
 
 	if (spec->hp_mux)
-		spec->mixers[spec->num_mixers++] = via_hp_mixer;
+		via_hp_build(spec);
 
-	spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+	via_smart51_build(spec);
 	return 1;
 }
 
@@ -4103,12 +4173,10 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	spec = via_new_spec(codec);
 	if (spec == NULL)
 		return -ENOMEM;
 
-	codec->spec = spec;
-
 	/* automatic parse from the BIOS config */
 	err = vt1708S_parse_auto_config(codec);
 	if (err < 0) {
@@ -4443,7 +4511,7 @@
 	spec->input_mux = &spec->private_imux[0];
 
 	if (spec->hp_mux)
-		spec->mixers[spec->num_mixers++] = via_hp_mixer;
+		via_hp_build(spec);
 
 	return 1;
 }
@@ -4464,12 +4532,10 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	spec = via_new_spec(codec);
 	if (spec == NULL)
 		return -ENOMEM;
 
-	codec->spec = spec;
-
 	/* automatic parse from the BIOS config */
 	err = vt1702_parse_auto_config(codec);
 	if (err < 0) {
@@ -4865,9 +4931,9 @@
 	spec->input_mux = &spec->private_imux[0];
 
 	if (spec->hp_mux)
-		spec->mixers[spec->num_mixers++] = via_hp_mixer;
+		via_hp_build(spec);
 
-	spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+	via_smart51_build(spec);
 
 	return 1;
 }
@@ -4888,12 +4954,10 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	spec = via_new_spec(codec);
 	if (spec == NULL)
 		return -ENOMEM;
 
-	codec->spec = spec;
-
 	/* automatic parse from the BIOS config */
 	err = vt1718S_parse_auto_config(codec);
 	if (err < 0) {
@@ -5014,6 +5078,7 @@
 	{
 	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	 .name = "Digital Mic Capture Switch",
+	 .subdevice = HDA_SUBDEV_NID_FLAG | 0x26,
 	 .count = 1,
 	 .info = vt1716s_dmic_info,
 	 .get = vt1716s_dmic_get,
@@ -5361,9 +5426,9 @@
 	spec->input_mux = &spec->private_imux[0];
 
 	if (spec->hp_mux)
-		spec->mixers[spec->num_mixers++] = via_hp_mixer;
+		via_hp_build(spec);
 
-	spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+	via_smart51_build(spec);
 
 	return 1;
 }
@@ -5384,12 +5449,10 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	spec = via_new_spec(codec);
 	if (spec == NULL)
 		return -ENOMEM;
 
-	codec->spec = spec;
-
 	/* automatic parse from the BIOS config */
 	err = vt1716S_parse_auto_config(codec);
 	if (err < 0) {
@@ -5719,7 +5782,7 @@
 	spec->input_mux = &spec->private_imux[0];
 
 	if (spec->hp_mux)
-		spec->mixers[spec->num_mixers++] = via_hp_mixer;
+		via_hp_build(spec);
 
 	return 1;
 }
@@ -5741,12 +5804,10 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	spec = via_new_spec(codec);
 	if (spec == NULL)
 		return -ENOMEM;
 
-	codec->spec = spec;
-
 	/* automatic parse from the BIOS config */
 	err = vt2002P_parse_auto_config(codec);
 	if (err < 0) {
@@ -6070,7 +6131,7 @@
 	spec->input_mux = &spec->private_imux[0];
 
 	if (spec->hp_mux)
-		spec->mixers[spec->num_mixers++] = via_hp_mixer;
+		via_hp_build(spec);
 
 	return 1;
 }
@@ -6092,12 +6153,10 @@
 	int err;
 
 	/* create a codec specific record */
-	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	spec = via_new_spec(codec);
 	if (spec == NULL)
 		return -ENOMEM;
 
-	codec->spec = spec;
-
 	/* automatic parse from the BIOS config */
 	err = vt1812_parse_auto_config(codec);
 	if (err < 0) {
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index c9438dd..dbc368c 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -199,7 +199,7 @@
 	snd_soc_write(codec, WM8900_REG_RESET, 0);
 
 	memcpy(codec->reg_cache, wm8900_reg_defaults,
-	       sizeof(codec->reg_cache));
+	       sizeof(wm8900_reg_defaults));
 }
 
 static int wm8900_hp_event(struct snd_soc_dapm_widget *w,