Import 2.4.0-test6pre3
[davej-history.git] / drivers / sound / maui.c
blob797150997a2ad095c6efcaba2b8d60fd729a0119
1 /*
2 * sound/maui.c
4 * The low level driver for Turtle Beach Maui and Tropez.
7 * Copyright (C) by Hannu Savolainen 1993-1997
9 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
10 * Version 2 (June 1991). See the "COPYING" file distributed with this software
11 * for more info.
13 * Changes:
14 * Alan Cox General clean up, use kernel IRQ
15 * system
16 * Christoph Hellwig Adapted to module_init/module_exit
18 * Status:
19 * Andrew J. Kroll Tested 06/01/1999 with:
20 * * OSWF.MOT File Version: 1.15
21 * * OSWF.MOT File Dated: 09/12/94
22 * * Older versions will cause problems.
25 #include <linux/config.h>
26 #include <linux/module.h>
27 #include <linux/init.h>
29 #define USE_SEQ_MACROS
30 #define USE_SIMPLE_MACROS
32 #include "sound_config.h"
33 #include "soundmodule.h"
34 #include "sound_firmware.h"
36 #include "mpu401.h"
38 static int maui_base = 0x330;
40 static volatile int irq_ok = 0;
41 static int *maui_osp;
43 #define HOST_DATA_PORT (maui_base + 2)
44 #define HOST_STAT_PORT (maui_base + 3)
45 #define HOST_CTRL_PORT (maui_base + 3)
47 #define STAT_TX_INTR 0x40
48 #define STAT_TX_AVAIL 0x20
49 #define STAT_TX_IENA 0x10
50 #define STAT_RX_INTR 0x04
51 #define STAT_RX_AVAIL 0x02
52 #define STAT_RX_IENA 0x01
54 static int (*orig_load_patch) (int dev, int format, const char *addr,
55 int offs, int count, int pmgr_flag) = NULL;
57 #include "maui_boot.h"
59 static int maui_wait(int mask)
61 int i;
64 * Perform a short initial wait without sleeping
67 for (i = 0; i < 100; i++)
68 if (inb(HOST_STAT_PORT) & mask)
69 return 1;
72 * Wait up to 15 seconds with sleeping
75 for (i = 0; i < 150; i++) {
76 if (inb(HOST_STAT_PORT) & mask)
77 return 1;
78 current->state = TASK_INTERRUPTIBLE;
79 schedule_timeout(HZ / 10);
80 if (signal_pending(current))
81 return 0;
83 return 0;
86 static int maui_read(void)
88 if (maui_wait(STAT_RX_AVAIL))
89 return inb(HOST_DATA_PORT);
90 return -1;
93 static int maui_write(unsigned char data)
95 if (maui_wait(STAT_TX_AVAIL)) {
96 outb((data), HOST_DATA_PORT);
97 return 1;
99 printk(KERN_WARNING "Maui: Write timeout\n");
100 return 0;
103 static void mauiintr(int irq, void *dev_id, struct pt_regs *dummy)
105 irq_ok = 1;
108 static int download_code(void)
110 int i, lines = 0;
111 int eol_seen = 0, done = 0;
112 int skip = 1;
114 printk(KERN_INFO "Code download (%d bytes): ", maui_osLen);
116 for (i = 0; i < maui_osLen; i++) {
117 if (maui_os[i] != '\r') {
118 if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) {
119 skip = 0;
121 if (maui_os[i] == '\n')
122 eol_seen = skip = 1;
123 else if (maui_os[i] == 'S') {
124 if (maui_os[i + 1] == '8')
125 done = 1;
126 if (!maui_write(0xF1))
127 goto failure;
128 if (!maui_write('S'))
129 goto failure;
130 } else {
131 if (!maui_write(maui_os[i]))
132 goto failure;
135 if (eol_seen) {
136 int c = 0;
137 int n;
139 eol_seen = 0;
141 for (n = 0; n < 2; n++) {
142 if (maui_wait(STAT_RX_AVAIL)) {
143 c = inb(HOST_DATA_PORT);
144 break;
147 if (c != 0x80) {
148 printk("Download not acknowledged\n");
149 return 0;
151 else if (!(lines++ % 10))
152 printk(".");
154 if (done) {
155 printk("\n");
156 printk(KERN_INFO "Download complete\n");
157 return 1;
164 failure:
165 printk("\n");
166 printk(KERN_ERR "Download failed!!!\n");
167 return 0;
170 static int __init maui_init(int irq)
172 unsigned char bits;
174 switch (irq) {
175 case 9:
176 bits = 0x00;
177 break;
178 case 5:
179 bits = 0x08;
180 break;
181 case 12:
182 bits = 0x10;
183 break;
184 case 15:
185 bits = 0x18;
186 break;
188 default:
189 printk(KERN_ERR "Maui: Invalid IRQ %d\n", irq);
190 return 0;
192 outb((0x00), HOST_CTRL_PORT); /* Reset */
193 outb((bits), HOST_DATA_PORT); /* Set the IRQ bits */
194 outb((bits | 0x80), HOST_DATA_PORT); /* Set the IRQ bits again? */
195 outb((0x80), HOST_CTRL_PORT); /* Leave reset */
196 outb((0x80), HOST_CTRL_PORT); /* Leave reset */
197 outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */
199 #ifdef CONFIG_SMP
201 int i;
202 for (i = 0; i < 1000000 && !irq_ok; i++)
204 if (!irq_ok)
205 return 0;
207 #endif
208 outb((0x80), HOST_CTRL_PORT); /* Leave reset */
210 printk(KERN_INFO "Turtle Beach Maui initialization\n");
212 if (!download_code())
213 return 0;
215 outb((0xE0), HOST_CTRL_PORT); /* Normal operation */
217 /* Select mpu401 mode */
219 maui_write(0xf0);
220 maui_write(1);
221 if (maui_read() != 0x80) {
222 maui_write(0xf0);
223 maui_write(1);
224 if (maui_read() != 0x80)
225 printk(KERN_ERR "Maui didn't acknowledge set HW mode command\n");
227 printk(KERN_INFO "Maui initialized OK\n");
228 return 1;
231 static int maui_short_wait(int mask) {
232 int i;
234 for (i = 0; i < 1000; i++) {
235 if (inb(HOST_STAT_PORT) & mask) {
236 return 1;
239 return 0;
242 static int maui_load_patch(int dev, int format, const char *addr,
243 int offs, int count, int pmgr_flag)
246 struct sysex_info header;
247 unsigned long left, src_offs;
248 int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header;
249 int i;
251 if (format == SYSEX_PATCH) /* Handled by midi_synth.c */
252 return orig_load_patch(dev, format, addr, offs, count, pmgr_flag);
254 if (format != MAUI_PATCH)
256 printk(KERN_WARNING "Maui: Unknown patch format\n");
258 if (count < hdr_size) {
259 /* printk("Maui error: Patch header too short\n");*/
260 return -EINVAL;
262 count -= hdr_size;
265 * Copy the header from user space but ignore the first bytes which have
266 * been transferred already.
269 if(copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs))
270 return -EFAULT;
272 if (count < header.len) {
273 printk(KERN_ERR "Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len);
274 header.len = count;
276 left = header.len;
277 src_offs = 0;
279 for (i = 0; i < left; i++) {
280 unsigned char data;
282 if(get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])))
283 return -EFAULT;
284 if (i == 0 && !(data & 0x80))
285 return -EINVAL;
287 if (maui_write(data) == -1)
288 return -EIO;
291 if ((i = maui_read()) != 0x80) {
292 if (i != -1)
293 printk("Maui: Error status %02x\n", i);
294 return -EIO;
296 return 0;
299 static int __init probe_maui(struct address_info *hw_config)
301 int i;
302 int tmp1, tmp2, ret;
304 if (check_region(hw_config->io_base, 8))
305 return 0;
307 maui_base = hw_config->io_base;
308 maui_osp = hw_config->osp;
310 if (request_irq(hw_config->irq, mauiintr, 0, "Maui", NULL) < 0)
311 return 0;
314 * Initialize the processor if necessary
317 if (maui_osLen > 0) {
318 if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) ||
319 !maui_write(0x9F) || /* Report firmware version */
320 !maui_short_wait(STAT_RX_AVAIL) ||
321 maui_read() == -1 || maui_read() == -1)
322 if (!maui_init(hw_config->irq)) {
323 free_irq(hw_config->irq, NULL);
324 return 0;
327 if (!maui_write(0xCF)) /* Report hardware version */ {
328 printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
329 free_irq(hw_config->irq, NULL);
330 return 0;
332 if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) {
333 printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
334 free_irq(hw_config->irq, NULL);
335 return 0;
337 if (tmp1 == 0xff || tmp2 == 0xff) {
338 free_irq(hw_config->irq, NULL);
339 return 0;
341 printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2);
343 if (!maui_write(0x9F)) /* Report firmware version */
344 return 0;
345 if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1)
346 return 0;
348 printk(KERN_DEBUG "WaveFront firmware version %d.%d\n", tmp1, tmp2);
350 if (!maui_write(0x85)) /* Report free DRAM */
351 return 0;
352 tmp1 = 0;
353 for (i = 0; i < 4; i++) {
354 tmp1 |= maui_read() << (7 * i);
356 printk(KERN_DEBUG "Available DRAM %dk\n", tmp1 / 1024);
358 for (i = 0; i < 1000; i++)
359 if (probe_mpu401(hw_config))
360 break;
362 ret = probe_mpu401(hw_config);
364 if (ret)
365 request_region(hw_config->io_base + 2, 6, "Maui");
367 return ret;
370 static void __init attach_maui(struct address_info *hw_config)
372 int this_dev;
374 conf_printf("Maui", hw_config);
376 hw_config->irq *= -1;
377 hw_config->name = "Maui";
378 attach_mpu401(hw_config);
380 if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ {
381 struct synth_operations *synth;
383 this_dev = hw_config->slots[1];
386 * Intercept patch loading calls so that they can be handled
387 * by the Maui driver.
390 synth = midi_devs[this_dev]->converter;
391 synth->id = "MAUI";
393 if (synth != NULL) {
394 orig_load_patch = synth->load_patch;
395 synth->load_patch = &maui_load_patch;
396 } else
397 printk(KERN_ERR "Maui: Can't install patch loader\n");
401 static void __exit unload_maui(struct address_info *hw_config)
403 int irq = hw_config->irq;
404 release_region(hw_config->io_base + 2, 6);
405 unload_mpu401(hw_config);
407 if (irq < 0)
408 irq = -irq;
409 if (irq > 0)
410 free_irq(irq, NULL);
413 static int fw_load = 0;
415 static struct address_info cfg;
417 static int __initdata io = -1;
418 static int __initdata irq = -1;
420 MODULE_PARM(io,"i");
421 MODULE_PARM(irq,"i");
424 * Install a Maui card. Needs mpu401 loaded already.
427 static int __init init_maui(void)
429 printk(KERN_INFO "Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996\n");
431 cfg.io_base = io;
432 cfg.irq = irq;
434 if (cfg.io_base == -1 || cfg.irq == -1) {
435 printk(KERN_INFO "maui: irq and io must be set.\n");
436 return -EINVAL;
439 if (maui_os == NULL) {
440 fw_load = 1;
441 maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os);
443 if (probe_maui(&cfg) == 0)
444 return -ENODEV;
445 attach_maui(&cfg);
446 SOUND_LOCK;
447 return 0;
450 static void __exit cleanup_maui(void)
452 if (fw_load && maui_os)
453 vfree(maui_os);
454 unload_maui(&cfg);
455 SOUND_LOCK_END;
458 module_init(init_maui);
459 module_exit(cleanup_maui);
461 #ifndef MODULE
462 static int __init setup_maui(char *str)
464 /* io, irq */
465 int ints[3];
467 str = get_options(str, ARRAY_SIZE(ints), ints);
469 io = ints[1];
470 irq = ints[2];
472 return 1;
475 __setup("maui=", setup_maui);
476 #endif