diff options
| author | Takashi Iwai <tiwai@suse.de> | 2009-10-02 03:03:58 -0400 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2009-10-02 03:03:58 -0400 |
| commit | 7085ec12a62ec2e990bc7d984bee7ba28e5c1dec (patch) | |
| tree | 8640697b30bae458cf36342889e07ad3abd5c3c2 | |
| parent | 02d3332285377c9de395c2b5b792805d43923fd0 (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.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) |
