| From 3868137ea41866773e75d9ac4b9988dcc361ff1d Mon Sep 17 00:00:00 2001 |
| From: Takashi Iwai <tiwai@suse.de> |
| Date: Mon, 27 Feb 2012 15:00:58 +0100 |
| Subject: ALSA: hda - Add a fake mute feature |
| |
| From: Takashi Iwai <tiwai@suse.de> |
| |
| commit 3868137ea41866773e75d9ac4b9988dcc361ff1d upstream. |
| |
| Some codecs don't supply the mute amp-capabilities although the lowest |
| volume gives the mute. It'd be handy if the parser provides the mute |
| mixers in such a case. |
| |
| This patch adds an extension amp-cap bit (which is used only in the |
| driver) to represent the min volume = mute state. Also modified the |
| amp cache code to support the fake mute feature when this bit is set |
| but the real mute bit is unset. |
| |
| In addition, conexant cx5051 parser uses this new feature to implement |
| the missing mute controls. |
| |
| Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=42825 |
| |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| sound/pci/hda/hda_codec.c | 8 ++++++-- |
| sound/pci/hda/hda_codec.h | 3 +++ |
| sound/pci/hda/patch_conexant.c | 22 +++++++++++++++++++++- |
| 3 files changed, 30 insertions(+), 3 deletions(-) |
| |
| --- a/sound/pci/hda/hda_codec.c |
| +++ b/sound/pci/hda/hda_codec.c |
| @@ -1651,7 +1651,11 @@ static void put_vol_mute(struct hda_code |
| parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT; |
| parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT; |
| parm |= index << AC_AMP_SET_INDEX_SHIFT; |
| - parm |= val; |
| + if ((val & HDA_AMP_MUTE) && !(info->amp_caps & AC_AMPCAP_MUTE) && |
| + (info->amp_caps & AC_AMPCAP_MIN_MUTE)) |
| + ; /* set the zero value as a fake mute */ |
| + else |
| + parm |= val; |
| snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); |
| info->vol[ch] = val; |
| } |
| @@ -1918,7 +1922,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kco |
| val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); |
| val1 += ofs; |
| val1 = ((int)val1) * ((int)val2); |
| - if (min_mute) |
| + if (min_mute || (caps & AC_AMPCAP_MIN_MUTE)) |
| val2 |= TLV_DB_SCALE_MUTE; |
| if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) |
| return -EFAULT; |
| --- a/sound/pci/hda/hda_codec.h |
| +++ b/sound/pci/hda/hda_codec.h |
| @@ -302,6 +302,9 @@ enum { |
| #define AC_AMPCAP_MUTE (1<<31) /* mute capable */ |
| #define AC_AMPCAP_MUTE_SHIFT 31 |
| |
| +/* driver-specific amp-caps: using bits 24-30 */ |
| +#define AC_AMPCAP_MIN_MUTE (1 << 30) /* min-volume = mute */ |
| + |
| /* Connection list */ |
| #define AC_CLIST_LENGTH (0x7f<<0) |
| #define AC_CLIST_LONG (1<<7) |
| --- a/sound/pci/hda/patch_conexant.c |
| +++ b/sound/pci/hda/patch_conexant.c |
| @@ -4127,7 +4127,8 @@ static int cx_auto_add_volume_idx(struct |
| err = snd_hda_ctl_add(codec, nid, kctl); |
| if (err < 0) |
| return err; |
| - if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE)) |
| + if (!(query_amp_caps(codec, nid, hda_dir) & |
| + (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE))) |
| break; |
| } |
| return 0; |
| @@ -4372,6 +4373,22 @@ static const struct hda_codec_ops cx_aut |
| .reboot_notify = snd_hda_shutup_pins, |
| }; |
| |
| +/* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches |
| + * can be created (bko#42825) |
| + */ |
| +static void add_cx5051_fake_mutes(struct hda_codec *codec) |
| +{ |
| + static hda_nid_t out_nids[] = { |
| + 0x10, 0x11, 0 |
| + }; |
| + hda_nid_t *p; |
| + |
| + for (p = out_nids; *p; p++) |
| + snd_hda_override_amp_caps(codec, *p, HDA_OUTPUT, |
| + AC_AMPCAP_MIN_MUTE | |
| + query_amp_caps(codec, *p, HDA_OUTPUT)); |
| +} |
| + |
| static int patch_conexant_auto(struct hda_codec *codec) |
| { |
| struct conexant_spec *spec; |
| @@ -4390,6 +4407,9 @@ static int patch_conexant_auto(struct hd |
| case 0x14f15045: |
| spec->single_adc_amp = 1; |
| break; |
| + case 0x14f15051: |
| + add_cx5051_fake_mutes(codec); |
| + break; |
| } |
| |
| err = cx_auto_search_adcs(codec); |