/* check whether a control with the given (nid, dir, idx) was assigned */
static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid,
- int dir, int idx)
+ int dir, int idx, int type)
{
unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
- return is_ctl_used(codec, val, NID_PATH_VOL_CTL) ||
- is_ctl_used(codec, val, NID_PATH_MUTE_CTL);
+ return is_ctl_used(codec, val, type);
}
static void print_nid_path(const char *pfx, struct nid_path *path)
/* get the default amp value for the target state */
static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
- int dir, bool enable)
+ int dir, unsigned int caps, bool enable)
{
- unsigned int caps;
unsigned int val = 0;
- caps = query_amp_caps(codec, nid, dir);
if (caps & AC_AMPCAP_NUM_STEPS) {
/* set to 0dB */
if (enable)
/* initialize the amp value (only at the first time) */
static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
{
- int val = get_amp_val_to_activate(codec, nid, dir, false);
+ unsigned int caps = query_amp_caps(codec, nid, dir);
+ int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
}
+/* calculate amp value mask we can modify;
+ * if the given amp is controlled by mixers, don't touch it
+ */
+static unsigned int get_amp_mask_to_modify(struct hda_codec *codec,
+ hda_nid_t nid, int dir, int idx,
+ unsigned int caps)
+{
+ unsigned int mask = 0xff;
+
+ if (caps & AC_AMPCAP_MUTE) {
+ if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL))
+ mask &= ~0x80;
+ }
+ if (caps & AC_AMPCAP_NUM_STEPS) {
+ if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
+ is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
+ mask &= ~0x7f;
+ }
+ return mask;
+}
+
static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
- int idx, bool enable)
+ int idx, int idx_to_check, bool enable)
{
- int val;
- if (is_ctl_associated(codec, nid, dir, idx) ||
- (!enable && is_active_nid(codec, nid, dir, idx)))
+ unsigned int caps;
+ unsigned int mask, val;
+
+ if (!enable && is_active_nid(codec, nid, dir, idx))
+ return;
+
+ caps = query_amp_caps(codec, nid, dir);
+ val = get_amp_val_to_activate(codec, nid, dir, caps, enable);
+ mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps);
+ if (!mask)
return;
- val = get_amp_val_to_activate(codec, nid, dir, enable);
- snd_hda_codec_amp_stereo(codec, nid, dir, idx, 0xff, val);
+
+ val &= mask;
+ snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val);
}
static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
{
hda_nid_t nid = path->path[i];
init_amp(codec, nid, HDA_OUTPUT, 0);
- activate_amp(codec, nid, HDA_OUTPUT, 0, enable);
+ activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable);
}
static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
for (n = 0; n < nums; n++)
init_amp(codec, nid, HDA_INPUT, n);
- if (is_ctl_associated(codec, nid, HDA_INPUT, idx))
- return;
-
/* here is a little bit tricky in comparison with activate_amp_out();
* when aa-mixer is available, we need to enable the path as well
*/
for (n = 0; n < nums; n++) {
if (n != idx && (!add_aamix || conn[n] != spec->mixer_nid))
continue;
- activate_amp(codec, nid, HDA_INPUT, n, enable);
+ activate_amp(codec, nid, HDA_INPUT, n, idx, enable);
}
}