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