diff options
Diffstat (limited to 'sound/pci/hda/patch_realtek.c')
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 42 |
1 files changed, 37 insertions, 5 deletions
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 | ||
3011 | static 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 | |||
3009 | static int alc_auto_add_vol_ctl(struct hda_codec *codec, | 3023 | static 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 */ |