diff options
Diffstat (limited to 'sound/oss/wf_midi.c')
-rw-r--r-- | sound/oss/wf_midi.c | 880 |
1 files changed, 880 insertions, 0 deletions
diff --git a/sound/oss/wf_midi.c b/sound/oss/wf_midi.c new file mode 100644 index 000000000000..7b167b74375b --- /dev/null +++ b/sound/oss/wf_midi.c | |||
@@ -0,0 +1,880 @@ | |||
1 | /* | ||
2 | * sound/wf_midi.c | ||
3 | * | ||
4 | * The low level driver for the WaveFront ICS2115 MIDI interface(s) | ||
5 | * Note that there is also an MPU-401 emulation (actually, a UART-401 | ||
6 | * emulation) on the CS4232 on the Tropez Plus. This code has nothing | ||
7 | * to do with that interface at all. | ||
8 | * | ||
9 | * The interface is essentially just a UART-401, but is has the | ||
10 | * interesting property of supporting what Turtle Beach called | ||
11 | * "Virtual MIDI" mode. In this mode, there are effectively *two* | ||
12 | * MIDI buses accessible via the interface, one that is routed | ||
13 | * solely to/from the external WaveFront synthesizer and the other | ||
14 | * corresponding to the pin/socket connector used to link external | ||
15 | * MIDI devices to the board. | ||
16 | * | ||
17 | * This driver fully supports this mode, allowing two distinct | ||
18 | * midi devices (/dev/midiNN and /dev/midiNN+1) to be used | ||
19 | * completely independently, giving 32 channels of MIDI routing, | ||
20 | * 16 to the WaveFront synth and 16 to the external MIDI bus. | ||
21 | * | ||
22 | * Switching between the two is accomplished externally by the driver | ||
23 | * using the two otherwise unused MIDI bytes. See the code for more details. | ||
24 | * | ||
25 | * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see wavefront.c) | ||
26 | * | ||
27 | * The main reason to turn off Virtual MIDI mode is when you want to | ||
28 | * tightly couple the WaveFront synth with an external MIDI | ||
29 | * device. You won't be able to distinguish the source of any MIDI | ||
30 | * data except via SysEx ID, but thats probably OK, since for the most | ||
31 | * part, the WaveFront won't be sending any MIDI data at all. | ||
32 | * | ||
33 | * The main reason to turn on Virtual MIDI Mode is to provide two | ||
34 | * completely independent 16-channel MIDI buses, one to the | ||
35 | * WaveFront and one to any external MIDI devices. Given the 32 | ||
36 | * voice nature of the WaveFront, its pretty easy to find a use | ||
37 | * for all 16 channels driving just that synth. | ||
38 | * | ||
39 | */ | ||
40 | |||
41 | /* | ||
42 | * Copyright (C) by Paul Barton-Davis 1998 | ||
43 | * Some portions of this file are derived from work that is: | ||
44 | * | ||
45 | * CopyriGht (C) by Hannu Savolainen 1993-1996 | ||
46 | * | ||
47 | * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) | ||
48 | * Version 2 (June 1991). See the "COPYING" file distributed with this software | ||
49 | * for more info. | ||
50 | */ | ||
51 | |||
52 | #include <linux/init.h> | ||
53 | #include <linux/interrupt.h> | ||
54 | #include <linux/spinlock.h> | ||
55 | #include "sound_config.h" | ||
56 | |||
57 | #include <linux/wavefront.h> | ||
58 | |||
59 | #ifdef MODULE | ||
60 | |||
61 | struct wf_mpu_config { | ||
62 | int base; | ||
63 | #define DATAPORT(d) (d)->base | ||
64 | #define COMDPORT(d) (d)->base+1 | ||
65 | #define STATPORT(d) (d)->base+1 | ||
66 | |||
67 | int irq; | ||
68 | int opened; | ||
69 | int devno; | ||
70 | int synthno; | ||
71 | int mode; | ||
72 | #define MODE_MIDI 1 | ||
73 | #define MODE_SYNTH 2 | ||
74 | |||
75 | void (*inputintr) (int dev, unsigned char data); | ||
76 | char isvirtual; /* do virtual I/O stuff */ | ||
77 | }; | ||
78 | |||
79 | static struct wf_mpu_config devs[2]; | ||
80 | static struct wf_mpu_config *phys_dev = &devs[0]; | ||
81 | static struct wf_mpu_config *virt_dev = &devs[1]; | ||
82 | |||
83 | static void start_uart_mode (void); | ||
84 | static DEFINE_SPINLOCK(lock); | ||
85 | |||
86 | #define OUTPUT_READY 0x40 | ||
87 | #define INPUT_AVAIL 0x80 | ||
88 | #define MPU_ACK 0xFE | ||
89 | #define UART_MODE_ON 0x3F | ||
90 | |||
91 | static inline int wf_mpu_status (void) | ||
92 | { | ||
93 | return inb (STATPORT (phys_dev)); | ||
94 | } | ||
95 | |||
96 | static inline int input_avail (void) | ||
97 | { | ||
98 | return !(wf_mpu_status() & INPUT_AVAIL); | ||
99 | } | ||
100 | |||
101 | static inline int output_ready (void) | ||
102 | { | ||
103 | return !(wf_mpu_status() & OUTPUT_READY); | ||
104 | } | ||
105 | |||
106 | static inline int read_data (void) | ||
107 | { | ||
108 | return inb (DATAPORT (phys_dev)); | ||
109 | } | ||
110 | |||
111 | static inline void write_data (unsigned char byte) | ||
112 | { | ||
113 | outb (byte, DATAPORT (phys_dev)); | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * States for the input scanner (should be in dev_table.h) | ||
118 | */ | ||
119 | |||
120 | #define MST_SYSMSG 100 /* System message (sysx etc). */ | ||
121 | #define MST_MTC 102 /* Midi Time Code (MTC) qframe msg */ | ||
122 | #define MST_SONGSEL 103 /* Song select */ | ||
123 | #define MST_SONGPOS 104 /* Song position pointer */ | ||
124 | #define MST_TIMED 105 /* Leading timing byte rcvd */ | ||
125 | |||
126 | /* buffer space check for input scanner */ | ||
127 | |||
128 | #define BUFTEST(mi) if (mi->m_ptr >= MI_MAX || mi->m_ptr < 0) \ | ||
129 | {printk(KERN_ERR "WF-MPU: Invalid buffer pointer %d/%d, s=%d\n", \ | ||
130 | mi->m_ptr, mi->m_left, mi->m_state);mi->m_ptr--;} | ||
131 | |||
132 | static unsigned char len_tab[] = /* # of data bytes following a status | ||
133 | */ | ||
134 | { | ||
135 | 2, /* 8x */ | ||
136 | 2, /* 9x */ | ||
137 | 2, /* Ax */ | ||
138 | 2, /* Bx */ | ||
139 | 1, /* Cx */ | ||
140 | 1, /* Dx */ | ||
141 | 2, /* Ex */ | ||
142 | 0 /* Fx */ | ||
143 | }; | ||
144 | |||
145 | static int | ||
146 | wf_mpu_input_scanner (int devno, int synthdev, unsigned char midic) | ||
147 | |||
148 | { | ||
149 | struct midi_input_info *mi = &midi_devs[devno]->in_info; | ||
150 | |||
151 | switch (mi->m_state) { | ||
152 | case MST_INIT: | ||
153 | switch (midic) { | ||
154 | case 0xf8: | ||
155 | /* Timer overflow */ | ||
156 | break; | ||
157 | |||
158 | case 0xfc: | ||
159 | break; | ||
160 | |||
161 | case 0xfd: | ||
162 | /* XXX do something useful with this. If there is | ||
163 | an external MIDI timer (e.g. a hardware sequencer, | ||
164 | a useful timer can be derived ... | ||
165 | |||
166 | For now, no timer support. | ||
167 | */ | ||
168 | break; | ||
169 | |||
170 | case 0xfe: | ||
171 | return MPU_ACK; | ||
172 | break; | ||
173 | |||
174 | case 0xf0: | ||
175 | case 0xf1: | ||
176 | case 0xf2: | ||
177 | case 0xf3: | ||
178 | case 0xf4: | ||
179 | case 0xf5: | ||
180 | case 0xf6: | ||
181 | case 0xf7: | ||
182 | break; | ||
183 | |||
184 | case 0xf9: | ||
185 | break; | ||
186 | |||
187 | case 0xff: | ||
188 | mi->m_state = MST_SYSMSG; | ||
189 | break; | ||
190 | |||
191 | default: | ||
192 | if (midic <= 0xef) { | ||
193 | mi->m_state = MST_TIMED; | ||
194 | } | ||
195 | else | ||
196 | printk (KERN_ERR "<MPU: Unknown event %02x> ", | ||
197 | midic); | ||
198 | } | ||
199 | break; | ||
200 | |||
201 | case MST_TIMED: | ||
202 | { | ||
203 | int msg = ((int) (midic & 0xf0) >> 4); | ||
204 | |||
205 | mi->m_state = MST_DATA; | ||
206 | |||
207 | if (msg < 8) { /* Data byte */ | ||
208 | |||
209 | msg = ((int) (mi->m_prev_status & 0xf0) >> 4); | ||
210 | msg -= 8; | ||
211 | mi->m_left = len_tab[msg] - 1; | ||
212 | |||
213 | mi->m_ptr = 2; | ||
214 | mi->m_buf[0] = mi->m_prev_status; | ||
215 | mi->m_buf[1] = midic; | ||
216 | |||
217 | if (mi->m_left <= 0) { | ||
218 | mi->m_state = MST_INIT; | ||
219 | do_midi_msg (synthdev, mi->m_buf, mi->m_ptr); | ||
220 | mi->m_ptr = 0; | ||
221 | } | ||
222 | } else if (msg == 0xf) { /* MPU MARK */ | ||
223 | |||
224 | mi->m_state = MST_INIT; | ||
225 | |||
226 | switch (midic) { | ||
227 | case 0xf8: | ||
228 | break; | ||
229 | |||
230 | case 0xf9: | ||
231 | break; | ||
232 | |||
233 | case 0xfc: | ||
234 | break; | ||
235 | |||
236 | default: | ||
237 | break; | ||
238 | } | ||
239 | } else { | ||
240 | mi->m_prev_status = midic; | ||
241 | msg -= 8; | ||
242 | mi->m_left = len_tab[msg]; | ||
243 | |||
244 | mi->m_ptr = 1; | ||
245 | mi->m_buf[0] = midic; | ||
246 | |||
247 | if (mi->m_left <= 0) { | ||
248 | mi->m_state = MST_INIT; | ||
249 | do_midi_msg (synthdev, mi->m_buf, mi->m_ptr); | ||
250 | mi->m_ptr = 0; | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | break; | ||
255 | |||
256 | case MST_SYSMSG: | ||
257 | switch (midic) { | ||
258 | case 0xf0: | ||
259 | mi->m_state = MST_SYSEX; | ||
260 | break; | ||
261 | |||
262 | case 0xf1: | ||
263 | mi->m_state = MST_MTC; | ||
264 | break; | ||
265 | |||
266 | case 0xf2: | ||
267 | mi->m_state = MST_SONGPOS; | ||
268 | mi->m_ptr = 0; | ||
269 | break; | ||
270 | |||
271 | case 0xf3: | ||
272 | mi->m_state = MST_SONGSEL; | ||
273 | break; | ||
274 | |||
275 | case 0xf6: | ||
276 | mi->m_state = MST_INIT; | ||
277 | |||
278 | /* | ||
279 | * Real time messages | ||
280 | */ | ||
281 | case 0xf8: | ||
282 | /* midi clock */ | ||
283 | mi->m_state = MST_INIT; | ||
284 | /* XXX need ext MIDI timer support */ | ||
285 | break; | ||
286 | |||
287 | case 0xfA: | ||
288 | mi->m_state = MST_INIT; | ||
289 | /* XXX need ext MIDI timer support */ | ||
290 | break; | ||
291 | |||
292 | case 0xFB: | ||
293 | mi->m_state = MST_INIT; | ||
294 | /* XXX need ext MIDI timer support */ | ||
295 | break; | ||
296 | |||
297 | case 0xFC: | ||
298 | mi->m_state = MST_INIT; | ||
299 | /* XXX need ext MIDI timer support */ | ||
300 | break; | ||
301 | |||
302 | case 0xFE: | ||
303 | /* active sensing */ | ||
304 | mi->m_state = MST_INIT; | ||
305 | break; | ||
306 | |||
307 | case 0xff: | ||
308 | mi->m_state = MST_INIT; | ||
309 | break; | ||
310 | |||
311 | default: | ||
312 | printk (KERN_ERR "unknown MIDI sysmsg %0x\n", midic); | ||
313 | mi->m_state = MST_INIT; | ||
314 | } | ||
315 | break; | ||
316 | |||
317 | case MST_MTC: | ||
318 | mi->m_state = MST_INIT; | ||
319 | break; | ||
320 | |||
321 | case MST_SYSEX: | ||
322 | if (midic == 0xf7) { | ||
323 | mi->m_state = MST_INIT; | ||
324 | } else { | ||
325 | /* XXX fix me */ | ||
326 | } | ||
327 | break; | ||
328 | |||
329 | case MST_SONGPOS: | ||
330 | BUFTEST (mi); | ||
331 | mi->m_buf[mi->m_ptr++] = midic; | ||
332 | if (mi->m_ptr == 2) { | ||
333 | mi->m_state = MST_INIT; | ||
334 | mi->m_ptr = 0; | ||
335 | /* XXX need ext MIDI timer support */ | ||
336 | } | ||
337 | break; | ||
338 | |||
339 | case MST_DATA: | ||
340 | BUFTEST (mi); | ||
341 | mi->m_buf[mi->m_ptr++] = midic; | ||
342 | if ((--mi->m_left) <= 0) { | ||
343 | mi->m_state = MST_INIT; | ||
344 | do_midi_msg (synthdev, mi->m_buf, mi->m_ptr); | ||
345 | mi->m_ptr = 0; | ||
346 | } | ||
347 | break; | ||
348 | |||
349 | default: | ||
350 | printk (KERN_ERR "Bad state %d ", mi->m_state); | ||
351 | mi->m_state = MST_INIT; | ||
352 | } | ||
353 | |||
354 | return 1; | ||
355 | } | ||
356 | |||
357 | static irqreturn_t | ||
358 | wf_mpuintr(int irq, void *dev_id, struct pt_regs *dummy) | ||
359 | |||
360 | { | ||
361 | struct wf_mpu_config *physical_dev = dev_id; | ||
362 | static struct wf_mpu_config *input_dev; | ||
363 | struct midi_input_info *mi = &midi_devs[physical_dev->devno]->in_info; | ||
364 | int n; | ||
365 | |||
366 | if (!input_avail()) { /* not for us */ | ||
367 | return IRQ_NONE; | ||
368 | } | ||
369 | |||
370 | if (mi->m_busy) | ||
371 | return IRQ_HANDLED; | ||
372 | spin_lock(&lock); | ||
373 | mi->m_busy = 1; | ||
374 | |||
375 | if (!input_dev) { | ||
376 | input_dev = physical_dev; | ||
377 | } | ||
378 | |||
379 | n = 50; /* XXX why ? */ | ||
380 | |||
381 | do { | ||
382 | unsigned char c = read_data (); | ||
383 | |||
384 | if (phys_dev->isvirtual) { | ||
385 | |||
386 | if (c == WF_EXTERNAL_SWITCH) { | ||
387 | input_dev = virt_dev; | ||
388 | continue; | ||
389 | } else if (c == WF_INTERNAL_SWITCH) { | ||
390 | input_dev = phys_dev; | ||
391 | continue; | ||
392 | } /* else just leave it as it is */ | ||
393 | |||
394 | } else { | ||
395 | input_dev = phys_dev; | ||
396 | } | ||
397 | |||
398 | if (input_dev->mode == MODE_SYNTH) { | ||
399 | |||
400 | wf_mpu_input_scanner (input_dev->devno, | ||
401 | input_dev->synthno, c); | ||
402 | |||
403 | } else if (input_dev->opened & OPEN_READ) { | ||
404 | |||
405 | if (input_dev->inputintr) { | ||
406 | input_dev->inputintr (input_dev->devno, c); | ||
407 | } | ||
408 | } | ||
409 | |||
410 | } while (input_avail() && n-- > 0); | ||
411 | |||
412 | mi->m_busy = 0; | ||
413 | spin_unlock(&lock); | ||
414 | return IRQ_HANDLED; | ||
415 | } | ||
416 | |||
417 | static int | ||
418 | wf_mpu_open (int dev, int mode, | ||
419 | void (*input) (int dev, unsigned char data), | ||
420 | void (*output) (int dev) | ||
421 | ) | ||
422 | { | ||
423 | struct wf_mpu_config *devc; | ||
424 | |||
425 | if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL) | ||
426 | return -(ENXIO); | ||
427 | |||
428 | if (phys_dev->devno == dev) { | ||
429 | devc = phys_dev; | ||
430 | } else if (phys_dev->isvirtual && virt_dev->devno == dev) { | ||
431 | devc = virt_dev; | ||
432 | } else { | ||
433 | printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev); | ||
434 | return -(EINVAL); | ||
435 | } | ||
436 | |||
437 | if (devc->opened) { | ||
438 | return -(EBUSY); | ||
439 | } | ||
440 | |||
441 | devc->mode = MODE_MIDI; | ||
442 | devc->opened = mode; | ||
443 | devc->synthno = 0; | ||
444 | |||
445 | devc->inputintr = input; | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static void | ||
450 | wf_mpu_close (int dev) | ||
451 | { | ||
452 | struct wf_mpu_config *devc; | ||
453 | |||
454 | if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL) | ||
455 | return; | ||
456 | |||
457 | if (phys_dev->devno == dev) { | ||
458 | devc = phys_dev; | ||
459 | } else if (phys_dev->isvirtual && virt_dev->devno == dev) { | ||
460 | devc = virt_dev; | ||
461 | } else { | ||
462 | printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev); | ||
463 | return; | ||
464 | } | ||
465 | |||
466 | devc->mode = 0; | ||
467 | devc->inputintr = NULL; | ||
468 | devc->opened = 0; | ||
469 | } | ||
470 | |||
471 | static int | ||
472 | wf_mpu_out (int dev, unsigned char midi_byte) | ||
473 | { | ||
474 | int timeout; | ||
475 | unsigned long flags; | ||
476 | static int lastoutdev = -1; | ||
477 | unsigned char switchch; | ||
478 | |||
479 | if (phys_dev->isvirtual && lastoutdev != dev) { | ||
480 | |||
481 | if (dev == phys_dev->devno) { | ||
482 | switchch = WF_INTERNAL_SWITCH; | ||
483 | } else if (dev == virt_dev->devno) { | ||
484 | switchch = WF_EXTERNAL_SWITCH; | ||
485 | } else { | ||
486 | printk (KERN_ERR "WF-MPU: bad device number %d", dev); | ||
487 | return (0); | ||
488 | } | ||
489 | |||
490 | /* XXX fix me */ | ||
491 | |||
492 | for (timeout = 30000; timeout > 0 && !output_ready (); | ||
493 | timeout--); | ||
494 | |||
495 | spin_lock_irqsave(&lock,flags); | ||
496 | |||
497 | if (!output_ready ()) { | ||
498 | printk (KERN_WARNING "WF-MPU: Send switch " | ||
499 | "byte timeout\n"); | ||
500 | spin_unlock_irqrestore(&lock,flags); | ||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | write_data (switchch); | ||
505 | spin_unlock_irqrestore(&lock,flags); | ||
506 | } | ||
507 | |||
508 | lastoutdev = dev; | ||
509 | |||
510 | /* | ||
511 | * Sometimes it takes about 30000 loops before the output becomes ready | ||
512 | * (After reset). Normally it takes just about 10 loops. | ||
513 | */ | ||
514 | |||
515 | /* XXX fix me */ | ||
516 | |||
517 | for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); | ||
518 | |||
519 | spin_lock_irqsave(&lock,flags); | ||
520 | if (!output_ready ()) { | ||
521 | spin_unlock_irqrestore(&lock,flags); | ||
522 | printk (KERN_WARNING "WF-MPU: Send data timeout\n"); | ||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | write_data (midi_byte); | ||
527 | spin_unlock_irqrestore(&lock,flags); | ||
528 | |||
529 | return 1; | ||
530 | } | ||
531 | |||
532 | static inline int wf_mpu_start_read (int dev) { | ||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static inline int wf_mpu_end_read (int dev) { | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | static int wf_mpu_ioctl (int dev, unsigned cmd, void __user *arg) | ||
541 | { | ||
542 | printk (KERN_WARNING | ||
543 | "WF-MPU: Intelligent mode not supported by hardware.\n"); | ||
544 | return -(EINVAL); | ||
545 | } | ||
546 | |||
547 | static int wf_mpu_buffer_status (int dev) | ||
548 | { | ||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | static struct synth_operations wf_mpu_synth_operations[2]; | ||
553 | static struct midi_operations wf_mpu_midi_operations[2]; | ||
554 | |||
555 | static struct midi_operations wf_mpu_midi_proto = | ||
556 | { | ||
557 | .owner = THIS_MODULE, | ||
558 | .info = {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, | ||
559 | .in_info = {0}, /* in_info */ | ||
560 | .open = wf_mpu_open, | ||
561 | .close = wf_mpu_close, | ||
562 | .ioctl = wf_mpu_ioctl, | ||
563 | .outputc = wf_mpu_out, | ||
564 | .start_read = wf_mpu_start_read, | ||
565 | .end_read = wf_mpu_end_read, | ||
566 | .buffer_status = wf_mpu_buffer_status, | ||
567 | }; | ||
568 | |||
569 | static struct synth_info wf_mpu_synth_info_proto = | ||
570 | {"WaveFront MPU-401 interface", 0, | ||
571 | SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT}; | ||
572 | |||
573 | static struct synth_info wf_mpu_synth_info[2]; | ||
574 | |||
575 | static int | ||
576 | wf_mpu_synth_ioctl (int dev, unsigned int cmd, void __user *arg) | ||
577 | { | ||
578 | int midi_dev; | ||
579 | int index; | ||
580 | |||
581 | midi_dev = synth_devs[dev]->midi_dev; | ||
582 | |||
583 | if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL) | ||
584 | return -(ENXIO); | ||
585 | |||
586 | if (midi_dev == phys_dev->devno) { | ||
587 | index = 0; | ||
588 | } else if (phys_dev->isvirtual && midi_dev == virt_dev->devno) { | ||
589 | index = 1; | ||
590 | } else { | ||
591 | return -(EINVAL); | ||
592 | } | ||
593 | |||
594 | switch (cmd) { | ||
595 | |||
596 | case SNDCTL_SYNTH_INFO: | ||
597 | if (copy_to_user(arg, | ||
598 | &wf_mpu_synth_info[index], | ||
599 | sizeof (struct synth_info))) | ||
600 | return -EFAULT; | ||
601 | return 0; | ||
602 | |||
603 | case SNDCTL_SYNTH_MEMAVL: | ||
604 | return 0x7fffffff; | ||
605 | |||
606 | default: | ||
607 | return -EINVAL; | ||
608 | } | ||
609 | } | ||
610 | |||
611 | static int | ||
612 | wf_mpu_synth_open (int dev, int mode) | ||
613 | { | ||
614 | int midi_dev; | ||
615 | struct wf_mpu_config *devc; | ||
616 | |||
617 | midi_dev = synth_devs[dev]->midi_dev; | ||
618 | |||
619 | if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL) { | ||
620 | return -(ENXIO); | ||
621 | } | ||
622 | |||
623 | if (phys_dev->devno == midi_dev) { | ||
624 | devc = phys_dev; | ||
625 | } else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) { | ||
626 | devc = virt_dev; | ||
627 | } else { | ||
628 | printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev); | ||
629 | return -(EINVAL); | ||
630 | } | ||
631 | |||
632 | if (devc->opened) { | ||
633 | return -(EBUSY); | ||
634 | } | ||
635 | |||
636 | devc->mode = MODE_SYNTH; | ||
637 | devc->synthno = dev; | ||
638 | devc->opened = mode; | ||
639 | devc->inputintr = NULL; | ||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | static void | ||
644 | wf_mpu_synth_close (int dev) | ||
645 | { | ||
646 | int midi_dev; | ||
647 | struct wf_mpu_config *devc; | ||
648 | |||
649 | midi_dev = synth_devs[dev]->midi_dev; | ||
650 | |||
651 | if (phys_dev->devno == midi_dev) { | ||
652 | devc = phys_dev; | ||
653 | } else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) { | ||
654 | devc = virt_dev; | ||
655 | } else { | ||
656 | printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev); | ||
657 | return; | ||
658 | } | ||
659 | |||
660 | devc->inputintr = NULL; | ||
661 | devc->opened = 0; | ||
662 | devc->mode = 0; | ||
663 | } | ||
664 | |||
665 | #define _MIDI_SYNTH_C_ | ||
666 | #define MIDI_SYNTH_NAME "WaveFront (MIDI)" | ||
667 | #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT | ||
668 | #include "midi_synth.h" | ||
669 | |||
670 | static struct synth_operations wf_mpu_synth_proto = | ||
671 | { | ||
672 | .owner = THIS_MODULE, | ||
673 | .id = "WaveFront (ICS2115)", | ||
674 | .info = NULL, /* info field, filled in during configuration */ | ||
675 | .midi_dev = 0, /* MIDI dev XXX should this be -1 ? */ | ||
676 | .synth_type = SYNTH_TYPE_MIDI, | ||
677 | .synth_subtype = SAMPLE_TYPE_WAVEFRONT, | ||
678 | .open = wf_mpu_synth_open, | ||
679 | .close = wf_mpu_synth_close, | ||
680 | .ioctl = wf_mpu_synth_ioctl, | ||
681 | .kill_note = midi_synth_kill_note, | ||
682 | .start_note = midi_synth_start_note, | ||
683 | .set_instr = midi_synth_set_instr, | ||
684 | .reset = midi_synth_reset, | ||
685 | .hw_control = midi_synth_hw_control, | ||
686 | .load_patch = midi_synth_load_patch, | ||
687 | .aftertouch = midi_synth_aftertouch, | ||
688 | .controller = midi_synth_controller, | ||
689 | .panning = midi_synth_panning, | ||
690 | .bender = midi_synth_bender, | ||
691 | .setup_voice = midi_synth_setup_voice, | ||
692 | .send_sysex = midi_synth_send_sysex | ||
693 | }; | ||
694 | |||
695 | static int | ||
696 | config_wf_mpu (struct wf_mpu_config *dev) | ||
697 | |||
698 | { | ||
699 | int is_external; | ||
700 | char *name; | ||
701 | int index; | ||
702 | |||
703 | if (dev == phys_dev) { | ||
704 | name = "WaveFront internal MIDI"; | ||
705 | is_external = 0; | ||
706 | index = 0; | ||
707 | memcpy ((char *) &wf_mpu_synth_operations[index], | ||
708 | (char *) &wf_mpu_synth_proto, | ||
709 | sizeof (struct synth_operations)); | ||
710 | } else { | ||
711 | name = "WaveFront external MIDI"; | ||
712 | is_external = 1; | ||
713 | index = 1; | ||
714 | /* no synth operations for an external MIDI interface */ | ||
715 | } | ||
716 | |||
717 | memcpy ((char *) &wf_mpu_synth_info[dev->devno], | ||
718 | (char *) &wf_mpu_synth_info_proto, | ||
719 | sizeof (struct synth_info)); | ||
720 | |||
721 | strcpy (wf_mpu_synth_info[index].name, name); | ||
722 | |||
723 | wf_mpu_synth_operations[index].midi_dev = dev->devno; | ||
724 | wf_mpu_synth_operations[index].info = &wf_mpu_synth_info[index]; | ||
725 | |||
726 | memcpy ((char *) &wf_mpu_midi_operations[index], | ||
727 | (char *) &wf_mpu_midi_proto, | ||
728 | sizeof (struct midi_operations)); | ||
729 | |||
730 | if (is_external) { | ||
731 | wf_mpu_midi_operations[index].converter = NULL; | ||
732 | } else { | ||
733 | wf_mpu_midi_operations[index].converter = | ||
734 | &wf_mpu_synth_operations[index]; | ||
735 | } | ||
736 | |||
737 | strcpy (wf_mpu_midi_operations[index].info.name, name); | ||
738 | |||
739 | midi_devs[dev->devno] = &wf_mpu_midi_operations[index]; | ||
740 | midi_devs[dev->devno]->in_info.m_busy = 0; | ||
741 | midi_devs[dev->devno]->in_info.m_state = MST_INIT; | ||
742 | midi_devs[dev->devno]->in_info.m_ptr = 0; | ||
743 | midi_devs[dev->devno]->in_info.m_left = 0; | ||
744 | midi_devs[dev->devno]->in_info.m_prev_status = 0; | ||
745 | |||
746 | devs[index].opened = 0; | ||
747 | devs[index].mode = 0; | ||
748 | |||
749 | return (0); | ||
750 | } | ||
751 | |||
752 | int virtual_midi_enable (void) | ||
753 | |||
754 | { | ||
755 | if ((virt_dev->devno < 0) && | ||
756 | (virt_dev->devno = sound_alloc_mididev()) == -1) { | ||
757 | printk (KERN_ERR | ||
758 | "WF-MPU: too many midi devices detected\n"); | ||
759 | return -1; | ||
760 | } | ||
761 | |||
762 | config_wf_mpu (virt_dev); | ||
763 | |||
764 | phys_dev->isvirtual = 1; | ||
765 | return virt_dev->devno; | ||
766 | } | ||
767 | |||
768 | int | ||
769 | virtual_midi_disable (void) | ||
770 | |||
771 | { | ||
772 | unsigned long flags; | ||
773 | |||
774 | spin_lock_irqsave(&lock,flags); | ||
775 | |||
776 | wf_mpu_close (virt_dev->devno); | ||
777 | /* no synth on virt_dev, so no need to call wf_mpu_synth_close() */ | ||
778 | phys_dev->isvirtual = 0; | ||
779 | |||
780 | spin_unlock_irqrestore(&lock,flags); | ||
781 | |||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | int __init detect_wf_mpu (int irq, int io_base) | ||
786 | { | ||
787 | if (!request_region(io_base, 2, "wavefront midi")) { | ||
788 | printk (KERN_WARNING "WF-MPU: I/O port %x already in use.\n", | ||
789 | io_base); | ||
790 | return -1; | ||
791 | } | ||
792 | |||
793 | phys_dev->base = io_base; | ||
794 | phys_dev->irq = irq; | ||
795 | phys_dev->devno = -1; | ||
796 | virt_dev->devno = -1; | ||
797 | |||
798 | return 0; | ||
799 | } | ||
800 | |||
801 | int __init install_wf_mpu (void) | ||
802 | { | ||
803 | if ((phys_dev->devno = sound_alloc_mididev()) < 0){ | ||
804 | |||
805 | printk (KERN_ERR "WF-MPU: Too many MIDI devices detected.\n"); | ||
806 | release_region(phys_dev->base, 2); | ||
807 | return -1; | ||
808 | } | ||
809 | |||
810 | phys_dev->isvirtual = 0; | ||
811 | |||
812 | if (config_wf_mpu (phys_dev)) { | ||
813 | |||
814 | printk (KERN_WARNING | ||
815 | "WF-MPU: configuration for MIDI device %d failed\n", | ||
816 | phys_dev->devno); | ||
817 | sound_unload_mididev (phys_dev->devno); | ||
818 | |||
819 | } | ||
820 | |||
821 | /* OK, now we're configured to handle an interrupt ... */ | ||
822 | |||
823 | if (request_irq (phys_dev->irq, wf_mpuintr, SA_INTERRUPT|SA_SHIRQ, | ||
824 | "wavefront midi", phys_dev) < 0) { | ||
825 | |||
826 | printk (KERN_ERR "WF-MPU: Failed to allocate IRQ%d\n", | ||
827 | phys_dev->irq); | ||
828 | return -1; | ||
829 | |||
830 | } | ||
831 | |||
832 | /* This being a WaveFront (ICS-2115) emulated MPU-401, we have | ||
833 | to switch it into UART (dumb) mode, because otherwise, it | ||
834 | won't do anything at all. | ||
835 | */ | ||
836 | |||
837 | start_uart_mode (); | ||
838 | |||
839 | return phys_dev->devno; | ||
840 | } | ||
841 | |||
842 | void | ||
843 | uninstall_wf_mpu (void) | ||
844 | |||
845 | { | ||
846 | release_region (phys_dev->base, 2); | ||
847 | free_irq (phys_dev->irq, phys_dev); | ||
848 | sound_unload_mididev (phys_dev->devno); | ||
849 | |||
850 | if (virt_dev->devno >= 0) { | ||
851 | sound_unload_mididev (virt_dev->devno); | ||
852 | } | ||
853 | } | ||
854 | |||
855 | static void | ||
856 | start_uart_mode (void) | ||
857 | |||
858 | { | ||
859 | int ok, i; | ||
860 | unsigned long flags; | ||
861 | |||
862 | spin_lock_irqsave(&lock,flags); | ||
863 | |||
864 | /* XXX fix me */ | ||
865 | |||
866 | for (i = 0; i < 30000 && !output_ready (); i++); | ||
867 | |||
868 | outb (UART_MODE_ON, COMDPORT(phys_dev)); | ||
869 | |||
870 | for (ok = 0, i = 50000; i > 0 && !ok; i--) { | ||
871 | if (input_avail ()) { | ||
872 | if (read_data () == MPU_ACK) { | ||
873 | ok = 1; | ||
874 | } | ||
875 | } | ||
876 | } | ||
877 | |||
878 | spin_unlock_irqrestore(&lock,flags); | ||
879 | } | ||
880 | #endif | ||