Skip to content

Commit

Permalink
ALSA: hda - Fix conflicts between Loopback Mixing and Independent HP
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Takashi Iwai committed Jan 21, 2013
1 parent f87498b commit a1e908e
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 8 deletions.
59 changes: 51 additions & 8 deletions sound/pci/hda/hda_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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:
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}

Expand All @@ -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;
}

Expand Down
1 change: 1 addition & 0 deletions sound/pci/hda/hda_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ struct hda_gen_spec {
unsigned int no_analog:1; /* digital I/O only */
unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
unsigned int indep_hp_enabled:1; /* independent HP enabled */
unsigned int have_aamix_ctl:1;

/* loopback mixing mode */
bool aamix_mode;
Expand Down

0 comments on commit a1e908e

Please sign in to comment.