cregit-Linux how code gets into the kernel

Release 4.13 sound/oss/uart401.c

Directory: sound/oss
/*
 * 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); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1694.12%266.67%
Himangi Saraogi15.88%133.33%
Total17100.00%3100.00%

#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); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2395.83%480.00%
Himangi Saraogi14.17%120.00%
Total24100.00%5100.00%


static int uart401_read(struct uart401_devc *devc) { return inb(DATAPORT); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1694.12%266.67%
Himangi Saraogi15.88%133.33%
Total17100.00%3100.00%


static void uart401_write(struct uart401_devc *devc, unsigned char byte) { outb((byte), DATAPORT); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2395.83%480.00%
Himangi Saraogi14.17%120.00%
Total24100.00%5100.00%

#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); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8898.88%480.00%
Himangi Saraogi11.12%120.00%
Total89100.00%5100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4384.31%571.43%
Andrew Morton713.73%114.29%
Himangi Saraogi11.96%114.29%
Total51100.00%7100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)10098.04%685.71%
Himangi Saraogi21.96%114.29%
Total102100.00%7100.00%


static void uart401_close(int dev) { struct uart401_devc *devc = (struct uart401_devc *) midi_devs[dev]->devc; reset_uart401(devc); devc->opened = 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3594.59%375.00%
Himangi Saraogi25.41%125.00%
Total37100.00%4100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)13190.34%571.43%
Peter Wächtler128.28%114.29%
Himangi Saraogi21.38%114.29%
Total145100.00%7100.00%


static inline int uart401_start_read(int dev) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)13100.00%3100.00%
Total13100.00%3100.00%


static inline int uart401_end_read(int dev) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)13100.00%3100.00%
Total13100.00%3100.00%


static inline void uart401_kick(int dev) { }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)9100.00%3100.00%
Total9100.00%3100.00%


static inline int uart401_buffer_status(int dev) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)13100.00%3100.00%
Total13100.00%3100.00%

#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); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)11389.68%571.43%
Peter Wächtler129.52%114.29%
Himangi Saraogi10.79%114.29%
Total126100.00%7100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)14797.35%133.33%
Joe Perches31.99%133.33%
Himangi Saraogi10.66%133.33%
Total151100.00%3100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)53089.53%1376.47%
Linus Torvalds325.41%15.88%
Peter Wächtler203.38%15.88%
Alexandru Gheorghiu81.35%15.88%
Himangi Saraogi20.34%15.88%
Total592100.00%17100.00%


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]); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)13099.24%888.89%
Himangi Saraogi10.76%111.11%
Total131100.00%9100.00%

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; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)64100.00%4100.00%
Total64100.00%4100.00%


static void __exit cleanup_uart401(void) { if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) unload_uart401(&cfg_mpu); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)31100.00%3100.00%
Total31100.00%3100.00%

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; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)49100.00%2100.00%
Total49100.00%2100.00%

__setup("uart401=", setup_uart401); #endif MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)183591.66%2262.86%
Peter Wächtler502.50%12.86%
Linus Torvalds381.90%25.71%
Alan Cox221.10%12.86%
Himangi Saraogi201.00%12.86%
Alexandru Gheorghiu80.40%12.86%
Andrew Morton70.35%12.86%
Jeff Garzik60.30%12.86%
David Howells60.30%12.86%
Joe Perches30.15%12.86%
Arnaldo Carvalho de Melo30.15%12.86%
Tejun Heo30.15%12.86%
Uwe Zeisberger10.05%12.86%
Total2002100.00%35100.00%
Directory: sound/oss
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.