diff options
author | Takashi Iwai <tiwai@suse.de> | 2013-01-21 14:11:25 (GMT) |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-01-21 14:11:25 (GMT) |
commit | a1e908edccd1b6928cda78371026b458e2c1973a (patch) | |
tree | a6db12980efa5d13dee688dabeb51b1a4f2f44b8 /sound/pci/hda/hda_generic.c | |
parent | f87498b65197f951899d8bbd99e5553227c41ec9 (diff) | |
download | linux-a1e908edccd1b6928cda78371026b458e2c1973a.tar.xz |
ALSA: hda - Fix conflicts between Loopback Mixing and Independent HP
This patch eventually fixes two issues:
- Handle the case where the primary output is a headphone and can have
independent HP mode;
so far we checked only the case where the headphone is the secondary
output.
- Fix the conflict of HP independent mode and aamix mode;
when switched to aamix mode, the DAC might be also switched to
another widget shared with other outputs. Then even if we disable
the DAC for the original output, it doesn't change -- because the
active route is from another (shared) DAC to HP pin through aamix.
So, in such a case, we have to prohibit the switch to aamix for HP
routes.
This fixes issues appearing on VT codecs.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_generic.c')
-rw-r--r-- | sound/pci/hda/hda_generic.c | 59 |
1 files changed, 51 insertions, 8 deletions
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index e26e8d3..6d1e843 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -1845,6 +1845,10 @@ static int indep_hp_get(struct snd_kcontrol *kcontrol, return 0; } +static void update_aamix_paths(struct hda_codec *codec, bool do_mix, + int nomix_path_idx, int mix_path_idx, + int out_type); + static int indep_hp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1860,11 +1864,31 @@ static int indep_hp_put(struct snd_kcontrol *kcontrol, } if (spec->indep_hp_enabled != select) { + hda_nid_t *dacp; + if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) + dacp = &spec->private_dac_nids[0]; + else + dacp = &spec->multiout.hp_out_nid[0]; + + /* update HP aamix paths in case it conflicts with indep HP */ + if (spec->have_aamix_ctl) { + if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) + update_aamix_paths(codec, spec->aamix_mode, + spec->out_paths[0], + spec->aamix_out_paths[0], + spec->autocfg.line_out_type); + else + update_aamix_paths(codec, spec->aamix_mode, + spec->hp_paths[0], + spec->aamix_out_paths[1], + AUTO_PIN_HP_OUT); + } + spec->indep_hp_enabled = select; if (spec->indep_hp_enabled) - spec->multiout.hp_out_nid[0] = 0; + *dacp = 0; else - spec->multiout.hp_out_nid[0] = spec->alt_dac_nid; + *dacp = spec->alt_dac_nid; ret = 1; } unlock: @@ -1884,16 +1908,21 @@ static const struct snd_kcontrol_new indep_hp_ctl = { static int create_indep_hp_ctls(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; + hda_nid_t dac; if (!spec->indep_hp) return 0; - if (!spec->multiout.hp_out_nid[0]) { + if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) + dac = spec->multiout.dac_nids[0]; + else + dac = spec->multiout.hp_out_nid[0]; + if (!dac) { spec->indep_hp = 0; return 0; } spec->indep_hp_enabled = false; - spec->alt_dac_nid = spec->multiout.hp_out_nid[0]; + spec->alt_dac_nid = dac; if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl)) return -ENOMEM; return 0; @@ -2026,14 +2055,24 @@ static int loopback_mixing_get(struct snd_kcontrol *kcontrol, } static void update_aamix_paths(struct hda_codec *codec, bool do_mix, - int nomix_path_idx, int mix_path_idx) + int nomix_path_idx, int mix_path_idx, + int out_type) { + struct hda_gen_spec *spec = codec->spec; struct nid_path *nomix_path, *mix_path; nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx); mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx); if (!nomix_path || !mix_path) return; + + /* if HP aamix path is driven from a different DAC and the + * independent HP mode is ON, can't turn on aamix path + */ + if (out_type == AUTO_PIN_HP_OUT && spec->indep_hp_enabled && + mix_path->path[0] != spec->alt_dac_nid) + do_mix = false; + if (do_mix) { snd_hda_activate_path(codec, nomix_path, false, true); snd_hda_activate_path(codec, mix_path, true, true); @@ -2054,11 +2093,14 @@ static int loopback_mixing_put(struct snd_kcontrol *kcontrol, return 0; spec->aamix_mode = val; update_aamix_paths(codec, val, spec->out_paths[0], - spec->aamix_out_paths[0]); + spec->aamix_out_paths[0], + spec->autocfg.line_out_type); update_aamix_paths(codec, val, spec->hp_paths[0], - spec->aamix_out_paths[1]); + spec->aamix_out_paths[1], + AUTO_PIN_HP_OUT); update_aamix_paths(codec, val, spec->speaker_paths[0], - spec->aamix_out_paths[2]); + spec->aamix_out_paths[2], + AUTO_PIN_SPEAKER_OUT); return 1; } @@ -2081,6 +2123,7 @@ static int create_loopback_mixing_ctl(struct hda_codec *codec) return 0; if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) return -ENOMEM; + spec->have_aamix_ctl = 1; return 0; } |