ALSA: hda - Build boost controls from selector widget in Cxt auto-parser

When the intermediate selector widget in the capture path provides the
boost volume, create the corresponding volume control.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 6c9abee..28664e1 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -108,6 +108,7 @@
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
 	struct hda_input_mux private_imux;
+	int imux_cfg_idx[HDA_MAX_NUM_INPUTS]; /* corresponding autocfg.input */
 	hda_nid_t imux_adcs[HDA_MAX_NUM_INPUTS];
 	hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
 	hda_nid_t private_adc_nids[HDA_MAX_NUM_INPUTS];
@@ -3464,30 +3465,42 @@
  * if do_select is set, actually select the route.
  */
 static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux,
-				     hda_nid_t pin, bool do_select, int depth)
+				     hda_nid_t pin, hda_nid_t *srcp,
+				     bool do_select, int depth)
 {
 	hda_nid_t conn[HDA_MAX_NUM_INPUTS];
 	int i, nums;
 
+	switch (get_wcaps_type(get_wcaps(codec, mux))) {
+	case AC_WID_AUD_IN:
+	case AC_WID_AUD_SEL:
+	case AC_WID_AUD_MIX:
+		break;
+	default:
+		return -1;
+	}
+
 	nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
 	for (i = 0; i < nums; i++)
 		if (conn[i] == pin) {
 			if (do_select)
 				snd_hda_codec_write(codec, mux, 0,
 						    AC_VERB_SET_CONNECT_SEL, i);
+			if (srcp)
+				*srcp = mux;
 			return i;
 		}
 	depth++;
 	if (depth == 2)
 		return -1;
 	for (i = 0; i < nums; i++) {
-		int ret  = __select_input_connection(codec, conn[i], pin,
+		int ret  = __select_input_connection(codec, conn[i], pin, srcp,
 						     do_select, depth);
 		if (ret >= 0) {
 			if (do_select)
 				snd_hda_codec_write(codec, mux, 0,
 						    AC_VERB_SET_CONNECT_SEL, i);
-			return ret;
+			return i;
 		}
 	}
 	return -1;
@@ -3496,13 +3509,13 @@
 static void select_input_connection(struct hda_codec *codec, hda_nid_t mux,
 				   hda_nid_t pin)
 {
-	__select_input_connection(codec, mux, pin, true, 0);
+	__select_input_connection(codec, mux, pin, NULL, true, 0);
 }
 
 static int get_input_connection(struct hda_codec *codec, hda_nid_t mux,
 				hda_nid_t pin)
 {
-	return __select_input_connection(codec, mux, pin, false, 0);
+	return __select_input_connection(codec, mux, pin, NULL, false, 0);
 }
 
 static int cx_auto_mux_enum_update(struct hda_codec *codec,
@@ -3637,6 +3650,7 @@
 			if (idx >= 0) {
 				const char *label;
 				label = hda_get_autocfg_input_label(codec, cfg, i);
+				spec->imux_cfg_idx[imux->num_items] = i;
 				spec->imux_adcs[imux->num_items] = adc;
 				spec->imux_pins[imux->num_items] =
 					cfg->inputs[i].pin;
@@ -3978,35 +3992,64 @@
 	return 0;
 }
 
+static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx,
+				    const char *label, int cidx)
+{
+	struct conexant_spec *spec = codec->spec;
+	hda_nid_t mux, nid;
+	int con;
+
+	nid = spec->imux_pins[idx];
+	if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
+		return cx_auto_add_volume(codec, label, " Boost", cidx,
+					  nid, HDA_INPUT);
+	con = __select_input_connection(codec, spec->imux_adcs[idx], nid, &mux,
+					false, 0);
+	if (con < 0)
+		return 0;
+	if (get_wcaps(codec, mux) & AC_WCAP_OUT_AMP)
+		return cx_auto_add_volume(codec, label, " Boost", 0,
+					  mux, HDA_OUTPUT);
+	return 0;
+}
+
 static int cx_auto_build_input_controls(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
-	struct auto_pin_cfg *cfg = &spec->autocfg;
-	static const char *prev_label;
+	struct hda_input_mux *imux = &spec->private_imux;
+	const char *prev_label;
+	int input_conn[HDA_MAX_NUM_INPUTS];
 	int i, err, cidx;
+	int multi_connection;
+
+	multi_connection = 0;
+	for (i = 0; i < imux->num_items; i++) {
+		cidx = get_input_connection(codec, spec->imux_adcs[i],
+					    spec->imux_pins[i]);
+		input_conn[i] = (spec->imux_adcs[i] << 8) | cidx;
+		if (i > 0 && input_conn[i] != input_conn[0])
+			multi_connection = 1;
+	}
 
 	prev_label = NULL;
 	cidx = 0;
-	for (i = 0; i < cfg->num_inputs; i++) {
-		hda_nid_t nid = cfg->inputs[i].pin;
+	for (i = 0; i < imux->num_items; i++) {
+		hda_nid_t nid = spec->imux_pins[i];
 		const char *label;
-		int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP;
 
-		label = hda_get_autocfg_input_label(codec, cfg, i);
+		label = hda_get_autocfg_input_label(codec, &spec->autocfg,
+						    spec->imux_cfg_idx[i]);
 		if (label == prev_label)
 			cidx++;
 		else
 			cidx = 0;
 		prev_label = label;
 
-		if (pin_amp) {
-			err = cx_auto_add_volume(codec, label, " Boost", cidx,
-						 nid, HDA_INPUT);
-			if (err < 0)
-				return err;
-		}
+		err = cx_auto_add_boost_volume(codec, i, label, cidx);
+		if (err < 0)
+			return err;
 
-		if (cfg->num_inputs == 1) {
+		if (!multi_connection) {
 			err = cx_auto_add_capture_volume(codec, nid,
 							 "Capture", "", cidx);
 		} else {