⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uart401.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
字号:
/* * 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	0x3Fstatic 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 devc\n");		return;	}	if (input_avail(devc))		uart401_input_loop(devc);}static intuart401_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 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(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 OK\n"));	}	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 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;	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%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] = kmalloc(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;	}	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 memory\n");		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 MODULEstatic 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);#endifMODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -