Skip to content

Commit

Permalink
[ALSA] Fix the analog loopback volumes of ALC codecs
Browse files Browse the repository at this point in the history
HDA Codec driver
Fix the analog loopback volumes of ALC codecs.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Takashi Iwai authored and Jaroslav Kysela committed Jun 22, 2005
1 parent ead9b7c commit 41e41f1
Showing 1 changed file with 97 additions and 25 deletions.
122 changes: 97 additions & 25 deletions sound/pci/hda/patch_realtek.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ struct alc_spec {

/* PCM information */
struct hda_pcm pcm_rec[2];

struct semaphore bind_mutex;
};

/* DAC/ADC assignment */
Expand Down Expand Up @@ -362,6 +364,73 @@ static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc
}


/*
* bound volume controls
*
* bind multiple volumes (# indices, from 0)
*/

#define AMP_VAL_IDX_SHIFT 19
#define AMP_VAL_IDX_MASK (0x0f<<19)

static int alc_bind_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
unsigned long pval;

down(&spec->bind_mutex);
pval = kcontrol->private_value;
kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
kcontrol->private_value = pval;
up(&spec->bind_mutex);
return 0;
}

static int alc_bind_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
unsigned long pval;

down(&spec->bind_mutex);
pval = kcontrol->private_value;
kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
kcontrol->private_value = pval;
up(&spec->bind_mutex);
return 0;
}

static int alc_bind_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
unsigned long pval;
int i, indices, change = 0;

down(&spec->bind_mutex);
pval = kcontrol->private_value;
indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT;
for (i = 0; i < indices; i++) {
kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | (i << AMP_VAL_IDX_SHIFT);
change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
}
kcontrol->private_value = pval;
up(&spec->bind_mutex);
return change;
}

#define ALC_BIND_VOL_MONO(xname, nid, channel, indices, direction) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
.info = alc_bind_vol_info, \
.get = alc_bind_vol_get, \
.put = alc_bind_vol_put, \
.private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) }

#define ALC_BIND_VOL(xname,nid,indices,dir) ALC_BIND_VOL_MONO(xname,nid,3,indices,dir)

/*
*/

Expand All @@ -370,12 +439,12 @@ static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc
* HP=0x19
*/
static snd_kcontrol_new_t alc880_base_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT),
HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
ALC_BIND_VOL("Surround Playback Volume", 0x0f, 2, HDA_OUTPUT),
HDA_CODEC_MUTE("Surround Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT),
ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x18, 1, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x18, 2, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
Expand All @@ -388,7 +457,7 @@ static snd_kcontrol_new_t alc880_base_mixer[] = {
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
ALC_BIND_VOL("Headphone Playback Volume", 0x0d, 2, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
/* We don't use NID 0x07 - see above */
HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
Expand Down Expand Up @@ -423,15 +492,15 @@ static snd_kcontrol_new_t alc880_base_mixer[] = {
* Line-In/Side=0x1a, Mic=0x18, F-Mic=0x1b, HP=0x19
*/
static snd_kcontrol_new_t alc880_five_stack_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT),
HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
ALC_BIND_VOL("Surround Playback Volume", 0x0f, 2, HDA_OUTPUT),
HDA_CODEC_MUTE("Surround Playback Switch", 0x17, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT),
ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
ALC_BIND_VOL("Side Playback Volume", 0x0d, 2, HDA_OUTPUT),
HDA_CODEC_MUTE("Side Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Expand All @@ -443,7 +512,7 @@ static snd_kcontrol_new_t alc880_five_stack_mixer[] = {
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
/* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), */
HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
/* We don't use NID 0x07 - see above */
HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
Expand Down Expand Up @@ -506,9 +575,9 @@ static snd_kcontrol_new_t alc880_w810_base_mixer[] = {
};

static snd_kcontrol_new_t alc880_z71v_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT),
HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
ALC_BIND_VOL("Headphone Playback Volume", 0x0d, 2, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Expand Down Expand Up @@ -1215,10 +1284,10 @@ static int alc_test_pin_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *
}

static snd_kcontrol_new_t alc880_test_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT),
ALC_BIND_VOL("Surround Playback Volume", 0x0d, 2, HDA_OUTPUT),
ALC_BIND_VOL("CLFE Playback Volume", 0x0e, 2, HDA_OUTPUT),
ALC_BIND_VOL("Side Playback Volume", 0x0f, 2, HDA_OUTPUT),
PIN_CTL_TEST("Front Pin Mode", 0x14),
PIN_CTL_TEST("Surround Pin Mode", 0x15),
PIN_CTL_TEST("CLFE Pin Mode", 0x16),
Expand Down Expand Up @@ -1402,6 +1471,7 @@ static int patch_alc880(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;

init_MUTEX(&spec->bind_mutex);
codec->spec = spec;

board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl);
Expand Down Expand Up @@ -1551,7 +1621,7 @@ static struct alc_channel_mode alc260_modes[1] = {
};

snd_kcontrol_new_t alc260_base_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
ALC_BIND_VOL("Front Playback Volume", 0x08, 2, HDA_OUTPUT),
/* use LINE2 for the output */
/* HDA_CODEC_MUTE("Front Playback Switch", 0x0f, 0x0, HDA_OUTPUT), */
HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Expand All @@ -1565,9 +1635,9 @@ snd_kcontrol_new_t alc260_base_mixer[] = {
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
ALC_BIND_VOL("Headphone Playback Volume", 0x09, 2, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
ALC_BIND_VOL_MONO("Mono Playback Volume", 0x0a, 1, 2, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
Expand Down Expand Up @@ -1660,6 +1730,7 @@ static int patch_alc260(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;

init_MUTEX(&spec->bind_mutex);
codec->spec = spec;

spec->mixers[spec->num_mixers] = alc260_base_mixer;
Expand Down Expand Up @@ -1757,15 +1828,15 @@ static int alc882_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u
* Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
*/
static snd_kcontrol_new_t alc882_base_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
ALC_BIND_VOL("Front Playback Volume", 0x0c, 2, HDA_OUTPUT),
HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
ALC_BIND_VOL("Surround Playback Volume", 0x0d, 2, HDA_OUTPUT),
HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
ALC_BIND_VOL_MONO("Center Playback Volume", 0x0e, 1, 2, HDA_OUTPUT),
ALC_BIND_VOL_MONO("LFE Playback Volume", 0x0e, 2, 2, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
ALC_BIND_VOL("Side Playback Volume", 0x0f, 2, HDA_OUTPUT),
HDA_CODEC_MUTE("Side Playback Switch", 0x17, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
Expand Down Expand Up @@ -1895,6 +1966,7 @@ static int patch_alc882(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;

init_MUTEX(&spec->bind_mutex);
codec->spec = spec;

spec->mixers[spec->num_mixers] = alc882_base_mixer;
Expand Down

0 comments on commit 41e41f1

Please sign in to comment.