| Linux kernel & device driver programming |
| [ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] |
1 /* 1
2 * Copyright (c) by Jaroslav Kysela <perex@pe
3 * Routines for control of CS4231(A)/CS4232/I
4 *
5 * Bugs:
6 * - sometimes record brokes playback with
7 * Yamaha OPL3-SA3 chip
8 * - CS4231 (GUS MAX) - still trouble with
9 * - broken initializat
10 *
11 * This program is free software; you can re
12 * it under the terms of the GNU General Pub
13 * the Free Software Foundation; either vers
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope t
17 * but WITHOUT ANY WARRANTY; without even th
18 * MERCHANTABILITY or FITNESS FOR A PARTICUL
19 * GNU General Public License for more detai
20 *
21 * You should have received a copy of the GN
22 * along with this program; if not, write to
23 * Foundation, Inc., 59 Temple Place, Suite
24 *
25 */
26
27 #include <linux/delay.h>
28 #include <linux/pm.h>
29 #include <linux/init.h>
30 #include <linux/interrupt.h>
31 #include <linux/slab.h>
32 #include <linux/ioport.h>
33 #include <sound/core.h>
34 #include <sound/wss.h>
35 #include <sound/pcm_params.h>
36 #include <sound/tlv.h>
37
38 #include <asm/io.h>
39 #include <asm/dma.h>
40 #include <asm/irq.h>
41
42 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz
43 MODULE_DESCRIPTION("Routines for control of CS
44 MODULE_LICENSE("GPL");
45
46 #if 0
47 #define SNDRV_DEBUG_MCE
48 #endif
49
50 /*
51 * Some variables
52 */
53
54 static unsigned char freq_bits[14] = {
55 /* 5510 */ 0x00 | CS4231_XTAL2,
56 /* 6620 */ 0x0E | CS4231_XTAL2,
57 /* 8000 */ 0x00 | CS4231_XTAL1,
58 /* 9600 */ 0x0E | CS4231_XTAL1,
59 /* 11025 */ 0x02 | CS4231_XTAL2,
60 /* 16000 */ 0x02 | CS4231_XTAL1,
61 /* 18900 */ 0x04 | CS4231_XTAL2,
62 /* 22050 */ 0x06 | CS4231_XTAL2,
63 /* 27042 */ 0x04 | CS4231_XTAL1,
64 /* 32000 */ 0x06 | CS4231_XTAL1,
65 /* 33075 */ 0x0C | CS4231_XTAL2,
66 /* 37800 */ 0x08 | CS4231_XTAL2,
67 /* 44100 */ 0x0A | CS4231_XTAL2,
68 /* 48000 */ 0x0C | CS4231_XTAL1
69 };
70
71 static unsigned int rates[14] = {
72 5510, 6620, 8000, 9600, 11025, 16000,
73 27042, 32000, 33075, 37800, 44100, 480
74 };
75
76 static struct snd_pcm_hw_constraint_list hw_co
77 .count = ARRAY_SIZE(rates),
78 .list = rates,
79 .mask = 0,
80 };
81
82 static int snd_wss_xrate(struct snd_pcm_runtim
83 {
84 return snd_pcm_hw_constraint_list(runt
85 &hw_
86 }
87
88 static unsigned char snd_wss_original_image[32
89 {
90 0x00, /* 00/00 - lic
91 0x00, /* 01/01 - ric
92 0x9f, /* 02/02 - la1
93 0x9f, /* 03/03 - ra1
94 0x9f, /* 04/04 - la2
95 0x9f, /* 05/05 - ra2
96 0xbf, /* 06/06 - loc
97 0xbf, /* 07/07 - roc
98 0x20, /* 08/08 - pdf
99 CS4231_AUTOCALIB, /* 09/09 - ic
100 0x00, /* 0a/10 - pc
101 0x00, /* 0b/11 - ti
102 CS4231_MODE2, /* 0c/12 - mi
103 0xfc, /* 0d/13 - lbc
104 0x00, /* 0e/14 - pbr
105 0x00, /* 0f/15 - pbr
106 0x80, /* 10/16 - afe
107 0x01, /* 11/17 - afe
108 0x9f, /* 12/18 - lli
109 0x9f, /* 13/19 - rli
110 0x00, /* 14/20 - tlb
111 0x00, /* 15/21 - thb
112 0x00, /* 16/22 - la3
113 0x00, /* 17/23 - ra3
114 0x00, /* 18/24 - afs
115 0x00, /* 19/25 - lam
116 0xcf, /* 1a/26 - mio
117 0x00, /* 1b/27 - ram
118 0x20, /* 1c/28 - cdf
119 0x00, /* 1d/29 - res
120 0x00, /* 1e/30 - cbr
121 0x00, /* 1f/31 - cbr
122 };
123
124 static unsigned char snd_opti93x_original_imag
125 {
126 0x00, /* 00/00 - l_mixout_ou
127 0x00, /* 01/01 - r_mixout_ou
128 0x88, /* 02/02 - l_cd_inctrl
129 0x88, /* 03/03 - r_cd_inctrl
130 0x88, /* 04/04 - l_a1/fm_inc
131 0x88, /* 05/05 - r_a1/fm_inc
132 0x80, /* 06/06 - l_dac_inctr
133 0x80, /* 07/07 - r_dac_inctr
134 0x00, /* 08/08 - ply_datafor
135 0x00, /* 09/09 - if_conf */
136 0x00, /* 0a/10 - pin_ctrl */
137 0x00, /* 0b/11 - err_init_re
138 0x0a, /* 0c/12 - id_reg */
139 0x00, /* 0d/13 - reserved */
140 0x00, /* 0e/14 - ply_upcount
141 0x00, /* 0f/15 - ply_lowcoun
142 0x88, /* 10/16 - reserved/l_
143 0x88, /* 11/17 - reserved/r_
144 0x88, /* 12/18 - l_line_inct
145 0x88, /* 13/19 - r_line_inct
146 0x88, /* 14/20 - l_mic_inctr
147 0x88, /* 15/21 - r_mic_inctr
148 0x80, /* 16/22 - l_out_outct
149 0x80, /* 17/23 - r_out_outct
150 0x00, /* 18/24 - reserved */
151 0x00, /* 19/25 - reserved */
152 0x00, /* 1a/26 - reserved */
153 0x00, /* 1b/27 - reserved */
154 0x00, /* 1c/28 - cap_datafor
155 0x00, /* 1d/29 - reserved */
156 0x00, /* 1e/30 - cap_upcount
157 0x00 /* 1f/31 - cap_lowcoun
158 };
159
160 /*
161 * Basic I/O functions
162 */
163
164 static inline void wss_outb(struct snd_wss *ch
165 {
166 outb(val, chip->port + offset);
167 }
168
169 static inline u8 wss_inb(struct snd_wss *chip,
170 {
171 return inb(chip->port + offset);
172 }
173
174 static void snd_wss_wait(struct snd_wss *chip)
175 {
176 int timeout;
177
178 for (timeout = 250;
179 timeout > 0 && (wss_inb(chip, CS4
180 timeout--)
181 udelay(100);
182 }
183
184 static void snd_wss_dout(struct snd_wss *chip,
185 unsigned char value)
186 {
187 int timeout;
188
189 for (timeout = 250;
190 timeout > 0 && (wss_inb(chip, CS4
191 timeout--)
192 udelay(10);
193 wss_outb(chip, CS4231P(REGSEL), chip->
194 wss_outb(chip, CS4231P(REG), value);
195 mb();
196 }
197
198 void snd_wss_out(struct snd_wss *chip, unsigne
199 {
200 snd_wss_wait(chip);
201 #ifdef CONFIG_SND_DEBUG
202 if (wss_inb(chip, CS4231P(REGSEL)) & C
203 snd_printk(KERN_DEBUG "out: au
204 "- reg = 0x%x, valu
205 #endif
206 wss_outb(chip, CS4231P(REGSEL), chip->
207 wss_outb(chip, CS4231P(REG), value);
208 chip->image[reg] = value;
209 mb();
210 snd_printdd("codec out - reg 0x%x = 0x
211 chip->mce_bit | reg, v
212 }
213 EXPORT_SYMBOL(snd_wss_out);
214
215 unsigned char snd_wss_in(struct snd_wss *chip,
216 {
217 snd_wss_wait(chip);
218 #ifdef CONFIG_SND_DEBUG
219 if (wss_inb(chip, CS4231P(REGSEL)) & C
220 snd_printk(KERN_DEBUG "in: aut
221 "- reg = 0x%x\n", r
222 #endif
223 wss_outb(chip, CS4231P(REGSEL), chip->
224 mb();
225 return wss_inb(chip, CS4231P(REG));
226 }
227 EXPORT_SYMBOL(snd_wss_in);
228
229 void snd_cs4236_ext_out(struct snd_wss *chip,
230 unsigned char val)
231 {
232 wss_outb(chip, CS4231P(REGSEL), chip->
233 wss_outb(chip, CS4231P(REG),
234 reg | (chip->image[CS4236_EXT
235 wss_outb(chip, CS4231P(REG), val);
236 chip->eimage[CS4236_REG(reg)] = val;
237 #if 0
238 printk(KERN_DEBUG "ext out : reg = 0x%
239 #endif
240 }
241 EXPORT_SYMBOL(snd_cs4236_ext_out);
242
243 unsigned char snd_cs4236_ext_in(struct snd_wss
244 {
245 wss_outb(chip, CS4231P(REGSEL), chip->
246 wss_outb(chip, CS4231P(REG),
247 reg | (chip->image[CS4236_EXT
248 #if 1
249 return wss_inb(chip, CS4231P(REG));
250 #else
251 {
252 unsigned char res;
253 res = wss_inb(chip, CS4231P(RE
254 printk(KERN_DEBUG "ext in : re
255 reg, res);
256 return res;
257 }
258 #endif
259 }
260 EXPORT_SYMBOL(snd_cs4236_ext_in);
261
262 #if 0
263
264 static void snd_wss_debug(struct snd_wss *chip
265 {
266 printk(KERN_DEBUG
267 "CS4231 REGS: INDEX = 0x%
268 " STATUS = 0x%
269 wss_in
270 wss_in
271 printk(KERN_DEBUG
272 " 0x00: left input = 0x%
273 " 0x10: alt 1 (CFIG 2) = 0x%
274 snd_ws
275 snd_ws
276 printk(KERN_DEBUG
277 " 0x01: right input = 0x%
278 " 0x11: alt 2 (CFIG 3) = 0x%
279 snd_ws
280 snd_ws
281 printk(KERN_DEBUG
282 " 0x02: GF1 left input = 0x%
283 " 0x12: left line in = 0x%
284 snd_ws
285 snd_ws
286 printk(KERN_DEBUG
287 " 0x03: GF1 right input = 0x%
288 " 0x13: right line in = 0x%
289 snd_ws
290 snd_ws
291 printk(KERN_DEBUG
292 " 0x04: CD left input = 0x%
293 " 0x14: timer low = 0x%
294 snd_ws
295 snd_ws
296 printk(KERN_DEBUG
297 " 0x05: CD right input = 0x%
298 " 0x15: timer high = 0x%
299 snd_ws
300 snd_ws
301 printk(KERN_DEBUG
302 " 0x06: left output = 0x%
303 " 0x16: left MIC (PnP) = 0x%
304 snd_ws
305 snd_ws
306 printk(KERN_DEBUG
307 " 0x07: right output = 0x%
308 " 0x17: right MIC (PnP) = 0x%
309 snd_ws
310 snd_ws
311 printk(KERN_DEBUG
312 " 0x08: playback format = 0x%
313 " 0x18: IRQ status = 0x%
314 snd_ws
315 snd_ws
316 printk(KERN_DEBUG
317 " 0x09: iface (CFIG 1) = 0x%
318 " 0x19: left line out = 0x%
319 snd_ws
320 snd_ws
321 printk(KERN_DEBUG
322 " 0x0a: pin control = 0x%
323 " 0x1a: mono control = 0x%
324 snd_ws
325 snd_ws
326 printk(KERN_DEBUG
327 " 0x0b: init & status = 0x%
328 " 0x1b: right line out = 0x%
329 snd_ws
330 snd_ws
331 printk(KERN_DEBUG
332 " 0x0c: revision & mode = 0x%
333 " 0x1c: record format = 0x%
334 snd_ws
335 snd_ws
336 printk(KERN_DEBUG
337 " 0x0d: loopback = 0x%
338 " 0x1d: var freq (PnP) = 0x%
339 snd_ws
340 snd_ws
341 printk(KERN_DEBUG
342 " 0x0e: ply upr count = 0x%
343 " 0x1e: ply lwr count = 0x%
344 snd_ws
345 snd_ws
346 printk(KERN_DEBUG
347 " 0x0f: rec upr count = 0x%
348 " 0x1f: rec lwr count = 0x%
349 snd_ws
350 snd_ws
351 }
352
353 #endif
354
355 /*
356 * CS4231 detection / MCE routines
357 */
358
359 static void snd_wss_busy_wait(struct snd_wss *
360 {
361 int timeout;
362
363 /* huh.. looks like this sequence is p
364 for (timeout = 5; timeout > 0; timeout
365 wss_inb(chip, CS4231P(REGSEL))
366 /* end of cleanup sequence */
367 for (timeout = 25000;
368 timeout > 0 && (wss_inb(chip, CS4
369 timeout--)
370 udelay(10);
371 }
372
373 void snd_wss_mce_up(struct snd_wss *chip)
374 {
375 unsigned long flags;
376 int timeout;
377
378 snd_wss_wait(chip);
379 #ifdef CONFIG_SND_DEBUG
380 if (wss_inb(chip, CS4231P(REGSEL)) & C
381 snd_printk(KERN_DEBUG
382 "mce_up - auto cali
383 #endif
384 spin_lock_irqsave(&chip->reg_lock, fla
385 chip->mce_bit |= CS4231_MCE;
386 timeout = wss_inb(chip, CS4231P(REGSEL
387 if (timeout == 0x80)
388 snd_printk(KERN_DEBUG "mce_up
389 "serious init probl
390 chip->port);
391 if (!(timeout & CS4231_MCE))
392 wss_outb(chip, CS4231P(REGSEL)
393 chip->mce_bit | (time
394 spin_unlock_irqrestore(&chip->reg_lock
395 }
396 EXPORT_SYMBOL(snd_wss_mce_up);
397
398 void snd_wss_mce_down(struct snd_wss *chip)
399 {
400 unsigned long flags;
401 unsigned long end_time;
402 int timeout;
403 int hw_mask = WSS_HW_CS4231_MASK | WSS
404
405 snd_wss_busy_wait(chip);
406
407 #ifdef CONFIG_SND_DEBUG
408 if (wss_inb(chip, CS4231P(REGSEL)) & C
409 snd_printk(KERN_DEBUG "mce_dow
410 "auto calibration t
411 (long)CS4231P(REGSE
412 #endif
413 spin_lock_irqsave(&chip->reg_lock, fla
414 chip->mce_bit &= ~CS4231_MCE;
415 timeout = wss_inb(chip, CS4231P(REGSEL
416 wss_outb(chip, CS4231P(REGSEL), chip->
417 spin_unlock_irqrestore(&chip->reg_lock
418 if (timeout == 0x80)
419 snd_printk(KERN_DEBUG "mce_dow
420 "serious init probl
421 chip->port);
422 if ((timeout & CS4231_MCE) == 0 || !(c
423 return;
424
425 /*
426 * Wait for (possible -- during init a
427 * calibration process to start. Needs
428 * which at the slowest possible rate
429 */
430 msleep(1);
431
432 snd_printdd("(1) jiffies = %lu\n", jif
433
434 /* check condition up to 250 ms */
435 end_time = jiffies + msecs_to_jiffies(
436 while (snd_wss_in(chip, CS4231_TEST_IN
437 CS4231_CALIB_IN_PROGRESS) {
438
439 if (time_after(jiffies, end_ti
440 snd_printk(KERN_ERR "m
441 "auto
442 return;
443 }
444 msleep(1);
445 }
446
447 snd_printdd("(2) jiffies = %lu\n", jif
448
449 /* check condition up to 100 ms */
450 end_time = jiffies + msecs_to_jiffies(
451 while (wss_inb(chip, CS4231P(REGSEL))
452 if (time_after(jiffies, end_ti
453 snd_printk(KERN_ERR "m
454 return;
455 }
456 msleep(1);
457 }
458
459 snd_printdd("(3) jiffies = %lu\n", jif
460 snd_printd("mce_down - exit = 0x%x\n",
461 }
462 EXPORT_SYMBOL(snd_wss_mce_down);
463
464 static unsigned int snd_wss_get_count(unsigned
465 {
466 switch (format & 0xe0) {
467 case CS4231_LINEAR_16:
468 case CS4231_LINEAR_16_BIG:
469 size >>= 1;
470 break;
471 case CS4231_ADPCM_16:
472 return size >> 2;
473 }
474 if (format & CS4231_STEREO)
475 size >>= 1;
476 return size;
477 }
478
479 static int snd_wss_trigger(struct snd_pcm_subs
480 int cmd)
481 {
482 struct snd_wss *chip = snd_pcm_substre
483 int result = 0;
484 unsigned int what;
485 struct snd_pcm_substream *s;
486 int do_start;
487
488 switch (cmd) {
489 case SNDRV_PCM_TRIGGER_START:
490 case SNDRV_PCM_TRIGGER_RESUME:
491 do_start = 1; break;
492 case SNDRV_PCM_TRIGGER_STOP:
493 case SNDRV_PCM_TRIGGER_SUSPEND:
494 do_start = 0; break;
495 default:
496 return -EINVAL;
497 }
498
499 what = 0;
500 snd_pcm_group_for_each_entry(s, substr
501 if (s == chip->playback_substr
502 what |= CS4231_PLAYBAC
503 snd_pcm_trigger_done(s
504 } else if (s == chip->capture_
505 what |= CS4231_RECORD_
506 snd_pcm_trigger_done(s
507 }
508 }
509 spin_lock(&chip->reg_lock);
510 if (do_start) {
511 chip->image[CS4231_IFACE_CTRL]
512 if (chip->trigger)
513 chip->trigger(chip, wh
514 } else {
515 chip->image[CS4231_IFACE_CTRL]
516 if (chip->trigger)
517 chip->trigger(chip, wh
518 }
519 snd_wss_out(chip, CS4231_IFACE_CTRL, c
520 spin_unlock(&chip->reg_lock);
521 #if 0
522 snd_wss_debug(chip);
523 #endif
524 return result;
525 }
526
527 /*
528 * CODEC I/O
529 */
530
531 static unsigned char snd_wss_get_rate(unsigned
532 {
533 int i;
534
535 for (i = 0; i < ARRAY_SIZE(rates); i++
536 if (rate == rates[i])
537 return freq_bits[i];
538 // snd_BUG();
539 return freq_bits[ARRAY_SIZE(rates) - 1
540 }
541
542 static unsigned char snd_wss_get_format(struct
543 int fo
544 int ch
545 {
546 unsigned char rformat;
547
548 rformat = CS4231_LINEAR_8;
549 switch (format) {
550 case SNDRV_PCM_FORMAT_MU_LAW: rforma
551 case SNDRV_PCM_FORMAT_A_LAW: rforma
552 case SNDRV_PCM_FORMAT_S16_LE: rforma
553 case SNDRV_PCM_FORMAT_S16_BE: rforma
554 case SNDRV_PCM_FORMAT_IMA_ADPCM:
555 }
556 if (channels > 1)
557 rformat |= CS4231_STEREO;
558 #if 0
559 snd_printk(KERN_DEBUG "get_format: 0x%
560 #endif
561 return rformat;
562 }
563
564 static void snd_wss_calibrate_mute(struct snd_
565 {
566 unsigned long flags;
567
568 mute = mute ? 0x80 : 0;
569 spin_lock_irqsave(&chip->reg_lock, fla
570 if (chip->calibrate_mute == mute) {
571 spin_unlock_irqrestore(&chip->
572 return;
573 }
574 if (!mute) {
575 snd_wss_dout(chip, CS4231_LEFT
576 chip->image[CS423
577 snd_wss_dout(chip, CS4231_RIGH
578 chip->image[CS423
579 snd_wss_dout(chip, CS4231_LOOP
580 chip->image[CS423
581 } else {
582 snd_wss_dout(chip, CS4231_LEFT
583 0);
584 snd_wss_dout(chip, CS4231_RIGH
585 0);
586 snd_wss_dout(chip, CS4231_LOOP
587 0xfd);
588 }
589
590 snd_wss_dout(chip, CS4231_AUX1_LEFT_IN
591 mute | chip->image[CS4231
592 snd_wss_dout(chip, CS4231_AUX1_RIGHT_I
593 mute | chip->image[CS4231
594 snd_wss_dout(chip, CS4231_AUX2_LEFT_IN
595 mute | chip->image[CS4231
596 snd_wss_dout(chip, CS4231_AUX2_RIGHT_I
597 mute | chip->image[CS4231
598 snd_wss_dout(chip, CS4231_LEFT_OUTPUT,
599 mute | chip->image[CS4231
600 snd_wss_dout(chip, CS4231_RIGHT_OUTPUT
601 mute | chip->image[CS4231
602 if (!(chip->hardware & WSS_HW_AD1848_M
603 snd_wss_dout(chip, CS4231_LEFT
604 mute | chip->imag
605 snd_wss_dout(chip, CS4231_RIGH
606 mute | chip->imag
607 snd_wss_dout(chip, CS4231_MONO
608 mute ? 0xc0 : chi
609 }
610 if (chip->hardware == WSS_HW_INTERWAVE
611 snd_wss_dout(chip, CS4231_LEFT
612 mute | chip->imag
613 snd_wss_dout(chip, CS4231_RIGH
614 mute | chip->imag
615 snd_wss_dout(chip, CS4231_LINE
616 mute | chip->imag
617 snd_wss_dout(chip, CS4231_LINE
618 mute | chip->imag
619 }
620 chip->calibrate_mute = mute;
621 spin_unlock_irqrestore(&chip->reg_lock
622 }
623
624 static void snd_wss_playback_format(struct snd
625 struct
626 unsigne
627 {
628 unsigned long flags;
629 int full_calib = 1;
630
631 mutex_lock(&chip->mce_mutex);
632 if (chip->hardware == WSS_HW_CS4231A |
633 (chip->hardware & WSS_HW_CS4232_MA
634 spin_lock_irqsave(&chip->reg_l
635 if ((chip->image[CS4231_PLAYBK
636 snd_wss_out(chip, CS42
637 chip->imag
638 chip->image[CS4231_PLA
639 snd_wss_out(chip, CS42
640 chip->imag
641 snd_wss_out(chip, CS42
642 chip->imag
643 udelay(100); /* Fixes
644 full_calib = 0;
645 }
646 spin_unlock_irqrestore(&chip->
647 } else if (chip->hardware == WSS_HW_AD
648 unsigned rate = params_rate(pa
649
650 /*
651 * Program the AD1845 correctl
652 * Note that we do NOT need to
653 * the PLAYBACK_ENABLE bit of
654 * register is set.
655 *
656 * NOTE: We seem to need to wr
657 * to get the correct sa
658 */
659 spin_lock_irqsave(&chip->reg_l
660 snd_wss_out(chip, CS4231_PLAYB
661 snd_wss_out(chip, AD1845_UPR_F
662 snd_wss_out(chip, AD1845_LWR_F
663 full_calib = 0;
664 spin_unlock_irqrestore(&chip->
665 }
666 if (full_calib) {
667 snd_wss_mce_up(chip);
668 spin_lock_irqsave(&chip->reg_l
669 if (chip->hardware != WSS_HW_I
670 if (chip->image[CS4231
671 pdfr = (pdfr &
672 (chip->
673 } else {
674 chip->image[CS4231_PLA
675 }
676 snd_wss_out(chip, CS4231_PLAYB
677 spin_unlock_irqrestore(&chip->
678 if (chip->hardware == WSS_HW_O
679 udelay(100); /* thi
680 snd_wss_mce_down(chip);
681 }
682 mutex_unlock(&chip->mce_mutex);
683 }
684
685 static void snd_wss_capture_format(struct snd_
686 struct snd_
687 unsigned ch
688 {
689 unsigned long flags;
690 int full_calib = 1;
691
692 mutex_lock(&chip->mce_mutex);
693 if (chip->hardware == WSS_HW_CS4231A |
694 (chip->hardware & WSS_HW_CS4232_MA
695 spin_lock_irqsave(&chip->reg_l
696 if ((chip->image[CS4231_PLAYBK
697 (chip->image[CS4231_IFACE_
698 snd_wss_out(chip, CS42
699 chip->image[CS
700 snd_wss_out(chip, CS42
701 chip->image[CS
702 snd_wss_out(chip, CS42
703 chip->image[CS
704 full_calib = 0;
705 }
706 spin_unlock_irqrestore(&chip->
707 } else if (chip->hardware == WSS_HW_AD
708 unsigned rate = params_rate(pa
709
710 /*
711 * Program the AD1845 correctl
712 * Note that we do NOT need to
713 * the PLAYBACK_ENABLE bit of
714 * register is set.
715 *
716 * NOTE: We seem to need to wr
717 * to get the correct sa
718 */
719 spin_lock_irqsave(&chip->reg_l
720 snd_wss_out(chip, CS4231_REC_F
721 snd_wss_out(chip, AD1845_UPR_F
722 snd_wss_out(chip, AD1845_LWR_F
723 full_calib = 0;
724 spin_unlock_irqrestore(&chip->
725 }
726 if (full_calib) {
727 snd_wss_mce_up(chip);
728 spin_lock_irqsave(&chip->reg_l
729 if (chip->hardware != WSS_HW_I
730 !(chip->image[CS4231_IFACE
731 if (chip->single_dma)
732 snd_wss_out(ch
733 else
734 snd_wss_out(ch
735 (chip->imag
736 (cdfr & 0x0
737 spin_unlock_irqrestore
738 snd_wss_mce_down(chip)
739 snd_wss_mce_up(chip);
740 spin_lock_irqsave(&chi
741 }
742 if (chip->hardware & WSS_HW_AD
743 snd_wss_out(chip, CS42
744 else
745 snd_wss_out(chip, CS42
746 spin_unlock_irqrestore(&chip->
747 snd_wss_mce_down(chip);
748 }
749 mutex_unlock(&chip->mce_mutex);
750 }
751
752 /*
753 * Timer interface
754 */
755
756 static unsigned long snd_wss_timer_resolution(
757 {
758 struct snd_wss *chip = snd_timer_chip(
759 if (chip->hardware & WSS_HW_CS4236B_MA
760 return 14467;
761 else
762 return chip->image[CS4231_PLAY
763 }
764
765 static int snd_wss_timer_start(struct snd_time
766 {
767 unsigned long flags;
768 unsigned int ticks;
769 struct snd_wss *chip = snd_timer_chip(
770 spin_lock_irqsave(&chip->reg_lock, fla
771 ticks = timer->sticks;
772 if ((chip->image[CS4231_ALT_FEATURE_1]
773 (unsigned char)(ticks >> 8) != chi
774 (unsigned char)ticks != chip->imag
775 chip->image[CS4231_TIMER_HIGH]
776 snd_wss_out(chip, CS4231_TIMER
777 chip->image[CS4231
778 chip->image[CS4231_TIMER_LOW]
779 snd_wss_out(chip, CS4231_TIMER
780 chip->image[CS4231
781 snd_wss_out(chip, CS4231_ALT_F
782 chip->image[CS4231
783 CS4231_TIMER_ENABL
784 }
785 spin_unlock_irqrestore(&chip->reg_lock
786 return 0;
787 }
788
789 static int snd_wss_timer_stop(struct snd_timer
790 {
791 unsigned long flags;
792 struct snd_wss *chip = snd_timer_chip(
793 spin_lock_irqsave(&chip->reg_lock, fla
794 chip->image[CS4231_ALT_FEATURE_1] &= ~
795 snd_wss_out(chip, CS4231_ALT_FEATURE_1
796 chip->image[CS4231_ALT_FEA
797 spin_unlock_irqrestore(&chip->reg_lock
798 return 0;
799 }
800
801 static void snd_wss_init(struct snd_wss *chip)
802 {
803 unsigned long flags;
804
805 snd_wss_calibrate_mute(chip, 1);
806 snd_wss_mce_down(chip);
807
808 #ifdef SNDRV_DEBUG_MCE
809 snd_printk(KERN_DEBUG "init: (1)\n");
810 #endif
811 snd_wss_mce_up(chip);
812 spin_lock_irqsave(&chip->reg_lock, fla
813 chip->image[CS4231_IFACE_CTRL] &= ~(CS
814 CS
815 CS
816 CS
817 CS
818 chip->image[CS4231_IFACE_CTRL] |= CS42
819 snd_wss_out(chip, CS4231_IFACE_CTRL, c
820 spin_unlock_irqrestore(&chip->reg_lock
821 snd_wss_mce_down(chip);
822
823 #ifdef SNDRV_DEBUG_MCE
824 snd_printk(KERN_DEBUG "init: (2)\n");
825 #endif
826
827 snd_wss_mce_up(chip);
828 spin_lock_irqsave(&chip->reg_lock, fla
829 chip->image[CS4231_IFACE_CTRL] &= ~CS4
830 snd_wss_out(chip, CS4231_IFACE_CTRL, c
831 snd_wss_out(chip,
832 CS4231_ALT_FEATURE_1, chip
833 spin_unlock_irqrestore(&chip->reg_lock
834 snd_wss_mce_down(chip);
835
836 #ifdef SNDRV_DEBUG_MCE
837 snd_printk(KERN_DEBUG "init: (3) - afe
838 chip->image[CS4231_ALT_FEAT
839 #endif
840
841 spin_lock_irqsave(&chip->reg_lock, fla
842 snd_wss_out(chip, CS4231_ALT_FEATURE_2
843 chip->image[CS4231_ALT_FEA
844 spin_unlock_irqrestore(&chip->reg_lock
845
846 snd_wss_mce_up(chip);
847 spin_lock_irqsave(&chip->reg_lock, fla
848 snd_wss_out(chip, CS4231_PLAYBK_FORMAT
849 chip->image[CS4231_PLAYBK_
850 spin_unlock_irqrestore(&chip->reg_lock
851 snd_wss_mce_down(chip);
852
853 #ifdef SNDRV_DEBUG_MCE
854 snd_printk(KERN_DEBUG "init: (4)\n");
855 #endif
856
857 snd_wss_mce_up(chip);
858 spin_lock_irqsave(&chip->reg_lock, fla
859 if (!(chip->hardware & WSS_HW_AD1848_M
860 snd_wss_out(chip, CS4231_REC_F
861 chip->image[CS4231
862 spin_unlock_irqrestore(&chip->reg_lock
863 snd_wss_mce_down(chip);
864 snd_wss_calibrate_mute(chip, 0);
865
866 #ifdef SNDRV_DEBUG_MCE
867 snd_printk(KERN_DEBUG "init: (5)\n");
868 #endif
869 }
870
871 static int snd_wss_open(struct snd_wss *chip,
872 {
873 unsigned long flags;
874
875 mutex_lock(&chip->open_mutex);
876 if ((chip->mode & mode) ||
877 ((chip->mode & WSS_MODE_OPEN) && c
878 mutex_unlock(&chip->open_mutex
879 return -EAGAIN;
880 }
881 if (chip->mode & WSS_MODE_OPEN) {
882 chip->mode |= mode;
883 mutex_unlock(&chip->open_mutex
884 return 0;
885 }
886 /* ok. now enable and ack CODEC IRQ */
887 spin_lock_irqsave(&chip->reg_lock, fla
888 if (!(chip->hardware & WSS_HW_AD1848_M
889 snd_wss_out(chip, CS4231_IRQ_S
890 CS4231_PLAYBACK_IR
891 CS4231_RECORD_IRQ
892 CS4231_TIMER_IRQ);
893 snd_wss_out(chip, CS4231_IRQ_S
894 }
895 wss_outb(chip, CS4231P(STATUS), 0);
896 wss_outb(chip, CS4231P(STATUS), 0);
897 chip->image[CS4231_PIN_CTRL] |= CS4231
898 snd_wss_out(chip, CS4231_PIN_CTRL, chi
899 if (!(chip->hardware & WSS_HW_AD1848_M
900 snd_wss_out(chip, CS4231_IRQ_S
901 CS4231_PLAYBACK_IR
902 CS4231_RECORD_IRQ
903 CS4231_TIMER_IRQ);
904 snd_wss_out(chip, CS4231_IRQ_S
905 }
906 spin_unlock_irqrestore(&chip->reg_lock
907
908 chip->mode = mode;
909 mutex_unlock(&chip->open_mutex);
910 return 0;
911 }
912
913 static void snd_wss_close(struct snd_wss *chip
914 {
915 unsigned long flags;
916
917 mutex_lock(&chip->open_mutex);
918 chip->mode &= ~mode;
919 if (chip->mode & WSS_MODE_OPEN) {
920 mutex_unlock(&chip->open_mutex
921 return;
922 }
923 /* disable IRQ */
924 spin_lock_irqsave(&chip->reg_lock, fla
925 if (!(chip->hardware & WSS_HW_AD1848_M
926 snd_wss_out(chip, CS4231_IRQ_S
927 wss_outb(chip, CS4231P(STATUS), 0);
928 wss_outb(chip, CS4231P(STATUS), 0);
929 chip->image[CS4231_PIN_CTRL] &= ~CS423
930 snd_wss_out(chip, CS4231_PIN_CTRL, chi
931
932 /* now disable record & playback */
933
934 if (chip->image[CS4231_IFACE_CTRL] & (
935
936 spin_unlock_irqrestore(&chip->
937 snd_wss_mce_up(chip);
938 spin_lock_irqsave(&chip->reg_l
939 chip->image[CS4231_IFACE_CTRL]
940
941 snd_wss_out(chip, CS4231_IFACE
942 chip->image[CS4231
943 spin_unlock_irqrestore(&chip->
944 snd_wss_mce_down(chip);
945 spin_lock_irqsave(&chip->reg_l
946 }
947
948 /* clear IRQ again */
949 if (!(chip->hardware & WSS_HW_AD1848_M
950 snd_wss_out(chip, CS4231_IRQ_S
951 wss_outb(chip, CS4231P(STATUS), 0);
952 wss_outb(chip, CS4231P(STATUS), 0);
953 spin_unlock_irqrestore(&chip->reg_lock
954
955 chip->mode = 0;
956 mutex_unlock(&chip->open_mutex);
957 }
958
959 /*
960 * timer open/close
961 */
962
963 static int snd_wss_timer_open(struct snd_timer
964 {
965 struct snd_wss *chip = snd_timer_chip(
966 snd_wss_open(chip, WSS_MODE_TIMER);
967 return 0;
968 }
969
970 static int snd_wss_timer_close(struct snd_time
971 {
972 struct snd_wss *chip = snd_timer_chip(
973 snd_wss_close(chip, WSS_MODE_TIMER);
974 return 0;
975 }
976
977 static struct snd_timer_hardware snd_wss_timer
978 {
979 .flags = SNDRV_TIMER_HW_AUTO,
980 .resolution = 9945,
981 .ticks = 65535,
982 .open = snd_wss_timer_open,
983 .close = snd_wss_timer_close,
984 .c_resolution = snd_wss_timer_resoluti
985 .start = snd_wss_timer_start,
986 .stop = snd_wss_timer_stop,
987 };
988
989 /*
990 * ok.. exported functions..
991 */
992
993 static int snd_wss_playback_hw_params(struct s
994 struc
995 {
996 struct snd_wss *chip = snd_pcm_substre
997 unsigned char new_pdfr;
998 int err;
999
1000 if ((err = snd_pcm_lib_malloc_pages(s
1001 return err;
1002 new_pdfr = snd_wss_get_format(chip, p
1003 params_channe
1004 snd_wss_get_r
1005 chip->set_playback_format(chip, hw_pa
1006 return 0;
1007 }
1008
1009 static int snd_wss_playback_hw_free(struct sn
1010 {
1011 return snd_pcm_lib_free_pages(substre
1012 }
1013
1014 static int snd_wss_playback_prepare(struct sn
1015 {
1016 struct snd_wss *chip = snd_pcm_substr
1017 struct snd_pcm_runtime *runtime = sub
1018 unsigned long flags;
1019 unsigned int size = snd_pcm_lib_buffe
1020 unsigned int count = snd_pcm_lib_peri
1021
1022 spin_lock_irqsave(&chip->reg_lock, fl
1023 chip->p_dma_size = size;
1024 chip->image[CS4231_IFACE_CTRL] &= ~(C
1025 snd_dma_program(chip->dma1, runtime->
1026 count = snd_wss_get_count(chip->image
1027 snd_wss_out(chip, CS4231_PLY_LWR_CNT,
1028 snd_wss_out(chip, CS4231_PLY_UPR_CNT,
1029 spin_unlock_irqrestore(&chip->reg_loc
1030 #if 0
1031 snd_wss_debug(chip);
1032 #endif
1033 return 0;
1034 }
1035
1036 static int snd_wss_capture_hw_params(struct s
1037 struc
1038 {
1039 struct snd_wss *chip = snd_pcm_substr
1040 unsigned char new_cdfr;
1041 int err;
1042
1043 if ((err = snd_pcm_lib_malloc_pages(s
1044 return err;
1045 new_cdfr = snd_wss_get_format(chip, p
1046 params_channels(hw
1047 snd_wss_get_rate(p
1048 chip->set_capture_format(chip, hw_par
1049 return 0;
1050 }
1051
1052 static int snd_wss_capture_hw_free(struct snd
1053 {
1054 return snd_pcm_lib_free_pages(substre
1055 }
1056
1057 static int snd_wss_capture_prepare(struct snd
1058 {
1059 struct snd_wss *chip = snd_pcm_substr
1060 struct snd_pcm_runtime *runtime = sub
1061 unsigned long flags;
1062 unsigned int size = snd_pcm_lib_buffe
1063 unsigned int count = snd_pcm_lib_peri
1064
1065 spin_lock_irqsave(&chip->reg_lock, fl
1066 chip->c_dma_size = size;
1067 chip->image[CS4231_IFACE_CTRL] &= ~(C
1068 snd_dma_program(chip->dma2, runtime->
1069 if (chip->hardware & WSS_HW_AD1848_MA
1070 count = snd_wss_get_count(chi
1071 cou
1072 else
1073 count = snd_wss_get_count(chi
1074 cou
1075 count--;
1076 if (chip->single_dma && chip->hardwar
1077 snd_wss_out(chip, CS4231_PLY_
1078 snd_wss_out(chip, CS4231_PLY_
1079 (unsigned char) (
1080 } else {
1081 snd_wss_out(chip, CS4231_REC_
1082 snd_wss_out(chip, CS4231_REC_
1083 (unsigned char) (
1084 }
1085 spin_unlock_irqrestore(&chip->reg_loc
1086 return 0;
1087 }
1088
1089 void snd_wss_overrange(struct snd_wss *chip)
1090 {
1091 unsigned long flags;
1092 unsigned char res;
1093
1094 spin_lock_irqsave(&chip->reg_lock, fl
1095 res = snd_wss_in(chip, CS4231_TEST_IN
1096 spin_unlock_irqrestore(&chip->reg_loc
1097 if (res & (0x08 | 0x02)) /* de
1098 chip->capture_substream->runt
1099 }
1100 EXPORT_SYMBOL(snd_wss_overrange);
1101
1102 irqreturn_t snd_wss_interrupt(int irq, void *
1103 {
1104 struct snd_wss *chip = dev_id;
1105 unsigned char status;
1106
1107 if (chip->hardware & WSS_HW_AD1848_MA
1108 /* pretend it was the only po
1109 status = CS4231_PLAYBACK_IRQ;
1110 else
1111 status = snd_wss_in(chip, CS4
1112 if (status & CS4231_TIMER_IRQ) {
1113 if (chip->timer)
1114 snd_timer_interrupt(c
1115 }
1116 if (chip->single_dma && chip->hardwar
1117 if (status & CS4231_PLAYBACK_
1118 if (chip->mode & WSS_
1119 if (chip->pla
1120 snd_p
1121 }
1122 if (chip->mode & WSS_
1123 if (chip->cap
1124 snd_w
1125 snd_p
1126 }
1127 }
1128 }
1129 } else {
1130 if (status & CS4231_PLAYBACK_
1131 if (chip->playback_su
1132 snd_pcm_perio
1133 }
1134 if (status & CS4231_RECORD_IR
1135 if (chip->capture_sub
1136 snd_wss_overr
1137 snd_pcm_perio
1138 }
1139 }
1140 }
1141
1142 spin_lock(&chip->reg_lock);
1143 status = ~CS4231_ALL_IRQS | ~status;
1144 if (chip->hardware & WSS_HW_AD1848_MA
1145 wss_outb(chip, CS4231P(STATUS
1146 else
1147 snd_wss_out(chip, CS4231_IRQ_
1148 spin_unlock(&chip->reg_lock);
1149 return IRQ_HANDLED;
1150 }
1151 EXPORT_SYMBOL(snd_wss_interrupt);
1152
1153 static snd_pcm_uframes_t snd_wss_playback_poi
1154 {
1155 struct snd_wss *chip = snd_pcm_substr
1156 size_t ptr;
1157
1158 if (!(chip->image[CS4231_IFACE_CTRL]
1159 return 0;
1160 ptr = snd_dma_pointer(chip->dma1, chi
1161 return bytes_to_frames(substream->run
1162 }
1163
1164 static snd_pcm_uframes_t snd_wss_capture_poin
1165 {
1166 struct snd_wss *chip = snd_pcm_substr
1167 size_t ptr;
1168
1169 if (!(chip->image[CS4231_IFACE_CTRL]
1170 return 0;
1171 ptr = snd_dma_pointer(chip->dma2, chi
1172 return bytes_to_frames(substream->run
1173 }
1174
1175 /*
1176
1177 */
1178
1179 static int snd_ad1848_probe(struct snd_wss *c
1180 {
1181 unsigned long timeout = jiffies + mse
1182 unsigned long flags;
1183 unsigned char r;
1184 unsigned short hardware = 0;
1185 int err = 0;
1186 int i;
1187
1188 while (wss_inb(chip, CS4231P(REGSEL))
1189 if (time_after(jiffies, timeo
1190 return -ENODEV;
1191 cond_resched();
1192 }
1193 spin_lock_irqsave(&chip->reg_lock, fl
1194
1195 /* set CS423x MODE 1 */
1196 snd_wss_dout(chip, CS4231_MISC_INFO,
1197
1198 snd_wss_dout(chip, CS4231_RIGHT_INPUT
1199 r = snd_wss_in(chip, CS4231_RIGHT_INP
1200 if (r != 0x45) {
1201 /* RMGE always high on AD1847
1202 if ((r & ~CS4231_ENABLE_MIC_G
1203 err = -ENODEV;
1204 goto out;
1205 }
1206 hardware = WSS_HW_AD1847;
1207 } else {
1208 snd_wss_dout(chip, CS4231_LEF
1209 r = snd_wss_in(chip, CS4231_L
1210 /* L/RMGE always low on AT232
1211 if ((r | CS4231_ENABLE_MIC_GA
1212 err = -ENODEV;
1213 goto out;
1214 }
1215 }
1216
1217 /* clear pending IRQ */
1218 wss_inb(chip, CS4231P(STATUS));
1219 wss_outb(chip, CS4231P(STATUS), 0);
1220 mb();
1221
1222 if ((chip->hardware & WSS_HW_TYPE_MAS
1223 goto out;
1224
1225 if (hardware) {
1226 chip->hardware = hardware;
1227 goto out;
1228 }
1229
1230 r = snd_wss_in(chip, CS4231_MISC_INFO
1231
1232 /* set CS423x MODE 2 */
1233 snd_wss_dout(chip, CS4231_MISC_INFO,
1234 for (i = 0; i < 16; i++) {
1235 if (snd_wss_in(chip, i) != sn
1236 /* we have more than
1237 if ((r & 0xf) != 0xa)
1238 goto out_mode
1239 /*
1240 * on CMI8330, CS4231
1241 * can be set to 0
1242 */
1243 snd_wss_dout(chip, CS
1244 r = snd_wss_in(chip,
1245 if (!r)
1246 chip->hardwar
1247 goto out_mode;
1248 }
1249 }
1250 if (r & 0x80)
1251 chip->hardware = WSS_HW_CS424
1252 else
1253 chip->hardware = WSS_HW_AD184
1254 out_mode:
1255 snd_wss_dout(chip, CS4231_MISC_INFO,
1256 out:
1257 spin_unlock_irqrestore(&chip->reg_loc
1258 return err;
1259 }
1260
1261 static int snd_wss_probe(struct snd_wss *chip
1262 {
1263 unsigned long flags;
1264 int i, id, rev, regnum;
1265 unsigned char *ptr;
1266 unsigned int hw;
1267
1268 id = snd_ad1848_probe(chip);
1269 if (id < 0)
1270 return id;
1271
1272 hw = chip->hardware;
1273 if ((hw & WSS_HW_TYPE_MASK) == WSS_HW
1274 for (i = 0; i < 50; i++) {
1275 mb();
1276 if (wss_inb(chip, CS4
1277 msleep(2);
1278 else {
1279 spin_lock_irq
1280 snd_wss_out(c
1281 C
1282 id = snd_wss_
1283 spin_unlock_i
1284 if (id == 0x0
1285 break
1286 }
1287 }
1288 snd_printdd("wss: port = 0x%l
1289 if (id != 0x0a)
1290 return -ENODEV; /* no
1291
1292 rev = snd_wss_in(chip, CS4231
1293 snd_printdd("CS4231: VERSION
1294 if (rev == 0x80) {
1295 unsigned char tmp = s
1296 snd_wss_out(chip, 23,
1297 if (snd_wss_in(chip,
1298 chip->hardwar
1299 else
1300 chip->hardwar
1301 } else if (rev == 0xa0) {
1302 chip->hardware = WSS_
1303 } else if (rev == 0xa2) {
1304 chip->hardware = WSS_
1305 } else if (rev == 0xb2) {
1306 chip->hardware = WSS_
1307 } else if (rev == 0x83) {
1308 chip->hardware = WSS_
1309 } else if (rev == 0x03) {
1310 chip->hardware = WSS_
1311 } else {
1312 snd_printk(KERN_ERR
1313 "unknown C
1314 return -ENODEV;
1315 }
1316 }
1317 spin_lock_irqsave(&chip->reg_lock, fl
1318 wss_inb(chip, CS4231P(STATUS)); /* cl
1319 wss_outb(chip, CS4231P(STATUS), 0);
1320 mb();
1321 spin_unlock_irqrestore(&chip->reg_loc
1322
1323 if (!(chip->hardware & WSS_HW_AD1848_
1324 chip->image[CS4231_MISC_INFO]
1325 switch (chip->hardware) {
1326 case WSS_HW_INTERWAVE:
1327 chip->image[CS4231_MISC_INFO]
1328 break;
1329 case WSS_HW_CS4235:
1330 case WSS_HW_CS4236B:
1331 case WSS_HW_CS4237B:
1332 case WSS_HW_CS4238B:
1333 case WSS_HW_CS4239:
1334 if (hw == WSS_HW_DETECT3)
1335 chip->image[CS4231_MI
1336 else
1337 chip->hardware = WSS_
1338 break;
1339 }
1340
1341 chip->image[CS4231_IFACE_CTRL] =
1342 (chip->image[CS4231_IFACE_CTRL] &
1343 (chip->single_dma ? CS4231_SINGLE
1344 if (chip->hardware != WSS_HW_OPTI93X)
1345 chip->image[CS4231_ALT_FEATUR
1346 chip->image[CS4231_ALT_FEATUR
1347 chip->hardware == WSS
1348 }
1349 /* enable fine grained frequency sele
1350 if (chip->hardware == WSS_HW_AD1845)
1351 chip->image[AD1845_PWR_DOWN]
1352
1353 ptr = (unsigned char *) &chip->image;
1354 regnum = (chip->hardware & WSS_HW_AD1
1355 snd_wss_mce_down(chip);
1356 spin_lock_irqsave(&chip->reg_lock, fl
1357 for (i = 0; i < regnum; i++) /* ok
1358 snd_wss_out(chip, i, *ptr++);
1359 spin_unlock_irqrestore(&chip->reg_loc
1360 snd_wss_mce_up(chip);
1361 snd_wss_mce_down(chip);
1362
1363 mdelay(2);
1364
1365 /* ok.. try check hardware version fo
1366 if ((hw & WSS_HW_TYPE_MASK) == WSS_HW
1367 if (chip->hardware == WSS_HW_
1368 rev = snd_cs4236_ext_
1369 snd_cs4236_ext_out(ch
1370 id = snd_cs4236_ext_i
1371 snd_cs4236_ext_out(ch
1372 snd_printdd("CS4231:
1373 if ((id & 0x1f) == 0x
1374 chip->hardwar
1375 switch (id >>
1376 case 4:
1377 case 5:
1378 case 6:
1379 break
1380 default:
1381 snd_p
1382
1383
1384
1385 }
1386 } else if ((id & 0x1f
1387 switch (id >>
1388 case 4:
1389 case 5:
1390 case 6:
1391 case 7:
1392 chip-
1393 break
1394 default:
1395 snd_p
1396
1397
1398
1399 }
1400 } else if ((id & 0x1f
1401 chip->hardwar
1402 switch (id >>
1403 case 4:
1404 case 5:
1405 case 6:
1406 case 7:
1407 break
1408 default:
1409 snd_p
1410
1411
1412
1413 }
1414 } else if ((id & 0x1f
1415 chip->hardwar
1416 switch (id >>
1417 case 5:
1418 case 6:
1419 case 7:
1420 break
1421 default:
1422 snd_p
1423
1424
1425
1426 }
1427 } else if ((id & 0x1f
1428 chip->hardwar
1429 switch (id >>
1430 case 4:
1431 case 5:
1432 case 6:
1433 break
1434 default:
1435 snd_p
1436
1437
1438
1439 }
1440 } else {
1441 snd_printk(KE
1442 "u
1443 "(
1444 }
1445 }
1446 }
1447 return 0; /* all things
1448 }
1449
1450 /*
1451
1452 */
1453
1454 static struct snd_pcm_hardware snd_wss_playba
1455 {
1456 .info = (SNDRV_PCM_IN
1457 SNDRV_PCM_IN
1458 SNDRV_PCM_IN
1459 SNDRV_PCM_IN
1460 .formats = (SNDRV_PCM_FM
1461 SNDRV_PCM_FM
1462 .rates = SNDRV_PCM_RAT
1463 .rate_min = 5510,
1464 .rate_max = 48000,
1465 .channels_min = 1,
1466 .channels_max = 2,
1467 .buffer_bytes_max = (128*1024),
1468 .period_bytes_min = 64,
1469 .period_bytes_max = (128*1024),
1470 .periods_min = 1,
1471 .periods_max = 1024,
1472 .fifo_size = 0,
1473 };
1474
1475 static struct snd_pcm_hardware snd_wss_captur
1476 {
1477 .info = (SNDRV_PCM_IN
1478 SNDRV_PCM_IN
1479 SNDRV_PCM_IN
1480 SNDRV_PCM_IN
1481 .formats = (SNDRV_PCM_FM
1482 SNDRV_PCM_FM
1483 .rates = SNDRV_PCM_RAT
1484 .rate_min = 5510,
1485 .rate_max = 48000,
1486 .channels_min = 1,
1487 .channels_max = 2,
1488 .buffer_bytes_max = (128*1024),
1489 .period_bytes_min = 64,
1490 .period_bytes_max = (128*1024),
1491 .periods_min = 1,
1492 .periods_max = 1024,
1493 .fifo_size = 0,
1494 };
1495
1496 /*
1497
1498 */
1499
1500 static int snd_wss_playback_open(struct snd_p
1501 {
1502 struct snd_wss *chip = snd_pcm_substr
1503 struct snd_pcm_runtime *runtime = sub
1504 int err;
1505
1506 runtime->hw = snd_wss_playback;
1507
1508 /* hardware limitation of older chips
1509 if (chip->hardware & WSS_HW_AD1848_MA
1510 runtime->hw.formats &= ~(SNDR
1511 SNDR
1512
1513 /* hardware bug in InterWave chipset
1514 if (chip->hardware == WSS_HW_INTERWAV
1515 runtime->hw.formats &= ~SNDRV
1516
1517 /* hardware limitation of cheap chips
1518 if (chip->hardware == WSS_HW_CS4235 |
1519 chip->hardware == WSS_HW_CS4239)
1520 runtime->hw.formats = SNDRV_P
1521
1522 snd_pcm_limit_isa_dma_size(chip->dma1
1523 snd_pcm_limit_isa_dma_size(chip->dma1
1524
1525 if (chip->claim_dma) {
1526 if ((err = chip->claim_dma(ch
1527 return err;
1528 }
1529
1530 err = snd_wss_open(chip, WSS_MODE_PLA
1531 if (err < 0) {
1532 if (chip->release_dma)
1533 chip->release_dma(chi
1534 snd_free_pages(runtime->dma_a
1535 return err;
1536 }
1537 chip->playback_substream = substream;
1538 snd_pcm_set_sync(substream);
1539 chip->rate_constraint(runtime);
1540 return 0;
1541 }
1542
1543 static int snd_wss_capture_open(struct snd_pc
1544 {
1545 struct snd_wss *chip = snd_pcm_substr
1546 struct snd_pcm_runtime *runtime = sub
1547 int err;
1548
1549 runtime->hw = snd_wss_capture;
1550
1551 /* hardware limitation of older chips
1552 if (chip->hardware & WSS_HW_AD1848_MA
1553 runtime->hw.formats &= ~(SNDR
1554 SNDR
1555
1556 /* hardware limitation of cheap chips
1557 if (chip->hardware == WSS_HW_CS4235 |
1558 chip->hardware == WSS_HW_CS4239 |
1559 chip->hardware == WSS_HW_OPTI93X)
1560 runtime->hw.formats = SNDRV_P
1561 SNDRV_P
1562
1563 snd_pcm_limit_isa_dma_size(chip->dma2
1564 snd_pcm_limit_isa_dma_size(chip->dma2
1565
1566 if (chip->claim_dma) {
1567 if ((err = chip->claim_dma(ch
1568 return err;
1569 }
1570
1571 err = snd_wss_open(chip, WSS_MODE_REC
1572 if (err < 0) {
1573 if (chip->release_dma)
1574 chip->release_dma(chi
1575 snd_free_pages(runtime->dma_a
1576 return err;
1577 }
1578 chip->capture_substream = substream;
1579 snd_pcm_set_sync(substream);
1580 chip->rate_constraint(runtime);
1581 return 0;
1582 }
1583
1584 static int snd_wss_playback_close(struct snd_
1585 {
1586 struct snd_wss *chip = snd_pcm_substr
1587
1588 chip->playback_substream = NULL;
1589 snd_wss_close(chip, WSS_MODE_PLAY);
1590 return 0;
1591 }
1592
1593 static int snd_wss_capture_close(struct snd_p
1594 {
1595 struct snd_wss *chip = snd_pcm_substr
1596
1597 chip->capture_substream = NULL;
1598 snd_wss_close(chip, WSS_MODE_RECORD);
1599 return 0;
1600 }
1601
1602 static void snd_wss_thinkpad_twiddle(struct s
1603 {
1604 int tmp;
1605
1606 if (!chip->thinkpad_flag)
1607 return;
1608
1609 outb(0x1c, AD1848_THINKPAD_CTL_PORT1)
1610 tmp = inb(AD1848_THINKPAD_CTL_PORT2);
1611
1612 if (on)
1613 /* turn it on */
1614 tmp |= AD1848_THINKPAD_CS4248
1615 else
1616 /* turn it off */
1617 tmp &= ~AD1848_THINKPAD_CS424
1618
1619 outb(tmp, AD1848_THINKPAD_CTL_PORT2);
1620 }
1621
1622 #ifdef CONFIG_PM
1623
1624 /* lowlevel suspend callback for CS4231 */
1625 static void snd_wss_suspend(struct snd_wss *c
1626 {
1627 int reg;
1628 unsigned long flags;
1629
1630 snd_pcm_suspend_all(chip->pcm);
1631 spin_lock_irqsave(&chip->reg_lock, fl
1632 for (reg = 0; reg < 32; reg++)
1633 chip->image[reg] = snd_wss_in
1634 spin_unlock_irqrestore(&chip->reg_loc
1635 if (chip->thinkpad_flag)
1636 snd_wss_thinkpad_twiddle(chip
1637 }
1638
1639 /* lowlevel resume callback for CS4231 */
1640 static void snd_wss_resume(struct snd_wss *ch
1641 {
1642 int reg;
1643 unsigned long flags;
1644 /* int timeout; */
1645
1646 if (chip->thinkpad_flag)
1647 snd_wss_thinkpad_twiddle(chip
1648 snd_wss_mce_up(chip);
1649 spin_lock_irqsave(&chip->reg_lock, fl
1650 for (reg = 0; reg < 32; reg++) {
1651 switch (reg) {
1652 case CS4231_VERSION:
1653 break;
1654 default:
1655 snd_wss_out(chip, reg
1656 break;
1657 }
1658 }
1659 spin_unlock_irqrestore(&chip->reg_loc
1660 #if 1
1661 snd_wss_mce_down(chip);
1662 #else
1663 /* The following is a workaround to a
1664 This is the first half of copy of
1665 include rescheduling. -- iwai
1666 */
1667 snd_wss_busy_wait(chip);
1668 spin_lock_irqsave(&chip->reg_lock, fl
1669 chip->mce_bit &= ~CS4231_MCE;
1670 timeout = wss_inb(chip, CS4231P(REGSE
1671 wss_outb(chip, CS4231P(REGSEL), chip-
1672 spin_unlock_irqrestore(&chip->reg_loc
1673 if (timeout == 0x80)
1674 snd_printk(KERN_ERR "down [0x
1675 "- codec still bus
1676 if ((timeout & CS4231_MCE) == 0 ||
1677 !(chip->hardware & (WSS_HW_CS4231
1678 return;
1679 }
1680 snd_wss_busy_wait(chip);
1681 #endif
1682 }
1683 #endif /* CONFIG_PM */
1684
1685 int snd_wss_free(struct snd_wss *chip)
1686 {
1687 release_and_free_resource(chip->res_p
1688 release_and_free_resource(chip->res_c
1689 if (chip->irq >= 0) {
1690 disable_irq(chip->irq);
1691 if (!(chip->hwshare & WSS_HWS
1692 free_irq(chip->irq, (
1693 }
1694 if (!(chip->hwshare & WSS_HWSHARE_DMA
1695 snd_dma_disable(chip->dma1);
1696 free_dma(chip->dma1);
1697 }
1698 if (!(chip->hwshare & WSS_HWSHARE_DMA
1699 chip->dma2 >= 0 && chip->dma2 !=
1700 snd_dma_disable(chip->dma2);
1701 free_dma(chip->dma2);
1702 }
1703 if (chip->timer)
1704 snd_device_free(chip->card, c
1705 kfree(chip);
1706 return 0;
1707 }
1708 EXPORT_SYMBOL(snd_wss_free);
1709
1710 static int snd_wss_dev_free(struct snd_device
1711 {
1712 struct snd_wss *chip = device->device
1713 return snd_wss_free(chip);
1714 }
1715
1716 const char *snd_wss_chip_id(struct snd_wss *c
1717 {
1718 switch (chip->hardware) {
1719 case WSS_HW_CS4231:
1720 return "CS4231";
1721 case WSS_HW_CS4231A:
1722 return "CS4231A";
1723 case WSS_HW_CS4232:
1724 return "CS4232";
1725 case WSS_HW_CS4232A:
1726 return "CS4232A";
1727 case WSS_HW_CS4235:
1728 return "CS4235";
1729 case WSS_HW_CS4236:
1730 return "CS4236";
1731 case WSS_HW_CS4236B:
1732 return "CS4236B";
1733 case WSS_HW_CS4237B:
1734 return "CS4237B";
1735 case WSS_HW_CS4238B:
1736 return "CS4238B";
1737 case WSS_HW_CS4239:
1738 return "CS4239";
1739 case WSS_HW_INTERWAVE:
1740 return "AMD InterWave";
1741 case WSS_HW_OPL3SA2:
1742 return chip->card->shortname;
1743 case WSS_HW_AD1845:
1744 return "AD1845";
1745 case WSS_HW_OPTI93X:
1746 return "OPTi 93x";
1747 case WSS_HW_AD1847:
1748 return "AD1847";
1749 case WSS_HW_AD1848:
1750 return "AD1848";
1751 case WSS_HW_CS4248:
1752 return "CS4248";
1753 case WSS_HW_CMI8330:
1754 return "CMI8330/C3D";
1755 default:
1756 return "???";
1757 }
1758 }
1759 EXPORT_SYMBOL(snd_wss_chip_id);
1760
1761 static int snd_wss_new(struct snd_card *card,
1762 unsigned short hard
1763 unsigned short hwsh
1764 struct snd_wss **rc
1765 {
1766 struct snd_wss *chip;
1767
1768 *rchip = NULL;
1769 chip = kzalloc(sizeof(*chip), GFP_KER
1770 if (chip == NULL)
1771 return -ENOMEM;
1772 chip->hardware = hardware;
1773 chip->hwshare = hwshare;
1774
1775 spin_lock_init(&chip->reg_lock);
1776 mutex_init(&chip->mce_mutex);
1777 mutex_init(&chip->open_mutex);
1778 chip->card = card;
1779 chip->rate_constraint = snd_wss_xrate
1780 chip->set_playback_format = snd_wss_p
1781 chip->set_capture_format = snd_wss_ca
1782 if (chip->hardware == WSS_HW_OPTI93X)
1783 memcpy(&chip->image, &snd_opt
1784 sizeof(snd_opti93x_ori
1785 else
1786 memcpy(&chip->image, &snd_wss
1787 sizeof(snd_wss_origina
1788 if (chip->hardware & WSS_HW_AD1848_MA
1789 chip->image[CS4231_PIN_CTRL]
1790 chip->image[CS4231_TEST_INIT]
1791 }
1792
1793 *rchip = chip;
1794 return 0;
1795 }
1796
1797 int snd_wss_create(struct snd_card *card,
1798 unsigned long port,
1799 unsigned long cport,
1800 int irq, int dma1, int
1801 unsigned short hardware
1802 unsigned short hwshare,
1803 struct snd_wss **rchip)
1804 {
1805 static struct snd_device_ops ops = {
1806 .dev_free = snd_wss_dev_f
1807 };
1808 struct snd_wss *chip;
1809 int err;
1810
1811 err = snd_wss_new(card, hardware, hws
1812 if (err < 0)
1813 return err;
1814
1815 chip->irq = -1;
1816 chip->dma1 = -1;
1817 chip->dma2 = -1;
1818
1819 chip->res_port = request_region(port,
1820 if (!chip->res_port) {
1821 snd_printk(KERN_ERR "wss: can
1822 snd_wss_free(chip);
1823 return -EBUSY;
1824 }
1825 chip->port = port;
1826 if ((long)cport >= 0) {
1827 chip->res_cport = request_reg
1828 if (!chip->res_cport) {
1829 snd_printk(KERN_ERR
1830 "wss: can't g
1831 snd_wss_free(chip);
1832 return -ENODEV;
1833 }
1834 }
1835 chip->cport = cport;
1836 if (!(hwshare & WSS_HWSHARE_IRQ))
1837 if (request_irq(irq, snd_wss_
1838 "WSS", (void
1839 snd_printk(KERN_ERR "
1840 snd_wss_free(chip);
1841 return -EBUSY;
1842 }
1843 chip->irq = irq;
1844 if (!(hwshare & WSS_HWSHARE_DMA1) &&
1845 snd_printk(KERN_ERR "wss: can
1846 snd_wss_free(chip);
1847 return -EBUSY;
1848 }
1849 chip->dma1 = dma1;
1850 if (!(hwshare & WSS_HWSHARE_DMA2) &&
1851 dma2 >= 0 && request_dma(dma2,
1852 snd_printk(KERN_ERR "wss: can
1853 snd_wss_free(chip);
1854 return -EBUSY;
1855 }
1856 if (dma1 == dma2 || dma2 < 0) {
1857 chip->single_dma = 1;
1858 chip->dma2 = chip->dma1;
1859 } else
1860 chip->dma2 = dma2;
1861
1862 if (hardware == WSS_HW_THINKPAD) {
1863 chip->thinkpad_flag = 1;
1864 chip->hardware = WSS_HW_DETEC
1865 snd_wss_thinkpad_twiddle(chip
1866 }
1867
1868 /* global setup */
1869 if (snd_wss_probe(chip) < 0) {
1870 snd_wss_free(chip);
1871 return -ENODEV;
1872 }
1873 snd_wss_init(chip);
1874
1875 #if 0
1876 if (chip->hardware & WSS_HW_CS4232_MA
1877 if (chip->res_cport == NULL)
1878 snd_printk(KERN_ERR "
1879 "not acces
1880 }
1881 #endif
1882
1883 /* Register device */
1884 err = snd_device_new(card, SNDRV_DEV_
1885 if (err < 0) {
1886 snd_wss_free(chip);
1887 return err;
1888 }
1889
1890 #ifdef CONFIG_PM
1891 /* Power Management */
1892 chip->suspend = snd_wss_suspend;
1893 chip->resume = snd_wss_resume;
1894 #endif
1895
1896 *rchip = chip;
1897 return 0;
1898 }
1899 EXPORT_SYMBOL(snd_wss_create);
1900
1901 static struct snd_pcm_ops snd_wss_playback_op
1902 .open = snd_wss_playback_open
1903 .close = snd_wss_playback_clos
1904 .ioctl = snd_pcm_lib_ioctl,
1905 .hw_params = snd_wss_playback_hw_p
1906 .hw_free = snd_wss_playback_hw_f
1907 .prepare = snd_wss_playback_prep
1908 .trigger = snd_wss_trigger,
1909 .pointer = snd_wss_playback_poin
1910 };
1911
1912 static struct snd_pcm_ops snd_wss_capture_ops
1913 .open = snd_wss_capture_open,
1914 .close = snd_wss_capture_close
1915 .ioctl = snd_pcm_lib_ioctl,
1916 .hw_params = snd_wss_capture_hw_pa
1917 .hw_free = snd_wss_capture_hw_fr
1918 .prepare = snd_wss_capture_prepa
1919 .trigger = snd_wss_trigger,
1920 .pointer = snd_wss_capture_point
1921 };
1922
1923 int snd_wss_pcm(struct snd_wss *chip, int dev
1924 {
1925 struct snd_pcm *pcm;
1926 int err;
1927
1928 err = snd_pcm_new(chip->card, "WSS",
1929 if (err < 0)
1930 return err;
1931
1932 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM
1933 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM
1934
1935 /* global setup */
1936 pcm->private_data = chip;
1937 pcm->info_flags = 0;
1938 if (chip->single_dma)
1939 pcm->info_flags |= SNDRV_PCM_
1940 if (chip->hardware != WSS_HW_INTERWAV
1941 pcm->info_flags |= SNDRV_PCM_
1942 strcpy(pcm->name, snd_wss_chip_id(chi
1943
1944 snd_pcm_lib_preallocate_pages_for_all
1945
1946
1947
1948 chip->pcm = pcm;
1949 if (rpcm)
1950 *rpcm = pcm;
1951 return 0;
1952 }
1953 EXPORT_SYMBOL(snd_wss_pcm);
1954
1955 static void snd_wss_timer_free(struct snd_tim
1956 {
1957 struct snd_wss *chip = timer->private
1958 chip->timer = NULL;
1959 }
1960
1961 int snd_wss_timer(struct snd_wss *chip, int d
1962 {
1963 struct snd_timer *timer;
1964 struct snd_timer_id tid;
1965 int err;
1966
1967 /* Timer initialization */
1968 tid.dev_class = SNDRV_TIMER_CLASS_CAR
1969 tid.dev_sclass = SNDRV_TIMER_SCLASS_N
1970 tid.card = chip->card->number;
1971 tid.device = device;
1972 tid.subdevice = 0;
1973 if ((err = snd_timer_new(chip->card,
1974 return err;
1975 strcpy(timer->name, snd_wss_chip_id(c
1976 timer->private_data = chip;
1977 timer->private_free = snd_wss_timer_f
1978 timer->hw = snd_wss_timer_table;
1979 chip->timer = timer;
1980 if (rtimer)
1981 *rtimer = timer;
1982 return 0;
1983 }
1984 EXPORT_SYMBOL(snd_wss_timer);
1985
1986 /*
1987 * MIXER part
1988 */
1989
1990 static int snd_wss_info_mux(struct snd_kcontr
1991 struct snd_ctl_el
1992 {
1993 static char *texts[4] = {
1994 "Line", "Aux", "Mic", "Mix"
1995 };
1996 static char *opl3sa_texts[4] = {
1997 "Line", "CD", "Mic", "Mix"
1998 };
1999 static char *gusmax_texts[4] = {
2000 "Line", "Synth", "Mic", "Mix"
2001 };
2002 char **ptexts = texts;
2003 struct snd_wss *chip = snd_kcontrol_c
2004
2005 if (snd_BUG_ON(!chip->card))
2006 return -EINVAL;
2007 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENU
2008 uinfo->count = 2;
2009 uinfo->value.enumerated.items = 4;
2010 if (uinfo->value.enumerated.item > 3)
2011 uinfo->value.enumerated.item
2012 if (!strcmp(chip->card->driver, "GUS
2013 ptexts = gusmax_texts;
2014 switch (chip->hardware) {
2015 case WSS_HW_INTERWAVE:
2016 ptexts = gusmax_texts;
2017 break;
2018 case WSS_HW_OPL3SA2:
2019 ptexts = opl3sa_texts;
2020 break;
2021 }
2022 strcpy(uinfo->value.enumerated.name,
2023 return 0;
2024 }
2025
2026 static int snd_wss_get_mux(struct snd_kcontro
2027 struct snd_ctl_ele
2028 {
2029 struct snd_wss *chip = snd_kcontrol_c
2030 unsigned long flags;
2031
2032 spin_lock_irqsave(&chip->reg_lock, fl
2033 ucontrol->value.enumerated.item[0] =
2034 ucontrol->value.enumerated.item[1] =
2035 spin_unlock_irqrestore(&chip->reg_loc
2036 return 0;
2037 }
2038
2039 static int snd_wss_put_mux(struct snd_kcontro
2040 struct snd_ctl_ele
2041 {
2042 struct snd_wss *chip = snd_kcontrol_c
2043 unsigned long flags;
2044 unsigned short left, right;
2045 int change;
2046
2047 if (ucontrol->value.enumerated.item[0
2048 ucontrol->value.enumerated.item[1
2049 return -EINVAL;
2050 left = ucontrol->value.enumerated.ite
2051 right = ucontrol->value.enumerated.it
2052 spin_lock_irqsave(&chip->reg_lock, fl
2053 left = (chip->image[CS4231_LEFT_INPUT
2054 right = (chip->image[CS4231_RIGHT_INP
2055 change = left != chip->image[CS4231_L
2056 right != chip->image[CS4231_
2057 snd_wss_out(chip, CS4231_LEFT_INPUT,
2058 snd_wss_out(chip, CS4231_RIGHT_INPUT,
2059 spin_unlock_irqrestore(&chip->reg_loc
2060 return change;
2061 }
2062
2063 int snd_wss_info_single(struct snd_kcontrol *
2064 struct snd_ctl_elem_i
2065 {
2066 int mask = (kcontrol->private_value >
2067
2068 uinfo->type = mask == 1 ? SNDRV_CTL_E
2069 uinfo->count = 1;
2070 uinfo->value.integer.min = 0;
2071 uinfo->value.integer.max = mask;
2072 return 0;
2073 }
2074 EXPORT_SYMBOL(snd_wss_info_single);
2075
2076 int snd_wss_get_single(struct snd_kcontrol *k
2077 struct snd_ctl_elem_va
2078 {
2079 struct snd_wss *chip = snd_kcontrol_c
2080 unsigned long flags;
2081 int reg = kcontrol->private_value & 0
2082 int shift = (kcontrol->private_value
2083 int mask = (kcontrol->private_value >
2084 int invert = (kcontrol->private_value
2085
2086 spin_lock_irqsave(&chip->reg_lock, fl
2087 ucontrol->value.integer.value[0] = (c
2088 spin_unlock_irqrestore(&chip->reg_loc
2089 if (invert)
2090 ucontrol->value.integer.value
2091 return 0;
2092 }
2093 EXPORT_SYMBOL(snd_wss_get_single);
2094
2095 int snd_wss_put_single(struct snd_kcontrol *k
2096 struct snd_ctl_elem_va
2097 {
2098 struct snd_wss *chip = snd_kcontrol_c
2099 unsigned long flags;
2100 int reg = kcontrol->private_value & 0
2101 int shift = (kcontrol->private_value
2102 int mask = (kcontrol->private_value >
2103 int invert = (kcontrol->private_value
2104 int change;
2105 unsigned short val;
2106
2107 val = (ucontrol->value.integer.value[
2108 if (invert)
2109 val = mask - val;
2110 val <<= shift;
2111 spin_lock_irqsave(&chip->reg_lock, fl
2112 val = (chip->image[reg] & ~(mask << s
2113 change = val != chip->image[reg];
2114 snd_wss_out(chip, reg, val);
2115 spin_unlock_irqrestore(&chip->reg_loc
2116 return change;
2117 }
2118 EXPORT_SYMBOL(snd_wss_put_single);
2119
2120 int snd_wss_info_double(struct snd_kcontrol *
2121 struct snd_ctl_elem_i
2122 {
2123 int mask = (kcontrol->private_value >
2124
2125 uinfo->type = mask == 1 ? SNDRV_CTL_E
2126 uinfo->count = 2;
2127 uinfo->value.integer.min = 0;
2128 uinfo->value.integer.max = mask;
2129 return 0;
2130 }
2131 EXPORT_SYMBOL(snd_wss_info_double);
2132
2133 int snd_wss_get_double(struct snd_kcontrol *k
2134 struct snd_ctl_elem_va
2135 {
2136 struct snd_wss *chip = snd_kcontrol_c
2137 unsigned long flags;
2138 int left_reg = kcontrol->private_valu
2139 int right_reg = (kcontrol->private_va
2140 int shift_left = (kcontrol->private_v
2141 int shift_right = (kcontrol->private_
2142 int mask = (kcontrol->private_value >
2143 int invert = (kcontrol->private_value
2144
2145 spin_lock_irqsave(&chip->reg_lock, fl
2146 ucontrol->value.integer.value[0] = (c
2147 ucontrol->value.integer.value[1] = (c
2148 spin_unlock_irqrestore(&chip->reg_loc
2149 if (invert) {
2150 ucontrol->value.integer.value
2151 ucontrol->value.integer.value
2152 }
2153 return 0;
2154 }
2155 EXPORT_SYMBOL(snd_wss_get_double);
2156
2157 int snd_wss_put_double(struct snd_kcontrol *k
2158 struct snd_ctl_elem_va
2159 {
2160 struct snd_wss *chip = snd_kcontrol_c
2161 unsigned long flags;
2162 int left_reg = kcontrol->private_valu
2163 int right_reg = (kcontrol->private_va
2164 int shift_left = (kcontrol->private_v
2165 int shift_right = (kcontrol->private_
2166 int mask = (kcontrol->private_value >
2167 int invert = (kcontrol->private_value
2168 int change;
2169 unsigned short val1, val2;
2170
2171 val1 = ucontrol->value.integer.value[
2172 val2 = ucontrol->value.integer.value[
2173 if (invert) {
2174 val1 = mask - val1;
2175 val2 = mask - val2;
2176 }
2177 val1 <<= shift_left;
2178 val2 <<= shift_right;
2179 spin_lock_irqsave(&chip->reg_lock, fl
2180 if (left_reg != right_reg) {
2181 val1 = (chip->image[left_reg]
2182 val2 = (chip->image[right_reg
2183 change = val1 != chip->image[
2184 val2 != chip->image[
2185 snd_wss_out(chip, left_reg, v
2186 snd_wss_out(chip, right_reg,
2187 } else {
2188 mask = (mask << shift_left) |
2189 val1 = (chip->image[left_reg]
2190 change = val1 != chip->image[
2191 snd_wss_out(chip, left_reg, v
2192 }
2193 spin_unlock_irqrestore(&chip->reg_loc
2194 return change;
2195 }
2196 EXPORT_SYMBOL(snd_wss_put_double);
2197
2198 static const DECLARE_TLV_DB_SCALE(db_scale_6b
2199 static const DECLARE_TLV_DB_SCALE(db_scale_5b
2200 static const DECLARE_TLV_DB_SCALE(db_scale_re
2201
2202 static struct snd_kcontrol_new snd_ad1848_con
2203 WSS_DOUBLE("PCM Playback Switch", 0, CS4231_L
2204 7, 7, 1, 1),
2205 WSS_DOUBLE_TLV("PCM Playback Volume", 0,
2206 CS4231_LEFT_OUTPUT, CS4231_RIG
2207 db_scale_6bit),
2208 WSS_DOUBLE("Aux Playback Switch", 0,
2209 CS4231_AUX1_LEFT_INPUT, CS4231_AUX
2210 WSS_DOUBLE_TLV("Aux Playback Volume", 0,
2211 CS4231_AUX1_LEFT_INPUT, CS4231
2212 db_scale_5bit_12db_max),
2213 WSS_DOUBLE("Aux Playback Switch", 1,
2214 CS4231_AUX2_LEFT_INPUT, CS4231_AUX
2215 WSS_DOUBLE_TLV("Aux Playback Volume", 1,
2216 CS4231_AUX2_LEFT_INPUT, CS4231
2217 db_scale_5bit_12db_max),
2218 WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LE
2219 0, 0, 15, 0, db_scale_rec_gai
2220 {
2221 .name = "Capture Source",
2222 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2223 .info = snd_wss_info_mux,
2224 .get = snd_wss_get_mux,
2225 .put = snd_wss_put_mux,
2226 },
2227 WSS_SINGLE("Loopback Capture Switch", 0, CS42
2228 WSS_SINGLE_TLV("Loopback Capture Volume", 0,
2229 db_scale_6bit),
2230 };
2231
2232 static struct snd_kcontrol_new snd_wss_contro
2233 WSS_DOUBLE("PCM Playback Switch", 0,
2234 CS4231_LEFT_OUTPUT, CS4231_RI
2235 WSS_DOUBLE("PCM Playback Volume", 0,
2236 CS4231_LEFT_OUTPUT, CS4231_RI
2237 WSS_DOUBLE("Line Playback Switch", 0,
2238 CS4231_LEFT_LINE_IN, CS4231_R
2239 WSS_DOUBLE("Line Playback Volume", 0,
2240 CS4231_LEFT_LINE_IN, CS4231_R
2241 WSS_DOUBLE("Aux Playback Switch", 0,
2242 CS4231_AUX1_LEFT_INPUT, CS423
2243 WSS_DOUBLE("Aux Playback Volume", 0,
2244 CS4231_AUX1_LEFT_INPUT, CS423
2245 WSS_DOUBLE("Aux Playback Switch", 1,
2246 CS4231_AUX2_LEFT_INPUT, CS423
2247 WSS_DOUBLE("Aux Playback Volume", 1,
2248 CS4231_AUX2_LEFT_INPUT, CS423
2249 WSS_SINGLE("Mono Playback Switch", 0,
2250 CS4231_MONO_CTRL, 7, 1, 1),
2251 WSS_SINGLE("Mono Playback Volume", 0,
2252 CS4231_MONO_CTRL, 0, 15, 1),
2253 WSS_SINGLE("Mono Output Playback Switch", 0,
2254 CS4231_MONO_CTRL, 6, 1, 1),
2255 WSS_SINGLE("Mono Output Playback Bypass", 0,
2256 CS4231_MONO_CTRL, 5, 1, 0),
2257 WSS_DOUBLE("Capture Volume", 0,
2258 CS4231_LEFT_INPUT, CS4231_RIG
2259 {
2260 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2261 .name = "Capture Source",
2262 .info = snd_wss_info_mux,
2263 .get = snd_wss_get_mux,
2264 .put = snd_wss_put_mux,
2265 },
2266 WSS_DOUBLE("Mic Boost", 0,
2267 CS4231_LEFT_INPUT, CS4231_RIG
2268 WSS_SINGLE("Loopback Capture Switch", 0,
2269 CS4231_LOOPBACK, 0, 1, 0),
2270 WSS_SINGLE("Loopback Capture Volume", 0,
2271 CS4231_LOOPBACK, 2, 63, 1)
2272 };
2273
2274 static struct snd_kcontrol_new snd_opti93x_co
2275 WSS_DOUBLE("Master Playback Switch", 0,
2276 OPTi93X_OUT_LEFT, OPTi93X_OUT
2277 WSS_DOUBLE("Master Playback Volume", 0,
2278 OPTi93X_OUT_LEFT, OPTi93X_OUT
2279 WSS_DOUBLE("PCM Playback Switch", 0,
2280 CS4231_LEFT_OUTPUT, CS4231_RI
2281 WSS_DOUBLE("PCM Playback Volume", 0,
2282 CS4231_LEFT_OUTPUT, CS4231_RI
2283 WSS_DOUBLE("FM Playback Switch", 0,
2284 CS4231_AUX2_LEFT_INPUT, CS423
2285 WSS_DOUBLE("FM Playback Volume", 0,
2286 CS4231_AUX2_LEFT_INPUT, CS423
2287 WSS_DOUBLE("Line Playback Switch", 0,
2288 CS4231_LEFT_LINE_IN, CS4231_R
2289 WSS_DOUBLE("Line Playback Volume", 0,
2290 CS4231_LEFT_LINE_IN, CS4231_R
2291 WSS_DOUBLE("Mic Playback Switch", 0,
2292 OPTi93X_MIC_LEFT_INPUT, OPTi9
2293 WSS_DOUBLE("Mic Playback Volume", 0,
2294 OPTi93X_MIC_LEFT_INPUT, OPTi9
2295 WSS_DOUBLE("Mic Boost", 0,
2296 CS4231_LEFT_INPUT, CS4231_RIG
2297 WSS_DOUBLE("CD Playback Switch", 0,
2298 CS4231_AUX1_LEFT_INPUT, CS423
2299 WSS_DOUBLE("CD Playback Volume", 0,
2300 CS4231_AUX1_LEFT_INPUT, CS423
2301 WSS_DOUBLE("Aux Playback Switch", 0,
2302 OPTi931_AUX_LEFT_INPUT, OPTi9
2303 WSS_DOUBLE("Aux Playback Volume", 0,
2304 OPTi931_AUX_LEFT_INPUT, OPTi9
2305 WSS_DOUBLE("Capture Volume", 0,
2306 CS4231_LEFT_INPUT, CS4231_RIG
2307 {
2308 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2309 .name = "Capture Source",
2310 .info = snd_wss_info_mux,
2311 .get = snd_wss_get_mux,
2312 .put = snd_wss_put_mux,
2313 }
2314 };
2315
2316 int snd_wss_mixer(struct snd_wss *chip)
2317 {
2318 struct snd_card *card;
2319 unsigned int idx;
2320 int err;
2321
2322 if (snd_BUG_ON(!chip || !chip->pcm))
2323 return -EINVAL;
2324
2325 card = chip->card;
2326
2327 strcpy(card->mixername, chip->pcm->na
2328
2329 if (chip->hardware == WSS_HW_OPTI93X)
2330 for (idx = 0; idx < ARRAY_SIZ
2331 err = snd_ctl_add(car
2332 snd_c
2333
2334 if (err < 0)
2335 return err;
2336 }
2337 else if (chip->hardware & WSS_HW_AD18
2338 for (idx = 0; idx < ARRAY_SIZ
2339 err = snd_ctl_add(car
2340 snd_c
2341
2342 if (err < 0)
2343 return err;
2344 }
2345 else
2346 for (idx = 0; idx < ARRAY_SIZ
2347 err = snd_ctl_add(car
2348 snd_c
2349
2350 if (err < 0)
2351 return err;
2352 }
2353 return 0;
2354 }
2355 EXPORT_SYMBOL(snd_wss_mixer);
2356
2357 const struct snd_pcm_ops *snd_wss_get_pcm_ops
2358 {
2359 return direction == SNDRV_PCM_STREAM_
2360 &snd_wss_playback_ops : &snd_
2361 }
2362 EXPORT_SYMBOL(snd_wss_get_pcm_ops);
2363
2364 /*
2365 * INIT part
2366 */
2367
2368 static int __init alsa_wss_init(void)
2369 {
2370 return 0;
2371 }
2372
2373 static void __exit alsa_wss_exit(void)
2374 {
2375 }
2376
2377 module_init(alsa_wss_init);
2378 module_exit(alsa_wss_exit);
2379
| This page was automatically generated by the LXR engine. |