mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-20 04:44:26 +08:00
ALSA: hda/realtek - Adjust badness calculation for multi-ios
Try harder to fit the multi-io pins also by checking the hard-wired connections for multi-ios. Also, the badness values are adjusted to prioritize the multi-ios as more valuable. These changes will enable the multi-io on some machines without losing the current capability. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
6f45304091
commit
276dd70bae
@ -2929,6 +2929,7 @@ static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
|
|||||||
static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
|
static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
|
||||||
{
|
{
|
||||||
struct alc_spec *spec = codec->spec;
|
struct alc_spec *spec = codec->spec;
|
||||||
|
int i;
|
||||||
if (found_in_nid_list(nid, spec->multiout.dac_nids,
|
if (found_in_nid_list(nid, spec->multiout.dac_nids,
|
||||||
ARRAY_SIZE(spec->private_dac_nids)) ||
|
ARRAY_SIZE(spec->private_dac_nids)) ||
|
||||||
found_in_nid_list(nid, spec->multiout.hp_out_nid,
|
found_in_nid_list(nid, spec->multiout.hp_out_nid,
|
||||||
@ -2936,6 +2937,10 @@ static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
|
|||||||
found_in_nid_list(nid, spec->multiout.extra_out_nid,
|
found_in_nid_list(nid, spec->multiout.extra_out_nid,
|
||||||
ARRAY_SIZE(spec->multiout.extra_out_nid)))
|
ARRAY_SIZE(spec->multiout.extra_out_nid)))
|
||||||
return true;
|
return true;
|
||||||
|
for (i = 0; i < spec->multi_ios; i++) {
|
||||||
|
if (spec->multi_io[i].dac == nid)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3028,20 +3033,20 @@ enum {
|
|||||||
BAD_NO_PRIMARY_DAC = 0x10000,
|
BAD_NO_PRIMARY_DAC = 0x10000,
|
||||||
/* No DAC is found for the extra output */
|
/* No DAC is found for the extra output */
|
||||||
BAD_NO_DAC = 0x4000,
|
BAD_NO_DAC = 0x4000,
|
||||||
|
/* No possible multi-ios */
|
||||||
|
BAD_MULTI_IO = 0x103,
|
||||||
/* No individual DAC for extra output */
|
/* No individual DAC for extra output */
|
||||||
BAD_NO_EXTRA_DAC = 0x1000,
|
BAD_NO_EXTRA_DAC = 0x102,
|
||||||
/* No individual DAC for extra surrounds */
|
/* No individual DAC for extra surrounds */
|
||||||
BAD_NO_EXTRA_SURR_DAC = 0x200,
|
BAD_NO_EXTRA_SURR_DAC = 0x101,
|
||||||
/* Primary DAC shared with main surrounds */
|
/* Primary DAC shared with main surrounds */
|
||||||
BAD_SHARED_SURROUND = 0x100,
|
BAD_SHARED_SURROUND = 0x100,
|
||||||
/* Volume widget is shared */
|
|
||||||
BAD_SHARED_VOL = 0x10,
|
|
||||||
/* Primary DAC shared with main CLFE */
|
/* Primary DAC shared with main CLFE */
|
||||||
BAD_SHARED_CLFE = 0x10,
|
BAD_SHARED_CLFE = 0x10,
|
||||||
/* Primary DAC shared with extra surrounds */
|
/* Primary DAC shared with extra surrounds */
|
||||||
BAD_SHARED_EXTRA_SURROUND = 0x10,
|
BAD_SHARED_EXTRA_SURROUND = 0x10,
|
||||||
/* No possible multi-ios */
|
/* Volume widget is shared */
|
||||||
BAD_MULTI_IO = 0x1,
|
BAD_SHARED_VOL = 0x10,
|
||||||
};
|
};
|
||||||
|
|
||||||
static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
|
static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
|
||||||
@ -3140,7 +3145,8 @@ static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int alc_auto_fill_multi_ios(struct hda_codec *codec,
|
static int alc_auto_fill_multi_ios(struct hda_codec *codec,
|
||||||
unsigned int location, int offset);
|
hda_nid_t reference_pin,
|
||||||
|
bool hardwired, int offset);
|
||||||
|
|
||||||
static bool alc_map_singles(struct hda_codec *codec, int outs,
|
static bool alc_map_singles(struct hda_codec *codec, int outs,
|
||||||
const hda_nid_t *pins, hda_nid_t *dacs)
|
const hda_nid_t *pins, hda_nid_t *dacs)
|
||||||
@ -3159,11 +3165,11 @@ static bool alc_map_singles(struct hda_codec *codec, int outs,
|
|||||||
|
|
||||||
/* fill in the dac_nids table from the parsed pin configuration */
|
/* fill in the dac_nids table from the parsed pin configuration */
|
||||||
static int fill_and_eval_dacs(struct hda_codec *codec,
|
static int fill_and_eval_dacs(struct hda_codec *codec,
|
||||||
bool fill_hardwired)
|
bool fill_hardwired,
|
||||||
|
bool fill_mio_first)
|
||||||
{
|
{
|
||||||
struct alc_spec *spec = codec->spec;
|
struct alc_spec *spec = codec->spec;
|
||||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||||
unsigned int location, defcfg;
|
|
||||||
int i, j, err, badness;
|
int i, j, err, badness;
|
||||||
|
|
||||||
/* set num_dacs once to full for alc_auto_look_for_dac() */
|
/* set num_dacs once to full for alc_auto_look_for_dac() */
|
||||||
@ -3181,14 +3187,20 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
|
|||||||
bool mapped;
|
bool mapped;
|
||||||
do {
|
do {
|
||||||
mapped = alc_map_singles(codec, cfg->line_outs,
|
mapped = alc_map_singles(codec, cfg->line_outs,
|
||||||
cfg->line_out_pins,
|
cfg->line_out_pins,
|
||||||
spec->private_dac_nids);
|
spec->private_dac_nids);
|
||||||
mapped |= alc_map_singles(codec, cfg->hp_outs,
|
mapped |= alc_map_singles(codec, cfg->hp_outs,
|
||||||
cfg->hp_pins,
|
cfg->hp_pins,
|
||||||
spec->multiout.hp_out_nid);
|
spec->multiout.hp_out_nid);
|
||||||
mapped |= alc_map_singles(codec, cfg->speaker_outs,
|
mapped |= alc_map_singles(codec, cfg->speaker_outs,
|
||||||
cfg->speaker_pins,
|
cfg->speaker_pins,
|
||||||
spec->multiout.extra_out_nid);
|
spec->multiout.extra_out_nid);
|
||||||
|
if (fill_mio_first && cfg->line_outs == 1 &&
|
||||||
|
cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
|
||||||
|
err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], true, 0);
|
||||||
|
if (!err)
|
||||||
|
mapped = true;
|
||||||
|
}
|
||||||
} while (mapped);
|
} while (mapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3240,14 +3252,13 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
|
if (fill_mio_first &&
|
||||||
|
cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
|
||||||
/* try to fill multi-io first */
|
/* try to fill multi-io first */
|
||||||
defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
|
err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0);
|
||||||
location = get_defcfg_location(defcfg);
|
|
||||||
err = alc_auto_fill_multi_ios(codec, location, 0);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
badness += err;
|
/* we don't count badness at this stage yet */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
|
if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
|
||||||
@ -3266,17 +3277,29 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
|
|||||||
return err;
|
return err;
|
||||||
badness += err;
|
badness += err;
|
||||||
}
|
}
|
||||||
if (!spec->multi_ios &&
|
if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
|
||||||
cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
|
err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0);
|
||||||
cfg->hp_outs) {
|
|
||||||
/* try multi-ios with HP + inputs */
|
|
||||||
defcfg = snd_hda_codec_get_pincfg(codec, cfg->hp_pins[0]);
|
|
||||||
location = get_defcfg_location(defcfg);
|
|
||||||
err = alc_auto_fill_multi_ios(codec, location, 1);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
badness += err;
|
badness += err;
|
||||||
}
|
}
|
||||||
|
if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
|
||||||
|
/* try multi-ios with HP + inputs */
|
||||||
|
err = alc_auto_fill_multi_ios(codec, cfg->hp_pins[0], false, 1);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
badness += err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spec->multi_ios == 2) {
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
spec->private_dac_nids[spec->multiout.num_dacs++] =
|
||||||
|
spec->multi_io[i].dac;
|
||||||
|
spec->ext_channel_count = 2;
|
||||||
|
} else if (spec->multi_ios) {
|
||||||
|
spec->multi_ios = 0;
|
||||||
|
badness += BAD_MULTI_IO;
|
||||||
|
}
|
||||||
|
|
||||||
return badness;
|
return badness;
|
||||||
}
|
}
|
||||||
@ -3326,8 +3349,8 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
|
|||||||
struct auto_pin_cfg *best_cfg;
|
struct auto_pin_cfg *best_cfg;
|
||||||
int best_badness = INT_MAX;
|
int best_badness = INT_MAX;
|
||||||
int badness;
|
int badness;
|
||||||
bool fill_hardwired = true;
|
bool fill_hardwired = true, fill_mio_first = true;
|
||||||
bool best_wired = true;
|
bool best_wired = true, best_mio = true;
|
||||||
bool hp_spk_swapped = false;
|
bool hp_spk_swapped = false;
|
||||||
|
|
||||||
best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL);
|
best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL);
|
||||||
@ -3336,23 +3359,28 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
|
|||||||
*best_cfg = *cfg;
|
*best_cfg = *cfg;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
badness = fill_and_eval_dacs(codec, fill_hardwired);
|
badness = fill_and_eval_dacs(codec, fill_hardwired,
|
||||||
|
fill_mio_first);
|
||||||
if (badness < 0)
|
if (badness < 0)
|
||||||
return badness;
|
return badness;
|
||||||
debug_badness("==> lo_type=%d, wired=%d, badness=0x%x\n",
|
debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n",
|
||||||
cfg->line_out_type, fill_hardwired, badness);
|
cfg->line_out_type, fill_hardwired, fill_mio_first,
|
||||||
|
badness);
|
||||||
debug_show_configs(spec, cfg);
|
debug_show_configs(spec, cfg);
|
||||||
if (badness < best_badness) {
|
if (badness < best_badness) {
|
||||||
best_badness = badness;
|
best_badness = badness;
|
||||||
*best_cfg = *cfg;
|
*best_cfg = *cfg;
|
||||||
best_wired = fill_hardwired;
|
best_wired = fill_hardwired;
|
||||||
|
best_mio = fill_mio_first;
|
||||||
}
|
}
|
||||||
if (!badness)
|
if (!badness)
|
||||||
break;
|
break;
|
||||||
if (fill_hardwired) {
|
fill_mio_first = !fill_mio_first;
|
||||||
fill_hardwired = false;
|
if (!fill_mio_first)
|
||||||
|
continue;
|
||||||
|
fill_hardwired = !fill_hardwired;
|
||||||
|
if (!fill_hardwired)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
if (hp_spk_swapped)
|
if (hp_spk_swapped)
|
||||||
break;
|
break;
|
||||||
hp_spk_swapped = true;
|
hp_spk_swapped = true;
|
||||||
@ -3389,10 +3417,10 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
|
|||||||
|
|
||||||
if (badness) {
|
if (badness) {
|
||||||
*cfg = *best_cfg;
|
*cfg = *best_cfg;
|
||||||
fill_and_eval_dacs(codec, best_wired);
|
fill_and_eval_dacs(codec, best_wired, best_mio);
|
||||||
}
|
}
|
||||||
debug_badness("==> Best config: lo_type=%d, wired=%d\n",
|
debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n",
|
||||||
cfg->line_out_type, best_wired);
|
cfg->line_out_type, best_wired, best_mio);
|
||||||
debug_show_configs(spec, cfg);
|
debug_show_configs(spec, cfg);
|
||||||
|
|
||||||
if (cfg->line_out_pins[0])
|
if (cfg->line_out_pins[0])
|
||||||
@ -3791,66 +3819,110 @@ static void alc_auto_init_extra_out(struct hda_codec *codec)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check whether the given pin can be a multi-io pin */
|
||||||
|
static bool can_be_multiio_pin(struct hda_codec *codec,
|
||||||
|
unsigned int location, hda_nid_t nid)
|
||||||
|
{
|
||||||
|
unsigned int defcfg, caps;
|
||||||
|
|
||||||
|
defcfg = snd_hda_codec_get_pincfg(codec, nid);
|
||||||
|
if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
|
||||||
|
return false;
|
||||||
|
if (location && get_defcfg_location(defcfg) != location)
|
||||||
|
return false;
|
||||||
|
caps = snd_hda_query_pin_caps(codec, nid);
|
||||||
|
if (!(caps & AC_PINCAP_OUT))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* multi-io helper
|
* multi-io helper
|
||||||
|
*
|
||||||
|
* When hardwired is set, try to fill ony hardwired pins, and returns
|
||||||
|
* zero if any pins are filled, non-zero if nothing found.
|
||||||
|
* When hardwired is off, try to fill possible input pins, and returns
|
||||||
|
* the badness value.
|
||||||
*/
|
*/
|
||||||
static int alc_auto_fill_multi_ios(struct hda_codec *codec,
|
static int alc_auto_fill_multi_ios(struct hda_codec *codec,
|
||||||
unsigned int location,
|
hda_nid_t reference_pin,
|
||||||
int offset)
|
bool hardwired, int offset)
|
||||||
{
|
{
|
||||||
struct alc_spec *spec = codec->spec;
|
struct alc_spec *spec = codec->spec;
|
||||||
struct auto_pin_cfg *cfg = &spec->autocfg;
|
struct auto_pin_cfg *cfg = &spec->autocfg;
|
||||||
hda_nid_t prime_dac = spec->private_dac_nids[0];
|
int type, i, j, dacs, num_pins, old_pins;
|
||||||
int type, i, dacs, num_pins = 0;
|
unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
|
||||||
|
unsigned int location = get_defcfg_location(defcfg);
|
||||||
int badness = 0;
|
int badness = 0;
|
||||||
|
|
||||||
|
old_pins = spec->multi_ios;
|
||||||
|
if (old_pins >= 2)
|
||||||
|
goto end_fill;
|
||||||
|
|
||||||
|
num_pins = 0;
|
||||||
|
for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
|
||||||
|
for (i = 0; i < cfg->num_inputs; i++) {
|
||||||
|
if (cfg->inputs[i].type != type)
|
||||||
|
continue;
|
||||||
|
if (can_be_multiio_pin(codec, location,
|
||||||
|
cfg->inputs[i].pin))
|
||||||
|
num_pins++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_pins < 2)
|
||||||
|
goto end_fill;
|
||||||
|
|
||||||
dacs = spec->multiout.num_dacs;
|
dacs = spec->multiout.num_dacs;
|
||||||
for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
|
for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
|
||||||
for (i = 0; i < cfg->num_inputs; i++) {
|
for (i = 0; i < cfg->num_inputs; i++) {
|
||||||
hda_nid_t nid = cfg->inputs[i].pin;
|
hda_nid_t nid = cfg->inputs[i].pin;
|
||||||
hda_nid_t dac = 0;
|
hda_nid_t dac = 0;
|
||||||
unsigned int defcfg, caps;
|
|
||||||
if (cfg->inputs[i].type != type)
|
if (cfg->inputs[i].type != type)
|
||||||
continue;
|
continue;
|
||||||
defcfg = snd_hda_codec_get_pincfg(codec, nid);
|
if (!can_be_multiio_pin(codec, location, nid))
|
||||||
if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
|
|
||||||
continue;
|
continue;
|
||||||
if (location && get_defcfg_location(defcfg) != location)
|
for (j = 0; j < spec->multi_ios; j++) {
|
||||||
|
if (nid == spec->multi_io[j].pin)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (j < spec->multi_ios)
|
||||||
continue;
|
continue;
|
||||||
caps = snd_hda_query_pin_caps(codec, nid);
|
|
||||||
if (!(caps & AC_PINCAP_OUT))
|
if (offset && offset + spec->multi_ios < dacs) {
|
||||||
continue;
|
dac = spec->private_dac_nids[offset + spec->multi_ios];
|
||||||
if (offset && offset + num_pins < dacs) {
|
|
||||||
dac = spec->private_dac_nids[offset + num_pins];
|
|
||||||
if (!alc_auto_is_dac_reachable(codec, nid, dac))
|
if (!alc_auto_is_dac_reachable(codec, nid, dac))
|
||||||
dac = 0;
|
dac = 0;
|
||||||
}
|
}
|
||||||
if (!dac)
|
if (hardwired)
|
||||||
|
dac = get_dac_if_single(codec, nid);
|
||||||
|
else if (!dac)
|
||||||
dac = alc_auto_look_for_dac(codec, nid);
|
dac = alc_auto_look_for_dac(codec, nid);
|
||||||
if (!dac) {
|
if (!dac) {
|
||||||
badness += BAD_MULTI_IO;
|
badness++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
spec->multi_io[num_pins].pin = nid;
|
spec->multi_io[spec->multi_ios].pin = nid;
|
||||||
spec->multi_io[num_pins].dac = dac;
|
spec->multi_io[spec->multi_ios].dac = dac;
|
||||||
num_pins++;
|
spec->multi_ios++;
|
||||||
spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
|
if (spec->multi_ios >= 2)
|
||||||
if (num_pins >= 2)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spec->multiout.num_dacs = dacs;
|
end_fill:
|
||||||
if (num_pins < 2) {
|
if (badness)
|
||||||
/* clear up again */
|
badness = BAD_MULTI_IO;
|
||||||
memset(spec->private_dac_nids + dacs, 0,
|
if (old_pins == spec->multi_ios) {
|
||||||
sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - dacs));
|
if (hardwired)
|
||||||
spec->private_dac_nids[0] = prime_dac;
|
return 1; /* nothing found */
|
||||||
|
else
|
||||||
|
return badness; /* no badness if nothing found */
|
||||||
|
}
|
||||||
|
if (!hardwired && spec->multi_ios < 2) {
|
||||||
|
spec->multi_ios = old_pins;
|
||||||
return badness;
|
return badness;
|
||||||
}
|
}
|
||||||
|
|
||||||
spec->multi_ios = num_pins;
|
|
||||||
spec->ext_channel_count = 2;
|
|
||||||
spec->multiout.num_dacs = num_pins + 1;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user