diff options
Diffstat (limited to 'sound/oss/wf_midi.c')
-rw-r--r-- | sound/oss/wf_midi.c | 880 |
1 files changed, 0 insertions, 880 deletions
diff --git a/sound/oss/wf_midi.c b/sound/oss/wf_midi.c deleted file mode 100644 index 75c0c143a759..000000000000 --- a/sound/oss/wf_midi.c +++ /dev/null @@ -1,880 +0,0 @@ -/* - * sound/oss/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, IRQF_DISABLED|IRQF_SHARED, - "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 |