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

📄 sscape.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * sound/sscape.c * * Low level driver for Ensoniq Soundscape * * Copyright by Hannu Savolainen 1994 * * 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. * */#include <i386/isa/sound/sound_config.h>#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SSCAPE)#include <i386/isa/sound/coproc.h>/* *    I/O ports */#define MIDI_DATA        0#define MIDI_CTRL        1#define HOST_CTRL        2#define TX_READY		0x02#define RX_READY		0x01#define HOST_DATA        3#define ODIE_ADDR        4#define ODIE_DATA        5/* *    Indirect registers */#define GA_INTSTAT_REG   0#define GA_INTENA_REG    1#define GA_DMAA_REG      2#define GA_DMAB_REG      3#define GA_INTCFG_REG    4#define GA_DMACFG_REG    5#define GA_CDCFG_REG     6#define GA_SMCFGA_REG    7#define GA_SMCFGB_REG    8#define GA_HMCTL_REG     9/* * DMA channel identifiers (A and B) */#define SSCAPE_DMA_A 		0#define SSCAPE_DMA_B		1#define PORT(name)	(devc->base+name)/* * Host commands recognized by the OBP microcode */#define CMD_GEN_HOST_ACK        0x80#define CMD_GEN_MPU_ACK         0x81#define CMD_GET_BOARD_TYPE      0x82#define CMD_SET_CONTROL         0x88#define CMD_GET_CONTROL         0x89#define CMD_SET_MT32            0x96#define CMD_GET_MT32            0x97#define CMD_SET_EXTMIDI         0x9b#define CMD_GET_EXTMIDI         0x9c#define CMD_ACK			0x80typedef struct sscape_info  {    int             base, irq, dma;    int             ok;		/* Properly detected */    int             dma_allocated;    int             my_audiodev;    int             opened;  }sscape_info;static struct sscape_info dev_info ={0};static struct sscape_info *devc = &dev_info;DEFINE_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag);#ifdef REVEAL_SPEA/* Spea and Reveal have assigned interrupt bits differently than Ensoniq */static char     valid_interrupts[] ={9, 7, 5, 15};#elsestatic char     valid_interrupts[] ={9, 5, 7, 10};#endifstatic unsigned charsscape_read (struct sscape_info *devc, int reg){  unsigned long   flags;  unsigned char   val;  DISABLE_INTR (flags);  OUTB (reg, PORT (ODIE_ADDR));  val = INB (PORT (ODIE_DATA));  RESTORE_INTR (flags);  return val;}static voidsscape_write (struct sscape_info *devc, int reg, int data){  unsigned long   flags;  DISABLE_INTR (flags);  OUTB (reg, PORT (ODIE_ADDR));  OUTB (data, PORT (ODIE_DATA));  RESTORE_INTR (flags);}static voidhost_open (struct sscape_info *devc){  OUTB (0x00, PORT (HOST_CTRL));	/* Put the board to the host mode */}static voidhost_close (struct sscape_info *devc){  OUTB (0x03, PORT (HOST_CTRL));	/* Put the board to the MIDI mode */}static inthost_write (struct sscape_info *devc, unsigned char *data, int count){  unsigned long   flags;  int             i, timeout;  DISABLE_INTR (flags);  /*     * Send the command and data bytes   */  for (i = 0; i < count; i++)    {      for (timeout = 10000; timeout > 0; timeout--)	if (INB (PORT (HOST_CTRL)) & TX_READY)	  break;      if (timeout <= 0)	{	  RESTORE_INTR (flags);	  return 0;	}      OUTB (data[i], PORT (HOST_DATA));    }  RESTORE_INTR (flags);  return 1;}static inthost_read (struct sscape_info *devc){  unsigned long   flags;  int             timeout;  unsigned char   data;  DISABLE_INTR (flags);  /*     * Read a byte   */  for (timeout = 10000; timeout > 0; timeout--)    if (INB (PORT (HOST_CTRL)) & RX_READY)      break;  if (timeout <= 0)    {      RESTORE_INTR (flags);      return -1;    }  data = INB (PORT (HOST_DATA));  RESTORE_INTR (flags);  return data;}static inthost_command1 (struct sscape_info *devc, int cmd){  unsigned char   buf[10];  buf[0] = (unsigned char) (cmd & 0xff);  return host_write (devc, buf, 1);}static inthost_command2 (struct sscape_info *devc, int cmd, int parm1){  unsigned char   buf[10];  buf[0] = (unsigned char) (cmd & 0xff);  buf[1] = (unsigned char) (parm1 & 0xff);  return host_write (devc, buf, 2);}static inthost_command3 (struct sscape_info *devc, int cmd, int parm1, int parm2){  unsigned char   buf[10];  buf[0] = (unsigned char) (cmd & 0xff);  buf[1] = (unsigned char) (parm1 & 0xff);  buf[2] = (unsigned char) (parm2 & 0xff);  return host_write (devc, buf, 3);}static voidset_mt32 (struct sscape_info *devc, int value){  host_open (devc);  host_command2 (devc, CMD_SET_MT32,		 value ? 1 : 0);  if (host_read (devc) != CMD_ACK)    {      printk ("SNDSCAPE: Setting MT32 mode failed\n");    }  host_close (devc);}static intget_board_type (struct sscape_info *devc){  int             tmp;  host_open (devc);  if (!host_command1 (devc, CMD_GET_BOARD_TYPE))    tmp = -1;  else    tmp = host_read (devc);  host_close (devc);  return tmp;}voidsscapeintr (INT_HANDLER_PARMS (irq, dummy)){  unsigned char   bits, tmp;  static int      debug = 0;  printk ("sscapeintr(0x%02x)\n", (bits = sscape_read (devc, GA_INTSTAT_REG)));  if (SOMEONE_WAITING (sscape_sleeper, sscape_sleep_flag))    {      WAKE_UP (sscape_sleeper, sscape_sleep_flag);    }  if (bits & 0x02)		/* Host interface interrupt */    {      printk ("SSCAPE: Host interrupt, data=%02x\n", host_read (devc));    }#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)  if (bits & 0x01)    {      mpuintr (INT_HANDLER_CALL (irq));      if (debug++ > 10)		/* Temporary debugging hack */	{	  sscape_write (devc, GA_INTENA_REG, 0x00);	/* Disable all interrupts */	}    }#endif  /*     * Acknowledge interrupts (toggle the interrupt bits)   */  tmp = sscape_read (devc, GA_INTENA_REG);  sscape_write (devc, GA_INTENA_REG, (~bits & 0x0e) | (tmp & 0xf1));}static voidsscape_enable_intr (struct sscape_info *devc, unsigned intr_bits){  unsigned char   temp, orig;  temp = orig = sscape_read (devc, GA_INTENA_REG);  temp |= intr_bits;  temp |= 0x80;			/* Master IRQ enable */  if (temp == orig)    return;			/* No change */  sscape_write (devc, GA_INTENA_REG, temp);}static voidsscape_disable_intr (struct sscape_info *devc, unsigned intr_bits){  unsigned char   temp, orig;  temp = orig = sscape_read (devc, GA_INTENA_REG);  temp &= ~intr_bits;  if ((temp & ~0x80) == 0x00)    temp = 0x00;		/* Master IRQ disable */  if (temp == orig)    return;			/* No change */  sscape_write (devc, GA_INTENA_REG, temp);}static voiddo_dma (struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode){  unsigned char   temp;  if (dma_chan != SSCAPE_DMA_A)    {      printk ("SSCAPE: Tried to use DMA channel  != A. Why?\n");      return;    }  DMAbuf_start_dma (devc->my_audiodev,		    buf,		    blk_size, mode);  temp = devc->dma << 4;	/* Setup DMA channel select bits */  if (devc->dma <= 3)    temp |= 0x80;		/* 8 bit DMA channel */  temp |= 1;			/* Trigger DMA */  sscape_write (devc, GA_DMAA_REG, temp);  temp &= 0xfe;			/* Clear DMA trigger */  sscape_write (devc, GA_DMAA_REG, temp);}static intverify_mpu (struct sscape_info *devc){  /*     * The SoundScape board could be in three modes (MPU, 8250 and host).     * If the card is not in the MPU mode, enabling the MPU driver will     * cause infinite loop (the driver believes that there is always some     * received data in the buffer.     *     * Detect this by looking if there are more than 10 received MIDI bytes     * (0x00) in the buffer.   */  int             i;  for (i = 0; i < 10; i++)    {      if (INB (devc->base + HOST_CTRL) & 0x80)	return 1;      if (INB (devc->base) != 0x00)	return 1;    }  printk ("SoundScape: The device is not in the MPU-401 mode\n");  return 0;}static intsscape_coproc_open (void *dev_info, int sub_device){  if (sub_device == COPR_MIDI)    {      set_mt32 (devc, 0);      if (!verify_mpu (devc))	return RET_ERROR (EIO);    }  return 0;}static voidsscape_coproc_close (void *dev_info, int sub_device){  struct sscape_info *devc = dev_info;  unsigned long   flags;  DISABLE_INTR (flags);  if (devc->dma_allocated)    {      sscape_write (devc, GA_DMAA_REG, 0x20);	/* DMA channel disabled */#ifndef EXCLUDE_NATIVE_PCM      DMAbuf_close_dma (devc->my_audiodev);#endif      devc->dma_allocated = 0;    }  RESET_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag);  RESTORE_INTR (flags);  return;}static voidsscape_coproc_reset (void *dev_info){}static intsscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, int flag){  unsigned long   flags;  unsigned char   temp;  int             done, timeout;  if (flag & CPF_FIRST)    {      /*         * First block. Have to allocate DMA and to reset the board         * before continuing.       */      DISABLE_INTR (flags);      if (devc->dma_allocated == 0)	{#ifndef EXCLUDE_NATIVE_PCM	  if (DMAbuf_open_dma (devc->my_audiodev) < 0)	    {	      RESTORE_INTR (flags);	      return 0;	    }#endif	  devc->dma_allocated = 1;	}      RESTORE_INTR (flags);      sscape_write (devc, GA_HMCTL_REG,		    (temp = sscape_read (devc, GA_HMCTL_REG)) & 0x3f);	/*Reset */      for (timeout = 10000; timeout > 0; timeout--)	sscape_read (devc, GA_HMCTL_REG);	/* Delay */      /* Take board out of reset */      sscape_write (devc, GA_HMCTL_REG,		    (temp = sscape_read (devc, GA_HMCTL_REG)) | 0x80);    }  /*     * Transfer one code block using DMA   */  memcpy (audio_devs[devc->my_audiodev]->dmap->raw_buf[0], block, size);  DISABLE_INTR (flags);/******** INTERRUPTS DISABLED NOW ********/  do_dma (devc, SSCAPE_DMA_A,	  audio_devs[devc->my_audiodev]->dmap->raw_buf_phys[0],	  size, DMA_MODE_WRITE);  /*   * Wait until transfer completes.   */  RESET_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag);  done = 0;  timeout = 100;  while (!done && timeout-- > 0)    {      int             resid;      DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1);      clear_dma_ff (devc->dma);      if ((resid = get_dma_residue (devc->dma)) == 0)	done = 1;    }  RESTORE_INTR (flags);  if (!done)    return 0;  if (flag & CPF_LAST)    {      /*         * Take the board out of reset       */      OUTB (0x00, PORT (HOST_CTRL));      OUTB (0x00, PORT (MIDI_CTRL));      temp = sscape_read (devc, GA_HMCTL_REG);      temp |= 0x40;      sscape_write (devc, GA_HMCTL_REG, temp);	/* Kickstart the board */      /*         * Wait until the ODB wakes up       */      DISABLE_INTR (flags);      done = 0;      timeout = 5 * HZ;      while (!done && timeout-- > 0)	{	  DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1);	  if (INB (PORT (HOST_DATA)) == 0xff)	/* OBP startup acknowledge */	    done = 1;	}      RESTORE_INTR (flags);      if (!done)	{	  printk ("SoundScape: The OBP didn't respond after code download\n");	  return 0;	}      DISABLE_INTR (flags);      done = 0;      timeout = 5 * HZ;      while (!done && timeout-- > 0)	{	  DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1);	  if (INB (PORT (HOST_DATA)) == 0xfe)	/* Host startup acknowledge */	    done = 1;	}      RESTORE_INTR (flags);      if (!done)	{	  printk ("SoundScape: OBP Initialization failed.\n");	  return 0;	}      printk ("SoundScape board of type %d initialized OK\n",	      get_board_type (devc));#ifdef SSCAPE_DEBUG3      /*         * Temporary debugging aid. Print contents of the registers after         * downloading the code.       */      {	int             i;	for (i = 0; i < 13; i++)	  printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i));

⌨️ 快捷键说明

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