1 /*
2 * sound/maui.c
3 *
4 * The low level driver for Turtle Beach Maui and Tropez.
5 *
6 *
7 * Copyright (C) by Hannu Savolainen 1993-1997
8 *
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.
12 *
13 * Changes:
14 * Alan Cox General clean up, use kernel IRQ
15 * system
16 * Christoph Hellwig Adapted to module_init/module_exit
17 * Bartlomiej Zolnierkiewicz
18 * Added __init to download_code()
19 *
20 * Status:
21 * Andrew J. Kroll Tested 06/01/1999 with:
22 * * OSWF.MOT File Version: 1.15
23 * * OSWF.MOT File Dated: 09/12/94
24 * * Older versions will cause problems.
25 */
26
27 #include <linux/config.h>
28 #include <linux/module.h>
29 #include <linux/init.h>
30
31 #define USE_SEQ_MACROS
32 #define USE_SIMPLE_MACROS
33
34 #include "sound_config.h"
35 #include "sound_firmware.h"
36
37 #include "mpu401.h"
38
39 static int maui_base = 0x330;
40
41 static volatile int irq_ok = 0;
42 static int *maui_osp;
43
44 #define HOST_DATA_PORT (maui_base + 2)
45 #define HOST_STAT_PORT (maui_base + 3)
46 #define HOST_CTRL_PORT (maui_base + 3)
47
48 #define STAT_TX_INTR 0x40
49 #define STAT_TX_AVAIL 0x20
50 #define STAT_TX_IENA 0x10
51 #define STAT_RX_INTR 0x04
52 #define STAT_RX_AVAIL 0x02
53 #define STAT_RX_IENA 0x01
54
55 static int (*orig_load_patch) (int dev, int format, const char *addr,
56 int offs, int count, int pmgr_flag) = NULL;
57
58 #include "maui_boot.h"
59
maui_wait(int mask)60 static int maui_wait(int mask)
61 {
62 int i;
63
64 /*
65 * Perform a short initial wait without sleeping
66 */
67
68 for (i = 0; i < 100; i++)
69 if (inb(HOST_STAT_PORT) & mask)
70 return 1;
71
72 /*
73 * Wait up to 15 seconds with sleeping
74 */
75
76 for (i = 0; i < 150; i++) {
77 if (inb(HOST_STAT_PORT) & mask)
78 return 1;
79 current->state = TASK_INTERRUPTIBLE;
80 schedule_timeout(HZ / 10);
81 if (signal_pending(current))
82 return 0;
83 }
84 return 0;
85 }
86
maui_read(void)87 static int maui_read(void)
88 {
89 if (maui_wait(STAT_RX_AVAIL))
90 return inb(HOST_DATA_PORT);
91 return -1;
92 }
93
maui_write(unsigned char data)94 static int maui_write(unsigned char data)
95 {
96 if (maui_wait(STAT_TX_AVAIL)) {
97 outb((data), HOST_DATA_PORT);
98 return 1;
99 }
100 printk(KERN_WARNING "Maui: Write timeout\n");
101 return 0;
102 }
103
mauiintr(int irq,void * dev_id,struct pt_regs * dummy)104 static void mauiintr(int irq, void *dev_id, struct pt_regs *dummy)
105 {
106 irq_ok = 1;
107 }
108
download_code(void)109 static int __init download_code(void)
110 {
111 int i, lines = 0;
112 int eol_seen = 0, done = 0;
113 int skip = 1;
114
115 printk(KERN_INFO "Code download (%d bytes): ", maui_osLen);
116
117 for (i = 0; i < maui_osLen; i++) {
118 if (maui_os[i] != '\r') {
119 if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) {
120 skip = 0;
121
122 if (maui_os[i] == '\n')
123 eol_seen = skip = 1;
124 else if (maui_os[i] == 'S') {
125 if (maui_os[i + 1] == '8')
126 done = 1;
127 if (!maui_write(0xF1))
128 goto failure;
129 if (!maui_write('S'))
130 goto failure;
131 } else {
132 if (!maui_write(maui_os[i]))
133 goto failure;
134 }
135
136 if (eol_seen) {
137 int c = 0;
138 int n;
139
140 eol_seen = 0;
141
142 for (n = 0; n < 2; n++) {
143 if (maui_wait(STAT_RX_AVAIL)) {
144 c = inb(HOST_DATA_PORT);
145 break;
146 }
147 }
148 if (c != 0x80) {
149 printk("Download not acknowledged\n");
150 return 0;
151 }
152 else if (!(lines++ % 10))
153 printk(".");
154
155 if (done) {
156 printk("\n");
157 printk(KERN_INFO "Download complete\n");
158 return 1;
159 }
160 }
161 }
162 }
163 }
164
165 failure:
166 printk("\n");
167 printk(KERN_ERR "Download failed!!!\n");
168 return 0;
169 }
170
maui_init(int irq)171 static int __init maui_init(int irq)
172 {
173 unsigned char bits;
174
175 switch (irq) {
176 case 9:
177 bits = 0x00;
178 break;
179 case 5:
180 bits = 0x08;
181 break;
182 case 12:
183 bits = 0x10;
184 break;
185 case 15:
186 bits = 0x18;
187 break;
188
189 default:
190 printk(KERN_ERR "Maui: Invalid IRQ %d\n", irq);
191 return 0;
192 }
193 outb((0x00), HOST_CTRL_PORT); /* Reset */
194 outb((bits), HOST_DATA_PORT); /* Set the IRQ bits */
195 outb((bits | 0x80), HOST_DATA_PORT); /* Set the IRQ bits again? */
196 outb((0x80), HOST_CTRL_PORT); /* Leave reset */
197 outb((0x80), HOST_CTRL_PORT); /* Leave reset */
198 outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */
199
200 #ifdef CONFIG_SMP
201 {
202 int i;
203 for (i = 0; i < 1000000 && !irq_ok; i++)
204 ;
205 if (!irq_ok)
206 return 0;
207 }
208 #endif
209 outb((0x80), HOST_CTRL_PORT); /* Leave reset */
210
211 printk(KERN_INFO "Turtle Beach Maui initialization\n");
212
213 if (!download_code())
214 return 0;
215
216 outb((0xE0), HOST_CTRL_PORT); /* Normal operation */
217
218 /* Select mpu401 mode */
219
220 maui_write(0xf0);
221 maui_write(1);
222 if (maui_read() != 0x80) {
223 maui_write(0xf0);
224 maui_write(1);
225 if (maui_read() != 0x80)
226 printk(KERN_ERR "Maui didn't acknowledge set HW mode command\n");
227 }
228 printk(KERN_INFO "Maui initialized OK\n");
229 return 1;
230 }
231
maui_short_wait(int mask)232 static int maui_short_wait(int mask) {
233 int i;
234
235 for (i = 0; i < 1000; i++) {
236 if (inb(HOST_STAT_PORT) & mask) {
237 return 1;
238 }
239 }
240 return 0;
241 }
242
maui_load_patch(int dev,int format,const char * addr,int offs,int count,int pmgr_flag)243 static int maui_load_patch(int dev, int format, const char *addr,
244 int offs, int count, int pmgr_flag)
245 {
246
247 struct sysex_info header;
248 unsigned long left, src_offs;
249 int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header;
250 int i;
251
252 if (format == SYSEX_PATCH) /* Handled by midi_synth.c */
253 return orig_load_patch(dev, format, addr, offs, count, pmgr_flag);
254
255 if (format != MAUI_PATCH)
256 {
257 printk(KERN_WARNING "Maui: Unknown patch format\n");
258 }
259 if (count < hdr_size) {
260 /* printk("Maui error: Patch header too short\n");*/
261 return -EINVAL;
262 }
263 count -= hdr_size;
264
265 /*
266 * Copy the header from user space but ignore the first bytes which have
267 * been transferred already.
268 */
269
270 if(copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs))
271 return -EFAULT;
272
273 if (count < header.len) {
274 printk(KERN_ERR "Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len);
275 header.len = count;
276 }
277 left = header.len;
278 src_offs = 0;
279
280 for (i = 0; i < left; i++) {
281 unsigned char data;
282
283 if(get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])))
284 return -EFAULT;
285 if (i == 0 && !(data & 0x80))
286 return -EINVAL;
287
288 if (maui_write(data) == -1)
289 return -EIO;
290 }
291
292 if ((i = maui_read()) != 0x80) {
293 if (i != -1)
294 printk("Maui: Error status %02x\n", i);
295 return -EIO;
296 }
297 return 0;
298 }
299
probe_maui(struct address_info * hw_config)300 static int __init probe_maui(struct address_info *hw_config)
301 {
302 int i;
303 int tmp1, tmp2, ret;
304
305 if (check_region(hw_config->io_base, 8))
306 return 0;
307
308 maui_base = hw_config->io_base;
309 maui_osp = hw_config->osp;
310
311 if (request_irq(hw_config->irq, mauiintr, 0, "Maui", NULL) < 0)
312 return 0;
313
314 /*
315 * Initialize the processor if necessary
316 */
317
318 if (maui_osLen > 0) {
319 if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) ||
320 !maui_write(0x9F) || /* Report firmware version */
321 !maui_short_wait(STAT_RX_AVAIL) ||
322 maui_read() == -1 || maui_read() == -1)
323 if (!maui_init(hw_config->irq)) {
324 free_irq(hw_config->irq, NULL);
325 return 0;
326 }
327 }
328 if (!maui_write(0xCF)) /* Report hardware version */ {
329 printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
330 free_irq(hw_config->irq, NULL);
331 return 0;
332 }
333 if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) {
334 printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
335 free_irq(hw_config->irq, NULL);
336 return 0;
337 }
338 if (tmp1 == 0xff || tmp2 == 0xff) {
339 free_irq(hw_config->irq, NULL);
340 return 0;
341 }
342 printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2);
343
344 if (!maui_write(0x9F)) /* Report firmware version */
345 return 0;
346 if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1)
347 return 0;
348
349 printk(KERN_DEBUG "WaveFront firmware version %d.%d\n", tmp1, tmp2);
350
351 if (!maui_write(0x85)) /* Report free DRAM */
352 return 0;
353 tmp1 = 0;
354 for (i = 0; i < 4; i++) {
355 tmp1 |= maui_read() << (7 * i);
356 }
357 printk(KERN_DEBUG "Available DRAM %dk\n", tmp1 / 1024);
358
359 for (i = 0; i < 1000; i++)
360 if (probe_mpu401(hw_config))
361 break;
362
363 ret = probe_mpu401(hw_config);
364
365 if (ret)
366 request_region(hw_config->io_base + 2, 6, "Maui");
367
368 return ret;
369 }
370
attach_maui(struct address_info * hw_config)371 static void __init attach_maui(struct address_info *hw_config)
372 {
373 int this_dev;
374
375 conf_printf("Maui", hw_config);
376
377 hw_config->irq *= -1;
378 hw_config->name = "Maui";
379 attach_mpu401(hw_config, THIS_MODULE);
380
381 if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ {
382 struct synth_operations *synth;
383
384 this_dev = hw_config->slots[1];
385
386 /*
387 * Intercept patch loading calls so that they can be handled
388 * by the Maui driver.
389 */
390
391 synth = midi_devs[this_dev]->converter;
392 synth->id = "MAUI";
393
394 if (synth != NULL) {
395 orig_load_patch = synth->load_patch;
396 synth->load_patch = &maui_load_patch;
397 } else
398 printk(KERN_ERR "Maui: Can't install patch loader\n");
399 }
400 }
401
unload_maui(struct address_info * hw_config)402 static void __exit unload_maui(struct address_info *hw_config)
403 {
404 int irq = hw_config->irq;
405 release_region(hw_config->io_base + 2, 6);
406 unload_mpu401(hw_config);
407
408 if (irq < 0)
409 irq = -irq;
410 if (irq > 0)
411 free_irq(irq, NULL);
412 }
413
414 static int fw_load = 0;
415
416 static struct address_info cfg;
417
418 static int __initdata io = -1;
419 static int __initdata irq = -1;
420
421 MODULE_PARM(io,"i");
422 MODULE_PARM(irq,"i");
423
424 /*
425 * Install a Maui card. Needs mpu401 loaded already.
426 */
427
init_maui(void)428 static int __init init_maui(void)
429 {
430 printk(KERN_INFO "Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996\n");
431
432 cfg.io_base = io;
433 cfg.irq = irq;
434
435 if (cfg.io_base == -1 || cfg.irq == -1) {
436 printk(KERN_INFO "maui: irq and io must be set.\n");
437 return -EINVAL;
438 }
439
440 if (maui_os == NULL) {
441 fw_load = 1;
442 maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os);
443 }
444 if (probe_maui(&cfg) == 0)
445 return -ENODEV;
446 attach_maui(&cfg);
447
448 return 0;
449 }
450
cleanup_maui(void)451 static void __exit cleanup_maui(void)
452 {
453 if (fw_load && maui_os)
454 vfree(maui_os);
455 unload_maui(&cfg);
456 }
457
458 module_init(init_maui);
459 module_exit(cleanup_maui);
460
461 #ifndef MODULE
setup_maui(char * str)462 static int __init setup_maui(char *str)
463 {
464 /* io, irq */
465 int ints[3];
466
467 str = get_options(str, ARRAY_SIZE(ints), ints);
468
469 io = ints[1];
470 irq = ints[2];
471
472 return 1;
473 }
474
475 __setup("maui=", setup_maui);
476 #endif
477 MODULE_LICENSE("GPL");
478