Merge branch 'fix/hda' into topic/hda
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 1482921..08d81b8 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -4372,6 +4372,34 @@
 }
 
 
+/* add the found input-pin to the cfg->inputs[] table */
+static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
+				   int type)
+{
+	if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
+		cfg->inputs[cfg->num_inputs].pin = nid;
+		cfg->inputs[cfg->num_inputs].type = type;
+		cfg->num_inputs++;
+	}
+}
+
+/* sort inputs in the order of AUTO_PIN_* type */
+static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
+{
+	int i, j;
+
+	for (i = 0; i < cfg->num_inputs; i++) {
+		for (j = i + 1; j < cfg->num_inputs; j++) {
+			if (cfg->inputs[i].type > cfg->inputs[j].type) {
+				struct auto_pin_cfg_item tmp;
+				tmp = cfg->inputs[i];
+				cfg->inputs[i] = cfg->inputs[j];
+				cfg->inputs[j] = tmp;
+			}
+		}
+	}
+}
+
 /*
  * Parse all pin widgets and store the useful pin nids to cfg
  *
@@ -4385,7 +4413,7 @@
  * output, i.e. to line_out_pins[0].  So, line_outs is always positive
  * if any analog output exists.
  *
- * The analog input pins are assigned to input_pins array.
+ * The analog input pins are assigned to inputs array.
  * The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
  * respectively.
  */
@@ -4398,6 +4426,7 @@
 	short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
 	short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
 	short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
+	int i;
 
 	memset(cfg, 0, sizeof(*cfg));
 
@@ -4468,33 +4497,17 @@
 			sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
 			cfg->hp_outs++;
 			break;
-		case AC_JACK_MIC_IN: {
-			int preferred, alt;
-			if (loc == AC_JACK_LOC_FRONT ||
-			    (loc & 0x30) == AC_JACK_LOC_INTERNAL) {
-				preferred = AUTO_PIN_FRONT_MIC;
-				alt = AUTO_PIN_MIC;
-			} else {
-				preferred = AUTO_PIN_MIC;
-				alt = AUTO_PIN_FRONT_MIC;
-			}
-			if (!cfg->input_pins[preferred])
-				cfg->input_pins[preferred] = nid;
-			else if (!cfg->input_pins[alt])
-				cfg->input_pins[alt] = nid;
+		case AC_JACK_MIC_IN:
+			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
 			break;
-		}
 		case AC_JACK_LINE_IN:
-			if (loc == AC_JACK_LOC_FRONT)
-				cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid;
-			else
-				cfg->input_pins[AUTO_PIN_LINE] = nid;
+			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
 			break;
 		case AC_JACK_CD:
-			cfg->input_pins[AUTO_PIN_CD] = nid;
+			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
 			break;
 		case AC_JACK_AUX:
-			cfg->input_pins[AUTO_PIN_AUX] = nid;
+			add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
 			break;
 		case AC_JACK_SPDIF_OUT:
 		case AC_JACK_DIG_OTHER_OUT:
@@ -4539,6 +4552,8 @@
 			memmove(sequences_hp + i, sequences_hp + i + 1,
 				sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
 		}
+		memset(cfg->hp_pins + cfg->hp_outs, 0,
+		       sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
 	}
 
 	/* sort by sequence */
@@ -4549,21 +4564,6 @@
 	sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
 			      cfg->hp_outs);
 
-	/* if we have only one mic, make it AUTO_PIN_MIC */
-	if (!cfg->input_pins[AUTO_PIN_MIC] &&
-	    cfg->input_pins[AUTO_PIN_FRONT_MIC]) {
-		cfg->input_pins[AUTO_PIN_MIC] =
-			cfg->input_pins[AUTO_PIN_FRONT_MIC];
-		cfg->input_pins[AUTO_PIN_FRONT_MIC] = 0;
-	}
-	/* ditto for line-in */
-	if (!cfg->input_pins[AUTO_PIN_LINE] &&
-	    cfg->input_pins[AUTO_PIN_FRONT_LINE]) {
-		cfg->input_pins[AUTO_PIN_LINE] =
-			cfg->input_pins[AUTO_PIN_FRONT_LINE];
-		cfg->input_pins[AUTO_PIN_FRONT_LINE] = 0;
-	}
-
 	/*
 	 * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
 	 * as a primary output
@@ -4602,6 +4602,8 @@
 		break;
 	}
 
+	sort_autocfg_input_pins(cfg);
+
 	/*
 	 * debug prints of the parsed results
 	 */
@@ -4621,14 +4623,13 @@
 	if (cfg->dig_outs)
 		snd_printd("   dig-out=0x%x/0x%x\n",
 			   cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
-	snd_printd("   inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
-		   " cd=0x%x, aux=0x%x\n",
-		   cfg->input_pins[AUTO_PIN_MIC],
-		   cfg->input_pins[AUTO_PIN_FRONT_MIC],
-		   cfg->input_pins[AUTO_PIN_LINE],
-		   cfg->input_pins[AUTO_PIN_FRONT_LINE],
-		   cfg->input_pins[AUTO_PIN_CD],
-		   cfg->input_pins[AUTO_PIN_AUX]);
+	snd_printd("   inputs:");
+	for (i = 0; i < cfg->num_inputs; i++) {
+		snd_printdd(" %s=0x%x",
+			    hda_get_autocfg_input_label(codec, cfg, i),
+			    cfg->inputs[i].pin);
+	}
+	snd_printd("\n");
 	if (cfg->dig_in_pin)
 		snd_printd("   dig-in=0x%x\n", cfg->dig_in_pin);
 
@@ -4636,11 +4637,174 @@
 }
 EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config);
 
-/* labels for input pins */
-const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = {
-	"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"
+enum {
+	MIC_ATTR_INT,
+	MIC_ATTR_DOCK,
+	MIC_ATTR_NORMAL,
+	MIC_ATTR_FRONT,
+	MIC_ATTR_REAR,
 };
-EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
+
+static int get_mic_pin_attr(unsigned int def_conf)
+{
+	unsigned int loc = get_defcfg_location(def_conf);
+	if (get_defcfg_connect(def_conf) == AC_JACK_PORT_FIXED ||
+	    (loc & 0x30) == AC_JACK_LOC_INTERNAL)
+		return MIC_ATTR_INT;
+	if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
+		return MIC_ATTR_DOCK;
+	if (loc == AC_JACK_LOC_REAR)
+		return MIC_ATTR_REAR;
+	if (loc == AC_JACK_LOC_FRONT)
+		return MIC_ATTR_FRONT;
+	return MIC_ATTR_NORMAL;
+}
+
+enum {
+	LINE_ATTR_DOCK,
+	LINE_ATTR_NORMAL,
+};
+
+static int get_line_pin_attr(unsigned int def_conf)
+{
+	unsigned int loc = get_defcfg_location(def_conf);
+	if ((loc & 0xf0) == AC_JACK_LOC_SEPARATE)
+		return LINE_ATTR_DOCK;
+	return LINE_ATTR_NORMAL;
+}
+
+/**
+ * hda_get_input_pin_label - Give a label for the given input pin
+ *
+ * When check_location is true, the function checks the pin location
+ * for mic and line-in pins, and set an appropriate prefix like "Front",
+ * "Rear", "Internal".
+ */
+
+const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
+					int check_location)
+{
+	unsigned int def_conf;
+	static const char *mic_names[] = {
+		"Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
+	};
+	static const char *line_names[] = {
+		"Dock Line", "Line",
+	};
+
+	def_conf = snd_hda_codec_get_pincfg(codec, pin);
+
+	switch (get_defcfg_device(def_conf)) {
+	case AC_JACK_MIC_IN:
+		if (!check_location)
+			return "Mic";
+		return mic_names[get_mic_pin_attr(def_conf)];
+	case AC_JACK_LINE_IN:
+		if (!check_location)
+			return "Line";
+		return line_names[get_line_pin_attr(def_conf)];
+	case AC_JACK_AUX:
+		return "Aux";
+	case AC_JACK_CD:
+		return "CD";
+	case AC_JACK_SPDIF_IN:
+		return "SPDIF In";
+	case AC_JACK_DIG_OTHER_IN:
+		return "Digital In";
+	default:
+		return "Misc";
+	}
+}
+EXPORT_SYMBOL_HDA(hda_get_input_pin_label);
+
+/* Check whether the location prefix needs to be added to the label.
+ * If all mic-jacks are in the same location (e.g. rear panel), we don't
+ * have to put "Front" prefix to each label.  In such a case, returns false.
+ */
+static int check_mic_location_need(struct hda_codec *codec,
+				   const struct auto_pin_cfg *cfg,
+				   int input)
+{
+	unsigned int defc;
+	int i, attr, attr2;
+
+	defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin);
+	attr = get_mic_pin_attr(defc);
+	/* for internal or docking mics, we need locations */
+	if (attr <= MIC_ATTR_NORMAL)
+		return 1;
+
+	attr = 0;
+	for (i = 0; i < cfg->num_inputs; i++) {
+		defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin);
+		attr2 = get_mic_pin_attr(defc);
+		if (attr2 >= MIC_ATTR_NORMAL) {
+			if (attr && attr != attr2)
+				return 1; /* different locations found */
+			attr = attr2;
+		}
+	}
+	return 0;
+}
+
+/**
+ * hda_get_autocfg_input_label - Get a label for the given input
+ *
+ * Get a label for the given input pin defined by the autocfg item.
+ * Unlike hda_get_input_pin_label(), this function checks all inputs
+ * defined in autocfg and avoids the redundant mic/line prefix as much as
+ * possible.
+ */
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+					const struct auto_pin_cfg *cfg,
+					int input)
+{
+	int type = cfg->inputs[input].type;
+	int has_multiple_pins = 0;
+
+	if ((input > 0 && cfg->inputs[input - 1].type == type) ||
+	    (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
+		has_multiple_pins = 1;
+	if (has_multiple_pins && type == AUTO_PIN_MIC)
+		has_multiple_pins &= check_mic_location_need(codec, cfg, input);
+	return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
+				       has_multiple_pins);
+}
+EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
+
+/**
+ * snd_hda_add_imux_item - Add an item to input_mux
+ *
+ * When the same label is used already in the existing items, the number
+ * suffix is appended to the label.  This label index number is stored
+ * to type_idx when non-NULL pointer is given.
+ */
+int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
+			  int index, int *type_idx)
+{
+	int i, label_idx = 0;
+	if (imux->num_items >= HDA_MAX_NUM_INPUTS) {
+		snd_printd(KERN_ERR "hda_codec: Too many imux items!\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < imux->num_items; i++) {
+		if (!strncmp(label, imux->items[i].label, strlen(label)))
+			label_idx++;
+	}
+	if (type_idx)
+		*type_idx = label_idx;
+	if (label_idx > 0)
+		snprintf(imux->items[imux->num_items].label,
+			 sizeof(imux->items[imux->num_items].label),
+			 "%s %d", label, label_idx);
+	else
+		strlcpy(imux->items[imux->num_items].label, label,
+			sizeof(imux->items[imux->num_items].label));
+	imux->items[imux->num_items].index = index;
+	imux->num_items++;
+	return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_add_imux_item);
 
 
 #ifdef CONFIG_PM
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 5ea2128..fb0582f8 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -61,7 +61,6 @@
 	struct hda_gnode *cap_vol_node;	/* Node for capture volume */
 	unsigned int cur_cap_src;	/* current capture source */
 	struct hda_input_mux input_mux;
-	char cap_labels[HDA_MAX_NUM_INPUTS][16];
 
 	unsigned int def_amp_in_caps;
 	unsigned int def_amp_out_caps;
@@ -506,11 +505,10 @@
  * returns 0 if not found, 1 if found, or a negative error code.
  */
 static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
-			       struct hda_gnode *node)
+			       struct hda_gnode *node, int idx)
 {
 	int i, err;
 	unsigned int pinctl;
-	char *label;
 	const char *type;
 
 	if (node->checked)
@@ -523,7 +521,7 @@
 			child = hda_get_node(spec, node->conn_list[i]);
 			if (! child)
 				continue;
-			err = parse_adc_sub_nodes(codec, spec, child);
+			err = parse_adc_sub_nodes(codec, spec, child, idx);
 			if (err < 0)
 				return err;
 			if (err > 0) {
@@ -564,9 +562,7 @@
 			return 0;
 		type = "Input";
 	}
-	label = spec->cap_labels[spec->input_mux.num_items];
-	strcpy(label, type);
-	spec->input_mux.items[spec->input_mux.num_items].label = label;
+	snd_hda_add_imux_item(&spec->input_mux, type, idx, NULL);
 
 	/* unmute the PIN external input */
 	unmute_input(codec, node, 0); /* index = 0? */
@@ -577,29 +573,6 @@
 	return 1; /* found */
 }
 
-/* add a capture source element */
-static void add_cap_src(struct hda_gspec *spec, int idx)
-{
-	struct hda_input_mux_item *csrc;
-	char *buf;
-	int num, ocap;
-
-	num = spec->input_mux.num_items;
-	csrc = &spec->input_mux.items[num];
-	buf = spec->cap_labels[num];
-	for (ocap = 0; ocap < num; ocap++) {
-		if (! strcmp(buf, spec->cap_labels[ocap])) {
-			/* same label already exists,
-			 * put the index number to be unique
-			 */
-			sprintf(buf, "%s %d", spec->cap_labels[ocap], num);
-			break;
-		}
-	}
-	csrc->index = idx;
-	spec->input_mux.num_items++;
-}
-
 /*
  * parse input
  */
@@ -624,22 +597,18 @@
 	for (i = 0; i < adc_node->nconns; i++) {
 		node = hda_get_node(spec, adc_node->conn_list[i]);
 		if (node && node->type == AC_WID_PIN) {
-			err = parse_adc_sub_nodes(codec, spec, node);
+			err = parse_adc_sub_nodes(codec, spec, node, i);
 			if (err < 0)
 				return err;
-			else if (err > 0)
-				add_cap_src(spec, i);
 		}
 	}
 	/* ... then check the rests, more complicated connections */
 	for (i = 0; i < adc_node->nconns; i++) {
 		node = hda_get_node(spec, adc_node->conn_list[i]);
 		if (node && node->type != AC_WID_PIN) {
-			err = parse_adc_sub_nodes(codec, spec, node);
+			err = parse_adc_sub_nodes(codec, spec, node, i);
 			if (err < 0)
 				return err;
-			else if (err > 0)
-				add_cap_src(spec, i);
 		}
 	}
 
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 28ab4ae..6943efc 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -215,7 +215,7 @@
  */
 #define HDA_MAX_NUM_INPUTS	16
 struct hda_input_mux_item {
-	const char *label;
+	char label[32];
 	unsigned int index;
 };
 struct hda_input_mux {
@@ -366,9 +366,7 @@
 
 enum {
 	AUTO_PIN_MIC,
-	AUTO_PIN_FRONT_MIC,
-	AUTO_PIN_LINE,
-	AUTO_PIN_FRONT_LINE,
+	AUTO_PIN_LINE_IN,
 	AUTO_PIN_CD,
 	AUTO_PIN_AUX,
 	AUTO_PIN_LAST
@@ -380,9 +378,22 @@
 	AUTO_PIN_HP_OUT
 };
 
-extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST];
-
 #define AUTO_CFG_MAX_OUTS	5
+#define AUTO_CFG_MAX_INS	8
+
+struct auto_pin_cfg_item {
+	hda_nid_t pin;
+	int type;
+};
+
+struct auto_pin_cfg;
+const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
+				    int check_location);
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+					const struct auto_pin_cfg *cfg,
+					int input);
+int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
+			  int index, int *type_index_ret);
 
 struct auto_pin_cfg {
 	int line_outs;
@@ -393,7 +404,8 @@
 	int hp_outs;
 	int line_out_type;	/* AUTO_PIN_XXX_OUT */
 	hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
-	hda_nid_t input_pins[AUTO_PIN_LAST];
+	int num_inputs;
+	struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
 	int dig_outs;
 	hda_nid_t dig_out_pins[2];
 	hda_nid_t dig_in_pin;
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index b697fd2..05db1cf 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -2880,7 +2880,7 @@
 
 /* create input playback/capture controls for the given pin */
 static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
-			    const char *ctlname, int boost)
+			    const char *ctlname, int ctlidx, int boost)
 {
 	char name[32];
 	int err, idx;
@@ -2909,25 +2909,27 @@
 }
 
 /* create playback/capture controls for input pins */
-static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec,
+static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
+	struct ad198x_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux;
-	int i, err;
+	int i, err, type, type_idx;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		err = new_analog_input(spec, cfg->input_pins[i],
-				       auto_pin_cfg_labels[i],
-				       i <= AUTO_PIN_FRONT_MIC);
+	for (i = 0; i < cfg->num_inputs; i++) {
+		const char *label;
+		type = cfg->inputs[i].type;
+		label = hda_get_autocfg_input_label(codec, cfg, i);
+		snd_hda_add_imux_item(imux, label,
+				      ad1988_pin_to_adc_idx(cfg->inputs[i].pin),
+				      &type_idx);
+		err = new_analog_input(spec, cfg->inputs[i].pin,
+				       label, type_idx,
+				       type == AUTO_PIN_MIC);
 		if (err < 0)
 			return err;
-		imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
-		imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]);
-		imux->num_items++;
 	}
-	imux->items[imux->num_items].label = "Mix";
-	imux->items[imux->num_items].index = 9;
-	imux->num_items++;
+	snd_hda_add_imux_item(imux, "Mix", 9, NULL);
 
 	if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
 			       "Analog Mix Playback Volume",
@@ -2994,12 +2996,11 @@
 static void ad1988_auto_init_analog_input(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec = codec->spec;
+	const struct auto_pin_cfg *cfg = &spec->autocfg;
 	int i, idx;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		hda_nid_t nid = spec->autocfg.input_pins[i];
-		if (! nid)
-			continue;
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
 		switch (nid) {
 		case 0x15: /* port-C */
 			snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
@@ -3009,7 +3010,7 @@
 			break;
 		}
 		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
+				    i == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
 		if (nid != AD1988_PIN_CD_NID)
 			snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
 					    AMP_OUT_MUTE);
@@ -3040,7 +3041,7 @@
 						"Speaker")) < 0 ||
 	    (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
 						"Headphone")) < 0 ||
-	    (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
+	    (err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
 		return err;
 
 	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c
index af47801..cca11fd 100644
--- a/sound/pci/hda/patch_ca0110.c
+++ b/sound/pci/hda/patch_ca0110.c
@@ -468,13 +468,13 @@
 			spec->dig_in = nid;
 			continue;
 		}
-		for (j = 0; j < AUTO_PIN_LAST; j++)
-			if (cfg->input_pins[j] == pin)
+		for (j = 0; j < cfg->num_inputs; j++)
+			if (cfg->inputs[j].pin == pin)
 				break;
-		if (j >= AUTO_PIN_LAST)
+		if (j >= cfg->num_inputs)
 			continue;
 		spec->input_pins[n] = pin;
-		spec->input_labels[n] = auto_pin_cfg_labels[j];
+		spec->input_labels[n] = hda_get_input_pin_label(codec, pin, 1);
 		spec->adcs[n] = nid;
 		n++;
 	}
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 488fd9a..ae75283 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -329,7 +329,7 @@
 {
 	struct cs_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
-	hda_nid_t pin = cfg->input_pins[idx];
+	hda_nid_t pin = cfg->inputs[idx].pin;
 	unsigned int val = snd_hda_query_pin_caps(codec, pin);
 	if (!(val & AC_PINCAP_PRES_DETECT))
 		return 0;
@@ -424,10 +424,8 @@
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	int i;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		hda_nid_t pin = cfg->input_pins[i];
-		if (!pin)
-			continue;
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t pin = cfg->inputs[i].pin;
 		spec->input_idx[spec->num_inputs] = i;
 		spec->capsrc_idx[i] = spec->num_inputs++;
 		spec->cur_input = i;
@@ -438,16 +436,17 @@
 
 	/* check whether the automatic mic switch is available */
 	if (spec->num_inputs == 2 &&
-	    spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) {
-		if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) {
-			if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
+	    cfg->inputs[0].type == AUTO_PIN_MIC &&
+	    cfg->inputs[1].type == AUTO_PIN_MIC) {
+		if (is_ext_mic(codec, cfg->inputs[0].pin)) {
+			if (!is_ext_mic(codec, cfg->inputs[1].pin)) {
 				spec->mic_detect = 1;
-				spec->automic_idx = AUTO_PIN_FRONT_MIC;
+				spec->automic_idx = 0;
 			}
 		} else {
-			if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
+			if (is_ext_mic(codec, cfg->inputs[1].pin)) {
 				spec->mic_detect = 1;
-				spec->automic_idx = AUTO_PIN_MIC;
+				spec->automic_idx = 1;
 			}
 		}
 	}
@@ -674,6 +673,7 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct cs_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
 	unsigned int idx;
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -682,7 +682,8 @@
 	if (uinfo->value.enumerated.item >= spec->num_inputs)
 		uinfo->value.enumerated.item = spec->num_inputs - 1;
 	idx = spec->input_idx[uinfo->value.enumerated.item];
-	strcpy(uinfo->value.enumerated.name, auto_pin_cfg_labels[idx]);
+	strcpy(uinfo->value.enumerated.name,
+	       hda_get_input_pin_label(codec, cfg->inputs[idx].pin, 1));
 	return 0;
 }
 
@@ -853,15 +854,12 @@
 	hda_nid_t nid;
 	unsigned int present;
 	
-	nid = cfg->input_pins[spec->automic_idx];
+	nid = cfg->inputs[spec->automic_idx].pin;
 	present = snd_hda_jack_detect(codec, nid);
 	if (present)
 		change_cur_input(codec, spec->automic_idx, 0);
-	else {
-		unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ?
-			AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC;
-		change_cur_input(codec, imic, 0);
-	}
+	else
+		change_cur_input(codec, !spec->automic_idx, 0);
 }
 
 /*
@@ -918,14 +916,14 @@
 	unsigned int coef;
 	int i;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
+	for (i = 0; i < cfg->num_inputs; i++) {
 		unsigned int ctl;
-		hda_nid_t pin = cfg->input_pins[i];
-		if (!pin || !spec->adc_nid[i])
+		hda_nid_t pin = cfg->inputs[i].pin;
+		if (!spec->adc_nid[i])
 			continue;
 		/* set appropriate pin control and mute first */
 		ctl = PIN_IN;
-		if (i <= AUTO_PIN_FRONT_MIC) {
+		if (cfg->inputs[i].type == AUTO_PIN_MIC) {
 			unsigned int caps = snd_hda_query_pin_caps(codec, pin);
 			caps >>= AC_PINCAP_VREF_SHIFT;
 			if (caps & AC_PINCAP_VREF_80)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index bcbf916..ab2947d 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <sound/core.h>
+#include <sound/jack.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_beep.h"
@@ -282,6 +283,12 @@
 	unsigned char amix_idx;
 };
 
+struct alc_jack {
+	hda_nid_t nid;
+	int type;
+	struct snd_jack *jack;
+};
+
 #define MUX_IDX_UNDEF	((unsigned char)-1)
 
 struct alc_customize_define {
@@ -357,6 +364,9 @@
 	/* PCM information */
 	struct hda_pcm pcm_rec[3];	/* used in alc_build_pcms() */
 
+	/* jack detection */
+	struct snd_array jacks;
+
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
 	struct alc_customize_define cdefine;
@@ -846,7 +856,7 @@
 {
 	unsigned int val = PIN_IN;
 
-	if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
+	if (auto_pin_type == AUTO_PIN_MIC) {
 		unsigned int pincap;
 		unsigned int oldval;
 		oldval = snd_hda_codec_read(codec, nid, 0,
@@ -990,25 +1000,132 @@
 	alc_fix_pll(codec);
 }
 
-static void alc_automute_pin(struct hda_codec *codec)
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+static void alc_free_jack_priv(struct snd_jack *jack)
+{
+	struct alc_jack *jacks = jack->private_data;
+	jacks->nid = 0;
+	jacks->jack = NULL;
+}
+
+static int alc_add_jack(struct hda_codec *codec,
+		hda_nid_t nid, int type)
+{
+	struct alc_spec *spec;
+	struct alc_jack *jack;
+	const char *name;
+	int err;
+
+	spec = codec->spec;
+	snd_array_init(&spec->jacks, sizeof(*jack), 32);
+	jack = snd_array_new(&spec->jacks);
+	if (!jack)
+		return -ENOMEM;
+
+	jack->nid = nid;
+	jack->type = type;
+	name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
+
+	err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
+	if (err < 0)
+		return err;
+	jack->jack->private_data = jack;
+	jack->jack->private_free = alc_free_jack_priv;
+	return 0;
+}
+
+static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
 {
 	struct alc_spec *spec = codec->spec;
-	unsigned int nid = spec->autocfg.hp_pins[0];
+	struct alc_jack *jacks = spec->jacks.list;
+
+	if (jacks) {
+		int i;
+		for (i = 0; i < spec->jacks.used; i++) {
+			if (jacks->nid == nid) {
+				unsigned int present;
+				present = snd_hda_jack_detect(codec, nid);
+
+				present = (present) ? jacks->type : 0;
+
+				snd_jack_report(jacks->jack, present);
+			}
+			jacks++;
+		}
+	}
+}
+
+static int alc_init_jacks(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	int err;
+	unsigned int hp_nid = spec->autocfg.hp_pins[0];
+	unsigned int mic_nid = spec->ext_mic.pin;
+
+	err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE);
+	if (err < 0)
+		return err;
+	alc_report_jack(codec, hp_nid);
+
+	err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE);
+	if (err < 0)
+		return err;
+	alc_report_jack(codec, mic_nid);
+
+	return 0;
+}
+#else
+static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
+{
+}
+
+static inline int alc_init_jacks(struct hda_codec *codec)
+{
+	return 0;
+}
+#endif
+
+static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int mute;
+	hda_nid_t nid;
 	int i;
 
-	if (!nid)
-		return;
-	spec->jack_present = snd_hda_jack_detect(codec, nid);
+	spec->jack_present = 0;
+	for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
+		nid = spec->autocfg.hp_pins[i];
+		if (!nid)
+			break;
+		if (snd_hda_jack_detect(codec, nid)) {
+			spec->jack_present = 1;
+			break;
+		}
+		alc_report_jack(codec, spec->autocfg.hp_pins[i]);
+	}
+
+	mute = spec->jack_present ? HDA_AMP_MUTE : 0;
+	/* Toggle internal speakers muting */
 	for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
 		nid = spec->autocfg.speaker_pins[i];
 		if (!nid)
 			break;
-		snd_hda_codec_write(codec, nid, 0,
+		if (pinctl) {
+			snd_hda_codec_write(codec, nid, 0,
 				    AC_VERB_SET_PIN_WIDGET_CONTROL,
 				    spec->jack_present ? 0 : PIN_OUT);
+		} else {
+			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, mute);
+		}
 	}
 }
 
+static void alc_automute_pin(struct hda_codec *codec)
+{
+	alc_automute_speaker(codec, 1);
+}
+
 static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
 				hda_nid_t nid)
 {
@@ -1090,6 +1207,7 @@
 					  AC_VERB_SET_CONNECT_SEL,
 					  alive->mux_idx);
 	}
+	alc_report_jack(codec, spec->ext_mic.pin);
 
 	/* FIXME: analog mixer */
 }
@@ -1236,24 +1354,35 @@
 static void alc_init_auto_hp(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int i;
 
-	if (!spec->autocfg.hp_pins[0])
-		return;
-
-	if (!spec->autocfg.speaker_pins[0]) {
-		if (spec->autocfg.line_out_pins[0] &&
-		    spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
-			spec->autocfg.speaker_pins[0] =
-				spec->autocfg.line_out_pins[0];
-		else
+	if (!cfg->hp_pins[0]) {
+		if (cfg->line_out_type != AUTO_PIN_HP_OUT)
 			return;
 	}
 
-	snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
-		    spec->autocfg.hp_pins[0]);
-	snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0,
+	if (!cfg->speaker_pins[0]) {
+		if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+			return;
+		memcpy(cfg->speaker_pins, cfg->line_out_pins,
+		       sizeof(cfg->speaker_pins));
+		cfg->speaker_outs = cfg->line_outs;
+	}
+
+	if (!cfg->hp_pins[0]) {
+		memcpy(cfg->hp_pins, cfg->line_out_pins,
+		       sizeof(cfg->hp_pins));
+		cfg->hp_outs = cfg->line_outs;
+	}
+
+	for (i = 0; i < cfg->hp_outs; i++) {
+		snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
+			    cfg->hp_pins[i]);
+		snd_hda_codec_write_cache(codec, cfg->hp_pins[i], 0,
 				  AC_VERB_SET_UNSOLICITED_ENABLE,
 				  AC_USRSP_EN | ALC880_HP_EVENT);
+	}
 	spec->unsol_event = alc_sku_unsol_event;
 }
 
@@ -1265,16 +1394,14 @@
 	int i;
 
 	/* there must be only two mic inputs exclusively */
-	for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++)
-		if (cfg->input_pins[i])
+	for (i = 0; i < cfg->num_inputs; i++)
+		if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
 			return;
 
 	fixed = ext = 0;
-	for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) {
-		hda_nid_t nid = cfg->input_pins[i];
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
 		unsigned int defcfg;
-		if (!nid)
-			return;
 		defcfg = snd_hda_codec_get_pincfg(codec, nid);
 		switch (get_defcfg_connect(defcfg)) {
 		case AC_JACK_PORT_FIXED:
@@ -1546,6 +1673,15 @@
 	return val;
 }
 
+static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
+							unsigned int coef_val)
+{
+	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
+			    coef_idx);
+	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
+			    coef_val);
+}
+
 /* set right pin controls for digital I/O */
 static void alc_auto_init_digital(struct hda_codec *codec)
 {
@@ -1713,31 +1849,7 @@
 
 static void alc_automute_amp(struct hda_codec *codec)
 {
-	struct alc_spec *spec = codec->spec;
-	unsigned int mute;
-	hda_nid_t nid;
-	int i;
-
-	spec->jack_present = 0;
-	for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
-		nid = spec->autocfg.hp_pins[i];
-		if (!nid)
-			break;
-		if (snd_hda_jack_detect(codec, nid)) {
-			spec->jack_present = 1;
-			break;
-		}
-	}
-
-	mute = spec->jack_present ? HDA_AMP_MUTE : 0;
-	/* Toggle internal speakers muting */
-	for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
-		nid = spec->autocfg.speaker_pins[i];
-		if (!nid)
-			break;
-		snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-	}
+	alc_automute_speaker(codec, 0);
 }
 
 static void alc_automute_amp_unsol_event(struct hda_codec *codec,
@@ -4719,7 +4831,7 @@
 
 /* add dynamic controls */
 static int add_control(struct alc_spec *spec, int type, const char *name,
-		       unsigned long val)
+		       int cidx, unsigned long val)
 {
 	struct snd_kcontrol_new *knew;
 
@@ -4731,6 +4843,7 @@
 	knew->name = kstrdup(name, GFP_KERNEL);
 	if (!knew->name)
 		return -ENOMEM;
+	knew->index = cidx;
 	if (get_amp_nid_(val))
 		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
 	knew->private_value = val;
@@ -4739,17 +4852,21 @@
 
 static int add_control_with_pfx(struct alc_spec *spec, int type,
 				const char *pfx, const char *dir,
-				const char *sfx, unsigned long val)
+				const char *sfx, int cidx, unsigned long val)
 {
 	char name[32];
 	snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
-	return add_control(spec, type, name, val);
+	return add_control(spec, type, name, cidx, val);
 }
 
-#define add_pb_vol_ctrl(spec, type, pfx, val) \
-	add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val)
-#define add_pb_sw_ctrl(spec, type, pfx, val) \
-	add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val)
+#define add_pb_vol_ctrl(spec, type, pfx, val)			\
+	add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
+#define add_pb_sw_ctrl(spec, type, pfx, val)			\
+	add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
+#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val)			\
+	add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
+#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val)			\
+	add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
 
 #define alc880_is_fixed_pin(nid)	((nid) >= 0x14 && (nid) <= 0x17)
 #define alc880_fixed_pin_idx(nid)	((nid) - 0x14)
@@ -4902,16 +5019,16 @@
 
 /* create input playback/capture controls for the given pin */
 static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
-			    const char *ctlname,
+			    const char *ctlname, int ctlidx,
 			    int idx, hda_nid_t mix_nid)
 {
 	int err;
 
-	err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
+	err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
 			  HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
 	if (err < 0)
 		return err;
-	err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
+	err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
 			  HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
 	if (err < 0)
 		return err;
@@ -4932,20 +5049,27 @@
 {
 	struct alc_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux[0];
-	int i, err, idx;
+	int i, err, idx, type, type_idx = 0;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
+	for (i = 0; i < cfg->num_inputs; i++) {
 		hda_nid_t pin;
+		const char *label;
 
-		pin = cfg->input_pins[i];
+		pin = cfg->inputs[i].pin;
 		if (!alc_is_input_pin(codec, pin))
 			continue;
 
+		type = cfg->inputs[i].type;
+		if (i > 0 && type == cfg->inputs[i - 1].type)
+			type_idx++;
+		else
+			type_idx = 0;
+		label = hda_get_autocfg_input_label(codec, cfg, i);
 		if (mixer) {
 			idx = get_connection_index(codec, mixer, pin);
 			if (idx >= 0) {
 				err = new_analog_input(spec, pin,
-						       auto_pin_cfg_labels[i],
+						       label, type_idx,
 						       idx, mixer);
 				if (err < 0)
 					return err;
@@ -4957,12 +5081,8 @@
 		idx = get_connection_index(codec, cap1, pin);
 		if (idx < 0 && cap2)
 			idx = get_connection_index(codec, cap2, pin);
-		if (idx >= 0) {
-			imux->items[imux->num_items].label =
-				auto_pin_cfg_labels[i];
-			imux->items[imux->num_items].index = idx;
-			imux->num_items++;
-		}
+		if (idx >= 0)
+			snd_hda_add_imux_item(imux, label, idx, NULL);
 	}
 	return 0;
 }
@@ -5034,10 +5154,11 @@
 static void alc880_auto_init_analog_input(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
 	int i;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		hda_nid_t nid = spec->autocfg.input_pins[i];
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
 		if (alc_is_input_pin(codec, nid)) {
 			alc_set_input_pin(codec, nid, i);
 			if (nid != ALC880_PIN_CD_NID &&
@@ -5204,19 +5325,13 @@
 static void fixup_single_adc(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	hda_nid_t pin = 0;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
 	int i;
 
 	/* search for the input pin; there must be only one */
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		if (spec->autocfg.input_pins[i]) {
-			pin = spec->autocfg.input_pins[i];
-			break;
-		}
-	}
-	if (!pin)
+	if (cfg->num_inputs != 1)
 		return;
-	i = init_capsrc_for_pin(codec, pin);
+	i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
 	if (i >= 0) {
 		/* use only this ADC */
 		if (spec->capsrc_nids)
@@ -5269,6 +5384,7 @@
 				 int num_nids)
 {
 	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
 	int n;
 	hda_nid_t fallback_adc = 0, fallback_cap = 0;
 
@@ -5294,10 +5410,8 @@
 			fallback_adc = adc;
 			fallback_cap = cap;
 		}
-		for (i = 0; i < AUTO_PIN_LAST; i++) {
-			hda_nid_t nid = spec->autocfg.input_pins[i];
-			if (!nid)
-				continue;
+		for (i = 0; i < cfg->num_inputs; i++) {
+			hda_nid_t nid = cfg->inputs[i].pin;
 			for (j = 0; j < nconns; j++) {
 				if (conn[j] == nid)
 					break;
@@ -5305,7 +5419,7 @@
 			if (j >= nconns)
 				break;
 		}
-		if (i >= AUTO_PIN_LAST) {
+		if (i >= cfg->num_inputs) {
 			int num_adcs = spec->num_adc_nids;
 			spec->private_adc_nids[num_adcs] = adc;
 			spec->private_capsrc_nids[num_adcs] = cap;
@@ -6673,10 +6787,11 @@
 static void alc260_auto_init_analog_input(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
 	int i;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		hda_nid_t nid = spec->autocfg.input_pins[i];
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
 		if (nid >= 0x12) {
 			alc_set_input_pin(codec, nid, i);
 			if (nid != ALC260_PIN_CD_NID &&
@@ -6800,14 +6915,12 @@
 	PINFIX_HP_DC5750,
 };
 
-static struct alc_pincfg alc260_hp_dc5750_pinfix[] = {
-	{ 0x11, 0x90130110 }, /* speaker */
-	{ }
-};
-
 static const struct alc_fixup alc260_fixups[] = {
 	[PINFIX_HP_DC5750] = {
-		.pins = alc260_hp_dc5750_pinfix
+		.pins = (const struct alc_pincfg[]) {
+			{ 0x11, 0x90130110 }, /* speaker */
+			{ }
+		}
 	},
 };
 
@@ -10453,24 +10566,20 @@
 	PINFIX_PB_M5210,
 };
 
-static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
-	{ 0x15, 0x01080104 }, /* side */
-	{ 0x16, 0x01011012 }, /* rear */
-	{ 0x17, 0x01016011 }, /* clfe */
-	{ }
-};
-
-static const struct hda_verb pb_m5210_verbs[] = {
-	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
-	{}
-};
-
 static const struct alc_fixup alc882_fixups[] = {
 	[PINFIX_ABIT_AW9D_MAX] = {
-		.pins = alc882_abit_aw9d_pinfix
+		.pins = (const struct alc_pincfg[]) {
+			{ 0x15, 0x01080104 }, /* side */
+			{ 0x16, 0x01011012 }, /* rear */
+			{ 0x17, 0x01016011 }, /* clfe */
+			{ }
+		}
 	},
 	[PINFIX_PB_M5210] = {
-		.verbs = pb_m5210_verbs
+		.verbs = (const struct hda_verb[]) {
+			{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
+			{}
+		}
 	},
 };
 
@@ -10545,12 +10654,11 @@
 static void alc882_auto_init_analog_input(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
 	int i;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		hda_nid_t nid = spec->autocfg.input_pins[i];
-		if (!nid)
-			continue;
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
 		alc_set_input_pin(codec, nid, i);
 		if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
 			snd_hda_codec_write(codec, nid, 0,
@@ -10613,24 +10721,23 @@
 static int alc_auto_add_mic_boost(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	int err;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int i, err;
 	hda_nid_t nid;
 
-	nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
-	if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
-		err = add_control(spec, ALC_CTL_WIDGET_VOL,
-				  "Mic Boost",
+	for (i = 0; i < cfg->num_inputs; i++) {
+		if (cfg->inputs[i].type > AUTO_PIN_MIC)
+			break;
+		nid = cfg->inputs[i].pin;
+		if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
+			char label[32];
+			snprintf(label, sizeof(label), "%s Boost",
+				 hda_get_autocfg_input_label(codec, cfg, i));
+			err = add_control(spec, ALC_CTL_WIDGET_VOL, label, 0,
 				  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
-		if (err < 0)
-			return err;
-	}
-	nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
-	if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
-		err = add_control(spec, ALC_CTL_WIDGET_VOL,
-				  "Front Mic Boost",
-				  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
-		if (err < 0)
-			return err;
+			if (err < 0)
+				return err;
+		}
 	}
 	return 0;
 }
@@ -11821,7 +11928,7 @@
 }
 
 static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
-				  const char *pfx, int *vbits)
+				  const char *pfx, int *vbits, int idx)
 {
 	unsigned long val;
 	int vbit;
@@ -11836,11 +11943,11 @@
 		val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
 	else
 		val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
-	return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val);
+	return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
 }
 
 static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
-				 const char *pfx)
+				 const char *pfx, int idx)
 {
 	unsigned long val;
 
@@ -11850,7 +11957,7 @@
 		val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
 	else
 		val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-	return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
+	return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
 }
 
 /* add playback controls from the parsed DAC table */
@@ -11859,7 +11966,7 @@
 {
 	const char *pfx;
 	int vbits;
-	int err;
+	int i, err;
 
 	spec->multiout.num_dacs = 1;	/* only use one dac */
 	spec->multiout.dac_nids = spec->private_dac_nids;
@@ -11869,39 +11976,52 @@
 		pfx = "Master";
 	else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
 		pfx = "Speaker";
+	else if (cfg->line_out_type == AUTO_PIN_HP_OUT)
+		pfx = "Headphone";
 	else
 		pfx = "Front";
-	err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx);
-	if (err < 0)
-		return err;
-	err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker");
-	if (err < 0)
-		return err;
-	err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone");
-	if (err < 0)
-		return err;
+	for (i = 0; i < 2; i++) {
+		err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
+		if (err < 0)
+			return err;
+		if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+			err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
+						    "Speaker", i);
+			if (err < 0)
+				return err;
+		}
+		if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+			err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
+						    "Headphone", i);
+			if (err < 0)
+				return err;
+		}
+	}
 
 	vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
 		alc262_check_volbit(cfg->speaker_pins[0]) |
 		alc262_check_volbit(cfg->hp_pins[0]);
 	if (vbits == 1 || vbits == 2)
 		pfx = "Master"; /* only one mixer is used */
-	else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-		pfx = "Speaker";
-	else
-		pfx = "Front";
 	vbits = 0;
-	err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits);
-	if (err < 0)
-		return err;
-	err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker",
-				     &vbits);
-	if (err < 0)
-		return err;
-	err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone",
-				     &vbits);
-	if (err < 0)
-		return err;
+	for (i = 0; i < 2; i++) {
+		err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
+					     &vbits, i);
+		if (err < 0)
+			return err;
+		if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+			err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
+						     "Speaker", &vbits, i);
+			if (err < 0)
+				return err;
+		}
+		if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+			err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
+						     "Headphone", &vbits, i);
+			if (err < 0)
+				return err;
+		}
+	}
 	return 0;
 }
 
@@ -12189,6 +12309,35 @@
 	{}
 };
 
+/*
+ * Pin config fixes
+ */
+enum {
+	PINFIX_FSC_H270,
+};
+
+static const struct alc_fixup alc262_fixups[] = {
+	[PINFIX_FSC_H270] = {
+		.pins = (const struct alc_pincfg[]) {
+			{ 0x14, 0x99130110 }, /* speaker */
+			{ 0x15, 0x0221142f }, /* front HP */
+			{ 0x1b, 0x0121141f }, /* rear HP */
+			{ }
+		}
+	},
+	[PINFIX_PB_M5210] = {
+		.verbs = (const struct hda_verb[]) {
+			{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
+			{}
+		}
+	},
+};
+
+static struct snd_pci_quirk alc262_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
+	{}
+};
+
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc262_loopbacks	alc880_loopbacks
@@ -12612,6 +12761,9 @@
 		board_config = ALC262_AUTO;
 	}
 
+	if (board_config == ALC262_AUTO)
+		alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 1);
+
 	if (board_config == ALC262_AUTO) {
 		/* automatic parse from the BIOS config */
 		err = alc262_parse_auto_config(codec);
@@ -12680,6 +12832,9 @@
 	if (!spec->no_analog && has_cdefine_beep(codec))
 		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
+	if (board_config == ALC262_AUTO)
+		alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 0);
+
 	spec->vmaster_nid = 0x0c;
 
 	codec->patch_ops = alc_patch_ops;
@@ -14447,22 +14602,83 @@
 	alc269_auto_init_hp_out(codec);
 	alc269_auto_init_analog_input(codec);
 	alc_auto_init_digital(codec);
+	alc_init_jacks(codec);
 	if (spec->unsol_event)
 		alc_inithook(codec);
 }
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int alc269_suspend(struct hda_codec *codec, pm_message_t state)
+{
+	struct alc_spec *spec = codec->spec;
+	int val;
+
+	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+		val = alc_read_coef_idx(codec, 0x04);
+		/* Power down output pin */
+		alc_write_coef_idx(codec, 0x04, val & ~(1<<11));
+	}
+
+	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+		val = alc_read_coef_idx(codec, 0x04);
+		/* Power down output pin */
+		alc_write_coef_idx(codec, 0x04, val & ~(1<<11));
+		msleep(150);
+	}
+
+	alc_shutup(codec);
+	if (spec && spec->power_hook)
+		spec->power_hook(codec);
+	return 0;
+}
+#endif
+#ifdef SND_HDA_NEEDS_RESUME
+static int alc269_resume(struct hda_codec *codec)
+{
+	int val;
+
+	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+		val = alc_read_coef_idx(codec, 0x04);
+		/* Power down output pin */
+		alc_write_coef_idx(codec, 0x04, val & ~(1<<11));
+		msleep(150);
+	}
+
+	codec->patch_ops.init(codec);
+
+	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+		val = alc_read_coef_idx(codec, 0x04);
+		/* Power up output pin */
+		alc_write_coef_idx(codec, 0x04, val | (1<<11));
+		msleep(200);
+	}
+
+	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+		val = alc_read_coef_idx(codec, 0x04);
+		/* Power up output pin */
+		alc_write_coef_idx(codec, 0x04, val | (1<<11));
+	}
+
+	snd_hda_codec_resume_amp(codec);
+	snd_hda_codec_resume_cache(codec);
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	if (codec->patch_ops.check_power_status)
+		codec->patch_ops.check_power_status(codec, 0x01);
+#endif
+	return 0;
+}
+#endif
+
 enum {
 	ALC269_FIXUP_SONY_VAIO,
 };
 
-static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = {
-	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
-	{}
-};
-
 static const struct alc_fixup alc269_fixups[] = {
 	[ALC269_FIXUP_SONY_VAIO] = {
-		.verbs = alc269_sony_vaio_fixup_verbs
+		.verbs = (const struct hda_verb[]) {
+			{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
+			{}
+		}
 	},
 };
 
@@ -14669,6 +14885,41 @@
 	},
 };
 
+static int alc269_fill_coef(struct hda_codec *codec)
+{
+	int val;
+
+	if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
+		alc_write_coef_idx(codec, 0xf, 0x960b);
+		alc_write_coef_idx(codec, 0xe, 0x8817);
+	}
+
+	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
+		alc_write_coef_idx(codec, 0xf, 0x960b);
+		alc_write_coef_idx(codec, 0xe, 0x8814);
+	}
+
+	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+		val = alc_read_coef_idx(codec, 0x04);
+		/* Power up output pin */
+		alc_write_coef_idx(codec, 0x04, val | (1<<11));
+	}
+
+	if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+		val = alc_read_coef_idx(codec, 0xd);
+		if ((val & 0x0c00) >> 10 != 0x1) {
+			/* Capless ramp up clock control */
+			alc_write_coef_idx(codec, 0xd, val | 1<<10);
+		}
+		val = alc_read_coef_idx(codec, 0x17);
+		if ((val & 0x01c0) >> 6 != 0x4) {
+			/* Class D power on reset */
+			alc_write_coef_idx(codec, 0x17, val | 1<<7);
+		}
+	}
+	return 0;
+}
+
 static int patch_alc269(struct hda_codec *codec)
 {
 	struct alc_spec *spec;
@@ -14694,6 +14945,8 @@
 	} else
 		alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
+	alc269_fill_coef(codec);
+
 	board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
 						  alc269_models,
 						  alc269_cfg_tbl);
@@ -14772,6 +15025,12 @@
 	spec->vmaster_nid = 0x02;
 
 	codec->patch_ops = alc_patch_ops;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	codec->patch_ops.suspend = alc269_suspend;
+#endif
+#ifdef SND_HDA_NEEDS_RESUME
+	codec->patch_ops.resume = alc269_resume;
+#endif
 	if (board_config == ALC269_AUTO)
 		spec->init_hook = alc269_auto_init;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -15586,10 +15845,11 @@
 static void alc861_auto_init_analog_input(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
 	int i;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		hda_nid_t nid = spec->autocfg.input_pins[i];
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
 		if (nid >= 0x0c && nid <= 0x11)
 			alc_set_input_pin(codec, nid, i);
 	}
@@ -15820,15 +16080,13 @@
 	PINFIX_FSC_AMILO_PI1505,
 };
 
-static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
-	{ 0x0b, 0x0221101f }, /* HP */
-	{ 0x0f, 0x90170310 }, /* speaker */
-	{ }
-};
-
 static const struct alc_fixup alc861_fixups[] = {
 	[PINFIX_FSC_AMILO_PI1505] = {
-		.pins = alc861_fsc_amilo_pi1505_pinfix
+		.pins = (const struct alc_pincfg[]) {
+			{ 0x0b, 0x0221101f }, /* HP */
+			{ 0x0f, 0x90170310 }, /* speaker */
+			{ }
+		}
 	},
 };
 
@@ -16580,10 +16838,11 @@
 static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
 	int i;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		hda_nid_t nid = spec->autocfg.input_pins[i];
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
 		if (alc_is_input_pin(codec, nid)) {
 			alc_set_input_pin(codec, nid, i);
 			if (nid != ALC861VD_PIN_CD_NID &&
@@ -16795,16 +17054,14 @@
 };
 
 /* reset GPIO1 */
-static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
-	{0x01, AC_VERB_SET_GPIO_MASK, 0x03},
-	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
-	{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
-	{ }
-};
-
 static const struct alc_fixup alc861vd_fixups[] = {
 	[ALC660VD_FIX_ASUS_GPIO1] = {
-		.verbs = alc660vd_fix_asus_gpio1_verbs,
+		.verbs = (const struct hda_verb[]) {
+			{0x01, AC_VERB_SET_GPIO_MASK, 0x03},
+			{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+			{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+			{ }
+		}
 	},
 };
 
@@ -18818,10 +19075,11 @@
 static void alc662_auto_init_analog_input(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
 	int i;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		hda_nid_t nid = spec->autocfg.input_pins[i];
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
 		if (alc_is_input_pin(codec, nid)) {
 			alc_set_input_pin(codec, nid, i);
 			if (nid != ALC662_PIN_CD_NID &&
@@ -18915,6 +19173,26 @@
 		alc_inithook(codec);
 }
 
+enum {
+	ALC662_FIXUP_IDEAPAD,
+};
+
+static const struct alc_fixup alc662_fixups[] = {
+	[ALC662_FIXUP_IDEAPAD] = {
+		.pins = (const struct alc_pincfg[]) {
+			{ 0x17, 0x99130112 }, /* subwoofer */
+			{ }
+		}
+	},
+};
+
+static struct snd_pci_quirk alc662_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
+	{}
+};
+
+
+
 static int patch_alc662(struct hda_codec *codec)
 {
 	struct alc_spec *spec;
@@ -18947,6 +19225,7 @@
 	}
 
 	if (board_config == ALC662_AUTO) {
+		alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 1);
 		/* automatic parse from the BIOS config */
 		err = alc662_parse_auto_config(codec);
 		if (err < 0) {
@@ -19005,8 +19284,11 @@
 	spec->vmaster_nid = 0x02;
 
 	codec->patch_ops = alc_patch_ops;
-	if (board_config == ALC662_AUTO)
+	if (board_config == ALC662_AUTO) {
 		spec->init_hook = alc662_auto_init;
+		alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 0);
+	}
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	if (!spec->loopback.amplist)
 		spec->loopback.amplist = alc662_loopbacks;
@@ -19050,6 +19332,39 @@
 /*
  * Analog capture ADC cgange
  */
+static void alc680_rec_autoswitch(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int pin_found = 0;
+	int type_found = AUTO_PIN_LAST;
+	hda_nid_t nid;
+	int i;
+
+	for (i = 0; i < cfg->num_inputs; i++) {
+		nid = cfg->inputs[i].pin;
+		if (!(snd_hda_query_pin_caps(codec, nid) &
+		      AC_PINCAP_PRES_DETECT))
+			continue;
+		if (snd_hda_jack_detect(codec, nid)) {
+			if (cfg->inputs[i].type < type_found) {
+				type_found = cfg->inputs[i].type;
+				pin_found = nid;
+			}
+		}
+	}
+
+	nid = 0x07;
+	if (pin_found)
+		snd_hda_get_connections(codec, pin_found, &nid, 1);
+
+	if (nid != spec->cur_adc)
+		__snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
+	spec->cur_adc = nid;
+	snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
+				   spec->cur_adc_format);
+}
+
 static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
 				      struct hda_codec *codec,
 				      unsigned int stream_tag,
@@ -19057,24 +19372,12 @@
 				      struct snd_pcm_substream *substream)
 {
 	struct alc_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->autocfg;
-	unsigned int pre_mic, pre_line;
 
-	pre_mic  = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]);
-	pre_line = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_LINE]);
-
+	spec->cur_adc = 0x07;
 	spec->cur_adc_stream_tag = stream_tag;
 	spec->cur_adc_format = format;
 
-	if (pre_mic || pre_line) {
-		if (pre_mic)
-			snd_hda_codec_setup_stream(codec, 0x08, stream_tag, 0,
-									format);
-		else
-			snd_hda_codec_setup_stream(codec, 0x09, stream_tag, 0,
-									format);
-	} else
-		snd_hda_codec_setup_stream(codec, 0x07, stream_tag, 0, format);
+	alc680_rec_autoswitch(codec);
 	return 0;
 }
 
@@ -19160,6 +19463,7 @@
 
 	{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT   | AC_USRSP_EN},
 	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT  | AC_USRSP_EN},
+	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT  | AC_USRSP_EN},
 
 	{ }
 };
@@ -19172,25 +19476,11 @@
 	spec->autocfg.hp_pins[0] = 0x16;
 	spec->autocfg.speaker_pins[0] = 0x14;
 	spec->autocfg.speaker_pins[1] = 0x15;
-	spec->autocfg.input_pins[AUTO_PIN_MIC] = 0x18;
-	spec->autocfg.input_pins[AUTO_PIN_LINE] = 0x19;
-}
-
-static void alc680_rec_autoswitch(struct hda_codec *codec)
-{
-	struct alc_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->autocfg;
-	unsigned int present;
-	hda_nid_t new_adc;
-
-	present = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]);
-
-	new_adc = present ? 0x8 : 0x7;
-	__snd_hda_codec_cleanup_stream(codec, !present ? 0x8 : 0x7, 1);
-	snd_hda_codec_setup_stream(codec, new_adc,
-				   spec->cur_adc_stream_tag, 0,
-				   spec->cur_adc_format);
-
+	spec->autocfg.num_inputs = 2;
+	spec->autocfg.inputs[0].pin = 0x18;
+	spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
+	spec->autocfg.inputs[1].pin = 0x19;
+	spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
 }
 
 static void alc680_unsol_event(struct hda_codec *codec,
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 95148e5..e4e7d43 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -382,6 +382,11 @@
 	0x03, 0x0c, 0x20, 0x40,
 };
 
+#define STAC92HD83XXX_NUM_DMICS	 2
+static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
+	0x11, 0x20, 0
+};
+
 #define STAC92HD83XXX_NUM_CAPS	2
 static unsigned long stac92hd83xxx_capvols[] = {
 	HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
@@ -1105,9 +1110,7 @@
 		struct hda_input_mux *smux = &spec->private_smux;
 		/* check for mute support on SPDIF out */
 		if (wcaps & AC_WCAP_OUT_AMP) {
-			smux->items[smux->num_items].label = "Off";
-			smux->items[smux->num_items].index = 0;
-			smux->num_items++;
+			snd_hda_add_imux_item(smux, "Off", 0, NULL);
 			spec->spdif_mute = 1;
 		}
 		stac_smux_mixer.count = spec->num_smuxes;
@@ -1180,14 +1183,11 @@
 		if (err < 0)
 			return err;
 	}
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		nid = cfg->input_pins[i];
-		if (nid) {
-			err = stac92xx_add_jack(codec, nid,
-						SND_JACK_MICROPHONE);
-			if (err < 0)
-				return err;
-		}
+	for (i = 0; i < cfg->num_inputs; i++) {
+		nid = cfg->inputs[i].pin;
+		err = stac92xx_add_jack(codec, nid, SND_JACK_MICROPHONE);
+		if (err < 0)
+			return err;
 	}
 
 	return 0;	
@@ -2789,7 +2789,7 @@
 	}
 
 	if (control) {
-		strcpy(name, auto_pin_cfg_labels[idx]);
+		strcpy(name, hda_get_input_pin_label(codec, nid, 1));
 		return stac92xx_add_control(codec->spec, control,
 					strcat(name, " Jack Mode"), nid);
 	}
@@ -2821,41 +2821,49 @@
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	hda_nid_t nid;
 	unsigned int pincap;
+	int i;
 
 	if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
 		return 0;
-	nid = cfg->input_pins[AUTO_PIN_LINE];
-	pincap = snd_hda_query_pin_caps(codec, nid);
-	if (pincap & AC_PINCAP_OUT)
-		return nid;
+	for (i = 0; i < cfg->num_inputs; i++) {
+		if (cfg->inputs[i].type == AUTO_PIN_LINE_IN) {
+			nid = cfg->inputs[i].pin;
+			pincap = snd_hda_query_pin_caps(codec, nid);
+			if (pincap & AC_PINCAP_OUT)
+				return nid;
+		}
+	}
 	return 0;
 }
 
+static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid);
+
 /* check whether the mic-input can be used as line-out */
-static hda_nid_t check_mic_out_switch(struct hda_codec *codec)
+static hda_nid_t check_mic_out_switch(struct hda_codec *codec, hda_nid_t *dac)
 {
 	struct sigmatel_spec *spec = codec->spec;
 	struct auto_pin_cfg *cfg = &spec->autocfg;
 	unsigned int def_conf, pincap;
-	unsigned int mic_pin;
+	int i;
 
+	*dac = 0;
 	if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
 		return 0;
-	mic_pin = AUTO_PIN_MIC;
-	for (;;) {
-		hda_nid_t nid = cfg->input_pins[mic_pin];
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
+		if (cfg->inputs[i].type != AUTO_PIN_MIC)
+			continue;
 		def_conf = snd_hda_codec_get_pincfg(codec, nid);
 		/* some laptops have an internal analog microphone
 		 * which can't be used as a output */
 		if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
 			pincap = snd_hda_query_pin_caps(codec, nid);
-			if (pincap & AC_PINCAP_OUT)
-				return nid;
+			if (pincap & AC_PINCAP_OUT) {
+				*dac = get_unassigned_dac(codec, nid);
+				if (*dac)
+					return nid;
+			}
 		}
-		if (mic_pin == AUTO_PIN_MIC)
-			mic_pin = AUTO_PIN_FRONT_MIC;
-		else
-			break;
 	}
 	return 0;
 }
@@ -3002,17 +3010,14 @@
 		}
 	}
 	/* add mic as output */
-	nid = check_mic_out_switch(codec);
-	if (nid) {
-		dac = get_unassigned_dac(codec, nid);
-		if (dac) {
-			snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
-				    nid, cfg->line_outs);
-			cfg->line_out_pins[cfg->line_outs] = nid;
-			cfg->line_outs++;
-			spec->mic_switch = nid;
-			add_spec_dacs(spec, dac);
-		}
+	nid = check_mic_out_switch(codec, &dac);
+	if (nid && dac) {
+		snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
+			    nid, cfg->line_outs);
+		cfg->line_out_pins[cfg->line_outs] = nid;
+		cfg->line_outs++;
+		spec->mic_switch = nid;
+		add_spec_dacs(spec, dac);
 	}
 
 	snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
@@ -3202,13 +3207,13 @@
 			return err;
 	}
 
-	for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) {
-		nid = cfg->input_pins[idx];
-		if (nid) {
-			err = stac92xx_add_jack_mode_control(codec, nid, idx);
-			if (err < 0)
-				return err;
-		}
+	for (idx = 0; idx < cfg->num_inputs; idx++) {
+		if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN)
+			break;
+		nid = cfg->inputs[idx].pin;
+		err = stac92xx_add_jack_mode_control(codec, nid, idx);
+		if (err < 0)
+			return err;
 	}
 
 	return 0;
@@ -3254,12 +3259,9 @@
 	if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
 		return -EINVAL;
 
-	for (i = 0; i < num_cons; i++) {
-		mono_mux->items[mono_mux->num_items].label =
-					stac92xx_mono_labels[i];
-		mono_mux->items[mono_mux->num_items].index = i;
-		mono_mux->num_items++;
-	}
+	for (i = 0; i < num_cons; i++)
+		snd_hda_add_imux_item(mono_mux, stac92xx_mono_labels[i], i,
+				      NULL);
 
 	return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
 				"Mono Mux", spec->mono_nid);
@@ -3384,11 +3386,8 @@
 	if (!labels)
 		labels = stac92xx_spdif_labels;
 
-	for (i = 0; i < num_cons; i++) {
-		spdif_mux->items[spdif_mux->num_items].label = labels[i];
-		spdif_mux->items[spdif_mux->num_items].index = i;
-		spdif_mux->num_items++;
-	}
+	for (i = 0; i < num_cons; i++)
+		snd_hda_add_imux_item(spdif_mux, labels[i], i, NULL);
 
 	return 0;
 }
@@ -3415,7 +3414,7 @@
 /* create a volume assigned to the given pin (only if supported) */
 /* return 1 if the volume control is created */
 static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid,
-				   const char *label, int direction)
+				   const char *label, int idx, int direction)
 {
 	unsigned int caps, nums;
 	char name[32];
@@ -3432,8 +3431,8 @@
 	if (!nums)
 		return 0;
 	snprintf(name, sizeof(name), "%s Capture Volume", label);
-	err = stac92xx_add_control(codec->spec, STAC_CTL_WIDGET_VOL, name,
-				    HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction));
+	err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, name,
+				       HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction));
 	if (err < 0)
 		return err;
 	return 1;
@@ -3446,27 +3445,14 @@
 	struct sigmatel_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux;
 	struct hda_input_mux *dimux = &spec->private_dimux;
-	int err, i, active_mics;
+	int err, i;
 	unsigned int def_conf;
 
-	dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
-	dimux->items[dimux->num_items].index = 0;
-	dimux->num_items++;
-
-	active_mics = 0;
-	for (i = 0; i < spec->num_dmics; i++) {
-		/* check the validity: sometimes it's a dead vendor-spec node */
-		if (get_wcaps_type(get_wcaps(codec, spec->dmic_nids[i]))
-		    != AC_WID_PIN)
-			continue;
-		def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]);
-		if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
-			active_mics++;
-	}
+	snd_hda_add_imux_item(dimux, stac92xx_dmic_labels[0], 0, NULL);
 
 	for (i = 0; i < spec->num_dmics; i++) {
 		hda_nid_t nid;
-		int index;
+		int index, type_idx;
 		const char *label;
 
 		nid = spec->dmic_nids[i];
@@ -3480,29 +3466,22 @@
 		if (index < 0)
 			continue;
 
-		if (active_mics == 1)
-			label = "Digital Mic";
-		else
-			label = stac92xx_dmic_labels[dimux->num_items];
+		label = hda_get_input_pin_label(codec, nid, 1);
+		snd_hda_add_imux_item(dimux, label, index, &type_idx);
 
-		err = create_elem_capture_vol(codec, nid, label, HDA_INPUT);
+		err = create_elem_capture_vol(codec, nid, label, type_idx,
+					      HDA_INPUT);
 		if (err < 0)
 			return err;
 		if (!err) {
 			err = create_elem_capture_vol(codec, nid, label,
-						      HDA_OUTPUT);
+						      type_idx, HDA_OUTPUT);
 			if (err < 0)
 				return err;
 		}
 
-		dimux->items[dimux->num_items].label = label;
-		dimux->items[dimux->num_items].index = index;
-		dimux->num_items++;
-		if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) {
-			imux->items[imux->num_items].label = label;
-			imux->items[imux->num_items].index = index;
-			imux->num_items++;
-		}
+		if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1)
+			snd_hda_add_imux_item(imux, label, index, NULL);
 	}
 
 	return 0;
@@ -3540,10 +3519,11 @@
 	int i;
 
 	mic->pin = pin;
-	for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
-		if (pin == cfg->input_pins[i])
+	for (i = 0; i < cfg->num_inputs; i++) {
+		if (pin == cfg->inputs[i].pin)
 			break;
-	if (i <= AUTO_PIN_FRONT_MIC) {
+	}
+	if (i < cfg->num_inputs && cfg->inputs[i].type == AUTO_PIN_MIC) {
 		/* analog pin */
 		i = get_connection_index(codec, spec->mux_nids[0], pin);
 		if (i < 0)
@@ -3577,13 +3557,13 @@
 	hda_nid_t fixed, ext;
 	int i;
 
-	for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) {
-		if (cfg->input_pins[i])
+	for (i = 0; i < cfg->num_inputs; i++) {
+		if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
 			return 0; /* must be exclusively mics */
 	}
 	fixed = ext = 0;
-	for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
-		if (check_mic_pin(codec, cfg->input_pins[i], &fixed, &ext))
+	for (i = 0; i < cfg->num_inputs; i++)
+		if (check_mic_pin(codec, cfg->inputs[i].pin, &fixed, &ext))
 			return 0;
 	for (i = 0; i < spec->num_dmics; i++)
 		if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext))
@@ -3604,13 +3584,12 @@
 	struct sigmatel_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux;
 	int i, j;
+	const char *label;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		hda_nid_t nid = cfg->input_pins[i];
-		int index, err;
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
+		int index, err, type_idx;
 
-		if (!nid)
-			continue;
 		index = -1;
 		for (j = 0; j < spec->num_muxes; j++) {
 			index = get_connection_index(codec, spec->mux_nids[j],
@@ -3621,15 +3600,14 @@
 		if (index < 0)
 			continue;
 
+		label = hda_get_autocfg_input_label(codec, cfg, i);
+		snd_hda_add_imux_item(imux, label, index, &type_idx);
+
 		err = create_elem_capture_vol(codec, nid,
-					      auto_pin_cfg_labels[i],
+					      label, type_idx,
 					      HDA_INPUT);
 		if (err < 0)
 			return err;
-
-		imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
-		imux->items[imux->num_items].index = index;
-		imux->num_items++;
 	}
 	spec->num_analog_muxes = imux->num_items;
 
@@ -4304,36 +4282,33 @@
 		if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT))
 			stac_issue_unsol_event(codec, spec->ext_mic.pin);
 	}
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		hda_nid_t nid = cfg->input_pins[i];
-		if (nid) {
-			unsigned int pinctl, conf;
-			if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
-				/* for mic pins, force to initialize */
-				pinctl = stac92xx_get_default_vref(codec, nid);
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
+		int type = cfg->inputs[i].type;
+		unsigned int pinctl, conf;
+		if (type == AUTO_PIN_MIC) {
+			/* for mic pins, force to initialize */
+			pinctl = stac92xx_get_default_vref(codec, nid);
+			pinctl |= AC_PINCTL_IN_EN;
+			stac92xx_auto_set_pinctl(codec, nid, pinctl);
+		} else {
+			pinctl = snd_hda_codec_read(codec, nid, 0,
+					AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+			/* if PINCTL already set then skip */
+			/* Also, if both INPUT and OUTPUT are set,
+			 * it must be a BIOS bug; need to override, too
+			 */
+			if (!(pinctl & AC_PINCTL_IN_EN) ||
+			    (pinctl & AC_PINCTL_OUT_EN)) {
+				pinctl &= ~AC_PINCTL_OUT_EN;
 				pinctl |= AC_PINCTL_IN_EN;
 				stac92xx_auto_set_pinctl(codec, nid, pinctl);
-			} else {
-				pinctl = snd_hda_codec_read(codec, nid, 0,
-					AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-				/* if PINCTL already set then skip */
-				/* Also, if both INPUT and OUTPUT are set,
-				 * it must be a BIOS bug; need to override, too
-				 */
-				if (!(pinctl & AC_PINCTL_IN_EN) ||
-				    (pinctl & AC_PINCTL_OUT_EN)) {
-					pinctl &= ~AC_PINCTL_OUT_EN;
-					pinctl |= AC_PINCTL_IN_EN;
-					stac92xx_auto_set_pinctl(codec, nid,
-								 pinctl);
-				}
 			}
-			conf = snd_hda_codec_get_pincfg(codec, nid);
-			if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
-				if (enable_pin_detect(codec, nid,
-						      STAC_INSERT_EVENT))
-					stac_issue_unsol_event(codec, nid);
-			}
+		}
+		conf = snd_hda_codec_get_pincfg(codec, nid);
+		if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
+			if (enable_pin_detect(codec, nid, STAC_INSERT_EVENT))
+				stac_issue_unsol_event(codec, nid);
 		}
 	}
 	for (i = 0; i < spec->num_dmics; i++)
@@ -4686,6 +4661,36 @@
 	}
 }
 
+/* get the pin connection (fixed, none, etc) */
+static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	unsigned int cfg;
+
+	cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
+	return get_defcfg_connect(cfg);
+}
+
+static int stac92xx_connected_ports(struct hda_codec *codec,
+					 hda_nid_t *nids, int num_nids)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	int idx, num;
+	unsigned int def_conf;
+
+	for (num = 0; num < num_nids; num++) {
+		for (idx = 0; idx < spec->num_pins; idx++)
+			if (spec->pin_nids[idx] == nids[num])
+				break;
+		if (idx >= spec->num_pins)
+			break;
+		def_conf = stac_get_defcfg_connect(codec, idx);
+		if (def_conf == AC_JACK_PORT_NONE)
+			break;
+	}
+	return num;
+}
+
 static void stac92xx_mic_detect(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
@@ -5316,6 +5321,8 @@
 	spec->linear_tone_beep = 1;
 	codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
 	spec->digbeep_nid = 0x21;
+	spec->dmic_nids = stac92hd83xxx_dmic_nids;
+	spec->dmux_nids = stac92hd83xxx_mux_nids;
 	spec->mux_nids = stac92hd83xxx_mux_nids;
 	spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids);
 	spec->adc_nids = stac92hd83xxx_adc_nids;
@@ -5361,9 +5368,13 @@
 	case 0x111d76d4:
 	case 0x111d7605:
 	case 0x111d76d5:
+	case 0x111d76e7:
 		if (spec->board_config == STAC_92HD83XXX_PWR_REF)
 			break;
 		spec->num_pwrs = 0;
+		spec->num_dmics = stac92xx_connected_ports(codec,
+				stac92hd83xxx_dmic_nids,
+				STAC92HD83XXX_NUM_DMICS);
 		break;
 	}
 
@@ -5422,36 +5433,6 @@
 	return 0;
 }
 
-/* get the pin connection (fixed, none, etc) */
-static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
-{
-	struct sigmatel_spec *spec = codec->spec;
-	unsigned int cfg;
-
-	cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
-	return get_defcfg_connect(cfg);
-}
-
-static int stac92hd71bxx_connected_ports(struct hda_codec *codec,
-					 hda_nid_t *nids, int num_nids)
-{
-	struct sigmatel_spec *spec = codec->spec;
-	int idx, num;
-	unsigned int def_conf;
-
-	for (num = 0; num < num_nids; num++) {
-		for (idx = 0; idx < spec->num_pins; idx++)
-			if (spec->pin_nids[idx] == nids[num])
-				break;
-		if (idx >= spec->num_pins)
-			break;
-		def_conf = stac_get_defcfg_connect(codec, idx);
-		if (def_conf == AC_JACK_PORT_NONE)
-			break;
-	}
-	return num;
-}
-
 static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec,
 					  hda_nid_t dig0pin)
 {
@@ -5590,7 +5571,7 @@
 	case 0x111d76b5:
 		spec->init = stac92hd71bxx_core_init;
 		codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
-		spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+		spec->num_dmics = stac92xx_connected_ports(codec,
 					stac92hd71bxx_dmic_nids,
 					STAC92HD71BXX_NUM_DMICS);
 		break;
@@ -5622,7 +5603,7 @@
 		snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
 		snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
 		stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0;
-		spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+		spec->num_dmics = stac92xx_connected_ports(codec,
 					stac92hd71bxx_dmic_nids,
 					STAC92HD71BXX_NUM_DMICS - 1);
 		break;
@@ -5636,7 +5617,7 @@
 	default:
 		spec->init = stac92hd71bxx_core_init;
 		codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
-		spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+		spec->num_dmics = stac92xx_connected_ports(codec,
 					stac92hd71bxx_dmic_nids,
 					STAC92HD71BXX_NUM_DMICS);
 		break;
@@ -6318,6 +6299,8 @@
 	{ .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx },
 	{ .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx },
 	{ .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx },
+	{ .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx},
 	{} /* terminator */
 };
 
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index ae3acb2..d1c3f8d 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -444,8 +444,8 @@
 
 
 /* add dynamic controls */
-static int via_add_control(struct via_spec *spec, int type, const char *name,
-			   unsigned long val)
+static int __via_add_control(struct via_spec *spec, int type, const char *name,
+			     int idx, unsigned long val)
 {
 	struct snd_kcontrol_new *knew;
 
@@ -463,6 +463,9 @@
 	return 0;
 }
 
+#define via_add_control(spec, type, name, val) \
+	__via_add_control(spec, type, name, 0, val)
+
 static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec,
 						struct snd_kcontrol_new *tmpl)
 {
@@ -494,18 +497,18 @@
 
 /* create input playback/capture controls for the given pin */
 static int via_new_analog_input(struct via_spec *spec, const char *ctlname,
-				int idx, int mix_nid)
+				int type_idx, int idx, int mix_nid)
 {
 	char name[32];
 	int err;
 
 	sprintf(name, "%s Playback Volume", ctlname);
-	err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+	err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx,
 			      HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
 	if (err < 0)
 		return err;
 	sprintf(name, "%s Playback Switch", ctlname);
-	err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name,
+	err = __via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name, type_idx,
 			      HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
 	if (err < 0)
 		return err;
@@ -557,17 +560,15 @@
 static void via_auto_init_analog_input(struct hda_codec *codec)
 {
 	struct via_spec *spec = codec->spec;
+	const struct auto_pin_cfg *cfg = &spec->autocfg;
 	unsigned int ctl;
 	int i;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		hda_nid_t nid = spec->autocfg.input_pins[i];
-		if (!nid)
-			continue;
-
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
 		if (spec->smart51_enabled && is_smart51_pins(spec, nid))
 			ctl = PIN_OUT;
-		else if (i <= AUTO_PIN_FRONT_MIC)
+		else if (i == AUTO_PIN_MIC)
 			ctl = PIN_VREF50;
 		else
 			ctl = PIN_IN;
@@ -1322,15 +1323,14 @@
 }
 static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin)
 {
-	int res = 0;
-	int index;
-	for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) {
-		if (pin == spec->autocfg.input_pins[index]) {
-			res = 1;
-			break;
-		}
+	const struct auto_pin_cfg *cfg = &spec->autocfg;
+	int i;
+
+	for (i = 0; i < cfg->num_inputs; i++) {
+		if (pin == cfg->inputs[i].pin)
+			return cfg->inputs[i].type <= AUTO_PIN_LINE_IN;
 	}
-	return res;
+	return 0;
 }
 
 static int via_smart51_info(struct snd_kcontrol *kcontrol,
@@ -1348,25 +1348,21 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct via_spec *spec = codec->spec;
-	int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
+	const struct auto_pin_cfg *cfg = &spec->autocfg;
 	int on = 1;
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(index); i++) {
-		hda_nid_t nid = spec->autocfg.input_pins[index[i]];
-		if (nid) {
-			int ctl =
-			    snd_hda_codec_read(codec, nid, 0,
-					       AC_VERB_GET_PIN_WIDGET_CONTROL,
-					       0);
-			if (i == AUTO_PIN_FRONT_MIC
-			    && spec->hp_independent_mode
-			    && spec->codec_type != VT1718S)
-				continue; /* ignore FMic for independent HP */
-			if (ctl & AC_PINCTL_IN_EN
-			    && !(ctl & AC_PINCTL_OUT_EN))
-				on = 0;
-		}
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
+		int ctl = snd_hda_codec_read(codec, nid, 0,
+					     AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+		if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
+			continue;
+		if (cfg->inputs[i].type == AUTO_PIN_MIC &&
+		    spec->hp_independent_mode && spec->codec_type != VT1718S)
+			continue; /* ignore FMic for independent HP */
+		if ((ctl & AC_PINCTL_IN_EN) && !(ctl & AC_PINCTL_OUT_EN))
+			on = 0;
 	}
 	*ucontrol->value.integer.value = on;
 	return 0;
@@ -1377,36 +1373,38 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct via_spec *spec = codec->spec;
+	const struct auto_pin_cfg *cfg = &spec->autocfg;
 	int out_in = *ucontrol->value.integer.value
 		? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN;
-	int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(index); i++) {
-		hda_nid_t nid = spec->autocfg.input_pins[index[i]];
-		if (i == AUTO_PIN_FRONT_MIC
-		    && spec->hp_independent_mode
-		    && spec->codec_type != VT1718S)
+	for (i = 0; i < cfg->num_inputs; i++) {
+		hda_nid_t nid = cfg->inputs[i].pin;
+		unsigned int parm;
+
+		if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
+			continue;
+		if (cfg->inputs[i].type == AUTO_PIN_MIC &&
+		    spec->hp_independent_mode && spec->codec_type != VT1718S)
 			continue; /* don't retask FMic for independent HP */
-		if (nid) {
-			unsigned int parm = snd_hda_codec_read(
-				codec, nid, 0,
-				AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-			parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
-			parm |= out_in;
-			snd_hda_codec_write(codec, nid, 0,
-					    AC_VERB_SET_PIN_WIDGET_CONTROL,
-					    parm);
-			if (out_in == AC_PINCTL_OUT_EN) {
-				mute_aa_path(codec, 1);
-				notify_aa_path_ctls(codec);
-			}
-			if (spec->codec_type == VT1718S)
-				snd_hda_codec_amp_stereo(
+
+		parm = snd_hda_codec_read(codec, nid, 0,
+					  AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+		parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
+		parm |= out_in;
+		snd_hda_codec_write(codec, nid, 0,
+				    AC_VERB_SET_PIN_WIDGET_CONTROL,
+				    parm);
+		if (out_in == AC_PINCTL_OUT_EN) {
+			mute_aa_path(codec, 1);
+			notify_aa_path_ctls(codec);
+		}
+		if (spec->codec_type == VT1718S) {
+			snd_hda_codec_amp_stereo(
 					codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE,
 					HDA_AMP_UNMUTE);
 		}
-		if (i == AUTO_PIN_FRONT_MIC) {
+		if (cfg->inputs[i].type == AUTO_PIN_MIC) {
 			if (spec->codec_type == VT1708S
 			    || spec->codec_type == VT1716S) {
 				/* input = index 1 (AOW3) */
@@ -1442,7 +1440,7 @@
 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 };
+	const struct auto_pin_cfg *cfg = &spec->autocfg;
 	hda_nid_t nid;
 	int i;
 
@@ -1450,13 +1448,14 @@
 	if (knew == NULL)
 		return -ENOMEM;
 
-	for (i = 0; i < ARRAY_SIZE(index); i++) {
-		nid = spec->autocfg.input_pins[index[i]];
-		if (nid) {
+	for (i = 0; i < cfg->num_inputs; i++) {
+		nid = cfg->inputs[i].pin;
+		if (cfg->inputs[i].type <= AUTO_PIN_LINE_IN) {
 			knew = via_clone_control(spec, &via_smart51_mixer[1]);
 			if (knew == NULL)
 				return -ENOMEM;
 			knew->subdevice = nid;
+			break;
 		}
 	}
 
@@ -2375,13 +2374,8 @@
 	static const char *texts[] = { "OFF", "ON", NULL};
 
 	/* for hp mode select */
-	i = 0;
-	while (texts[i] != NULL) {
-		imux->items[imux->num_items].label =  texts[i];
-		imux->items[imux->num_items].index = i;
-		imux->num_items++;
-		i++;
-	}
+	for (i = 0; texts[i]; i++)
+		snd_hda_add_imux_item(imux, texts[i], i, NULL);
 
 	spec->hp_mux = &spec->private_imux[1];
 }
@@ -2413,51 +2407,53 @@
 }
 
 /* create playback/capture controls for input pins */
-static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
-						const struct auto_pin_cfg *cfg)
+static int vt_auto_create_analog_input_ctls(struct hda_codec *codec,
+					    const struct auto_pin_cfg *cfg,
+					    hda_nid_t cap_nid,
+					    hda_nid_t pin_idxs[], int num_idxs)
 {
-	static char *labels[] = {
-		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-	};
+	struct via_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux[0];
-	int i, err, idx = 0;
+	int i, err, idx, type, type_idx = 0;
 
 	/* for internal loopback recording select */
-	imux->items[imux->num_items].label = "Stereo Mixer";
-	imux->items[imux->num_items].index = idx;
-	imux->num_items++;
-
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		if (!cfg->input_pins[i])
-			continue;
-
-		switch (cfg->input_pins[i]) {
-		case 0x1d: /* Mic */
-			idx = 2;
-			break;
-
-		case 0x1e: /* Line In */
-			idx = 3;
-			break;
-
-		case 0x21: /* Front Mic */
-			idx = 4;
-			break;
-
-		case 0x24: /* CD */
-			idx = 1;
+	for (idx = 0; idx < num_idxs; idx++) {
+		if (pin_idxs[idx] == 0xff) {
+			snd_hda_add_imux_item(imux, "Stereo Mixer", idx, NULL);
 			break;
 		}
-		err = via_new_analog_input(spec, labels[i], idx, 0x17);
+	}
+
+	for (i = 0; i < cfg->num_inputs; i++) {
+		const char *label;
+		type = cfg->inputs[i].type;
+		for (idx = 0; idx < num_idxs; idx++)
+			if (pin_idxs[idx] == cfg->inputs[i].pin)
+				break;
+		if (idx >= num_idxs)
+			continue;
+		if (i > 0 && type == cfg->inputs[i - 1].type)
+			type_idx++;
+		else
+			type_idx = 0;
+		label = hda_get_autocfg_input_label(codec, cfg, i);
+		err = via_new_analog_input(spec, label, type_idx, idx, cap_nid);
 		if (err < 0)
 			return err;
-		imux->items[imux->num_items].label = labels[i];
-		imux->items[imux->num_items].index = idx;
-		imux->num_items++;
+		snd_hda_add_imux_item(imux, label, idx, NULL);
 	}
 	return 0;
 }
 
+/* create playback/capture controls for input pins */
+static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec,
+						const struct auto_pin_cfg *cfg)
+{
+	static hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 };
+	return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs,
+						ARRAY_SIZE(pin_idxs));
+}
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static struct hda_amp_list vt1708_loopbacks[] = {
 	{ 0x17, HDA_INPUT, 1 },
@@ -2554,7 +2550,7 @@
 	err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
 	if (err < 0)
 		return err;
-	err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	err = vt1708_auto_create_analog_input_ctls(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
 	/* add jack detect on/off control */
@@ -3021,49 +3017,12 @@
 }
 
 /* create playback/capture controls for input pins */
-static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static char *labels[] = {
-		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-	};
-	struct hda_input_mux *imux = &spec->private_imux[0];
-	int i, err, idx = 0;
-
-	/* for internal loopback recording select */
-	imux->items[imux->num_items].label = "Stereo Mixer";
-	imux->items[imux->num_items].index = idx;
-	imux->num_items++;
-
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		if (!cfg->input_pins[i])
-			continue;
-
-		switch (cfg->input_pins[i]) {
-		case 0x1d: /* Mic */
-			idx = 2;
-			break;
-
-		case 0x1e: /* Line In */
-			idx = 3;
-			break;
-
-		case 0x21: /* Front Mic */
-			idx = 4;
-			break;
-
-		case 0x23: /* CD */
-			idx = 1;
-			break;
-		}
-		err = via_new_analog_input(spec, labels[i], idx, 0x18);
-		if (err < 0)
-			return err;
-		imux->items[imux->num_items].label = labels[i];
-		imux->items[imux->num_items].index = idx;
-		imux->num_items++;
-	}
-	return 0;
+	static hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 };
+	return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs,
+						ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1709_parse_auto_config(struct hda_codec *codec)
@@ -3086,7 +3045,7 @@
 	err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
 	if (err < 0)
 		return err;
-	err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	err = vt1709_auto_create_analog_input_ctls(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
 
@@ -3588,49 +3547,12 @@
 }
 
 /* create playback/capture controls for input pins */
-static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static char *labels[] = {
-		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-	};
-	struct hda_input_mux *imux = &spec->private_imux[0];
-	int i, err, idx = 0;
-
-	/* for internal loopback recording select */
-	imux->items[imux->num_items].label = "Stereo Mixer";
-	imux->items[imux->num_items].index = idx;
-	imux->num_items++;
-
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		if (!cfg->input_pins[i])
-			continue;
-
-		switch (cfg->input_pins[i]) {
-		case 0x1a: /* Mic */
-			idx = 2;
-			break;
-
-		case 0x1b: /* Line In */
-			idx = 3;
-			break;
-
-		case 0x1e: /* Front Mic */
-			idx = 4;
-			break;
-
-		case 0x1f: /* CD */
-			idx = 1;
-			break;
-		}
-		err = via_new_analog_input(spec, labels[i], idx, 0x16);
-		if (err < 0)
-			return err;
-		imux->items[imux->num_items].label = labels[i];
-		imux->items[imux->num_items].index = idx;
-		imux->num_items++;
-	}
-	return 0;
+	static hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e };
+	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
+						ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1708B_parse_auto_config(struct hda_codec *codec)
@@ -3653,7 +3575,7 @@
 	err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
 	if (err < 0)
 		return err;
-	err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	err = vt1708B_auto_create_analog_input_ctls(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
 
@@ -4061,49 +3983,12 @@
 }
 
 /* create playback/capture controls for input pins */
-static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static char *labels[] = {
-		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-	};
-	struct hda_input_mux *imux = &spec->private_imux[0];
-	int i, err, idx = 0;
-
-	/* for internal loopback recording select */
-	imux->items[imux->num_items].label = "Stereo Mixer";
-	imux->items[imux->num_items].index = 5;
-	imux->num_items++;
-
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		if (!cfg->input_pins[i])
-			continue;
-
-		switch (cfg->input_pins[i]) {
-		case 0x1a: /* Mic */
-			idx = 2;
-			break;
-
-		case 0x1b: /* Line In */
-			idx = 3;
-			break;
-
-		case 0x1e: /* Front Mic */
-			idx = 4;
-			break;
-
-		case 0x1f: /* CD */
-			idx = 1;
-			break;
-		}
-		err = via_new_analog_input(spec, labels[i], idx, 0x16);
-		if (err < 0)
-			return err;
-		imux->items[imux->num_items].label = labels[i];
-		imux->items[imux->num_items].index = idx-1;
-		imux->num_items++;
-	}
-	return 0;
+	static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
+	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
+						ARRAY_SIZE(pin_idxs));
 }
 
 /* fill out digital output widgets; one for master and one for slave outputs */
@@ -4151,7 +4036,7 @@
 	err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
 	if (err < 0)
 		return err;
-	err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	err = vt1708S_auto_create_analog_input_ctls(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
 
@@ -4441,58 +4326,20 @@
 	imux = &spec->private_imux[1];
 
 	/* for hp mode select */
-	i = 0;
-	while (texts[i] != NULL)	{
-		imux->items[imux->num_items].label =  texts[i];
-		imux->items[imux->num_items].index = i;
-		imux->num_items++;
-		i++;
-	}
+	for (i = 0; texts[i]; i++)
+		snd_hda_add_imux_item(imux, texts[i], i, NULL);
 
 	spec->hp_mux = &spec->private_imux[1];
 	return 0;
 }
 
 /* create playback/capture controls for input pins */
-static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static char *labels[] = {
-		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-	};
-	struct hda_input_mux *imux = &spec->private_imux[0];
-	int i, err, idx = 0;
-
-	/* for internal loopback recording select */
-	imux->items[imux->num_items].label = "Stereo Mixer";
-	imux->items[imux->num_items].index = 3;
-	imux->num_items++;
-
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		if (!cfg->input_pins[i])
-			continue;
-
-		switch (cfg->input_pins[i]) {
-		case 0x14: /* Mic */
-			idx = 1;
-			break;
-
-		case 0x15: /* Line In */
-			idx = 2;
-			break;
-
-		case 0x18: /* Front Mic */
-			idx = 3;
-			break;
-		}
-		err = via_new_analog_input(spec, labels[i], idx, 0x1A);
-		if (err < 0)
-			return err;
-		imux->items[imux->num_items].label = labels[i];
-		imux->items[imux->num_items].index = idx-1;
-		imux->num_items++;
-	}
-	return 0;
+	static hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff };
+	return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs,
+						ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1702_parse_auto_config(struct hda_codec *codec)
@@ -4521,7 +4368,7 @@
 				  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
 				  (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
 				  (1 << AC_AMPCAP_MUTE_SHIFT));
-	err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	err = vt1702_auto_create_analog_input_ctls(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
 
@@ -4872,49 +4719,12 @@
 }
 
 /* create playback/capture controls for input pins */
-static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static char *labels[] = {
-		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-	};
-	struct hda_input_mux *imux = &spec->private_imux[0];
-	int i, err, idx = 0;
-
-	/* for internal loopback recording select */
-	imux->items[imux->num_items].label = "Stereo Mixer";
-	imux->items[imux->num_items].index = 5;
-	imux->num_items++;
-
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		if (!cfg->input_pins[i])
-			continue;
-
-		switch (cfg->input_pins[i]) {
-		case 0x2b: /* Mic */
-			idx = 1;
-			break;
-
-		case 0x2a: /* Line In */
-			idx = 2;
-			break;
-
-		case 0x29: /* Front Mic */
-			idx = 3;
-			break;
-
-		case 0x2c: /* CD */
-			idx = 0;
-			break;
-		}
-		err = via_new_analog_input(spec, labels[i], idx, 0x21);
-		if (err < 0)
-			return err;
-		imux->items[imux->num_items].label = labels[i];
-		imux->items[imux->num_items].index = idx;
-		imux->num_items++;
-	}
-	return 0;
+	static hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff };
+	return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
+						ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1718S_parse_auto_config(struct hda_codec *codec)
@@ -4938,7 +4748,7 @@
 	err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
 	if (err < 0)
 		return err;
-	err = vt1718S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	err = vt1718S_auto_create_analog_input_ctls(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
 
@@ -5371,49 +5181,12 @@
 }
 
 /* create playback/capture controls for input pins */
-static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static char *labels[] = {
-		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-	};
-	struct hda_input_mux *imux = &spec->private_imux[0];
-	int i, err, idx = 0;
-
-	/* for internal loopback recording select */
-	imux->items[imux->num_items].label = "Stereo Mixer";
-	imux->items[imux->num_items].index = 5;
-	imux->num_items++;
-
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		if (!cfg->input_pins[i])
-			continue;
-
-		switch (cfg->input_pins[i]) {
-		case 0x1a: /* Mic */
-			idx = 2;
-			break;
-
-		case 0x1b: /* Line In */
-			idx = 3;
-			break;
-
-		case 0x1e: /* Front Mic */
-			idx = 4;
-			break;
-
-		case 0x1f: /* CD */
-			idx = 1;
-			break;
-		}
-		err = via_new_analog_input(spec, labels[i], idx, 0x16);
-		if (err < 0)
-			return err;
-		imux->items[imux->num_items].label = labels[i];
-		imux->items[imux->num_items].index = idx-1;
-		imux->num_items++;
-	}
-	return 0;
+	static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
+	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
+						ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1716S_parse_auto_config(struct hda_codec *codec)
@@ -5436,7 +5209,7 @@
 	err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
 	if (err < 0)
 		return err;
-	err = vt1716S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	err = vt1716S_auto_create_analog_input_ctls(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
 
@@ -5717,54 +5490,25 @@
 }
 
 /* create playback/capture controls for input pins */
-static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static char *labels[] = {
-		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-	};
+	struct via_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux[0];
-	int i, err, idx = 0;
+	static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff };
+	int err;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		if (!cfg->input_pins[i])
-			continue;
-
-		switch (cfg->input_pins[i]) {
-		case 0x2b: /* Mic */
-			idx = 0;
-			break;
-
-		case 0x2a: /* Line In */
-			idx = 1;
-			break;
-
-		case 0x29: /* Front Mic */
-			idx = 2;
-			break;
-		}
-		err = via_new_analog_input(spec, labels[i], idx, 0x21);
-		if (err < 0)
-			return err;
-		imux->items[imux->num_items].label = labels[i];
-		imux->items[imux->num_items].index = idx;
-		imux->num_items++;
-	}
-
+	err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
+					       ARRAY_SIZE(pin_idxs));
+	if (err < 0)
+		return err;
 	/* build volume/mute control of loopback */
-	err = via_new_analog_input(spec, "Stereo Mixer", 3, 0x21);
+	err = via_new_analog_input(spec, "Stereo Mixer", 0, 3, 0x21);
 	if (err < 0)
 		return err;
 
-	/* for internal loopback recording select */
-	imux->items[imux->num_items].label = "Stereo Mixer";
-	imux->items[imux->num_items].index = 3;
-	imux->num_items++;
-
 	/* for digital mic select */
-	imux->items[imux->num_items].label = "Digital Mic";
-	imux->items[imux->num_items].index = 4;
-	imux->num_items++;
+	snd_hda_add_imux_item(imux, "Digital Mic", 4, NULL);
 
 	return 0;
 }
@@ -5792,7 +5536,7 @@
 	err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
 	if (err < 0)
 		return err;
-	err = vt2002P_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	err = vt2002P_auto_create_analog_input_ctls(codec, &spec->autocfg);
 	if (err < 0)
 		return err;
 
@@ -6067,53 +5811,26 @@
 }
 
 /* create playback/capture controls for input pins */
-static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
 {
-	static char *labels[] = {
-		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-	};
+	struct via_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux[0];
-	int i, err, idx = 0;
+	static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff };
+	int err;
 
-	for (i = 0; i < AUTO_PIN_LAST; i++) {
-		if (!cfg->input_pins[i])
-			continue;
-
-		switch (cfg->input_pins[i]) {
-		case 0x2b: /* Mic */
-			idx = 0;
-			break;
-
-		case 0x2a: /* Line In */
-			idx = 1;
-			break;
-
-		case 0x29: /* Front Mic */
-			idx = 2;
-			break;
-		}
-		err = via_new_analog_input(spec, labels[i], idx, 0x21);
-		if (err < 0)
-			return err;
-		imux->items[imux->num_items].label = labels[i];
-		imux->items[imux->num_items].index = idx;
-		imux->num_items++;
-	}
-	/* build volume/mute control of loopback */
-	err = via_new_analog_input(spec, "Stereo Mixer", 5, 0x21);
+	err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
+					       ARRAY_SIZE(pin_idxs));
 	if (err < 0)
 		return err;
 
-	/* for internal loopback recording select */
-	imux->items[imux->num_items].label = "Stereo Mixer";
-	imux->items[imux->num_items].index = 5;
-	imux->num_items++;
+	/* build volume/mute control of loopback */
+	err = via_new_analog_input(spec, "Stereo Mixer", 0, 5, 0x21);
+	if (err < 0)
+		return err;
 
 	/* for digital mic select */
-	imux->items[imux->num_items].label = "Digital Mic";
-	imux->items[imux->num_items].index = 6;
-	imux->num_items++;
+	snd_hda_add_imux_item(imux, "Digital Mic", 6, NULL);
 
 	return 0;
 }
@@ -6141,7 +5858,7 @@
 	err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
 	if (err < 0)
 		return err;
-	err = vt1812_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	err = vt1812_auto_create_analog_input_ctls(codec, &spec->autocfg);
 	if (err < 0)
 		return err;