[ALSA] Skip ac97 SPDIF controls
[linux-2.6.git] / sound / pci / ca0106 / ca0106_mixer.c
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 = snd_ctl_new1(&snd_ca0106_spdif_control, emu)) == NULL)
624                 return -ENOMEM;
625         if ((err = snd_ctl_add(card, kctl)))
626                 return err;
627         return 0;
628 }
629