Skip to contentSkip to conversation

aureon.c - adc mux, master vol

PATCH In review Christoph Haderer 3 participants 6 messages Jul 3, 2004 – Jul 16, 2004

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 aureon.c - adc mux, master vol

The attached patch fixes a problem in adc_mux_put (without these changes, wrong values a written to the right input mux);
it also reverts the changes of dac_vol_get and dac_vol_put which where introduced in revision 1.11, because in the current version changing the Master Volume control affects only DAC1 volume (IMHO WM_DAC_MASTER_ATTEN is the right location - not WM_DAC_ATTEN).

Regards,
Christoph Haderer

aureon.c renamed from aureon.c.old +11 -6
@@ -227,7 +227,10 @@
 	unsigned short vol;
 
 	down(&ice->gpio_mutex);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN;
+	if (kcontrol->private_value)
+		idx = WM_DAC_MASTER_ATTEN;
+	else
+		idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN;
 	vol = wm_get(ice, idx) & 0x7f;
 	if (vol <= 0x1a)
 		ucontrol->value.integer.value[0] = 0;
@@ -245,7 +248,10 @@
 	int change;
 
 	snd_ice1712_save_gpio_status(ice);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN;
+	if (kcontrol->private_value)
+		idx = WM_DAC_MASTER_ATTEN;
+	else
+		idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN;
 	nvol = ucontrol->value.integer.value[0] + 0x1a;
 	ovol = wm_get(ice, idx) & 0x7f;
 	change = (ovol != nvol);
@@ -374,8 +380,7 @@
 
 	down(&ice->gpio_mutex);
 	val = wm_get(ice, WM_ADC_MUX);
-	ucontrol->value.integer.value[0] = val & 7;
-	ucontrol->value.integer.value[1] = (val >> 4) & 7;
+	ucontrol->value.integer.value = val & 7;
 	up(&ice->gpio_mutex);
 	return 0;
 }
@@ -389,8 +394,8 @@
 	snd_ice1712_save_gpio_status(ice);
 	oval = wm_get(ice, WM_ADC_MUX);
 	nval = oval & ~0x77;
-	nval |= ucontrol->value.integer.value[0] & 7;
-	nval |= (ucontrol->value.integer.value[1] & 7) << 4;
+	nval |= ucontrol->value.integer.value & 7;
+	nval |= (ucontrol->value.integer.value & 7) << 4;
 	change = (oval != nval);
 	if (change)
 		wm_put(ice, WM_ADC_MUX, nval);
#1 lore raw

Hi Chirstoph,

At Sat, 03 Jul 2004 17:46:24 +0200,

Quoted 8 lines · Christoph Haderer

[1 <text/plain; us-ascii (7bit)>]
The attached patch fixes a problem in adc_mux_put (without these changes, wrong values a written to the right input mux);
it also reverts the changes of dac_vol_get and dac_vol_put which where introduced in revision 1.11, because in the current version changing the Master Volume control affects only DAC1 volume (IMHO WM_DAC_MASTER_ATTEN is the right location - not WM_DAC_ATTEN).

Thanks for the patch. Looks like I forgot to remove/change some things. It would be nice if you can test aureon boards with the latest changes.

The below is the completely rewritten patch. It includes

- Removal of 'Master Playback Volume', which is bogus (it forces to change all DAC volumes)

- Split 'DAC Volumes' to Front/Rear/Center/LFE/Side volumes. Please test whether the volume element really corresponds to the assigned output. Rear and Center/LFE might be swapped.
- Fix ADC capture mutx for stereo.

thanks,

Takashi

Index: alsa-kernel/pci/ice1712/aureon.c
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/pci/ice1712/aureon.c,v retrieving revision 1.15

pci/ice1712/aureon.c +110 -88
diff -u -r1.15 aureon.c
@@ -168,9 +168,8 @@
 }
 
 /*
- * DAC mute control
  */
-static int wm_dac_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+static int aureon_mono_bool_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	uinfo->count = 1;
@@ -179,6 +178,11 @@
 	return 0;
 }
 
+/*
+ * DAC mute control
+ */
+#define wm_dac_mute_info	aureon_mono_bool_info
+
 static int wm_dac_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
@@ -213,8 +217,9 @@
  */
 static int wm_dac_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
+	int voices = kcontrol->private_value >> 8;
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 1;
+	uinfo->count = voices;
 	uinfo->value.integer.min = 0;		/* mute */
 	uinfo->value.integer.max = 101;		/* 0dB */
 	return 0;
@@ -223,16 +228,20 @@
 static int wm_dac_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
+	int i, idx, ofs, voices;
 	unsigned short vol;
 
+	voices = kcontrol->private_value >> 8;
+	ofs = kcontrol->private_value & 0xff;
 	down(&ice->gpio_mutex);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN;
-	vol = wm_get(ice, idx) & 0x7f;
-	if (vol <= 0x1a)
-		ucontrol->value.integer.value[0] = 0;
-	else
-		ucontrol->value.integer.value[0] = vol - 0x1a;
+	for (i = 0; i < voices; i++) {
+		idx  = WM_DAC_ATTEN + ofs + i;
+		vol = wm_get(ice, idx) & 0x7f;
+		if (vol <= 0x1a)
+			ucontrol->value.integer.value[i] = 0;
+		else
+			ucontrol->value.integer.value[i] = vol - 0x1a;
+	}
 	up(&ice->gpio_mutex);
 	return 0;
 }
@@ -240,21 +249,23 @@
 static int wm_dac_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
+	int i, idx, ofs, voices;
 	unsigned short ovol, nvol;
-	int change;
+	int change = 0;
 
+	voices = kcontrol->private_value >> 8;
+	ofs = kcontrol->private_value & 0xff;
 	snd_ice1712_save_gpio_status(ice);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN;
-	nvol = ucontrol->value.integer.value[0] + 0x1a;
-	ovol = wm_get(ice, idx) & 0x7f;
-	change = (ovol != nvol);
-	if (change) {
-		if (nvol <= 0x1a && ovol <= 0x1a)
-			change = 0;
-		else {
+	for (i = 0; i < 2; i++) {
+		idx  = WM_DAC_ATTEN + ofs + i;
+		nvol = ucontrol->value.integer.value[i] + 0x1a;
+		ovol = wm_get(ice, idx) & 0x7f;
+		if (ovol != nvol) {
+			if (nvol <= 0x1a && ovol <= 0x1a)
+				continue;
 			wm_put(ice, idx, nvol | 0x80); /* zero-detect, prelatch */
 			wm_put_nocache(ice, idx, nvol | 0x180); /* update */
+			change = 1;
 		}
 	}
 	snd_ice1712_restore_gpio_status(ice);
@@ -264,14 +275,7 @@
 /*
  * ADC mute control
  */
-static int wm_adc_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
-{
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = 1;
-	return 0;
-}
+#define wm_adc_mute_info	aureon_mono_bool_info
 
 static int wm_adc_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
@@ -308,7 +312,7 @@
 static int wm_adc_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 1;
+	uinfo->count = 2;
 	uinfo->value.integer.min = 0;		/* -12dB */
 	uinfo->value.integer.max = 0x1f;	/* 19dB */
 	return 0;
@@ -317,13 +321,15 @@
 static int wm_adc_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
+	int i, idx;
 	unsigned short vol;
 
 	down(&ice->gpio_mutex);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN;
-	vol = wm_get(ice, idx) & 0x1f;
-	ucontrol->value.integer.value[0] = vol;
+	for (i = 0; i < 2; i++) {
+		idx = WM_ADC_GAIN + i;
+		vol = wm_get(ice, idx) & 0x1f;
+		ucontrol->value.integer.value[i] = vol;
+	}
 	up(&ice->gpio_mutex);
 	return 0;
 }
@@ -331,17 +337,20 @@
 static int wm_adc_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
+	int i, idx;
 	unsigned short ovol, nvol;
-	int change;
+	int change = 0;
 
 	snd_ice1712_save_gpio_status(ice);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN;
-	nvol = ucontrol->value.integer.value[0];
-	ovol = wm_get(ice, idx);
-	change = ((ovol & 0x1f)  != nvol);
-	if (change)
-		wm_put(ice, idx, nvol | (ovol & ~0x1f));
+	for (i = 0; i < 2; i++) {
+		idx  = WM_ADC_GAIN + i;
+		nvol = ucontrol->value.integer.value[i];
+		ovol = wm_get(ice, idx);
+		if ((ovol & 0x1f) != nvol) {
+			wm_put(ice, idx, nvol | (ovol & ~0x1f));
+			change = 1;
+		}
+	}
 	snd_ice1712_restore_gpio_status(ice);
 	return change;
 }
@@ -359,7 +368,7 @@
 		"AC97"		//AIN5
 	};
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
+	uinfo->count = 2;
 	uinfo->value.enumerated.items = 5;
 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
@@ -424,14 +433,7 @@
 	return ( tmp & AUREON_HP_SEL )!= 0;
 }
 
-static int aureon_bool_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo)
-{
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = 1;
-	return 0;
-}
+#define aureon_hpamp_info	aureon_mono_bool_info
 
 static int aureon_hpamp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
@@ -452,6 +454,9 @@
 /*
  * Deemphasis
  */
+
+#define aureon_deemp_info	aureon_mono_bool_info
+
 static int aureon_deemp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
@@ -523,44 +528,60 @@
  * mixers
  */
 
-static snd_kcontrol_new_t aureon51_dac_control __devinitdata = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "DAC Volume",
-	.count = 6,
-	.info = wm_dac_vol_info,
-	.get = wm_dac_vol_get,
-	.put = wm_dac_vol_put,
-};
-
-static snd_kcontrol_new_t aureon71_dac_control __devinitdata = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "DAC Volume",
-	.count = 8,
-	.info = wm_dac_vol_info,
-	.get = wm_dac_vol_get,
-	.put = wm_dac_vol_put,
-};
-
-static snd_kcontrol_new_t wm_controls[] __devinitdata = {
+static snd_kcontrol_new_t aureon_dac_controls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Switch",
-		.info = wm_dac_mute_info,
-		.get = wm_dac_mute_get,
-		.put = wm_dac_mute_put,
+		.name = "Front Playback Volume",
+		.info = wm_dac_vol_info,
+		.get = wm_dac_vol_get,
+		.put = wm_dac_vol_put,
+		.private_value = (2 << 8) | 0
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Rear Playback Volume",
+		.info = wm_dac_vol_info,
+		.get = wm_dac_vol_get,
+		.put = wm_dac_vol_put,
+		.private_value = (2 << 8) | 2
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Center Playback Volume",
+		.info = wm_dac_vol_info,
+		.get = wm_dac_vol_get,
+		.put = wm_dac_vol_put,
+		.private_value = (1 << 8) | 4
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Volume",
+		.name = "LFE Playback Volume",
 		.info = wm_dac_vol_info,
 		.get = wm_dac_vol_get,
 		.put = wm_dac_vol_put,
-		.private_value = 1,
+		.private_value = (1 << 8) | 5
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "ADC Switch",
-		.count = 2,
+		.name = "Side Playback Volume",
+		.info = wm_dac_vol_info,
+		.get = wm_dac_vol_get,
+		.put = wm_dac_vol_put,
+		.private_value = (2 << 8) | 6
+	}
+};
+
+static snd_kcontrol_new_t wm_controls[] __devinitdata = {
+ 	{
+ 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = wm_dac_mute_info,
+		.get = wm_dac_mute_get,
+		.put = wm_dac_mute_put,
+ 	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Switch",
 		.info = wm_adc_mute_info,
 		.get = wm_adc_mute_get,
 		.put = wm_adc_mute_put,
@@ -568,15 +589,14 @@
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "ADC Volume",
-		.count = 2,
+		.name = "Capture Volume",
 		.info = wm_adc_vol_info,
 		.get = wm_adc_vol_get,
 		.put = wm_adc_vol_put,
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Route",
+		.name = "Capture Source",
 		.info = wm_adc_mux_info,
 		.get = wm_adc_mux_get,
 		.put = wm_adc_mux_put,
@@ -584,14 +604,14 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Headphone Amplifier Switch",
-		.info = aureon_bool_info,
+		.info = aureon_hpamp_info,
 		.get = aureon_hpamp_get,
 		.put = aureon_hpamp_put
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "DAC Deemphasis Switch",
-		.info = aureon_bool_info,
+		.info = aureon_deemp_info,
 		.get = aureon_deemp_get,
 		.put = aureon_deemp_put
 	},
@@ -607,15 +627,17 @@
 
 static int __devinit aureon_add_controls(ice1712_t *ice)
 {
-	unsigned int i;
+	unsigned int i, counts;
 	int err;
 
+	counts = ARRAY_SIZE(aureon_dac_controls);
 	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon51_dac_control, ice));
-	else
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon71_dac_control, ice));
-	if (err < 0)
-		return err;
+		counts--; /* no side */
+	for (i = 0; i < counts; i++) {
+		err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice));
+		if (err < 0)
+			return err;
+	}
 
 	for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
 		err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
#2 lore raw

I think it would be convenient for the end user to keep the Master volume attenuation on Aureon & Prodigy. There are seperate analog and digital volume controls on the chip and since each DAC has it's analog volume control as a mixer element, why not have the master digital volume as another control?

Minor change one could say but imagine someone trying to adjust the volume of his 5.1 speaker system while playing a DVD.

Apostolos

Quoted 15 lines · Takashi Iwai

Thanks for the patch. Looks like I forgot to remove/change some things. It would be nice if you can test aureon boards with the latest changes.

The below is the completely rewritten patch. It includes

- Removal of 'Master Playback Volume', which is bogus (it forces to change all DAC volumes)

- Split 'DAC Volumes' to Front/Rear/Center/LFE/Side volumes. Please test whether the volume element really corresponds to the assigned output. Rear and Center/LFE might be swapped.
- Fix ADC capture mutx for stereo.

Quoted 5 lines

thanks,

Takashi

-------------------------------------------------------
This SF.Net email sponsored by Black Hat Briefings & Training.
Attend Black Hat Briefings & Training, Las Vegas July 24-29 - digital self defense, top technical experts, no vendor pitches, unmatched networking opportunities. Visit www.blackhat.com

#3 lore raw

Hi,

it seems that my last post didn't go out properly...

At Tue, 06 Jul 2004 21:05:44 -0400,

Quoted 7 lines · Apostolos Dimitromanolakis

I think it would be convenient for the end user to keep the Master volume attenuation on Aureon & Prodigy. There are seperate analog and digital volume controls on the chip and since each DAC has it's analog volume control as a mixer element, why not have the master digital volume as another control?

The master volume control on WM codec seems not to be a real 'master control'. It's no independent control but just modifies the all DAC volumes at once.

If we keep this, the DAC volumes must be updated and the changes must be notified. But then the question is how to handle master volume when only a DAC volume is changed?

BTW, the attached patch is to use more intuitive control names for volume and capture controls. The bogus master volume is removed. Could aureon/prodigy owners can test it?

It's to the latest CVS.

thanks,

Takashi

Index: alsa-kernel/pci/ice1712/aureon.c
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/pci/ice1712/aureon.c,v retrieving revision 1.15

pci/ice1712/aureon.c +125 -90
diff -u -r1.15 aureon.c
@@ -168,9 +168,8 @@
 }
 
 /*
- * DAC mute control
  */
-static int wm_dac_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+static int aureon_mono_bool_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	uinfo->count = 1;
@@ -179,6 +178,11 @@
 	return 0;
 }
 
+/*
+ * DAC mute control
+ */
+#define wm_dac_mute_info	aureon_mono_bool_info
+
 static int wm_dac_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
@@ -213,8 +217,9 @@
  */
 static int wm_dac_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
+	int voices = kcontrol->private_value >> 8;
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 1;
+	uinfo->count = voices;
 	uinfo->value.integer.min = 0;		/* mute */
 	uinfo->value.integer.max = 101;		/* 0dB */
 	return 0;
@@ -223,16 +228,20 @@
 static int wm_dac_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
+	int i, idx, ofs, voices;
 	unsigned short vol;
 
+	voices = kcontrol->private_value >> 8;
+	ofs = kcontrol->private_value & 0xff;
 	down(&ice->gpio_mutex);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN;
-	vol = wm_get(ice, idx) & 0x7f;
-	if (vol <= 0x1a)
-		ucontrol->value.integer.value[0] = 0;
-	else
-		ucontrol->value.integer.value[0] = vol - 0x1a;
+	for (i = 0; i < voices; i++) {
+		idx  = WM_DAC_ATTEN + ofs + i;
+		vol = wm_get(ice, idx) & 0x7f;
+		if (vol <= 0x1a)
+			ucontrol->value.integer.value[i] = 0;
+		else
+			ucontrol->value.integer.value[i] = vol - 0x1a;
+	}
 	up(&ice->gpio_mutex);
 	return 0;
 }
@@ -240,21 +249,23 @@
 static int wm_dac_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
+	int i, idx, ofs, voices;
 	unsigned short ovol, nvol;
-	int change;
+	int change = 0;
 
+	voices = kcontrol->private_value >> 8;
+	ofs = kcontrol->private_value & 0xff;
 	snd_ice1712_save_gpio_status(ice);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN;
-	nvol = ucontrol->value.integer.value[0] + 0x1a;
-	ovol = wm_get(ice, idx) & 0x7f;
-	change = (ovol != nvol);
-	if (change) {
-		if (nvol <= 0x1a && ovol <= 0x1a)
-			change = 0;
-		else {
+	for (i = 0; i < 2; i++) {
+		idx  = WM_DAC_ATTEN + ofs + i;
+		nvol = ucontrol->value.integer.value[i] + 0x1a;
+		ovol = wm_get(ice, idx) & 0x7f;
+		if (ovol != nvol) {
+			if (nvol <= 0x1a && ovol <= 0x1a)
+				continue;
 			wm_put(ice, idx, nvol | 0x80); /* zero-detect, prelatch */
 			wm_put_nocache(ice, idx, nvol | 0x180); /* update */
+			change = 1;
 		}
 	}
 	snd_ice1712_restore_gpio_status(ice);
@@ -264,10 +275,10 @@
 /*
  * ADC mute control
  */
-static int wm_adc_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+static int wm_adc_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-	uinfo->count = 1;
+	uinfo->count = 2;
 	uinfo->value.integer.min = 0;
 	uinfo->value.integer.max = 1;
 	return 0;
@@ -277,10 +288,13 @@
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
+	int i;
 
 	down(&ice->gpio_mutex);
-	val = wm_get(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_ADC_GAIN);
-	ucontrol->value.integer.value[0] = ~val>>5 & 0x1;
+	for (i = 0; i < 2; i++) {
+		val = wm_get(ice, WM_ADC_GAIN + i);
+		ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
+	}
 	up(&ice->gpio_mutex);
 	return 0;
 }
@@ -289,14 +303,17 @@
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short new, old;
-	int change;
+	int i, change = 0;
 
 	snd_ice1712_save_gpio_status(ice);
-	old = wm_get(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_ADC_GAIN);
-	new = (~ucontrol->value.integer.value[0]<<5&0x20) | (old&~0x20);
-	change = (new != old);
-	if (change)
-		wm_put(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_ADC_GAIN, new);
+	for (i = 0; i < 2; i++) {
+		old = wm_get(ice, WM_ADC_GAIN + i);
+		new = (~ucontrol->value.integer.value[i]<<5&0x20) | (old&~0x20);
+		if (new != old) {
+			wm_put(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_ADC_GAIN, new);
+			change = 1;
+		}
+	}
 	snd_ice1712_restore_gpio_status(ice);
 
 	return change;
@@ -308,7 +325,7 @@
 static int wm_adc_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 1;
+	uinfo->count = 2;
 	uinfo->value.integer.min = 0;		/* -12dB */
 	uinfo->value.integer.max = 0x1f;	/* 19dB */
 	return 0;
@@ -317,13 +334,15 @@
 static int wm_adc_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
+	int i, idx;
 	unsigned short vol;
 
 	down(&ice->gpio_mutex);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN;
-	vol = wm_get(ice, idx) & 0x1f;
-	ucontrol->value.integer.value[0] = vol;
+	for (i = 0; i < 2; i++) {
+		idx = WM_ADC_GAIN + i;
+		vol = wm_get(ice, idx) & 0x1f;
+		ucontrol->value.integer.value[i] = vol;
+	}
 	up(&ice->gpio_mutex);
 	return 0;
 }
@@ -331,17 +350,20 @@
 static int wm_adc_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
+	int i, idx;
 	unsigned short ovol, nvol;
-	int change;
+	int change = 0;
 
 	snd_ice1712_save_gpio_status(ice);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN;
-	nvol = ucontrol->value.integer.value[0];
-	ovol = wm_get(ice, idx);
-	change = ((ovol & 0x1f)  != nvol);
-	if (change)
-		wm_put(ice, idx, nvol | (ovol & ~0x1f));
+	for (i = 0; i < 2; i++) {
+		idx  = WM_ADC_GAIN + i;
+		nvol = ucontrol->value.integer.value[i];
+		ovol = wm_get(ice, idx);
+		if ((ovol & 0x1f) != nvol) {
+			wm_put(ice, idx, nvol | (ovol & ~0x1f));
+			change = 1;
+		}
+	}
 	snd_ice1712_restore_gpio_status(ice);
 	return change;
 }
@@ -359,7 +381,7 @@
 		"AC97"		//AIN5
 	};
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
+	uinfo->count = 2;
 	uinfo->value.enumerated.items = 5;
 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
@@ -424,14 +446,7 @@
 	return ( tmp & AUREON_HP_SEL )!= 0;
 }
 
-static int aureon_bool_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo)
-{
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = 1;
-	return 0;
-}
+#define aureon_hpamp_info	aureon_mono_bool_info
 
 static int aureon_hpamp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
@@ -452,6 +467,9 @@
 /*
  * Deemphasis
  */
+
+#define aureon_deemp_info	aureon_mono_bool_info
+
 static int aureon_deemp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
@@ -523,44 +541,60 @@
  * mixers
  */
 
-static snd_kcontrol_new_t aureon51_dac_control __devinitdata = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "DAC Volume",
-	.count = 6,
-	.info = wm_dac_vol_info,
-	.get = wm_dac_vol_get,
-	.put = wm_dac_vol_put,
-};
-
-static snd_kcontrol_new_t aureon71_dac_control __devinitdata = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "DAC Volume",
-	.count = 8,
-	.info = wm_dac_vol_info,
-	.get = wm_dac_vol_get,
-	.put = wm_dac_vol_put,
-};
-
-static snd_kcontrol_new_t wm_controls[] __devinitdata = {
+static snd_kcontrol_new_t aureon_dac_controls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Switch",
-		.info = wm_dac_mute_info,
-		.get = wm_dac_mute_get,
-		.put = wm_dac_mute_put,
+		.name = "Front Playback Volume",
+		.info = wm_dac_vol_info,
+		.get = wm_dac_vol_get,
+		.put = wm_dac_vol_put,
+		.private_value = (2 << 8) | 0
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Rear Playback Volume",
+		.info = wm_dac_vol_info,
+		.get = wm_dac_vol_get,
+		.put = wm_dac_vol_put,
+		.private_value = (2 << 8) | 2
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Center Playback Volume",
+		.info = wm_dac_vol_info,
+		.get = wm_dac_vol_get,
+		.put = wm_dac_vol_put,
+		.private_value = (1 << 8) | 4
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Volume",
+		.name = "LFE Playback Volume",
 		.info = wm_dac_vol_info,
 		.get = wm_dac_vol_get,
 		.put = wm_dac_vol_put,
-		.private_value = 1,
+		.private_value = (1 << 8) | 5
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "ADC Switch",
-		.count = 2,
+		.name = "Side Playback Volume",
+		.info = wm_dac_vol_info,
+		.get = wm_dac_vol_get,
+		.put = wm_dac_vol_put,
+		.private_value = (2 << 8) | 6
+	}
+};
+
+static snd_kcontrol_new_t wm_controls[] __devinitdata = {
+ 	{
+ 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = wm_dac_mute_info,
+		.get = wm_dac_mute_get,
+		.put = wm_dac_mute_put,
+ 	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Switch",
 		.info = wm_adc_mute_info,
 		.get = wm_adc_mute_get,
 		.put = wm_adc_mute_put,
@@ -568,15 +602,14 @@
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "ADC Volume",
-		.count = 2,
+		.name = "Capture Volume",
 		.info = wm_adc_vol_info,
 		.get = wm_adc_vol_get,
 		.put = wm_adc_vol_put,
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Route",
+		.name = "Capture Source",
 		.info = wm_adc_mux_info,
 		.get = wm_adc_mux_get,
 		.put = wm_adc_mux_put,
@@ -584,14 +617,14 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Headphone Amplifier Switch",
-		.info = aureon_bool_info,
+		.info = aureon_hpamp_info,
 		.get = aureon_hpamp_get,
 		.put = aureon_hpamp_put
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "DAC Deemphasis Switch",
-		.info = aureon_bool_info,
+		.info = aureon_deemp_info,
 		.get = aureon_deemp_get,
 		.put = aureon_deemp_put
 	},
@@ -607,15 +640,17 @@
 
 static int __devinit aureon_add_controls(ice1712_t *ice)
 {
-	unsigned int i;
+	unsigned int i, counts;
 	int err;
 
+	counts = ARRAY_SIZE(aureon_dac_controls);
 	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon51_dac_control, ice));
-	else
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon71_dac_control, ice));
-	if (err < 0)
-		return err;
+		counts--; /* no side */
+	for (i = 0; i < counts; i++) {
+		err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice));
+		if (err < 0)
+			return err;
+	}
 
 	for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
 		err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
#4 lore raw

Yeah you are right about the master volume as it is implemented but I think there are seperate analog & digital volume control so it could be possible to use analog for the master and the digital for the DAC channels.

I will be away from my computer so I can't test the patch right now but I will have a look at the driver again soon.

Apostolos

Quoted 29 lines · Takashi Iwai

Hi,

it seems that my last post didn't go out properly...

At Tue, 06 Jul 2004 21:05:44 -0400,

Quoted 7 lines · Apostolos Dimitromanolakis

I think it would be convenient for the end user to keep the Master volume attenuation on Aureon & Prodigy. There are seperate analog and digital volume controls on the chip and since each DAC has it's analog volume control as a mixer element, why not have the master digital volume as another control?

The master volume control on WM codec seems not to be a real 'master control'. It's no independent control but just modifies the all DAC volumes at once.

If we keep this, the DAC volumes must be updated and the changes must be notified. But then the question is how to handle master volume when only a DAC volume is changed?

BTW, the attached patch is to use more intuitive control names for volume and capture controls. The bogus master volume is removed. Could aureon/prodigy owners can test it?

Quoted 8 lines

It's to the latest CVS.

thanks,

Takashi

-------------------------------------------------------
This SF.Net email is sponsored by BEA Weblogic Workshop FREE Java Enterprise J2EE developer tools!
Get your free copy of BEA WebLogic Workshop 8.1 today.
http://ads.osdn.com/?ad_id=4721&alloc_id=10040&op=click

#5 lore raw

At Thu, 15 Jul 2004 13:40:49 -0400,

Quoted 5 lines · Apostolos Dimitromanolakis

Yeah you are right about the master volume as it is implemented but I think there are seperate analog & digital volume control so it could be possible to use analog for the master and the digital for the DAC channels.

Oh, that's a good point.

The attached is a new patch including the master digital volume. Please let me know if it works.

Takashi

Index: alsa-kernel/pci/ice1712/aureon.c
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/pci/ice1712/aureon.c,v retrieving revision 1.15

pci/ice1712/aureon.c +174 -92
diff -u -r1.15 aureon.c
@@ -75,7 +75,7 @@
 #define WM_DAC_ATTEN		0x00	/* DAC1-8 analog attenuation */
 #define WM_DAC_MASTER_ATTEN	0x08	/* DAC master analog attenuation */
 #define WM_DAC_DIG_ATTEN	0x09	/* DAC1-8 digital attenuation */
-#define WM_DAC_DIG_MATER_ATTEN	0x11	/* DAC master digital attenuation */
+#define WM_DAC_DIG_MASTER_ATTEN	0x11	/* DAC master digital attenuation */
 #define WM_PHASE_SWAP		0x12	/* DAC phase */
 #define WM_DAC_CTRL1		0x13	/* DAC control bits */
 #define WM_MUTE			0x14	/* mute controls */
@@ -168,9 +168,8 @@
 }
 
 /*
- * DAC mute control
  */
-static int wm_dac_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+static int aureon_mono_bool_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	uinfo->count = 1;
@@ -179,6 +178,11 @@
 	return 0;
 }
 
+/*
+ * DAC mute control
+ */
+#define wm_dac_mute_info	aureon_mono_bool_info
+
 static int wm_dac_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
@@ -213,9 +217,10 @@
  */
 static int wm_dac_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
+	int voices = kcontrol->private_value >> 8;
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;		/* mute */
+	uinfo->count = voices;
+	uinfo->value.integer.min = 0;		/* mute (-101dB) */
 	uinfo->value.integer.max = 101;		/* 0dB */
 	return 0;
 }
@@ -223,16 +228,20 @@
 static int wm_dac_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
+	int i, idx, ofs, voices;
 	unsigned short vol;
 
+	voices = kcontrol->private_value >> 8;
+	ofs = kcontrol->private_value & 0xff;
 	down(&ice->gpio_mutex);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN;
-	vol = wm_get(ice, idx) & 0x7f;
-	if (vol <= 0x1a)
-		ucontrol->value.integer.value[0] = 0;
-	else
-		ucontrol->value.integer.value[0] = vol - 0x1a;
+	for (i = 0; i < voices; i++) {
+		idx  = WM_DAC_ATTEN + ofs + i;
+		vol = wm_get(ice, idx) & 0x7f;
+		if (vol <= 0x1a)
+			ucontrol->value.integer.value[i] = 0;
+		else
+			ucontrol->value.integer.value[i] = vol - 0x1a;
+	}
 	up(&ice->gpio_mutex);
 	return 0;
 }
@@ -240,34 +249,76 @@
 static int wm_dac_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
+	int i, idx, ofs, voices;
 	unsigned short ovol, nvol;
-	int change;
+	int change = 0;
 
+	voices = kcontrol->private_value >> 8;
+	ofs = kcontrol->private_value & 0xff;
 	snd_ice1712_save_gpio_status(ice);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN;
-	nvol = ucontrol->value.integer.value[0] + 0x1a;
-	ovol = wm_get(ice, idx) & 0x7f;
-	change = (ovol != nvol);
-	if (change) {
-		if (nvol <= 0x1a && ovol <= 0x1a)
-			change = 0;
-		else {
+	for (i = 0; i < 2; i++) {
+		idx  = WM_DAC_ATTEN + ofs + i;
+		nvol = ucontrol->value.integer.value[i] + 0x1a;
+		ovol = wm_get(ice, idx) & 0x7f;
+		if (ovol != nvol) {
+			if (nvol <= 0x1a && ovol <= 0x1a)
+				continue;
 			wm_put(ice, idx, nvol | 0x80); /* zero-detect, prelatch */
 			wm_put_nocache(ice, idx, nvol | 0x180); /* update */
+			change = 1;
 		}
 	}
 	snd_ice1712_restore_gpio_status(ice);
 	return change;
 }
 
+/* digital master volume */
+static int wm_master_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;		/* mute (-127.5dB) */
+	uinfo->value.integer.max = 0xff;	/* 0dB */
+	return 0;
+}
+
+static int wm_master_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned short vol;
+
+	down(&ice->gpio_mutex);
+	vol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
+	ucontrol->value.integer.value[0] = 0xff - vol;
+	up(&ice->gpio_mutex);
+	return 0;
+}
+
+static int wm_master_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned short ovol, nvol;
+	int change = 0;
+
+	snd_ice1712_save_gpio_status(ice);
+	nvol = 0xff - ucontrol->value.integer.value[0];
+	ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
+	if (ovol != nvol) {
+		wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
+		wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
+		change = 1;
+	}
+	snd_ice1712_restore_gpio_status(ice);
+	return change;
+}
+
 /*
  * ADC mute control
  */
-static int wm_adc_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+static int wm_adc_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-	uinfo->count = 1;
+	uinfo->count = 2;
 	uinfo->value.integer.min = 0;
 	uinfo->value.integer.max = 1;
 	return 0;
@@ -277,10 +328,13 @@
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
+	int i;
 
 	down(&ice->gpio_mutex);
-	val = wm_get(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_ADC_GAIN);
-	ucontrol->value.integer.value[0] = ~val>>5 & 0x1;
+	for (i = 0; i < 2; i++) {
+		val = wm_get(ice, WM_ADC_GAIN + i);
+		ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
+	}
 	up(&ice->gpio_mutex);
 	return 0;
 }
@@ -289,14 +343,17 @@
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short new, old;
-	int change;
+	int i, change = 0;
 
 	snd_ice1712_save_gpio_status(ice);
-	old = wm_get(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_ADC_GAIN);
-	new = (~ucontrol->value.integer.value[0]<<5&0x20) | (old&~0x20);
-	change = (new != old);
-	if (change)
-		wm_put(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_ADC_GAIN, new);
+	for (i = 0; i < 2; i++) {
+		old = wm_get(ice, WM_ADC_GAIN + i);
+		new = (~ucontrol->value.integer.value[i]<<5&0x20) | (old&~0x20);
+		if (new != old) {
+			wm_put(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_ADC_GAIN, new);
+			change = 1;
+		}
+	}
 	snd_ice1712_restore_gpio_status(ice);
 
 	return change;
@@ -308,7 +365,7 @@
 static int wm_adc_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	uinfo->count = 1;
+	uinfo->count = 2;
 	uinfo->value.integer.min = 0;		/* -12dB */
 	uinfo->value.integer.max = 0x1f;	/* 19dB */
 	return 0;
@@ -317,13 +374,15 @@
 static int wm_adc_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
+	int i, idx;
 	unsigned short vol;
 
 	down(&ice->gpio_mutex);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN;
-	vol = wm_get(ice, idx) & 0x1f;
-	ucontrol->value.integer.value[0] = vol;
+	for (i = 0; i < 2; i++) {
+		idx = WM_ADC_GAIN + i;
+		vol = wm_get(ice, idx) & 0x1f;
+		ucontrol->value.integer.value[i] = vol;
+	}
 	up(&ice->gpio_mutex);
 	return 0;
 }
@@ -331,17 +390,20 @@
 static int wm_adc_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int idx;
+	int i, idx;
 	unsigned short ovol, nvol;
-	int change;
+	int change = 0;
 
 	snd_ice1712_save_gpio_status(ice);
-	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN;
-	nvol = ucontrol->value.integer.value[0];
-	ovol = wm_get(ice, idx);
-	change = ((ovol & 0x1f)  != nvol);
-	if (change)
-		wm_put(ice, idx, nvol | (ovol & ~0x1f));
+	for (i = 0; i < 2; i++) {
+		idx  = WM_ADC_GAIN + i;
+		nvol = ucontrol->value.integer.value[i];
+		ovol = wm_get(ice, idx);
+		if ((ovol & 0x1f) != nvol) {
+			wm_put(ice, idx, nvol | (ovol & ~0x1f));
+			change = 1;
+		}
+	}
 	snd_ice1712_restore_gpio_status(ice);
 	return change;
 }
@@ -359,7 +421,7 @@
 		"AC97"		//AIN5
 	};
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
+	uinfo->count = 2;
 	uinfo->value.enumerated.items = 5;
 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
@@ -424,14 +486,7 @@
 	return ( tmp & AUREON_HP_SEL )!= 0;
 }
 
-static int aureon_bool_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo)
-{
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = 1;
-	return 0;
-}
+#define aureon_hpamp_info	aureon_mono_bool_info
 
 static int aureon_hpamp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
@@ -452,6 +507,9 @@
 /*
  * Deemphasis
  */
+
+#define aureon_deemp_info	aureon_mono_bool_info
+
 static int aureon_deemp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
@@ -523,44 +581,67 @@
  * mixers
  */
 
-static snd_kcontrol_new_t aureon51_dac_control __devinitdata = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "DAC Volume",
-	.count = 6,
-	.info = wm_dac_vol_info,
-	.get = wm_dac_vol_get,
-	.put = wm_dac_vol_put,
-};
-
-static snd_kcontrol_new_t aureon71_dac_control __devinitdata = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "DAC Volume",
-	.count = 8,
-	.info = wm_dac_vol_info,
-	.get = wm_dac_vol_get,
-	.put = wm_dac_vol_put,
-};
-
-static snd_kcontrol_new_t wm_controls[] __devinitdata = {
+static snd_kcontrol_new_t aureon_dac_controls[] __devinitdata = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Switch",
-		.info = wm_dac_mute_info,
-		.get = wm_dac_mute_get,
-		.put = wm_dac_mute_put,
+		.name = "Front Playback Volume",
+		.info = wm_dac_vol_info,
+		.get = wm_dac_vol_get,
+		.put = wm_dac_vol_put,
+		.private_value = (2 << 8) | 0
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Volume",
+		.name = "Rear Playback Volume",
+		.info = wm_dac_vol_info,
+		.get = wm_dac_vol_get,
+		.put = wm_dac_vol_put,
+		.private_value = (2 << 8) | 2
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Center Playback Volume",
 		.info = wm_dac_vol_info,
 		.get = wm_dac_vol_get,
 		.put = wm_dac_vol_put,
-		.private_value = 1,
+		.private_value = (1 << 8) | 4
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "ADC Switch",
-		.count = 2,
+		.name = "LFE Playback Volume",
+		.info = wm_dac_vol_info,
+		.get = wm_dac_vol_get,
+		.put = wm_dac_vol_put,
+		.private_value = (1 << 8) | 5
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Side Playback Volume",
+		.info = wm_dac_vol_info,
+		.get = wm_dac_vol_get,
+		.put = wm_dac_vol_put,
+		.private_value = (2 << 8) | 6
+	}
+};
+
+static snd_kcontrol_new_t wm_controls[] __devinitdata = {
+ 	{
+ 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = wm_dac_mute_info,
+		.get = wm_dac_mute_get,
+		.put = wm_dac_mute_put,
+ 	},
+ 	{
+ 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Volume",
+		.info = wm_master_vol_info,
+		.get = wm_master_vol_get,
+		.put = wm_master_vol_put,
+ 	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Switch",
 		.info = wm_adc_mute_info,
 		.get = wm_adc_mute_get,
 		.put = wm_adc_mute_put,
@@ -568,15 +649,14 @@
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "ADC Volume",
-		.count = 2,
+		.name = "Capture Volume",
 		.info = wm_adc_vol_info,
 		.get = wm_adc_vol_get,
 		.put = wm_adc_vol_put,
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Route",
+		.name = "Capture Source",
 		.info = wm_adc_mux_info,
 		.get = wm_adc_mux_get,
 		.put = wm_adc_mux_put,
@@ -584,14 +664,14 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Headphone Amplifier Switch",
-		.info = aureon_bool_info,
+		.info = aureon_hpamp_info,
 		.get = aureon_hpamp_get,
 		.put = aureon_hpamp_put
 	},
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "DAC Deemphasis Switch",
-		.info = aureon_bool_info,
+		.info = aureon_deemp_info,
 		.get = aureon_deemp_get,
 		.put = aureon_deemp_put
 	},
@@ -607,15 +687,17 @@
 
 static int __devinit aureon_add_controls(ice1712_t *ice)
 {
-	unsigned int i;
+	unsigned int i, counts;
 	int err;
 
+	counts = ARRAY_SIZE(aureon_dac_controls);
 	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY)
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon51_dac_control, ice));
-	else
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon71_dac_control, ice));
-	if (err < 0)
-		return err;
+		counts--; /* no side */
+	for (i = 0; i < counts; i++) {
+		err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice));
+		if (err < 0)
+			return err;
+	}
 
 	for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
 		err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));