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