ALSA: hda - Improve the input source name labels

This patch improves the input-source label strings to be generated from
the pin information instead of fixed strings per AUTO_PIN_* type.
This gives more suitable labels, especially for mic and line-in pins.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 0ee4439..e328434 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -4607,7 +4607,7 @@
 	snd_printd("   inputs:");
 	for (i = 0; i < cfg->num_inputs; i++) {
 		snd_printdd(" %s=0x%x",
-			    auto_pin_cfg_labels[cfg->inputs[i].type],
+			    hda_get_autocfg_input_label(codec, cfg, i),
 			    cfg->inputs[i].pin);
 	}
 	snd_printd("\n");
@@ -4618,28 +4618,87 @@
 }
 EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config);
 
-/* labels for input pins - for obsoleted config stuff */
-const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = {
-	"Mic", "Line", "CD", "Aux"
-};
-EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
+const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
+					int check_location)
+{
+	unsigned int def_conf, loc;
 
-void snd_hda_get_input_pin_label(const struct auto_pin_cfg *cfg,
-				 int input, char *str)
+	def_conf = snd_hda_codec_get_pincfg(codec, pin);
+	loc = get_defcfg_location(def_conf);
+
+	switch (get_defcfg_device(def_conf)) {
+	case AC_JACK_MIC_IN:
+		if (!check_location)
+			return "Mic";
+		if (get_defcfg_connect(def_conf) == AC_JACK_PORT_FIXED ||
+		    (loc & 0x30) == AC_JACK_LOC_INTERNAL)
+			return "Internal Mic";
+		if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
+			return "Dock Mic";
+		if (loc == AC_JACK_LOC_REAR)
+			return "Rear Mic";
+		return "Mic";
+	case AC_JACK_LINE_IN:
+		if (!check_location)
+			return "Line";
+		if ((loc & 0xf0) == AC_JACK_LOC_SEPARATE)
+			return "Dock Line";
+		return "Line";
+	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);
+
+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 idx;
+	int has_multiple_pins = 0;
 
-	for  (idx = 0; idx < 3 && --input >= 0; idx++) {
-		if (type != cfg->inputs[input].type)
-			break;
-	}
-	if (idx > 0)
-		sprintf(str, "%s %d", auto_pin_cfg_labels[type], idx);
-	else
-		strcpy(str, auto_pin_cfg_labels[type]);
+	if ((input > 0 && cfg->inputs[input - 1].type == type) ||
+	    (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
+		has_multiple_pins = 1;
+	return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
+				       has_multiple_pins);
 }
-EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_label);
+EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
+
+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 cce18ba..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);
-	strcpy(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 72e7b2f..6943efc 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -378,8 +378,6 @@
 	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
 
@@ -389,8 +387,13 @@
 };
 
 struct auto_pin_cfg;
-void snd_hda_get_input_pin_label(const struct auto_pin_cfg *cfg,
-				 int input, char *label);
+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;
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 85fc0b9..05db1cf 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -2909,32 +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, type, type_idx = 0;
+	int i, err, type, type_idx;
 
 	for (i = 0; i < cfg->num_inputs; i++) {
+		const char *label;
 		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);
+		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,
-				       auto_pin_cfg_labels[type], type_idx,
+				       label, type_idx,
 				       type == AUTO_PIN_MIC);
 		if (err < 0)
 			return err;
-		snd_hda_get_input_pin_label(cfg, i,
-			imux->items[imux->num_items].label);
-		imux->items[imux->num_items].index =
-			ad1988_pin_to_adc_idx(cfg->inputs[i].pin);
-		imux->num_items++;
 	}
-	strcpy(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",
@@ -3046,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 42b3fb4..cca11fd 100644
--- a/sound/pci/hda/patch_ca0110.c
+++ b/sound/pci/hda/patch_ca0110.c
@@ -474,8 +474,7 @@
 		if (j >= cfg->num_inputs)
 			continue;
 		spec->input_pins[n] = pin;
-		spec->input_labels[n] =
-			auto_pin_cfg_labels[cfg->inputs[j].type];
+		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 adb5ec5..ae75283 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -673,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;
@@ -681,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;
 }
 
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 8ae30cc..9c2c19c 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -4947,6 +4947,7 @@
 
 	for (i = 0; i < cfg->num_inputs; i++) {
 		hda_nid_t pin;
+		const char *label;
 
 		pin = cfg->inputs[i].pin;
 		if (!alc_is_input_pin(codec, pin))
@@ -4957,12 +4958,13 @@
 			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[type],
-						       type_idx, idx, mixer);
+						       label, type_idx,
+						       idx, mixer);
 				if (err < 0)
 					return err;
 			}
@@ -4973,12 +4975,8 @@
 		idx = get_connection_index(codec, cap1, pin);
 		if (idx < 0 && cap2)
 			idx = get_connection_index(codec, cap2, pin);
-		if (idx >= 0) {
-			snd_hda_get_input_pin_label(cfg, i,
-				imux->items[imux->num_items].label);
-			imux->items[imux->num_items].index = idx;
-			imux->num_items++;
-		}
+		if (idx >= 0)
+			snd_hda_add_imux_item(imux, label, idx, NULL);
 	}
 	return 0;
 }
@@ -10626,9 +10624,9 @@
 			break;
 		nid = cfg->inputs[i].pin;
 		if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
-			char pinname[32], label[32];
-			snd_hda_get_input_pin_label(cfg, i, pinname);
-			snprintf(label, sizeof(label), "%s Boost", pinname);
+			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)
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index d9c8b4d..e4e7d43 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -191,11 +191,6 @@
 	signed char dmux_idx;
 };
 
-struct unique_input_names {
-	int num;
-	char uname[HDA_MAX_NUM_INPUTS][32];
-};
-
 struct sigmatel_spec {
 	struct snd_kcontrol_new *mixers[4];
 	unsigned int num_mixers;
@@ -312,7 +307,6 @@
 	struct hda_input_mux private_imux;
 	struct hda_input_mux private_smux;
 	struct hda_input_mux private_mono_mux;
-	struct unique_input_names private_u_inp_names;
 };
 
 static hda_nid_t stac9200_adc_nids[1] = {
@@ -1116,9 +1110,7 @@
 		struct hda_input_mux *smux = &spec->private_smux;
 		/* check for mute support on SPDIF out */
 		if (wcaps & AC_WCAP_OUT_AMP) {
-			strcpy(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;
@@ -2797,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);
 	}
@@ -3267,12 +3259,9 @@
 	if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
 		return -EINVAL;
 
-	for (i = 0; i < num_cons; i++) {
-		strcpy(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);
@@ -3397,11 +3386,8 @@
 	if (!labels)
 		labels = stac92xx_spdif_labels;
 
-	for (i = 0; i < num_cons; i++) {
-		strcpy(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;
 }
@@ -3452,76 +3438,6 @@
 	return 1;
 }
 
-static const char *get_input_src_label(struct hda_codec *codec, hda_nid_t nid)
-{
-	unsigned int def_conf;
-
-	def_conf = snd_hda_codec_get_pincfg(codec, nid);
-
-	switch (get_defcfg_device(def_conf)) {
-	case AC_JACK_MIC_IN:
-		if (get_defcfg_connect(def_conf) == AC_JACK_PORT_FIXED ||
-				((get_defcfg_location(def_conf) & 0xf0)
-						== AC_JACK_LOC_INTERNAL))
-			return "Internal Mic";
-		if ((get_defcfg_location(def_conf) & 0xf0)
-						== AC_JACK_LOC_SEPARATE)
-			return "Dock Mic";
-		if (get_defcfg_location(def_conf) == AC_JACK_LOC_REAR)
-			return "Rear Mic";
-		return "Mic";
-	case AC_JACK_LINE_IN:
-		if ((get_defcfg_location(def_conf) & 0xf0)
-						== AC_JACK_LOC_SEPARATE)
-			return "Dock Line";
-		return "Line";
-	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";
-	}
-
-	snd_printd("invalid inp pin %02x device config %08x", nid, def_conf);
-	return NULL;
-}
-
-static const char *get_unique_inp_src_label(struct hda_codec *codec,
-				hda_nid_t nid)
-{
-	int i, n;
-	const char *label;
-	struct sigmatel_spec *spec = codec->spec;
-	struct hda_input_mux *imux = &spec->private_imux;
-	struct hda_input_mux *dimux = &spec->private_dimux;
-	struct unique_input_names *unames = &spec->private_u_inp_names;
-
-	label = get_input_src_label(codec, nid);
-	n = 0;
-
-	for (i = 0; i < imux->num_items; i++) {
-		if (!strncmp(label, imux->items[i].label, strlen(label)))
-			n++;
-	}
-	if (snd_hda_get_bool_hint(codec, "separate_dmux") == 1) {
-		for (i = 0; i < dimux->num_items; i++) {
-			if (!strncmp(label, dimux->items[i].label,
-					strlen(label)))
-				n++;
-		}
-	}
-	if (n > 0 && unames->num < HDA_MAX_NUM_INPUTS) {
-		sprintf(&unames->uname[unames->num][0], "%.28s %d", label, n);
-		label = &unames->uname[unames->num][0];
-		unames->num++;
-	}
-
-	return label;
-}
-
 /* create playback/capture controls for input pins on dmic capable codecs */
 static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
 						const struct auto_pin_cfg *cfg)
@@ -3532,13 +3448,11 @@
 	int err, i;
 	unsigned int def_conf;
 
-	strcpy(dimux->items[dimux->num_items].label, stac92xx_dmic_labels[0]);
-	dimux->items[dimux->num_items].index = 0;
-	dimux->num_items++;
+	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];
@@ -3552,28 +3466,22 @@
 		if (index < 0)
 			continue;
 
-		label = get_unique_inp_src_label(codec, nid);
-		if (label == NULL)
-			return -EINVAL;
+		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, 0, 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, 0,
-						      HDA_OUTPUT);
+			err = create_elem_capture_vol(codec, nid, label,
+						      type_idx, HDA_OUTPUT);
 			if (err < 0)
 				return err;
 		}
 
-		strcpy(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) {
-			strcpy(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;
@@ -3675,12 +3583,12 @@
 {
 	struct sigmatel_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux;
-	int i, j, type_idx = 0;
+	int i, j;
 	const char *label;
 
 	for (i = 0; i < cfg->num_inputs; i++) {
 		hda_nid_t nid = cfg->inputs[i].pin;
-		int index, err;
+		int index, err, type_idx;
 
 		index = -1;
 		for (j = 0; j < spec->num_muxes; j++) {
@@ -3692,24 +3600,14 @@
 		if (index < 0)
 			continue;
 
-		if (i > 0 && cfg->inputs[i].type == cfg->inputs[i - 1].type)
-			type_idx++;
-		else
-			type_idx = 0;
-
-		label = get_unique_inp_src_label(codec, nid);
-		if (label == NULL)
-			return -EINVAL;
+		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,
 					      label, type_idx,
 					      HDA_INPUT);
 		if (err < 0)
 			return err;
-
-		strcpy(imux->items[imux->num_items].label, label);
-		imux->items[imux->num_items].index = index;
-		imux->num_items++;
 	}
 	spec->num_analog_muxes = imux->num_items;
 
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index de5f61d..d1c3f8d 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -2374,13 +2374,8 @@
 	static const char *texts[] = { "OFF", "ON", NULL};
 
 	/* for hp mode select */
-	i = 0;
-	while (texts[i] != NULL) {
-		strcpy(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];
 }
@@ -2412,26 +2407,25 @@
 }
 
 /* create playback/capture controls for input pins */
-static int vt_auto_create_analog_input_ctls(struct via_spec *spec,
+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)
 {
+	struct via_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux[0];
 	int i, err, idx, type, type_idx = 0;
 
 	/* for internal loopback recording select */
 	for (idx = 0; idx < num_idxs; idx++) {
 		if (pin_idxs[idx] == 0xff) {
-			strcpy(imux->items[imux->num_items].label,
-			       "Stereo Mixer");
-			imux->items[imux->num_items].index = idx;
-			imux->num_items++;
+			snd_hda_add_imux_item(imux, "Stereo Mixer", idx, NULL);
 			break;
 		}
 	}
 
 	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)
@@ -2442,24 +2436,21 @@
 			type_idx++;
 		else
 			type_idx = 0;
-		err = via_new_analog_input(spec, auto_pin_cfg_labels[type],
-					   type_idx, idx, cap_nid);
+		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;
-		snd_hda_get_input_pin_label(cfg, i,
-			imux->items[imux->num_items].label);
-		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 via_spec *spec,
+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(spec, cfg, 0x17, pin_idxs,
+	return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 }
 
@@ -2559,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 */
@@ -3026,11 +3017,11 @@
 }
 
 /* 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 hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 };
-	return vt_auto_create_analog_input_ctls(spec, cfg, 0x18, pin_idxs,
+	return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 }
 
@@ -3054,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;
 
@@ -3556,11 +3547,11 @@
 }
 
 /* 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 hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e };
-	return vt_auto_create_analog_input_ctls(spec, cfg, 0x16, pin_idxs,
+	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 }
 
@@ -3584,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;
 
@@ -3992,11 +3983,11 @@
 }
 
 /* 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 hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
-	return vt_auto_create_analog_input_ctls(spec, cfg, 0x16, pin_idxs,
+	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 }
 
@@ -4045,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;
 
@@ -4335,24 +4326,19 @@
 	imux = &spec->private_imux[1];
 
 	/* for hp mode select */
-	i = 0;
-	while (texts[i] != NULL)	{
-		strcpy(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 hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff };
-	return vt_auto_create_analog_input_ctls(spec, cfg, 0x1a, pin_idxs,
+	return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 }
 
@@ -4382,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;
 
@@ -4733,11 +4719,11 @@
 }
 
 /* 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 hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff };
-	return vt_auto_create_analog_input_ctls(spec, cfg, 0x21, pin_idxs,
+	return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 }
 
@@ -4762,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;
 
@@ -5195,11 +5181,11 @@
 }
 
 /* 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 hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
-	return vt_auto_create_analog_input_ctls(spec, cfg, 0x16, pin_idxs,
+	return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
 						ARRAY_SIZE(pin_idxs));
 }
 
@@ -5223,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;
 
@@ -5504,14 +5490,15 @@
 }
 
 /* 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)
 {
+	struct via_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux[0];
 	static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff };
 	int err;
 
-	err = vt_auto_create_analog_input_ctls(spec, cfg, 0x21, pin_idxs,
+	err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
 					       ARRAY_SIZE(pin_idxs));
 	if (err < 0)
 		return err;
@@ -5521,9 +5508,7 @@
 		return err;
 
 	/* for digital mic select */
-	strcpy(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;
 }
@@ -5551,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;
 
@@ -5826,14 +5811,15 @@
 }
 
 /* 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)
 {
+	struct via_spec *spec = codec->spec;
 	struct hda_input_mux *imux = &spec->private_imux[0];
 	static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff };
 	int err;
 
-	err = vt_auto_create_analog_input_ctls(spec, cfg, 0x21, pin_idxs,
+	err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
 					       ARRAY_SIZE(pin_idxs));
 	if (err < 0)
 		return err;
@@ -5844,9 +5830,7 @@
 		return err;
 
 	/* for digital mic select */
-	strcpy(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;
 }
@@ -5874,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;