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 
wf_mpu_status(void)88 static inline int wf_mpu_status (void)
89 {
90 	return inb (STATPORT (phys_dev));
91 }
92 
input_avail(void)93 static inline int input_avail (void)
94 {
95 	return !(wf_mpu_status() & INPUT_AVAIL);
96 }
97 
output_ready(void)98 static inline int output_ready (void)
99 {
100 	return !(wf_mpu_status() & OUTPUT_READY);
101 }
102 
read_data(void)103 static inline int  read_data (void)
104 {
105 	return inb (DATAPORT (phys_dev));
106 }
107 
write_data(unsigned char byte)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
wf_mpu_input_scanner(int devno,int synthdev,unsigned char midic)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 				break;
235 			}
236 		} else {
237 			mi->m_prev_status = midic;
238 			msg -= 8;
239 			mi->m_left = len_tab[msg];
240 
241 			mi->m_ptr = 1;
242 			mi->m_buf[0] = midic;
243 
244 			if (mi->m_left <= 0) {
245 				mi->m_state = MST_INIT;
246 				do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
247 				mi->m_ptr = 0;
248 			}
249 		}
250 	}
251 	break;
252 
253 	case MST_SYSMSG:
254 		switch (midic) {
255 		case 0xf0:
256 			mi->m_state = MST_SYSEX;
257 			break;
258 
259 		case 0xf1:
260 			mi->m_state = MST_MTC;
261 			break;
262 
263 		case 0xf2:
264 			mi->m_state = MST_SONGPOS;
265 			mi->m_ptr = 0;
266 			break;
267 
268 		case 0xf3:
269 			mi->m_state = MST_SONGSEL;
270 			break;
271 
272 		case 0xf6:
273 			mi->m_state = MST_INIT;
274 
275 			/*
276 			 *    Real time messages
277 			 */
278 		case 0xf8:
279 			/* midi clock */
280 			mi->m_state = MST_INIT;
281 			/* XXX need ext MIDI timer support */
282 			break;
283 
284 		case 0xfA:
285 			mi->m_state = MST_INIT;
286 			/* XXX need ext MIDI timer support */
287 			break;
288 
289 		case 0xFB:
290 			mi->m_state = MST_INIT;
291 			/* XXX need ext MIDI timer support */
292 			break;
293 
294 		case 0xFC:
295 			mi->m_state = MST_INIT;
296 			/* XXX need ext MIDI timer support */
297 			break;
298 
299 		case 0xFE:
300 			/* active sensing */
301 			mi->m_state = MST_INIT;
302 			break;
303 
304 		case 0xff:
305 			mi->m_state = MST_INIT;
306 			break;
307 
308 		default:
309 			printk (KERN_ERR "unknown MIDI sysmsg %0x\n", midic);
310 			mi->m_state = MST_INIT;
311 		}
312 		break;
313 
314 	case MST_MTC:
315 		mi->m_state = MST_INIT;
316 		break;
317 
318 	case MST_SYSEX:
319 		if (midic == 0xf7) {
320 			mi->m_state = MST_INIT;
321 		} else {
322 			/* XXX fix me */
323 		}
324 		break;
325 
326 	case MST_SONGPOS:
327 		BUFTEST (mi);
328 		mi->m_buf[mi->m_ptr++] = midic;
329 		if (mi->m_ptr == 2) {
330 			mi->m_state = MST_INIT;
331 			mi->m_ptr = 0;
332 			/* XXX need ext MIDI timer support */
333 		}
334 		break;
335 
336 	case MST_DATA:
337 		BUFTEST (mi);
338 		mi->m_buf[mi->m_ptr++] = midic;
339 		if ((--mi->m_left) <= 0) {
340 			mi->m_state = MST_INIT;
341 			do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
342 			mi->m_ptr = 0;
343 		}
344 		break;
345 
346 	default:
347 		printk (KERN_ERR "Bad state %d ", mi->m_state);
348 		mi->m_state = MST_INIT;
349 	}
350 
351 	return 1;
352 }
353 
354 void
wf_mpuintr(int irq,void * dev_id,struct pt_regs * dummy)355 wf_mpuintr (int irq, void *dev_id, struct pt_regs *dummy)
356 
357 {
358 	struct wf_mpu_config *physical_dev = dev_id;
359 	static struct wf_mpu_config *input_dev = 0;
360 	struct midi_input_info *mi = &midi_devs[physical_dev->devno]->in_info;
361 	int n;
362 
363 	if (!input_avail()) { /* not for us */
364 		return;
365 	}
366 
367 	if (mi->m_busy) return;
368 	mi->m_busy = 1;
369 	sti ();
370 
371 	if (!input_dev) {
372 		input_dev = physical_dev;
373 	}
374 
375 	n = 50; /* XXX why ? */
376 
377 	do {
378 		unsigned char c = read_data ();
379 
380 		if (phys_dev->isvirtual) {
381 
382 			if (c == WF_EXTERNAL_SWITCH) {
383 				input_dev = virt_dev;
384 				continue;
385 			} else if (c == WF_INTERNAL_SWITCH) {
386 				input_dev = phys_dev;
387 				continue;
388 			} /* else just leave it as it is */
389 
390 		} else {
391 			input_dev = phys_dev;
392 		}
393 
394 		if (input_dev->mode == MODE_SYNTH) {
395 
396 			wf_mpu_input_scanner (input_dev->devno,
397 					      input_dev->synthno, c);
398 
399 		} else if (input_dev->opened & OPEN_READ) {
400 
401 			if (input_dev->inputintr) {
402 				input_dev->inputintr (input_dev->devno, c);
403 			}
404 		}
405 
406 	} while (input_avail() && n-- > 0);
407 
408 	mi->m_busy = 0;
409 }
410 
411 static int
wf_mpu_open(int dev,int mode,void (* input)(int dev,unsigned char data),void (* output)(int dev))412 wf_mpu_open (int dev, int mode,
413 	     void            (*input) (int dev, unsigned char data),
414 	     void            (*output) (int dev)
415 	)
416 {
417 	struct wf_mpu_config *devc;
418 
419 	if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
420 		return -(ENXIO);
421 
422 	if (phys_dev->devno == dev) {
423 		devc = phys_dev;
424 	} else if (phys_dev->isvirtual && virt_dev->devno == dev) {
425 		devc = virt_dev;
426 	} else {
427 		printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
428 		return -(EINVAL);
429 	}
430 
431 	if (devc->opened) {
432 		return -(EBUSY);
433 	}
434 
435 	devc->mode = MODE_MIDI;
436 	devc->opened = mode;
437 	devc->synthno = 0;
438 
439 	devc->inputintr = input;
440 	return 0;
441 }
442 
443 static void
wf_mpu_close(int dev)444 wf_mpu_close (int dev)
445 {
446 	struct wf_mpu_config *devc;
447 
448 	if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
449 		return;
450 
451 	if (phys_dev->devno == dev) {
452 		devc = phys_dev;
453 	} else if (phys_dev->isvirtual && virt_dev->devno == dev) {
454 		devc = virt_dev;
455 	} else {
456 		printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
457 		return;
458 	}
459 
460 	devc->mode = 0;
461 	devc->inputintr = NULL;
462 	devc->opened = 0;
463 }
464 
465 static int
wf_mpu_out(int dev,unsigned char midi_byte)466 wf_mpu_out (int dev, unsigned char midi_byte)
467 {
468 	int             timeout;
469 	unsigned long   flags;
470 	static int lastoutdev = -1;
471 	unsigned char switchch;
472 
473 	if (phys_dev->isvirtual && lastoutdev != dev) {
474 
475 		if (dev == phys_dev->devno) {
476 			switchch = WF_INTERNAL_SWITCH;
477 		} else if (dev == virt_dev->devno) {
478 			switchch = WF_EXTERNAL_SWITCH;
479 		} else {
480 			printk (KERN_ERR "WF-MPU: bad device number %d", dev);
481 			return (0);
482 		}
483 
484 		/* XXX fix me */
485 
486 		for (timeout = 30000; timeout > 0 && !output_ready ();
487 		     timeout--);
488 
489 		save_flags (flags);
490 		cli ();
491 
492 		if (!output_ready ()) {
493 			printk (KERN_WARNING "WF-MPU: Send switch "
494 				"byte timeout\n");
495 			restore_flags (flags);
496 			return 0;
497 		}
498 
499 		write_data (switchch);
500 		restore_flags (flags);
501 	}
502 
503 	lastoutdev = dev;
504 
505 	/*
506 	 * Sometimes it takes about 30000 loops before the output becomes ready
507 	 * (After reset). Normally it takes just about 10 loops.
508 	 */
509 
510 	/* XXX fix me */
511 
512 	for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);
513 
514 	save_flags (flags);
515 	cli ();
516 	if (!output_ready ()) {
517 		printk (KERN_WARNING "WF-MPU: Send data timeout\n");
518 		restore_flags (flags);
519 		return 0;
520 	}
521 
522 	write_data (midi_byte);
523 	restore_flags (flags);
524 
525 	return 1;
526 }
527 
wf_mpu_start_read(int dev)528 static inline int wf_mpu_start_read (int dev) {
529 	return 0;
530 }
531 
wf_mpu_end_read(int dev)532 static inline int wf_mpu_end_read (int dev) {
533 	return 0;
534 }
535 
wf_mpu_ioctl(int dev,unsigned cmd,caddr_t arg)536 static int wf_mpu_ioctl (int dev, unsigned cmd, caddr_t arg)
537 {
538 	printk (KERN_WARNING
539 		"WF-MPU: Intelligent mode not supported by hardware.\n");
540 	return -(EINVAL);
541 }
542 
wf_mpu_buffer_status(int dev)543 static int wf_mpu_buffer_status (int dev)
544 {
545 	return 0;
546 }
547 
548 static struct synth_operations wf_mpu_synth_operations[2];
549 static struct midi_operations  wf_mpu_midi_operations[2];
550 
551 static struct midi_operations wf_mpu_midi_proto =
552 {
553 	owner:		THIS_MODULE,
554 	info:		{"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
555 	in_info:	{0},   /* in_info */
556 	open:		wf_mpu_open,
557 	close:		wf_mpu_close,
558 	ioctl:		wf_mpu_ioctl,
559 	outputc:	wf_mpu_out,
560 	start_read:	wf_mpu_start_read,
561 	end_read:	wf_mpu_end_read,
562 	buffer_status:	wf_mpu_buffer_status,
563 };
564 
565 static struct synth_info wf_mpu_synth_info_proto =
566 {"WaveFront MPU-401 interface", 0,
567  SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT};
568 
569 static struct synth_info wf_mpu_synth_info[2];
570 
571 static int
wf_mpu_synth_ioctl(int dev,unsigned int cmd,caddr_t arg)572 wf_mpu_synth_ioctl (int dev,
573 		    unsigned int cmd, caddr_t arg)
574 {
575 	int             midi_dev;
576 	int index;
577 
578 	midi_dev = synth_devs[dev]->midi_dev;
579 
580 	if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL)
581 		return -(ENXIO);
582 
583 	if (midi_dev == phys_dev->devno) {
584 		index = 0;
585 	} else if (phys_dev->isvirtual && midi_dev == virt_dev->devno) {
586 		index = 1;
587 	} else {
588 		return -(EINVAL);
589 	}
590 
591 	switch (cmd) {
592 
593 	case SNDCTL_SYNTH_INFO:
594 		if(copy_to_user (&((char *) arg)[0],
595 			      &wf_mpu_synth_info[index],
596 			      sizeof (struct synth_info)))
597 			return -EFAULT;
598 		return 0;
599 
600 	case SNDCTL_SYNTH_MEMAVL:
601 		return 0x7fffffff;
602 
603 	default:
604 		return -EINVAL;
605 	}
606 }
607 
608 static int
wf_mpu_synth_open(int dev,int mode)609 wf_mpu_synth_open (int dev, int mode)
610 {
611 	int             midi_dev;
612 	struct wf_mpu_config *devc;
613 
614 	midi_dev = synth_devs[dev]->midi_dev;
615 
616 	if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL) {
617 		return -(ENXIO);
618 	}
619 
620 	if (phys_dev->devno == midi_dev) {
621 		devc = phys_dev;
622 	} else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
623 		devc = virt_dev;
624 	} else {
625 		printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
626 		return -(EINVAL);
627 	}
628 
629 	if (devc->opened) {
630 		return -(EBUSY);
631 	}
632 
633 	devc->mode = MODE_SYNTH;
634 	devc->synthno = dev;
635 	devc->opened = mode;
636 	devc->inputintr = NULL;
637 	return 0;
638 }
639 
640 static void
wf_mpu_synth_close(int dev)641 wf_mpu_synth_close (int dev)
642 {
643 	int             midi_dev;
644 	struct wf_mpu_config *devc;
645 
646 	midi_dev = synth_devs[dev]->midi_dev;
647 
648 	if (phys_dev->devno == midi_dev) {
649 		devc = phys_dev;
650 	} else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
651 		devc = virt_dev;
652 	} else {
653 		printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
654 		return;
655 	}
656 
657 	devc->inputintr = NULL;
658 	devc->opened = 0;
659 	devc->mode = 0;
660 }
661 
662 #define _MIDI_SYNTH_C_
663 #define MIDI_SYNTH_NAME	"WaveFront (MIDI)"
664 #define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
665 #include "midi_synth.h"
666 
667 static struct synth_operations wf_mpu_synth_proto =
668 {
669 	owner:		THIS_MODULE,
670 	id:		"WaveFront (ICS2115)",
671 	info:		NULL,  /* info field, filled in during configuration */
672 	midi_dev:	0,     /* MIDI dev XXX should this be -1 ? */
673 	synth_type:	SYNTH_TYPE_MIDI,
674 	synth_subtype:	SAMPLE_TYPE_WAVEFRONT,
675 	open:		wf_mpu_synth_open,
676 	close:		wf_mpu_synth_close,
677 	ioctl:		wf_mpu_synth_ioctl,
678 	kill_note:	midi_synth_kill_note,
679 	start_note:	midi_synth_start_note,
680 	set_instr:	midi_synth_set_instr,
681 	reset:		midi_synth_reset,
682 	hw_control:	midi_synth_hw_control,
683 	load_patch:	midi_synth_load_patch,
684 	aftertouch:	midi_synth_aftertouch,
685 	controller:	midi_synth_controller,
686 	panning:	midi_synth_panning,
687 	bender:		midi_synth_bender,
688 	setup_voice:	midi_synth_setup_voice,
689 	send_sysex:	midi_synth_send_sysex
690 };
691 
692 static int
config_wf_mpu(struct wf_mpu_config * dev)693 config_wf_mpu (struct wf_mpu_config *dev)
694 
695 {
696 	int is_external;
697 	char *name;
698 	int index;
699 
700 	if (dev == phys_dev) {
701 		name = "WaveFront internal MIDI";
702 		is_external = 0;
703 		index = 0;
704 		memcpy ((char *) &wf_mpu_synth_operations[index],
705 			(char *) &wf_mpu_synth_proto,
706 			sizeof (struct synth_operations));
707 	} else {
708 		name = "WaveFront external MIDI";
709 		is_external = 1;
710 		index = 1;
711 		/* no synth operations for an external MIDI interface */
712 	}
713 
714 	memcpy ((char *) &wf_mpu_synth_info[dev->devno],
715 		(char *) &wf_mpu_synth_info_proto,
716 		sizeof (struct synth_info));
717 
718 	strcpy (wf_mpu_synth_info[index].name, name);
719 
720 	wf_mpu_synth_operations[index].midi_dev = dev->devno;
721 	wf_mpu_synth_operations[index].info = &wf_mpu_synth_info[index];
722 
723 	memcpy ((char *) &wf_mpu_midi_operations[index],
724 		(char *) &wf_mpu_midi_proto,
725 		sizeof (struct midi_operations));
726 
727 	if (is_external) {
728 		wf_mpu_midi_operations[index].converter = NULL;
729 	} else {
730 		wf_mpu_midi_operations[index].converter =
731 			&wf_mpu_synth_operations[index];
732 	}
733 
734 	strcpy (wf_mpu_midi_operations[index].info.name, name);
735 
736 	midi_devs[dev->devno] = &wf_mpu_midi_operations[index];
737 	midi_devs[dev->devno]->in_info.m_busy = 0;
738 	midi_devs[dev->devno]->in_info.m_state = MST_INIT;
739 	midi_devs[dev->devno]->in_info.m_ptr = 0;
740 	midi_devs[dev->devno]->in_info.m_left = 0;
741 	midi_devs[dev->devno]->in_info.m_prev_status = 0;
742 
743 	devs[index].opened = 0;
744 	devs[index].mode = 0;
745 
746 	return (0);
747 }
748 
virtual_midi_enable(void)749 int virtual_midi_enable (void)
750 
751 {
752 	if ((virt_dev->devno < 0) &&
753 	    (virt_dev->devno = sound_alloc_mididev()) == -1) {
754 		printk (KERN_ERR
755 			"WF-MPU: too many midi devices detected\n");
756 		return -1;
757 	}
758 
759 	config_wf_mpu (virt_dev);
760 
761 	phys_dev->isvirtual = 1;
762 	return virt_dev->devno;
763 }
764 
765 int
virtual_midi_disable(void)766 virtual_midi_disable (void)
767 
768 {
769 	unsigned long flags;
770 
771 	save_flags (flags);
772 	cli();
773 
774 	wf_mpu_close (virt_dev->devno);
775 	/* no synth on virt_dev, so no need to call wf_mpu_synth_close() */
776 	phys_dev->isvirtual = 0;
777 
778 	restore_flags (flags);
779 
780 	return 0;
781 }
782 
detect_wf_mpu(int irq,int io_base)783 int __init detect_wf_mpu (int irq, int io_base)
784 {
785 	if (check_region (io_base, 2)) {
786 		printk (KERN_WARNING "WF-MPU: I/O port %x already in use.\n",
787 			io_base);
788 		return -1;
789 	}
790 
791 	phys_dev->base = io_base;
792 	phys_dev->irq = irq;
793 	phys_dev->devno = -1;
794 	virt_dev->devno = -1;
795 
796 	return 0;
797 }
798 
install_wf_mpu(void)799 int __init install_wf_mpu (void)
800 {
801 	if ((phys_dev->devno = sound_alloc_mididev()) < 0){
802 
803 		printk (KERN_ERR "WF-MPU: Too many MIDI devices detected.\n");
804 		return -1;
805 
806 	}
807 
808 	request_region (phys_dev->base, 2, "wavefront midi");
809 	phys_dev->isvirtual = 0;
810 
811 	if (config_wf_mpu (phys_dev)) {
812 
813 		printk (KERN_WARNING
814 			"WF-MPU: configuration for MIDI device %d failed\n",
815 			phys_dev->devno);
816 		sound_unload_mididev (phys_dev->devno);
817 
818 	}
819 
820 	/* OK, now we're configured to handle an interrupt ... */
821 
822 	if (request_irq (phys_dev->irq, wf_mpuintr, SA_INTERRUPT|SA_SHIRQ,
823 			 "wavefront midi", phys_dev) < 0) {
824 
825 		printk (KERN_ERR "WF-MPU: Failed to allocate IRQ%d\n",
826 			phys_dev->irq);
827 		return -1;
828 
829 	}
830 
831 	/* This being a WaveFront (ICS-2115) emulated MPU-401, we have
832 	   to switch it into UART (dumb) mode, because otherwise, it
833 	   won't do anything at all.
834 	*/
835 
836 	start_uart_mode ();
837 
838 	return phys_dev->devno;
839 }
840 
841 void
uninstall_wf_mpu(void)842 uninstall_wf_mpu (void)
843 
844 {
845 	release_region (phys_dev->base, 2);
846 	free_irq (phys_dev->irq, phys_dev);
847 	sound_unload_mididev (phys_dev->devno);
848 
849 	if (virt_dev->devno >= 0) {
850 		sound_unload_mididev (virt_dev->devno);
851 	}
852 }
853 
854 static void
start_uart_mode(void)855 start_uart_mode (void)
856 
857 {
858 	int             ok, i;
859 	unsigned long   flags;
860 
861 	save_flags (flags);
862 	cli ();
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 	restore_flags (flags);
879 }
880 #endif
881