aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-10-02 03:03:58 -0400
committerTakashi Iwai <tiwai@suse.de>2009-10-02 03:03:58 -0400
commit7085ec12a62ec2e990bc7d984bee7ba28e5c1dec (patch)
tree8640697b30bae458cf36342889e07ad3abd5c3c2
parent02d3332285377c9de395c2b5b792805d43923fd0 (diff)
ALSA: hda - Fix / improve ALC66x parser
The auto-parser for ALC662/663/272 codecs doesn't work properly when a speaker is connected to mono NID 0x17, and doesn't handle the dynamic DAC assignment properly. This patch fixes the issues and also improves the assignment of DACs so that HP and speakers can have independent volume controls. Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/patch_realtek.c241
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 */
17150static 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 */
17161static 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 */
17176static 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 */
17199static 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
17216static 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
17225static 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 */
17150static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, 17240static 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 */
17221static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, 17296/* return DAC nid if any new DAC is assigned */
17297static 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
17275static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, 17334static 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
17290static void alc662_auto_init_multi_out(struct hda_codec *codec) 17354static 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;