diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index edec98f1a9a57a1ce3adfadb869ef16be8992a63..cadfe65e2fe1f6ae69246e12cf163d1f1cf03a5e 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -3056,39 +3056,92 @@ static int create_capture_mixers(struct hda_codec *codec) /* * add mic boosts if needed */ + +/* check whether the given amp is feasible as a boost volume */ +static bool check_boost_vol(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx) +{ + unsigned int step; + + if (!nid_has_volume(codec, nid, dir) || + is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) || + is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL)) + return false; + + step = (query_amp_caps(codec, nid, dir) & AC_AMPCAP_STEP_SIZE) + >> AC_AMPCAP_STEP_SIZE_SHIFT; + if (step < 0x20) + return false; + return true; +} + +/* look for a boost amp in a widget close to the pin */ +static unsigned int look_for_boost_amp(struct hda_codec *codec, + struct nid_path *path) +{ + unsigned int val = 0; + hda_nid_t nid; + int depth; + + for (depth = 0; depth < 3; depth++) { + if (depth >= path->depth - 1) + break; + nid = path->path[depth]; + if (depth && check_boost_vol(codec, nid, HDA_OUTPUT, 0)) { + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + break; + } else if (check_boost_vol(codec, nid, HDA_INPUT, + path->idx[depth])) { + val = HDA_COMPOSE_AMP_VAL(nid, 3, path->idx[depth], + HDA_INPUT); + break; + } + } + + return val; +} + static int parse_mic_boost(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; + struct hda_input_mux *imux = &spec->input_mux; int i, err; - hda_nid_t nid; - 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 boost_label[44]; - struct nid_path *path; - unsigned int val; + if (!spec->num_adc_nids) + return 0; - if (!nid_has_volume(codec, nid, HDA_INPUT)) - continue; + for (i = 0; i < imux->num_items; i++) { + struct nid_path *path; + unsigned int val; + int idx; + char boost_label[44]; - snprintf(boost_label, sizeof(boost_label), - "%s Boost Volume", - spec->input_labels[i]); - val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); - err = add_control(spec, HDA_CTL_WIDGET_VOL, - boost_label, - spec->input_label_idxs[i], val); - if (err < 0) - return err; + idx = imux->items[i].index; + if (idx >= imux->num_items) + continue; - path = snd_hda_get_nid_path(codec, nid, 0); - if (path) - path->ctls[NID_PATH_BOOST_CTL] = val; - } + /* check only line-in and mic pins */ + if (cfg->inputs[idx].type > AUTO_PIN_MIC) + continue; + + path = get_input_path(codec, 0, i); + if (!path) + continue; + + val = look_for_boost_amp(codec, path); + if (!val) + continue; + + /* create a boost control */ + snprintf(boost_label, sizeof(boost_label), + "%s Boost Volume", spec->input_labels[idx]); + err = add_control(spec, HDA_CTL_WIDGET_VOL, boost_label, + spec->input_label_idxs[idx], val); + if (err < 0) + return err; + + path->ctls[NID_PATH_BOOST_CTL] = val; } return 0; }