diff options
Diffstat (limited to 'sound/oss/uart401.c')
-rw-r--r-- | sound/oss/uart401.c | 477 |
1 files changed, 0 insertions, 477 deletions
diff --git a/sound/oss/uart401.c b/sound/oss/uart401.c deleted file mode 100644 index 83dcc85b8688..000000000000 --- a/sound/oss/uart401.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * sound/oss/uart401.c - * - * MPU-401 UART driver (formerly uart401_midi.c) - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free 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. - * - * Changes: - * Alan Cox Reformatted, removed sound_mem usage, use normal Linux - * interrupt allocation. Protect against bogus unload - * Fixed to allow IRQ > 15 - * Christoph Hellwig Adapted to module_init/module_exit - * Arnaldo C. de Melo got rid of check_region - * - * Status: - * Untested - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include "sound_config.h" - -#include "mpu401.h" - -struct uart401_devc -{ - int base; - int irq; - int *osp; - void (*midi_input_intr) (int dev, unsigned char data); - int opened, disabled; - volatile unsigned char input_byte; - int my_dev; - int share_irq; - spinlock_t lock; -}; - -#define DATAPORT (devc->base) -#define COMDPORT (devc->base+1) -#define STATPORT (devc->base+1) - -static int uart401_status(struct uart401_devc *devc) -{ - return inb(STATPORT); -} - -#define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL)) -#define output_ready(devc) (!(uart401_status(devc)&OUTPUT_READY)) - -static void uart401_cmd(struct uart401_devc *devc, unsigned char cmd) -{ - outb((cmd), COMDPORT); -} - -static int uart401_read(struct uart401_devc *devc) -{ - return inb(DATAPORT); -} - -static void uart401_write(struct uart401_devc *devc, unsigned char byte) -{ - outb((byte), DATAPORT); -} - -#define OUTPUT_READY 0x40 -#define INPUT_AVAIL 0x80 -#define MPU_ACK 0xFE -#define MPU_RESET 0xFF -#define UART_MODE_ON 0x3F - -static int reset_uart401(struct uart401_devc *devc); -static void enter_uart_mode(struct uart401_devc *devc); - -static void uart401_input_loop(struct uart401_devc *devc) -{ - int work_limit=30000; - - while (input_avail(devc) && --work_limit) - { - unsigned char c = uart401_read(devc); - - if (c == MPU_ACK) - devc->input_byte = c; - else if (devc->opened & OPEN_READ && devc->midi_input_intr) - devc->midi_input_intr(devc->my_dev, c); - } - if(work_limit==0) - printk(KERN_WARNING "Too much work in interrupt on uart401 (0x%X). UART jabbering ??\n", devc->base); -} - -irqreturn_t uart401intr(int irq, void *dev_id) -{ - struct uart401_devc *devc = dev_id; - - if (devc == NULL) - { - printk(KERN_ERR "uart401: bad devc\n"); - return IRQ_NONE; - } - - if (input_avail(devc)) - uart401_input_loop(devc); - return IRQ_HANDLED; -} - -static int -uart401_open(int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - struct uart401_devc *devc = (struct uart401_devc *) - midi_devs[dev]->devc; - - if (devc->opened) - return -EBUSY; - - /* Flush the UART */ - - while (input_avail(devc)) - uart401_read(devc); - - devc->midi_input_intr = input; - devc->opened = mode; - enter_uart_mode(devc); - devc->disabled = 0; - - return 0; -} - -static void uart401_close(int dev) -{ - struct uart401_devc *devc = (struct uart401_devc *) - midi_devs[dev]->devc; - - reset_uart401(devc); - devc->opened = 0; -} - -static int uart401_out(int dev, unsigned char midi_byte) -{ - int timeout; - unsigned long flags; - struct uart401_devc *devc = (struct uart401_devc *) - midi_devs[dev]->devc; - - if (devc->disabled) - return 1; - /* - * Test for input since pending input seems to block the output. - */ - - spin_lock_irqsave(&devc->lock,flags); - if (input_avail(devc)) - uart401_input_loop(devc); - - spin_unlock_irqrestore(&devc->lock,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(devc); timeout--); - - if (!output_ready(devc)) - { - printk(KERN_WARNING "uart401: Timeout - Device not responding\n"); - devc->disabled = 1; - reset_uart401(devc); - enter_uart_mode(devc); - return 1; - } - uart401_write(devc, midi_byte); - return 1; -} - -static inline int uart401_start_read(int dev) -{ - return 0; -} - -static inline int uart401_end_read(int dev) -{ - return 0; -} - -static inline void uart401_kick(int dev) -{ -} - -static inline int uart401_buffer_status(int dev) -{ - return 0; -} - -#define MIDI_SYNTH_NAME "MPU-401 UART" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -static const struct midi_operations uart401_operations = -{ - .owner = THIS_MODULE, - .info = {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401}, - .converter = &std_midi_synth, - .in_info = {0}, - .open = uart401_open, - .close = uart401_close, - .outputc = uart401_out, - .start_read = uart401_start_read, - .end_read = uart401_end_read, - .kick = uart401_kick, - .buffer_status = uart401_buffer_status, -}; - -static void enter_uart_mode(struct uart401_devc *devc) -{ - int ok, timeout; - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - - devc->input_byte = 0; - uart401_cmd(devc, UART_MODE_ON); - - ok = 0; - for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (devc->input_byte == MPU_ACK) - ok = 1; - else if (input_avail(devc)) - if (uart401_read(devc) == MPU_ACK) - ok = 1; - - spin_unlock_irqrestore(&devc->lock,flags); -} - -static int reset_uart401(struct uart401_devc *devc) -{ - int ok, timeout, n; - - /* - * Send the RESET command. Try again if no success at the first time. - */ - - ok = 0; - - for (n = 0; n < 2 && !ok; n++) - { - for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); - devc->input_byte = 0; - uart401_cmd(devc, MPU_RESET); - - /* - * 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 (devc->input_byte == MPU_ACK) /* Interrupt */ - ok = 1; - else if (input_avail(devc)) - { - if (uart401_read(devc) == MPU_ACK) - ok = 1; - } - } - } - - /* Flush input before enabling interrupts */ - if (ok) - uart401_input_loop(devc); - else - DDB(printk("Reset UART401 failed - No hardware detected.\n")); - - return ok; -} - -int probe_uart401(struct address_info *hw_config, struct module *owner) -{ - struct uart401_devc *devc; - char *name = "MPU-401 (UART) MIDI"; - int ok = 0; - unsigned long flags; - - DDB(printk("Entered probe_uart401()\n")); - - /* Default to "not found" */ - hw_config->slots[4] = -1; - - if (!request_region(hw_config->io_base, 4, "MPU-401 UART")) { - printk(KERN_INFO "uart401: could not request_region(%d, 4)\n", hw_config->io_base); - return 0; - } - - devc = kmalloc(sizeof(struct uart401_devc), GFP_KERNEL); - if (!devc) { - printk(KERN_WARNING "uart401: Can't allocate memory\n"); - goto cleanup_region; - } - - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->osp = hw_config->osp; - devc->midi_input_intr = NULL; - devc->opened = 0; - devc->input_byte = 0; - devc->my_dev = 0; - devc->share_irq = 0; - spin_lock_init(&devc->lock); - - spin_lock_irqsave(&devc->lock,flags); - ok = reset_uart401(devc); - spin_unlock_irqrestore(&devc->lock,flags); - - if (!ok) - goto cleanup_devc; - - if (hw_config->name) - name = hw_config->name; - - if (devc->irq < 0) { - devc->share_irq = 1; - devc->irq *= -1; - } else - devc->share_irq = 0; - - if (!devc->share_irq) - if (request_irq(devc->irq, uart401intr, 0, "MPU-401 UART", devc) < 0) { - printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq); - devc->share_irq = 1; - } - devc->my_dev = sound_alloc_mididev(); - enter_uart_mode(devc); - - if (devc->my_dev == -1) { - printk(KERN_INFO "uart401: Too many midi devices detected\n"); - goto cleanup_irq; - } - conf_printf(name, hw_config); - midi_devs[devc->my_dev] = kmemdup(&uart401_operations, - sizeof(struct midi_operations), - GFP_KERNEL); - if (!midi_devs[devc->my_dev]) { - printk(KERN_ERR "uart401: Failed to allocate memory\n"); - goto cleanup_unload_mididev; - } - - if (owner) - midi_devs[devc->my_dev]->owner = owner; - - midi_devs[devc->my_dev]->devc = devc; - midi_devs[devc->my_dev]->converter = kmemdup(&std_midi_synth, - sizeof(struct synth_operations), - GFP_KERNEL); - - if (!midi_devs[devc->my_dev]->converter) { - printk(KERN_WARNING "uart401: Failed to allocate memory\n"); - goto cleanup_midi_devs; - } - strcpy(midi_devs[devc->my_dev]->info.name, name); - midi_devs[devc->my_dev]->converter->id = "UART401"; - midi_devs[devc->my_dev]->converter->midi_dev = devc->my_dev; - - if (owner) - midi_devs[devc->my_dev]->converter->owner = owner; - - hw_config->slots[4] = devc->my_dev; - sequencer_init(); - devc->opened = 0; - return 1; -cleanup_midi_devs: - kfree(midi_devs[devc->my_dev]); -cleanup_unload_mididev: - sound_unload_mididev(devc->my_dev); -cleanup_irq: - if (!devc->share_irq) - free_irq(devc->irq, devc); -cleanup_devc: - kfree(devc); -cleanup_region: - release_region(hw_config->io_base, 4); - return 0; -} - -void unload_uart401(struct address_info *hw_config) -{ - struct uart401_devc *devc; - int n=hw_config->slots[4]; - - /* Not set up */ - if(n==-1 || midi_devs[n]==NULL) - return; - - /* Not allocated (erm ??) */ - - devc = midi_devs[hw_config->slots[4]]->devc; - if (devc == NULL) - return; - - reset_uart401(devc); - release_region(hw_config->io_base, 4); - - if (!devc->share_irq) - free_irq(devc->irq, devc); - kfree(midi_devs[devc->my_dev]->converter); - kfree(midi_devs[devc->my_dev]); - kfree(devc); - - /* This kills midi_devs[x] */ - sound_unload_mididev(hw_config->slots[4]); -} - -EXPORT_SYMBOL(probe_uart401); -EXPORT_SYMBOL(unload_uart401); -EXPORT_SYMBOL(uart401intr); - -static struct address_info cfg_mpu; - -static int io = -1; -static int irq = -1; - -module_param_hw(io, int, ioport, 0444); -module_param_hw(irq, int, irq, 0444); - - -static int __init init_uart401(void) -{ - cfg_mpu.irq = irq; - cfg_mpu.io_base = io; - - /* Can be loaded either for module use or to provide functions - to others */ - if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) { - printk(KERN_INFO "MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997"); - if (!probe_uart401(&cfg_mpu, THIS_MODULE)) - return -ENODEV; - } - - return 0; -} - -static void __exit cleanup_uart401(void) -{ - if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) - unload_uart401(&cfg_mpu); -} - -module_init(init_uart401); -module_exit(cleanup_uart401); - -#ifndef MODULE -static int __init setup_uart401(char *str) -{ - /* io, irq */ - int ints[3]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - - return 1; -} - -__setup("uart401=", setup_uart401); -#endif -MODULE_LICENSE("GPL"); |