diff --git a/[refs] b/[refs] index c99062fa00eb..2fe6ac09ecdd 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: bc54976721d30f5ec51e90dcd1aca56494e0b0cf +refs/heads/master: 9bf387b6121bc446f275b0de8196d4dea8a3c876 diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index 13d4548a5381..6fb39221aac4 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -221,6 +221,7 @@ struct alc_spec { unsigned int inv_dmic_fixup:1; /* has inverted digital-mic workaround */ unsigned int inv_dmic_muted:1; /* R-ch of inv d-mic is muted? */ unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */ + unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */ unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */ @@ -2474,6 +2475,10 @@ static int check_dyn_adc_switch(struct hda_codec *codec) spec->num_adc_nids = 1; /* reduce to a single ADC */ } + /* single index for individual volumes ctls */ + if (!spec->dyn_adc_switch && spec->multi_cap_vol) + spec->num_adc_nids = 1; + return 0; } @@ -2545,12 +2550,122 @@ static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path) return 0; } +static int add_single_cap_ctl(struct hda_codec *codec, const char *label, + int idx, bool is_switch, unsigned int ctl) +{ + struct alc_spec *spec = codec->spec; + char tmpname[44]; + int type = is_switch ? ALC_CTL_WIDGET_MUTE : ALC_CTL_WIDGET_VOL; + const char *sfx = is_switch ? "Switch" : "Volume"; + + if (!ctl) + return 0; + + if (label) + snprintf(tmpname, sizeof(tmpname), + "%s Capture %s", label, sfx); + else + snprintf(tmpname, sizeof(tmpname), + "Capture %s", sfx); + return add_control(spec, type, tmpname, idx, ctl); +} + +/* create single (and simple) capture volume and switch controls */ +static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx, + unsigned int vol_ctl, unsigned int sw_ctl) +{ + int err; + err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl); + if (err < 0) + return err; + err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl); + if (err < 0) + return err; + return 0; +} + +/* create bound capture volume and switch controls */ +static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx, + unsigned int vol_ctl, unsigned int sw_ctl) +{ + struct alc_spec *spec = codec->spec; + struct snd_kcontrol_new *knew; + + if (vol_ctl) { + knew = alc_kcontrol_new(spec, NULL, &cap_vol_temp); + if (!knew) + return -ENOMEM; + knew->index = idx; + knew->private_value = vol_ctl; + knew->subdevice = HDA_SUBDEV_AMP_FLAG; + } + if (sw_ctl) { + knew = alc_kcontrol_new(spec, NULL, &cap_sw_temp); + if (!knew) + return -ENOMEM; + knew->index = idx; + knew->private_value = sw_ctl; + knew->subdevice = HDA_SUBDEV_AMP_FLAG; + } + return 0; +} + +/* return the vol ctl when used first in the imux list */ +static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type) +{ + struct alc_spec *spec = codec->spec; + struct nid_path *path; + unsigned int ctl; + int i; + + path = get_nid_path(codec, spec->imux_pins[idx], + get_adc_nid(codec, 0, idx)); + if (!path) + return 0; + ctl = path->ctls[type]; + if (!ctl) + return 0; + for (i = 0; i < idx - 1; i++) { + path = get_nid_path(codec, spec->imux_pins[i], + get_adc_nid(codec, 0, i)); + if (path && path->ctls[type] == ctl) + return 0; + } + return ctl; +} + +/* create individual capture volume and switch controls per input */ +static int create_multi_cap_vol_ctl(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->input_mux; + int i, err, type, type_idx = 0; + const char *prev_label = NULL; + + for (i = 0; i < imux->num_items; i++) { + const char *label; + label = hda_get_autocfg_input_label(codec, &spec->autocfg, i); + if (prev_label && !strcmp(label, prev_label)) + type_idx++; + else + type_idx = 0; + prev_label = label; + + for (type = 0; type < 2; type++) { + err = add_single_cap_ctl(codec, label, type_idx, type, + get_first_cap_ctl(codec, i, type)); + if (err < 0) + return err; + } + } + return 0; +} + static int create_capture_mixers(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->input_mux; - struct snd_kcontrol_new *knew; - int i, n, nums; + int i, n, nums, err; if (spec->dyn_adc_switch) nums = 1; @@ -2558,6 +2673,7 @@ static int create_capture_mixers(struct hda_codec *codec) nums = spec->num_adc_nids; if (!spec->auto_mic && imux->num_items > 1) { + struct snd_kcontrol_new *knew; knew = alc_kcontrol_new(spec, NULL, &cap_src_temp); if (!knew) return -ENOMEM; @@ -2565,6 +2681,7 @@ static int create_capture_mixers(struct hda_codec *codec) } for (n = 0; n < nums; n++) { + bool multi = false; int vol, sw; vol = sw = 0; @@ -2577,26 +2694,22 @@ static int create_capture_mixers(struct hda_codec *codec) parse_capvol_in_path(codec, path); if (!vol) vol = path->ctls[NID_PATH_VOL_CTL]; + else if (vol != path->ctls[NID_PATH_VOL_CTL]) + multi = true; if (!sw) sw = path->ctls[NID_PATH_MUTE_CTL]; + else if (sw != path->ctls[NID_PATH_MUTE_CTL]) + multi = true; } - if (vol) { - knew = alc_kcontrol_new(spec, NULL, &cap_vol_temp); - if (!knew) - return -ENOMEM; - knew->index = n; - knew->private_value = vol; - knew->subdevice = HDA_SUBDEV_AMP_FLAG; - } - if (sw) { - knew = alc_kcontrol_new(spec, NULL, &cap_sw_temp); - if (!knew) - return -ENOMEM; - knew->index = n; - knew->private_value = sw; - knew->subdevice = HDA_SUBDEV_AMP_FLAG; - } + if (!multi) + err = create_single_cap_vol_ctl(codec, n, vol, sw); + else if (!spec->multi_cap_vol) + err = create_bind_cap_vol_ctl(codec, n, vol, sw); + else + err = create_multi_cap_vol_ctl(codec); + if (err < 0) + return err; } return 0;