diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index ebb558414314..edec98f1a9a5 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -315,11 +315,10 @@ static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type) /* check whether a control with the given (nid, dir, idx) was assigned */ static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid, - int dir, int idx) + int dir, int idx, int type) { unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir); - return is_ctl_used(codec, val, NID_PATH_VOL_CTL) || - is_ctl_used(codec, val, NID_PATH_MUTE_CTL); + return is_ctl_used(codec, val, type); } static void print_nid_path(const char *pfx, struct nid_path *path) @@ -590,12 +589,10 @@ static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, /* get the default amp value for the target state */ static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid, - int dir, bool enable) + int dir, unsigned int caps, bool enable) { - unsigned int caps; unsigned int val = 0; - caps = query_amp_caps(codec, nid, dir); if (caps & AC_AMPCAP_NUM_STEPS) { /* set to 0dB */ if (enable) @@ -611,19 +608,49 @@ static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid, /* initialize the amp value (only at the first time) */ static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) { - int val = get_amp_val_to_activate(codec, nid, dir, false); + unsigned int caps = query_amp_caps(codec, nid, dir); + int val = get_amp_val_to_activate(codec, nid, dir, caps, false); snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); } -static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, - int idx, bool enable) +/* calculate amp value mask we can modify; + * if the given amp is controlled by mixers, don't touch it + */ +static unsigned int get_amp_mask_to_modify(struct hda_codec *codec, + hda_nid_t nid, int dir, int idx, + unsigned int caps) { - int val; - if (is_ctl_associated(codec, nid, dir, idx) || - (!enable && is_active_nid(codec, nid, dir, idx))) + unsigned int mask = 0xff; + + if (caps & AC_AMPCAP_MUTE) { + if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL)) + mask &= ~0x80; + } + if (caps & AC_AMPCAP_NUM_STEPS) { + if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) || + is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL)) + mask &= ~0x7f; + } + return mask; +} + +static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, + int idx, int idx_to_check, bool enable) +{ + unsigned int caps; + unsigned int mask, val; + + if (!enable && is_active_nid(codec, nid, dir, idx)) return; - val = get_amp_val_to_activate(codec, nid, dir, enable); - snd_hda_codec_amp_stereo(codec, nid, dir, idx, 0xff, val); + + caps = query_amp_caps(codec, nid, dir); + val = get_amp_val_to_activate(codec, nid, dir, caps, enable); + mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps); + if (!mask) + return; + + val &= mask; + snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val); } static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, @@ -631,7 +658,7 @@ static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, { hda_nid_t nid = path->path[i]; init_amp(codec, nid, HDA_OUTPUT, 0); - activate_amp(codec, nid, HDA_OUTPUT, 0, enable); + activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable); } static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, @@ -655,16 +682,13 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, for (n = 0; n < nums; n++) init_amp(codec, nid, HDA_INPUT, n); - if (is_ctl_associated(codec, nid, HDA_INPUT, idx)) - return; - /* here is a little bit tricky in comparison with activate_amp_out(); * when aa-mixer is available, we need to enable the path as well */ for (n = 0; n < nums; n++) { if (n != idx && (!add_aamix || conn[n] != spec->mixer_nid)) continue; - activate_amp(codec, nid, HDA_INPUT, n, enable); + activate_amp(codec, nid, HDA_INPUT, n, idx, enable); } }