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

📄 sb16drv.c

📁 IXP425的BSP代码
💻 C
📖 第 1 页 / 共 2 页
字号:
}static int dspIoctl (int devId, int function, int arg){  DSP_FD *pDsp = (DSP_FD *)devId;  SND_DEV *pDev = pDsp->dev.pDev;  union arg_union  {    int i;    long l;    int *pInt;    long *pLong;    snd_info_t *pInfo;  } u_arg;    u_arg.i = arg;  switch (function)  {    case SNDCTL_DSP_SYNC:      while (pDev->taskBusy) taskDelay (1);      return OK;    case SNDCTL_DSP_GETBLKSIZE:      *u_arg.pInt = MAX_DMA_SIZE;      return OK;    case SNDCTL_DSP_SPEED:      {	int i = *u_arg.pLong;	if (i < RATE_MIN) i = RATE_MIN;	if (i > RATE_MAX) i = RATE_MAX;	while (pDev->taskBusy) taskDelay (1);	pDsp->info.rate = i;	return OK;      }    case SNDCTL_DSP_STEREO:      while (pDev->taskBusy) taskDelay (1);      pDsp->info.stereo = *u_arg.pInt;      return OK;    case SNDCTL_DSP_SAMPLESIZE:      if (*u_arg.pInt == 8 || *u_arg.pInt == 16)      {	while (pDev->taskBusy) taskDelay (1);	pDsp->info.sampleSize = *u_arg.pInt;	return OK;      }      break;    case SNDCTL_DSP_SETFORMAT:      pDsp->info.uLaw = *u_arg.pInt;      return OK;      break;    case SNDCTL_GET_INFO:      *u_arg.pInfo = pDsp->info;      return OK;    case SNDCTL_SET_INFO:      while (pDev->taskBusy) taskDelay (1);      pDsp->info = *u_arg.pInfo;      return OK;  }  errno = S_ioLib_UNKNOWN_REQUEST;  return ERROR;}/* Mixer device methods. */static int mixerClose (int devId){  MIXER_FD *pMixer = (MIXER_FD *)devId;  SND_DEV *pDev = pMixer->dev.pDev;  if (semTake (pDev->devSem, 30 * sysClkRateGet()))  {    errno = S_ioLib_DEVICE_ERROR;    return ERROR;  }  pDev->pMixer = NULL;  free (pMixer);  semGive (pDev->devSem);  return OK;}static int mixerRead (int devId, char *buffer, int maxbytes){  errno = S_ioLib_DEVICE_ERROR;  return ERROR;}static int mixerWrite (int devId, char *buffer, int nbytes){  errno = S_ioLib_DEVICE_ERROR;  return ERROR;}static int mixerIoctl (int devId, int function, int arg){  MIXER_FD *pMixer = (MIXER_FD *)devId;  union arg_union  {    int i;    long l;    int *pInt;    long *pLong;    snd_info_t *pInfo;  } u_arg;    u_arg.i = arg;  switch (function)  {    case SNDCTL_SET_VOLUME:      {	int volume = *u_arg.pLong;	mixer_set_level (pMixer->dev.pDev, "master", volume);	return OK;      }    case SNDCTL_GET_VOLUME:      {	*u_arg.pLong = mixer_get_level (pMixer->dev.pDev, "master");	return OK;      }  }  errno = S_ioLib_UNKNOWN_REQUEST;  return ERROR;}static void processOutput (SND_DEV *pDev, DMA_MSG mDma){  int dmaChannel = IS_16BITS(pDev->pDsp) ? pDev->dma16 : pDev->dma8;  if (pDev->pDsp->dmaDirection != O_WRONLY ||      pDev->pDsp->dmaChannel   != dmaChannel)  {    pDev->dmaAuto = 0;    pDev->pDsp->dmaDirection = mDma.direction;    pDev->pDsp->dmaChannel   = dmaChannel;  }  if (pDev->dmaAuto)  {    if (mDma.length != MAX_DMA_SIZE)    {      /* If this was the interrupt from the middle of the block,       * then wait around for the next one.       */      if (pDev->dmaAuto)      {	pDev->dmaAuto = 0;	if (semTake (pDev->intSem, 5 * sysClkRateGet()))	  logMsg ("SB16: Interrupt timeout\n", 0, 0, 0, 0, 0, 0);	freeDmaBuffer (pDev);      }      /* We are done with auto init mode.       */      dsp_command (pDev, IS_16BITS(pDev->pDsp) ?		   SB_DSP_DMA16_EXIT : SB_DSP_DMA8_EXIT);      /* Setup a one-shot.       */      dmaSetup (DMA_MODE_SINGLE | DMA_MODE_WRITE,		mDma.buffer, mDma.length, dmaChannel);      /* Send out this block.       */      dsp_output (pDev->pDsp, mDma.length);    }  }  else  {    dsp_command (pDev, SB_DSP_DMA8_OFF);    dsp_command (pDev, SB_DSP_DMA16_OFF);    if (mDma.buffer == snd_dmaBuffer && mDma.length == MAX_DMA_SIZE)    {      pDev->dmaAuto = 2;      dmaSetup (DMA_MODE_SINGLE | DMA_MODE_WRITE | DMA_MODE_AUTO_ENABLE,		snd_dmaBuffer, MAX_DMA_MSGS * MAX_DMA_SIZE, dmaChannel);      /* Check for the next buffer available when half the buffer       * has been transferred.       */      mDma.length >>= 1;    }    else    {      dmaSetup (DMA_MODE_SINGLE | DMA_MODE_WRITE,		mDma.buffer, mDma.length, dmaChannel);    }    /* Send out this block.     */    dsp_output (pDev->pDsp, mDma.length);  }}/* Interrupt handler and Helper task */static void dspInterrupt (SND_DEV *pDev){  int status;  sysOutByte (SBP(pDev, MIXER_ADDR), SB_MIXER_IRQ_STAT);  status = sysInByte (SBP(pDev, MIXER_DATA));  /* 8bit DMA interrupt   */  if (status & 1)  {    dsp_ack_8bit (pDev);    semGive (pDev->intSem);  }  /* 16bit DMA interrupt   */  if (status & 2)  {    dsp_ack_16bit (pDev);    semGive (pDev->intSem);  }}static int dspHelperTask (SND_DEV *pDev){  DMA_MSG mDma;  while (1)  {    pDev->taskBusy = pDev->dmaAuto = 0;    dsp_command (pDev, SB_DSP_SPEAKER_OFF);    dsp_command (pDev, SB_DSP_DMA8_OFF);    dsp_command (pDev, SB_DSP_DMA16_OFF);    if (msgQReceive (pDev->dmaQ, (char *)&mDma,		     sizeof (mDma), WAIT_FOREVER) != sizeof (mDma))      return 0;    pDev->taskBusy = 1;    dsp_command (pDev, SB_DSP_SPEAKER_ON);    do    {      switch (mDma.direction)      {	case O_WRONLY:	  processOutput (pDev, mDma);	  break;	case O_RDONLY:	  break;      }      /* wait for a DMA interrupt       */      if (semTake (pDev->intSem, 5 * sysClkRateGet()))	logMsg ("SB16: Interrupt timeout\n", 0, 0, 0, 0, 0, 0);      if (pDev->dmaAuto)      {	/* We can do this, because we know the stream will be	 * non-contiguous if any properties change (rate, direction, etc).	 */	while (pDev->dmaAuto)	{	  pDev->dmaAuto--;	  if (pDev->dmaAuto)	  {	    if (msgQReceive (pDev->dmaQ, (char *)&mDma,			     sizeof (mDma), NO_WAIT) != sizeof (mDma))	    {	      pDev->dmaAuto = 0;	    }	  }	  else	  {	    /* Great, we can keep going with 2 more interrupts to follow.	     */	    pDev->dmaAuto = 2;	    freeDmaBuffer (pDev);	  }	  /* wait for the next DMA interrupt	   */	  if (semTake (pDev->intSem, 5 * sysClkRateGet()))	    logMsg ("SB16: Interrupt timeout\n", 0, 0, 0, 0, 0, 0);	}	/* We can't do any more DMA continuously.	 */	dsp_command (pDev, IS_16BITS(pDev->pDsp) ?		     SB_DSP_DMA16_EXIT : SB_DSP_DMA8_EXIT);      }      freeDmaBuffer (pDev);    } while (msgQReceive (pDev->dmaQ, (char *)&mDma,			  sizeof (mDma), NO_WAIT) == sizeof (mDma));  }}/* DMA buffer management routines *//* DMA buffers are never grabbed by the interrupt routine */static int createDmaBuffer (void){/*   snd_dmaBuffer = sysDmaMalloc (MAX_DMA_MSGS * MAX_DMA_SIZE); */  bzero (snd_dmaBuffer, MAX_DMA_MSGS * MAX_DMA_SIZE);  return snd_dmaBuffer ? OK : ERROR;}static char *getDmaBuffer (SND_DEV *pDev){  char *dmaBuffer;  semTake (pDev->bufSem, WAIT_FOREVER);  semTake (pDev->devSem, WAIT_FOREVER);  dmaBuffer = snd_dmaBuffer + pDev->dmaIndex * MAX_DMA_SIZE;  pDev->dmaIndex = (pDev->dmaIndex + 1) % MAX_DMA_MSGS;  semGive (pDev->devSem);  return dmaBuffer;}/* DMA buffers are always freed by the interrupt routine */static void freeDmaBuffer (SND_DEV *pDev){  semGive (pDev->bufSem);}/* Low level register access routines. */static int dsp_init (SND_DEV *pDev){  int version;  /* Initialization the DSP   */  if (dsp_reset (pDev) < 0)  {    logMsg ("SB16: [0x%x] reset failed... 0x%x\n",	    pDev->port, sysInByte (SBP(pDev, READ)), 0, 0, 0, 0);    return -ENODEV;  }  /* Get the version number of the DSP   */  if ((version = dsp_version (pDev)) < 0)  {    logMsg ("SB16: [0x%x] get version failed... 0x%x\n",	    pDev->port, sysInByte (SBP(pDev, READ)), 0, 0, 0, 0);    return -ENODEV;  }  pDev->version = version;  switch (pDev->version >> 8)  {    case 1: case 2: case 3:      logMsg ("SB16: [0x%x] DSP chip version %i.%i is not supported"	      " with the SB16 code\n", pDev->port, pDev->version >> 8,	      pDev->version & 0xff, 0, 0, 0);      return -ENODEV;    case 4:      break;    default:      logMsg ("SB16: [0x%x] unknown DSP chip version %i.%i\n",	      pDev->port, pDev->version >> 8, pDev->version & 0xff, 0, 0, 0);      return -ENODEV;  }  dsp_command (pDev, SB_DSP_SPEAKER_OFF);  opl3_init (pDev);  return 0;}static int dsp_version (SND_DEV *pDev){  int i;  unsigned int result = -1;  sysIntDisablePIC (pDev->irq);  dsp_command (pDev, SB_DSP_GET_VERSION);  for (i = 100000; i; i--)    if (sysInByte (SBP(pDev, DATA_AVAIL)) & 0x80)    {      result = (short) sysInByte (SBP(pDev, READ)) << 8;      break;    }  for (i = 100000; i; i--)    if (sysInByte (SBP(pDev, DATA_AVAIL)) & 0x80)    {      result |= (short) sysInByte (SBP(pDev, READ));      break;    }  sysIntEnablePIC (pDev->irq);  return result;}static int dsp_reset (SND_DEV *pDev){  int i;  sysIntDisablePIC (pDev->irq);  sysOutByte (SBP(pDev, RESET), 1);  sysDelay ();  sysOutByte (SBP(pDev, RESET), 0);  sysDelay ();  for (i = 0; i < 1000 && !(sysInByte (SBP(pDev, DATA_AVAIL)) & 0x80); i++);  i = sysInByte (SBP(pDev, READ));  sysIntEnablePIC (pDev->irq);  if (i == 0xaa) return 0;  return -ENODEV;}/* OPL3 functions... */static int opl3_init (SND_DEV *pDev){  int i;  /* Reset opl3 timers 1 and 2   */  opl3_command (SBP(pDev, OPL3_LEFT), TIMER_CONTROL_REGISTER,		TIMER1_MASK | TIMER2_MASK);  /* Reset the IRQ of the FM chip   */  opl3_command (SBP(pDev, OPL3_LEFT), TIMER_CONTROL_REGISTER, IRQ_RESET);  i = sysInByte (SBP(pDev, OPL3_LEFT));  if (i == 0x00 || i == 0x0f)  {    opl3_command (SBP(pDev, OPL3_RIGHT), OPL3_MODE_REGISTER, 0x00);    opl3_command (SBP(pDev, OPL3_RIGHT), OPL3_MODE_REGISTER, OPL3_ENABLE);    opl3_command (SBP(pDev, OPL3_RIGHT), CONNECTION_SELECT_REGISTER, 0x00);    for (i=0; i<9; i++)      opl3_command (SBP(pDev, OPL3_LEFT), KEYON_BLOCK, 0);    opl3_command (SBP(pDev, OPL3_LEFT), TEST_REGISTER, ENABLE_WAVE_SELECT);    opl3_command (SBP(pDev, OPL3_LEFT), PERCUSSION_REGISTER, 0x00);    opl3_command (SBP(pDev, OPL3_RIGHT), OPL3_MODE_REGISTER, 0x00);  }  else    logMsg ("SB16: [0x%x] OPL3 detect failed... 0x%x\n",	    pDev->port, i, 0, 0, 0, 0);  return 0;}/* Mixer stuff.  Really belongs in it's own device.... */static int mixer_init (SND_DEV *pDev){  int irq;  int mpu;  switch (pDev->irq)  {    case 2: case 9: irq = 0x01; break;    case 5:         irq = 0x02; break;    case 7:         irq = 0x04; break;    case 10:        irq = 0x08; break;    default:        irq = 0x00;  }  mixer_write (pDev, 0x0, 0x0); /* reset mixer */  sysDelay ();  mpu = mixer_read (pDev, SB_MIXER_MPU_NR) & ~0x06;  mixer_write (pDev, SB_MIXER_IRQ_NR, irq);  mixer_write (pDev, SB_MIXER_DMA_NR, (1 << pDev->dma16) | (1 << pDev->dma8));  mixer_write (pDev, SB_MIXER_MPU_NR, mpu & 0x02); /* disable mpu */  /* Turn on all inputs.   */  mixer_write (pDev, SB_MIXER_OUTPUT_SW, 0x1f);  /* Set volumes to reasonable values for now...   */  mixer_set_level (pDev, "master", 90 << 8 | 90);  mixer_set_level (pDev, "pcm", 90 << 8 | 90);  mixer_set_level (pDev, "speaker", 0);  mixer_set_level (pDev, "ogain", 0);  mixer_set_level (pDev, "igain", 0);  mixer_set_level (pDev, "treble", 50);  mixer_set_level (pDev, "bass",   50);  return 0;}/**$Log: sb16drv.c,v $Revision 1.5  1999/12/18 00:01:38  stevehCorrected loop bug for audio on small buffers.Connected up fwd,back and stop buttons.Attempted to connect up logic to display link that mouse is over,but api seems to not work for this.Revision 1.4  1999/12/03 06:52:09  stevehCreated new IOCTL to set 8-bit uLaw format in SB driver.Moved uLaw code from java to driver.*/

⌨️ 快捷键说明

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