diff options
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/hda_generic.c | 47 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.h | 4 |
2 files changed, 50 insertions, 1 deletions
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 4b1524a861f3..1485d871d628 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -133,6 +133,9 @@ static void parse_user_hints(struct hda_codec *codec) | |||
133 | val = snd_hda_get_bool_hint(codec, "line_in_auto_switch"); | 133 | val = snd_hda_get_bool_hint(codec, "line_in_auto_switch"); |
134 | if (val >= 0) | 134 | if (val >= 0) |
135 | spec->line_in_auto_switch = !!val; | 135 | spec->line_in_auto_switch = !!val; |
136 | val = snd_hda_get_bool_hint(codec, "auto_mute_via_amp"); | ||
137 | if (val >= 0) | ||
138 | spec->auto_mute_via_amp = !!val; | ||
136 | val = snd_hda_get_bool_hint(codec, "need_dac_fix"); | 139 | val = snd_hda_get_bool_hint(codec, "need_dac_fix"); |
137 | if (val >= 0) | 140 | if (val >= 0) |
138 | spec->need_dac_fix = !!val; | 141 | spec->need_dac_fix = !!val; |
@@ -808,6 +811,9 @@ static void resume_path_from_idx(struct hda_codec *codec, int path_idx) | |||
808 | * Helper functions for creating mixer ctl elements | 811 | * Helper functions for creating mixer ctl elements |
809 | */ | 812 | */ |
810 | 813 | ||
814 | static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, | ||
815 | struct snd_ctl_elem_value *ucontrol); | ||
816 | |||
811 | enum { | 817 | enum { |
812 | HDA_CTL_WIDGET_VOL, | 818 | HDA_CTL_WIDGET_VOL, |
813 | HDA_CTL_WIDGET_MUTE, | 819 | HDA_CTL_WIDGET_MUTE, |
@@ -815,7 +821,15 @@ enum { | |||
815 | }; | 821 | }; |
816 | static const struct snd_kcontrol_new control_templates[] = { | 822 | static const struct snd_kcontrol_new control_templates[] = { |
817 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), | 823 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), |
818 | HDA_CODEC_MUTE(NULL, 0, 0, 0), | 824 | /* only the put callback is replaced for handling the special mute */ |
825 | { | ||
826 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
827 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
828 | .info = snd_hda_mixer_amp_switch_info, | ||
829 | .get = snd_hda_mixer_amp_switch_get, | ||
830 | .put = hda_gen_mixer_mute_put, /* replaced */ | ||
831 | .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), | ||
832 | }, | ||
819 | HDA_BIND_MUTE(NULL, 0, 0, 0), | 833 | HDA_BIND_MUTE(NULL, 0, 0, 0), |
820 | }; | 834 | }; |
821 | 835 | ||
@@ -922,6 +936,23 @@ static int add_stereo_sw(struct hda_codec *codec, const char *pfx, | |||
922 | return add_sw_ctl(codec, pfx, cidx, chs, path); | 936 | return add_sw_ctl(codec, pfx, cidx, chs, path); |
923 | } | 937 | } |
924 | 938 | ||
939 | /* playback mute control with the software mute bit check */ | ||
940 | static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, | ||
941 | struct snd_ctl_elem_value *ucontrol) | ||
942 | { | ||
943 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
944 | struct hda_gen_spec *spec = codec->spec; | ||
945 | |||
946 | if (spec->auto_mute_via_amp) { | ||
947 | hda_nid_t nid = get_amp_nid(kcontrol); | ||
948 | bool enabled = !((spec->mute_bits >> nid) & 1); | ||
949 | ucontrol->value.integer.value[0] &= enabled; | ||
950 | ucontrol->value.integer.value[1] &= enabled; | ||
951 | } | ||
952 | |||
953 | return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
954 | } | ||
955 | |||
925 | /* any ctl assigned to the path with the given index? */ | 956 | /* any ctl assigned to the path with the given index? */ |
926 | static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type) | 957 | static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type) |
927 | { | 958 | { |
@@ -3719,6 +3750,16 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, | |||
3719 | unsigned int val, oldval; | 3750 | unsigned int val, oldval; |
3720 | if (!nid) | 3751 | if (!nid) |
3721 | break; | 3752 | break; |
3753 | |||
3754 | if (spec->auto_mute_via_amp) { | ||
3755 | if (mute) | ||
3756 | spec->mute_bits |= (1ULL << nid); | ||
3757 | else | ||
3758 | spec->mute_bits &= ~(1ULL << nid); | ||
3759 | set_pin_eapd(codec, nid, !mute); | ||
3760 | continue; | ||
3761 | } | ||
3762 | |||
3722 | oldval = snd_hda_codec_get_pin_target(codec, nid); | 3763 | oldval = snd_hda_codec_get_pin_target(codec, nid); |
3723 | if (oldval & PIN_IN) | 3764 | if (oldval & PIN_IN) |
3724 | continue; /* no mute for inputs */ | 3765 | continue; /* no mute for inputs */ |
@@ -3786,6 +3827,10 @@ static void call_update_outputs(struct hda_codec *codec) | |||
3786 | spec->automute_hook(codec); | 3827 | spec->automute_hook(codec); |
3787 | else | 3828 | else |
3788 | snd_hda_gen_update_outputs(codec); | 3829 | snd_hda_gen_update_outputs(codec); |
3830 | |||
3831 | /* sync the whole vmaster slaves to reflect the new auto-mute status */ | ||
3832 | if (spec->auto_mute_via_amp && !codec->bus->shutdown) | ||
3833 | snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false); | ||
3789 | } | 3834 | } |
3790 | 3835 | ||
3791 | /* standard HP-automute helper */ | 3836 | /* standard HP-automute helper */ |
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 76200314ee95..e199a852388b 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h | |||
@@ -209,6 +209,7 @@ struct hda_gen_spec { | |||
209 | unsigned int master_mute:1; /* master mute over all */ | 209 | unsigned int master_mute:1; /* master mute over all */ |
210 | unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */ | 210 | unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */ |
211 | unsigned int line_in_auto_switch:1; /* allow line-in auto switch */ | 211 | unsigned int line_in_auto_switch:1; /* allow line-in auto switch */ |
212 | unsigned int auto_mute_via_amp:1; /* auto-mute via amp instead of pinctl */ | ||
212 | 213 | ||
213 | /* parser behavior flags; set before snd_hda_gen_parse_auto_config() */ | 214 | /* parser behavior flags; set before snd_hda_gen_parse_auto_config() */ |
214 | unsigned int suppress_auto_mute:1; /* suppress input jack auto mute */ | 215 | unsigned int suppress_auto_mute:1; /* suppress input jack auto mute */ |
@@ -237,6 +238,9 @@ struct hda_gen_spec { | |||
237 | unsigned int have_aamix_ctl:1; | 238 | unsigned int have_aamix_ctl:1; |
238 | unsigned int hp_mic_jack_modes:1; | 239 | unsigned int hp_mic_jack_modes:1; |
239 | 240 | ||
241 | /* additional mute flags (only effective with auto_mute_via_amp=1) */ | ||
242 | u64 mute_bits; | ||
243 | |||
240 | /* badness tables for output path evaluations */ | 244 | /* badness tables for output path evaluations */ |
241 | const struct badness_table *main_out_badness; | 245 | const struct badness_table *main_out_badness; |
242 | const struct badness_table *extra_out_badness; | 246 | const struct badness_table *extra_out_badness; |