ALSA: hda - Build boost controls from selector widget in Cxt auto-parser
authorTakashi Iwai <tiwai@suse.de>
Mon, 16 May 2011 09:33:02 +0000 (11:33 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 16 May 2011 09:33:02 +0000 (11:33 +0200)
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>
sound/pci/hda/patch_conexant.c

index 6c9abee..28664e1 100644 (file)
@@ -108,6 +108,7 @@ struct conexant_spec {
        /* 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 @@ static int cx_auto_mux_enum_get(struct snd_kcontrol *kcontrol,
  * 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 int __select_input_connection(struct hda_codec *codec, hda_nid_t mux,
 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 @@ static void cx_auto_parse_input(struct hda_codec *codec)
                        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 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
        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 {