summaryrefslogtreecommitdiff
path: root/sound/pci/hda/hda_generic.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-01-21 18:11:25 +0400
committerTakashi Iwai <tiwai@suse.de>2013-01-21 18:11:25 +0400
commita1e908edccd1b6928cda78371026b458e2c1973a (patch)
treea6db12980efa5d13dee688dabeb51b1a4f2f44b8 /sound/pci/hda/hda_generic.c
parentf87498b65197f951899d8bbd99e5553227c41ec9 (diff)
downloadlinux-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.c59
1 files changed, 51 insertions, 8 deletions
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index e26e8d3430f2..6d1e843c6e8d 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;
}