Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 353002
b: refs/heads/master
c: 78e635c
h: refs/heads/master
v: v3
  • Loading branch information
Takashi Iwai committed Jan 10, 2013
1 parent 104edd0 commit 1ba8cc1
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 90 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 792cf2fa2ea926c0c07277c0b67ab60745e8f898
refs/heads/master: 78e635c93b0e385dc23d18c2a4047fc8857467bd
182 changes: 93 additions & 89 deletions trunk/sound/pci/hda/patch_realtek.c
Original file line number Diff line number Diff line change
Expand Up @@ -2858,55 +2858,6 @@ static void alc_auto_init_analog_input(struct hda_codec *codec)
}
}

/* convert from MIX nid to DAC */
static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
{
hda_nid_t list[5];
int i, num;

if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_AUD_OUT)
return nid;
num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
for (i = 0; i < num; i++) {
if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
return list[i];
}
return 0;
}

/* go down to the selector widget before the mixer */
static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
{
hda_nid_t srcs[5];
int num = snd_hda_get_connections(codec, pin, srcs,
ARRAY_SIZE(srcs));
if (num != 1 ||
get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
return pin;
return srcs[0];
}

/* select the connection from pin to DAC if needed */
static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
hda_nid_t dac)
{
hda_nid_t mix[5];
int i, num;

pin = alc_go_down_to_selector(codec, pin);
num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
if (num < 2)
return 0;
for (i = 0; i < num; i++) {
if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
snd_hda_codec_update_cache(codec, pin, 0,
AC_VERB_SET_CONNECT_SEL, i);
return 0;
}
}
return 0;
}

static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
{
struct alc_spec *spec = codec->spec;
Expand Down Expand Up @@ -3825,51 +3776,102 @@ static int alc_auto_create_speaker_out(struct hda_codec *codec)
"Speaker");
}

static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
hda_nid_t pin, int pin_type,
hda_nid_t dac)
/* is a volume or mute control already present? */
static bool __is_out_ctl_present(struct hda_codec *codec,
struct nid_path *exclude_path,
hda_nid_t nid, int dir, int types)
{
int i, num;
hda_nid_t nid, mix = 0;
hda_nid_t srcs[HDA_MAX_CONNECTIONS];
struct nid_path *path;
struct alc_spec *spec = codec->spec;
int i, type;

alc_set_pin_output(codec, pin, pin_type);
nid = alc_go_down_to_selector(codec, pin);
num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
for (i = 0; i < num; i++) {
if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
for (i = 0; i < spec->out_path.used; i++) {
struct nid_path *p = snd_array_elem(&spec->out_path, i);
if (p == exclude_path || p->depth <= 0)
continue;
mix = srcs[i];
break;
for (type = 0; type < 2; type++) {
if (types & (1 << type)) {
unsigned int val = p->ctls[type];
if (get_amp_nid_(val) == nid &&
get_amp_direction_(val) == dir)
return true;
}
}
}
if (!mix)
return;
return false;
}

#define is_out_ctl_present(codec, path, nid, dir) \
__is_out_ctl_present(codec, path, nid, dir, 3) /* check both types */
#define is_out_vol_ctl_present(codec, nid, dir) \
__is_out_ctl_present(codec, NULL, nid, dir, 1 << NID_PATH_VOL_CTL)
#define is_out_mute_ctl_present(codec, nid, dir) \
__is_out_ctl_present(codec, NULL, nid, dir, 1 << NID_PATH_MUTE_CTL)

static int get_default_amp_val(struct hda_codec *codec, hda_nid_t nid, int dir)
{
unsigned int caps, offset;
unsigned int val = 0;

caps = query_amp_caps(codec, nid, dir);
if (caps & AC_AMPCAP_NUM_STEPS) {
offset = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
/* if a volume control is assigned, set the lowest level
* as default; otherwise set to 0dB
*/
if (is_out_vol_ctl_present(codec, nid, dir))
val = 0;
else
val = offset;
}
if (caps & AC_AMPCAP_MUTE) {
/* if a mute control is assigned, mute as default */
if (is_out_mute_ctl_present(codec, nid, dir))
val |= HDA_AMP_MUTE;
}
return val;
}

/* configure the path from the given dac to the pin as the proper output */
static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
hda_nid_t pin, int pin_type,
hda_nid_t dac, bool force)
{
int i, val;
struct nid_path *path;

/* need the manual connection? */
if (num > 1)
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
/* unmute mixer widget inputs */
if (nid_has_mute(codec, mix, HDA_INPUT)) {
snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_UNMUTE(0));
snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_UNMUTE(1));
}
/* initialize volume */
alc_set_pin_output(codec, pin, pin_type);
path = get_out_path(codec, pin, dac);
if (!path)
return;
nid = alc_look_for_out_vol_nid(codec, path);
if (nid)
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_ZERO);

/* unmute DAC if it's not assigned to a mixer */
nid = alc_look_for_out_mute_nid(codec, path);
if (nid == mix && nid_has_mute(codec, dac, HDA_OUTPUT))
snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_ZERO);
for (i = path->depth - 1; i >= 0; i--) {
hda_nid_t nid = path->path[i];
if (i > 0 && path->multi[i - 1])
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_CONNECT_SEL,
path->idx[i - 1]);

if (i != 0 && i != path->depth - 1 &&
(get_wcaps(codec, nid) & AC_WCAP_IN_AMP) &&
(force || !is_out_ctl_present(codec, path, nid,
HDA_INPUT))) {
val = get_default_amp_val(codec, nid, HDA_INPUT);
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_UNMUTE(0) | val);
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_UNMUTE(1) | val);
}
if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
(force || !is_out_ctl_present(codec, path, nid,
HDA_OUTPUT))) {
val = get_default_amp_val(codec, nid, HDA_OUTPUT);
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_UNMUTE | val);
}
}
}

static void alc_auto_init_multi_out(struct hda_codec *codec)
Expand All @@ -3882,7 +3884,8 @@ static void alc_auto_init_multi_out(struct hda_codec *codec)
hda_nid_t nid = spec->autocfg.line_out_pins[i];
if (nid)
alc_auto_set_output_and_unmute(codec, nid, pin_type,
spec->multiout.dac_nids[i]);
spec->multiout.dac_nids[i], true);

}
}

Expand All @@ -3905,7 +3908,7 @@ static void alc_auto_init_extra_out(struct hda_codec *codec)
else
dac = spec->multiout.dac_nids[0];
}
alc_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
alc_auto_set_output_and_unmute(codec, pin, PIN_HP, dac, true);
}
for (i = 0; i < spec->autocfg.speaker_outs; i++) {
if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
Expand All @@ -3920,7 +3923,7 @@ static void alc_auto_init_extra_out(struct hda_codec *codec)
else
dac = spec->multiout.dac_nids[0];
}
alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac, true);
}
}

Expand Down Expand Up @@ -4081,7 +4084,8 @@ static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
HDA_AMP_MUTE, 0);
alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
alc_auto_set_output_and_unmute(codec, nid, PIN_OUT,
spec->multi_io[idx].dac, false);
} else {
if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
Expand Down

0 comments on commit 1ba8cc1

Please sign in to comment.