]> git.karo-electronics.de Git - mv-sheeva.git/blob - sound/isa/cs423x/cs4236_lib.c
ALSA: cs4236: update control names
[mv-sheeva.git] / sound / isa / cs423x / cs4236_lib.c
1 /*
2  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
3  *  Routines for control of CS4235/4236B/4237B/4238B/4239 chips
4  *
5  *  Note:
6  *     -----
7  *
8  *  Bugs:
9  *     -----
10  *
11  *   This program is free software; you can redistribute it and/or modify
12  *   it under the terms of the GNU General Public License as published by
13  *   the Free Software Foundation; either version 2 of the License, or
14  *   (at your option) any later version.
15  *
16  *   This program is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU General Public License for more details.
20  *
21  *   You should have received a copy of the GNU General Public License
22  *   along with this program; if not, write to the Free Software
23  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
24  *
25  */
26
27 /*
28  *  Indirect control registers (CS4236B+)
29  * 
30  *  C0
31  *     D8: WSS reset (all chips)
32  *
33  *  C1 (all chips except CS4236)
34  *     D7-D5: version 
35  *     D4-D0: chip id
36  *             11101 - CS4235
37  *             01011 - CS4236B
38  *             01000 - CS4237B
39  *             01001 - CS4238B
40  *             11110 - CS4239
41  *
42  *  C2
43  *     D7-D4: 3D Space (CS4235,CS4237B,CS4238B,CS4239)
44  *     D3-D0: 3D Center (CS4237B); 3D Volume (CS4238B)
45  * 
46  *  C3
47  *     D7: 3D Enable (CS4237B)
48  *     D6: 3D Mono Enable (CS4237B)
49  *     D5: 3D Serial Output (CS4237B,CS4238B)
50  *     D4: 3D Enable (CS4235,CS4238B,CS4239)
51  *
52  *  C4
53  *     D7: consumer serial port enable (CS4237B,CS4238B)
54  *     D6: channels status block reset (CS4237B,CS4238B)
55  *     D5: user bit in sub-frame of digital audio data (CS4237B,CS4238B)
56  *     D4: validity bit bit in sub-frame of digital audio data (CS4237B,CS4238B)
57  * 
58  *  C5  lower channel status (digital serial data description) (CS4237B,CS4238B)
59  *     D7-D6: first two bits of category code
60  *     D5: lock
61  *     D4-D3: pre-emphasis (0 = none, 1 = 50/15us)
62  *     D2: copy/copyright (0 = copy inhibited)
63  *     D1: 0 = digital audio / 1 = non-digital audio
64  *     
65  *  C6  upper channel status (digital serial data description) (CS4237B,CS4238B)
66  *     D7-D6: sample frequency (0 = 44.1kHz)
67  *     D5: generation status (0 = no indication, 1 = original/commercially precaptureed data)
68  *     D4-D0: category code (upper bits)
69  *
70  *  C7  reserved (must write 0)
71  *
72  *  C8  wavetable control
73  *     D7: volume control interrupt enable (CS4235,CS4239)
74  *     D6: hardware volume control format (CS4235,CS4239)
75  *     D3: wavetable serial port enable (all chips)
76  *     D2: DSP serial port switch (all chips)
77  *     D1: disable MCLK (all chips)
78  *     D0: force BRESET low (all chips)
79  *
80  */
81
82 #include <asm/io.h>
83 #include <linux/delay.h>
84 #include <linux/init.h>
85 #include <linux/time.h>
86 #include <linux/wait.h>
87 #include <sound/core.h>
88 #include <sound/wss.h>
89 #include <sound/asoundef.h>
90 #include <sound/initval.h>
91
92 /*
93  *
94  */
95
96 static unsigned char snd_cs4236_ext_map[18] = {
97         /* CS4236_LEFT_LINE */          0xff,
98         /* CS4236_RIGHT_LINE */         0xff,
99         /* CS4236_LEFT_MIC */           0xdf,
100         /* CS4236_RIGHT_MIC */          0xdf,
101         /* CS4236_LEFT_MIX_CTRL */      0xe0 | 0x18,
102         /* CS4236_RIGHT_MIX_CTRL */     0xe0,
103         /* CS4236_LEFT_FM */            0xbf,
104         /* CS4236_RIGHT_FM */           0xbf,
105         /* CS4236_LEFT_DSP */           0xbf,
106         /* CS4236_RIGHT_DSP */          0xbf,
107         /* CS4236_RIGHT_LOOPBACK */     0xbf,
108         /* CS4236_DAC_MUTE */           0xe0,
109         /* CS4236_ADC_RATE */           0x01,   /* 48kHz */
110         /* CS4236_DAC_RATE */           0x01,   /* 48kHz */
111         /* CS4236_LEFT_MASTER */        0xbf,
112         /* CS4236_RIGHT_MASTER */       0xbf,
113         /* CS4236_LEFT_WAVE */          0xbf,
114         /* CS4236_RIGHT_WAVE */         0xbf
115 };
116
117 /*
118  *
119  */
120
121 static void snd_cs4236_ctrl_out(struct snd_wss *chip,
122                                 unsigned char reg, unsigned char val)
123 {
124         outb(reg, chip->cport + 3);
125         outb(chip->cimage[reg] = val, chip->cport + 4);
126 }
127
128 static unsigned char snd_cs4236_ctrl_in(struct snd_wss *chip, unsigned char reg)
129 {
130         outb(reg, chip->cport + 3);
131         return inb(chip->cport + 4);
132 }
133
134 /*
135  *  PCM
136  */
137
138 #define CLOCKS 8
139
140 static struct snd_ratnum clocks[CLOCKS] = {
141         { .num = 16934400, .den_min = 353, .den_max = 353, .den_step = 1 },
142         { .num = 16934400, .den_min = 529, .den_max = 529, .den_step = 1 },
143         { .num = 16934400, .den_min = 617, .den_max = 617, .den_step = 1 },
144         { .num = 16934400, .den_min = 1058, .den_max = 1058, .den_step = 1 },
145         { .num = 16934400, .den_min = 1764, .den_max = 1764, .den_step = 1 },
146         { .num = 16934400, .den_min = 2117, .den_max = 2117, .den_step = 1 },
147         { .num = 16934400, .den_min = 2558, .den_max = 2558, .den_step = 1 },
148         { .num = 16934400/16, .den_min = 21, .den_max = 192, .den_step = 1 }
149 };
150
151 static struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = {
152         .nrats = CLOCKS,
153         .rats = clocks,
154 };
155
156 static int snd_cs4236_xrate(struct snd_pcm_runtime *runtime)
157 {
158         return snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
159                                              &hw_constraints_clocks);
160 }
161
162 static unsigned char divisor_to_rate_register(unsigned int divisor)
163 {
164         switch (divisor) {
165         case 353:       return 1;
166         case 529:       return 2;
167         case 617:       return 3;
168         case 1058:      return 4;
169         case 1764:      return 5;
170         case 2117:      return 6;
171         case 2558:      return 7;
172         default:
173                 if (divisor < 21 || divisor > 192) {
174                         snd_BUG();
175                         return 192;
176                 }
177                 return divisor;
178         }
179 }
180
181 static void snd_cs4236_playback_format(struct snd_wss *chip,
182                                        struct snd_pcm_hw_params *params,
183                                        unsigned char pdfr)
184 {
185         unsigned long flags;
186         unsigned char rate = divisor_to_rate_register(params->rate_den);
187         
188         spin_lock_irqsave(&chip->reg_lock, flags);
189         /* set fast playback format change and clean playback FIFO */
190         snd_wss_out(chip, CS4231_ALT_FEATURE_1,
191                     chip->image[CS4231_ALT_FEATURE_1] | 0x10);
192         snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0);
193         snd_wss_out(chip, CS4231_ALT_FEATURE_1,
194                     chip->image[CS4231_ALT_FEATURE_1] & ~0x10);
195         snd_cs4236_ext_out(chip, CS4236_DAC_RATE, rate);
196         spin_unlock_irqrestore(&chip->reg_lock, flags);
197 }
198
199 static void snd_cs4236_capture_format(struct snd_wss *chip,
200                                       struct snd_pcm_hw_params *params,
201                                       unsigned char cdfr)
202 {
203         unsigned long flags;
204         unsigned char rate = divisor_to_rate_register(params->rate_den);
205         
206         spin_lock_irqsave(&chip->reg_lock, flags);
207         /* set fast capture format change and clean capture FIFO */
208         snd_wss_out(chip, CS4231_ALT_FEATURE_1,
209                     chip->image[CS4231_ALT_FEATURE_1] | 0x20);
210         snd_wss_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0);
211         snd_wss_out(chip, CS4231_ALT_FEATURE_1,
212                     chip->image[CS4231_ALT_FEATURE_1] & ~0x20);
213         snd_cs4236_ext_out(chip, CS4236_ADC_RATE, rate);
214         spin_unlock_irqrestore(&chip->reg_lock, flags);
215 }
216
217 #ifdef CONFIG_PM
218
219 static void snd_cs4236_suspend(struct snd_wss *chip)
220 {
221         int reg;
222         unsigned long flags;
223         
224         spin_lock_irqsave(&chip->reg_lock, flags);
225         for (reg = 0; reg < 32; reg++)
226                 chip->image[reg] = snd_wss_in(chip, reg);
227         for (reg = 0; reg < 18; reg++)
228                 chip->eimage[reg] = snd_cs4236_ext_in(chip, CS4236_I23VAL(reg));
229         for (reg = 2; reg < 9; reg++)
230                 chip->cimage[reg] = snd_cs4236_ctrl_in(chip, reg);
231         spin_unlock_irqrestore(&chip->reg_lock, flags);
232 }
233
234 static void snd_cs4236_resume(struct snd_wss *chip)
235 {
236         int reg;
237         unsigned long flags;
238         
239         snd_wss_mce_up(chip);
240         spin_lock_irqsave(&chip->reg_lock, flags);
241         for (reg = 0; reg < 32; reg++) {
242                 switch (reg) {
243                 case CS4236_EXT_REG:
244                 case CS4231_VERSION:
245                 case 27:        /* why? CS4235 - master left */
246                 case 29:        /* why? CS4235 - master right */
247                         break;
248                 default:
249                         snd_wss_out(chip, reg, chip->image[reg]);
250                         break;
251                 }
252         }
253         for (reg = 0; reg < 18; reg++)
254                 snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), chip->eimage[reg]);
255         for (reg = 2; reg < 9; reg++) {
256                 switch (reg) {
257                 case 7:
258                         break;
259                 default:
260                         snd_cs4236_ctrl_out(chip, reg, chip->cimage[reg]);
261                 }
262         }
263         spin_unlock_irqrestore(&chip->reg_lock, flags);
264         snd_wss_mce_down(chip);
265 }
266
267 #endif /* CONFIG_PM */
268 /*
269  * This function does no fail if the chip is not CS4236B or compatible.
270  * It just an equivalent to the snd_wss_create() then.
271  */
272 int snd_cs4236_create(struct snd_card *card,
273                       unsigned long port,
274                       unsigned long cport,
275                       int irq, int dma1, int dma2,
276                       unsigned short hardware,
277                       unsigned short hwshare,
278                       struct snd_wss **rchip)
279 {
280         struct snd_wss *chip;
281         unsigned char ver1, ver2;
282         unsigned int reg;
283         int err;
284
285         *rchip = NULL;
286         if (hardware == WSS_HW_DETECT)
287                 hardware = WSS_HW_DETECT3;
288
289         err = snd_wss_create(card, port, cport,
290                              irq, dma1, dma2, hardware, hwshare, &chip);
291         if (err < 0)
292                 return err;
293
294         if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) {
295                 snd_printd("chip is not CS4236+, hardware=0x%x\n",
296                            chip->hardware);
297                 *rchip = chip;
298                 return 0;
299         }
300 #if 0
301         {
302                 int idx;
303                 for (idx = 0; idx < 8; idx++)
304                         snd_printk(KERN_DEBUG "CD%i = 0x%x\n",
305                                    idx, inb(chip->cport + idx));
306                 for (idx = 0; idx < 9; idx++)
307                         snd_printk(KERN_DEBUG "C%i = 0x%x\n",
308                                    idx, snd_cs4236_ctrl_in(chip, idx));
309         }
310 #endif
311         if (cport < 0x100 || cport == SNDRV_AUTO_PORT) {
312                 snd_printk(KERN_ERR "please, specify control port "
313                            "for CS4236+ chips\n");
314                 snd_device_free(card, chip);
315                 return -ENODEV;
316         }
317         ver1 = snd_cs4236_ctrl_in(chip, 1);
318         ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
319         snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n",
320                         cport, ver1, ver2);
321         if (ver1 != ver2) {
322                 snd_printk(KERN_ERR "CS4236+ chip detected, but "
323                            "control port 0x%lx is not valid\n", cport);
324                 snd_device_free(card, chip);
325                 return -ENODEV;
326         }
327         snd_cs4236_ctrl_out(chip, 0, 0x00);
328         snd_cs4236_ctrl_out(chip, 2, 0xff);
329         snd_cs4236_ctrl_out(chip, 3, 0x00);
330         snd_cs4236_ctrl_out(chip, 4, 0x80);
331         reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) |
332               IEC958_AES0_CON_EMPHASIS_NONE;
333         snd_cs4236_ctrl_out(chip, 5, reg);
334         snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2);
335         snd_cs4236_ctrl_out(chip, 7, 0x00);
336         /*
337          * 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958
338          * output is working with this setup, other hardware should
339          * have different signal paths and this value should be
340          * selectable in the future
341          */
342         snd_cs4236_ctrl_out(chip, 8, 0x8c);
343         chip->rate_constraint = snd_cs4236_xrate;
344         chip->set_playback_format = snd_cs4236_playback_format;
345         chip->set_capture_format = snd_cs4236_capture_format;
346 #ifdef CONFIG_PM
347         chip->suspend = snd_cs4236_suspend;
348         chip->resume = snd_cs4236_resume;
349 #endif
350
351         /* initialize extended registers */
352         for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++)
353                 snd_cs4236_ext_out(chip, CS4236_I23VAL(reg),
354                                    snd_cs4236_ext_map[reg]);
355
356         /* initialize compatible but more featured registers */
357         snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40);
358         snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40);
359         snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
360         snd_wss_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff);
361         snd_wss_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf);
362         snd_wss_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf);
363         snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
364         snd_wss_out(chip, CS4231_LEFT_LINE_IN, 0xff);
365         snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
366         switch (chip->hardware) {
367         case WSS_HW_CS4235:
368         case WSS_HW_CS4239:
369                 snd_wss_out(chip, CS4235_LEFT_MASTER, 0xff);
370                 snd_wss_out(chip, CS4235_RIGHT_MASTER, 0xff);
371                 break;
372         }
373
374         *rchip = chip;
375         return 0;
376 }
377
378 int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
379 {
380         struct snd_pcm *pcm;
381         int err;
382         
383         err = snd_wss_pcm(chip, device, &pcm);
384         if (err < 0)
385                 return err;
386         pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX;
387         if (rpcm)
388                 *rpcm = pcm;
389         return 0;
390 }
391
392 /*
393  *  MIXER
394  */
395
396 #define CS4236_SINGLE(xname, xindex, reg, shift, mask, invert) \
397 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
398   .info = snd_cs4236_info_single, \
399   .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \
400   .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
401
402 static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
403 {
404         int mask = (kcontrol->private_value >> 16) & 0xff;
405
406         uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
407         uinfo->count = 1;
408         uinfo->value.integer.min = 0;
409         uinfo->value.integer.max = mask;
410         return 0;
411 }
412
413 static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
414 {
415         struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
416         unsigned long flags;
417         int reg = kcontrol->private_value & 0xff;
418         int shift = (kcontrol->private_value >> 8) & 0xff;
419         int mask = (kcontrol->private_value >> 16) & 0xff;
420         int invert = (kcontrol->private_value >> 24) & 0xff;
421         
422         spin_lock_irqsave(&chip->reg_lock, flags);
423         ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(reg)] >> shift) & mask;
424         spin_unlock_irqrestore(&chip->reg_lock, flags);
425         if (invert)
426                 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
427         return 0;
428 }
429
430 static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
431 {
432         struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
433         unsigned long flags;
434         int reg = kcontrol->private_value & 0xff;
435         int shift = (kcontrol->private_value >> 8) & 0xff;
436         int mask = (kcontrol->private_value >> 16) & 0xff;
437         int invert = (kcontrol->private_value >> 24) & 0xff;
438         int change;
439         unsigned short val;
440         
441         val = (ucontrol->value.integer.value[0] & mask);
442         if (invert)
443                 val = mask - val;
444         val <<= shift;
445         spin_lock_irqsave(&chip->reg_lock, flags);
446         val = (chip->eimage[CS4236_REG(reg)] & ~(mask << shift)) | val;
447         change = val != chip->eimage[CS4236_REG(reg)];
448         snd_cs4236_ext_out(chip, reg, val);
449         spin_unlock_irqrestore(&chip->reg_lock, flags);
450         return change;
451 }
452
453 #define CS4236_SINGLEC(xname, xindex, reg, shift, mask, invert) \
454 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
455   .info = snd_cs4236_info_single, \
456   .get = snd_cs4236_get_singlec, .put = snd_cs4236_put_singlec, \
457   .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
458
459 static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
460 {
461         struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
462         unsigned long flags;
463         int reg = kcontrol->private_value & 0xff;
464         int shift = (kcontrol->private_value >> 8) & 0xff;
465         int mask = (kcontrol->private_value >> 16) & 0xff;
466         int invert = (kcontrol->private_value >> 24) & 0xff;
467         
468         spin_lock_irqsave(&chip->reg_lock, flags);
469         ucontrol->value.integer.value[0] = (chip->cimage[reg] >> shift) & mask;
470         spin_unlock_irqrestore(&chip->reg_lock, flags);
471         if (invert)
472                 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
473         return 0;
474 }
475
476 static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
477 {
478         struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
479         unsigned long flags;
480         int reg = kcontrol->private_value & 0xff;
481         int shift = (kcontrol->private_value >> 8) & 0xff;
482         int mask = (kcontrol->private_value >> 16) & 0xff;
483         int invert = (kcontrol->private_value >> 24) & 0xff;
484         int change;
485         unsigned short val;
486         
487         val = (ucontrol->value.integer.value[0] & mask);
488         if (invert)
489                 val = mask - val;
490         val <<= shift;
491         spin_lock_irqsave(&chip->reg_lock, flags);
492         val = (chip->cimage[reg] & ~(mask << shift)) | val;
493         change = val != chip->cimage[reg];
494         snd_cs4236_ctrl_out(chip, reg, val);
495         spin_unlock_irqrestore(&chip->reg_lock, flags);
496         return change;
497 }
498
499 #define CS4236_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
500 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
501   .info = snd_cs4236_info_double, \
502   .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
503   .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
504
505 static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
506 {
507         int mask = (kcontrol->private_value >> 24) & 0xff;
508
509         uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
510         uinfo->count = 2;
511         uinfo->value.integer.min = 0;
512         uinfo->value.integer.max = mask;
513         return 0;
514 }
515
516 static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
517 {
518         struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
519         unsigned long flags;
520         int left_reg = kcontrol->private_value & 0xff;
521         int right_reg = (kcontrol->private_value >> 8) & 0xff;
522         int shift_left = (kcontrol->private_value >> 16) & 0x07;
523         int shift_right = (kcontrol->private_value >> 19) & 0x07;
524         int mask = (kcontrol->private_value >> 24) & 0xff;
525         int invert = (kcontrol->private_value >> 22) & 1;
526         
527         spin_lock_irqsave(&chip->reg_lock, flags);
528         ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(left_reg)] >> shift_left) & mask;
529         ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask;
530         spin_unlock_irqrestore(&chip->reg_lock, flags);
531         if (invert) {
532                 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
533                 ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
534         }
535         return 0;
536 }
537
538 static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
539 {
540         struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
541         unsigned long flags;
542         int left_reg = kcontrol->private_value & 0xff;
543         int right_reg = (kcontrol->private_value >> 8) & 0xff;
544         int shift_left = (kcontrol->private_value >> 16) & 0x07;
545         int shift_right = (kcontrol->private_value >> 19) & 0x07;
546         int mask = (kcontrol->private_value >> 24) & 0xff;
547         int invert = (kcontrol->private_value >> 22) & 1;
548         int change;
549         unsigned short val1, val2;
550         
551         val1 = ucontrol->value.integer.value[0] & mask;
552         val2 = ucontrol->value.integer.value[1] & mask;
553         if (invert) {
554                 val1 = mask - val1;
555                 val2 = mask - val2;
556         }
557         val1 <<= shift_left;
558         val2 <<= shift_right;
559         spin_lock_irqsave(&chip->reg_lock, flags);
560         if (left_reg != right_reg) {
561                 val1 = (chip->eimage[CS4236_REG(left_reg)] & ~(mask << shift_left)) | val1;
562                 val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2;
563                 change = val1 != chip->eimage[CS4236_REG(left_reg)] || val2 != chip->eimage[CS4236_REG(right_reg)];
564                 snd_cs4236_ext_out(chip, left_reg, val1);
565                 snd_cs4236_ext_out(chip, right_reg, val2);
566         } else {
567                 val1 = (chip->eimage[CS4236_REG(left_reg)] & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
568                 change = val1 != chip->eimage[CS4236_REG(left_reg)];
569                 snd_cs4236_ext_out(chip, left_reg, val1);
570         }
571         spin_unlock_irqrestore(&chip->reg_lock, flags);
572         return change;
573 }
574
575 #define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
576 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
577   .info = snd_cs4236_info_double, \
578   .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
579   .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
580
581 static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
582 {
583         struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
584         unsigned long flags;
585         int left_reg = kcontrol->private_value & 0xff;
586         int right_reg = (kcontrol->private_value >> 8) & 0xff;
587         int shift_left = (kcontrol->private_value >> 16) & 0x07;
588         int shift_right = (kcontrol->private_value >> 19) & 0x07;
589         int mask = (kcontrol->private_value >> 24) & 0xff;
590         int invert = (kcontrol->private_value >> 22) & 1;
591         
592         spin_lock_irqsave(&chip->reg_lock, flags);
593         ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
594         ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask;
595         spin_unlock_irqrestore(&chip->reg_lock, flags);
596         if (invert) {
597                 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
598                 ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
599         }
600         return 0;
601 }
602
603 static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
604 {
605         struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
606         unsigned long flags;
607         int left_reg = kcontrol->private_value & 0xff;
608         int right_reg = (kcontrol->private_value >> 8) & 0xff;
609         int shift_left = (kcontrol->private_value >> 16) & 0x07;
610         int shift_right = (kcontrol->private_value >> 19) & 0x07;
611         int mask = (kcontrol->private_value >> 24) & 0xff;
612         int invert = (kcontrol->private_value >> 22) & 1;
613         int change;
614         unsigned short val1, val2;
615         
616         val1 = ucontrol->value.integer.value[0] & mask;
617         val2 = ucontrol->value.integer.value[1] & mask;
618         if (invert) {
619                 val1 = mask - val1;
620                 val2 = mask - val2;
621         }
622         val1 <<= shift_left;
623         val2 <<= shift_right;
624         spin_lock_irqsave(&chip->reg_lock, flags);
625         val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
626         val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2;
627         change = val1 != chip->image[left_reg] || val2 != chip->eimage[CS4236_REG(right_reg)];
628         snd_wss_out(chip, left_reg, val1);
629         snd_cs4236_ext_out(chip, right_reg, val2);
630         spin_unlock_irqrestore(&chip->reg_lock, flags);
631         return change;
632 }
633
634 #define CS4236_MASTER_DIGITAL(xname, xindex) \
635 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
636   .info = snd_cs4236_info_double, \
637   .get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \
638   .private_value = 71 << 24 }
639
640 static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol)
641 {
642         return (vol < 64) ? 63 - vol : 64 + (71 - vol);
643 }        
644
645 static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
646 {
647         struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
648         unsigned long flags;
649         
650         spin_lock_irqsave(&chip->reg_lock, flags);
651         ucontrol->value.integer.value[0] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & 0x7f);
652         ucontrol->value.integer.value[1] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & 0x7f);
653         spin_unlock_irqrestore(&chip->reg_lock, flags);
654         return 0;
655 }
656
657 static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
658 {
659         struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
660         unsigned long flags;
661         int change;
662         unsigned short val1, val2;
663         
664         val1 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[0] & 0x7f);
665         val2 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[1] & 0x7f);
666         spin_lock_irqsave(&chip->reg_lock, flags);
667         val1 = (chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & ~0x7f) | val1;
668         val2 = (chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & ~0x7f) | val2;
669         change = val1 != chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] || val2 != chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)];
670         snd_cs4236_ext_out(chip, CS4236_LEFT_MASTER, val1);
671         snd_cs4236_ext_out(chip, CS4236_RIGHT_MASTER, val2);
672         spin_unlock_irqrestore(&chip->reg_lock, flags);
673         return change;
674 }
675
676 #define CS4235_OUTPUT_ACCU(xname, xindex) \
677 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
678   .info = snd_cs4236_info_double, \
679   .get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \
680   .private_value = 3 << 24 }
681
682 static inline int snd_cs4235_mixer_output_accu_get_volume(int vol)
683 {
684         switch ((vol >> 5) & 3) {
685         case 0: return 1;
686         case 1: return 3;
687         case 2: return 2;
688         case 3: return 0;
689         }
690         return 3;
691 }
692
693 static inline int snd_cs4235_mixer_output_accu_set_volume(int vol)
694 {
695         switch (vol & 3) {
696         case 0: return 3 << 5;
697         case 1: return 0 << 5;
698         case 2: return 2 << 5;
699         case 3: return 1 << 5;
700         }
701         return 1 << 5;
702 }
703
704 static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
705 {
706         struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
707         unsigned long flags;
708         
709         spin_lock_irqsave(&chip->reg_lock, flags);
710         ucontrol->value.integer.value[0] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_LEFT_MASTER]);
711         ucontrol->value.integer.value[1] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_RIGHT_MASTER]);
712         spin_unlock_irqrestore(&chip->reg_lock, flags);
713         return 0;
714 }
715
716 static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
717 {
718         struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
719         unsigned long flags;
720         int change;
721         unsigned short val1, val2;
722         
723         val1 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[0]);
724         val2 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[1]);
725         spin_lock_irqsave(&chip->reg_lock, flags);
726         val1 = (chip->image[CS4235_LEFT_MASTER] & ~(3 << 5)) | val1;
727         val2 = (chip->image[CS4235_RIGHT_MASTER] & ~(3 << 5)) | val2;
728         change = val1 != chip->image[CS4235_LEFT_MASTER] || val2 != chip->image[CS4235_RIGHT_MASTER];
729         snd_wss_out(chip, CS4235_LEFT_MASTER, val1);
730         snd_wss_out(chip, CS4235_RIGHT_MASTER, val2);
731         spin_unlock_irqrestore(&chip->reg_lock, flags);
732         return change;
733 }
734
735 static struct snd_kcontrol_new snd_cs4236_controls[] = {
736
737 CS4236_DOUBLE("Master Digital Playback Switch", 0,
738                 CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
739 CS4236_DOUBLE("Master Digital Capture Switch", 0,
740                 CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
741 CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
742
743 CS4236_DOUBLE("Capture Boost Volume", 0,
744                 CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
745
746 WSS_DOUBLE("PCM Playback Switch", 0,
747                 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
748 WSS_DOUBLE("PCM Playback Volume", 0,
749                 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
750
751 CS4236_DOUBLE("DSP Playback Switch", 0,
752                 CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
753 CS4236_DOUBLE("DSP Playback Volume", 0,
754                 CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1),
755
756 CS4236_DOUBLE("FM Playback Switch", 0,
757                 CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
758 CS4236_DOUBLE("FM Playback Volume", 0,
759                 CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1),
760
761 CS4236_DOUBLE("Wavetable Playback Switch", 0,
762                 CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
763 CS4236_DOUBLE("Wavetable Playback Volume", 0,
764                 CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1),
765
766 WSS_DOUBLE("Synth Playback Switch", 0,
767                 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
768 WSS_DOUBLE("Synth Volume", 0,
769                 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
770 WSS_DOUBLE("Synth Capture Switch", 0,
771                 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
772 WSS_DOUBLE("Synth Capture Bypass", 0,
773                 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1),
774
775 CS4236_DOUBLE("Mic Playback Switch", 0,
776                 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
777 CS4236_DOUBLE("Mic Capture Switch", 0,
778                 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
779 CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1),
780 CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0,
781                 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0),
782
783 WSS_DOUBLE("Line Playback Switch", 0,
784                 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
785 WSS_DOUBLE("Line Volume", 0,
786                 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
787 WSS_DOUBLE("Line Capture Switch", 0,
788                 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
789 WSS_DOUBLE("Line Capture Bypass", 0,
790                 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1),
791
792 WSS_DOUBLE("CD Playback Switch", 0,
793                 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
794 WSS_DOUBLE("CD Volume", 0,
795                 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
796 WSS_DOUBLE("CD Capture Switch", 0,
797                 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
798
799 CS4236_DOUBLE1("Mono Output Playback Switch", 0,
800                 CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
801 CS4236_DOUBLE1("Beep Playback Switch", 0,
802                 CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
803 WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
804 WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0),
805
806 WSS_DOUBLE("Capture Volume", 0,
807                 CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
808 WSS_DOUBLE("Analog Loopback Capture Switch", 0,
809                 CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
810
811 WSS_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
812 CS4236_DOUBLE1("Digital Loopback Playback Volume", 0,
813                 CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1)
814 };
815
816 static struct snd_kcontrol_new snd_cs4235_controls[] = {
817
818 WSS_DOUBLE("Master Playback Switch", 0,
819                 CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1),
820 WSS_DOUBLE("Master Playback Volume", 0,
821                 CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1),
822
823 CS4235_OUTPUT_ACCU("Playback Volume", 0),
824
825 WSS_DOUBLE("Synth Playback Switch", 1,
826                 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
827 WSS_DOUBLE("Synth Capture Switch", 1,
828                 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
829 WSS_DOUBLE("Synth Volume", 1,
830                 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
831
832 CS4236_DOUBLE("Capture Volume", 0,
833                 CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
834
835 WSS_DOUBLE("PCM Playback Switch", 0,
836                 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
837 WSS_DOUBLE("PCM Capture Switch", 0,
838                 CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
839 WSS_DOUBLE("PCM Volume", 0,
840                 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
841
842 CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
843
844 CS4236_DOUBLE("FM Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
845
846 CS4236_DOUBLE("Wavetable Switch", 0,
847                 CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
848
849 CS4236_DOUBLE("Mic Capture Switch", 0,
850                 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
851 CS4236_DOUBLE("Mic Playback Switch", 0,
852                 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
853 CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1),
854 CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0),
855
856 WSS_DOUBLE("Line Playback Switch", 0,
857                 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
858 WSS_DOUBLE("Line Capture Switch", 0,
859                 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
860 WSS_DOUBLE("Line Volume", 0,
861                 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
862
863 WSS_DOUBLE("CD Playback Switch", 1,
864                 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
865 WSS_DOUBLE("CD Capture Switch", 1,
866                 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
867 WSS_DOUBLE("CD Volume", 1,
868                 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
869
870 CS4236_DOUBLE1("Beep Playback Switch", 0,
871                 CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
872 WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
873
874 WSS_DOUBLE("Analog Loopback Switch", 0,
875                 CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
876 };
877
878 #define CS4236_IEC958_ENABLE(xname, xindex) \
879 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
880   .info = snd_cs4236_info_single, \
881   .get = snd_cs4236_get_iec958_switch, .put = snd_cs4236_put_iec958_switch, \
882   .private_value = 1 << 16 }
883
884 static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
885 {
886         struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
887         unsigned long flags;
888         
889         spin_lock_irqsave(&chip->reg_lock, flags);
890         ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0;
891 #if 0
892         printk(KERN_DEBUG "get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, "
893                "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
894                         snd_wss_in(chip, CS4231_ALT_FEATURE_1),
895                         snd_cs4236_ctrl_in(chip, 3),
896                         snd_cs4236_ctrl_in(chip, 4),
897                         snd_cs4236_ctrl_in(chip, 5),
898                         snd_cs4236_ctrl_in(chip, 6),
899                         snd_cs4236_ctrl_in(chip, 8));
900 #endif
901         spin_unlock_irqrestore(&chip->reg_lock, flags);
902         return 0;
903 }
904
905 static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
906 {
907         struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
908         unsigned long flags;
909         int change;
910         unsigned short enable, val;
911         
912         enable = ucontrol->value.integer.value[0] & 1;
913
914         mutex_lock(&chip->mce_mutex);
915         snd_wss_mce_up(chip);
916         spin_lock_irqsave(&chip->reg_lock, flags);
917         val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1);
918         change = val != chip->image[CS4231_ALT_FEATURE_1];
919         snd_wss_out(chip, CS4231_ALT_FEATURE_1, val);
920         val = snd_cs4236_ctrl_in(chip, 4) | 0xc0;
921         snd_cs4236_ctrl_out(chip, 4, val);
922         udelay(100);
923         val &= ~0x40;
924         snd_cs4236_ctrl_out(chip, 4, val);
925         spin_unlock_irqrestore(&chip->reg_lock, flags);
926         snd_wss_mce_down(chip);
927         mutex_unlock(&chip->mce_mutex);
928
929 #if 0
930         printk(KERN_DEBUG "set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, "
931                "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
932                         snd_wss_in(chip, CS4231_ALT_FEATURE_1),
933                         snd_cs4236_ctrl_in(chip, 3),
934                         snd_cs4236_ctrl_in(chip, 4),
935                         snd_cs4236_ctrl_in(chip, 5),
936                         snd_cs4236_ctrl_in(chip, 6),
937                         snd_cs4236_ctrl_in(chip, 8));
938 #endif
939         return change;
940 }
941
942 static struct snd_kcontrol_new snd_cs4236_iec958_controls[] = {
943 CS4236_IEC958_ENABLE("IEC958 Output Enable", 0),
944 CS4236_SINGLEC("IEC958 Output Validity", 0, 4, 4, 1, 0),
945 CS4236_SINGLEC("IEC958 Output User", 0, 4, 5, 1, 0),
946 CS4236_SINGLEC("IEC958 Output CSBR", 0, 4, 6, 1, 0),
947 CS4236_SINGLEC("IEC958 Output Channel Status Low", 0, 5, 1, 127, 0),
948 CS4236_SINGLEC("IEC958 Output Channel Status High", 0, 6, 0, 255, 0)
949 };
950
951 static struct snd_kcontrol_new snd_cs4236_3d_controls_cs4235[] = {
952 CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0),
953 CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1)
954 };
955
956 static struct snd_kcontrol_new snd_cs4236_3d_controls_cs4237[] = {
957 CS4236_SINGLEC("3D Control - Switch", 0, 3, 7, 1, 0),
958 CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1),
959 CS4236_SINGLEC("3D Control - Center", 0, 2, 0, 15, 1),
960 CS4236_SINGLEC("3D Control - Mono", 0, 3, 6, 1, 0),
961 CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0)
962 };
963
964 static struct snd_kcontrol_new snd_cs4236_3d_controls_cs4238[] = {
965 CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0),
966 CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1),
967 CS4236_SINGLEC("3D Control - Volume", 0, 2, 0, 15, 1),
968 CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0)
969 };
970
971 int snd_cs4236_mixer(struct snd_wss *chip)
972 {
973         struct snd_card *card;
974         unsigned int idx, count;
975         int err;
976         struct snd_kcontrol_new *kcontrol;
977
978         if (snd_BUG_ON(!chip || !chip->card))
979                 return -EINVAL;
980         card = chip->card;
981         strcpy(card->mixername, snd_wss_chip_id(chip));
982
983         if (chip->hardware == WSS_HW_CS4235 ||
984             chip->hardware == WSS_HW_CS4239) {
985                 for (idx = 0; idx < ARRAY_SIZE(snd_cs4235_controls); idx++) {
986                         if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4235_controls[idx], chip))) < 0)
987                                 return err;
988                 }
989         } else {
990                 for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_controls); idx++) {
991                         if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_controls[idx], chip))) < 0)
992                                 return err;
993                 }
994         }
995         switch (chip->hardware) {
996         case WSS_HW_CS4235:
997         case WSS_HW_CS4239:
998                 count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4235);
999                 kcontrol = snd_cs4236_3d_controls_cs4235;
1000                 break;
1001         case WSS_HW_CS4237B:
1002                 count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4237);
1003                 kcontrol = snd_cs4236_3d_controls_cs4237;
1004                 break;
1005         case WSS_HW_CS4238B:
1006                 count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4238);
1007                 kcontrol = snd_cs4236_3d_controls_cs4238;
1008                 break;
1009         default:
1010                 count = 0;
1011                 kcontrol = NULL;
1012         }
1013         for (idx = 0; idx < count; idx++, kcontrol++) {
1014                 if ((err = snd_ctl_add(card, snd_ctl_new1(kcontrol, chip))) < 0)
1015                         return err;
1016         }
1017         if (chip->hardware == WSS_HW_CS4237B ||
1018             chip->hardware == WSS_HW_CS4238B) {
1019                 for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_iec958_controls); idx++) {
1020                         if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_iec958_controls[idx], chip))) < 0)
1021                                 return err;
1022                 }
1023         }
1024         return 0;
1025 }