diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 241 |
1 files changed, 155 insertions, 86 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 87da5e805c8e..7810d3dcad83 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -17146,70 +17146,145 @@ static struct alc_config_preset alc662_presets[] = { | |||
17146 | * BIOS auto configuration | 17146 | * BIOS auto configuration |
17147 | */ | 17147 | */ |
17148 | 17148 | ||
17149 | /* convert from MIX nid to DAC */ | ||
17150 | static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid) | ||
17151 | { | ||
17152 | if (nid == 0x0f) | ||
17153 | return 0x02; | ||
17154 | else if (nid >= 0x0c && nid <= 0x0e) | ||
17155 | return nid - 0x0c + 0x02; | ||
17156 | else | ||
17157 | return 0; | ||
17158 | } | ||
17159 | |||
17160 | /* get MIX nid connected to the given pin targeted to DAC */ | ||
17161 | static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, | ||
17162 | hda_nid_t dac) | ||
17163 | { | ||
17164 | hda_nid_t mix[4]; | ||
17165 | int i, num; | ||
17166 | |||
17167 | num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); | ||
17168 | for (i = 0; i < num; i++) { | ||
17169 | if (alc662_mix_to_dac(mix[i]) == dac) | ||
17170 | return mix[i]; | ||
17171 | } | ||
17172 | return 0; | ||
17173 | } | ||
17174 | |||
17175 | /* look for an empty DAC slot */ | ||
17176 | static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin) | ||
17177 | { | ||
17178 | struct alc_spec *spec = codec->spec; | ||
17179 | hda_nid_t srcs[5]; | ||
17180 | int i, j, num; | ||
17181 | |||
17182 | num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); | ||
17183 | if (num < 0) | ||
17184 | return 0; | ||
17185 | for (i = 0; i < num; i++) { | ||
17186 | hda_nid_t nid = alc662_mix_to_dac(srcs[i]); | ||
17187 | if (!nid) | ||
17188 | continue; | ||
17189 | for (j = 0; j < spec->multiout.num_dacs; j++) | ||
17190 | if (spec->multiout.dac_nids[j] == nid) | ||
17191 | break; | ||
17192 | if (j >= spec->multiout.num_dacs) | ||
17193 | return nid; | ||
17194 | } | ||
17195 | return 0; | ||
17196 | } | ||
17197 | |||
17198 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
17199 | static int alc662_auto_fill_dac_nids(struct hda_codec *codec, | ||
17200 | const struct auto_pin_cfg *cfg) | ||
17201 | { | ||
17202 | struct alc_spec *spec = codec->spec; | ||
17203 | int i; | ||
17204 | hda_nid_t dac; | ||
17205 | |||
17206 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
17207 | for (i = 0; i < cfg->line_outs; i++) { | ||
17208 | dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]); | ||
17209 | if (!dac) | ||
17210 | continue; | ||
17211 | spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; | ||
17212 | } | ||
17213 | return 0; | ||
17214 | } | ||
17215 | |||
17216 | static int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx, | ||
17217 | hda_nid_t nid, unsigned int chs) | ||
17218 | { | ||
17219 | char name[32]; | ||
17220 | sprintf(name, "%s Playback Volume", pfx); | ||
17221 | return add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
17222 | HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); | ||
17223 | } | ||
17224 | |||
17225 | static int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx, | ||
17226 | hda_nid_t nid, unsigned int chs) | ||
17227 | { | ||
17228 | char name[32]; | ||
17229 | sprintf(name, "%s Playback Switch", pfx); | ||
17230 | return add_control(spec, ALC_CTL_WIDGET_MUTE, name, | ||
17231 | HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT)); | ||
17232 | } | ||
17233 | |||
17234 | #define alc662_add_stereo_vol(spec, pfx, nid) \ | ||
17235 | alc662_add_vol_ctl(spec, pfx, nid, 3) | ||
17236 | #define alc662_add_stereo_sw(spec, pfx, nid) \ | ||
17237 | alc662_add_sw_ctl(spec, pfx, nid, 3) | ||
17238 | |||
17149 | /* add playback controls from the parsed DAC table */ | 17239 | /* add playback controls from the parsed DAC table */ |
17150 | static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, | 17240 | static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, |
17151 | const struct auto_pin_cfg *cfg) | 17241 | const struct auto_pin_cfg *cfg) |
17152 | { | 17242 | { |
17153 | char name[32]; | 17243 | struct alc_spec *spec = codec->spec; |
17154 | static const char *chname[4] = { | 17244 | static const char *chname[4] = { |
17155 | "Front", "Surround", NULL /*CLFE*/, "Side" | 17245 | "Front", "Surround", NULL /*CLFE*/, "Side" |
17156 | }; | 17246 | }; |
17157 | hda_nid_t nid; | 17247 | hda_nid_t nid, mix; |
17158 | int i, err; | 17248 | int i, err; |
17159 | 17249 | ||
17160 | for (i = 0; i < cfg->line_outs; i++) { | 17250 | for (i = 0; i < cfg->line_outs; i++) { |
17161 | if (!spec->multiout.dac_nids[i]) | 17251 | nid = spec->multiout.dac_nids[i]; |
17252 | if (!nid) | ||
17253 | continue; | ||
17254 | mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid); | ||
17255 | if (!mix) | ||
17162 | continue; | 17256 | continue; |
17163 | nid = alc880_idx_to_dac(i); | ||
17164 | if (i == 2) { | 17257 | if (i == 2) { |
17165 | /* Center/LFE */ | 17258 | /* Center/LFE */ |
17166 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | 17259 | err = alc662_add_vol_ctl(spec, "Center", nid, 1); |
17167 | "Center Playback Volume", | ||
17168 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, | ||
17169 | HDA_OUTPUT)); | ||
17170 | if (err < 0) | 17260 | if (err < 0) |
17171 | return err; | 17261 | return err; |
17172 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | 17262 | err = alc662_add_vol_ctl(spec, "LFE", nid, 2); |
17173 | "LFE Playback Volume", | ||
17174 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, | ||
17175 | HDA_OUTPUT)); | ||
17176 | if (err < 0) | 17263 | if (err < 0) |
17177 | return err; | 17264 | return err; |
17178 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, | 17265 | err = alc662_add_sw_ctl(spec, "Center", mix, 1); |
17179 | "Center Playback Switch", | ||
17180 | HDA_COMPOSE_AMP_VAL(0x0e, 1, 0, | ||
17181 | HDA_INPUT)); | ||
17182 | if (err < 0) | 17266 | if (err < 0) |
17183 | return err; | 17267 | return err; |
17184 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, | 17268 | err = alc662_add_sw_ctl(spec, "LFE", mix, 2); |
17185 | "LFE Playback Switch", | ||
17186 | HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, | ||
17187 | HDA_INPUT)); | ||
17188 | if (err < 0) | 17269 | if (err < 0) |
17189 | return err; | 17270 | return err; |
17190 | } else { | 17271 | } else { |
17191 | const char *pfx; | 17272 | const char *pfx; |
17192 | if (cfg->line_outs == 1 && | 17273 | if (cfg->line_outs == 1 && |
17193 | cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { | 17274 | cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { |
17194 | if (!cfg->hp_pins) | 17275 | if (cfg->hp_outs) |
17195 | pfx = "Speaker"; | 17276 | pfx = "Speaker"; |
17196 | else | 17277 | else |
17197 | pfx = "PCM"; | 17278 | pfx = "PCM"; |
17198 | } else | 17279 | } else |
17199 | pfx = chname[i]; | 17280 | pfx = chname[i]; |
17200 | sprintf(name, "%s Playback Volume", pfx); | 17281 | err = alc662_add_vol_ctl(spec, pfx, nid, 3); |
17201 | err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
17202 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, | ||
17203 | HDA_OUTPUT)); | ||
17204 | if (err < 0) | 17282 | if (err < 0) |
17205 | return err; | 17283 | return err; |
17206 | if (cfg->line_outs == 1 && | 17284 | if (cfg->line_outs == 1 && |
17207 | cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) | 17285 | cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) |
17208 | pfx = "Speaker"; | 17286 | pfx = "Speaker"; |
17209 | sprintf(name, "%s Playback Switch", pfx); | 17287 | err = alc662_add_sw_ctl(spec, pfx, mix, 3); |
17210 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, | ||
17211 | HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i), | ||
17212 | 3, 0, HDA_INPUT)); | ||
17213 | if (err < 0) | 17288 | if (err < 0) |
17214 | return err; | 17289 | return err; |
17215 | } | 17290 | } |
@@ -17218,54 +17293,38 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, | |||
17218 | } | 17293 | } |
17219 | 17294 | ||
17220 | /* add playback controls for speaker and HP outputs */ | 17295 | /* add playback controls for speaker and HP outputs */ |
17221 | static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, | 17296 | /* return DAC nid if any new DAC is assigned */ |
17297 | static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, | ||
17222 | const char *pfx) | 17298 | const char *pfx) |
17223 | { | 17299 | { |
17224 | hda_nid_t nid; | 17300 | struct alc_spec *spec = codec->spec; |
17301 | hda_nid_t nid, mix; | ||
17225 | int err; | 17302 | int err; |
17226 | char name[32]; | ||
17227 | 17303 | ||
17228 | if (!pin) | 17304 | if (!pin) |
17229 | return 0; | 17305 | return 0; |
17230 | 17306 | nid = alc662_look_for_dac(codec, pin); | |
17231 | if (pin == 0x17) { | 17307 | if (!nid) { |
17232 | /* ALC663 has a mono output pin on 0x17 */ | 17308 | char name[32]; |
17309 | /* the corresponding DAC is already occupied */ | ||
17310 | if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) | ||
17311 | return 0; /* no way */ | ||
17312 | /* create a switch only */ | ||
17233 | sprintf(name, "%s Playback Switch", pfx); | 17313 | sprintf(name, "%s Playback Switch", pfx); |
17234 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, | 17314 | return add_control(spec, ALC_CTL_WIDGET_MUTE, name, |
17235 | HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT)); | 17315 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); |
17236 | return err; | ||
17237 | } | 17316 | } |
17238 | 17317 | ||
17239 | if (alc880_is_fixed_pin(pin)) { | 17318 | mix = alc662_dac_to_mix(codec, pin, nid); |
17240 | nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); | 17319 | if (!mix) |
17241 | /* printk(KERN_DEBUG "DAC nid=%x\n",nid); */ | 17320 | return 0; |
17242 | /* specify the DAC as the extra output */ | 17321 | err = alc662_add_vol_ctl(spec, pfx, nid, 3); |
17243 | if (!spec->multiout.hp_nid) | 17322 | if (err < 0) |
17244 | spec->multiout.hp_nid = nid; | 17323 | return err; |
17245 | else | 17324 | err = alc662_add_sw_ctl(spec, pfx, mix, 3); |
17246 | spec->multiout.extra_out_nid[0] = nid; | 17325 | if (err < 0) |
17247 | /* control HP volume/switch on the output mixer amp */ | 17326 | return err; |
17248 | nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin)); | 17327 | return nid; |
17249 | sprintf(name, "%s Playback Volume", pfx); | ||
17250 | err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | ||
17251 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | ||
17252 | if (err < 0) | ||
17253 | return err; | ||
17254 | sprintf(name, "%s Playback Switch", pfx); | ||
17255 | err = add_control(spec, ALC_CTL_BIND_MUTE, name, | ||
17256 | HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); | ||
17257 | if (err < 0) | ||
17258 | return err; | ||
17259 | } else if (alc880_is_multi_pin(pin)) { | ||
17260 | /* set manual connection */ | ||
17261 | /* we have only a switch on HP-out PIN */ | ||
17262 | sprintf(name, "%s Playback Switch", pfx); | ||
17263 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, | ||
17264 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
17265 | if (err < 0) | ||
17266 | return err; | ||
17267 | } | ||
17268 | return 0; | ||
17269 | } | 17328 | } |
17270 | 17329 | ||
17271 | /* create playback/capture controls for input pins */ | 17330 | /* create playback/capture controls for input pins */ |
@@ -17274,30 +17333,35 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, | |||
17274 | 17333 | ||
17275 | static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, | 17334 | static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, |
17276 | hda_nid_t nid, int pin_type, | 17335 | hda_nid_t nid, int pin_type, |
17277 | int dac_idx) | 17336 | hda_nid_t dac) |
17278 | { | 17337 | { |
17338 | int i, num; | ||
17339 | hda_nid_t srcs[4]; | ||
17340 | |||
17279 | alc_set_pin_output(codec, nid, pin_type); | 17341 | alc_set_pin_output(codec, nid, pin_type); |
17280 | /* need the manual connection? */ | 17342 | /* need the manual connection? */ |
17281 | if (alc880_is_multi_pin(nid)) { | 17343 | num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs)); |
17282 | struct alc_spec *spec = codec->spec; | 17344 | if (num <= 1) |
17283 | int idx = alc880_multi_pin_idx(nid); | 17345 | return; |
17284 | snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0, | 17346 | for (i = 0; i < num; i++) { |
17285 | AC_VERB_SET_CONNECT_SEL, | 17347 | if (alc662_mix_to_dac(srcs[i]) != dac) |
17286 | alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx])); | 17348 | continue; |
17349 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i); | ||
17350 | return; | ||
17287 | } | 17351 | } |
17288 | } | 17352 | } |
17289 | 17353 | ||
17290 | static void alc662_auto_init_multi_out(struct hda_codec *codec) | 17354 | static void alc662_auto_init_multi_out(struct hda_codec *codec) |
17291 | { | 17355 | { |
17292 | struct alc_spec *spec = codec->spec; | 17356 | struct alc_spec *spec = codec->spec; |
17357 | int pin_type = get_pin_type(spec->autocfg.line_out_type); | ||
17293 | int i; | 17358 | int i; |
17294 | 17359 | ||
17295 | for (i = 0; i <= HDA_SIDE; i++) { | 17360 | for (i = 0; i <= HDA_SIDE; i++) { |
17296 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | 17361 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; |
17297 | int pin_type = get_pin_type(spec->autocfg.line_out_type); | ||
17298 | if (nid) | 17362 | if (nid) |
17299 | alc662_auto_set_output_and_unmute(codec, nid, pin_type, | 17363 | alc662_auto_set_output_and_unmute(codec, nid, pin_type, |
17300 | i); | 17364 | spec->multiout.dac_nids[i]); |
17301 | } | 17365 | } |
17302 | } | 17366 | } |
17303 | 17367 | ||
@@ -17307,12 +17371,13 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec) | |||
17307 | hda_nid_t pin; | 17371 | hda_nid_t pin; |
17308 | 17372 | ||
17309 | pin = spec->autocfg.hp_pins[0]; | 17373 | pin = spec->autocfg.hp_pins[0]; |
17310 | if (pin) /* connect to front */ | 17374 | if (pin) |
17311 | /* use dac 0 */ | 17375 | alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, |
17312 | alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); | 17376 | spec->multiout.hp_nid); |
17313 | pin = spec->autocfg.speaker_pins[0]; | 17377 | pin = spec->autocfg.speaker_pins[0]; |
17314 | if (pin) | 17378 | if (pin) |
17315 | alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); | 17379 | alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, |
17380 | spec->multiout.extra_out_nid[0]); | ||
17316 | } | 17381 | } |
17317 | 17382 | ||
17318 | #define ALC662_PIN_CD_NID ALC880_PIN_CD_NID | 17383 | #define ALC662_PIN_CD_NID ALC880_PIN_CD_NID |
@@ -17350,21 +17415,25 @@ static int alc662_parse_auto_config(struct hda_codec *codec) | |||
17350 | if (!spec->autocfg.line_outs) | 17415 | if (!spec->autocfg.line_outs) |
17351 | return 0; /* can't find valid BIOS pin config */ | 17416 | return 0; /* can't find valid BIOS pin config */ |
17352 | 17417 | ||
17353 | err = alc880_auto_fill_dac_nids(spec, &spec->autocfg); | 17418 | err = alc662_auto_fill_dac_nids(codec, &spec->autocfg); |
17354 | if (err < 0) | 17419 | if (err < 0) |
17355 | return err; | 17420 | return err; |
17356 | err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg); | 17421 | err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg); |
17357 | if (err < 0) | 17422 | if (err < 0) |
17358 | return err; | 17423 | return err; |
17359 | err = alc662_auto_create_extra_out(spec, | 17424 | err = alc662_auto_create_extra_out(codec, |
17360 | spec->autocfg.speaker_pins[0], | 17425 | spec->autocfg.speaker_pins[0], |
17361 | "Speaker"); | 17426 | "Speaker"); |
17362 | if (err < 0) | 17427 | if (err < 0) |
17363 | return err; | 17428 | return err; |
17364 | err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], | 17429 | if (err) |
17430 | spec->multiout.extra_out_nid[0] = err; | ||
17431 | err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], | ||
17365 | "Headphone"); | 17432 | "Headphone"); |
17366 | if (err < 0) | 17433 | if (err < 0) |
17367 | return err; | 17434 | return err; |
17435 | if (err) | ||
17436 | spec->multiout.hp_nid = err; | ||
17368 | err = alc662_auto_create_input_ctls(codec, &spec->autocfg); | 17437 | err = alc662_auto_create_input_ctls(codec, &spec->autocfg); |
17369 | if (err < 0) | 17438 | if (err < 0) |
17370 | return err; | 17439 | return err; |