patch-2.1.110 linux/drivers/sound/wf_midi.c
Next file: linux/drivers/sound/yss225.c
Previous file: linux/drivers/sound/wavfront.c
Back to the patch index
Back to the overall index
- Lines: 985
- Date:
Sat Jul 18 14:11:41 1998
- Orig file:
v2.1.109/linux/drivers/sound/wf_midi.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.1.109/linux/drivers/sound/wf_midi.c linux/drivers/sound/wf_midi.c
@@ -0,0 +1,984 @@
+/*
+ * 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
+ * Substantial 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/config.h>
+#include "sound_config.h"
+#include "soundmodule.h"
+
+#include <linux/wavefront.h>
+
+#if (defined(CONFIG_WAVEFRONT) && defined(CONFIG_MIDI)) || defined(MODULE)
+
+struct wf_mpu_config {
+ int base; /* I/O base */
+ int irq;
+ int opened; /* Open mode */
+ int devno;
+ int synthno;
+ int mode;
+#define MODE_MIDI 1
+#define MODE_SYNTH 2
+
+ void (*inputintr) (int dev, unsigned char data);
+
+ /* Virtual MIDI support */
+
+ char configured_for_virtual; /* setup for virtual completed */
+ char isvirtual; /* do virtual I/O stuff */
+ char isexternal; /* i am an external interface */
+ int internal; /* external interface midi_devno */
+ int external; /* external interface midi_devno */
+};
+
+#define DATAPORT(base) (base)
+#define COMDPORT(base) (base+1)
+#define STATPORT(base) (base+1)
+
+static void start_uart_mode (struct wf_mpu_config *devc);
+
+static int
+wf_mpu_status (struct wf_mpu_config *devc)
+{
+ return inb (STATPORT (devc->base));
+}
+
+static void
+wf_mpu_cmd (struct wf_mpu_config *devc, unsigned char cmd)
+{
+ outb ((cmd), COMDPORT(devc->base));
+}
+
+#define input_avail(devc) (!(wf_mpu_status(devc)&INPUT_AVAIL))
+#define output_ready(devc) (!(wf_mpu_status(devc)&OUTPUT_READY))
+
+static int
+read_data (struct wf_mpu_config *devc)
+{
+ return inb (DATAPORT (devc->base));
+}
+
+static void
+write_data (struct wf_mpu_config *devc, unsigned char byte)
+{
+ outb (byte, DATAPORT (devc->base));
+}
+
+#define OUTPUT_READY 0x40
+#define INPUT_AVAIL 0x80
+#define MPU_ACK 0xFE
+#define MPU_RESET 0xFF
+#define UART_MODE_ON 0x3F
+
+static struct wf_mpu_config dev_conf[MAX_MIDI_DEV] =
+{
+ {0}
+};
+
+static volatile int irq2dev[17] =
+{-1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1};
+
+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[MAX_MIDI_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 (struct wf_mpu_config *devc, unsigned char midic)
+{
+ struct midi_input_info *mi;
+
+ mi = &midi_devs[devc->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 (devc->synthno, 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:
+ }
+ } 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 (devc->synthno, 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 (devc->synthno, 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;
+}
+
+void
+wf_mpuintr (int irq, void *dev_id, struct pt_regs *dummy)
+{
+ struct wf_mpu_config *devc;
+ int dev;
+ static struct wf_mpu_config *isrc = 0;
+ int n;
+ struct midi_input_info *mi;
+ static int cnt = 0;
+
+ if (irq < 0 || irq > 15) {
+ printk (KERN_ERR "WF-MPU: bogus interrupt #%d", irq);
+ return;
+ }
+ dev = irq2dev[irq];
+ mi = &midi_devs[dev]->in_info;
+ if (mi->m_busy) return;
+ mi->m_busy = 1;
+ sti ();
+
+ n = 50;
+
+ /* guarantee that we're working with the "real" (internal)
+ interface before doing anything physical.
+ */
+
+ devc = &dev_conf[dev];
+ devc = &dev_conf[devc->internal];
+
+ if (isrc == 0) {
+
+ /* This is just an initial setting. If Virtual MIDI mode is
+ enabled on the ICS2115, we'll get a switch char before
+ anything else, and if it isn't, then the guess will be
+ correct for our purposes.
+ */
+
+ isrc = &dev_conf[devc->internal];
+ }
+
+ while (input_avail (devc) && n-- > 0) {
+ unsigned char c = read_data (devc);
+
+ if (devc->isvirtual) {
+ if (c == WF_EXTERNAL_SWITCH) {
+ isrc = &dev_conf[devc->external];
+ continue;
+ } else if (c == WF_INTERNAL_SWITCH) {
+ isrc = &dev_conf[devc->internal];
+ continue;
+ } /* else just leave it as it is */
+ } else {
+ isrc = &dev_conf[devc->internal];
+ }
+
+ if (isrc->mode == MODE_SYNTH) {
+
+ wf_mpu_input_scanner (isrc, c);
+
+ } else if (isrc->opened & OPEN_READ) {
+
+ if (isrc->inputintr) {
+ isrc->inputintr (isrc->devno, c);
+ }
+ }
+ }
+
+ mi->m_busy = 0;
+}
+
+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;
+
+ devc = &dev_conf[dev];
+
+ 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;
+
+ devc = &dev_conf[dev];
+ 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;
+
+ struct wf_mpu_config *devc;
+ unsigned char switchch;
+
+ /* The actual output has to occur using the "internal" config info
+ */
+
+ devc = &dev_conf[dev_conf[dev].internal];
+
+ if (devc->isvirtual && lastoutdev != dev) {
+
+ if (dev == devc->internal) {
+ switchch = WF_INTERNAL_SWITCH;
+ } else if (dev == devc->external) {
+ switchch = WF_EXTERNAL_SWITCH;
+ } else {
+ printk (KERN_ERR "WF-MPU: bad device number %d", dev);
+ return (0);
+ }
+
+ for (timeout = 30000; timeout > 0 && !output_ready (devc);
+ timeout--);
+
+ save_flags (flags);
+ cli ();
+
+ if (!output_ready (devc)) {
+ printk (KERN_WARNING "WF-MPU: Send switch "
+ "byte timeout\n");
+ restore_flags (flags);
+ return 0;
+ }
+
+ write_data (devc, switchch);
+ restore_flags (flags);
+ }
+
+ lastoutdev = dev;
+
+ /*
+ * Sometimes it takes about 30000 loops before the output becomes ready
+ * (After reset). Normally it takes just about 10 loops.
+ */
+
+ for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--);
+
+ save_flags (flags);
+ cli ();
+ if (!output_ready (devc)) {
+ printk (KERN_WARNING "WF-MPU: Send data timeout\n");
+ restore_flags (flags);
+ return 0;
+ }
+
+ write_data (devc, midi_byte);
+ restore_flags (flags);
+
+ return 1;
+}
+
+static int
+wf_mpu_start_read (int dev)
+{
+ return 0;
+}
+
+static int
+wf_mpu_end_read (int dev)
+{
+ return 0;
+}
+
+static int
+wf_mpu_ioctl (int dev, unsigned cmd, caddr_t arg)
+{
+ printk (KERN_WARNING
+ "WF-MPU: Intelligent mode not supported by hardware.\n");
+ return -(EINVAL);
+}
+
+static void
+wf_mpu_kick (int dev)
+{
+}
+
+static int
+wf_mpu_buffer_status (int dev)
+{
+ return 0; /*
+ * No data in buffers
+ */
+}
+
+static int
+wf_mpu_synth_ioctl (int dev,
+ unsigned int cmd, caddr_t arg)
+{
+ int midi_dev;
+
+ midi_dev = synth_devs[dev]->midi_dev;
+
+ if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL)
+ return -(ENXIO);
+
+ switch (cmd) {
+
+ case SNDCTL_SYNTH_INFO:
+ copy_to_user (&((char *) arg)[0],
+ &wf_mpu_synth_info[midi_dev],
+ sizeof (struct synth_info));
+
+ return 0;
+ break;
+
+ case SNDCTL_SYNTH_MEMAVL:
+ return 0x7fffffff;
+ break;
+
+ 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);
+ }
+
+ devc = &dev_conf[midi_dev];
+ 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;
+
+ devc = &dev_conf[midi_dev];
+ devc->inputintr = NULL;
+ devc->opened = 0;
+ devc->mode = 0;
+}
+
+#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 =
+{
+ "WaveFront (ICS2115)",
+ NULL, /* info field, filled in during configuration */
+ 0, /* MIDI dev XXX should this be -1 ? */
+ SYNTH_TYPE_MIDI,
+ SAMPLE_TYPE_WAVEFRONT,
+ wf_mpu_synth_open,
+ wf_mpu_synth_close,
+ wf_mpu_synth_ioctl,
+ midi_synth_kill_note,
+ midi_synth_start_note,
+ midi_synth_set_instr,
+ midi_synth_reset,
+ midi_synth_hw_control,
+ midi_synth_load_patch,
+ midi_synth_aftertouch,
+ midi_synth_controller,
+ midi_synth_panning,
+ NULL,
+ midi_synth_bender,
+ NULL, /* alloc */
+ midi_synth_setup_voice,
+ midi_synth_send_sysex
+};
+
+static struct synth_operations wf_mpu_synth_operations[WAVEFRONT_MAX_DEVICES*2];
+static struct midi_operations wf_mpu_midi_operations[WAVEFRONT_MAX_DEVICES*2];
+static int wfmpu_cnt = 0;
+
+static struct midi_operations wf_mpu_midi_proto =
+{
+ {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
+ NULL, /*converter*/
+ {0}, /* in_info */
+ wf_mpu_open,
+ wf_mpu_close,
+ wf_mpu_ioctl,
+ wf_mpu_out,
+ wf_mpu_start_read,
+ wf_mpu_end_read,
+ wf_mpu_kick,
+ NULL,
+ wf_mpu_buffer_status,
+ NULL
+};
+
+
+static int
+config_wf_mpu (int dev, struct address_info *hw_config)
+
+{
+ struct wf_mpu_config *devc;
+ int internal;
+
+ if (wfmpu_cnt >= WAVEFRONT_MAX_DEVICES * 2) {
+ printk (KERN_ERR "WF-MPU: eh ? more MPU devices "
+ "than cards ?!!\n");
+ return (-1);
+ }
+
+ /* There is no synth available on the external interface,
+ so do the synth stuff to the internal interface only.
+ */
+
+ internal = dev_conf[dev].internal;
+ devc = &dev_conf[internal];
+
+ if (!dev_conf[dev].isexternal) {
+ memcpy ((char *) &wf_mpu_synth_operations[wfmpu_cnt],
+ (char *) &wf_mpu_synth_proto,
+ sizeof (struct synth_operations));
+ }
+
+ memcpy ((char *) &wf_mpu_midi_operations[wfmpu_cnt],
+ (char *) &wf_mpu_midi_proto,
+ sizeof (struct midi_operations));
+
+ if (dev_conf[dev].isexternal) {
+ wf_mpu_midi_operations[wfmpu_cnt].converter = NULL;
+ } else {
+ wf_mpu_midi_operations[wfmpu_cnt].converter =
+ &wf_mpu_synth_operations[wfmpu_cnt];
+ }
+
+ memcpy ((char *) &wf_mpu_synth_info[dev],
+ (char *) &wf_mpu_synth_info_proto,
+ sizeof (struct synth_info));
+
+ strcpy (wf_mpu_synth_info[dev].name, hw_config->name);
+ strcpy (wf_mpu_midi_operations[wfmpu_cnt].info.name, hw_config->name);
+
+ conf_printf (hw_config->name, hw_config);
+
+ if (!dev_conf[dev].isexternal) {
+ wf_mpu_synth_operations[wfmpu_cnt].midi_dev = dev;
+ }
+ wf_mpu_synth_operations[wfmpu_cnt].info = &wf_mpu_synth_info[dev];
+
+ midi_devs[dev] = &wf_mpu_midi_operations[wfmpu_cnt];
+
+ dev_conf[dev].opened = 0;
+ dev_conf[dev].mode = 0;
+ dev_conf[dev].configured_for_virtual = 0;
+ dev_conf[dev].devno = dev;
+
+ midi_devs[dev]->in_info.m_busy = 0;
+ midi_devs[dev]->in_info.m_state = MST_INIT;
+ midi_devs[dev]->in_info.m_ptr = 0;
+ midi_devs[dev]->in_info.m_left = 0;
+ midi_devs[dev]->in_info.m_prev_status = 0;
+
+ wfmpu_cnt++;
+
+ return (0);
+}
+
+int
+virtual_midi_enable (int dev, struct address_info *hw_config)
+
+{
+ int idev;
+ int edev;
+ struct wf_mpu_config *devc;
+
+ devc = &dev_conf[dev];
+
+ if (devc->configured_for_virtual) {
+
+ idev = devc->internal;
+ edev = devc->external;
+
+ } else {
+
+ if (hw_config == NULL) {
+ printk (KERN_ERR
+ "WF-MPU: virtual midi first "
+ "enabled without hw_config!\n");
+ return -EINVAL;
+ }
+
+ idev = devc->internal;
+
+ if ((edev = sound_alloc_mididev()) == -1) {
+ printk (KERN_ERR
+ "WF-MPU: too many midi devices detected\n");
+ return -1;
+ }
+
+ hw_config->slots[WF_EXTERNAL_MIDI_SLOT] = edev;
+ }
+
+ dev_conf[edev].isvirtual = 1;
+ dev_conf[idev].isvirtual = 1;
+
+ if (dev_conf[idev].configured_for_virtual) {
+ return 0;
+ }
+
+ /* Configure external interface struct */
+
+ devc = &dev_conf[edev];
+ devc->internal = idev;
+ devc->external = edev;
+ devc->isexternal = 1;
+
+ /* Configure external interface struct
+ (devc->isexternal and devc->internal set in attach_wf_mpu())
+ */
+
+ devc = &dev_conf[idev];
+ devc->external = edev;
+
+ /* Configure the tables for the external */
+
+ if (config_wf_mpu (edev, hw_config)) {
+ printk (KERN_WARNING "WF-MPU: configuration for MIDI "
+ "device %d failed\n", edev);
+ return (-1);
+ }
+
+ /* Don't bother to do this again if we are toggled back and
+ forth between virtual MIDI mode and "normal" operation.
+ */
+
+ dev_conf[edev].configured_for_virtual = 1;
+ dev_conf[idev].configured_for_virtual = 1;
+
+ return 0;
+}
+
+void
+virtual_midi_disable (int dev)
+
+{
+ struct wf_mpu_config *devc;
+ unsigned long flags;
+
+ save_flags (flags);
+ cli();
+
+ /* Assumes for logical purposes that the caller has taken
+ care of fiddling with WaveFront hardware commands to
+ turn off Virtual MIDI mode.
+ */
+
+ devc = &dev_conf[dev];
+
+ devc = &dev_conf[devc->internal];
+ devc->isvirtual = 0;
+
+ devc = &dev_conf[devc->external];
+ devc->isvirtual = 0;
+
+ restore_flags (flags);
+}
+
+void
+attach_wf_mpu (struct address_info *hw_config)
+{
+ int m;
+ struct wf_mpu_config *devc;
+
+ if (request_irq (hw_config->irq, wf_mpuintr,
+ 0, "WaveFront MIDI", NULL) < 0) {
+ printk (KERN_ERR "WF-MPU: Failed to allocate IRQ%d\n",
+ hw_config->irq);
+ return;
+ }
+
+ if ((m = sound_alloc_mididev()) == -1){
+ printk (KERN_ERR "WF-MPU: Too many MIDI devices detected.\n");
+ free_irq (hw_config->irq, NULL);
+ release_region (hw_config->io_base, 2);
+ return;
+ }
+
+ request_region (hw_config->io_base, 2, "WaveFront MPU");
+
+ hw_config->slots[WF_INTERNAL_MIDI_SLOT] = m;
+ devc = &dev_conf[m];
+ devc->base = hw_config->io_base;
+ devc->irq = hw_config->irq;
+ devc->isexternal = 0;
+ devc->internal = m;
+ devc->external = -1;
+ devc->isvirtual = 0;
+
+ irq2dev[devc->irq] = m;
+
+ if (config_wf_mpu (m, hw_config)) {
+ printk (KERN_WARNING
+ "WF-MPU: configuration for MIDI device %d failed\n", m);
+ sound_unload_mididev (m);
+ }
+
+ /* 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 (devc);
+
+}
+
+int
+probe_wf_mpu (struct address_info *hw_config)
+
+{
+ if (hw_config->irq < 0 || hw_config->irq > 16) {
+ printk (KERN_WARNING "WF-MPU: bogus IRQ value requested (%d)\n",
+ hw_config->irq);
+ return 0;
+ }
+
+ if (check_region (hw_config->io_base, 2)) {
+ printk (KERN_WARNING "WF-MPU: I/O port %x already in use\n\n",
+ hw_config->io_base);
+ return 0;
+ }
+
+ if (inb (hw_config->io_base + 1) == 0xff) { /* Just bus float? */
+ printk ("WF-MPU: Port %x looks dead.\n", hw_config->io_base);
+ return 0;
+ }
+
+ return 1;
+}
+
+void
+unload_wf_mpu (struct address_info *hw_config)
+{
+
+ release_region (hw_config->io_base, 2);
+ sound_unload_mididev (hw_config->slots[WF_INTERNAL_MIDI_SLOT]);
+ if (hw_config->irq > 0) {
+ free_irq (hw_config->irq, NULL);
+ }
+ if (hw_config->slots[WF_EXTERNAL_MIDI_SLOT] > 0) {
+ sound_unload_mididev (hw_config->slots[WF_EXTERNAL_MIDI_SLOT]);
+ }
+}
+
+static void
+start_uart_mode (struct wf_mpu_config *devc)
+{
+ int ok, timeout;
+ unsigned long flags;
+
+ save_flags (flags);
+ cli ();
+
+ for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--);
+
+ wf_mpu_cmd (devc, UART_MODE_ON);
+
+ for (ok = 0, timeout = 50000; timeout > 0 && !ok; timeout--) {
+ if (input_avail (devc)) {
+ if (read_data (devc) == MPU_ACK) {
+ ok = 1;
+ }
+ }
+ }
+
+ restore_flags (flags);
+}
+
+#endif
+
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov