diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/oss/mad16.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/oss/mad16.c')
-rw-r--r-- | sound/oss/mad16.c | 1097 |
1 files changed, 1097 insertions, 0 deletions
diff --git a/sound/oss/mad16.c b/sound/oss/mad16.c new file mode 100644 index 000000000000..a7067f169919 --- /dev/null +++ b/sound/oss/mad16.c | |||
@@ -0,0 +1,1097 @@ | |||
1 | /* | ||
2 | * Copyright (C) by Hannu Savolainen 1993-1997 | ||
3 | * | ||
4 | * mad16.c | ||
5 | * | ||
6 | * Initialization code for OPTi MAD16 compatible audio chips. Including | ||
7 | * | ||
8 | * OPTi 82C928 MAD16 (replaced by C929) | ||
9 | * OAK OTI-601D Mozart | ||
10 | * OAK OTI-605 Mozart (later version with MPU401 Midi) | ||
11 | * OPTi 82C929 MAD16 Pro | ||
12 | * OPTi 82C930 | ||
13 | * OPTi 82C924 | ||
14 | * | ||
15 | * These audio interface chips don't produce sound themselves. They just | ||
16 | * connect some other components (OPL-[234] and a WSS compatible codec) | ||
17 | * to the PC bus and perform I/O, DMA and IRQ address decoding. There is | ||
18 | * also a UART for the MPU-401 mode (not 82C928/Mozart). | ||
19 | * The Mozart chip appears to be compatible with the 82C928, although later | ||
20 | * issues of the card, using the OTI-605 chip, have an MPU-401 compatible Midi | ||
21 | * port. This port is configured differently to that of the OPTi audio chips. | ||
22 | * | ||
23 | * Changes | ||
24 | * | ||
25 | * Alan Cox Clean up, added module selections. | ||
26 | * | ||
27 | * A. Wik Added support for Opti924 PnP. | ||
28 | * Improved debugging support. 16-May-1998 | ||
29 | * Fixed bug. 16-Jun-1998 | ||
30 | * | ||
31 | * Torsten Duwe Made Opti924 PnP support non-destructive | ||
32 | * 23-Dec-1998 | ||
33 | * | ||
34 | * Paul Grayson Added support for Midi on later Mozart cards. | ||
35 | * 25-Nov-1999 | ||
36 | * Christoph Hellwig Adapted to module_init/module_exit. | ||
37 | * Arnaldo C. de Melo got rid of attach_uart401 21-Sep-2000 | ||
38 | * | ||
39 | * Pavel Rabel Clean up Nov-2000 | ||
40 | */ | ||
41 | |||
42 | #include <linux/config.h> | ||
43 | #include <linux/init.h> | ||
44 | #include <linux/module.h> | ||
45 | #include <linux/gameport.h> | ||
46 | #include <linux/spinlock.h> | ||
47 | #include "sound_config.h" | ||
48 | |||
49 | #include "ad1848.h" | ||
50 | #include "sb.h" | ||
51 | #include "mpu401.h" | ||
52 | |||
53 | static int mad16_conf; | ||
54 | static int mad16_cdsel; | ||
55 | static struct gameport *gameport; | ||
56 | static DEFINE_SPINLOCK(lock); | ||
57 | |||
58 | #define C928 1 | ||
59 | #define MOZART 2 | ||
60 | #define C929 3 | ||
61 | #define C930 4 | ||
62 | #define C924 5 | ||
63 | |||
64 | /* | ||
65 | * Registers | ||
66 | * | ||
67 | * The MAD16 occupies I/O ports 0xf8d to 0xf93 (fixed locations). | ||
68 | * All ports are inactive by default. They can be activated by | ||
69 | * writing 0xE2 or 0xE3 to the password register. The password is valid | ||
70 | * only until the next I/O read or write. | ||
71 | * | ||
72 | * 82C930 uses 0xE4 as the password and indirect addressing to access | ||
73 | * the config registers. | ||
74 | */ | ||
75 | |||
76 | #define MC0_PORT 0xf8c /* Dummy port */ | ||
77 | #define MC1_PORT 0xf8d /* SB address, CD-ROM interface type, joystick */ | ||
78 | #define MC2_PORT 0xf8e /* CD-ROM address, IRQ, DMA, plus OPL4 bit */ | ||
79 | #define MC3_PORT 0xf8f | ||
80 | #define PASSWD_REG 0xf8f | ||
81 | #define MC4_PORT 0xf90 | ||
82 | #define MC5_PORT 0xf91 | ||
83 | #define MC6_PORT 0xf92 | ||
84 | #define MC7_PORT 0xf93 | ||
85 | #define MC8_PORT 0xf94 | ||
86 | #define MC9_PORT 0xf95 | ||
87 | #define MC10_PORT 0xf96 | ||
88 | #define MC11_PORT 0xf97 | ||
89 | #define MC12_PORT 0xf98 | ||
90 | |||
91 | static int board_type = C928; | ||
92 | |||
93 | static int *mad16_osp; | ||
94 | static int c931_detected; /* minor differences from C930 */ | ||
95 | static char c924pnp; /* " " " C924 */ | ||
96 | static int debug; /* debugging output */ | ||
97 | |||
98 | #ifdef DDB | ||
99 | #undef DDB | ||
100 | #endif | ||
101 | #define DDB(x) do {if (debug) x;} while (0) | ||
102 | |||
103 | static unsigned char mad_read(int port) | ||
104 | { | ||
105 | unsigned long flags; | ||
106 | unsigned char tmp; | ||
107 | |||
108 | spin_lock_irqsave(&lock,flags); | ||
109 | |||
110 | switch (board_type) /* Output password */ | ||
111 | { | ||
112 | case C928: | ||
113 | case MOZART: | ||
114 | outb((0xE2), PASSWD_REG); | ||
115 | break; | ||
116 | |||
117 | case C929: | ||
118 | outb((0xE3), PASSWD_REG); | ||
119 | break; | ||
120 | |||
121 | case C930: | ||
122 | /* outb(( 0xE4), PASSWD_REG); */ | ||
123 | break; | ||
124 | |||
125 | case C924: | ||
126 | /* the c924 has its ports relocated by -128 if | ||
127 | PnP is enabled -aw */ | ||
128 | if (!c924pnp) | ||
129 | outb((0xE5), PASSWD_REG); else | ||
130 | outb((0xE5), PASSWD_REG - 0x80); | ||
131 | break; | ||
132 | } | ||
133 | |||
134 | if (board_type == C930) | ||
135 | { | ||
136 | outb((port - MC0_PORT), 0xe0e); /* Write to index reg */ | ||
137 | tmp = inb(0xe0f); /* Read from data reg */ | ||
138 | } | ||
139 | else | ||
140 | if (!c924pnp) | ||
141 | tmp = inb(port); else | ||
142 | tmp = inb(port-0x80); | ||
143 | spin_unlock_irqrestore(&lock,flags); | ||
144 | |||
145 | return tmp; | ||
146 | } | ||
147 | |||
148 | static void mad_write(int port, int value) | ||
149 | { | ||
150 | unsigned long flags; | ||
151 | |||
152 | spin_lock_irqsave(&lock,flags); | ||
153 | |||
154 | switch (board_type) /* Output password */ | ||
155 | { | ||
156 | case C928: | ||
157 | case MOZART: | ||
158 | outb((0xE2), PASSWD_REG); | ||
159 | break; | ||
160 | |||
161 | case C929: | ||
162 | outb((0xE3), PASSWD_REG); | ||
163 | break; | ||
164 | |||
165 | case C930: | ||
166 | /* outb(( 0xE4), PASSWD_REG); */ | ||
167 | break; | ||
168 | |||
169 | case C924: | ||
170 | if (!c924pnp) | ||
171 | outb((0xE5), PASSWD_REG); else | ||
172 | outb((0xE5), PASSWD_REG - 0x80); | ||
173 | break; | ||
174 | } | ||
175 | |||
176 | if (board_type == C930) | ||
177 | { | ||
178 | outb((port - MC0_PORT), 0xe0e); /* Write to index reg */ | ||
179 | outb(((unsigned char) (value & 0xff)), 0xe0f); | ||
180 | } | ||
181 | else | ||
182 | if (!c924pnp) | ||
183 | outb(((unsigned char) (value & 0xff)), port); else | ||
184 | outb(((unsigned char) (value & 0xff)), port-0x80); | ||
185 | spin_unlock_irqrestore(&lock,flags); | ||
186 | } | ||
187 | |||
188 | static int __init detect_c930(void) | ||
189 | { | ||
190 | unsigned char tmp = mad_read(MC1_PORT); | ||
191 | |||
192 | if ((tmp & 0x06) != 0x06) | ||
193 | { | ||
194 | DDB(printk("Wrong C930 signature (%x)\n", tmp)); | ||
195 | /* return 0; */ | ||
196 | } | ||
197 | mad_write(MC1_PORT, 0); | ||
198 | |||
199 | if (mad_read(MC1_PORT) != 0x06) | ||
200 | { | ||
201 | DDB(printk("Wrong C930 signature2 (%x)\n", tmp)); | ||
202 | /* return 0; */ | ||
203 | } | ||
204 | mad_write(MC1_PORT, tmp); /* Restore bits */ | ||
205 | |||
206 | mad_write(MC7_PORT, 0); | ||
207 | if ((tmp = mad_read(MC7_PORT)) != 0) | ||
208 | { | ||
209 | DDB(printk("MC7 not writable (%x)\n", tmp)); | ||
210 | return 0; | ||
211 | } | ||
212 | mad_write(MC7_PORT, 0xcb); | ||
213 | if ((tmp = mad_read(MC7_PORT)) != 0xcb) | ||
214 | { | ||
215 | DDB(printk("MC7 not writable2 (%x)\n", tmp)); | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | tmp = mad_read(MC0_PORT+18); | ||
220 | if (tmp == 0xff || tmp == 0x00) | ||
221 | return 1; | ||
222 | /* We probably have a C931 */ | ||
223 | DDB(printk("Detected C931 config=0x%02x\n", tmp)); | ||
224 | c931_detected = 1; | ||
225 | |||
226 | /* | ||
227 | * We cannot configure the chip if it is in PnP mode. | ||
228 | * If we have a CSN assigned (bit 8 in MC13) we first try | ||
229 | * a software reset, then a software power off, finally | ||
230 | * Clearing PnP mode. The last option is not | ||
231 | * Bit 8 in MC13 | ||
232 | */ | ||
233 | if ((mad_read(MC0_PORT+13) & 0x80) == 0) | ||
234 | return 1; | ||
235 | |||
236 | /* Software reset */ | ||
237 | mad_write(MC9_PORT, 0x02); | ||
238 | mad_write(MC9_PORT, 0x00); | ||
239 | |||
240 | if ((mad_read(MC0_PORT+13) & 0x80) == 0) | ||
241 | return 1; | ||
242 | |||
243 | /* Power off, and on again */ | ||
244 | mad_write(MC9_PORT, 0xc2); | ||
245 | mad_write(MC9_PORT, 0xc0); | ||
246 | |||
247 | if ((mad_read(MC0_PORT+13) & 0x80) == 0) | ||
248 | return 1; | ||
249 | |||
250 | #if 0 | ||
251 | /* Force off PnP mode. This is not recommended because | ||
252 | * the PnP bios will not recognize the chip on the next | ||
253 | * warm boot and may assignd different resources to other | ||
254 | * PnP/PCI cards. | ||
255 | */ | ||
256 | mad_write(MC0_PORT+17, 0x04); | ||
257 | #endif | ||
258 | return 1; | ||
259 | } | ||
260 | |||
261 | static int __init detect_mad16(void) | ||
262 | { | ||
263 | unsigned char tmp, tmp2, bit; | ||
264 | int i, port; | ||
265 | |||
266 | /* | ||
267 | * Check that reading a register doesn't return bus float (0xff) | ||
268 | * when the card is accessed using password. This may fail in case | ||
269 | * the card is in low power mode. Normally at least the power saving | ||
270 | * mode bit should be 0. | ||
271 | */ | ||
272 | |||
273 | if ((tmp = mad_read(MC1_PORT)) == 0xff) | ||
274 | { | ||
275 | DDB(printk("MC1_PORT returned 0xff\n")); | ||
276 | return 0; | ||
277 | } | ||
278 | for (i = 0xf8d; i <= 0xf98; i++) | ||
279 | if (!c924pnp) | ||
280 | DDB(printk("Port %0x (init value) = %0x\n", i, mad_read(i))); | ||
281 | else | ||
282 | DDB(printk("Port %0x (init value) = %0x\n", i-0x80, mad_read(i))); | ||
283 | |||
284 | if (board_type == C930) | ||
285 | return detect_c930(); | ||
286 | |||
287 | /* | ||
288 | * Now check that the gate is closed on first I/O after writing | ||
289 | * the password. (This is how a MAD16 compatible card works). | ||
290 | */ | ||
291 | |||
292 | if ((tmp2 = inb(MC1_PORT)) == tmp) /* It didn't close */ | ||
293 | { | ||
294 | DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2)); | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | bit = (c924pnp) ? 0x20 : 0x80; | ||
299 | port = (c924pnp) ? MC2_PORT : MC1_PORT; | ||
300 | |||
301 | tmp = mad_read(port); | ||
302 | mad_write(port, tmp ^ bit); /* Toggle a bit */ | ||
303 | if ((tmp2 = mad_read(port)) != (tmp ^ bit)) /* Compare the bit */ | ||
304 | { | ||
305 | mad_write(port, tmp); /* Restore */ | ||
306 | DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2)); | ||
307 | return 0; | ||
308 | } | ||
309 | mad_write(port, tmp); /* Restore */ | ||
310 | return 1; /* Bingo */ | ||
311 | } | ||
312 | |||
313 | static int __init wss_init(struct address_info *hw_config) | ||
314 | { | ||
315 | /* | ||
316 | * Check if the IO port returns valid signature. The original MS Sound | ||
317 | * system returns 0x04 while some cards (AudioTrix Pro for example) | ||
318 | * return 0x00. | ||
319 | */ | ||
320 | |||
321 | if ((inb(hw_config->io_base + 3) & 0x3f) != 0x04 && | ||
322 | (inb(hw_config->io_base + 3) & 0x3f) != 0x00) | ||
323 | { | ||
324 | DDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb(hw_config->io_base + 3))); | ||
325 | return 0; | ||
326 | } | ||
327 | /* | ||
328 | * Check that DMA0 is not in use with a 8 bit board. | ||
329 | */ | ||
330 | if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) | ||
331 | { | ||
332 | printk("MSS: Can't use DMA0 with a 8 bit card/slot\n"); | ||
333 | return 0; | ||
334 | } | ||
335 | if (hw_config->irq > 9 && inb(hw_config->io_base + 3) & 0x80) | ||
336 | printk(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); | ||
337 | return 1; | ||
338 | } | ||
339 | |||
340 | static void __init init_c930(struct address_info *hw_config, int base) | ||
341 | { | ||
342 | unsigned char cfg = 0; | ||
343 | |||
344 | cfg |= (0x0f & mad16_conf); | ||
345 | |||
346 | if(c931_detected) | ||
347 | { | ||
348 | /* Bit 0 has reversd meaning. Bits 1 and 2 sese | ||
349 | reversed on write. | ||
350 | Support only IDE cdrom. IDE port programmed | ||
351 | somewhere else. */ | ||
352 | cfg = (cfg & 0x09) ^ 0x07; | ||
353 | } | ||
354 | cfg |= base << 4; | ||
355 | mad_write(MC1_PORT, cfg); | ||
356 | |||
357 | /* MC2 is CD configuration. Don't touch it. */ | ||
358 | |||
359 | mad_write(MC3_PORT, 0); /* Disable SB mode IRQ and DMA */ | ||
360 | |||
361 | /* bit 2 of MC4 reverses it's meaning between the C930 | ||
362 | and the C931. */ | ||
363 | cfg = c931_detected ? 0x04 : 0x00; | ||
364 | |||
365 | if(mad16_cdsel & 0x20) | ||
366 | mad_write(MC4_PORT, 0x62|cfg); /* opl4 */ | ||
367 | else | ||
368 | mad_write(MC4_PORT, 0x52|cfg); /* opl3 */ | ||
369 | |||
370 | mad_write(MC5_PORT, 0x3C); /* Init it into mode2 */ | ||
371 | mad_write(MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */ | ||
372 | mad_write(MC7_PORT, 0xCB); | ||
373 | mad_write(MC10_PORT, 0x11); | ||
374 | } | ||
375 | |||
376 | static int __init chip_detect(void) | ||
377 | { | ||
378 | int i; | ||
379 | |||
380 | /* | ||
381 | * Then try to detect with the old password | ||
382 | */ | ||
383 | board_type = C924; | ||
384 | |||
385 | DDB(printk("Detect using password = 0xE5\n")); | ||
386 | |||
387 | if (detect_mad16()) { | ||
388 | return 1; | ||
389 | } | ||
390 | |||
391 | board_type = C928; | ||
392 | |||
393 | DDB(printk("Detect using password = 0xE2\n")); | ||
394 | |||
395 | if (detect_mad16()) | ||
396 | { | ||
397 | unsigned char model; | ||
398 | |||
399 | if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) { | ||
400 | DDB(printk("mad16.c: Mozart detected\n")); | ||
401 | board_type = MOZART; | ||
402 | } else { | ||
403 | DDB(printk("mad16.c: 82C928 detected???\n")); | ||
404 | board_type = C928; | ||
405 | } | ||
406 | return 1; | ||
407 | } | ||
408 | |||
409 | board_type = C929; | ||
410 | |||
411 | DDB(printk("Detect using password = 0xE3\n")); | ||
412 | |||
413 | if (detect_mad16()) | ||
414 | { | ||
415 | DDB(printk("mad16.c: 82C929 detected\n")); | ||
416 | return 1; | ||
417 | } | ||
418 | |||
419 | if (inb(PASSWD_REG) != 0xff) | ||
420 | return 0; | ||
421 | |||
422 | /* | ||
423 | * First relocate MC# registers to 0xe0e/0xe0f, disable password | ||
424 | */ | ||
425 | |||
426 | outb((0xE4), PASSWD_REG); | ||
427 | outb((0x80), PASSWD_REG); | ||
428 | |||
429 | board_type = C930; | ||
430 | |||
431 | DDB(printk("Detect using password = 0xE4\n")); | ||
432 | |||
433 | for (i = 0xf8d; i <= 0xf93; i++) | ||
434 | DDB(printk("port %03x = %02x\n", i, mad_read(i))); | ||
435 | |||
436 | if(detect_mad16()) { | ||
437 | DDB(printk("mad16.c: 82C930 detected\n")); | ||
438 | return 1; | ||
439 | } | ||
440 | |||
441 | /* The C931 has the password reg at F8D */ | ||
442 | outb((0xE4), 0xF8D); | ||
443 | outb((0x80), 0xF8D); | ||
444 | DDB(printk("Detect using password = 0xE4 for C931\n")); | ||
445 | |||
446 | if (detect_mad16()) { | ||
447 | return 1; | ||
448 | } | ||
449 | |||
450 | board_type = C924; | ||
451 | c924pnp++; | ||
452 | DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n")); | ||
453 | if (detect_mad16()) { | ||
454 | DDB(printk("mad16.c: 82C924 PnP detected\n")); | ||
455 | return 1; | ||
456 | } | ||
457 | |||
458 | c924pnp=0; | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static int __init probe_mad16(struct address_info *hw_config) | ||
464 | { | ||
465 | int i; | ||
466 | unsigned char tmp; | ||
467 | unsigned char cs4231_mode = 0; | ||
468 | |||
469 | int ad_flags = 0; | ||
470 | |||
471 | signed char bits; | ||
472 | |||
473 | static char dma_bits[4] = { | ||
474 | 1, 2, 0, 3 | ||
475 | }; | ||
476 | |||
477 | int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; | ||
478 | int dma = hw_config->dma, dma2 = hw_config->dma2; | ||
479 | unsigned char dma2_bit = 0; | ||
480 | int base; | ||
481 | struct resource *ports; | ||
482 | |||
483 | mad16_osp = hw_config->osp; | ||
484 | |||
485 | switch (hw_config->io_base) { | ||
486 | case 0x530: | ||
487 | base = 0; | ||
488 | break; | ||
489 | case 0xe80: | ||
490 | base = 1; | ||
491 | break; | ||
492 | case 0xf40: | ||
493 | base = 2; | ||
494 | break; | ||
495 | case 0x604: | ||
496 | base = 3; | ||
497 | break; | ||
498 | default: | ||
499 | printk(KERN_ERR "MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base); | ||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | if (dma != 0 && dma != 1 && dma != 3) { | ||
504 | printk(KERN_ERR "MSS: Bad DMA %d\n", dma); | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | /* | ||
509 | * Check that all ports return 0xff (bus float) when no password | ||
510 | * is written to the password register. | ||
511 | */ | ||
512 | |||
513 | DDB(printk("--- Detecting MAD16 / Mozart ---\n")); | ||
514 | if (!chip_detect()) | ||
515 | return 0; | ||
516 | |||
517 | switch (hw_config->irq) { | ||
518 | case 7: | ||
519 | bits = 8; | ||
520 | break; | ||
521 | case 9: | ||
522 | bits = 0x10; | ||
523 | break; | ||
524 | case 10: | ||
525 | bits = 0x18; | ||
526 | break; | ||
527 | case 12: | ||
528 | bits = 0x20; | ||
529 | break; | ||
530 | case 5: /* Also IRQ5 is possible on C930 */ | ||
531 | if (board_type == C930 || c924pnp) { | ||
532 | bits = 0x28; | ||
533 | break; | ||
534 | } | ||
535 | default: | ||
536 | printk(KERN_ERR "MAD16/Mozart: Bad IRQ %d\n", hw_config->irq); | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | ports = request_region(hw_config->io_base + 4, 4, "ad1848"); | ||
541 | if (!ports) { | ||
542 | printk(KERN_ERR "MSS: I/O port conflict\n"); | ||
543 | return 0; | ||
544 | } | ||
545 | if (!request_region(hw_config->io_base, 4, "mad16 WSS config")) { | ||
546 | release_region(hw_config->io_base + 4, 4); | ||
547 | printk(KERN_ERR "MSS: I/O port conflict\n"); | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | if (board_type == C930) { | ||
552 | init_c930(hw_config, base); | ||
553 | goto got_it; | ||
554 | } | ||
555 | |||
556 | for (i = 0xf8d; i <= 0xf93; i++) { | ||
557 | if (!c924pnp) | ||
558 | DDB(printk("port %03x = %02x\n", i, mad_read(i))); | ||
559 | else | ||
560 | DDB(printk("port %03x = %02x\n", i-0x80, mad_read(i))); | ||
561 | } | ||
562 | |||
563 | /* | ||
564 | * Set the WSS address | ||
565 | */ | ||
566 | |||
567 | tmp = (mad_read(MC1_PORT) & 0x0f) | 0x80; /* Enable WSS, Disable SB */ | ||
568 | tmp |= base << 4; /* WSS port select bits */ | ||
569 | |||
570 | /* | ||
571 | * Set optional CD-ROM and joystick settings. | ||
572 | */ | ||
573 | |||
574 | tmp &= ~0x0f; | ||
575 | tmp |= (mad16_conf & 0x0f); /* CD-ROM and joystick bits */ | ||
576 | mad_write(MC1_PORT, tmp); | ||
577 | |||
578 | tmp = mad16_cdsel; | ||
579 | mad_write(MC2_PORT, tmp); | ||
580 | mad_write(MC3_PORT, 0xf0); /* Disable SB */ | ||
581 | |||
582 | if (board_type == C924) /* Specific C924 init values */ | ||
583 | { | ||
584 | mad_write(MC4_PORT, 0xA0); | ||
585 | mad_write(MC5_PORT, 0x05); | ||
586 | mad_write(MC6_PORT, 0x03); | ||
587 | } | ||
588 | if (!ad1848_detect(ports, &ad_flags, mad16_osp)) | ||
589 | goto fail; | ||
590 | |||
591 | if (ad_flags & (AD_F_CS4231 | AD_F_CS4248)) | ||
592 | cs4231_mode = 0x02; /* CS4248/CS4231 sync delay switch */ | ||
593 | |||
594 | if (board_type == C929) | ||
595 | { | ||
596 | mad_write(MC4_PORT, 0xa2); | ||
597 | mad_write(MC5_PORT, 0xA5 | cs4231_mode); | ||
598 | mad_write(MC6_PORT, 0x03); /* Disable MPU401 */ | ||
599 | } | ||
600 | else | ||
601 | { | ||
602 | mad_write(MC4_PORT, 0x02); | ||
603 | mad_write(MC5_PORT, 0x30 | cs4231_mode); | ||
604 | } | ||
605 | |||
606 | for (i = 0xf8d; i <= 0xf93; i++) { | ||
607 | if (!c924pnp) | ||
608 | DDB(printk("port %03x after init = %02x\n", i, mad_read(i))); | ||
609 | else | ||
610 | DDB(printk("port %03x after init = %02x\n", i-0x80, mad_read(i))); | ||
611 | } | ||
612 | |||
613 | got_it: | ||
614 | ad_flags = 0; | ||
615 | if (!ad1848_detect(ports, &ad_flags, mad16_osp)) | ||
616 | goto fail; | ||
617 | |||
618 | if (!wss_init(hw_config)) | ||
619 | goto fail; | ||
620 | |||
621 | /* | ||
622 | * Set the IRQ and DMA addresses. | ||
623 | */ | ||
624 | |||
625 | outb((bits | 0x40), config_port); | ||
626 | if ((inb(version_port) & 0x40) == 0) | ||
627 | printk(KERN_ERR "[IRQ Conflict?]\n"); | ||
628 | |||
629 | /* | ||
630 | * Handle the capture DMA channel | ||
631 | */ | ||
632 | |||
633 | if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma) | ||
634 | { | ||
635 | if (!((dma == 0 && dma2 == 1) || | ||
636 | (dma == 1 && dma2 == 0) || | ||
637 | (dma == 3 && dma2 == 0))) | ||
638 | { /* Unsupported combination. Try to swap channels */ | ||
639 | int tmp = dma; | ||
640 | |||
641 | dma = dma2; | ||
642 | dma2 = tmp; | ||
643 | } | ||
644 | if ((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) || | ||
645 | (dma == 3 && dma2 == 0)) | ||
646 | { | ||
647 | dma2_bit = 0x04; /* Enable capture DMA */ | ||
648 | } | ||
649 | else | ||
650 | { | ||
651 | printk("MAD16: Invalid capture DMA\n"); | ||
652 | dma2 = dma; | ||
653 | } | ||
654 | } | ||
655 | else dma2 = dma; | ||
656 | |||
657 | outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ | ||
658 | |||
659 | hw_config->slots[0] = ad1848_init("mad16 WSS", ports, | ||
660 | hw_config->irq, | ||
661 | dma, | ||
662 | dma2, 0, | ||
663 | hw_config->osp, | ||
664 | THIS_MODULE); | ||
665 | return 1; | ||
666 | |||
667 | fail: | ||
668 | release_region(hw_config->io_base + 4, 4); | ||
669 | release_region(hw_config->io_base, 4); | ||
670 | return 0; | ||
671 | } | ||
672 | |||
673 | static int __init probe_mad16_mpu(struct address_info *hw_config) | ||
674 | { | ||
675 | unsigned char tmp; | ||
676 | |||
677 | if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ | ||
678 | { | ||
679 | |||
680 | #ifdef CONFIG_MAD16_OLDCARD | ||
681 | |||
682 | tmp = mad_read(MC3_PORT); | ||
683 | |||
684 | /* | ||
685 | * MAD16 SB base is defined by the WSS base. It cannot be changed | ||
686 | * alone. | ||
687 | * Ignore configured I/O base. Use the active setting. | ||
688 | */ | ||
689 | |||
690 | if (mad_read(MC1_PORT) & 0x20) | ||
691 | hw_config->io_base = 0x240; | ||
692 | else | ||
693 | hw_config->io_base = 0x220; | ||
694 | |||
695 | switch (hw_config->irq) | ||
696 | { | ||
697 | case 5: | ||
698 | tmp = (tmp & 0x3f) | 0x80; | ||
699 | break; | ||
700 | case 7: | ||
701 | tmp = (tmp & 0x3f); | ||
702 | break; | ||
703 | case 11: | ||
704 | tmp = (tmp & 0x3f) | 0x40; | ||
705 | break; | ||
706 | default: | ||
707 | printk(KERN_ERR "mad16/Mozart: Invalid MIDI IRQ\n"); | ||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | mad_write(MC3_PORT, tmp | 0x04); | ||
712 | hw_config->driver_use_1 = SB_MIDI_ONLY; | ||
713 | if (!request_region(hw_config->io_base, 16, "soundblaster")) | ||
714 | return 0; | ||
715 | if (!sb_dsp_detect(hw_config, 0, 0, NULL)) { | ||
716 | release_region(hw_config->io_base, 16); | ||
717 | return 0; | ||
718 | } | ||
719 | |||
720 | if (mad_read(MC1_PORT) & 0x20) | ||
721 | hw_config->io_base = 0x240; | ||
722 | else | ||
723 | hw_config->io_base = 0x220; | ||
724 | |||
725 | hw_config->name = "Mad16/Mozart"; | ||
726 | sb_dsp_init(hw_config, THIS_MODULE); | ||
727 | return 1; | ||
728 | #else | ||
729 | /* assuming all later Mozart cards are identified as | ||
730 | * either 82C928 or Mozart. If so, following code attempts | ||
731 | * to set MPU register. TODO - add probing | ||
732 | */ | ||
733 | |||
734 | tmp = mad_read(MC8_PORT); | ||
735 | |||
736 | switch (hw_config->irq) | ||
737 | { | ||
738 | case 5: | ||
739 | tmp |= 0x08; | ||
740 | break; | ||
741 | case 7: | ||
742 | tmp |= 0x10; | ||
743 | break; | ||
744 | case 9: | ||
745 | tmp |= 0x18; | ||
746 | break; | ||
747 | case 10: | ||
748 | tmp |= 0x20; | ||
749 | break; | ||
750 | case 11: | ||
751 | tmp |= 0x28; | ||
752 | break; | ||
753 | default: | ||
754 | printk(KERN_ERR "mad16/MOZART: invalid mpu_irq\n"); | ||
755 | return 0; | ||
756 | } | ||
757 | |||
758 | switch (hw_config->io_base) | ||
759 | { | ||
760 | case 0x300: | ||
761 | tmp |= 0x01; | ||
762 | break; | ||
763 | case 0x310: | ||
764 | tmp |= 0x03; | ||
765 | break; | ||
766 | case 0x320: | ||
767 | tmp |= 0x05; | ||
768 | break; | ||
769 | case 0x330: | ||
770 | tmp |= 0x07; | ||
771 | break; | ||
772 | default: | ||
773 | printk(KERN_ERR "mad16/MOZART: invalid mpu_io\n"); | ||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | mad_write(MC8_PORT, tmp); /* write MPU port parameters */ | ||
778 | goto probe_401; | ||
779 | #endif | ||
780 | } | ||
781 | tmp = mad_read(MC6_PORT) & 0x83; | ||
782 | tmp |= 0x80; /* MPU-401 enable */ | ||
783 | |||
784 | /* Set the MPU base bits */ | ||
785 | |||
786 | switch (hw_config->io_base) | ||
787 | { | ||
788 | case 0x300: | ||
789 | tmp |= 0x60; | ||
790 | break; | ||
791 | case 0x310: | ||
792 | tmp |= 0x40; | ||
793 | break; | ||
794 | case 0x320: | ||
795 | tmp |= 0x20; | ||
796 | break; | ||
797 | case 0x330: | ||
798 | tmp |= 0x00; | ||
799 | break; | ||
800 | default: | ||
801 | printk(KERN_ERR "MAD16: Invalid MIDI port 0x%x\n", hw_config->io_base); | ||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | /* Set the MPU IRQ bits */ | ||
806 | |||
807 | switch (hw_config->irq) | ||
808 | { | ||
809 | case 5: | ||
810 | tmp |= 0x10; | ||
811 | break; | ||
812 | case 7: | ||
813 | tmp |= 0x18; | ||
814 | break; | ||
815 | case 9: | ||
816 | tmp |= 0x00; | ||
817 | break; | ||
818 | case 10: | ||
819 | tmp |= 0x08; | ||
820 | break; | ||
821 | default: | ||
822 | printk(KERN_ERR "MAD16: Invalid MIDI IRQ %d\n", hw_config->irq); | ||
823 | break; | ||
824 | } | ||
825 | |||
826 | mad_write(MC6_PORT, tmp); /* Write MPU401 config */ | ||
827 | |||
828 | #ifndef CONFIG_MAD16_OLDCARD | ||
829 | probe_401: | ||
830 | #endif | ||
831 | hw_config->driver_use_1 = SB_MIDI_ONLY; | ||
832 | hw_config->name = "Mad16/Mozart"; | ||
833 | return probe_uart401(hw_config, THIS_MODULE); | ||
834 | } | ||
835 | |||
836 | static void __exit unload_mad16(struct address_info *hw_config) | ||
837 | { | ||
838 | ad1848_unload(hw_config->io_base + 4, | ||
839 | hw_config->irq, | ||
840 | hw_config->dma, | ||
841 | hw_config->dma2, 0); | ||
842 | release_region(hw_config->io_base, 4); | ||
843 | sound_unload_audiodev(hw_config->slots[0]); | ||
844 | } | ||
845 | |||
846 | static void __exit unload_mad16_mpu(struct address_info *hw_config) | ||
847 | { | ||
848 | #ifdef CONFIG_MAD16_OLDCARD | ||
849 | if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ | ||
850 | { | ||
851 | sb_dsp_unload(hw_config, 0); | ||
852 | return; | ||
853 | } | ||
854 | #endif | ||
855 | |||
856 | unload_uart401(hw_config); | ||
857 | } | ||
858 | |||
859 | static struct address_info cfg; | ||
860 | static struct address_info cfg_mpu; | ||
861 | |||
862 | static int found_mpu; | ||
863 | |||
864 | static int __initdata mpu_io = 0; | ||
865 | static int __initdata mpu_irq = 0; | ||
866 | static int __initdata io = -1; | ||
867 | static int __initdata dma = -1; | ||
868 | static int __initdata dma16 = -1; /* Set this for modules that need it */ | ||
869 | static int __initdata irq = -1; | ||
870 | static int __initdata cdtype = 0; | ||
871 | static int __initdata cdirq = 0; | ||
872 | static int __initdata cdport = 0x340; | ||
873 | static int __initdata cddma = -1; | ||
874 | static int __initdata opl4 = 0; | ||
875 | static int __initdata joystick = 0; | ||
876 | |||
877 | module_param(mpu_io, int, 0); | ||
878 | module_param(mpu_irq, int, 0); | ||
879 | module_param(io, int, 0); | ||
880 | module_param(dma, int, 0); | ||
881 | module_param(dma16, int, 0); | ||
882 | module_param(irq, int, 0); | ||
883 | module_param(cdtype, int, 0); | ||
884 | module_param(cdirq, int, 0); | ||
885 | module_param(cdport, int, 0); | ||
886 | module_param(cddma, int, 0); | ||
887 | module_param(opl4, int, 0); | ||
888 | module_param(joystick, bool, 0); | ||
889 | module_param(debug, bool, 0644); | ||
890 | |||
891 | static int __initdata dma_map[2][8] = | ||
892 | { | ||
893 | {0x03, -1, -1, -1, -1, 0x00, 0x01, 0x02}, | ||
894 | {0x03, -1, 0x01, 0x00, -1, -1, -1, -1} | ||
895 | }; | ||
896 | |||
897 | static int __initdata irq_map[16] = | ||
898 | { | ||
899 | 0x00, -1, -1, 0x0A, | ||
900 | -1, 0x04, -1, 0x08, | ||
901 | -1, 0x10, 0x14, 0x18, | ||
902 | -1, -1, -1, -1 | ||
903 | }; | ||
904 | |||
905 | static int __devinit mad16_register_gameport(int io_port) | ||
906 | { | ||
907 | if (!request_region(io_port, 1, "mad16 gameport")) { | ||
908 | printk(KERN_ERR "mad16: gameport address 0x%#x already in use\n", io_port); | ||
909 | return -EBUSY; | ||
910 | } | ||
911 | |||
912 | gameport = gameport_allocate_port(); | ||
913 | if (!gameport) { | ||
914 | printk(KERN_ERR "mad16: can not allocate memory for gameport\n"); | ||
915 | release_region(io_port, 1); | ||
916 | return -ENOMEM; | ||
917 | } | ||
918 | |||
919 | gameport_set_name(gameport, "MAD16 Gameport"); | ||
920 | gameport_set_phys(gameport, "isa%04x/gameport0", io_port); | ||
921 | gameport->io = io_port; | ||
922 | |||
923 | gameport_register_port(gameport); | ||
924 | |||
925 | return 0; | ||
926 | } | ||
927 | |||
928 | static int __devinit init_mad16(void) | ||
929 | { | ||
930 | int dmatype = 0; | ||
931 | |||
932 | printk(KERN_INFO "MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); | ||
933 | |||
934 | printk(KERN_INFO "CDROM "); | ||
935 | switch (cdtype) | ||
936 | { | ||
937 | case 0x00: | ||
938 | printk("Disabled"); | ||
939 | cdirq = 0; | ||
940 | break; | ||
941 | case 0x02: | ||
942 | printk("Sony CDU31A"); | ||
943 | dmatype = 1; | ||
944 | if(cddma == -1) cddma = 3; | ||
945 | break; | ||
946 | case 0x04: | ||
947 | printk("Mitsumi"); | ||
948 | dmatype = 0; | ||
949 | if(cddma == -1) cddma = 5; | ||
950 | break; | ||
951 | case 0x06: | ||
952 | printk("Panasonic Lasermate"); | ||
953 | dmatype = 1; | ||
954 | if(cddma == -1) cddma = 3; | ||
955 | break; | ||
956 | case 0x08: | ||
957 | printk("Secondary IDE"); | ||
958 | dmatype = 0; | ||
959 | if(cddma == -1) cddma = 5; | ||
960 | break; | ||
961 | case 0x0A: | ||
962 | printk("Primary IDE"); | ||
963 | dmatype = 0; | ||
964 | if(cddma == -1) cddma = 5; | ||
965 | break; | ||
966 | default: | ||
967 | printk("\n"); | ||
968 | printk(KERN_ERR "Invalid CDROM type\n"); | ||
969 | return -EINVAL; | ||
970 | } | ||
971 | |||
972 | /* | ||
973 | * Build the config words | ||
974 | */ | ||
975 | |||
976 | mad16_conf = (joystick ^ 1) | cdtype; | ||
977 | mad16_cdsel = 0; | ||
978 | if (opl4) | ||
979 | mad16_cdsel |= 0x20; | ||
980 | |||
981 | if(cdtype){ | ||
982 | if (cddma > 7 || cddma < 0 || dma_map[dmatype][cddma] == -1) | ||
983 | { | ||
984 | printk("\n"); | ||
985 | printk(KERN_ERR "Invalid CDROM DMA\n"); | ||
986 | return -EINVAL; | ||
987 | } | ||
988 | if (cddma) | ||
989 | printk(", DMA %d", cddma); | ||
990 | else | ||
991 | printk(", no DMA"); | ||
992 | |||
993 | if (!cdirq) | ||
994 | printk(", no IRQ"); | ||
995 | else if (cdirq < 0 || cdirq > 15 || irq_map[cdirq] == -1) | ||
996 | { | ||
997 | printk(", invalid IRQ (disabling)"); | ||
998 | cdirq = 0; | ||
999 | } | ||
1000 | else printk(", IRQ %d", cdirq); | ||
1001 | |||
1002 | mad16_cdsel |= dma_map[dmatype][cddma]; | ||
1003 | |||
1004 | if (cdtype < 0x08) | ||
1005 | { | ||
1006 | switch (cdport) | ||
1007 | { | ||
1008 | case 0x340: | ||
1009 | mad16_cdsel |= 0x00; | ||
1010 | break; | ||
1011 | case 0x330: | ||
1012 | mad16_cdsel |= 0x40; | ||
1013 | break; | ||
1014 | case 0x360: | ||
1015 | mad16_cdsel |= 0x80; | ||
1016 | break; | ||
1017 | case 0x320: | ||
1018 | mad16_cdsel |= 0xC0; | ||
1019 | break; | ||
1020 | default: | ||
1021 | printk(KERN_ERR "Unknown CDROM I/O base %d\n", cdport); | ||
1022 | return -EINVAL; | ||
1023 | } | ||
1024 | } | ||
1025 | mad16_cdsel |= irq_map[cdirq]; | ||
1026 | } | ||
1027 | |||
1028 | printk(".\n"); | ||
1029 | |||
1030 | cfg.io_base = io; | ||
1031 | cfg.irq = irq; | ||
1032 | cfg.dma = dma; | ||
1033 | cfg.dma2 = dma16; | ||
1034 | |||
1035 | if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { | ||
1036 | printk(KERN_ERR "I/O, DMA and irq are mandatory\n"); | ||
1037 | return -EINVAL; | ||
1038 | } | ||
1039 | |||
1040 | if (!request_region(MC0_PORT, 12, "mad16")) | ||
1041 | return -EBUSY; | ||
1042 | |||
1043 | if (!probe_mad16(&cfg)) { | ||
1044 | release_region(MC0_PORT, 12); | ||
1045 | return -ENODEV; | ||
1046 | } | ||
1047 | |||
1048 | cfg_mpu.io_base = mpu_io; | ||
1049 | cfg_mpu.irq = mpu_irq; | ||
1050 | |||
1051 | found_mpu = probe_mad16_mpu(&cfg_mpu); | ||
1052 | |||
1053 | if (joystick) | ||
1054 | mad16_register_gameport(0x201); | ||
1055 | |||
1056 | return 0; | ||
1057 | } | ||
1058 | |||
1059 | static void __exit cleanup_mad16(void) | ||
1060 | { | ||
1061 | if (found_mpu) | ||
1062 | unload_mad16_mpu(&cfg_mpu); | ||
1063 | if (gameport) { | ||
1064 | /* the gameport was initialized so we must free it up */ | ||
1065 | gameport_unregister_port(gameport); | ||
1066 | gameport = NULL; | ||
1067 | release_region(0x201, 1); | ||
1068 | } | ||
1069 | unload_mad16(&cfg); | ||
1070 | release_region(MC0_PORT, 12); | ||
1071 | } | ||
1072 | |||
1073 | module_init(init_mad16); | ||
1074 | module_exit(cleanup_mad16); | ||
1075 | |||
1076 | #ifndef MODULE | ||
1077 | static int __init setup_mad16(char *str) | ||
1078 | { | ||
1079 | /* io, irq */ | ||
1080 | int ints[8]; | ||
1081 | |||
1082 | str = get_options(str, ARRAY_SIZE(ints), ints); | ||
1083 | |||
1084 | io = ints[1]; | ||
1085 | irq = ints[2]; | ||
1086 | dma = ints[3]; | ||
1087 | dma16 = ints[4]; | ||
1088 | mpu_io = ints[5]; | ||
1089 | mpu_irq = ints[6]; | ||
1090 | joystick = ints[7]; | ||
1091 | |||
1092 | return 1; | ||
1093 | } | ||
1094 | |||
1095 | __setup("mad16=", setup_mad16); | ||
1096 | #endif | ||
1097 | MODULE_LICENSE("GPL"); | ||