Commit 7085ec12a62ec2e990bc7d984bee7ba28e5c1dec

Authored by Takashi Iwai
1 parent 02d3332285

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>

Showing 1 changed file with 155 additions and 86 deletions Side-by-side Diff

sound/pci/hda/patch_realtek.c
... ... @@ -17146,70 +17146,145 @@
17146 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 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 17241 const struct auto_pin_cfg *cfg)
17152 17242 {
17153   - char name[32];
  17243 + struct alc_spec *spec = codec->spec;
17154 17244 static const char *chname[4] = {
17155 17245 "Front", "Surround", NULL /*CLFE*/, "Side"
17156 17246 };
17157   - hda_nid_t nid;
  17247 + hda_nid_t nid, mix;
17158 17248 int i, err;
17159 17249  
17160 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)
17162 17253 continue;
17163   - nid = alc880_idx_to_dac(i);
  17254 + mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
  17255 + if (!mix)
  17256 + continue;
17164 17257 if (i == 2) {
17165 17258 /* Center/LFE */
17166   - err = add_control(spec, ALC_CTL_WIDGET_VOL,
17167   - "Center Playback Volume",
17168   - HDA_COMPOSE_AMP_VAL(nid, 1, 0,
17169   - HDA_OUTPUT));
  17259 + err = alc662_add_vol_ctl(spec, "Center", nid, 1);
17170 17260 if (err < 0)
17171 17261 return err;
17172   - err = add_control(spec, ALC_CTL_WIDGET_VOL,
17173   - "LFE Playback Volume",
17174   - HDA_COMPOSE_AMP_VAL(nid, 2, 0,
17175   - HDA_OUTPUT));
  17262 + err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
17176 17263 if (err < 0)
17177 17264 return err;
17178   - err = add_control(spec, ALC_CTL_WIDGET_MUTE,
17179   - "Center Playback Switch",
17180   - HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
17181   - HDA_INPUT));
  17265 + err = alc662_add_sw_ctl(spec, "Center", mix, 1);
17182 17266 if (err < 0)
17183 17267 return err;
17184   - err = add_control(spec, ALC_CTL_WIDGET_MUTE,
17185   - "LFE Playback Switch",
17186   - HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
17187   - HDA_INPUT));
  17268 + err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
17188 17269 if (err < 0)
17189 17270 return err;
17190 17271 } else {
17191 17272 const char *pfx;
17192 17273 if (cfg->line_outs == 1 &&
17193 17274 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
17194   - if (!cfg->hp_pins)
  17275 + if (cfg->hp_outs)
17195 17276 pfx = "Speaker";
17196 17277 else
17197 17278 pfx = "PCM";
17198 17279 } else
17199 17280 pfx = chname[i];
17200   - sprintf(name, "%s Playback Volume", pfx);
17201   - err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
17202   - HDA_COMPOSE_AMP_VAL(nid, 3, 0,
17203   - HDA_OUTPUT));
  17281 + err = alc662_add_vol_ctl(spec, pfx, nid, 3);
17204 17282 if (err < 0)
17205 17283 return err;
17206 17284 if (cfg->line_outs == 1 &&
17207 17285 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
17208 17286 pfx = "Speaker";
17209   - sprintf(name, "%s Playback Switch", pfx);
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));
  17287 + err = alc662_add_sw_ctl(spec, pfx, mix, 3);
17213 17288 if (err < 0)
17214 17289 return err;
17215 17290 }
17216 17291  
17217 17292  
17218 17293  
17219 17294  
17220 17295  
... ... @@ -17218,54 +17293,38 @@
17218 17293 }
17219 17294  
17220 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 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 17302 int err;
17226   - char name[32];
17227 17303  
17228 17304 if (!pin)
17229 17305 return 0;
17230   -
17231   - if (pin == 0x17) {
17232   - /* ALC663 has a mono output pin on 0x17 */
  17306 + nid = alc662_look_for_dac(codec, pin);
  17307 + if (!nid) {
  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 17313 sprintf(name, "%s Playback Switch", pfx);
17234   - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
17235   - HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
17236   - return err;
  17314 + return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
  17315 + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
17237 17316 }
17238 17317  
17239   - if (alc880_is_fixed_pin(pin)) {
17240   - nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
17241   - /* printk(KERN_DEBUG "DAC nid=%x\n",nid); */
17242   - /* specify the DAC as the extra output */
17243   - if (!spec->multiout.hp_nid)
17244   - spec->multiout.hp_nid = nid;
17245   - else
17246   - spec->multiout.extra_out_nid[0] = nid;
17247   - /* control HP volume/switch on the output mixer amp */
17248   - nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
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;
  17318 + mix = alc662_dac_to_mix(codec, pin, nid);
  17319 + if (!mix)
  17320 + return 0;
  17321 + err = alc662_add_vol_ctl(spec, pfx, nid, 3);
  17322 + if (err < 0)
  17323 + return err;
  17324 + err = alc662_add_sw_ctl(spec, pfx, mix, 3);
  17325 + if (err < 0)
  17326 + return err;
  17327 + return nid;
17269 17328 }
17270 17329  
17271 17330 /* create playback/capture controls for input pins */
17272 17331  
17273 17332  
17274 17333  
17275 17334  
17276 17335  
... ... @@ -17274,30 +17333,35 @@
17274 17333  
17275 17334 static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
17276 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 17341 alc_set_pin_output(codec, nid, pin_type);
17280 17342 /* need the manual connection? */
17281   - if (alc880_is_multi_pin(nid)) {
17282   - struct alc_spec *spec = codec->spec;
17283   - int idx = alc880_multi_pin_idx(nid);
17284   - snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
17285   - AC_VERB_SET_CONNECT_SEL,
17286   - alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
  17343 + num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
  17344 + if (num <= 1)
  17345 + return;
  17346 + for (i = 0; i < num; i++) {
  17347 + if (alc662_mix_to_dac(srcs[i]) != dac)
  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 17354 static void alc662_auto_init_multi_out(struct hda_codec *codec)
17291 17355 {
17292 17356 struct alc_spec *spec = codec->spec;
  17357 + int pin_type = get_pin_type(spec->autocfg.line_out_type);
17293 17358 int i;
17294 17359  
17295 17360 for (i = 0; i <= HDA_SIDE; i++) {
17296 17361 hda_nid_t nid = spec->autocfg.line_out_pins[i];
17297   - int pin_type = get_pin_type(spec->autocfg.line_out_type);
17298 17362 if (nid)
17299 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  
17304 17368  
... ... @@ -17307,12 +17371,13 @@
17307 17371 hda_nid_t pin;
17308 17372  
17309 17373 pin = spec->autocfg.hp_pins[0];
17310   - if (pin) /* connect to front */
17311   - /* use dac 0 */
17312   - alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
  17374 + if (pin)
  17375 + alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
  17376 + spec->multiout.hp_nid);
17313 17377 pin = spec->autocfg.speaker_pins[0];
17314 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 17383 #define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
17319 17384  
17320 17385  
17321 17386  
17322 17387  
... ... @@ -17350,21 +17415,25 @@
17350 17415 if (!spec->autocfg.line_outs)
17351 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 17419 if (err < 0)
17355 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 17422 if (err < 0)
17358 17423 return err;
17359   - err = alc662_auto_create_extra_out(spec,
  17424 + err = alc662_auto_create_extra_out(codec,
17360 17425 spec->autocfg.speaker_pins[0],
17361 17426 "Speaker");
17362 17427 if (err < 0)
17363 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 17432 "Headphone");
17366 17433 if (err < 0)
17367 17434 return err;
  17435 + if (err)
  17436 + spec->multiout.hp_nid = err;
17368 17437 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
17369 17438 if (err < 0)
17370 17439 return err;