Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/sound/oss/wf_midi.c b/sound/oss/wf_midi.c
new file mode 100644
index 0000000..7b167b7
--- /dev/null
+++ b/sound/oss/wf_midi.c
@@ -0,0 +1,880 @@
+/*
+ * sound/wf_midi.c
+ *
+ * The low level driver for the WaveFront ICS2115 MIDI interface(s)
+ * Note that there is also an MPU-401 emulation (actually, a UART-401
+ * emulation) on the CS4232 on the Tropez Plus. This code has nothing
+ * to do with that interface at all.
+ *
+ * The interface is essentially just a UART-401, but is has the
+ * interesting property of supporting what Turtle Beach called
+ * "Virtual MIDI" mode. In this mode, there are effectively *two*
+ * MIDI buses accessible via the interface, one that is routed
+ * solely to/from the external WaveFront synthesizer and the other
+ * corresponding to the pin/socket connector used to link external
+ * MIDI devices to the board.
+ *
+ * This driver fully supports this mode, allowing two distinct
+ * midi devices (/dev/midiNN and /dev/midiNN+1) to be used
+ * completely independently, giving 32 channels of MIDI routing,
+ * 16 to the WaveFront synth and 16 to the external MIDI bus.
+ *
+ * Switching between the two is accomplished externally by the driver
+ * using the two otherwise unused MIDI bytes. See the code for more details.
+ *
+ * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see wavefront.c)
+ *
+ * The main reason to turn off Virtual MIDI mode is when you want to
+ * tightly couple the WaveFront synth with an external MIDI
+ * device. You won't be able to distinguish the source of any MIDI
+ * data except via SysEx ID, but thats probably OK, since for the most
+ * part, the WaveFront won't be sending any MIDI data at all.
+ *  
+ * The main reason to turn on Virtual MIDI Mode is to provide two
+ * completely independent 16-channel MIDI buses, one to the
+ * WaveFront and one to any external MIDI devices. Given the 32
+ * voice nature of the WaveFront, its pretty easy to find a use
+ * for all 16 channels driving just that synth.
+ *
+ */
+
+/*
+ * Copyright (C) by Paul Barton-Davis 1998
+ * Some portions of this file are derived from work that is:
+ *
+ *    CopyriGht (C) by Hannu Savolainen 1993-1996
+ *
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include "sound_config.h"
+
+#include <linux/wavefront.h>
+
+#ifdef MODULE
+
+struct wf_mpu_config {
+	int             base;
+#define	DATAPORT(d)   (d)->base
+#define	COMDPORT(d)   (d)->base+1
+#define	STATPORT(d)   (d)->base+1
+
+	int             irq;
+	int             opened;
+	int             devno;
+	int             synthno;
+	int             mode;
+#define MODE_MIDI	1
+#define MODE_SYNTH	2
+
+	void            (*inputintr) (int dev, unsigned char data);
+	char isvirtual;                /* do virtual I/O stuff */
+};
+
+static struct wf_mpu_config  devs[2];
+static struct wf_mpu_config *phys_dev = &devs[0];
+static struct wf_mpu_config *virt_dev = &devs[1];
+
+static void start_uart_mode (void);
+static DEFINE_SPINLOCK(lock);
+
+#define	OUTPUT_READY	0x40
+#define	INPUT_AVAIL	0x80
+#define	MPU_ACK		0xFE
+#define	UART_MODE_ON	0x3F
+
+static inline int wf_mpu_status (void)
+{
+	return inb (STATPORT (phys_dev));
+}
+
+static inline int input_avail (void)
+{
+	return !(wf_mpu_status() & INPUT_AVAIL);
+}
+
+static inline int output_ready (void)
+{
+	return !(wf_mpu_status() & OUTPUT_READY);
+}
+
+static inline int  read_data (void)
+{
+	return inb (DATAPORT (phys_dev));
+}
+
+static inline void write_data (unsigned char byte)
+{
+	outb (byte, DATAPORT (phys_dev));
+}
+
+/*
+ * States for the input scanner (should be in dev_table.h)
+ */
+
+#define MST_SYSMSG		100	/* System message (sysx etc). */
+#define MST_MTC			102	/* Midi Time Code (MTC) qframe msg */
+#define MST_SONGSEL		103	/* Song select */
+#define MST_SONGPOS		104	/* Song position pointer */
+#define MST_TIMED		105	/* Leading timing byte rcvd */
+
+/* buffer space check for input scanner */
+
+#define BUFTEST(mi) if (mi->m_ptr >= MI_MAX || mi->m_ptr < 0) \
+{printk(KERN_ERR "WF-MPU: Invalid buffer pointer %d/%d, s=%d\n", \
+	mi->m_ptr, mi->m_left, mi->m_state);mi->m_ptr--;}
+
+static unsigned char len_tab[] =	/* # of data bytes following a status
+					 */
+{
+	2,				/* 8x */
+	2,				/* 9x */
+	2,				/* Ax */
+	2,				/* Bx */
+	1,				/* Cx */
+	1,				/* Dx */
+	2,				/* Ex */
+	0				/* Fx */
+};
+
+static int
+wf_mpu_input_scanner (int devno, int synthdev, unsigned char midic)
+
+{
+	struct midi_input_info *mi = &midi_devs[devno]->in_info;
+
+	switch (mi->m_state) {
+	case MST_INIT:
+		switch (midic) {
+		case 0xf8:
+			/* Timer overflow */
+			break;
+		
+		case 0xfc:
+			break;
+		
+		case 0xfd:
+			/* XXX do something useful with this. If there is
+			   an external MIDI timer (e.g. a hardware sequencer,
+			   a useful timer can be derived ...
+		   
+			   For now, no timer support.
+			*/
+			break;
+		
+		case 0xfe:
+			return MPU_ACK;
+			break;
+		
+		case 0xf0:
+		case 0xf1:
+		case 0xf2:
+		case 0xf3:
+		case 0xf4:
+		case 0xf5:
+		case 0xf6:
+		case 0xf7:
+			break;
+		
+		case 0xf9:
+			break;
+		
+		case 0xff:
+			mi->m_state = MST_SYSMSG;
+			break;
+		
+		default:
+			if (midic <= 0xef) {
+				mi->m_state = MST_TIMED;
+			}
+			else
+				printk (KERN_ERR "<MPU: Unknown event %02x> ",
+					midic);
+		}
+		break;
+	  
+	case MST_TIMED:
+	{
+		int             msg = ((int) (midic & 0xf0) >> 4);
+	  
+		mi->m_state = MST_DATA;
+	  
+		if (msg < 8) {	/* Data byte */
+	      
+			msg = ((int) (mi->m_prev_status & 0xf0) >> 4);
+			msg -= 8;
+			mi->m_left = len_tab[msg] - 1;
+	      
+			mi->m_ptr = 2;
+			mi->m_buf[0] = mi->m_prev_status;
+			mi->m_buf[1] = midic;
+
+			if (mi->m_left <= 0) {
+				mi->m_state = MST_INIT;
+				do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
+				mi->m_ptr = 0;
+			}
+		} else if (msg == 0xf) {	/* MPU MARK */
+	      
+			mi->m_state = MST_INIT;
+
+			switch (midic) {
+			case 0xf8:
+				break;
+		    
+			case 0xf9:
+				break;
+		    
+			case 0xfc:
+				break;
+		    
+			default:
+				break;
+			}
+		} else {
+			mi->m_prev_status = midic;
+			msg -= 8;
+			mi->m_left = len_tab[msg];
+	      
+			mi->m_ptr = 1;
+			mi->m_buf[0] = midic;
+	      
+			if (mi->m_left <= 0) {
+				mi->m_state = MST_INIT;
+				do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
+				mi->m_ptr = 0;
+			}
+		}
+	}
+	break;
+
+	case MST_SYSMSG:
+		switch (midic) {
+		case 0xf0:
+			mi->m_state = MST_SYSEX;
+			break;
+	    
+		case 0xf1:
+			mi->m_state = MST_MTC;
+			break;
+
+		case 0xf2:
+			mi->m_state = MST_SONGPOS;
+			mi->m_ptr = 0;
+			break;
+	    
+		case 0xf3:
+			mi->m_state = MST_SONGSEL;
+			break;
+	    
+		case 0xf6:
+			mi->m_state = MST_INIT;
+	    
+			/*
+			 *    Real time messages
+			 */
+		case 0xf8:
+			/* midi clock */
+			mi->m_state = MST_INIT;
+			/* XXX need ext MIDI timer support */
+			break;
+	    
+		case 0xfA:
+			mi->m_state = MST_INIT;
+			/* XXX need ext MIDI timer support */
+			break;
+	    
+		case 0xFB:
+			mi->m_state = MST_INIT;
+			/* XXX need ext MIDI timer support */
+			break;
+	    
+		case 0xFC:
+			mi->m_state = MST_INIT;
+			/* XXX need ext MIDI timer support */
+			break;
+	    
+		case 0xFE:
+			/* active sensing */
+			mi->m_state = MST_INIT;
+			break;
+	    
+		case 0xff:
+			mi->m_state = MST_INIT;
+			break;
+
+		default:
+			printk (KERN_ERR "unknown MIDI sysmsg %0x\n", midic);
+			mi->m_state = MST_INIT;
+		}
+		break;
+
+	case MST_MTC:
+		mi->m_state = MST_INIT;
+		break;
+
+	case MST_SYSEX:
+		if (midic == 0xf7) {
+			mi->m_state = MST_INIT;
+		} else {
+			/* XXX fix me */
+		}
+		break;
+
+	case MST_SONGPOS:
+		BUFTEST (mi);
+		mi->m_buf[mi->m_ptr++] = midic;
+		if (mi->m_ptr == 2) {
+			mi->m_state = MST_INIT;
+			mi->m_ptr = 0;
+			/* XXX need ext MIDI timer support */
+		}
+		break;
+
+	case MST_DATA:
+		BUFTEST (mi);
+		mi->m_buf[mi->m_ptr++] = midic;
+		if ((--mi->m_left) <= 0) {
+			mi->m_state = MST_INIT;
+			do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
+			mi->m_ptr = 0;
+		}
+		break;
+
+	default:
+		printk (KERN_ERR "Bad state %d ", mi->m_state);
+		mi->m_state = MST_INIT;
+	}
+
+	return 1;
+}
+
+static irqreturn_t
+wf_mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
+
+{
+	struct wf_mpu_config *physical_dev = dev_id;
+	static struct wf_mpu_config *input_dev;
+	struct midi_input_info *mi = &midi_devs[physical_dev->devno]->in_info;
+	int n;
+
+	if (!input_avail()) { /* not for us */
+		return IRQ_NONE;
+	}
+
+	if (mi->m_busy)
+		return IRQ_HANDLED;
+	spin_lock(&lock);
+	mi->m_busy = 1;
+
+	if (!input_dev) {
+		input_dev = physical_dev;
+	}
+
+	n = 50; /* XXX why ? */
+
+	do {
+		unsigned char c = read_data ();
+      
+		if (phys_dev->isvirtual) {
+
+			if (c == WF_EXTERNAL_SWITCH) {
+				input_dev = virt_dev;
+				continue;
+			} else if (c == WF_INTERNAL_SWITCH) { 
+				input_dev = phys_dev;
+				continue;
+			} /* else just leave it as it is */
+
+		} else {
+			input_dev = phys_dev;
+		}
+
+		if (input_dev->mode == MODE_SYNTH) {
+	  
+			wf_mpu_input_scanner (input_dev->devno,
+					      input_dev->synthno, c);
+	  
+		} else if (input_dev->opened & OPEN_READ) {
+	  
+			if (input_dev->inputintr) {
+				input_dev->inputintr (input_dev->devno, c);
+			} 
+		}
+
+	} while (input_avail() && n-- > 0);
+
+	mi->m_busy = 0;
+	spin_unlock(&lock);
+	return IRQ_HANDLED;
+}
+
+static int
+wf_mpu_open (int dev, int mode,
+	     void            (*input) (int dev, unsigned char data),
+	     void            (*output) (int dev)
+	)
+{
+	struct wf_mpu_config *devc;
+
+	if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
+		return -(ENXIO);
+
+	if (phys_dev->devno == dev) {
+		devc = phys_dev;
+	} else if (phys_dev->isvirtual && virt_dev->devno == dev) {
+		devc = virt_dev;
+	} else {
+		printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
+		return -(EINVAL);
+	}
+
+	if (devc->opened) {
+		return -(EBUSY);
+	}
+
+	devc->mode = MODE_MIDI;
+	devc->opened = mode;
+	devc->synthno = 0;
+
+	devc->inputintr = input;
+	return 0;
+}
+ 
+static void
+wf_mpu_close (int dev)
+{
+	struct wf_mpu_config *devc;
+
+	if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
+		return;
+
+	if (phys_dev->devno == dev) {
+		devc = phys_dev;
+	} else if (phys_dev->isvirtual && virt_dev->devno == dev) {
+		devc = virt_dev;
+	} else {
+		printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
+		return;
+	}
+
+	devc->mode = 0;
+	devc->inputintr = NULL;
+	devc->opened = 0;
+}
+
+static int
+wf_mpu_out (int dev, unsigned char midi_byte)
+{
+	int             timeout;
+	unsigned long   flags;
+	static int lastoutdev = -1;
+	unsigned char switchch;
+
+	if (phys_dev->isvirtual && lastoutdev != dev) {
+      
+		if (dev == phys_dev->devno) { 
+			switchch = WF_INTERNAL_SWITCH;
+		} else if (dev == virt_dev->devno) { 
+			switchch = WF_EXTERNAL_SWITCH;
+		} else {
+			printk (KERN_ERR "WF-MPU: bad device number %d", dev);
+			return (0);
+		}
+
+		/* XXX fix me */
+      
+		for (timeout = 30000; timeout > 0 && !output_ready ();
+		     timeout--);
+      
+		spin_lock_irqsave(&lock,flags);
+      
+		if (!output_ready ()) {
+			printk (KERN_WARNING "WF-MPU: Send switch "
+				"byte timeout\n");
+			spin_unlock_irqrestore(&lock,flags);
+			return 0;
+		}
+      
+		write_data (switchch);
+		spin_unlock_irqrestore(&lock,flags);
+	} 
+
+	lastoutdev = dev;
+
+	/*
+	 * Sometimes it takes about 30000 loops before the output becomes ready
+	 * (After reset). Normally it takes just about 10 loops.
+	 */
+
+	/* XXX fix me */
+
+	for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);
+
+	spin_lock_irqsave(&lock,flags);
+	if (!output_ready ()) {
+		spin_unlock_irqrestore(&lock,flags);
+		printk (KERN_WARNING "WF-MPU: Send data timeout\n");
+		return 0;
+	}
+
+	write_data (midi_byte);
+	spin_unlock_irqrestore(&lock,flags);
+
+	return 1;
+}
+
+static inline int wf_mpu_start_read (int dev) {
+	return 0;
+}
+
+static inline int wf_mpu_end_read (int dev) {
+	return 0;
+}
+
+static int wf_mpu_ioctl (int dev, unsigned cmd, void __user *arg)
+{
+	printk (KERN_WARNING
+		"WF-MPU: Intelligent mode not supported by hardware.\n");
+	return -(EINVAL);
+}
+
+static int wf_mpu_buffer_status (int dev)
+{
+	return 0;
+}
+
+static struct synth_operations wf_mpu_synth_operations[2];
+static struct midi_operations  wf_mpu_midi_operations[2];
+
+static struct midi_operations wf_mpu_midi_proto =
+{
+	.owner		= THIS_MODULE,
+	.info		= {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
+	.in_info	= {0},   /* in_info */
+	.open		= wf_mpu_open,
+	.close		= wf_mpu_close,
+	.ioctl		= wf_mpu_ioctl,
+	.outputc	= wf_mpu_out,
+	.start_read	= wf_mpu_start_read,
+	.end_read	= wf_mpu_end_read,
+	.buffer_status	= wf_mpu_buffer_status,
+};
+
+static struct synth_info wf_mpu_synth_info_proto =
+{"WaveFront MPU-401 interface", 0,
+ SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT};
+
+static struct synth_info wf_mpu_synth_info[2];
+
+static int
+wf_mpu_synth_ioctl (int dev, unsigned int cmd, void __user *arg)
+{
+	int             midi_dev;
+	int index;
+
+	midi_dev = synth_devs[dev]->midi_dev;
+
+	if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL)
+		return -(ENXIO);
+
+	if (midi_dev == phys_dev->devno) {
+		index = 0;
+	} else if (phys_dev->isvirtual && midi_dev == virt_dev->devno) {
+		index = 1;
+	} else {
+		return -(EINVAL);
+	}
+
+	switch (cmd) {
+
+	case SNDCTL_SYNTH_INFO:
+		if (copy_to_user(arg,
+			      &wf_mpu_synth_info[index],
+			      sizeof (struct synth_info)))
+			return -EFAULT;
+		return 0;
+	
+	case SNDCTL_SYNTH_MEMAVL:
+		return 0x7fffffff;
+	
+	default:
+		return -EINVAL;
+	}
+}
+
+static int
+wf_mpu_synth_open (int dev, int mode)
+{
+	int             midi_dev;
+	struct wf_mpu_config *devc;
+
+	midi_dev = synth_devs[dev]->midi_dev;
+
+	if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL) {
+		return -(ENXIO);
+	}
+  
+	if (phys_dev->devno == midi_dev) {
+		devc = phys_dev;
+	} else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
+		devc = virt_dev;
+	} else {
+		printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
+		return -(EINVAL);
+	}
+
+	if (devc->opened) {
+		return -(EBUSY);
+	}
+  
+	devc->mode = MODE_SYNTH;
+	devc->synthno = dev;
+	devc->opened = mode;
+	devc->inputintr = NULL;
+	return 0;
+}
+
+static void
+wf_mpu_synth_close (int dev)
+{
+	int             midi_dev;
+	struct wf_mpu_config *devc;
+
+	midi_dev = synth_devs[dev]->midi_dev;
+
+	if (phys_dev->devno == midi_dev) {
+		devc = phys_dev;
+	} else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
+		devc = virt_dev;
+	} else {
+		printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
+		return;
+	}
+
+	devc->inputintr = NULL;
+	devc->opened = 0;
+	devc->mode = 0;
+}
+
+#define _MIDI_SYNTH_C_
+#define MIDI_SYNTH_NAME	"WaveFront (MIDI)"
+#define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
+#include "midi_synth.h"
+
+static struct synth_operations wf_mpu_synth_proto =
+{
+	.owner		= THIS_MODULE,
+	.id		= "WaveFront (ICS2115)",
+	.info		= NULL,  /* info field, filled in during configuration */
+	.midi_dev	= 0,     /* MIDI dev XXX should this be -1 ? */
+	.synth_type	= SYNTH_TYPE_MIDI,
+	.synth_subtype	= SAMPLE_TYPE_WAVEFRONT,
+	.open		= wf_mpu_synth_open,
+	.close		= wf_mpu_synth_close,
+	.ioctl		= wf_mpu_synth_ioctl,
+	.kill_note	= midi_synth_kill_note,
+	.start_note	= midi_synth_start_note,
+	.set_instr	= midi_synth_set_instr,
+	.reset		= midi_synth_reset,
+	.hw_control	= midi_synth_hw_control,
+	.load_patch	= midi_synth_load_patch,
+	.aftertouch	= midi_synth_aftertouch,
+	.controller	= midi_synth_controller,
+	.panning	= midi_synth_panning,
+	.bender		= midi_synth_bender,
+	.setup_voice	= midi_synth_setup_voice,
+	.send_sysex	= midi_synth_send_sysex
+};
+
+static int
+config_wf_mpu (struct wf_mpu_config *dev)
+
+{
+	int is_external;
+	char *name;
+	int index;
+
+	if (dev == phys_dev) {
+		name = "WaveFront internal MIDI";
+		is_external = 0;
+		index = 0;
+		memcpy ((char *) &wf_mpu_synth_operations[index],
+			(char *) &wf_mpu_synth_proto,
+			sizeof (struct synth_operations));
+	} else {
+		name = "WaveFront external MIDI";
+		is_external = 1;
+		index = 1;
+		/* no synth operations for an external MIDI interface */
+	}
+
+	memcpy ((char *) &wf_mpu_synth_info[dev->devno],
+		(char *) &wf_mpu_synth_info_proto,
+		sizeof (struct synth_info));
+
+	strcpy (wf_mpu_synth_info[index].name, name);
+
+	wf_mpu_synth_operations[index].midi_dev = dev->devno;
+	wf_mpu_synth_operations[index].info = &wf_mpu_synth_info[index];
+
+	memcpy ((char *) &wf_mpu_midi_operations[index],
+		(char *) &wf_mpu_midi_proto,
+		sizeof (struct midi_operations));
+  
+	if (is_external) {
+		wf_mpu_midi_operations[index].converter = NULL;
+	} else {
+		wf_mpu_midi_operations[index].converter =
+			&wf_mpu_synth_operations[index];
+	}
+
+	strcpy (wf_mpu_midi_operations[index].info.name, name);
+
+	midi_devs[dev->devno] = &wf_mpu_midi_operations[index];
+	midi_devs[dev->devno]->in_info.m_busy = 0;
+	midi_devs[dev->devno]->in_info.m_state = MST_INIT;
+	midi_devs[dev->devno]->in_info.m_ptr = 0;
+	midi_devs[dev->devno]->in_info.m_left = 0;
+	midi_devs[dev->devno]->in_info.m_prev_status = 0;
+
+	devs[index].opened = 0;
+	devs[index].mode = 0;
+
+	return (0);
+}
+
+int virtual_midi_enable (void)
+
+{
+	if ((virt_dev->devno < 0) &&
+	    (virt_dev->devno = sound_alloc_mididev()) == -1) {
+		printk (KERN_ERR
+			"WF-MPU: too many midi devices detected\n");
+		return -1;
+	}
+
+	config_wf_mpu (virt_dev);
+
+	phys_dev->isvirtual = 1;
+	return virt_dev->devno;
+}
+
+int
+virtual_midi_disable (void)
+
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&lock,flags);
+
+	wf_mpu_close (virt_dev->devno);
+	/* no synth on virt_dev, so no need to call wf_mpu_synth_close() */
+	phys_dev->isvirtual = 0;
+
+	spin_unlock_irqrestore(&lock,flags);
+
+	return 0;
+}
+
+int __init detect_wf_mpu (int irq, int io_base)
+{
+	if (!request_region(io_base, 2, "wavefront midi")) {
+		printk (KERN_WARNING "WF-MPU: I/O port %x already in use.\n",
+			io_base);
+		return -1;
+	}
+
+	phys_dev->base = io_base;
+	phys_dev->irq = irq;
+	phys_dev->devno = -1;
+	virt_dev->devno = -1;
+
+	return 0;
+}
+
+int __init install_wf_mpu (void)
+{
+	if ((phys_dev->devno = sound_alloc_mididev()) < 0){
+
+		printk (KERN_ERR "WF-MPU: Too many MIDI devices detected.\n");
+		release_region(phys_dev->base, 2);
+		return -1;
+	}
+
+	phys_dev->isvirtual = 0;
+
+	if (config_wf_mpu (phys_dev)) {
+
+		printk (KERN_WARNING
+			"WF-MPU: configuration for MIDI device %d failed\n",
+			phys_dev->devno);
+		sound_unload_mididev (phys_dev->devno);
+
+	}
+
+	/* OK, now we're configured to handle an interrupt ... */
+
+	if (request_irq (phys_dev->irq, wf_mpuintr, SA_INTERRUPT|SA_SHIRQ,
+			 "wavefront midi", phys_dev) < 0) {
+
+		printk (KERN_ERR "WF-MPU: Failed to allocate IRQ%d\n",
+			phys_dev->irq);
+		return -1;
+
+	}
+
+	/* This being a WaveFront (ICS-2115) emulated MPU-401, we have
+	   to switch it into UART (dumb) mode, because otherwise, it
+	   won't do anything at all.
+	*/
+  
+	start_uart_mode ();
+
+	return phys_dev->devno;
+}
+ 
+void
+uninstall_wf_mpu (void)
+
+{
+	release_region (phys_dev->base, 2); 
+	free_irq (phys_dev->irq, phys_dev);
+	sound_unload_mididev (phys_dev->devno);
+
+	if (virt_dev->devno >= 0) {
+		sound_unload_mididev (virt_dev->devno);
+	}
+}
+
+static void
+start_uart_mode (void)
+
+{
+	int             ok, i;
+	unsigned long   flags;
+
+	spin_lock_irqsave(&lock,flags);
+
+	/* XXX fix me */
+
+	for (i = 0; i < 30000 && !output_ready (); i++);
+
+	outb (UART_MODE_ON, COMDPORT(phys_dev));
+
+	for (ok = 0, i = 50000; i > 0 && !ok; i--) {
+		if (input_avail ()) {
+			if (read_data () == MPU_ACK) {
+				ok = 1;
+			}
+		}
+	}
+
+	spin_unlock_irqrestore(&lock,flags);
+}
+#endif