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)