From c267468e988bc620a2c167579304157c34c4fe95 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 24 Aug 2011 17:57:44 +0200 Subject: [PATCH] ALSA: hda - Prefer multi-io to speakers for realtek auto-parser When the multi-io jacks are available, parse them first and assign DACs before parsing speakers and headphones. This allows a better chance of surround I/O in some desktops and laptops with limited DACs. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 98 ++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index de63619..fa95825 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2814,8 +2814,9 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) if (found_in_nid_list(nid, spec->multiout.dac_nids, spec->multiout.num_dacs)) continue; - if (spec->multiout.hp_out_nid[0] == nid) - continue; + if (found_in_nid_list(nid, spec->multiout.hp_out_nid, + ARRAY_SIZE(spec->multiout.hp_out_nid))) + continue; if (found_in_nid_list(nid, spec->multiout.extra_out_nid, ARRAY_SIZE(spec->multiout.extra_out_nid))) continue; @@ -2832,6 +2833,29 @@ static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) return 0; } +static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs, + const hda_nid_t *pins, hda_nid_t *dacs) +{ + int i; + + if (num_outs && !dacs[0]) { + dacs[0] = alc_auto_look_for_dac(codec, pins[0]); + if (!dacs[0]) + return 0; + } + + for (i = 1; i < num_outs; i++) + dacs[i] = get_dac_if_single(codec, pins[i]); + for (i = 1; i < num_outs; i++) { + if (!dacs[i]) + dacs[i] = alc_auto_look_for_dac(codec, pins[i]); + } + return 0; +} + +static int alc_auto_fill_multi_ios(struct hda_codec *codec, + unsigned int location); + /* fill in the dac_nids table from the parsed pin configuration */ static int alc_auto_fill_dac_nids(struct hda_codec *codec) { @@ -2886,35 +2910,27 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); } - if (cfg->hp_outs && !spec->multiout.hp_out_nid[0]) - spec->multiout.hp_out_nid[0] = - alc_auto_look_for_dac(codec, cfg->hp_pins[0]); - if (cfg->speaker_outs && !spec->multiout.extra_out_nid[0]) - spec->multiout.extra_out_nid[0] = - alc_auto_look_for_dac(codec, cfg->speaker_pins[0]); + if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + /* try to fill multi-io first */ + unsigned int location, defcfg; + int num_pins; - return 0; -} + defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]); + location = get_defcfg_location(defcfg); -/* fill in the dac_nids table for surround speakers, etc */ -static int alc_auto_fill_extra_dacs(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int i; + num_pins = alc_auto_fill_multi_ios(codec, location); + if (num_pins > 0) { + spec->multi_ios = num_pins; + spec->ext_channel_count = 2; + spec->multiout.num_dacs = num_pins + 1; + } + } - if (cfg->speaker_outs < 2 || !spec->multiout.extra_out_nid[0]) - return 0; + alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins, + spec->multiout.hp_out_nid); + alc_auto_fill_extra_dacs(codec, cfg->speaker_outs, cfg->speaker_pins, + spec->multiout.extra_out_nid); - for (i = 1; i < cfg->speaker_outs; i++) - spec->multiout.extra_out_nid[i] = - get_dac_if_single(codec, cfg->speaker_pins[i]); - for (i = 1; i < cfg->speaker_outs; i++) { - if (spec->multiout.extra_out_nid[i]) - continue; - spec->multiout.extra_out_nid[i] = - alc_auto_look_for_dac(codec, cfg->speaker_pins[0]); - } return 0; } @@ -3264,6 +3280,7 @@ static int alc_auto_fill_multi_ios(struct hda_codec *codec, { struct alc_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t prime_dac = spec->private_dac_nids[0]; int type, i, num_pins = 0; for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { @@ -3291,8 +3308,13 @@ static int alc_auto_fill_multi_ios(struct hda_codec *codec, } } spec->multiout.num_dacs = 1; - if (num_pins < 2) + if (num_pins < 2) { + /* clear up again */ + memset(spec->private_dac_nids, 0, + sizeof(spec->private_dac_nids)); + spec->private_dac_nids[0] = prime_dac; return 0; + } return num_pins; } @@ -3381,19 +3403,8 @@ static const struct snd_kcontrol_new alc_auto_channel_mode_enum = { static int alc_auto_add_multi_channel_mode(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int location, defcfg; - int num_pins; - - if (cfg->line_outs != 1 || - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) - return 0; - defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]); - location = get_defcfg_location(defcfg); - - num_pins = alc_auto_fill_multi_ios(codec, location); - if (num_pins > 0) { + if (spec->multi_ios > 0) { struct snd_kcontrol_new *knew; knew = alc_kcontrol_new(spec); @@ -3403,10 +3414,6 @@ static int alc_auto_add_multi_channel_mode(struct hda_codec *codec) knew->name = kstrdup("Channel Mode", GFP_KERNEL); if (!knew->name) return -ENOMEM; - - spec->multi_ios = num_pins; - spec->ext_channel_count = 2; - spec->multiout.num_dacs = num_pins + 1; } return 0; } @@ -3723,9 +3730,6 @@ static int alc_parse_auto_config(struct hda_codec *codec, err = alc_auto_add_multi_channel_mode(codec); if (err < 0) return err; - err = alc_auto_fill_extra_dacs(codec); - if (err < 0) - return err; err = alc_auto_create_multi_out_ctls(codec, cfg); if (err < 0) return err; -- 2.7.4