uart401.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
- /*
- * sound/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/module.h>
- #include "sound_config.h"
- #include "mpu401.h"
- typedef 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;
- }
- uart401_devc;
- #define DATAPORT (devc->base)
- #define COMDPORT (devc->base+1)
- #define STATPORT (devc->base+1)
- static int uart401_status(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(uart401_devc * devc, unsigned char cmd)
- {
- outb((cmd), COMDPORT);
- }
- static int uart401_read(uart401_devc * devc)
- {
- return inb(DATAPORT);
- }
- static void uart401_write(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(uart401_devc * devc);
- static void enter_uart_mode(uart401_devc * devc);
- static void uart401_input_loop(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);
- }
- void uart401intr(int irq, void *dev_id, struct pt_regs *dummy)
- {
- uart401_devc *devc = dev_id;
- if (devc == NULL)
- {
- printk(KERN_ERR "uart401: bad devcn");
- return;
- }
- if (input_avail(devc))
- uart401_input_loop(devc);
- }
- static int
- uart401_open(int dev, int mode,
- void (*input) (int dev, unsigned char data),
- void (*output) (int dev)
- )
- {
- uart401_devc *devc = (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)
- {
- uart401_devc *devc = (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;
- uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
- if (devc->disabled)
- return 1;
- /*
- * Test for input since pending input seems to block the output.
- */
- save_flags(flags);
- cli();
- if (input_avail(devc))
- uart401_input_loop(devc);
- restore_flags(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 respondingn");
- 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(uart401_devc * devc)
- {
- int ok, timeout;
- unsigned long flags;
- save_flags(flags);
- cli();
- 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;
- restore_flags(flags);
- }
- static int reset_uart401(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;
- }
- }
- }
- if (ok)
- {
- DEB(printk("Reset UART401 OKn"));
- }
- else
- DDB(printk("Reset UART401 failed - No hardware detected.n"));
- if (ok)
- uart401_input_loop(devc); /*
- * Flush input before enabling interrupts
- */
- return ok;
- }
- int probe_uart401(struct address_info *hw_config, struct module *owner)
- {
- 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(uart401_devc), GFP_KERNEL);
- if (!devc) {
- printk(KERN_WARNING "uart401: Can't allocate memoryn");
- 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;
- save_flags(flags);
- cli();
- ok = reset_uart401(devc);
- restore_flags(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%dn", 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 detectedn");
- goto cleanup_irq;
- }
- conf_printf(name, hw_config);
- midi_devs[devc->my_dev] = kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
- if (!midi_devs[devc->my_dev]) {
- printk(KERN_ERR "uart401: Failed to allocate memoryn");
- goto cleanup_unload_mididev;
- }
- memcpy(midi_devs[devc->my_dev], &uart401_operations, sizeof(struct midi_operations));
- if (owner)
- midi_devs[devc->my_dev]->owner = owner;
-
- midi_devs[devc->my_dev]->devc = devc;
- midi_devs[devc->my_dev]->converter = kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
- if (!midi_devs[devc->my_dev]->converter) {
- printk(KERN_WARNING "uart401: Failed to allocate memoryn");
- goto cleanup_midi_devs;
- }
- memcpy(midi_devs[devc->my_dev]->converter, &std_midi_synth, sizeof(struct synth_operations));
- 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)
- {
- 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);
- if (devc)
- {
- kfree(midi_devs[devc->my_dev]->converter);
- kfree(midi_devs[devc->my_dev]);
- kfree(devc);
- devc = NULL;
- }
- /* 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 __initdata io = -1;
- static int __initdata irq = -1;
- MODULE_PARM(io, "i");
- MODULE_PARM(irq, "i");
- 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");