When a boost control influences on multiple input paths, we shouldn't pick up the name string specific to one input but rather choose a more generic name. A problem seen often is that a single mic boost controls both internal and external mics although the driver picks up the very first name randomly like "Internal Mic Boost". This should have been "Mic Boost", instead.
This patch tries to correct that behavior: when a boost control is available, check whether it conflicts with other inputs. If it does, use a common string ("Mic", "Line") as long as possible, or take a generic name "Input".
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/hda_generic.c | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-)
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 8cebdcfdcfdc..e3f934703aa2 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -3651,6 +3651,8 @@ 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; + static const char *input_type_labels[3] = { "Mic", "Line", "Input" }; + int input_type_idxs[3] = {}; int i;
if (!spec->num_adc_nids) @@ -3659,7 +3661,9 @@ static int parse_mic_boost(struct hda_codec *codec) for (i = 0; i < imux->num_items; i++) { struct nid_path *path; unsigned int val; - int idx; + int idx, type, j; + bool conflict; + const char *pfx; char boost_label[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
idx = imux->items[i].index; @@ -3678,11 +3682,43 @@ static int parse_mic_boost(struct hda_codec *codec) if (!val) continue;
+ /* check whether conflicting with other input paths */ + type = cfg->inputs[idx].type; + conflict = false; + for (j = i + 1; j < imux->num_items; j++) { + int idx_next = imux->items[i].index; + int type_next; + struct nid_path *path_next; + if (idx_next >= imux->num_items) + continue; + type_next = cfg->inputs[idx_next].type; + if (type_next > AUTO_PIN_LINE_IN) + continue; + path_next = get_input_path(codec, 0, j); + if (!path_next) + continue; + /* conflicting value? */ + if (look_for_boost_amp(codec, path_next) == val) { + conflict = true; + if (type != type_next) { + type = 2; /* generic input */ + break; + } + } + } + /* create a boost control */ + if (!conflict) { + pfx = spec->input_labels[idx]; + idx = spec->input_label_idxs[idx]; + } else { + pfx = input_type_labels[type]; + idx = input_type_idxs[type]++; + } + snprintf(boost_label, sizeof(boost_label), - "%s Boost Volume", spec->input_labels[idx]); - if (!add_control(spec, HDA_CTL_WIDGET_VOL, boost_label, - spec->input_label_idxs[idx], val)) + "%s Boost Volume", pfx); + if (!add_control(spec, HDA_CTL_WIDGET_VOL, boost_label, idx, val)) return -ENOMEM;
path->ctls[NID_PATH_BOOST_CTL] = val;