Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c267468e authored by Takashi Iwai's avatar Takashi Iwai
Browse files

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: default avatarTakashi Iwai <tiwai@suse.de>
parent 9c4e84d3
Loading
Loading
Loading
Loading
+51 −47
Original line number Diff line number Diff line
@@ -2814,7 +2814,8 @@ 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)
		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)))
@@ -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;
}
@@ -3721,9 +3728,6 @@ static int alc_parse_auto_config(struct hda_codec *codec,
	if (err < 0)
		return err;
	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);