aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-10-27 10:33:27 -0400
committerTakashi Iwai <tiwai@suse.de>2011-10-27 10:58:00 -0400
commit527e4d73af16dfc35a770dfdc3874ef63c359ea6 (patch)
tree2b0b601f2a9b7836f8377eceb9324f81c56313a3 /sound/pci
parent5cdf745ebae0f5bcf9b798d8fd5cb57add592cc1 (diff)
ALSA: hda/realtek - Fix missing volume controls with ALC260
ALC260 has multiple mixer widgets connected to the shared DAC, but the driver currently doesn't check this possibility and ignores when the DAC is shared with others. This resulted in the silent output from some routes because of lack of the amp setup. This patch adds the workaround for it by checking the route even with the shared DAC, but also checking the conflict with the existing control for the very same widget NID. Reference: https://bugzilla.novell.com/show_bug.cgi?id=726812 Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/hda_local.h3
-rw-r--r--sound/pci/hda/patch_realtek.c42
2 files changed, 39 insertions, 6 deletions
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 46c581c3fa84..81e12c0ed0a2 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -600,7 +600,8 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
600#define get_amp_nid_(pv) ((pv) & 0xffff) 600#define get_amp_nid_(pv) ((pv) & 0xffff)
601#define get_amp_nid(kc) get_amp_nid_((kc)->private_value) 601#define get_amp_nid(kc) get_amp_nid_((kc)->private_value)
602#define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) 602#define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3)
603#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) 603#define get_amp_direction_(pv) (((pv) >> 18) & 0x1)
604#define get_amp_direction(kc) get_amp_direction_((kc)->private_value)
604#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) 605#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
605#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f) 606#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f)
606#define get_amp_min_mute(kc) (((kc)->private_value >> 29) & 0x1) 607#define get_amp_min_mute(kc) (((kc)->private_value >> 29) & 0x1)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 011644b7c2d1..8f93b97559a5 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -116,6 +116,8 @@ struct alc_spec {
116 const hda_nid_t *capsrc_nids; 116 const hda_nid_t *capsrc_nids;
117 hda_nid_t dig_in_nid; /* digital-in NID; optional */ 117 hda_nid_t dig_in_nid; /* digital-in NID; optional */
118 hda_nid_t mixer_nid; /* analog-mixer NID */ 118 hda_nid_t mixer_nid; /* analog-mixer NID */
119 DECLARE_BITMAP(vol_ctls, 0x20 << 1);
120 DECLARE_BITMAP(sw_ctls, 0x20 << 1);
119 121
120 /* capture setup for dynamic dual-adc switch */ 122 /* capture setup for dynamic dual-adc switch */
121 hda_nid_t cur_adc; 123 hda_nid_t cur_adc;
@@ -3006,14 +3008,32 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
3006 return 0; 3008 return 0;
3007} 3009}
3008 3010
3011static inline unsigned int get_ctl_pos(unsigned int data)
3012{
3013 hda_nid_t nid = get_amp_nid_(data);
3014 unsigned int dir = get_amp_direction_(data);
3015 return (nid << 1) | dir;
3016}
3017
3018#define is_ctl_used(bits, data) \
3019 test_bit(get_ctl_pos(data), bits)
3020#define mark_ctl_usage(bits, data) \
3021 set_bit(get_ctl_pos(data), bits)
3022
3009static int alc_auto_add_vol_ctl(struct hda_codec *codec, 3023static int alc_auto_add_vol_ctl(struct hda_codec *codec,
3010 const char *pfx, int cidx, 3024 const char *pfx, int cidx,
3011 hda_nid_t nid, unsigned int chs) 3025 hda_nid_t nid, unsigned int chs)
3012{ 3026{
3027 struct alc_spec *spec = codec->spec;
3028 unsigned int val;
3013 if (!nid) 3029 if (!nid)
3014 return 0; 3030 return 0;
3031 val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
3032 if (is_ctl_used(spec->vol_ctls, val) && chs != 2) /* exclude LFE */
3033 return 0;
3034 mark_ctl_usage(spec->vol_ctls, val);
3015 return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx, 3035 return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx,
3016 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); 3036 val);
3017} 3037}
3018 3038
3019#define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \ 3039#define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \
@@ -3026,6 +3046,7 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec,
3026 const char *pfx, int cidx, 3046 const char *pfx, int cidx,
3027 hda_nid_t nid, unsigned int chs) 3047 hda_nid_t nid, unsigned int chs)
3028{ 3048{
3049 struct alc_spec *spec = codec->spec;
3029 int wid_type; 3050 int wid_type;
3030 int type; 3051 int type;
3031 unsigned long val; 3052 unsigned long val;
@@ -3042,6 +3063,9 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec,
3042 type = ALC_CTL_BIND_MUTE; 3063 type = ALC_CTL_BIND_MUTE;
3043 val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT); 3064 val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT);
3044 } 3065 }
3066 if (is_ctl_used(spec->sw_ctls, val) && chs != 2) /* exclude LFE */
3067 return 0;
3068 mark_ctl_usage(spec->sw_ctls, val);
3045 return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); 3069 return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
3046} 3070}
3047 3071
@@ -3136,12 +3160,16 @@ static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
3136 int err; 3160 int err;
3137 3161
3138 if (!dac) { 3162 if (!dac) {
3163 unsigned int val;
3139 /* the corresponding DAC is already occupied */ 3164 /* the corresponding DAC is already occupied */
3140 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) 3165 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
3141 return 0; /* no way */ 3166 return 0; /* no way */
3142 /* create a switch only */ 3167 /* create a switch only */
3143 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, 3168 val = HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT);
3144 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); 3169 if (is_ctl_used(spec->sw_ctls, val))
3170 return 0; /* already created */
3171 mark_ctl_usage(spec->sw_ctls, val);
3172 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
3145 } 3173 }
3146 3174
3147 sw = alc_look_for_out_mute_nid(codec, pin, dac); 3175 sw = alc_look_for_out_mute_nid(codec, pin, dac);
@@ -3186,8 +3214,12 @@ static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins,
3186 if (!num_pins || !pins[0]) 3214 if (!num_pins || !pins[0])
3187 return 0; 3215 return 0;
3188 3216
3189 if (num_pins == 1) 3217 if (num_pins == 1) {
3190 return alc_auto_create_extra_out(codec, *pins, *dacs, pfx); 3218 hda_nid_t dac = *dacs;
3219 if (!dac)
3220 dac = spec->multiout.dac_nids[0];
3221 return alc_auto_create_extra_out(codec, *pins, dac, pfx);
3222 }
3191 3223
3192 if (dacs[num_pins - 1]) { 3224 if (dacs[num_pins - 1]) {
3193 /* OK, we have a multi-output system with individual volumes */ 3225 /* OK, we have a multi-output system with individual volumes */