aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-06-24 10:00:21 -0400
committerTakashi Iwai <tiwai@suse.de>2013-06-25 02:13:51 -0400
commit7eebffd3f4328c6dc220521f14b384affdaf9427 (patch)
treecdf1a8acef8802984e3de1ee84d964ed5fa62215 /sound/pci/hda
parent1ca2f2ec9e74e9d6e398e09b6468b4462c6d6b6e (diff)
ALSA: hda - Add auto_mute_via_amp flag to generic parser
Add a new flag, auto_mute_via_amp, to determine the behavior of the headphone / line-out auto-mute. When this flag is set, the generic driver mutes the speaker and line outputs via the amp mute of each pin, instead of changing the pin control values. This is introduced for devices that don't work expectedly with the pin control values; for example, some devices are known to keep enabling the speaker outputs no matter which pin control values are set on the speaker pins. The driver doesn't check actually whether the pins have the output amp caps, but assumes that the proper mixer (mute) controls are created on all these pins. If not the case, you can't use this flag for your device. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_generic.c47
-rw-r--r--sound/pci/hda/hda_generic.h4
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
814static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
815 struct snd_ctl_elem_value *ucontrol);
816
811enum { 817enum {
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};
816static const struct snd_kcontrol_new control_templates[] = { 822static 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 */
940static 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? */
926static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type) 957static 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;