return false;
}
-static void clear_vol_marks(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i < spec->out_path.used; i++) {
- struct nid_path *path = snd_array_elem(&spec->out_path, i);
- path->ctls[0] = path->ctls[1] = 0;
- }
-}
-
/* badness definition */
enum {
/* No primary DAC is found for the main output */
return NULL;
}
-static int eval_shared_vol_badness(struct hda_codec *codec, hda_nid_t pin,
- hda_nid_t dac)
+/* look for widgets in the path between the given NIDs appropriate for
+ * volume and mute controls, and assign the values to ctls[].
+ *
+ * When no appropriate widget is found in the path, the badness value
+ * is incremented depending on the situation. The function returns the
+ * total badness for both volume and mute controls.
+ */
+static int assign_out_path_ctls(struct hda_codec *codec, hda_nid_t pin,
+ hda_nid_t dac)
{
struct nid_path *path = get_out_path(codec, pin, dac);
hda_nid_t nid;
nid = alc_look_for_out_mute_nid(codec, path);
if (nid) {
unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid));
- if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT)
+ if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT ||
+ nid_has_mute(codec, nid, HDA_OUTPUT))
val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
else
val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
if (!add_new_out_path(codec, pin, dac))
dac = dacs[i] = 0;
if (dac)
- badness += eval_shared_vol_badness(codec, pin, dac);
+ badness += assign_out_path_ctls(codec, pin, dac);
}
return badness;
spec->vmaster_nid = alc_look_for_out_vol_nid(codec, path);
}
- /* clear the bitmap flags for creating controls */
- clear_vol_marks(codec);
kfree(best_cfg);
return 0;
}
+/* replace the channels in the composed amp value with the given number */
+static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs)
+{
+ val &= ~(0x3U << 16);
+ val |= chs << 16;
+ return val;
+}
+
static int alc_auto_add_vol_ctl(struct hda_codec *codec,
const char *pfx, int cidx,
- hda_nid_t nid, unsigned int chs,
+ unsigned int chs,
struct nid_path *path)
{
unsigned int val;
- if (!nid || !path)
+ if (!path)
return 0;
- val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
- if (is_ctl_used(codec, val, NID_PATH_VOL_CTL) && chs != 2) /* exclude LFE */
+ val = path->ctls[NID_PATH_VOL_CTL];
+ if (!val)
return 0;
- path->ctls[NID_PATH_VOL_CTL] = val;
- return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx,
- val);
+ val = amp_val_replace_channels(val, chs);
+ return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx, val);
+}
+
+/* return the channel bits suitable for the given path->ctls[] */
+static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path,
+ int type)
+{
+ int chs = 1; /* mono (left only) */
+ if (path) {
+ hda_nid_t nid = get_amp_nid_(path->ctls[type]);
+ if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO))
+ chs = 3; /* stereo */
+ }
+ return chs;
}
static int alc_auto_add_stereo_vol(struct hda_codec *codec,
const char *pfx, int cidx,
- hda_nid_t nid, struct nid_path *path)
+ struct nid_path *path)
{
- int chs = 1;
- if (get_wcaps(codec, nid) & AC_WCAP_STEREO)
- chs = 3;
- return alc_auto_add_vol_ctl(codec, pfx, cidx, nid, chs, path);
+ int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL);
+ return alc_auto_add_vol_ctl(codec, pfx, cidx, chs, path);
}
/* create a mute-switch for the given mixer widget;
*/
static int alc_auto_add_sw_ctl(struct hda_codec *codec,
const char *pfx, int cidx,
- hda_nid_t nid, unsigned int chs,
+ unsigned int chs,
struct nid_path *path)
{
- int wid_type;
- int type;
- unsigned long val;
- if (!nid || !path)
+ unsigned int val;
+ int type = ALC_CTL_WIDGET_MUTE;
+
+ if (!path)
return 0;
- wid_type = get_wcaps_type(get_wcaps(codec, nid));
- if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) {
- type = ALC_CTL_WIDGET_MUTE;
- val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
- } else if (snd_hda_get_num_conns(codec, nid) == 1) {
- type = ALC_CTL_WIDGET_MUTE;
- val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT);
- } else {
- type = ALC_CTL_BIND_MUTE;
- val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT);
- }
- if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL) && chs != 2) /* exclude LFE */
+ val = path->ctls[NID_PATH_MUTE_CTL];
+ if (!val)
return 0;
- path->ctls[NID_PATH_MUTE_CTL] = val;
+ val = amp_val_replace_channels(val, chs);
+ if (get_amp_direction_(val) == HDA_INPUT) {
+ hda_nid_t nid = get_amp_nid_(val);
+ if (snd_hda_get_num_conns(codec, nid) > 1) {
+ type = ALC_CTL_BIND_MUTE;
+ val |= 2 << 19; /* FIXME: fixed two widgets, so far */
+ }
+ }
return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
}
static int alc_auto_add_stereo_sw(struct hda_codec *codec, const char *pfx,
- int cidx, hda_nid_t nid,
- struct nid_path *path)
+ int cidx, struct nid_path *path)
{
- int chs = 1;
- if (get_wcaps(codec, nid) & AC_WCAP_STEREO)
- chs = 3;
- return alc_auto_add_sw_ctl(codec, pfx, cidx, nid, chs, path);
+ int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL);
+ return alc_auto_add_sw_ctl(codec, pfx, cidx, chs, path);
}
static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
const char *name;
int index;
hda_nid_t dac, pin;
- hda_nid_t sw, vol;
struct nid_path *path;
dac = spec->multiout.dac_nids[i];
path = get_out_path(codec, pin, dac);
if (!path)
continue;
- sw = alc_look_for_out_mute_nid(codec, path);
- vol = alc_look_for_out_vol_nid(codec, path);
if (!name || !strcmp(name, "CLFE")) {
/* Center/LFE */
- err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1,
- path);
+ err = alc_auto_add_vol_ctl(codec, "Center", 0, 1, path);
if (err < 0)
return err;
- err = alc_auto_add_vol_ctl(codec, "LFE", 0, vol, 2,
- path);
+ err = alc_auto_add_vol_ctl(codec, "LFE", 0, 2, path);
if (err < 0)
return err;
- err = alc_auto_add_sw_ctl(codec, "Center", 0, sw, 1,
- path);
+ err = alc_auto_add_sw_ctl(codec, "Center", 0, 1, path);
if (err < 0)
return err;
- err = alc_auto_add_sw_ctl(codec, "LFE", 0, sw, 2,
- path);
+ err = alc_auto_add_sw_ctl(codec, "LFE", 0, 2, path);
if (err < 0)
return err;
} else {
- err = alc_auto_add_stereo_vol(codec, name, index, vol,
- path);
+ err = alc_auto_add_stereo_vol(codec, name, index, path);
if (err < 0)
return err;
- err = alc_auto_add_stereo_sw(codec, name, index, sw,
- path);
+ err = alc_auto_add_stereo_sw(codec, name, index, path);
if (err < 0)
return err;
}
hda_nid_t dac, const char *pfx,
int cidx)
{
- struct alc_spec *spec = codec->spec;
struct nid_path *path;
- hda_nid_t sw, vol;
int err;
path = get_out_path(codec, pin, dac);
if (!path)
return 0;
-
- if (!dac) {
- unsigned int val;
- /* the corresponding DAC is already occupied */
- if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
- return 0; /* no way */
- /* create a switch only */
- val = HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT);
- if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL))
- return 0; /* already created */
- path->ctls[NID_PATH_MUTE_CTL] = val;
- return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, cidx, val);
+ /* bind volume control will be created in the case of dac = 0 */
+ if (dac) {
+ err = alc_auto_add_stereo_vol(codec, pfx, cidx, path);
+ if (err < 0)
+ return err;
}
-
- sw = alc_look_for_out_mute_nid(codec, path);
- vol = alc_look_for_out_vol_nid(codec, path);
- err = alc_auto_add_stereo_vol(codec, pfx, cidx, vol, path);
- if (err < 0)
- return err;
- err = alc_auto_add_stereo_sw(codec, pfx, cidx, sw, path);
+ err = alc_auto_add_stereo_sw(codec, pfx, cidx, path);
if (err < 0)
return err;
return 0;
return badness;
}
- return 0;
+ /* assign volume and mute controls */
+ for (i = old_pins; i < spec->multi_ios; i++)
+ badness += assign_out_path_ctls(codec, spec->multi_io[i].pin,
+ spec->multi_io[i].dac);
+
+ return badness;
}
static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,