ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / sound / isa / sb / sb_mixer.c
1 /*
2  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3  *  Routines for Sound Blaster mixer control
4  *
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19  *
20  */
21
22 #include <sound/driver.h>
23 #include <asm/io.h>
24 #include <linux/delay.h>
25 #include <linux/time.h>
26 #include <sound/core.h>
27 #include <sound/sb.h>
28 #include <sound/control.h>
29
30 #define chip_t sb_t
31
32 #undef IO_DEBUG
33
34 void snd_sbmixer_write(sb_t *chip, unsigned char reg, unsigned char data)
35 {
36         outb(reg, SBP(chip, MIXER_ADDR));
37         udelay(10);
38         outb(data, SBP(chip, MIXER_DATA));
39         udelay(10);
40 #ifdef IO_DEBUG
41         snd_printk("mixer_write 0x%x 0x%x\n", reg, data);
42 #endif
43 }
44
45 unsigned char snd_sbmixer_read(sb_t *chip, unsigned char reg)
46 {
47         unsigned char result;
48
49         outb(reg, SBP(chip, MIXER_ADDR));
50         udelay(10);
51         result = inb(SBP(chip, MIXER_DATA));
52         udelay(10);
53 #ifdef IO_DEBUG
54         snd_printk("mixer_read 0x%x 0x%x\n", reg, result);
55 #endif
56         return result;
57 }
58
59 /*
60  * Single channel mixer element
61  */
62
63 static int snd_sbmixer_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
64 {
65         int mask = (kcontrol->private_value >> 24) & 0xff;
66
67         uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
68         uinfo->count = 1;
69         uinfo->value.integer.min = 0;
70         uinfo->value.integer.max = mask;
71         return 0;
72 }
73
74 static int snd_sbmixer_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
75 {
76         sb_t *sb = snd_kcontrol_chip(kcontrol);
77         unsigned long flags;
78         int reg = kcontrol->private_value & 0xff;
79         int shift = (kcontrol->private_value >> 16) & 0xff;
80         int mask = (kcontrol->private_value >> 24) & 0xff;
81         unsigned char val;
82
83         spin_lock_irqsave(&sb->mixer_lock, flags);
84         val = (snd_sbmixer_read(sb, reg) >> shift) & mask;
85         spin_unlock_irqrestore(&sb->mixer_lock, flags);
86         ucontrol->value.integer.value[0] = val;
87         return 0;
88 }
89
90 static int snd_sbmixer_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
91 {
92         sb_t *sb = snd_kcontrol_chip(kcontrol);
93         unsigned long flags;
94         int reg = kcontrol->private_value & 0xff;
95         int shift = (kcontrol->private_value >> 16) & 0x07;
96         int mask = (kcontrol->private_value >> 24) & 0xff;
97         int change;
98         unsigned char val, oval;
99
100         val = (ucontrol->value.integer.value[0] & mask) << shift;
101         spin_lock_irqsave(&sb->mixer_lock, flags);
102         oval = snd_sbmixer_read(sb, reg);
103         val = (oval & ~(mask << shift)) | val;
104         change = val != oval;
105         if (change)
106                 snd_sbmixer_write(sb, reg, val);
107         spin_unlock_irqrestore(&sb->mixer_lock, flags);
108         return change;
109 }
110
111 /*
112  * Double channel mixer element
113  */
114
115 static int snd_sbmixer_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
116 {
117         int mask = (kcontrol->private_value >> 24) & 0xff;
118
119         uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
120         uinfo->count = 2;
121         uinfo->value.integer.min = 0;
122         uinfo->value.integer.max = mask;
123         return 0;
124 }
125
126 static int snd_sbmixer_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
127 {
128         sb_t *sb = snd_kcontrol_chip(kcontrol);
129         unsigned long flags;
130         int left_reg = kcontrol->private_value & 0xff;
131         int right_reg = (kcontrol->private_value >> 8) & 0xff;
132         int left_shift = (kcontrol->private_value >> 16) & 0x07;
133         int right_shift = (kcontrol->private_value >> 19) & 0x07;
134         int mask = (kcontrol->private_value >> 24) & 0xff;
135         unsigned char left, right;
136
137         spin_lock_irqsave(&sb->mixer_lock, flags);
138         left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask;
139         right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask;
140         spin_unlock_irqrestore(&sb->mixer_lock, flags);
141         ucontrol->value.integer.value[0] = left;
142         ucontrol->value.integer.value[1] = right;
143         return 0;
144 }
145
146 static int snd_sbmixer_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
147 {
148         sb_t *sb = snd_kcontrol_chip(kcontrol);
149         unsigned long flags;
150         int left_reg = kcontrol->private_value & 0xff;
151         int right_reg = (kcontrol->private_value >> 8) & 0xff;
152         int left_shift = (kcontrol->private_value >> 16) & 0x07;
153         int right_shift = (kcontrol->private_value >> 19) & 0x07;
154         int mask = (kcontrol->private_value >> 24) & 0xff;
155         int change;
156         unsigned char left, right, oleft, oright;
157
158         left = (ucontrol->value.integer.value[0] & mask) << left_shift;
159         right = (ucontrol->value.integer.value[1] & mask) << right_shift;
160         spin_lock_irqsave(&sb->mixer_lock, flags);
161         if (left_reg == right_reg) {
162                 oleft = snd_sbmixer_read(sb, left_reg);
163                 left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right;
164                 change = left != oleft;
165                 if (change)
166                         snd_sbmixer_write(sb, left_reg, left);
167         } else {
168                 oleft = snd_sbmixer_read(sb, left_reg);
169                 oright = snd_sbmixer_read(sb, right_reg);
170                 left = (oleft & ~(mask << left_shift)) | left;
171                 right = (oright & ~(mask << right_shift)) | right;
172                 change = left != oleft || right != oright;
173                 if (change) {
174                         snd_sbmixer_write(sb, left_reg, left);
175                         snd_sbmixer_write(sb, right_reg, right);
176                 }
177         }
178         spin_unlock_irqrestore(&sb->mixer_lock, flags);
179         return change;
180 }
181
182 /*
183  * DT-019x / ALS-007 capture/input switch
184  */
185
186 static int snd_dt019x_input_sw_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
187 {
188         static char *texts[5] = {
189                 "CD", "Mic", "Line", "Synth", "Master"
190         };
191
192         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
193         uinfo->count = 1;
194         uinfo->value.enumerated.items = 5;
195         if (uinfo->value.enumerated.item > 4)
196                 uinfo->value.enumerated.item = 4;
197         strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
198         return 0;
199 }
200
201 static int snd_dt019x_input_sw_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
202 {
203         sb_t *sb = snd_kcontrol_chip(kcontrol);
204         unsigned long flags;
205         unsigned char oval;
206         
207         spin_lock_irqsave(&sb->mixer_lock, flags);
208         oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
209         spin_unlock_irqrestore(&sb->mixer_lock, flags);
210         switch (oval & 0x07) {
211         case SB_DT019X_CAP_CD:
212                 ucontrol->value.enumerated.item[0] = 0;
213                 break;
214         case SB_DT019X_CAP_MIC:
215                 ucontrol->value.enumerated.item[0] = 1;
216                 break;
217         case SB_DT019X_CAP_LINE:
218                 ucontrol->value.enumerated.item[0] = 2;
219                 break;
220         case SB_DT019X_CAP_MAIN:
221                 ucontrol->value.enumerated.item[0] = 4;
222                 break;
223         /* To record the synth on these cards you must record the main.   */
224         /* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */
225         /* duplicate case labels if left uncommented. */
226         /* case SB_DT019X_CAP_SYNTH:
227          *      ucontrol->value.enumerated.item[0] = 3;
228          *      break;
229          */
230         default:
231                 ucontrol->value.enumerated.item[0] = 4;
232                 break;
233         }
234         return 0;
235 }
236
237 static int snd_dt019x_input_sw_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
238 {
239         sb_t *sb = snd_kcontrol_chip(kcontrol);
240         unsigned long flags;
241         int change;
242         unsigned char nval, oval;
243         
244         if (ucontrol->value.enumerated.item[0] > 4)
245                 return -EINVAL;
246         switch (ucontrol->value.enumerated.item[0]) {
247         case 0:
248                 nval = SB_DT019X_CAP_CD;
249                 break;
250         case 1:
251                 nval = SB_DT019X_CAP_MIC;
252                 break;
253         case 2:
254                 nval = SB_DT019X_CAP_LINE;
255                 break;
256         case 3:
257                 nval = SB_DT019X_CAP_SYNTH;
258                 break;
259         case 4:
260                 nval = SB_DT019X_CAP_MAIN;
261                 break;
262         default:
263                 nval = SB_DT019X_CAP_MAIN;
264         }
265         spin_lock_irqsave(&sb->mixer_lock, flags);
266         oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
267         change = nval != oval;
268         if (change)
269                 snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval);
270         spin_unlock_irqrestore(&sb->mixer_lock, flags);
271         return change;
272 }
273
274 /*
275  * SBPRO input multiplexer
276  */
277
278 static int snd_sb8mixer_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
279 {
280         static char *texts[3] = {
281                 "Mic", "CD", "Line"
282         };
283
284         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
285         uinfo->count = 1;
286         uinfo->value.enumerated.items = 3;
287         if (uinfo->value.enumerated.item > 2)
288                 uinfo->value.enumerated.item = 2;
289         strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
290         return 0;
291 }
292
293
294 static int snd_sb8mixer_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
295 {
296         sb_t *sb = snd_kcontrol_chip(kcontrol);
297         unsigned long flags;
298         unsigned char oval;
299         
300         spin_lock_irqsave(&sb->mixer_lock, flags);
301         oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
302         spin_unlock_irqrestore(&sb->mixer_lock, flags);
303         switch ((oval >> 0x01) & 0x03) {
304         case SB_DSP_MIXS_CD:
305                 ucontrol->value.enumerated.item[0] = 1;
306                 break;
307         case SB_DSP_MIXS_LINE:
308                 ucontrol->value.enumerated.item[0] = 2;
309                 break;
310         default:
311                 ucontrol->value.enumerated.item[0] = 0;
312                 break;
313         }
314         return 0;
315 }
316
317 static int snd_sb8mixer_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
318 {
319         sb_t *sb = snd_kcontrol_chip(kcontrol);
320         unsigned long flags;
321         int change;
322         unsigned char nval, oval;
323         
324         if (ucontrol->value.enumerated.item[0] > 2)
325                 return -EINVAL;
326         switch (ucontrol->value.enumerated.item[0]) {
327         case 1:
328                 nval = SB_DSP_MIXS_CD;
329                 break;
330         case 2:
331                 nval = SB_DSP_MIXS_LINE;
332                 break;
333         default:
334                 nval = SB_DSP_MIXS_MIC;
335         }
336         nval <<= 1;
337         spin_lock_irqsave(&sb->mixer_lock, flags);
338         oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
339         nval |= oval & ~0x06;
340         change = nval != oval;
341         if (change)
342                 snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval);
343         spin_unlock_irqrestore(&sb->mixer_lock, flags);
344         return change;
345 }
346
347 /*
348  * SB16 input switch
349  */
350
351 static int snd_sb16mixer_info_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
352 {
353         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
354         uinfo->count = 4;
355         uinfo->value.integer.min = 0;
356         uinfo->value.integer.max = 1;
357         return 0;
358 }
359
360 static int snd_sb16mixer_get_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
361 {
362         sb_t *sb = snd_kcontrol_chip(kcontrol);
363         unsigned long flags;
364         int reg1 = kcontrol->private_value & 0xff;
365         int reg2 = (kcontrol->private_value >> 8) & 0xff;
366         int left_shift = (kcontrol->private_value >> 16) & 0x0f;
367         int right_shift = (kcontrol->private_value >> 24) & 0x0f;
368         unsigned char val1, val2;
369
370         spin_lock_irqsave(&sb->mixer_lock, flags);
371         val1 = snd_sbmixer_read(sb, reg1);
372         val2 = snd_sbmixer_read(sb, reg2);
373         spin_unlock_irqrestore(&sb->mixer_lock, flags);
374         ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01;
375         ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01;
376         ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01;
377         ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01;
378         return 0;
379 }                                                                                                                   
380
381 static int snd_sb16mixer_put_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
382 {
383         sb_t *sb = snd_kcontrol_chip(kcontrol);
384         unsigned long flags;
385         int reg1 = kcontrol->private_value & 0xff;
386         int reg2 = (kcontrol->private_value >> 8) & 0xff;
387         int left_shift = (kcontrol->private_value >> 16) & 0x0f;
388         int right_shift = (kcontrol->private_value >> 24) & 0x0f;
389         int change;
390         unsigned char val1, val2, oval1, oval2;
391
392         spin_lock_irqsave(&sb->mixer_lock, flags);
393         oval1 = snd_sbmixer_read(sb, reg1);
394         oval2 = snd_sbmixer_read(sb, reg2);
395         val1 = oval1 & ~((1 << left_shift) | (1 << right_shift));
396         val2 = oval2 & ~((1 << left_shift) | (1 << right_shift));
397         val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift;
398         val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift;
399         val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift;
400         val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift;
401         change = val1 != oval1 || val2 != oval2;
402         if (change) {
403                 snd_sbmixer_write(sb, reg1, val1);
404                 snd_sbmixer_write(sb, reg2, val2);
405         }
406         spin_unlock_irqrestore(&sb->mixer_lock, flags);
407         return change;
408 }
409
410
411 /*
412  */
413 /*
414  */
415 int snd_sbmixer_add_ctl(sb_t *chip, const char *name, int index, int type, unsigned long value)
416 {
417         static snd_kcontrol_new_t newctls[] = {
418                 [SB_MIX_SINGLE] = {
419                         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
420                         .info = snd_sbmixer_info_single,
421                         .get = snd_sbmixer_get_single,
422                         .put = snd_sbmixer_put_single,
423                 },
424                 [SB_MIX_DOUBLE] = {
425                         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
426                         .info = snd_sbmixer_info_double,
427                         .get = snd_sbmixer_get_double,
428                         .put = snd_sbmixer_put_double,
429                 },
430                 [SB_MIX_INPUT_SW] = {
431                         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
432                         .info = snd_sb16mixer_info_input_sw,
433                         .get = snd_sb16mixer_get_input_sw,
434                         .put = snd_sb16mixer_put_input_sw,
435                 },
436                 [SB_MIX_CAPTURE_PRO] = {
437                         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
438                         .info = snd_sb8mixer_info_mux,
439                         .get = snd_sb8mixer_get_mux,
440                         .put = snd_sb8mixer_put_mux,
441                 },
442                 [SB_MIX_CAPTURE_DT019X] = {
443                         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
444                         .info = snd_dt019x_input_sw_info,
445                         .get = snd_dt019x_input_sw_get,
446                         .put = snd_dt019x_input_sw_put,
447                 },
448         };
449         snd_kcontrol_t *ctl;
450         int err;
451
452         ctl = snd_ctl_new1(&newctls[type], chip);
453         if (! ctl)
454                 return -ENOMEM;
455         strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
456         ctl->id.index = index;
457         ctl->private_value = value;
458         if ((err = snd_ctl_add(chip->card, ctl)) < 0) {
459                 snd_ctl_free_one(ctl);
460                 return err;
461         }
462         return 0;
463 }
464
465 /*
466  * SB 2.0 specific mixer elements
467  */
468
469 static struct sbmix_elem snd_sb20_ctl_master_play_vol =
470         SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7);
471 static struct sbmix_elem snd_sb20_ctl_pcm_play_vol =
472         SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3);
473 static struct sbmix_elem snd_sb20_ctl_synth_play_vol =
474         SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7);
475 static struct sbmix_elem snd_sb20_ctl_cd_play_vol =
476         SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7);
477
478 static struct sbmix_elem *snd_sb20_controls[] = {
479         &snd_sb20_ctl_master_play_vol,
480         &snd_sb20_ctl_pcm_play_vol,
481         &snd_sb20_ctl_synth_play_vol,
482         &snd_sb20_ctl_cd_play_vol
483 };
484
485 static unsigned char snd_sb20_init_values[][2] = {
486         { SB_DSP20_MASTER_DEV, 0 },
487         { SB_DSP20_FM_DEV, 0 },
488 };
489
490 /*
491  * SB Pro specific mixer elements
492  */
493 static struct sbmix_elem snd_sbpro_ctl_master_play_vol =
494         SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7);
495 static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol =
496         SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7);
497 static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter =
498         SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1);
499 static struct sbmix_elem snd_sbpro_ctl_synth_play_vol =
500         SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7);
501 static struct sbmix_elem snd_sbpro_ctl_cd_play_vol =
502         SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7);
503 static struct sbmix_elem snd_sbpro_ctl_line_play_vol =
504         SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7);
505 static struct sbmix_elem snd_sbpro_ctl_mic_play_vol =
506         SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3);
507 static struct sbmix_elem snd_sbpro_ctl_capture_source =
508         {
509                 .name = "Capture Source",
510                 .type = SB_MIX_CAPTURE_PRO
511         };
512 static struct sbmix_elem snd_sbpro_ctl_capture_filter =
513         SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1);
514 static struct sbmix_elem snd_sbpro_ctl_capture_low_filter =
515         SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1);
516
517 static struct sbmix_elem *snd_sbpro_controls[] = {
518         &snd_sbpro_ctl_master_play_vol,
519         &snd_sbpro_ctl_pcm_play_vol,
520         &snd_sbpro_ctl_pcm_play_filter,
521         &snd_sbpro_ctl_synth_play_vol,
522         &snd_sbpro_ctl_cd_play_vol,
523         &snd_sbpro_ctl_line_play_vol,
524         &snd_sbpro_ctl_mic_play_vol,
525         &snd_sbpro_ctl_capture_source,
526         &snd_sbpro_ctl_capture_filter,
527         &snd_sbpro_ctl_capture_low_filter
528 };
529
530 static unsigned char snd_sbpro_init_values[][2] = {
531         { SB_DSP_MASTER_DEV, 0 },
532         { SB_DSP_PCM_DEV, 0 },
533         { SB_DSP_FM_DEV, 0 },
534 };
535
536 /*
537  * SB16 specific mixer elements
538  */
539 static struct sbmix_elem snd_sb16_ctl_master_play_vol =
540         SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31);
541 static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch =
542         SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1);
543 static struct sbmix_elem snd_sb16_ctl_tone_bass =
544         SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15);
545 static struct sbmix_elem snd_sb16_ctl_tone_treble =
546         SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15);
547 static struct sbmix_elem snd_sb16_ctl_pcm_play_vol =
548         SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31);
549 static struct sbmix_elem snd_sb16_ctl_synth_capture_route =
550         SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5);
551 static struct sbmix_elem snd_sb16_ctl_synth_play_vol =
552         SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31);
553 static struct sbmix_elem snd_sb16_ctl_cd_capture_route =
554         SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1);
555 static struct sbmix_elem snd_sb16_ctl_cd_play_switch =
556         SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1);
557 static struct sbmix_elem snd_sb16_ctl_cd_play_vol =
558         SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31);
559 static struct sbmix_elem snd_sb16_ctl_line_capture_route =
560         SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3);
561 static struct sbmix_elem snd_sb16_ctl_line_play_switch =
562         SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1);
563 static struct sbmix_elem snd_sb16_ctl_line_play_vol =
564         SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31);
565 static struct sbmix_elem snd_sb16_ctl_mic_capture_route =
566         SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0);
567 static struct sbmix_elem snd_sb16_ctl_mic_play_switch =
568         SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1);
569 static struct sbmix_elem snd_sb16_ctl_mic_play_vol =
570         SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31);
571 static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol =
572         SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3);
573 static struct sbmix_elem snd_sb16_ctl_capture_vol =
574         SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3);
575 static struct sbmix_elem snd_sb16_ctl_play_vol =
576         SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3);
577 static struct sbmix_elem snd_sb16_ctl_auto_mic_gain =
578         SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1);
579
580 static struct sbmix_elem *snd_sb16_controls[] = {
581         &snd_sb16_ctl_master_play_vol,
582         &snd_sb16_ctl_3d_enhance_switch,
583         &snd_sb16_ctl_tone_bass,
584         &snd_sb16_ctl_tone_treble,
585         &snd_sb16_ctl_pcm_play_vol,
586         &snd_sb16_ctl_synth_capture_route,
587         &snd_sb16_ctl_synth_play_vol,
588         &snd_sb16_ctl_cd_capture_route,
589         &snd_sb16_ctl_cd_play_switch,
590         &snd_sb16_ctl_cd_play_vol,
591         &snd_sb16_ctl_line_capture_route,
592         &snd_sb16_ctl_line_play_switch,
593         &snd_sb16_ctl_line_play_vol,
594         &snd_sb16_ctl_mic_capture_route,
595         &snd_sb16_ctl_mic_play_switch,
596         &snd_sb16_ctl_mic_play_vol,
597         &snd_sb16_ctl_pc_speaker_vol,
598         &snd_sb16_ctl_capture_vol,
599         &snd_sb16_ctl_play_vol,
600         &snd_sb16_ctl_auto_mic_gain
601 };
602
603 static unsigned char snd_sb16_init_values[][2] = {
604         { SB_DSP4_MASTER_DEV + 0, 0 },
605         { SB_DSP4_MASTER_DEV + 1, 0 },
606         { SB_DSP4_PCM_DEV + 0, 0 },
607         { SB_DSP4_PCM_DEV + 1, 0 },
608         { SB_DSP4_SYNTH_DEV + 0, 0 },
609         { SB_DSP4_SYNTH_DEV + 1, 0 },
610         { SB_DSP4_INPUT_LEFT, 0 },
611         { SB_DSP4_INPUT_RIGHT, 0 },
612         { SB_DSP4_OUTPUT_SW, 0 },
613         { SB_DSP4_SPEAKER_DEV, 0 },
614 };
615
616 /*
617  * DT019x specific mixer elements
618  */
619 static struct sbmix_elem snd_dt019x_ctl_master_play_vol =
620         SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15);
621 static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol =
622         SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15);
623 static struct sbmix_elem snd_dt019x_ctl_synth_play_vol =
624         SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15);
625 static struct sbmix_elem snd_dt019x_ctl_cd_play_vol =
626         SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15);
627 static struct sbmix_elem snd_dt019x_ctl_mic_play_vol =
628         SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7);
629 static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol =
630         SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0,  7);
631 static struct sbmix_elem snd_dt019x_ctl_line_play_vol =
632         SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15);
633 static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch =
634         SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1);
635 static struct sbmix_elem snd_dt019x_ctl_synth_play_switch =
636         SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1);
637 static struct sbmix_elem snd_dt019x_ctl_capture_source =
638         {
639                 .name = "Capture Source",
640                 .type = SB_MIX_CAPTURE_DT019X
641         };
642
643 static struct sbmix_elem *snd_dt019x_controls[] = {
644         &snd_dt019x_ctl_master_play_vol,
645         &snd_dt019x_ctl_pcm_play_vol,
646         &snd_dt019x_ctl_synth_play_vol,
647         &snd_dt019x_ctl_cd_play_vol,
648         &snd_dt019x_ctl_mic_play_vol,
649         &snd_dt019x_ctl_pc_speaker_vol,
650         &snd_dt019x_ctl_line_play_vol,
651         &snd_sb16_ctl_mic_play_switch,
652         &snd_sb16_ctl_cd_play_switch,
653         &snd_sb16_ctl_line_play_switch,
654         &snd_dt019x_ctl_pcm_play_switch,
655         &snd_dt019x_ctl_synth_play_switch,
656         &snd_dt019x_ctl_capture_source
657 };
658
659 static unsigned char snd_dt019x_init_values[][2] = {
660         { SB_DT019X_MASTER_DEV, 0 },
661         { SB_DT019X_PCM_DEV, 0 },
662         { SB_DT019X_SYNTH_DEV, 0 },
663         { SB_DT019X_CD_DEV, 0 },
664         { SB_DT019X_MIC_DEV, 0 },       /* Includes PC-speaker in high nibble */
665         { SB_DT019X_LINE_DEV, 0 },
666         { SB_DSP4_OUTPUT_SW, 0 },
667         { SB_DT019X_OUTPUT_SW2, 0 },
668         { SB_DT019X_CAPTURE_SW, 0x06 },
669 };
670
671 /*
672  * ALS4000 specific mixer elements
673  */
674 /* FIXME: SB_ALS4000_MONO_IO_CTRL needs output select ctrl ! */
675 static struct sbmix_elem snd_als4000_ctl_mono_output_switch =
676         SB_SINGLE("Mono Output Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1);
677 /* FIXME: mono input switch also available on DT019X ? */
678 static struct sbmix_elem snd_als4000_ctl_mono_input_switch =
679         SB_SINGLE("Mono Input Switch", SB_DT019X_OUTPUT_SW2, 0, 1);
680 static struct sbmix_elem snd_als4000_ctl_mic_20db_boost =
681         SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03);
682 static struct sbmix_elem snd_als4000_ctl_mixer_out_to_in =
683         SB_SINGLE("Mixer Out To In", SB_ALS4000_MIC_IN_GAIN, 7, 0x01);
684 /* FIXME: 3D needs much more sophisticated controls, many more features ! */
685 static struct sbmix_elem snd_als4000_ctl_3d_output_switch =
686         SB_SINGLE("3D Output Switch", SB_ALS4000_3D_SND_FX, 6, 0x01);
687 static struct sbmix_elem snd_als4000_ctl_3d_output_ratio =
688         SB_SINGLE("3D Output Ratio", SB_ALS4000_3D_SND_FX, 0, 0x07);
689 static struct sbmix_elem snd_als4000_ctl_3d_poweroff_switch =
690         SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01);
691 static struct sbmix_elem snd_als4000_ctl_3d_delay =
692         SB_SINGLE("3D Delay", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f);
693 #if NOT_AVAILABLE
694 static struct sbmix_elem snd_als4000_ctl_fmdac =
695         SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01);
696 static struct sbmix_elem snd_als4000_ctl_qsound =
697         SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f);
698 #endif
699
700 static struct sbmix_elem *snd_als4000_controls[] = {
701         &snd_sb16_ctl_master_play_vol,
702         &snd_dt019x_ctl_pcm_play_switch,
703         &snd_sb16_ctl_pcm_play_vol,
704         &snd_sb16_ctl_synth_capture_route,
705         &snd_dt019x_ctl_synth_play_switch,
706         &snd_sb16_ctl_synth_play_vol,
707         &snd_sb16_ctl_cd_capture_route,
708         &snd_sb16_ctl_cd_play_switch,
709         &snd_sb16_ctl_cd_play_vol,
710         &snd_sb16_ctl_line_capture_route,
711         &snd_sb16_ctl_line_play_switch,
712         &snd_sb16_ctl_line_play_vol,
713         &snd_sb16_ctl_mic_capture_route,
714         &snd_als4000_ctl_mic_20db_boost,
715         &snd_sb16_ctl_auto_mic_gain,
716         &snd_sb16_ctl_mic_play_switch,
717         &snd_sb16_ctl_mic_play_vol,
718         &snd_sb16_ctl_pc_speaker_vol,
719         &snd_sb16_ctl_capture_vol,
720         &snd_sb16_ctl_play_vol,
721         &snd_als4000_ctl_mono_output_switch,
722         &snd_als4000_ctl_mono_input_switch,
723         &snd_als4000_ctl_mixer_out_to_in,
724         &snd_als4000_ctl_3d_output_switch,
725         &snd_als4000_ctl_3d_output_ratio,
726         &snd_als4000_ctl_3d_delay,
727         &snd_als4000_ctl_3d_poweroff_switch,
728 #if NOT_AVAILABLE
729         &snd_als4000_ctl_fmdac,
730         &snd_als4000_ctl_qsound,
731 #endif
732 };
733
734 static unsigned char snd_als4000_init_values[][2] = {
735         { SB_DSP4_MASTER_DEV + 0, 0 },
736         { SB_DSP4_MASTER_DEV + 1, 0 },
737         { SB_DSP4_PCM_DEV + 0, 0 },
738         { SB_DSP4_PCM_DEV + 1, 0 },
739         { SB_DSP4_SYNTH_DEV + 0, 0 },
740         { SB_DSP4_SYNTH_DEV + 1, 0 },
741         { SB_DSP4_SPEAKER_DEV, 0 },
742         { SB_DSP4_OUTPUT_SW, 0 },
743         { SB_DSP4_INPUT_LEFT, 0 },
744         { SB_DSP4_INPUT_RIGHT, 0 },
745         { SB_DT019X_OUTPUT_SW2, 0 },
746         { SB_ALS4000_MIC_IN_GAIN, 0 },
747 };
748
749
750 /*
751  */
752 static int snd_sbmixer_init(sb_t *chip,
753                             struct sbmix_elem **controls,
754                             int controls_count,
755                             unsigned char map[][2],
756                             int map_count,
757                             char *name)
758 {
759         unsigned long flags;
760         snd_card_t *card = chip->card;
761         int idx, err;
762
763         /* mixer reset */
764         spin_lock_irqsave(&chip->mixer_lock, flags);
765         snd_sbmixer_write(chip, 0x00, 0x00);
766         spin_unlock_irqrestore(&chip->mixer_lock, flags);
767
768         /* mute and zero volume channels */
769         for (idx = 0; idx < map_count; idx++) {
770                 spin_lock_irqsave(&chip->mixer_lock, flags);
771                 snd_sbmixer_write(chip, map[idx][0], map[idx][1]);
772                 spin_unlock_irqrestore(&chip->mixer_lock, flags);
773         }
774
775         for (idx = 0; idx < controls_count; idx++) {
776                 if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0)
777                         return err;
778         }
779         snd_component_add(card, name);
780         strcpy(card->mixername, name);
781         return 0;
782 }
783
784 int snd_sbmixer_new(sb_t *chip)
785 {
786         snd_card_t * card;
787         int err;
788
789         snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
790
791         card = chip->card;
792
793         switch (chip->hardware) {
794         case SB_HW_10:
795                 return 0; /* no mixer chip on SB1.x */
796         case SB_HW_20:
797         case SB_HW_201:
798                 if ((err = snd_sbmixer_init(chip,
799                                             snd_sb20_controls,
800                                             ARRAY_SIZE(snd_sb20_controls),
801                                             snd_sb20_init_values,
802                                             ARRAY_SIZE(snd_sb20_init_values),
803                                             "CTL1335")) < 0)
804                         return err;
805                 break;
806         case SB_HW_PRO:
807                 if ((err = snd_sbmixer_init(chip,
808                                             snd_sbpro_controls,
809                                             ARRAY_SIZE(snd_sbpro_controls),
810                                             snd_sbpro_init_values,
811                                             ARRAY_SIZE(snd_sbpro_init_values),
812                                             "CTL1345")) < 0)
813                         return err;
814                 break;
815         case SB_HW_16:
816         case SB_HW_ALS100:
817                 if ((err = snd_sbmixer_init(chip,
818                                             snd_sb16_controls,
819                                             ARRAY_SIZE(snd_sb16_controls),
820                                             snd_sb16_init_values,
821                                             ARRAY_SIZE(snd_sb16_init_values),
822                                             "CTL1745")) < 0)
823                         return err;
824                 break;
825         case SB_HW_ALS4000:
826                 if ((err = snd_sbmixer_init(chip,
827                                             snd_als4000_controls,
828                                             ARRAY_SIZE(snd_als4000_controls),
829                                             snd_als4000_init_values,
830                                             ARRAY_SIZE(snd_als4000_init_values),
831                                             "ALS4000")) < 0)
832                         return err;
833                 break;
834         case SB_HW_DT019X:
835                 if ((err = snd_sbmixer_init(chip,
836                                             snd_dt019x_controls,
837                                             ARRAY_SIZE(snd_dt019x_controls),
838                                             snd_dt019x_init_values,
839                                             ARRAY_SIZE(snd_dt019x_init_values),
840                                             "DT019X")) < 0)
841                 break;
842         default:
843                 strcpy(card->mixername, "???");
844         }
845         return 0;
846 }