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 "sound_config.h"
54
55 #include <linux/wavefront.h>
56
57 #ifdef MODULE
58
59 struct wf_mpu_config {
60 int base;
61 #define DATAPORT(d) (d)->base
62 #define COMDPORT(d) (d)->base+1
63 #define STATPORT(d) (d)->base+1
64
65 int irq;
66 int opened;
67 int devno;
68 int synthno;
69 int mode;
70 #define MODE_MIDI 1
71 #define MODE_SYNTH 2
72
73 void (*inputintr) (int dev, unsigned char data);
74 char isvirtual; /* do virtual I/O stuff */
75 };
76
77 static struct wf_mpu_config devs[2];
78 static struct wf_mpu_config *phys_dev = &devs[0];
79 static struct wf_mpu_config *virt_dev = &devs[1];
80
81 static void start_uart_mode (void);
82
83 #define OUTPUT_READY 0x40
84 #define INPUT_AVAIL 0x80
85 #define MPU_ACK 0xFE
86 #define UART_MODE_ON 0x3F
87
88 static inline int wf_mpu_status (void)
89 {
90 return inb (STATPORT (phys_dev));
91 }
92
93 static inline int input_avail (void)
94 {
95 return !(wf_mpu_status() & INPUT_AVAIL);
96 }
97
98 static inline int output_ready (void)
99 {
100 return !(wf_mpu_status() & OUTPUT_READY);
101 }
102
103 static inline int read_data (void)
104 {
105 return inb (DATAPORT (phys_dev));
106 }
107
108 static inline void write_data (unsigned char byte)
109 {
110 outb (byte, DATAPORT (phys_dev));
111 }
112
113 /*
114 * States for the input scanner (should be in dev_table.h)
115 */
116
117 #define MST_SYSMSG 100 /* System message (sysx etc). */
118 #define MST_MTC 102 /* Midi Time Code (MTC) qframe msg */
119 #define MST_SONGSEL 103 /* Song select */
120 #define MST_SONGPOS 104 /* Song position pointer */
121 #define MST_TIMED 105 /* Leading timing byte rcvd */
122
123 /* buffer space check for input scanner */
124
125 #define BUFTEST(mi) if (mi->m_ptr >= MI_MAX || mi->m_ptr < 0) \
126 {printk(KERN_ERR "WF-MPU: Invalid buffer pointer %d/%d, s=%d\n", \
127 mi->m_ptr, mi->m_left, mi->m_state);mi->m_ptr--;}
128
129 static unsigned char len_tab[] = /* # of data bytes following a status
130 */
131 {
132 2, /* 8x */
133 2, /* 9x */
134 2, /* Ax */
135 2, /* Bx */
136 1, /* Cx */
137 1, /* Dx */
138 2, /* Ex */
139 0 /* Fx */
140 };
141
142 static int
143 wf_mpu_input_scanner (int devno, int synthdev, unsigned char midic)
144
145 {
146 struct midi_input_info *mi = &midi_devs[devno]->in_info;
147
148 switch (mi->m_state) {
149 case MST_INIT:
150 switch (midic) {
151 case 0xf8:
152 /* Timer overflow */
153 break;
154
155 case 0xfc:
156 break;
157
158 case 0xfd:
159 /* XXX do something useful with this. If there is
160 an external MIDI timer (e.g. a hardware sequencer,
161 a useful timer can be derived ...
162
163 For now, no timer support.
164 */
165 break;
166
167 case 0xfe:
168 return MPU_ACK;
169 break;
170
171 case 0xf0:
172 case 0xf1:
173 case 0xf2:
174 case 0xf3:
175 case 0xf4:
176 case 0xf5:
177 case 0xf6:
178 case 0xf7:
179 break;
180
181 case 0xf9:
182 break;
183
184 case 0xff:
185 mi->m_state = MST_SYSMSG;
186 break;
187
188 default:
189 if (midic <= 0xef) {
190 mi->m_state = MST_TIMED;
191 }
192 else
193 printk (KERN_ERR "<MPU: Unknown event %02x> ",
194 midic);
195 }
196 break;
197
198 case MST_TIMED:
199 {
200 int msg = ((int) (midic & 0xf0) >> 4);
201
202 mi->m_state = MST_DATA;
203
204 if (msg < 8) { /* Data byte */
205
206 msg = ((int) (mi->m_prev_status & 0xf0) >> 4);
207 msg -= 8;
208 mi->m_left = len_tab[msg] - 1;
209
210 mi->m_ptr = 2;
211 mi->m_buf[0] = mi->m_prev_status;
212 mi->m_buf[1] = midic;
213
214 if (mi->m_left <= 0) {
215 mi->m_state = MST_INIT;
216 do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
217 mi->m_ptr = 0;
218 }
219 } else if (msg == 0xf) { /* MPU MARK */
220
221 mi->m_state = MST_INIT;
222
223 switch (midic) {
224 case 0xf8:
225 break;
226
227 case 0xf9:
228 break;
229
230 case 0xfc:
231 break;
232
233 default:
234 }
235 } else {
236 mi->m_prev_status = midic;
237 msg -= 8;
238 mi->m_left = len_tab[msg];
239
240 mi->m_ptr = 1;
241 mi->m_buf[0] = midic;
242
243 if (mi->m_left <= 0) {
244 mi->m_state = MST_INIT;
245 do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
246 mi->m_ptr = 0;
247 }
248 }
249 }
250 break;
251
252 case MST_SYSMSG:
253 switch (midic) {
254 case 0xf0:
255 mi->m_state = MST_SYSEX;
256 break;
257
258 case 0xf1:
259 mi->m_state = MST_MTC;
260 break;
261
262 case 0xf2:
263 mi->m_state = MST_SONGPOS;
264 mi->m_ptr = 0;
265 break;
266
267 case 0xf3:
268 mi->m_state = MST_SONGSEL;
269 break;
270
271 case 0xf6:
272 mi->m_state = MST_INIT;
273
274 /*
275 * Real time messages
276 */
277 case 0xf8:
278 /* midi clock */
279 mi->m_state = MST_INIT;
280 /* XXX need ext MIDI timer support */
281 break;
282
283 case 0xfA:
284 mi->m_state = MST_INIT;
285 /* XXX need ext MIDI timer support */
286 break;
287
288 case 0xFB:
289 mi->m_state = MST_INIT;
290 /* XXX need ext MIDI timer support */
291 break;
292
293 case 0xFC:
294 mi->m_state = MST_INIT;
295 /* XXX need ext MIDI timer support */
296 break;
297
298 case 0xFE:
299 /* active sensing */
300 mi->m_state = MST_INIT;
301 break;
302
303 case 0xff:
304 mi->m_state = MST_INIT;
305 break;
306
307 default:
308 printk (KERN_ERR "unknown MIDI sysmsg %0x\n", midic);
309 mi->m_state = MST_INIT;
310 }
311 break;
312
313 case MST_MTC:
314 mi->m_state = MST_INIT;
315 break;
316
317 case MST_SYSEX:
318 if (midic == 0xf7) {
319 mi->m_state = MST_INIT;
320 } else {
321 /* XXX fix me */
322 }
323 break;
324
325 case MST_SONGPOS:
326 BUFTEST (mi);
327 mi->m_buf[mi->m_ptr++] = midic;
328 if (mi->m_ptr == 2) {
329 mi->m_state = MST_INIT;
330 mi->m_ptr = 0;
331 /* XXX need ext MIDI timer support */
332 }
333 break;
334
335 case MST_DATA:
336 BUFTEST (mi);
337 mi->m_buf[mi->m_ptr++] = midic;
338 if ((--mi->m_left) <= 0) {
339 mi->m_state = MST_INIT;
340 do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
341 mi->m_ptr = 0;
342 }
343 break;
344
345 default:
346 printk (KERN_ERR "Bad state %d ", mi->m_state);
347 mi->m_state = MST_INIT;
348 }
349
350 return 1;
351 }
352
353 void
354 wf_mpuintr (int irq, void *dev_id, struct pt_regs *dummy)
355
356 {
357 struct wf_mpu_config *physical_dev = dev_id;
358 static struct wf_mpu_config *input_dev = 0;
359 struct midi_input_info *mi = &midi_devs[physical_dev->devno]->in_info;
360 int n;
361
362 if (!input_avail()) { /* not for us */
363 return;
364 }
365
366 if (mi->m_busy) return;
367 mi->m_busy = 1;
368 sti ();
369
370 if (!input_dev) {
371 input_dev = physical_dev;
372 }
373
374 n = 50; /* XXX why ? */
375
376 do {
377 unsigned char c = read_data ();
378
379 if (phys_dev->isvirtual) {
380
381 if (c == WF_EXTERNAL_SWITCH) {
382 input_dev = virt_dev;
383 continue;
384 } else if (c == WF_INTERNAL_SWITCH) {
385 input_dev = phys_dev;
386 continue;
387 } /* else just leave it as it is */
388
389 } else {
390 input_dev = phys_dev;
391 }
392
393 if (input_dev->mode == MODE_SYNTH) {
394
395 wf_mpu_input_scanner (input_dev->devno,
396 input_dev->synthno, c);
397
398 } else if (input_dev->opened & OPEN_READ) {
399
400 if (input_dev->inputintr) {
401 input_dev->inputintr (input_dev->devno, c);
402 }
403 }
404
405 } while (input_avail() && n-- > 0);
406
407 mi->m_busy = 0;
408 }
409
410 static int
411 wf_mpu_open (int dev, int mode,
412 void (*input) (int dev, unsigned char data),
413 void (*output) (int dev)
414 )
415 {
416 struct wf_mpu_config *devc;
417
418 if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
419 return -(ENXIO);
420
421 if (phys_dev->devno == dev) {
422 devc = phys_dev;
423 } else if (phys_dev->isvirtual && virt_dev->devno == dev) {
424 devc = virt_dev;
425 } else {
426 printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
427 return -(EINVAL);
428 }
429
430 if (devc->opened) {
431 return -(EBUSY);
432 }
433
434 devc->mode = MODE_MIDI;
435 devc->opened = mode;
436 devc->synthno = 0;
437
438 devc->inputintr = input;
439 return 0;
440 }
441
442 static void
443 wf_mpu_close (int dev)
444 {
445 struct wf_mpu_config *devc;
446
447 if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
448 return;
449
450 if (phys_dev->devno == dev) {
451 devc = phys_dev;
452 } else if (phys_dev->isvirtual && virt_dev->devno == dev) {
453 devc = virt_dev;
454 } else {
455 printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
456 return;
457 }
458
459 devc->mode = 0;
460 devc->inputintr = NULL;
461 devc->opened = 0;
462 }
463
464 static int
465 wf_mpu_out (int dev, unsigned char midi_byte)
466 {
467 int timeout;
468 unsigned long flags;
469 static int lastoutdev = -1;
470 unsigned char switchch;
471
472 if (phys_dev->isvirtual && lastoutdev != dev) {
473
474 if (dev == phys_dev->devno) {
475 switchch = WF_INTERNAL_SWITCH;
476 } else if (dev == virt_dev->devno) {
477 switchch = WF_EXTERNAL_SWITCH;
478 } else {
479 printk (KERN_ERR "WF-MPU: bad device number %d", dev);
480 return (0);
481 }
482
483 /* XXX fix me */
484
485 for (timeout = 30000; timeout > 0 && !output_ready ();
486 timeout--);
487
488 save_flags (flags);
489 cli ();
490
491 if (!output_ready ()) {
492 printk (KERN_WARNING "WF-MPU: Send switch "
493 "byte timeout\n");
494 restore_flags (flags);
495 return 0;
496 }
497
498 write_data (switchch);
499 restore_flags (flags);
500 }
501
502 lastoutdev = dev;
503
504 /*
505 * Sometimes it takes about 30000 loops before the output becomes ready
506 * (After reset). Normally it takes just about 10 loops.
507 */
508
509 /* XXX fix me */
510
511 for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);
512
513 save_flags (flags);
514 cli ();
515 if (!output_ready ()) {
516 printk (KERN_WARNING "WF-MPU: Send data timeout\n");
517 restore_flags (flags);
518 return 0;
519 }
520
521 write_data (midi_byte);
522 restore_flags (flags);
523
524 return 1;
525 }
526
527 static inline int wf_mpu_start_read (int dev) {
528 return 0;
529 }
530
531 static inline int wf_mpu_end_read (int dev) {
532 return 0;
533 }
534
535 static int wf_mpu_ioctl (int dev, unsigned cmd, caddr_t arg)
536 {
537 printk (KERN_WARNING
538 "WF-MPU: Intelligent mode not supported by hardware.\n");
539 return -(EINVAL);
540 }
541
542 static int wf_mpu_buffer_status (int dev)
543 {
544 return 0;
545 }
546
547 static struct synth_operations wf_mpu_synth_operations[2];
548 static struct midi_operations wf_mpu_midi_operations[2];
549
550 static struct midi_operations wf_mpu_midi_proto =
551 {
552 owner: THIS_MODULE,
553 info: {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
554 in_info: {0}, /* in_info */
555 open: wf_mpu_open,
556 close: wf_mpu_close,
557 ioctl: wf_mpu_ioctl,
558 outputc: wf_mpu_out,
559 start_read: wf_mpu_start_read,
560 end_read: wf_mpu_end_read,
561 buffer_status: wf_mpu_buffer_status,
562 };
563
564 static struct synth_info wf_mpu_synth_info_proto =
565 {"WaveFront MPU-401 interface", 0,
566 SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT};
567
568 static struct synth_info wf_mpu_synth_info[2];
569
570 static int
571 wf_mpu_synth_ioctl (int dev,
572 unsigned int cmd, caddr_t arg)
573 {
574 int midi_dev;
575 int index;
576
577 midi_dev = synth_devs[dev]->midi_dev;
578
579 if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL)
580 return -(ENXIO);
581
582 if (midi_dev == phys_dev->devno) {
583 index = 0;
584 } else if (phys_dev->isvirtual && midi_dev == virt_dev->devno) {
585 index = 1;
586 } else {
587 return -(EINVAL);
588 }
589
590 switch (cmd) {
591
592 case SNDCTL_SYNTH_INFO:
593 copy_to_user (&((char *) arg)[0],
594 &wf_mpu_synth_info[index],
595 sizeof (struct synth_info));
596
597 return 0;
598 break;
599
600 case SNDCTL_SYNTH_MEMAVL:
601 return 0x7fffffff;
602 break;
603
604 default:
605 return -(EINVAL);
606 }
607 }
608
609 static int
610 wf_mpu_synth_open (int dev, int mode)
611 {
612 int midi_dev;
613 struct wf_mpu_config *devc;
614
615 midi_dev = synth_devs[dev]->midi_dev;
616
617 if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL) {
618 return -(ENXIO);
619 }
620
621 if (phys_dev->devno == midi_dev) {
622 devc = phys_dev;
623 } else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
624 devc = virt_dev;
625 } else {
626 printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
627 return -(EINVAL);
628 }
629
630 if (devc->opened) {
631 return -(EBUSY);
632 }
633
634 devc->mode = MODE_SYNTH;
635 devc->synthno = dev;
636 devc->opened = mode;
637 devc->inputintr = NULL;
638 return 0;
639 }
640
641 static void
642 wf_mpu_synth_close (int dev)
643 {
644 int midi_dev;
645 struct wf_mpu_config *devc;
646
647 midi_dev = synth_devs[dev]->midi_dev;
648
649 if (phys_dev->devno == midi_dev) {
650 devc = phys_dev;
651 } else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
652 devc = virt_dev;
653 } else {
654 printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
655 return;
656 }
657
658 devc->inputintr = NULL;
659 devc->opened = 0;
660 devc->mode = 0;
661 }
662
663 #define _MIDI_SYNTH_C_
664 #define MIDI_SYNTH_NAME "WaveFront (MIDI)"
665 #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
666 #include "midi_synth.h"
667
668 static struct synth_operations wf_mpu_synth_proto =
669 {
670 owner: THIS_MODULE,
671 id: "WaveFront (ICS2115)",
672 info: NULL, /* info field, filled in during configuration */
673 midi_dev: 0, /* MIDI dev XXX should this be -1 ? */
674 synth_type: SYNTH_TYPE_MIDI,
675 synth_subtype: SAMPLE_TYPE_WAVEFRONT,
676 open: wf_mpu_synth_open,
677 close: wf_mpu_synth_close,
678 ioctl: wf_mpu_synth_ioctl,
679 kill_note: midi_synth_kill_note,
680 start_note: midi_synth_start_note,
681 set_instr: midi_synth_set_instr,
682 reset: midi_synth_reset,
683 hw_control: midi_synth_hw_control,
684 load_patch: midi_synth_load_patch,
685 aftertouch: midi_synth_aftertouch,
686 controller: midi_synth_controller,
687 panning: midi_synth_panning,
688 bender: midi_synth_bender,
689 setup_voice: midi_synth_setup_voice,
690 send_sysex: midi_synth_send_sysex
691 };
692
693 static int
694 config_wf_mpu (struct wf_mpu_config *dev)
695
696 {
697 int is_external;
698 char *name;
699 int index;
700
701 if (dev == phys_dev) {
702 name = "WaveFront internal MIDI";
703 is_external = 0;
704 index = 0;
705 memcpy ((char *) &wf_mpu_synth_operations[index],
706 (char *) &wf_mpu_synth_proto,
707 sizeof (struct synth_operations));
708 } else {
709 name = "WaveFront external MIDI";
710 is_external = 1;
711 index = 1;
712 /* no synth operations for an external MIDI interface */
713 }
714
715 memcpy ((char *) &wf_mpu_synth_info[dev->devno],
716 (char *) &wf_mpu_synth_info_proto,
717 sizeof (struct synth_info));
718
719 strcpy (wf_mpu_synth_info[index].name, name);
720
721 wf_mpu_synth_operations[index].midi_dev = dev->devno;
722 wf_mpu_synth_operations[index].info = &wf_mpu_synth_info[index];
723
724 memcpy ((char *) &wf_mpu_midi_operations[index],
725 (char *) &wf_mpu_midi_proto,
726 sizeof (struct midi_operations));
727
728 if (is_external) {
729 wf_mpu_midi_operations[index].converter = NULL;
730 } else {
731 wf_mpu_midi_operations[index].converter =
732 &wf_mpu_synth_operations[index];
733 }
734
735 strcpy (wf_mpu_midi_operations[index].info.name, name);
736
737 midi_devs[dev->devno] = &wf_mpu_midi_operations[index];
738 midi_devs[dev->devno]->in_info.m_busy = 0;
739 midi_devs[dev->devno]->in_info.m_state = MST_INIT;
740 midi_devs[dev->devno]->in_info.m_ptr = 0;
741 midi_devs[dev->devno]->in_info.m_left = 0;
742 midi_devs[dev->devno]->in_info.m_prev_status = 0;
743
744 devs[index].opened = 0;
745 devs[index].mode = 0;
746
747 return (0);
748 }
749
750 int virtual_midi_enable (void)
751
752 {
753 if ((virt_dev->devno < 0) &&
754 (virt_dev->devno = sound_alloc_mididev()) == -1) {
755 printk (KERN_ERR
756 "WF-MPU: too many midi devices detected\n");
757 return -1;
758 }
759
760 config_wf_mpu (virt_dev);
761
762 phys_dev->isvirtual = 1;
763 return virt_dev->devno;
764 }
765
766 int
767 virtual_midi_disable (void)
768
769 {
770 unsigned long flags;
771
772 save_flags (flags);
773 cli();
774
775 wf_mpu_close (virt_dev->devno);
776 /* no synth on virt_dev, so no need to call wf_mpu_synth_close() */
777 phys_dev->isvirtual = 0;
778
779 restore_flags (flags);
780
781 return 0;
782 }
783
784 int __init detect_wf_mpu (int irq, int io_base)
785 {
786 if (check_region (io_base, 2)) {
787 printk (KERN_WARNING "WF-MPU: I/O port %x already in use.\n",
788 io_base);
789 return -1;
790 }
791
792 phys_dev->base = io_base;
793 phys_dev->irq = irq;
794 phys_dev->devno = -1;
795 virt_dev->devno = -1;
796
797 return 0;
798 }
799
800 int __init install_wf_mpu (void)
801 {
802 if ((phys_dev->devno = sound_alloc_mididev()) < 0){
803
804 printk (KERN_ERR "WF-MPU: Too many MIDI devices detected.\n");
805 return -1;
806
807 }
808
809 request_region (phys_dev->base, 2, "wavefront midi");
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 save_flags (flags);
863 cli ();
864
865 /* XXX fix me */
866
867 for (i = 0; i < 30000 && !output_ready (); i++);
868
869 outb (UART_MODE_ON, COMDPORT(phys_dev));
870
871 for (ok = 0, i = 50000; i > 0 && !ok; i--) {
872 if (input_avail ()) {
873 if (read_data () == MPU_ACK) {
874 ok = 1;
875 }
876 }
877 }
878
879 restore_flags (flags);
880 }
881 #endif
882
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.