URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [sound/] [uart401.c] - Rev 1765
Compare with Previous | Blame | View Log
/* * sound/uart401.c * * MPU-401 UART driver (formerly uart401_midi.c) */ /* * 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" #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) typedef struct uart401_devc { int base; int irq; int *osp; void (*midi_input_intr) (int dev, unsigned char data); int opened; volatile unsigned char input_byte; int my_dev; int share_irq; } uart401_devc; static uart401_devc *detected_devc = NULL; static uart401_devc *irq2devc[16] = {NULL}; #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 uart401_input_loop (uart401_devc * devc) { while (input_avail (devc)) { 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); } } void uart401intr (int irq, void *dev_id, struct pt_regs *dummy) { uart401_devc *devc; if (irq < 1 || irq > 15) return; devc = irq2devc[irq]; if (devc == NULL) 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); } while (input_avail (devc)) uart401_read (devc); devc->midi_input_intr = input; devc->opened = mode; return 0; } static void uart401_close (int dev) { uart401_devc *devc = (uart401_devc *) midi_devs[dev]->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; /* * 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 ("MPU-401: Timeout\n"); return 0; } uart401_write (devc, midi_byte); return 1; } static int uart401_start_read (int dev) { return 0; } static int uart401_end_read (int dev) { return 0; } static int uart401_ioctl (int dev, unsigned cmd, caddr_t arg) { return -(EINVAL); } static void uart401_kick (int dev) { } static 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 struct midi_operations uart401_operations = { {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401}, &std_midi_synth, {0}, uart401_open, uart401_close, uart401_ioctl, uart401_out, uart401_start_read, uart401_end_read, uart401_kick, NULL, uart401_buffer_status, NULL }; 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); } void attach_uart401 (struct address_info *hw_config) { uart401_devc *devc; char *name = "MPU-401 (UART) MIDI"; if (hw_config->name) name = hw_config->name; if (detected_devc == NULL) return; devc = (uart401_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (uart401_devc))); if (sound_nblocks < 1024) sound_nblocks++;; if (devc == NULL) { printk ("uart401: Can't allocate memory\n"); return; } memcpy ((char *) devc, (char *) detected_devc, sizeof (uart401_devc)); detected_devc = NULL; devc->irq = hw_config->irq; if (devc->irq < 0) { devc->share_irq = 1; devc->irq *= -1; } else devc->share_irq = 0; if (devc->irq < 1 || devc->irq > 15) return; if (!devc->share_irq) if (snd_set_irq_handler (devc->irq, uart401intr, "uart401", devc->osp) < 0) { printk ("uart401: Failed to allocate IRQ%d\n", devc->irq); return; } irq2devc[devc->irq] = devc; devc->my_dev = num_midis; request_region (hw_config->io_base, 4, "SB MIDI"); enter_uart_mode (devc); if (num_midis >= MAX_MIDI_DEV) { printk ("Sound: Too many midi devices detected\n"); return; } conf_printf (name, hw_config); std_midi_synth.midi_dev = devc->my_dev = num_midis; midi_devs[num_midis] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct midi_operations))); if (sound_nblocks < 1024) sound_nblocks++;; if (midi_devs[num_midis] == NULL) { printk ("uart401: Failed to allocate memory\n"); return; } memcpy ((char *) midi_devs[num_midis], (char *) &uart401_operations, sizeof (struct midi_operations)); midi_devs[num_midis]->devc = devc; midi_devs[num_midis]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations))); if (sound_nblocks < 1024) sound_nblocks++;; if (midi_devs[num_midis]->converter == NULL) { printk ("uart401: Failed to allocate memory\n"); return; } memcpy ((char *) midi_devs[num_midis]->converter, (char *) &std_midi_synth, sizeof (struct synth_operations)); strcpy (midi_devs[num_midis]->info.name, name); num_midis++; devc->opened = 0; } 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; /* save_flags(flags);cli(); */ 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) uart401_input_loop (devc); /* * Flush input before enabling interrupts */ /* restore_flags(flags); */ return ok; } int probe_uart401 (struct address_info *hw_config) { int ok = 0; static uart401_devc hw_info; uart401_devc *devc = &hw_info; detected_devc = NULL; if (check_region (hw_config->io_base, 4)) return 0; 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; ok = reset_uart401 (devc); if (ok) detected_devc = devc; return ok; } void unload_uart401 (struct address_info *hw_config) { uart401_devc *devc; int irq = hw_config->irq; if (irq < 0) irq *= -1; if (irq < 1 || irq > 15) return; devc = irq2devc[irq]; if (devc == NULL) return; reset_uart401 (devc); release_region (hw_config->io_base, 4); if (!devc->share_irq) snd_release_irq (devc->irq); } #endif