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