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

📄 mpu401.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * sound/mpu401.c * * The low level driver for Roland MPU-401 compatible Midi cards. * * Copyright by Hannu Savolainen 1993 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Modified: *  Riccardo Facchetti  24 Mar 1995 *  - Added the Audio Excel DSP 16 initialization routine. */#define USE_SEQ_MACROS#define USE_SIMPLE_MACROS#include <i386/isa/sound/sound_config.h>#ifdef CONFIGURE_SOUNDCARD#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)#include <i386/isa/sound/coproc.h>static int      init_sequence[20];	/* NOTE! pos 0 = len, start pos 1. */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;  };#define	DATAPORT(base)   (base)#define	COMDPORT(base)   (base+1)#define	STATPORT(base)   (base+1)#define mpu401_status(base)		INB(STATPORT(base))#define input_avail(base)		(!(mpu401_status(base)&INPUT_AVAIL))#define output_ready(base)		(!(mpu401_status(base)&OUTPUT_READY))#define write_command(base, cmd)		OUTB(cmd, COMDPORT(base))#define read_data(base)		INB(DATAPORT(base))#define write_data(base, byte)	OUTB(byte, DATAPORT(base))#define	OUTPUT_READY	0x40#define	INPUT_AVAIL	0x80#define	MPU_ACK		0xF7#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      irq2dev[16] ={-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};static int      reset_mpu401 (struct mpu_config *devc);static void     set_uart_mode (int dev, struct mpu_config *devc, int arg);static void     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, 0, 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 intmpu_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;	  break;	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 = (midic & 0xf0) >> 4;	devc->m_state = ST_DATABYTE;	if (msg < 8)		/* Data byte */	  {	    /* printk("midi msg (running status) "); */	    msg = (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 voidmpu401_input_loop (struct mpu_config *devc){  unsigned long   flags;  int             busy;  int             n;  DISABLE_INTR (flags);  busy = devc->m_busy;  devc->m_busy = 1;  RESTORE_INTR (flags);  if (busy)			/* Already inside the scanner */    return;  n = 50;  while (input_avail (devc->base) && n-- > 0)    {      unsigned char   c = read_data (devc->base);      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;}voidmpuintr (INT_HANDLER_PARMS (irq, dummy)){  struct mpu_config *devc;  int             dev;#ifdef linux  sti ();#endif  if (irq < 1 || irq > 15)    {      printk ("MPU-401: Interrupt #%d?\n", irq);      return;    }  dev = irq2dev[irq];  if (dev == -1)    {      /* printk ("MPU-401: Interrupt #%d?\n", irq); */      return;    }  devc = &dev_conf[dev];  if (input_avail (devc->base))    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->base);      }}static intmpu401_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)    return RET_ERROR (ENXIO);  devc = &dev_conf[dev];  if (devc->opened)    {      printk ("MPU-401: Midi busy\n");      return RET_ERROR (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 downloadin it's microcode.   */  if (!devc->initialized)    {      if (mpu401_status (devc->base) == 0xff)	/* Bus float */	{	  printk ("MPU-401: Device not initialized properly\n");	  return RET_ERROR (EIO);	}      reset_mpu401 (devc);    }  irq2dev[devc->irq] = dev;  if (devc->shared_irq == 0)    if ((err = snd_set_irq_handler (devc->irq, mpuintr, midi_devs[dev]->info.name) < 0))      {	return err;      }  if (midi_devs[dev]->coproc)    if ((err = midi_devs[dev]->coproc->	 open (midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0)      {	if (devc->shared_irq == 0)	  snd_release_irq (devc->irq);	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 voidmpu401_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;  if (devc->shared_irq == 0)    snd_release_irq (devc->irq);  devc->inputintr = NULL;  if (midi_devs[dev]->coproc)    midi_devs[dev]->coproc->close (midi_devs[dev]->coproc->devc, COPR_MIDI);  devc->opened = 0;}static intmpu401_out (int dev, unsigned char midi_byte){  int             timeout;  unsigned long   flags;  struct mpu_config *devc;  devc = &dev_conf[dev];#if 0  /*   * Test for input since pending input seems to block the output.   */  if (input_avail (devc->base))    {      mpu401_input_loop (devc);    }#endif  /*   * Sometimes it takes about 13000 loops before the output becomes ready   * (After reset). Normally it takes just about 10 loops.   */  for (timeout = 3000; timeout > 0 && !output_ready (devc->base); timeout--);  DISABLE_INTR (flags);  if (!output_ready (devc->base))    {      printk ("MPU-401: Send data timeout\n");      RESTORE_INTR (flags);      return 0;    }  write_data (devc->base, midi_byte);  RESTORE_INTR (flags);  return 1;}static intmpu401_command (int dev, mpu_command_rec * cmd)

⌨️ 快捷键说明

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