Root/
1 | /* |
2 | * sound/oss/trix.c |
3 | * |
4 | * Low level driver for the MediaTrix AudioTrix Pro |
5 | * (MT-0002-PC Control Chip) |
6 | * |
7 | * |
8 | * Copyright (C) by Hannu Savolainen 1993-1997 |
9 | * |
10 | * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) |
11 | * Version 2 (June 1991). See the "COPYING" file distributed with this software |
12 | * for more info. |
13 | * |
14 | * Changes |
15 | * Alan Cox Modularisation, cleanup. |
16 | * Christoph Hellwig Adapted to module_init/module_exit |
17 | * Arnaldo C. de Melo Got rid of attach_uart401 |
18 | */ |
19 | |
20 | #include <linux/init.h> |
21 | #include <linux/module.h> |
22 | |
23 | #include "sound_config.h" |
24 | #include "sb.h" |
25 | #include "sound_firmware.h" |
26 | |
27 | #include "ad1848.h" |
28 | #include "mpu401.h" |
29 | |
30 | #include "trix_boot.h" |
31 | |
32 | static int mpu; |
33 | |
34 | static int joystick; |
35 | |
36 | static unsigned char trix_read(int addr) |
37 | { |
38 | outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ |
39 | return inb(0x391); /* MT-0002-PC ASIC data */ |
40 | } |
41 | |
42 | static void trix_write(int addr, int data) |
43 | { |
44 | outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ |
45 | outb(((unsigned char) data), 0x391); /* MT-0002-PC ASIC data */ |
46 | } |
47 | |
48 | static void download_boot(int base) |
49 | { |
50 | int i = 0, n = trix_boot_len; |
51 | |
52 | if (trix_boot_len == 0) |
53 | return; |
54 | |
55 | trix_write(0xf8, 0x00); /* ??????? */ |
56 | outb((0x01), base + 6); /* Clear the internal data pointer */ |
57 | outb((0x00), base + 6); /* Restart */ |
58 | |
59 | /* |
60 | * Write the boot code to the RAM upload/download register. |
61 | * Each write increments the internal data pointer. |
62 | */ |
63 | outb((0x01), base + 6); /* Clear the internal data pointer */ |
64 | outb((0x1A), 0x390); /* Select RAM download/upload port */ |
65 | |
66 | for (i = 0; i < n; i++) |
67 | outb((trix_boot[i]), 0x391); |
68 | for (i = n; i < 10016; i++) /* Clear up to first 16 bytes of data RAM */ |
69 | outb((0x00), 0x391); |
70 | outb((0x00), base + 6); /* Reset */ |
71 | outb((0x50), 0x390); /* ?????? */ |
72 | |
73 | } |
74 | |
75 | static int trix_set_wss_port(struct address_info *hw_config) |
76 | { |
77 | unsigned char addr_bits; |
78 | |
79 | if (trix_read(0x15) != 0x71) /* No ASIC signature */ |
80 | { |
81 | MDB(printk(KERN_ERR "No AudioTrix ASIC signature found\n")); |
82 | return 0; |
83 | } |
84 | |
85 | /* |
86 | * Reset some registers. |
87 | */ |
88 | |
89 | trix_write(0x13, 0); |
90 | trix_write(0x14, 0); |
91 | |
92 | /* |
93 | * Configure the ASIC to place the codec to the proper I/O location |
94 | */ |
95 | |
96 | switch (hw_config->io_base) |
97 | { |
98 | case 0x530: |
99 | addr_bits = 0; |
100 | break; |
101 | case 0x604: |
102 | addr_bits = 1; |
103 | break; |
104 | case 0xE80: |
105 | addr_bits = 2; |
106 | break; |
107 | case 0xF40: |
108 | addr_bits = 3; |
109 | break; |
110 | default: |
111 | return 0; |
112 | } |
113 | |
114 | trix_write(0x19, (trix_read(0x19) & 0x03) | addr_bits); |
115 | return 1; |
116 | } |
117 | |
118 | /* |
119 | * Probe and attach routines for the Windows Sound System mode of |
120 | * AudioTrix Pro |
121 | */ |
122 | |
123 | static int __init init_trix_wss(struct address_info *hw_config) |
124 | { |
125 | static unsigned char dma_bits[4] = { |
126 | 1, 2, 0, 3 |
127 | }; |
128 | struct resource *ports; |
129 | int config_port = hw_config->io_base + 0; |
130 | int dma1 = hw_config->dma, dma2 = hw_config->dma2; |
131 | int old_num_mixers = num_mixers; |
132 | u8 config, bits; |
133 | int ret; |
134 | |
135 | switch(hw_config->irq) { |
136 | case 7: |
137 | bits = 8; |
138 | break; |
139 | case 9: |
140 | bits = 0x10; |
141 | break; |
142 | case 10: |
143 | bits = 0x18; |
144 | break; |
145 | case 11: |
146 | bits = 0x20; |
147 | break; |
148 | default: |
149 | printk(KERN_ERR "AudioTrix: Bad WSS IRQ %d\n", hw_config->irq); |
150 | return 0; |
151 | } |
152 | |
153 | switch (dma1) { |
154 | case 0: |
155 | case 1: |
156 | case 3: |
157 | break; |
158 | default: |
159 | printk(KERN_ERR "AudioTrix: Bad WSS DMA %d\n", dma1); |
160 | return 0; |
161 | } |
162 | |
163 | switch (dma2) { |
164 | case -1: |
165 | case 0: |
166 | case 1: |
167 | case 3: |
168 | break; |
169 | default: |
170 | printk(KERN_ERR "AudioTrix: Bad capture DMA %d\n", dma2); |
171 | return 0; |
172 | } |
173 | |
174 | /* |
175 | * Check if the IO port returns valid signature. The original MS Sound |
176 | * system returns 0x04 while some cards (AudioTrix Pro for example) |
177 | * return 0x00. |
178 | */ |
179 | ports = request_region(hw_config->io_base + 4, 4, "ad1848"); |
180 | if (!ports) { |
181 | printk(KERN_ERR "AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); |
182 | return 0; |
183 | } |
184 | |
185 | if (!request_region(hw_config->io_base, 4, "MSS config")) { |
186 | printk(KERN_ERR "AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); |
187 | release_region(hw_config->io_base + 4, 4); |
188 | return 0; |
189 | } |
190 | |
191 | if (!trix_set_wss_port(hw_config)) |
192 | goto fail; |
193 | |
194 | config = inb(hw_config->io_base + 3); |
195 | |
196 | if ((config & 0x3f) != 0x00) |
197 | { |
198 | MDB(printk(KERN_ERR "No MSS signature detected on port 0x%x\n", hw_config->io_base)); |
199 | goto fail; |
200 | } |
201 | |
202 | /* |
203 | * Check that DMA0 is not in use with a 8 bit board. |
204 | */ |
205 | |
206 | if (dma1 == 0 && config & 0x80) |
207 | { |
208 | printk(KERN_ERR "AudioTrix: Can't use DMA0 with a 8 bit card slot\n"); |
209 | goto fail; |
210 | } |
211 | if (hw_config->irq > 9 && config & 0x80) |
212 | { |
213 | printk(KERN_ERR "AudioTrix: Can't use IRQ%d with a 8 bit card slot\n", hw_config->irq); |
214 | goto fail; |
215 | } |
216 | |
217 | ret = ad1848_detect(ports, NULL, hw_config->osp); |
218 | if (!ret) |
219 | goto fail; |
220 | |
221 | if (joystick==1) |
222 | trix_write(0x15, 0x80); |
223 | |
224 | /* |
225 | * Set the IRQ and DMA addresses. |
226 | */ |
227 | |
228 | outb((bits | 0x40), config_port); |
229 | |
230 | if (dma2 == -1 || dma2 == dma1) |
231 | { |
232 | bits |= dma_bits[dma1]; |
233 | dma2 = dma1; |
234 | } |
235 | else |
236 | { |
237 | unsigned char tmp; |
238 | |
239 | tmp = trix_read(0x13) & ~30; |
240 | trix_write(0x13, tmp | 0x80 | (dma1 << 4)); |
241 | |
242 | tmp = trix_read(0x14) & ~30; |
243 | trix_write(0x14, tmp | 0x80 | (dma2 << 4)); |
244 | } |
245 | |
246 | outb((bits), config_port); /* Write IRQ+DMA setup */ |
247 | |
248 | hw_config->slots[0] = ad1848_init("AudioTrix Pro", ports, |
249 | hw_config->irq, |
250 | dma1, |
251 | dma2, |
252 | 0, |
253 | hw_config->osp, |
254 | THIS_MODULE); |
255 | |
256 | if (num_mixers > old_num_mixers) /* Mixer got installed */ |
257 | { |
258 | AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); /* Line in */ |
259 | AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); |
260 | AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* OPL4 */ |
261 | AD1848_REROUTE(SOUND_MIXER_SPEAKER, SOUND_MIXER_ALTPCM); /* SB */ |
262 | } |
263 | return 1; |
264 | |
265 | fail: |
266 | release_region(hw_config->io_base, 4); |
267 | release_region(hw_config->io_base + 4, 4); |
268 | return 0; |
269 | } |
270 | |
271 | static int __init probe_trix_sb(struct address_info *hw_config) |
272 | { |
273 | |
274 | int tmp; |
275 | unsigned char conf; |
276 | extern int sb_be_quiet; |
277 | int old_quiet; |
278 | static signed char irq_translate[] = { |
279 | -1, -1, -1, 0, 1, 2, -1, 3 |
280 | }; |
281 | |
282 | if (trix_boot_len == 0) |
283 | return 0; /* No boot code -> no fun */ |
284 | |
285 | if ((hw_config->io_base & 0xffffff8f) != 0x200) |
286 | return 0; |
287 | |
288 | tmp = hw_config->irq; |
289 | if (tmp > 7) |
290 | return 0; |
291 | if (irq_translate[tmp] == -1) |
292 | return 0; |
293 | |
294 | tmp = hw_config->dma; |
295 | if (tmp != 1 && tmp != 3) |
296 | return 0; |
297 | |
298 | if (!request_region(hw_config->io_base, 16, "soundblaster")) { |
299 | printk(KERN_ERR "AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base); |
300 | return 0; |
301 | } |
302 | |
303 | conf = 0x84; /* DMA and IRQ enable */ |
304 | conf |= hw_config->io_base & 0x70; /* I/O address bits */ |
305 | conf |= irq_translate[hw_config->irq]; |
306 | if (hw_config->dma == 3) |
307 | conf |= 0x08; |
308 | trix_write(0x1b, conf); |
309 | |
310 | download_boot(hw_config->io_base); |
311 | |
312 | hw_config->name = "AudioTrix SB"; |
313 | if (!sb_dsp_detect(hw_config, 0, 0, NULL)) { |
314 | release_region(hw_config->io_base, 16); |
315 | return 0; |
316 | } |
317 | |
318 | hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING; |
319 | |
320 | /* Prevent false alarms */ |
321 | old_quiet = sb_be_quiet; |
322 | sb_be_quiet = 1; |
323 | |
324 | sb_dsp_init(hw_config, THIS_MODULE); |
325 | |
326 | sb_be_quiet = old_quiet; |
327 | return 1; |
328 | } |
329 | |
330 | static int __init probe_trix_mpu(struct address_info *hw_config) |
331 | { |
332 | unsigned char conf; |
333 | static int irq_bits[] = { |
334 | -1, -1, -1, 1, 2, 3, -1, 4, -1, 5 |
335 | }; |
336 | |
337 | if (hw_config->irq > 9) |
338 | { |
339 | printk(KERN_ERR "AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); |
340 | return 0; |
341 | } |
342 | if (irq_bits[hw_config->irq] == -1) |
343 | { |
344 | printk(KERN_ERR "AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); |
345 | return 0; |
346 | } |
347 | switch (hw_config->io_base) |
348 | { |
349 | case 0x330: |
350 | conf = 0x00; |
351 | break; |
352 | case 0x370: |
353 | conf = 0x04; |
354 | break; |
355 | case 0x3b0: |
356 | conf = 0x08; |
357 | break; |
358 | case 0x3f0: |
359 | conf = 0x0c; |
360 | break; |
361 | default: |
362 | return 0; /* Invalid port */ |
363 | } |
364 | |
365 | conf |= irq_bits[hw_config->irq] << 4; |
366 | trix_write(0x19, (trix_read(0x19) & 0x83) | conf); |
367 | hw_config->name = "AudioTrix Pro"; |
368 | return probe_uart401(hw_config, THIS_MODULE); |
369 | } |
370 | |
371 | static void __exit unload_trix_wss(struct address_info *hw_config) |
372 | { |
373 | int dma2 = hw_config->dma2; |
374 | |
375 | if (dma2 == -1) |
376 | dma2 = hw_config->dma; |
377 | |
378 | release_region(0x390, 2); |
379 | release_region(hw_config->io_base, 4); |
380 | |
381 | ad1848_unload(hw_config->io_base + 4, |
382 | hw_config->irq, |
383 | hw_config->dma, |
384 | dma2, |
385 | 0); |
386 | sound_unload_audiodev(hw_config->slots[0]); |
387 | } |
388 | |
389 | static inline void __exit unload_trix_mpu(struct address_info *hw_config) |
390 | { |
391 | unload_uart401(hw_config); |
392 | } |
393 | |
394 | static inline void __exit unload_trix_sb(struct address_info *hw_config) |
395 | { |
396 | sb_dsp_unload(hw_config, mpu); |
397 | } |
398 | |
399 | static struct address_info cfg; |
400 | static struct address_info cfg2; |
401 | static struct address_info cfg_mpu; |
402 | |
403 | static int sb; |
404 | static int fw_load; |
405 | |
406 | static int __initdata io = -1; |
407 | static int __initdata irq = -1; |
408 | static int __initdata dma = -1; |
409 | static int __initdata dma2 = -1; /* Set this for modules that need it */ |
410 | static int __initdata sb_io = -1; |
411 | static int __initdata sb_dma = -1; |
412 | static int __initdata sb_irq = -1; |
413 | static int __initdata mpu_io = -1; |
414 | static int __initdata mpu_irq = -1; |
415 | |
416 | module_param(io, int, 0); |
417 | module_param(irq, int, 0); |
418 | module_param(dma, int, 0); |
419 | module_param(dma2, int, 0); |
420 | module_param(sb_io, int, 0); |
421 | module_param(sb_dma, int, 0); |
422 | module_param(sb_irq, int, 0); |
423 | module_param(mpu_io, int, 0); |
424 | module_param(mpu_irq, int, 0); |
425 | module_param(joystick, bool, 0); |
426 | |
427 | static int __init init_trix(void) |
428 | { |
429 | printk(KERN_INFO "MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); |
430 | |
431 | cfg.io_base = io; |
432 | cfg.irq = irq; |
433 | cfg.dma = dma; |
434 | cfg.dma2 = dma2; |
435 | |
436 | cfg2.io_base = sb_io; |
437 | cfg2.irq = sb_irq; |
438 | cfg2.dma = sb_dma; |
439 | |
440 | cfg_mpu.io_base = mpu_io; |
441 | cfg_mpu.irq = mpu_irq; |
442 | |
443 | if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { |
444 | printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); |
445 | return -EINVAL; |
446 | } |
447 | |
448 | if (cfg2.io_base != -1 && (cfg2.irq == -1 || cfg2.dma == -1)) { |
449 | printk(KERN_INFO "CONFIG_SB_IRQ and CONFIG_SB_DMA must be specified if SB_IO is set.\n"); |
450 | return -EINVAL; |
451 | } |
452 | if (cfg_mpu.io_base != -1 && cfg_mpu.irq == -1) { |
453 | printk(KERN_INFO "CONFIG_MPU_IRQ must be specified if MPU_IO is set.\n"); |
454 | return -EINVAL; |
455 | } |
456 | if (!trix_boot) |
457 | { |
458 | fw_load = 1; |
459 | trix_boot_len = mod_firmware_load("/etc/sound/trxpro.bin", |
460 | (char **) &trix_boot); |
461 | } |
462 | |
463 | if (!request_region(0x390, 2, "AudioTrix")) { |
464 | printk(KERN_ERR "AudioTrix: Config port I/O conflict\n"); |
465 | return -ENODEV; |
466 | } |
467 | |
468 | if (!init_trix_wss(&cfg)) { |
469 | release_region(0x390, 2); |
470 | return -ENODEV; |
471 | } |
472 | |
473 | /* |
474 | * We must attach in the right order to get the firmware |
475 | * loaded up in time. |
476 | */ |
477 | |
478 | if (cfg2.io_base != -1) { |
479 | sb = probe_trix_sb(&cfg2); |
480 | } |
481 | |
482 | if (cfg_mpu.io_base != -1) |
483 | mpu = probe_trix_mpu(&cfg_mpu); |
484 | |
485 | return 0; |
486 | } |
487 | |
488 | static void __exit cleanup_trix(void) |
489 | { |
490 | if (fw_load && trix_boot) |
491 | vfree(trix_boot); |
492 | if (sb) |
493 | unload_trix_sb(&cfg2); |
494 | if (mpu) |
495 | unload_trix_mpu(&cfg_mpu); |
496 | unload_trix_wss(&cfg); |
497 | } |
498 | |
499 | module_init(init_trix); |
500 | module_exit(cleanup_trix); |
501 | |
502 | #ifndef MODULE |
503 | static int __init setup_trix (char *str) |
504 | { |
505 | /* io, irq, dma, dma2, sb_io, sb_irq, sb_dma, mpu_io, mpu_irq */ |
506 | int ints[9]; |
507 | |
508 | str = get_options(str, ARRAY_SIZE(ints), ints); |
509 | |
510 | io = ints[1]; |
511 | irq = ints[2]; |
512 | dma = ints[3]; |
513 | dma2 = ints[4]; |
514 | sb_io = ints[5]; |
515 | sb_irq = ints[6]; |
516 | sb_dma = ints[6]; |
517 | mpu_io = ints[7]; |
518 | mpu_irq = ints[8]; |
519 | |
520 | return 1; |
521 | } |
522 | |
523 | __setup("trix=", setup_trix); |
524 | #endif |
525 | MODULE_LICENSE("GPL"); |
526 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9