Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 |