[ALSA] hda-codec - Add virtual master controls
Add master controls using vmaster to codecs that have no real hardware master volume registers. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
3b0a5f22d4
commit
2134ea4f37
|
@ -1012,6 +1012,66 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* set (static) TLV for virtual master volume; recalculated as max 0dB
|
||||
*/
|
||||
void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
|
||||
unsigned int *tlv)
|
||||
{
|
||||
u32 caps;
|
||||
int nums, step;
|
||||
|
||||
caps = query_amp_caps(codec, nid, dir);
|
||||
nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
|
||||
step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT;
|
||||
step = (step + 1) * 25;
|
||||
tlv[0] = SNDRV_CTL_TLVT_DB_SCALE;
|
||||
tlv[1] = 2 * sizeof(unsigned int);
|
||||
tlv[2] = -nums * step;
|
||||
tlv[3] = step;
|
||||
}
|
||||
|
||||
/* find a mixer control element with the given name */
|
||||
struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
|
||||
const char *name)
|
||||
{
|
||||
struct snd_ctl_elem_id id;
|
||||
memset(&id, 0, sizeof(id));
|
||||
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
strcpy(id.name, name);
|
||||
return snd_ctl_find_id(codec->bus->card, &id);
|
||||
}
|
||||
|
||||
/* create a virtual master control and add slaves */
|
||||
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
||||
unsigned int *tlv, const char **slaves)
|
||||
{
|
||||
struct snd_kcontrol *kctl;
|
||||
const char **s;
|
||||
int err;
|
||||
|
||||
kctl = snd_ctl_make_virtual_master(name, tlv);
|
||||
if (!kctl)
|
||||
return -ENOMEM;
|
||||
err = snd_ctl_add(codec->bus->card, kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (s = slaves; *s; s++) {
|
||||
struct snd_kcontrol *sctl;
|
||||
|
||||
sctl = snd_hda_find_mixer_ctl(codec, *s);
|
||||
if (!sctl) {
|
||||
snd_printdd("Cannot find slave %s, skipped\n", *s);
|
||||
continue;
|
||||
}
|
||||
err = snd_ctl_add_slave(kctl, sctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* switch */
|
||||
int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
|
|
|
@ -90,6 +90,13 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
|
|||
void snd_hda_codec_resume_amp(struct hda_codec *codec);
|
||||
#endif
|
||||
|
||||
void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
|
||||
unsigned int *tlv);
|
||||
struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
|
||||
const char *name);
|
||||
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
|
||||
unsigned int *tlv, const char **slaves);
|
||||
|
||||
/* amp value bits */
|
||||
#define HDA_AMP_MUTE 0x80
|
||||
#define HDA_AMP_UNMUTE 0x00
|
||||
|
|
|
@ -78,6 +78,11 @@ struct ad198x_spec {
|
|||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
struct hda_loopback_check loopback;
|
||||
#endif
|
||||
/* for virtual master */
|
||||
hda_nid_t vmaster_nid;
|
||||
u32 vmaster_tlv[4];
|
||||
const char **slave_vols;
|
||||
const char **slave_sws;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -125,6 +130,28 @@ static int ad198x_init(struct hda_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char *ad_slave_vols[] = {
|
||||
"Front Playback Volume",
|
||||
"Surround Playback Volume",
|
||||
"Center Playback Volume",
|
||||
"LFE Playback Volume",
|
||||
"Side Playback Volume",
|
||||
"Headphone Playback Volume",
|
||||
"Mono Playback Volume",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *ad_slave_sws[] = {
|
||||
"Front Playback Switch",
|
||||
"Surround Playback Switch",
|
||||
"Center Playback Switch",
|
||||
"LFE Playback Switch",
|
||||
"Side Playback Switch",
|
||||
"Headphone Playback Switch",
|
||||
"Mono Playback Switch",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int ad198x_build_controls(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_spec *spec = codec->spec;
|
||||
|
@ -146,6 +173,27 @@ static int ad198x_build_controls(struct hda_codec *codec)
|
|||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* if we have no master control, let's create it */
|
||||
if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
|
||||
snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
|
||||
HDA_OUTPUT, spec->vmaster_tlv);
|
||||
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
|
||||
spec->vmaster_tlv,
|
||||
(spec->slave_vols ?
|
||||
spec->slave_vols : ad_slave_vols));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
|
||||
err = snd_hda_add_vmaster(codec, "Master Playback Switch",
|
||||
NULL,
|
||||
(spec->slave_sws ?
|
||||
spec->slave_sws : ad_slave_sws));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -899,6 +947,7 @@ static int patch_ad1986a(struct hda_codec *codec)
|
|||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
spec->loopback.amplist = ad1986a_loopbacks;
|
||||
#endif
|
||||
spec->vmaster_nid = 0x1b;
|
||||
|
||||
codec->patch_ops = ad198x_patch_ops;
|
||||
|
||||
|
@ -1141,6 +1190,7 @@ static int patch_ad1983(struct hda_codec *codec)
|
|||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
spec->loopback.amplist = ad1983_loopbacks;
|
||||
#endif
|
||||
spec->vmaster_nid = 0x05;
|
||||
|
||||
codec->patch_ops = ad198x_patch_ops;
|
||||
|
||||
|
@ -1537,6 +1587,7 @@ static int patch_ad1981(struct hda_codec *codec)
|
|||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
spec->loopback.amplist = ad1981_loopbacks;
|
||||
#endif
|
||||
spec->vmaster_nid = 0x05;
|
||||
|
||||
codec->patch_ops = ad198x_patch_ops;
|
||||
|
||||
|
@ -2850,6 +2901,7 @@ static int patch_ad1988(struct hda_codec *codec)
|
|||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
spec->loopback.amplist = ad1988_loopbacks;
|
||||
#endif
|
||||
spec->vmaster_nid = 0x04;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3016,6 +3068,19 @@ static struct hda_amp_list ad1884_loopbacks[] = {
|
|||
};
|
||||
#endif
|
||||
|
||||
static const char *ad1884_slave_vols[] = {
|
||||
"PCM Playback Volume",
|
||||
"Mic Playback Volume",
|
||||
"Mono Playback Volume",
|
||||
"Front Mic Playback Volume",
|
||||
"Mic Playback Volume",
|
||||
"CD Playback Volume",
|
||||
"Internal Mic Playback Volume",
|
||||
"Docking Mic Playback Volume"
|
||||
"Beep Playback Volume",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int patch_ad1884(struct hda_codec *codec)
|
||||
{
|
||||
struct ad198x_spec *spec;
|
||||
|
@ -3043,6 +3108,9 @@ static int patch_ad1884(struct hda_codec *codec)
|
|||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
spec->loopback.amplist = ad1884_loopbacks;
|
||||
#endif
|
||||
spec->vmaster_nid = 0x04;
|
||||
/* we need to cover all playback volumes */
|
||||
spec->slave_vols = ad1884_slave_vols;
|
||||
|
||||
codec->patch_ops = ad198x_patch_ops;
|
||||
|
||||
|
@ -3485,6 +3553,7 @@ static int patch_ad1882(struct hda_codec *codec)
|
|||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
spec->loopback.amplist = ad1882_loopbacks;
|
||||
#endif
|
||||
spec->vmaster_nid = 0x04;
|
||||
|
||||
codec->patch_ops = ad198x_patch_ops;
|
||||
|
||||
|
|
|
@ -262,6 +262,9 @@ struct alc_spec {
|
|||
unsigned int sense_updated: 1;
|
||||
unsigned int jack_present: 1;
|
||||
|
||||
/* for virtual master */
|
||||
hda_nid_t vmaster_nid;
|
||||
u32 vmaster_tlv[4];
|
||||
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
||||
struct hda_loopback_check loopback;
|
||||
#endif
|
||||
|
@ -1309,8 +1312,8 @@ static hda_nid_t alc880_f1734_dac_nids[1] = {
|
|||
static struct snd_kcontrol_new alc880_f1734_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
|
||||
|
@ -1408,10 +1411,10 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
|
|||
|
||||
/* Uniwill */
|
||||
static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
|
||||
HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
|
||||
|
@ -1451,15 +1454,49 @@ static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
|
|||
};
|
||||
|
||||
static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
|
||||
HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
|
||||
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
||||
/*
|
||||
* virtual master controls
|
||||
*/
|
||||
|
||||
/*
|
||||
* slave controls for virtual master
|
||||
*/
|
||||
static const char *alc_slave_vols[] = {
|
||||
"Front Playback Volume",
|
||||
"Surround Playback Volume",
|
||||
"Center Playback Volume",
|
||||
"LFE Playback Volume",
|
||||
"Side Playback Volume",
|
||||
"Headphone Playback Volume",
|
||||
"Speaker Playback Volume",
|
||||
"Mono Playback Volume",
|
||||
"iSpeaker Playback Volume",
|
||||
"Line-Out Playback Volume",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char *alc_slave_sws[] = {
|
||||
"Front Playback Switch",
|
||||
"Surround Playback Switch",
|
||||
"Center Playback Switch",
|
||||
"LFE Playback Switch",
|
||||
"Side Playback Switch",
|
||||
"Headphone Playback Switch",
|
||||
"Speaker Playback Switch",
|
||||
"Mono Playback Switch",
|
||||
"iSpeaker Playback Switch",
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* build control elements
|
||||
*/
|
||||
|
@ -1486,6 +1523,23 @@ static int alc_build_controls(struct hda_codec *codec)
|
|||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* if we have no master control, let's create it */
|
||||
if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
|
||||
snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
|
||||
HDA_OUTPUT, spec->vmaster_tlv);
|
||||
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
|
||||
spec->vmaster_tlv, alc_slave_vols);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
|
||||
err = snd_hda_add_vmaster(codec, "Master Playback Switch",
|
||||
NULL, alc_slave_sws);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2034,8 +2088,8 @@ static struct hda_channel_mode alc880_lg_ch_modes[3] = {
|
|||
|
||||
static struct snd_kcontrol_new alc880_lg_mixer[] = {
|
||||
/* FIXME: it's not really "master" but front channels */
|
||||
HDA_CODEC_VOLUME("Master Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Master Playback Switch", 0x0f, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
|
||||
|
@ -3592,6 +3646,8 @@ static int patch_alc880(struct hda_codec *codec)
|
|||
}
|
||||
}
|
||||
|
||||
spec->vmaster_nid = 0x0c;
|
||||
|
||||
codec->patch_ops = alc_patch_ops;
|
||||
if (board_config == ALC880_AUTO)
|
||||
spec->init_hook = alc880_auto_init;
|
||||
|
@ -4969,6 +5025,8 @@ static int patch_alc260(struct hda_codec *codec)
|
|||
spec->stream_digital_playback = &alc260_pcm_digital_playback;
|
||||
spec->stream_digital_capture = &alc260_pcm_digital_capture;
|
||||
|
||||
spec->vmaster_nid = 0x08;
|
||||
|
||||
codec->patch_ops = alc_patch_ops;
|
||||
if (board_config == ALC260_AUTO)
|
||||
spec->init_hook = alc260_auto_init;
|
||||
|
@ -5169,15 +5227,15 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
|
|||
};
|
||||
|
||||
static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
|
||||
HDA_CODEC_VOLUME("Master Volume", 0x0c, 0x00, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE ("Master Switch", 0x0c, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE ("Speaker Switch", 0x14, 0x00, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Line Out Volume", 0x0d,0x00, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Line In Playback Volume", 0x0b, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE ("Line In Playback Switch", 0x0b, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
|
||||
HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
|
||||
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
|
||||
HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
|
||||
{ } /* end */
|
||||
};
|
||||
|
@ -6181,6 +6239,8 @@ static int patch_alc882(struct hda_codec *codec)
|
|||
}
|
||||
}
|
||||
|
||||
spec->vmaster_nid = 0x0c;
|
||||
|
||||
codec->patch_ops = alc_patch_ops;
|
||||
if (board_config == ALC882_AUTO)
|
||||
spec->init_hook = alc882_auto_init;
|
||||
|
@ -7763,6 +7823,8 @@ static int patch_alc883(struct hda_codec *codec)
|
|||
spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
|
||||
}
|
||||
|
||||
spec->vmaster_nid = 0x0c;
|
||||
|
||||
codec->patch_ops = alc_patch_ops;
|
||||
if (board_config == ALC883_AUTO)
|
||||
spec->init_hook = alc883_auto_init;
|
||||
|
@ -9123,6 +9185,8 @@ static int patch_alc262(struct hda_codec *codec)
|
|||
}
|
||||
}
|
||||
|
||||
spec->vmaster_nid = 0x0c;
|
||||
|
||||
codec->patch_ops = alc_patch_ops;
|
||||
if (board_config == ALC262_AUTO)
|
||||
spec->init_hook = alc262_auto_init;
|
||||
|
@ -9848,6 +9912,9 @@ static int patch_alc268(struct hda_codec *codec)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
spec->vmaster_nid = 0x02;
|
||||
|
||||
codec->patch_ops = alc_patch_ops;
|
||||
if (board_config == ALC268_AUTO)
|
||||
spec->init_hook = alc268_auto_init;
|
||||
|
@ -11358,6 +11425,8 @@ static int patch_alc861(struct hda_codec *codec)
|
|||
spec->stream_digital_playback = &alc861_pcm_digital_playback;
|
||||
spec->stream_digital_capture = &alc861_pcm_digital_capture;
|
||||
|
||||
spec->vmaster_nid = 0x03;
|
||||
|
||||
codec->patch_ops = alc_patch_ops;
|
||||
if (board_config == ALC861_AUTO)
|
||||
spec->init_hook = alc861_auto_init;
|
||||
|
@ -12334,6 +12403,8 @@ static int patch_alc861vd(struct hda_codec *codec)
|
|||
spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
|
||||
spec->num_mixers++;
|
||||
|
||||
spec->vmaster_nid = 0x02;
|
||||
|
||||
codec->patch_ops = alc_patch_ops;
|
||||
|
||||
if (board_config == ALC861VD_AUTO)
|
||||
|
@ -13305,6 +13376,8 @@ static int patch_alc662(struct hda_codec *codec)
|
|||
spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
|
||||
}
|
||||
|
||||
spec->vmaster_nid = 0x02;
|
||||
|
||||
codec->patch_ops = alc_patch_ops;
|
||||
if (board_config == ALC662_AUTO)
|
||||
spec->init_hook = alc662_auto_init;
|
||||
|
|
|
@ -170,6 +170,9 @@ struct sigmatel_spec {
|
|||
struct snd_kcontrol_new *kctl_alloc;
|
||||
struct hda_input_mux private_dimux;
|
||||
struct hda_input_mux private_imux;
|
||||
|
||||
/* virtual master */
|
||||
unsigned int vmaster_tlv[4];
|
||||
};
|
||||
|
||||
static hda_nid_t stac9200_adc_nids[1] = {
|
||||
|
@ -794,6 +797,34 @@ static struct snd_kcontrol_new stac_dmux_mixer = {
|
|||
.put = stac92xx_dmux_enum_put,
|
||||
};
|
||||
|
||||
static const char *slave_vols[] = {
|
||||
"Front Playback Volume",
|
||||
"Surround Playback Volume",
|
||||
"Center Playback Volume",
|
||||
"LFE Playback Volume",
|
||||
"Side Playback Volume",
|
||||
"Headphone Playback Volume",
|
||||
"Headphone Playback Volume",
|
||||
"Speaker Playback Volume",
|
||||
"External Speaker Playback Volume",
|
||||
"Speaker2 Playback Volume",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *slave_sws[] = {
|
||||
"Front Playback Switch",
|
||||
"Surround Playback Switch",
|
||||
"Center Playback Switch",
|
||||
"LFE Playback Switch",
|
||||
"Side Playback Switch",
|
||||
"Headphone Playback Switch",
|
||||
"Headphone Playback Switch",
|
||||
"Speaker Playback Switch",
|
||||
"External Speaker Playback Switch",
|
||||
"Speaker2 Playback Switch",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int stac92xx_build_controls(struct hda_codec *codec)
|
||||
{
|
||||
struct sigmatel_spec *spec = codec->spec;
|
||||
|
@ -827,6 +858,23 @@ static int stac92xx_build_controls(struct hda_codec *codec)
|
|||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* if we have no master control, let's create it */
|
||||
if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
|
||||
snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
|
||||
HDA_OUTPUT, spec->vmaster_tlv);
|
||||
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
|
||||
spec->vmaster_tlv, slave_vols);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
|
||||
err = snd_hda_add_vmaster(codec, "Master Playback Switch",
|
||||
NULL, slave_sws);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue