xref: /openbmc/linux/sound/pci/ca0106/ca0106_mixer.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  *  Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
3*1da177e4SLinus Torvalds  *  Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
4*1da177e4SLinus Torvalds  *  Version: 0.0.16
5*1da177e4SLinus Torvalds  *
6*1da177e4SLinus Torvalds  *  FEATURES currently supported:
7*1da177e4SLinus Torvalds  *    See ca0106_main.c for features.
8*1da177e4SLinus Torvalds  *
9*1da177e4SLinus Torvalds  *  Changelog:
10*1da177e4SLinus Torvalds  *    Support interrupts per period.
11*1da177e4SLinus Torvalds  *    Removed noise from Center/LFE channel when in Analog mode.
12*1da177e4SLinus Torvalds  *    Rename and remove mixer controls.
13*1da177e4SLinus Torvalds  *  0.0.6
14*1da177e4SLinus Torvalds  *    Use separate card based DMA buffer for periods table list.
15*1da177e4SLinus Torvalds  *  0.0.7
16*1da177e4SLinus Torvalds  *    Change remove and rename ctrls into lists.
17*1da177e4SLinus Torvalds  *  0.0.8
18*1da177e4SLinus Torvalds  *    Try to fix capture sources.
19*1da177e4SLinus Torvalds  *  0.0.9
20*1da177e4SLinus Torvalds  *    Fix AC3 output.
21*1da177e4SLinus Torvalds  *    Enable S32_LE format support.
22*1da177e4SLinus Torvalds  *  0.0.10
23*1da177e4SLinus Torvalds  *    Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".)
24*1da177e4SLinus Torvalds  *  0.0.11
25*1da177e4SLinus Torvalds  *    Add Model name recognition.
26*1da177e4SLinus Torvalds  *  0.0.12
27*1da177e4SLinus Torvalds  *    Correct interrupt timing. interrupt at end of period, instead of in the middle of a playback period.
28*1da177e4SLinus Torvalds  *    Remove redundent "voice" handling.
29*1da177e4SLinus Torvalds  *  0.0.13
30*1da177e4SLinus Torvalds  *    Single trigger call for multi channels.
31*1da177e4SLinus Torvalds  *  0.0.14
32*1da177e4SLinus Torvalds  *    Set limits based on what the sound card hardware can do.
33*1da177e4SLinus Torvalds  *    playback periods_min=2, periods_max=8
34*1da177e4SLinus Torvalds  *    capture hw constraints require period_size = n * 64 bytes.
35*1da177e4SLinus Torvalds  *    playback hw constraints require period_size = n * 64 bytes.
36*1da177e4SLinus Torvalds  *  0.0.15
37*1da177e4SLinus Torvalds  *    Separated ca0106.c into separate functional .c files.
38*1da177e4SLinus Torvalds  *  0.0.16
39*1da177e4SLinus Torvalds  *    Modified Copyright message.
40*1da177e4SLinus Torvalds  *
41*1da177e4SLinus Torvalds  *  This code was initally based on code from ALSA's emu10k1x.c which is:
42*1da177e4SLinus Torvalds  *  Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
43*1da177e4SLinus Torvalds  *
44*1da177e4SLinus Torvalds  *   This program is free software; you can redistribute it and/or modify
45*1da177e4SLinus Torvalds  *   it under the terms of the GNU General Public License as published by
46*1da177e4SLinus Torvalds  *   the Free Software Foundation; either version 2 of the License, or
47*1da177e4SLinus Torvalds  *   (at your option) any later version.
48*1da177e4SLinus Torvalds  *
49*1da177e4SLinus Torvalds  *   This program is distributed in the hope that it will be useful,
50*1da177e4SLinus Torvalds  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
51*1da177e4SLinus Torvalds  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
52*1da177e4SLinus Torvalds  *   GNU General Public License for more details.
53*1da177e4SLinus Torvalds  *
54*1da177e4SLinus Torvalds  *   You should have received a copy of the GNU General Public License
55*1da177e4SLinus Torvalds  *   along with this program; if not, write to the Free Software
56*1da177e4SLinus Torvalds  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
57*1da177e4SLinus Torvalds  *
58*1da177e4SLinus Torvalds  */
59*1da177e4SLinus Torvalds #include <sound/driver.h>
60*1da177e4SLinus Torvalds #include <linux/delay.h>
61*1da177e4SLinus Torvalds #include <linux/init.h>
62*1da177e4SLinus Torvalds #include <linux/interrupt.h>
63*1da177e4SLinus Torvalds #include <linux/pci.h>
64*1da177e4SLinus Torvalds #include <linux/slab.h>
65*1da177e4SLinus Torvalds #include <linux/moduleparam.h>
66*1da177e4SLinus Torvalds #include <sound/core.h>
67*1da177e4SLinus Torvalds #include <sound/initval.h>
68*1da177e4SLinus Torvalds #include <sound/pcm.h>
69*1da177e4SLinus Torvalds #include <sound/ac97_codec.h>
70*1da177e4SLinus Torvalds #include <sound/info.h>
71*1da177e4SLinus Torvalds 
72*1da177e4SLinus Torvalds #include "ca0106.h"
73*1da177e4SLinus Torvalds 
74*1da177e4SLinus Torvalds static int snd_ca0106_shared_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
75*1da177e4SLinus Torvalds {
76*1da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
77*1da177e4SLinus Torvalds 	uinfo->count = 1;
78*1da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
79*1da177e4SLinus Torvalds 	uinfo->value.integer.max = 1;
80*1da177e4SLinus Torvalds 	return 0;
81*1da177e4SLinus Torvalds }
82*1da177e4SLinus Torvalds 
83*1da177e4SLinus Torvalds static int snd_ca0106_shared_spdif_get(snd_kcontrol_t * kcontrol,
84*1da177e4SLinus Torvalds 					snd_ctl_elem_value_t * ucontrol)
85*1da177e4SLinus Torvalds {
86*1da177e4SLinus Torvalds 	ca0106_t *emu = snd_kcontrol_chip(kcontrol);
87*1da177e4SLinus Torvalds 
88*1da177e4SLinus Torvalds 	ucontrol->value.enumerated.item[0] = emu->spdif_enable;
89*1da177e4SLinus Torvalds 	return 0;
90*1da177e4SLinus Torvalds }
91*1da177e4SLinus Torvalds 
92*1da177e4SLinus Torvalds static int snd_ca0106_shared_spdif_put(snd_kcontrol_t * kcontrol,
93*1da177e4SLinus Torvalds 					snd_ctl_elem_value_t * ucontrol)
94*1da177e4SLinus Torvalds {
95*1da177e4SLinus Torvalds 	ca0106_t *emu = snd_kcontrol_chip(kcontrol);
96*1da177e4SLinus Torvalds 	unsigned int val;
97*1da177e4SLinus Torvalds 	int change = 0;
98*1da177e4SLinus Torvalds 	u32 mask;
99*1da177e4SLinus Torvalds 
100*1da177e4SLinus Torvalds 	val = ucontrol->value.enumerated.item[0] ;
101*1da177e4SLinus Torvalds 	change = (emu->spdif_enable != val);
102*1da177e4SLinus Torvalds 	if (change) {
103*1da177e4SLinus Torvalds 		emu->spdif_enable = val;
104*1da177e4SLinus Torvalds 		if (val == 1) {
105*1da177e4SLinus Torvalds 			/* Digital */
106*1da177e4SLinus Torvalds 			snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
107*1da177e4SLinus Torvalds 			snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000);
108*1da177e4SLinus Torvalds 			snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0,
109*1da177e4SLinus Torvalds 				snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000);
110*1da177e4SLinus Torvalds 			mask = inl(emu->port + GPIO) & ~0x101;
111*1da177e4SLinus Torvalds 			outl(mask, emu->port + GPIO);
112*1da177e4SLinus Torvalds 
113*1da177e4SLinus Torvalds 		} else {
114*1da177e4SLinus Torvalds 			/* Analog */
115*1da177e4SLinus Torvalds 			snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
116*1da177e4SLinus Torvalds 			snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000b0000);
117*1da177e4SLinus Torvalds 			snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0,
118*1da177e4SLinus Torvalds 				snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000);
119*1da177e4SLinus Torvalds 			mask = inl(emu->port + GPIO) | 0x101;
120*1da177e4SLinus Torvalds 			outl(mask, emu->port + GPIO);
121*1da177e4SLinus Torvalds 		}
122*1da177e4SLinus Torvalds 	}
123*1da177e4SLinus Torvalds         return change;
124*1da177e4SLinus Torvalds }
125*1da177e4SLinus Torvalds 
126*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_ca0106_shared_spdif __devinitdata =
127*1da177e4SLinus Torvalds {
128*1da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
129*1da177e4SLinus Torvalds 	.name =		"SPDIF Out",
130*1da177e4SLinus Torvalds 	.info =		snd_ca0106_shared_spdif_info,
131*1da177e4SLinus Torvalds 	.get =		snd_ca0106_shared_spdif_get,
132*1da177e4SLinus Torvalds 	.put =		snd_ca0106_shared_spdif_put
133*1da177e4SLinus Torvalds };
134*1da177e4SLinus Torvalds 
135*1da177e4SLinus Torvalds static int snd_ca0106_capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
136*1da177e4SLinus Torvalds {
137*1da177e4SLinus Torvalds 	static char *texts[6] = { "SPDIF out", "i2s mixer out", "SPDIF in", "i2s in", "AC97 in", "SRC out" };
138*1da177e4SLinus Torvalds 
139*1da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
140*1da177e4SLinus Torvalds 	uinfo->count = 1;
141*1da177e4SLinus Torvalds 	uinfo->value.enumerated.items = 6;
142*1da177e4SLinus Torvalds 	if (uinfo->value.enumerated.item > 5)
143*1da177e4SLinus Torvalds                 uinfo->value.enumerated.item = 5;
144*1da177e4SLinus Torvalds 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
145*1da177e4SLinus Torvalds 	return 0;
146*1da177e4SLinus Torvalds }
147*1da177e4SLinus Torvalds 
148*1da177e4SLinus Torvalds static int snd_ca0106_capture_source_get(snd_kcontrol_t * kcontrol,
149*1da177e4SLinus Torvalds 					snd_ctl_elem_value_t * ucontrol)
150*1da177e4SLinus Torvalds {
151*1da177e4SLinus Torvalds 	ca0106_t *emu = snd_kcontrol_chip(kcontrol);
152*1da177e4SLinus Torvalds 
153*1da177e4SLinus Torvalds 	ucontrol->value.enumerated.item[0] = emu->capture_source;
154*1da177e4SLinus Torvalds 	return 0;
155*1da177e4SLinus Torvalds }
156*1da177e4SLinus Torvalds 
157*1da177e4SLinus Torvalds static int snd_ca0106_capture_source_put(snd_kcontrol_t * kcontrol,
158*1da177e4SLinus Torvalds 					snd_ctl_elem_value_t * ucontrol)
159*1da177e4SLinus Torvalds {
160*1da177e4SLinus Torvalds 	ca0106_t *emu = snd_kcontrol_chip(kcontrol);
161*1da177e4SLinus Torvalds 	unsigned int val;
162*1da177e4SLinus Torvalds 	int change = 0;
163*1da177e4SLinus Torvalds 	u32 mask;
164*1da177e4SLinus Torvalds 	u32 source;
165*1da177e4SLinus Torvalds 
166*1da177e4SLinus Torvalds 	val = ucontrol->value.enumerated.item[0] ;
167*1da177e4SLinus Torvalds 	change = (emu->capture_source != val);
168*1da177e4SLinus Torvalds 	if (change) {
169*1da177e4SLinus Torvalds 		emu->capture_source = val;
170*1da177e4SLinus Torvalds 		source = (val << 28) | (val << 24) | (val << 20) | (val << 16);
171*1da177e4SLinus Torvalds 		mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff;
172*1da177e4SLinus Torvalds 		snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask);
173*1da177e4SLinus Torvalds 	}
174*1da177e4SLinus Torvalds         return change;
175*1da177e4SLinus Torvalds }
176*1da177e4SLinus Torvalds 
177*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_ca0106_capture_source __devinitdata =
178*1da177e4SLinus Torvalds {
179*1da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
180*1da177e4SLinus Torvalds 	.name =		"Capture Source",
181*1da177e4SLinus Torvalds 	.info =		snd_ca0106_capture_source_info,
182*1da177e4SLinus Torvalds 	.get =		snd_ca0106_capture_source_get,
183*1da177e4SLinus Torvalds 	.put =		snd_ca0106_capture_source_put
184*1da177e4SLinus Torvalds };
185*1da177e4SLinus Torvalds 
186*1da177e4SLinus Torvalds static int snd_ca0106_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
187*1da177e4SLinus Torvalds {
188*1da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
189*1da177e4SLinus Torvalds 	uinfo->count = 1;
190*1da177e4SLinus Torvalds 	return 0;
191*1da177e4SLinus Torvalds }
192*1da177e4SLinus Torvalds 
193*1da177e4SLinus Torvalds static int snd_ca0106_spdif_get(snd_kcontrol_t * kcontrol,
194*1da177e4SLinus Torvalds                                  snd_ctl_elem_value_t * ucontrol)
195*1da177e4SLinus Torvalds {
196*1da177e4SLinus Torvalds 	ca0106_t *emu = snd_kcontrol_chip(kcontrol);
197*1da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
198*1da177e4SLinus Torvalds 
199*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
200*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
201*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
202*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
203*1da177e4SLinus Torvalds         return 0;
204*1da177e4SLinus Torvalds }
205*1da177e4SLinus Torvalds 
206*1da177e4SLinus Torvalds static int snd_ca0106_spdif_get_mask(snd_kcontrol_t * kcontrol,
207*1da177e4SLinus Torvalds 				      snd_ctl_elem_value_t * ucontrol)
208*1da177e4SLinus Torvalds {
209*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = 0xff;
210*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = 0xff;
211*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = 0xff;
212*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = 0xff;
213*1da177e4SLinus Torvalds         return 0;
214*1da177e4SLinus Torvalds }
215*1da177e4SLinus Torvalds 
216*1da177e4SLinus Torvalds static int snd_ca0106_spdif_put(snd_kcontrol_t * kcontrol,
217*1da177e4SLinus Torvalds                                  snd_ctl_elem_value_t * ucontrol)
218*1da177e4SLinus Torvalds {
219*1da177e4SLinus Torvalds 	ca0106_t *emu = snd_kcontrol_chip(kcontrol);
220*1da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
221*1da177e4SLinus Torvalds 	int change;
222*1da177e4SLinus Torvalds 	unsigned int val;
223*1da177e4SLinus Torvalds 
224*1da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
225*1da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
226*1da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
227*1da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
228*1da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
229*1da177e4SLinus Torvalds 	if (change) {
230*1da177e4SLinus Torvalds 		snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, val);
231*1da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
232*1da177e4SLinus Torvalds 	}
233*1da177e4SLinus Torvalds         return change;
234*1da177e4SLinus Torvalds }
235*1da177e4SLinus Torvalds 
236*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_ca0106_spdif_mask_control =
237*1da177e4SLinus Torvalds {
238*1da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
239*1da177e4SLinus Torvalds         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
240*1da177e4SLinus Torvalds         .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
241*1da177e4SLinus Torvalds 	.count =	4,
242*1da177e4SLinus Torvalds         .info =         snd_ca0106_spdif_info,
243*1da177e4SLinus Torvalds         .get =          snd_ca0106_spdif_get_mask
244*1da177e4SLinus Torvalds };
245*1da177e4SLinus Torvalds 
246*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_ca0106_spdif_control =
247*1da177e4SLinus Torvalds {
248*1da177e4SLinus Torvalds         .iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
249*1da177e4SLinus Torvalds         .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
250*1da177e4SLinus Torvalds 	.count =	4,
251*1da177e4SLinus Torvalds         .info =         snd_ca0106_spdif_info,
252*1da177e4SLinus Torvalds         .get =          snd_ca0106_spdif_get,
253*1da177e4SLinus Torvalds         .put =          snd_ca0106_spdif_put
254*1da177e4SLinus Torvalds };
255*1da177e4SLinus Torvalds 
256*1da177e4SLinus Torvalds static int snd_ca0106_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
257*1da177e4SLinus Torvalds {
258*1da177e4SLinus Torvalds         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
259*1da177e4SLinus Torvalds         uinfo->count = 2;
260*1da177e4SLinus Torvalds         uinfo->value.integer.min = 0;
261*1da177e4SLinus Torvalds         uinfo->value.integer.max = 255;
262*1da177e4SLinus Torvalds         return 0;
263*1da177e4SLinus Torvalds }
264*1da177e4SLinus Torvalds 
265*1da177e4SLinus Torvalds static int snd_ca0106_volume_get(snd_kcontrol_t * kcontrol,
266*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol, int reg, int channel_id)
267*1da177e4SLinus Torvalds {
268*1da177e4SLinus Torvalds         ca0106_t *emu = snd_kcontrol_chip(kcontrol);
269*1da177e4SLinus Torvalds         unsigned int value;
270*1da177e4SLinus Torvalds 
271*1da177e4SLinus Torvalds         value = snd_ca0106_ptr_read(emu, reg, channel_id);
272*1da177e4SLinus Torvalds         ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */
273*1da177e4SLinus Torvalds         ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */
274*1da177e4SLinus Torvalds         return 0;
275*1da177e4SLinus Torvalds }
276*1da177e4SLinus Torvalds 
277*1da177e4SLinus Torvalds static int snd_ca0106_volume_get_spdif_front(snd_kcontrol_t * kcontrol,
278*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
279*1da177e4SLinus Torvalds {
280*1da177e4SLinus Torvalds 	int channel_id = CONTROL_FRONT_CHANNEL;
281*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME1;
282*1da177e4SLinus Torvalds         return snd_ca0106_volume_get(kcontrol, ucontrol, reg, channel_id);
283*1da177e4SLinus Torvalds }
284*1da177e4SLinus Torvalds 
285*1da177e4SLinus Torvalds static int snd_ca0106_volume_get_spdif_center_lfe(snd_kcontrol_t * kcontrol,
286*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
287*1da177e4SLinus Torvalds {
288*1da177e4SLinus Torvalds 	int channel_id = CONTROL_CENTER_LFE_CHANNEL;
289*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME1;
290*1da177e4SLinus Torvalds         return snd_ca0106_volume_get(kcontrol, ucontrol, reg, channel_id);
291*1da177e4SLinus Torvalds }
292*1da177e4SLinus Torvalds static int snd_ca0106_volume_get_spdif_unknown(snd_kcontrol_t * kcontrol,
293*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
294*1da177e4SLinus Torvalds {
295*1da177e4SLinus Torvalds 	int channel_id = CONTROL_UNKNOWN_CHANNEL;
296*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME1;
297*1da177e4SLinus Torvalds         return snd_ca0106_volume_get(kcontrol, ucontrol, reg, channel_id);
298*1da177e4SLinus Torvalds }
299*1da177e4SLinus Torvalds static int snd_ca0106_volume_get_spdif_rear(snd_kcontrol_t * kcontrol,
300*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
301*1da177e4SLinus Torvalds {
302*1da177e4SLinus Torvalds 	int channel_id = CONTROL_REAR_CHANNEL;
303*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME1;
304*1da177e4SLinus Torvalds         return snd_ca0106_volume_get(kcontrol, ucontrol, reg, channel_id);
305*1da177e4SLinus Torvalds }
306*1da177e4SLinus Torvalds static int snd_ca0106_volume_get_analog_front(snd_kcontrol_t * kcontrol,
307*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
308*1da177e4SLinus Torvalds {
309*1da177e4SLinus Torvalds 	int channel_id = CONTROL_FRONT_CHANNEL;
310*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME2;
311*1da177e4SLinus Torvalds         return snd_ca0106_volume_get(kcontrol, ucontrol, reg, channel_id);
312*1da177e4SLinus Torvalds }
313*1da177e4SLinus Torvalds 
314*1da177e4SLinus Torvalds static int snd_ca0106_volume_get_analog_center_lfe(snd_kcontrol_t * kcontrol,
315*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
316*1da177e4SLinus Torvalds {
317*1da177e4SLinus Torvalds 	int channel_id = CONTROL_CENTER_LFE_CHANNEL;
318*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME2;
319*1da177e4SLinus Torvalds         return snd_ca0106_volume_get(kcontrol, ucontrol, reg, channel_id);
320*1da177e4SLinus Torvalds }
321*1da177e4SLinus Torvalds static int snd_ca0106_volume_get_analog_unknown(snd_kcontrol_t * kcontrol,
322*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
323*1da177e4SLinus Torvalds {
324*1da177e4SLinus Torvalds 	int channel_id = CONTROL_UNKNOWN_CHANNEL;
325*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME2;
326*1da177e4SLinus Torvalds         return snd_ca0106_volume_get(kcontrol, ucontrol, reg, channel_id);
327*1da177e4SLinus Torvalds }
328*1da177e4SLinus Torvalds static int snd_ca0106_volume_get_analog_rear(snd_kcontrol_t * kcontrol,
329*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
330*1da177e4SLinus Torvalds {
331*1da177e4SLinus Torvalds 	int channel_id = CONTROL_REAR_CHANNEL;
332*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME2;
333*1da177e4SLinus Torvalds         return snd_ca0106_volume_get(kcontrol, ucontrol, reg, channel_id);
334*1da177e4SLinus Torvalds }
335*1da177e4SLinus Torvalds 
336*1da177e4SLinus Torvalds static int snd_ca0106_volume_get_feedback(snd_kcontrol_t * kcontrol,
337*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
338*1da177e4SLinus Torvalds {
339*1da177e4SLinus Torvalds 	int channel_id = 1;
340*1da177e4SLinus Torvalds 	int reg = CAPTURE_CONTROL;
341*1da177e4SLinus Torvalds         return snd_ca0106_volume_get(kcontrol, ucontrol, reg, channel_id);
342*1da177e4SLinus Torvalds }
343*1da177e4SLinus Torvalds 
344*1da177e4SLinus Torvalds static int snd_ca0106_volume_put(snd_kcontrol_t * kcontrol,
345*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol, int reg, int channel_id)
346*1da177e4SLinus Torvalds {
347*1da177e4SLinus Torvalds         ca0106_t *emu = snd_kcontrol_chip(kcontrol);
348*1da177e4SLinus Torvalds         unsigned int value;
349*1da177e4SLinus Torvalds         //value = snd_ca0106_ptr_read(emu, reg, channel_id);
350*1da177e4SLinus Torvalds         //value = value & 0xffff;
351*1da177e4SLinus Torvalds         value = ((0xff - ucontrol->value.integer.value[0]) << 24) | ((0xff - ucontrol->value.integer.value[1]) << 16);
352*1da177e4SLinus Torvalds         value = value | ((0xff - ucontrol->value.integer.value[0]) << 8) | ((0xff - ucontrol->value.integer.value[1]) );
353*1da177e4SLinus Torvalds         snd_ca0106_ptr_write(emu, reg, channel_id, value);
354*1da177e4SLinus Torvalds         return 1;
355*1da177e4SLinus Torvalds }
356*1da177e4SLinus Torvalds static int snd_ca0106_volume_put_spdif_front(snd_kcontrol_t * kcontrol,
357*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
358*1da177e4SLinus Torvalds {
359*1da177e4SLinus Torvalds 	int channel_id = CONTROL_FRONT_CHANNEL;
360*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME1;
361*1da177e4SLinus Torvalds         return snd_ca0106_volume_put(kcontrol, ucontrol, reg, channel_id);
362*1da177e4SLinus Torvalds }
363*1da177e4SLinus Torvalds static int snd_ca0106_volume_put_spdif_center_lfe(snd_kcontrol_t * kcontrol,
364*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
365*1da177e4SLinus Torvalds {
366*1da177e4SLinus Torvalds 	int channel_id = CONTROL_CENTER_LFE_CHANNEL;
367*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME1;
368*1da177e4SLinus Torvalds         return snd_ca0106_volume_put(kcontrol, ucontrol, reg, channel_id);
369*1da177e4SLinus Torvalds }
370*1da177e4SLinus Torvalds static int snd_ca0106_volume_put_spdif_unknown(snd_kcontrol_t * kcontrol,
371*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
372*1da177e4SLinus Torvalds {
373*1da177e4SLinus Torvalds 	int channel_id = CONTROL_UNKNOWN_CHANNEL;
374*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME1;
375*1da177e4SLinus Torvalds         return snd_ca0106_volume_put(kcontrol, ucontrol, reg, channel_id);
376*1da177e4SLinus Torvalds }
377*1da177e4SLinus Torvalds static int snd_ca0106_volume_put_spdif_rear(snd_kcontrol_t * kcontrol,
378*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
379*1da177e4SLinus Torvalds {
380*1da177e4SLinus Torvalds 	int channel_id = CONTROL_REAR_CHANNEL;
381*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME1;
382*1da177e4SLinus Torvalds         return snd_ca0106_volume_put(kcontrol, ucontrol, reg, channel_id);
383*1da177e4SLinus Torvalds }
384*1da177e4SLinus Torvalds static int snd_ca0106_volume_put_analog_front(snd_kcontrol_t * kcontrol,
385*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
386*1da177e4SLinus Torvalds {
387*1da177e4SLinus Torvalds 	int channel_id = CONTROL_FRONT_CHANNEL;
388*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME2;
389*1da177e4SLinus Torvalds         return snd_ca0106_volume_put(kcontrol, ucontrol, reg, channel_id);
390*1da177e4SLinus Torvalds }
391*1da177e4SLinus Torvalds static int snd_ca0106_volume_put_analog_center_lfe(snd_kcontrol_t * kcontrol,
392*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
393*1da177e4SLinus Torvalds {
394*1da177e4SLinus Torvalds 	int channel_id = CONTROL_CENTER_LFE_CHANNEL;
395*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME2;
396*1da177e4SLinus Torvalds         return snd_ca0106_volume_put(kcontrol, ucontrol, reg, channel_id);
397*1da177e4SLinus Torvalds }
398*1da177e4SLinus Torvalds static int snd_ca0106_volume_put_analog_unknown(snd_kcontrol_t * kcontrol,
399*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
400*1da177e4SLinus Torvalds {
401*1da177e4SLinus Torvalds 	int channel_id = CONTROL_UNKNOWN_CHANNEL;
402*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME2;
403*1da177e4SLinus Torvalds         return snd_ca0106_volume_put(kcontrol, ucontrol, reg, channel_id);
404*1da177e4SLinus Torvalds }
405*1da177e4SLinus Torvalds static int snd_ca0106_volume_put_analog_rear(snd_kcontrol_t * kcontrol,
406*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
407*1da177e4SLinus Torvalds {
408*1da177e4SLinus Torvalds 	int channel_id = CONTROL_REAR_CHANNEL;
409*1da177e4SLinus Torvalds 	int reg = PLAYBACK_VOLUME2;
410*1da177e4SLinus Torvalds         return snd_ca0106_volume_put(kcontrol, ucontrol, reg, channel_id);
411*1da177e4SLinus Torvalds }
412*1da177e4SLinus Torvalds 
413*1da177e4SLinus Torvalds static int snd_ca0106_volume_put_feedback(snd_kcontrol_t * kcontrol,
414*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
415*1da177e4SLinus Torvalds {
416*1da177e4SLinus Torvalds 	int channel_id = 1;
417*1da177e4SLinus Torvalds 	int reg = CAPTURE_CONTROL;
418*1da177e4SLinus Torvalds         return snd_ca0106_volume_put(kcontrol, ucontrol, reg, channel_id);
419*1da177e4SLinus Torvalds }
420*1da177e4SLinus Torvalds 
421*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_ca0106_volume_control_analog_front =
422*1da177e4SLinus Torvalds {
423*1da177e4SLinus Torvalds         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
424*1da177e4SLinus Torvalds         .name =         "Analog Front Volume",
425*1da177e4SLinus Torvalds         .info =         snd_ca0106_volume_info,
426*1da177e4SLinus Torvalds         .get =          snd_ca0106_volume_get_analog_front,
427*1da177e4SLinus Torvalds         .put =          snd_ca0106_volume_put_analog_front
428*1da177e4SLinus Torvalds };
429*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_ca0106_volume_control_analog_center_lfe =
430*1da177e4SLinus Torvalds {
431*1da177e4SLinus Torvalds         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
432*1da177e4SLinus Torvalds         .name =         "Analog Center/LFE Volume",
433*1da177e4SLinus Torvalds         .info =         snd_ca0106_volume_info,
434*1da177e4SLinus Torvalds         .get =          snd_ca0106_volume_get_analog_center_lfe,
435*1da177e4SLinus Torvalds         .put =          snd_ca0106_volume_put_analog_center_lfe
436*1da177e4SLinus Torvalds };
437*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_ca0106_volume_control_analog_unknown =
438*1da177e4SLinus Torvalds {
439*1da177e4SLinus Torvalds         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
440*1da177e4SLinus Torvalds         .name =         "Analog Unknown Volume",
441*1da177e4SLinus Torvalds         .info =         snd_ca0106_volume_info,
442*1da177e4SLinus Torvalds         .get =          snd_ca0106_volume_get_analog_unknown,
443*1da177e4SLinus Torvalds         .put =          snd_ca0106_volume_put_analog_unknown
444*1da177e4SLinus Torvalds };
445*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_ca0106_volume_control_analog_rear =
446*1da177e4SLinus Torvalds {
447*1da177e4SLinus Torvalds         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
448*1da177e4SLinus Torvalds         .name =         "Analog Rear Volume",
449*1da177e4SLinus Torvalds         .info =         snd_ca0106_volume_info,
450*1da177e4SLinus Torvalds         .get =          snd_ca0106_volume_get_analog_rear,
451*1da177e4SLinus Torvalds         .put =          snd_ca0106_volume_put_analog_rear
452*1da177e4SLinus Torvalds };
453*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_ca0106_volume_control_spdif_front =
454*1da177e4SLinus Torvalds {
455*1da177e4SLinus Torvalds         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
456*1da177e4SLinus Torvalds         .name =         "SPDIF Front Volume",
457*1da177e4SLinus Torvalds         .info =         snd_ca0106_volume_info,
458*1da177e4SLinus Torvalds         .get =          snd_ca0106_volume_get_spdif_front,
459*1da177e4SLinus Torvalds         .put =          snd_ca0106_volume_put_spdif_front
460*1da177e4SLinus Torvalds };
461*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_ca0106_volume_control_spdif_center_lfe =
462*1da177e4SLinus Torvalds {
463*1da177e4SLinus Torvalds         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
464*1da177e4SLinus Torvalds         .name =         "SPDIF Center/LFE Volume",
465*1da177e4SLinus Torvalds         .info =         snd_ca0106_volume_info,
466*1da177e4SLinus Torvalds         .get =          snd_ca0106_volume_get_spdif_center_lfe,
467*1da177e4SLinus Torvalds         .put =          snd_ca0106_volume_put_spdif_center_lfe
468*1da177e4SLinus Torvalds };
469*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_ca0106_volume_control_spdif_unknown =
470*1da177e4SLinus Torvalds {
471*1da177e4SLinus Torvalds         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
472*1da177e4SLinus Torvalds         .name =         "SPDIF Unknown Volume",
473*1da177e4SLinus Torvalds         .info =         snd_ca0106_volume_info,
474*1da177e4SLinus Torvalds         .get =          snd_ca0106_volume_get_spdif_unknown,
475*1da177e4SLinus Torvalds         .put =          snd_ca0106_volume_put_spdif_unknown
476*1da177e4SLinus Torvalds };
477*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_ca0106_volume_control_spdif_rear =
478*1da177e4SLinus Torvalds {
479*1da177e4SLinus Torvalds         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
480*1da177e4SLinus Torvalds         .name =         "SPDIF Rear Volume",
481*1da177e4SLinus Torvalds         .info =         snd_ca0106_volume_info,
482*1da177e4SLinus Torvalds         .get =          snd_ca0106_volume_get_spdif_rear,
483*1da177e4SLinus Torvalds         .put =          snd_ca0106_volume_put_spdif_rear
484*1da177e4SLinus Torvalds };
485*1da177e4SLinus Torvalds 
486*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_ca0106_volume_control_feedback =
487*1da177e4SLinus Torvalds {
488*1da177e4SLinus Torvalds         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
489*1da177e4SLinus Torvalds         .name =         "CAPTURE feedback into PLAYBACK",
490*1da177e4SLinus Torvalds         .info =         snd_ca0106_volume_info,
491*1da177e4SLinus Torvalds         .get =          snd_ca0106_volume_get_feedback,
492*1da177e4SLinus Torvalds         .put =          snd_ca0106_volume_put_feedback
493*1da177e4SLinus Torvalds };
494*1da177e4SLinus Torvalds 
495*1da177e4SLinus Torvalds 
496*1da177e4SLinus Torvalds static int remove_ctl(snd_card_t *card, const char *name)
497*1da177e4SLinus Torvalds {
498*1da177e4SLinus Torvalds 	snd_ctl_elem_id_t id;
499*1da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
500*1da177e4SLinus Torvalds 	strcpy(id.name, name);
501*1da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
502*1da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
503*1da177e4SLinus Torvalds }
504*1da177e4SLinus Torvalds 
505*1da177e4SLinus Torvalds static snd_kcontrol_t *ctl_find(snd_card_t *card, const char *name)
506*1da177e4SLinus Torvalds {
507*1da177e4SLinus Torvalds 	snd_ctl_elem_id_t sid;
508*1da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
509*1da177e4SLinus Torvalds 	/* FIXME: strcpy is bad. */
510*1da177e4SLinus Torvalds 	strcpy(sid.name, name);
511*1da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
512*1da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
513*1da177e4SLinus Torvalds }
514*1da177e4SLinus Torvalds 
515*1da177e4SLinus Torvalds static int rename_ctl(snd_card_t *card, const char *src, const char *dst)
516*1da177e4SLinus Torvalds {
517*1da177e4SLinus Torvalds 	snd_kcontrol_t *kctl = ctl_find(card, src);
518*1da177e4SLinus Torvalds 	if (kctl) {
519*1da177e4SLinus Torvalds 		strcpy(kctl->id.name, dst);
520*1da177e4SLinus Torvalds 		return 0;
521*1da177e4SLinus Torvalds 	}
522*1da177e4SLinus Torvalds 	return -ENOENT;
523*1da177e4SLinus Torvalds }
524*1da177e4SLinus Torvalds 
525*1da177e4SLinus Torvalds int __devinit snd_ca0106_mixer(ca0106_t *emu)
526*1da177e4SLinus Torvalds {
527*1da177e4SLinus Torvalds         int err;
528*1da177e4SLinus Torvalds         snd_kcontrol_t *kctl;
529*1da177e4SLinus Torvalds         snd_card_t *card = emu->card;
530*1da177e4SLinus Torvalds 	char **c;
531*1da177e4SLinus Torvalds 	static char *ca0106_remove_ctls[] = {
532*1da177e4SLinus Torvalds 		"Master Mono Playback Switch",
533*1da177e4SLinus Torvalds 		"Master Mono Playback Volume",
534*1da177e4SLinus Torvalds 		"3D Control - Switch",
535*1da177e4SLinus Torvalds 		"3D Control Sigmatel - Depth",
536*1da177e4SLinus Torvalds 		"PCM Playback Switch",
537*1da177e4SLinus Torvalds 		"PCM Playback Volume",
538*1da177e4SLinus Torvalds 		"CD Playback Switch",
539*1da177e4SLinus Torvalds 		"CD Playback Volume",
540*1da177e4SLinus Torvalds 		"Phone Playback Switch",
541*1da177e4SLinus Torvalds 		"Phone Playback Volume",
542*1da177e4SLinus Torvalds 		"Video Playback Switch",
543*1da177e4SLinus Torvalds 		"Video Playback Volume",
544*1da177e4SLinus Torvalds 		"PC Speaker Playback Switch",
545*1da177e4SLinus Torvalds 		"PC Speaker Playback Volume",
546*1da177e4SLinus Torvalds 		"Mono Output Select",
547*1da177e4SLinus Torvalds 		"Capture Source",
548*1da177e4SLinus Torvalds 		"Capture Switch",
549*1da177e4SLinus Torvalds 		"Capture Volume",
550*1da177e4SLinus Torvalds 		"External Amplifier",
551*1da177e4SLinus Torvalds 		"Sigmatel 4-Speaker Stereo Playback Switch",
552*1da177e4SLinus Torvalds 		"Sigmatel Surround Phase Inversion Playback ",
553*1da177e4SLinus Torvalds 		NULL
554*1da177e4SLinus Torvalds 	};
555*1da177e4SLinus Torvalds 	static char *ca0106_rename_ctls[] = {
556*1da177e4SLinus Torvalds 		"Master Playback Switch", "Capture Switch",
557*1da177e4SLinus Torvalds 		"Master Playback Volume", "Capture Volume",
558*1da177e4SLinus Torvalds 		"Line Playback Switch", "AC97 Line Capture Switch",
559*1da177e4SLinus Torvalds 		"Line Playback Volume", "AC97 Line Capture Volume",
560*1da177e4SLinus Torvalds 		"Aux Playback Switch", "AC97 Aux Capture Switch",
561*1da177e4SLinus Torvalds 		"Aux Playback Volume", "AC97 Aux Capture Volume",
562*1da177e4SLinus Torvalds 		"Mic Playback Switch", "AC97 Mic Capture Switch",
563*1da177e4SLinus Torvalds 		"Mic Playback Volume", "AC97 Mic Capture Volume",
564*1da177e4SLinus Torvalds 		"Mic Select", "AC97 Mic Select",
565*1da177e4SLinus Torvalds 		"Mic Boost (+20dB)", "AC97 Mic Boost (+20dB)",
566*1da177e4SLinus Torvalds 		NULL
567*1da177e4SLinus Torvalds 	};
568*1da177e4SLinus Torvalds #if 1
569*1da177e4SLinus Torvalds 	for (c=ca0106_remove_ctls; *c; c++)
570*1da177e4SLinus Torvalds 		remove_ctl(card, *c);
571*1da177e4SLinus Torvalds 	for (c=ca0106_rename_ctls; *c; c += 2)
572*1da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
573*1da177e4SLinus Torvalds #endif
574*1da177e4SLinus Torvalds 
575*1da177e4SLinus Torvalds         if ((kctl = snd_ctl_new1(&snd_ca0106_volume_control_analog_front, emu)) == NULL)
576*1da177e4SLinus Torvalds                 return -ENOMEM;
577*1da177e4SLinus Torvalds         if ((err = snd_ctl_add(card, kctl)))
578*1da177e4SLinus Torvalds                 return err;
579*1da177e4SLinus Torvalds         if ((kctl = snd_ctl_new1(&snd_ca0106_volume_control_analog_rear, emu)) == NULL)
580*1da177e4SLinus Torvalds                 return -ENOMEM;
581*1da177e4SLinus Torvalds         if ((err = snd_ctl_add(card, kctl)))
582*1da177e4SLinus Torvalds                 return err;
583*1da177e4SLinus Torvalds         if ((kctl = snd_ctl_new1(&snd_ca0106_volume_control_analog_center_lfe, emu)) == NULL)
584*1da177e4SLinus Torvalds                 return -ENOMEM;
585*1da177e4SLinus Torvalds         if ((err = snd_ctl_add(card, kctl)))
586*1da177e4SLinus Torvalds                 return err;
587*1da177e4SLinus Torvalds         if ((kctl = snd_ctl_new1(&snd_ca0106_volume_control_analog_unknown, emu)) == NULL)
588*1da177e4SLinus Torvalds                 return -ENOMEM;
589*1da177e4SLinus Torvalds         if ((err = snd_ctl_add(card, kctl)))
590*1da177e4SLinus Torvalds                 return err;
591*1da177e4SLinus Torvalds         if ((kctl = snd_ctl_new1(&snd_ca0106_volume_control_spdif_front, emu)) == NULL)
592*1da177e4SLinus Torvalds                 return -ENOMEM;
593*1da177e4SLinus Torvalds         if ((err = snd_ctl_add(card, kctl)))
594*1da177e4SLinus Torvalds                 return err;
595*1da177e4SLinus Torvalds         if ((kctl = snd_ctl_new1(&snd_ca0106_volume_control_spdif_rear, emu)) == NULL)
596*1da177e4SLinus Torvalds                 return -ENOMEM;
597*1da177e4SLinus Torvalds         if ((err = snd_ctl_add(card, kctl)))
598*1da177e4SLinus Torvalds                 return err;
599*1da177e4SLinus Torvalds         if ((kctl = snd_ctl_new1(&snd_ca0106_volume_control_spdif_center_lfe, emu)) == NULL)
600*1da177e4SLinus Torvalds                 return -ENOMEM;
601*1da177e4SLinus Torvalds         if ((err = snd_ctl_add(card, kctl)))
602*1da177e4SLinus Torvalds                 return err;
603*1da177e4SLinus Torvalds         if ((kctl = snd_ctl_new1(&snd_ca0106_volume_control_spdif_unknown, emu)) == NULL)
604*1da177e4SLinus Torvalds                 return -ENOMEM;
605*1da177e4SLinus Torvalds         if ((err = snd_ctl_add(card, kctl)))
606*1da177e4SLinus Torvalds                 return err;
607*1da177e4SLinus Torvalds         if ((kctl = snd_ctl_new1(&snd_ca0106_volume_control_feedback, emu)) == NULL)
608*1da177e4SLinus Torvalds                 return -ENOMEM;
609*1da177e4SLinus Torvalds         if ((err = snd_ctl_add(card, kctl)))
610*1da177e4SLinus Torvalds                 return err;
611*1da177e4SLinus Torvalds 	if ((kctl = snd_ctl_new1(&snd_ca0106_spdif_mask_control, emu)) == NULL)
612*1da177e4SLinus Torvalds 		return -ENOMEM;
613*1da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
614*1da177e4SLinus Torvalds 		return err;
615*1da177e4SLinus Torvalds 	if ((kctl = snd_ctl_new1(&snd_ca0106_shared_spdif, emu)) == NULL)
616*1da177e4SLinus Torvalds 		return -ENOMEM;
617*1da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
618*1da177e4SLinus Torvalds 		return err;
619*1da177e4SLinus Torvalds 	if ((kctl = snd_ctl_new1(&snd_ca0106_capture_source, emu)) == NULL)
620*1da177e4SLinus Torvalds 		return -ENOMEM;
621*1da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
622*1da177e4SLinus Torvalds 		return err;
623*1da177e4SLinus Torvalds 	if ((kctl = ctl_find(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT))) != NULL) {
624*1da177e4SLinus Torvalds 		/* already defined by ac97, remove it */
625*1da177e4SLinus Torvalds 		/* FIXME: or do we need both controls? */
626*1da177e4SLinus Torvalds 		remove_ctl(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT));
627*1da177e4SLinus Torvalds 	}
628*1da177e4SLinus Torvalds 	if ((kctl = snd_ctl_new1(&snd_ca0106_spdif_control, emu)) == NULL)
629*1da177e4SLinus Torvalds 		return -ENOMEM;
630*1da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
631*1da177e4SLinus Torvalds 		return err;
632*1da177e4SLinus Torvalds         return 0;
633*1da177e4SLinus Torvalds }
634*1da177e4SLinus Torvalds 
635