📄 mpu401.c
字号:
/* * sound/mpu401.c * * The low level driver for Roland MPU-401 compatible Midi cards. * * This version supports just the DUMB UART mode. * * Copyright by Hannu Savolainen 1993 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */#include "sound_config.h"#ifdef CONFIGURE_SOUNDCARD#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)#define DATAPORT (mpu401_base) /* MPU-401 Data I/O Port on IBM */#define COMDPORT (mpu401_base+1) /* MPU-401 Command Port on IBM */#define STATPORT (mpu401_base+1) /* MPU-401 Status Port on IBM */#define mpu401_status() INB(STATPORT)#define input_avail() (!(mpu401_status()&INPUT_AVAIL))#define output_ready() (!(mpu401_status()&OUTPUT_READY))#define mpu401_cmd(cmd) OUTB(cmd, COMDPORT)#define mpu401_read() INB(DATAPORT)#define mpu401_write(byte) OUTB(byte, DATAPORT)#define OUTPUT_READY 0x40 /* Mask for Data Read Redy Bit */#define INPUT_AVAIL 0x80 /* Mask for Data Send Ready Bit */#define MPU_ACK 0xFE /* MPU-401 Acknowledge Response */#define MPU_RESET 0xFF /* MPU-401 Total Reset Command */#define UART_MODE_ON 0x3F /* MPU-401 "Dumb UART Mode" */static int mpu401_opened = 0;static int mpu401_base = 0x330;static int mpu401_irq;static int mpu401_detected = 0;static int my_dev;static int reset_mpu401 (void);static void (*midi_input_intr) (int dev, unsigned char data);static voidmpu401_input_loop (void){ int count; count = 10; while (count) /* Not timed out */ if (input_avail ()) { unsigned char c = mpu401_read (); count = 100; if (mpu401_opened & OPEN_READ) midi_input_intr (my_dev, c); } else while (!input_avail () && count) count--;}voidmpuintr (int unit){ if (input_avail ()) mpu401_input_loop ();}/* * It looks like there is no input interrupts in the UART mode. Let's try * polling. */static voidpoll_mpu401 (unsigned long dummy){ unsigned long flags; DEFINE_TIMER(mpu401_timer, poll_mpu401); if (!(mpu401_opened & OPEN_READ)) return; /* No longer required */ DISABLE_INTR (flags); if (input_avail ()) mpu401_input_loop (); ACTIVATE_TIMER(mpu401_timer, poll_mpu401, 1); /* Come back later */ RESTORE_INTR (flags);}static intmpu401_open (int dev, int mode, void (*input) (int dev, unsigned char data), void (*output) (int dev)){ if (mpu401_opened) { printk ("MPU-401: Midi busy\n"); return RET_ERROR (EBUSY); } mpu401_input_loop (); midi_input_intr = input; mpu401_opened = mode; poll_mpu401 (0); /* Enable input polling */ return 0;}static voidmpu401_close (int dev){ mpu401_opened = 0;}static intmpu401_out (int dev, unsigned char midi_byte){ int timeout; unsigned long flags; /* * Test for input since pending input seems to block the output. */ DISABLE_INTR (flags); if (input_avail ()) mpu401_input_loop (); RESTORE_INTR (flags); /* * Sometimes it takes about 13000 loops before the output becomes ready * (After reset). Normally it takes just about 10 loops. */ for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /* Wait */ if (!output_ready ()) { printk ("MPU-401: Timeout\n"); return 0; } mpu401_write (midi_byte); return 1;}static intmpu401_command (int dev, unsigned char midi_byte){ return 1;}static intmpu401_start_read (int dev){ return 0;}static intmpu401_end_read (int dev){ return 0;}static intmpu401_ioctl (int dev, unsigned cmd, unsigned arg){ return RET_ERROR (EINVAL);}static voidmpu401_kick (int dev){}static intmpu401_buffer_status (int dev){ return 0; /* No data in buffers */}static struct midi_operations mpu401_operations ={ {"MPU-401", 0, 0, SNDCARD_MPU401}, mpu401_open, mpu401_close, mpu401_ioctl, mpu401_out, mpu401_start_read, mpu401_end_read, mpu401_kick, mpu401_command, mpu401_buffer_status};longattach_mpu401 (long mem_start, struct address_info *hw_config){ int ok, timeout; unsigned long flags; mpu401_base = hw_config->io_base; mpu401_irq = hw_config->irq; if (!mpu401_detected) return RET_ERROR (EIO); DISABLE_INTR (flags); for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */ mpu401_cmd (UART_MODE_ON); ok = 0; for (timeout = 50000; timeout > 0 && !ok; timeout--) if (input_avail ()) if (mpu401_read () == MPU_ACK) ok = 1; RESTORE_INTR (flags); printk (" <Roland MPU-401>"); my_dev = num_midis; mpu401_dev = num_midis; midi_devs[num_midis++] = &mpu401_operations; return mem_start;}static intreset_mpu401 (void){ unsigned long flags; int ok, timeout, n; /* * Send the RESET command. Try again if no success at the first time. */ ok = 0; DISABLE_INTR (flags); for (n = 0; n < 2 && !ok; n++) { for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */ mpu401_cmd (MPU_RESET); /* Send MPU-401 RESET Command */ /* * Wait at least 25 msec. This method is not accurate so let's make the * loop bit longer. Cannot sleep since this is called during boot. */ for (timeout = 50000; timeout > 0 && !ok; timeout--) if (input_avail ()) if (mpu401_read () == MPU_ACK) ok = 1; } mpu401_opened = 0; if (ok) mpu401_input_loop (); /* Flush input before enabling interrupts */ RESTORE_INTR (flags); return ok;}intprobe_mpu401 (struct address_info *hw_config){ int ok = 0; mpu401_base = hw_config->io_base; mpu401_irq = hw_config->irq; if (snd_set_irq_handler (mpu401_irq, mpuintr) < 0) return 0; ok = reset_mpu401 (); mpu401_detected = ok; return ok;}#endif#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -