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

📄 mpu401.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * sound/mpu401.c * * The low level driver for Roland MPU-401 compatible Midi cards. *//* * 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. * * * Thomas Sailer	ioctl code reworked (vmalloc/vfree removed) * Alan Cox		modularisation, use normal request_irq, use dev_id * Bartlomiej Zolnierkiewicz	removed some __init to allow using many drivers */#include <linux/module.h>#include <linux/init.h>#define USE_SEQ_MACROS#define USE_SIMPLE_MACROS#include "sound_config.h"#include "coproc.h"#include "mpu401.h"static int      timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL;struct mpu_config{	int             base;	/*				 * I/O base				 */	int             irq;	int             opened;	/*				 * Open mode				 */	int             devno;	int             synthno;	int             uart_mode;	int             initialized;	int             mode;#define MODE_MIDI	1#define MODE_SYNTH	2	unsigned char   version, revision;	unsigned int    capabilities;#define MPU_CAP_INTLG	0x10000000#define MPU_CAP_SYNC	0x00000010#define MPU_CAP_FSK	0x00000020#define MPU_CAP_CLS	0x00000040#define MPU_CAP_SMPTE 	0x00000080#define MPU_CAP_2PORT	0x00000001	int             timer_flag;#define MBUF_MAX	10#define BUFTEST(dc) if (dc->m_ptr >= MBUF_MAX || dc->m_ptr < 0) \	{printk( "MPU: Invalid buffer pointer %d/%d, s=%d\n",  dc->m_ptr,  dc->m_left,  dc->m_state);dc->m_ptr--;}	  int             m_busy;	  unsigned char   m_buf[MBUF_MAX];	  int             m_ptr;	  int             m_state;	  int             m_left;	  unsigned char   last_status;	  void            (*inputintr) (int dev, unsigned char data);	  int             shared_irq;	  int            *osp;  };#define	DATAPORT(base)   (base)#define	COMDPORT(base)   (base+1)#define	STATPORT(base)   (base+1)static int mpu401_status(struct mpu_config *devc){	return inb(STATPORT(devc->base));}#define input_avail(devc)		(!(mpu401_status(devc)&INPUT_AVAIL))#define output_ready(devc)		(!(mpu401_status(devc)&OUTPUT_READY))static void write_command(struct mpu_config *devc, unsigned char cmd){	outb(cmd, COMDPORT(devc->base));}static int read_data(struct mpu_config *devc){	return inb(DATAPORT(devc->base));}static void write_data(struct mpu_config *devc, unsigned char byte){	outb(byte, DATAPORT(devc->base));}#define	OUTPUT_READY	0x40#define	INPUT_AVAIL	0x80#define	MPU_ACK		0xFE#define	MPU_RESET	0xFF#define	UART_MODE_ON	0x3Fstatic struct mpu_config dev_conf[MAX_MIDI_DEV] ={	{0}};static int n_mpu_devs = 0;static int reset_mpu401(struct mpu_config *devc);static void set_uart_mode(int dev, struct mpu_config *devc, int arg);static int mpu_timer_init(int midi_dev);static void mpu_timer_interrupt(void);static void timer_ext_event(struct mpu_config *devc, int event, int parm);static struct synth_info mpu_synth_info_proto = {	"MPU-401 MIDI interface", 	0, 	SYNTH_TYPE_MIDI, 	MIDI_TYPE_MPU401, 	0, 128, 	0, 128, 	SYNTH_CAP_INPUT};static struct synth_info mpu_synth_info[MAX_MIDI_DEV];/* * States for the input scanner */#define ST_INIT			0	/* Ready for timing byte or msg */#define ST_TIMED		1	/* Leading timing byte rcvd */#define ST_DATABYTE		2	/* Waiting for (nr_left) data bytes */#define ST_SYSMSG		100	/* System message (sysx etc). */#define ST_SYSEX		101	/* System exclusive msg */#define ST_MTC			102	/* Midi Time Code (MTC) qframe msg */#define ST_SONGSEL		103	/* Song select */#define ST_SONGPOS		104	/* Song position pointer */static unsigned char len_tab[] =	/* # of data bytes following a status					 */{	2,			/* 8x */	2,			/* 9x */	2,			/* Ax */	2,			/* Bx */	1,			/* Cx */	1,			/* Dx */	2,			/* Ex */	0			/* Fx */};#define STORE(cmd) \{ \	int len; \	unsigned char obuf[8]; \	cmd; \	seq_input_event(obuf, len); \}#define _seqbuf obuf#define _seqbufptr 0#define _SEQ_ADVBUF(x) len=xstatic int mpu_input_scanner(struct mpu_config *devc, unsigned char midic){	switch (devc->m_state)	{		case ST_INIT:			switch (midic)			{				case 0xf8:				/* Timer overflow */					break;				case 0xfc:					printk("<all end>");			 		break;				case 0xfd:					if (devc->timer_flag)						mpu_timer_interrupt();					break;				case 0xfe:					return MPU_ACK;				case 0xf0:				case 0xf1:				case 0xf2:				case 0xf3:				case 0xf4:				case 0xf5:				case 0xf6:				case 0xf7:					printk("<Trk data rq #%d>", midic & 0x0f);					break;				case 0xf9:					printk("<conductor rq>");					break;				case 0xff:					devc->m_state = ST_SYSMSG;					break;				default:					if (midic <= 0xef)					{						/* printk( "mpu time: %d ",  midic); */						devc->m_state = ST_TIMED;					}					else						printk("<MPU: Unknown event %02x> ", midic);			}			break;		case ST_TIMED:			{				int msg = ((int) (midic & 0xf0) >> 4);				devc->m_state = ST_DATABYTE;				if (msg < 8)	/* Data byte */				{					/* printk( "midi msg (running status) "); */					msg = ((int) (devc->last_status & 0xf0) >> 4);					msg -= 8;					devc->m_left = len_tab[msg] - 1;					devc->m_ptr = 2;					devc->m_buf[0] = devc->last_status;					devc->m_buf[1] = midic;					if (devc->m_left <= 0)					{						devc->m_state = ST_INIT;						do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);						devc->m_ptr = 0;					}				}				else if (msg == 0xf)	/* MPU MARK */				{					devc->m_state = ST_INIT;					switch (midic)					{						case 0xf8:							/* printk( "NOP "); */							break;						case 0xf9:							/* printk( "meas end "); */							break;						case 0xfc:							/* printk( "data end "); */							break;						default:							printk("Unknown MPU mark %02x\n", midic);					}				}				else				{					devc->last_status = midic;					/* printk( "midi msg "); */					msg -= 8;					devc->m_left = len_tab[msg];					devc->m_ptr = 1;					devc->m_buf[0] = midic;					if (devc->m_left <= 0)					{						devc->m_state = ST_INIT;						do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);						devc->m_ptr = 0;					}				}			}			break;		case ST_SYSMSG:			switch (midic)			{				case 0xf0:					printk("<SYX>");					devc->m_state = ST_SYSEX;					break;				case 0xf1:					devc->m_state = ST_MTC;					break;				case 0xf2:					devc->m_state = ST_SONGPOS;					devc->m_ptr = 0;					break;				case 0xf3:					devc->m_state = ST_SONGSEL;					break;				case 0xf6:					/* printk( "tune_request\n"); */					devc->m_state = ST_INIT;					/*					 *    Real time messages					 */				case 0xf8:					/* midi clock */					devc->m_state = ST_INIT;					timer_ext_event(devc, TMR_CLOCK, 0);					break;				case 0xfA:					devc->m_state = ST_INIT;					timer_ext_event(devc, TMR_START, 0);					break;				case 0xFB:					devc->m_state = ST_INIT;					timer_ext_event(devc, TMR_CONTINUE, 0);					break;				case 0xFC:					devc->m_state = ST_INIT;					timer_ext_event(devc, TMR_STOP, 0);					break;				case 0xFE:					/* active sensing */					devc->m_state = ST_INIT;					break;				case 0xff:					/* printk( "midi hard reset"); */					devc->m_state = ST_INIT;					break;				default:					printk("unknown MIDI sysmsg %0x\n", midic);					devc->m_state = ST_INIT;			}			break;		case ST_MTC:			devc->m_state = ST_INIT;			printk("MTC frame %x02\n", midic);			break;		case ST_SYSEX:			if (midic == 0xf7)			{				printk("<EOX>");				devc->m_state = ST_INIT;			}			else				printk("%02x ", midic);			break;		case ST_SONGPOS:			BUFTEST(devc);			devc->m_buf[devc->m_ptr++] = midic;			if (devc->m_ptr == 2)			{				devc->m_state = ST_INIT;				devc->m_ptr = 0;				timer_ext_event(devc, TMR_SPP,					((devc->m_buf[1] & 0x7f) << 7) |					(devc->m_buf[0] & 0x7f));			}			break;		case ST_DATABYTE:			BUFTEST(devc);			devc->m_buf[devc->m_ptr++] = midic;			if ((--devc->m_left) <= 0)			{				devc->m_state = ST_INIT;				do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);				devc->m_ptr = 0;			}			break;		default:			printk("Bad state %d ", devc->m_state);			devc->m_state = ST_INIT;	}	return 1;}static void mpu401_input_loop(struct mpu_config *devc){	unsigned long flags;	int busy;	int n;	save_flags(flags);	cli();	busy = devc->m_busy;	devc->m_busy = 1;	restore_flags(flags);	if (busy)		/* Already inside the scanner */		return;	n = 50;	while (input_avail(devc) && n-- > 0)	{		unsigned char c = read_data(devc);		if (devc->mode == MODE_SYNTH)		{			mpu_input_scanner(devc, c);		}		else if (devc->opened & OPEN_READ && devc->inputintr != NULL)			devc->inputintr(devc->devno, c);	}	devc->m_busy = 0;}int intchk_mpu401(void *dev_id){	struct mpu_config *devc;	int dev = (int) dev_id;	devc = &dev_conf[dev];	return input_avail(devc);}void mpuintr(int irq, void *dev_id, struct pt_regs *dummy){	struct mpu_config *devc;	int dev = (int) dev_id;	sti();	devc = &dev_conf[dev];	if (input_avail(devc))	{		if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH))			mpu401_input_loop(devc);		else		{			/* Dummy read (just to acknowledge the interrupt) */			read_data(devc);		}	}}static int mpu401_open(int dev, int mode,	    void            (*input) (int dev, unsigned char data),	    void            (*output) (int dev)){	int err;	struct mpu_config *devc;	if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)		return -ENXIO;	devc = &dev_conf[dev];	if (devc->opened)		  return -EBUSY;	/*	 *  Verify that the device is really running.	 *  Some devices (such as Ensoniq SoundScape don't	 *  work before the on board processor (OBP) is initialized	 *  by downloading its microcode.	 */	if (!devc->initialized)	{		if (mpu401_status(devc) == 0xff)	/* Bus float */		{			printk(KERN_ERR "mpu401: Device not initialized properly\n");			return -EIO;		}		reset_mpu401(devc);	}	if (midi_devs[dev]->coproc)	{		if ((err = midi_devs[dev]->coproc->		     open(midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0)		{			printk("MPU-401: Can't access coprocessor device\n");			return err;		}	}		set_uart_mode(dev, devc, 1);	devc->mode = MODE_MIDI;	devc->synthno = 0;	mpu401_input_loop(devc);	devc->inputintr = input;	devc->opened = mode;	return 0;}static void mpu401_close(int dev){	struct mpu_config *devc;	devc = &dev_conf[dev];	if (devc->uart_mode)		reset_mpu401(devc);	/*					 * This disables the UART mode					 */	devc->mode = 0;	devc->inputintr = NULL;	if (midi_devs[dev]->coproc)		midi_devs[dev]->coproc->close(midi_devs[dev]->coproc->devc, COPR_MIDI);	devc->opened = 0;}static int mpu401_out(int dev, unsigned char midi_byte){	int timeout;	unsigned long flags;	struct mpu_config *devc;	devc = &dev_conf[dev];	/*	 * Sometimes it takes about 30000 loops before the output becomes ready	 * (After reset). Normally it takes just about 10 loops.	 */	for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--);	save_flags(flags);	cli();	if (!output_ready(devc))	{		printk(KERN_WARNING "mpu401: Send data timeout\n");		restore_flags(flags);		return 0;	}	write_data(devc, midi_byte);	restore_flags(flags);	return 1;}static int mpu401_command(int dev, mpu_command_rec * cmd){	int i, timeout, ok;	int ret = 0;	unsigned long   flags;	struct mpu_config *devc;	devc = &dev_conf[dev];	if (devc->uart_mode)	/*				 * Not possible in UART mode				 */	{		printk(KERN_WARNING "mpu401: commands not possible in the UART mode\n");		return -EINVAL;	}	/*	 * Test for input since pending input seems to block the output.	 */	if (input_avail(devc))		mpu401_input_loop(devc);	/*	 * Sometimes it takes about 50000 loops before the output becomes ready	 * (After reset). Normally it takes just about 10 loops.	 */	timeout = 50000;retry:	if (timeout-- <= 0)

⌨️ 快捷键说明

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