📄 igs5050snd.c
字号:
/* igs5050Snd.c - IGST 5050 Sound Support Module *//* Copyright 2000 - 2003 Wind River Systems, Inc. *//*modification history--------------------01g,18jun03,jlb Updated to Tornado 2.201f,18oct01,jlb Obtain PCI memory base from BSP (SPR 69996)01e,19jul01,msr Added uglMemAccessCheck() call to test mem access.01d,14jun01,rfm Added BSP API support for MIPS3201c,18dec00,jlb Return ERROR when device already open01b,11sep00,jlb Use soundcard.h verses sound.h01a,14mar00,jlb written*//* DESCRIPTIONThis file provides the audio device driver for the IGS5050 graphics/audiodevice. This driver is specifically written for the IGS5050 demonstrationboard developed by IGS Technologies, Inc. It operates the audio processorin conjunction with the AC97 codec. *//* includes */#include "vxWorks.h"#include "errno.h"#include "fcntl.h"#include "intLib.h"#include "ioLib.h"#include "iosLib.h"#include "iv.h"#include "logLib.h"#include "lstLib.h"#include "semLib.h"#include "stdlib.h"#include "string.h"#include "taskLib.h"#include "selectLib.h"#include "cacheLib.h"#include "sysLib.h"#include "drv/pci/pciConfigLib.h"#include "ugl/audio/soundcard.h"#include "ugl/driver/audio/igsAudio.h"#include "ugl/driver/audio/ac97.h"#include "ugl/ugl.h"#define INT_VEC_GET(irq) (0x20 + irq)LOCAL int DrvNum;/* Forward declarations *//* Driver implementation functions */static int igsSndOpen (SND_DEV *pDev, char *fileName, int flags, int mode);static int igsSndClose (int devId);static int igsSndRead (int devId, char *buffer, int maxbytes);static int igsSndWrite (int devId, char *buffer, int nbytes);static int igsSndIoctl (int devId, int function, int arg);/* Interrupt handler */static void audioInterrupt (SND_DEV *pDev);/* Utility functions */int igsDspInit (SND_DEV *pDev);DSP_FD * igsDspOpen (SND_DEV *pDev);int igsMixerInit (SND_DEV *pDev);MIXER_FD * igsMixerOpen (SND_DEV *pDev);#ifdef USE_BSP_APIint igsAudioIsaRegBase;#endif/******************************************************************************* igsSndDevCreate - create the IGS audio driver device ** This routine creates the audio device for the IGS-5050. The inputs for* creation of the audio device are generic and is meant to cover all audio* driver situations. For this driver, all of the input parameters are not* used. The following parameters are used:**\is*\i <devName>* Provides the name of the device that is to be created. The name must* be in the format "/name", for example /sound.*\i <channel>* The channel that is to be used on the audio processor.*\ie** RETURNS: OK when device successfully created; otherwise ERROR** ERRNO: N/A** SEE ALSO: */STATUS igsSndDevCreate ( char *devName, /* name of device */ int channel, /* hardware channel to use */ int instance, /* instance of the board */ int intLevel, /* interrupt level (not used) */ int intVec, /* interrupt vector (not used - from PCI header) */ int dma8, /* DMA channel for 16 bit (not used) */ int dma16 /* DMA channel for 8 bit (not used( */ ) { SND_DEV *pDev; DEV_HDR * pHdr; char *pName; UINT32 val;#ifdef USE_BSP_API WINDML_DEVICE * pWindMLDev;#else int busno, devno, funcno; UINT32 baseAdrs; UINT8 intLine; int size;#endif /* if device is already present, do not create again */ pHdr = iosDevFind (devName, &pName); if ((pHdr != NULL) && (strcmp (devName, pHdr->name) == 0)) return (OK);#ifdef USE_BSP_API if ((pWindMLDev = sysWindMLDevGet(WINDML_AUDIO_DEVICE, 0, VENDOR_PCI_TVIA, DEVICE_ID_TVIA_5050_AUDIO)) == UGL_NULL) { return(ERROR); } val = WINDML_IO_ENABLE | WINDML_MEM_ENABLE; sysWindMLDevCtrl(pWindMLDev, WINDML_ACCESS_MODE_SET, &val);#else /* USE_BSP_API */ /* Locate the device on the PCI bus */ if (pciFindDevice (IGS_VENDOR_ID, IGS5000_DEVICE_ID, instance, &busno, &devno, &funcno) != OK) return (ERROR); /* Device found, obtain the base address and interrupt */ if (uglPCIAddressGet (busno, devno, funcno, PCI_CFG_BASE_ADDRESS_0, (char *)&baseAdrs, &size) != OK) return (ERROR); if (uglMemAccessCheck ("IGS-5050 Audio", (char *)baseAdrs, size) != UGL_STATUS_OK) return (ERROR); pciConfigInByte (busno, devno, funcno, PCI_CFG_DEV_INT_LINE, &intLine);#endif /* USE_BSP_API */ /* Get audio control structure */ pDev = (SND_DEV *)malloc (sizeof(SND_DEV)); bzero ((char *)pDev, sizeof(SND_DEV));#ifdef USE_BSP_API /* Get the PCI base address */ sysWindMLDevCtrl(pWindMLDev, WINDML_PCI_MEMBASE_GET, &val); pDev->pBaseIOAdrs = (UINT8 *)pWindMLDev->pPhysBaseAdrs0; pDev->devSem = semBCreate (SEM_Q_FIFO, SEM_FULL); pDev->intSem = semBCreate (SEM_Q_FIFO, SEM_FULL); pDev->mode = O_RDONLY; pDev->channel = channel; pDev->pWindMLDev = pWindMLDev; pDev->pciMembase = val; igsAudioIsaRegBase = (int)pWindMLDev->pRegBase; /* Enable Linear mode for PCI access */ igsOut(GR_INDEX, 0x33); if ((igsIn(GR_DATA) & 8) == 0) { val = igsIn(GR_DATA) | 8; igsOut(GR_DATA, val); }#else /* USE_BSP_API */ pDev->pBaseIOAdrs = (UINT8 *)baseAdrs; pDev->irq = intLine; pDev->devSem = semBCreate (SEM_Q_FIFO, SEM_FULL); pDev->intSem = semBCreate (SEM_Q_FIFO, SEM_FULL); pDev->mode = O_RDONLY; pDev->channel = channel; /* Enable Linear mode for PCI access */ igsOut(GR_INDEX, 0x33); if ((igsIn(GR_DATA) & 8) == 0) { val = igsIn(GR_DATA) | 8; igsOut(GR_DATA, val); }#endif /* USE_BSP_API */ /* Install the driver */ DrvNum = iosDrvInstall (NULL, NULL, igsSndOpen, igsSndClose, igsSndRead, igsSndWrite, igsSndIoctl); /* hook in select processing */ selWakeupListInit (&pDev->selList); /* Initialize the DSP */ igsDspInit (pDev); /* Initialize the mixer */ igsMixerInit (pDev); if (iosDevAdd (&pDev->devHdr, devName, DrvNum) == ERROR) { free ((char *)pDev); return(ERROR); } /* Disable interrupts */ sndIgsAddrEngIntDisable (pDev->pBaseIOAdrs); sndIgsAudioOut32 (pDev->pBaseIOAdrs, AUDSTOP, 0xffffffff); sndIgsAudioOut32 (pDev->pBaseIOAdrs, AINTEN, 0); sndIgsAudioOut32 (pDev->pBaseIOAdrs, AINT0, 0xffffffff);#ifdef USE_BSP_API sysWindMLIntConnect(pWindMLDev, audioInterrupt, (int)pDev); sysWindMLIntEnable(pDev->pWindMLDev);#else /* USE_BSP_API */ /* Attach interrupt handler and enable interrupts */ intConnect (INUM_TO_IVEC (INT_VEC_GET (pDev->irq)), audioInterrupt, (int)pDev); sysIntEnablePIC (pDev->irq);#endif /* USE_BSP_API */ return(OK); }/******************************************************************************* igsSndOpen - open an IGS audio device ** This routine opens an audio device for the IGS-5050. The following* audio devices may be opened /xxxx/dsp and /xxxx/mixer.** RETURNS: device control structure when successfully opened; otherwise* ERROR** ERRNO: N/A** SEE ALSO: */static int igsSndOpen ( SND_DEV *pDev, /* device control structure */ char *fileName, /* sub-device to open */ int flags, /* open flags */ int mode /* open mode */ ) { SND_FD *pSnd = (SND_FD *)ERROR; /* wait for device to become available */ if (semTake (pDev->devSem, 30 * sysClkRateGet())) errno = S_ioLib_DEVICE_ERROR; else { if (strcmp (fileName, "/dsp") == 0) { /* open the DSP */ DSP_FD *pDsp; pDsp = igsDspOpen (pDev); if (pDsp != (DSP_FD *)ERROR) { pDev->pDsp = pDsp; pSnd = (SND_FD *)pDsp; } } else if(strcmp (fileName, "/mixer") == 0) { /* open the mixer */ MIXER_FD *pMixer; pMixer = igsMixerOpen (pDev); if (pMixer != (MIXER_FD *)ERROR) { pDev->pMixer = pMixer; pSnd = (SND_FD *)pMixer; } } else errno = ENODEV; } semGive (pDev->devSem); return ((int)pSnd); }/******************************************************************************* igsSndClose - close an IGS audio device ** This routine closes an audio device for the IGS-5050.** RETURNS: OK when device closed; otherwise ERROR** ERRNO: N/A** SEE ALSO: */static int igsSndClose ( int devId /* device control structure */ ) { SND_FD *pSnd = (SND_FD *)devId; return(pSnd->fdClose (devId)); }/******************************************************************************* igsSndRead - read from an IGS audio device ** This routine reads from the audio device for the IGS-5050.** RETURNS: number of bytes read** ERRNO: N/A** SEE ALSO: */static int igsSndRead ( int devId, /* device control structure */ char *buffer, /* location to store read data */ int maxbytes /* number of bytes to read */ ) { SND_FD *pSnd = (SND_FD *)devId; if (pSnd->fdRead == NULL) { errno = S_ioLib_UNKNOWN_REQUEST; return(ERROR); } else return(pSnd->fdRead (devId, buffer, maxbytes)); }/******************************************************************************* igsSndWrite - write to an IGS audio device ** This routine writes to the audio device for the IGS-5050.** RETURNS: Number of bytes written** ERRNO: N/A** SEE ALSO: */static int igsSndWrite ( int devId, /* device control structure */ char *buffer, /* location of data buffer */ int nbytes /* number of bytes to output */ ) { SND_FD *pSnd = (SND_FD *)devId; if (pSnd->fdWrite == NULL) { errno = S_ioLib_UNKNOWN_REQUEST; return(ERROR); } else return(pSnd->fdWrite (devId, buffer, nbytes)); }/******************************************************************************* igsSndIoctl - handle IOCTL for an IGS audio device ** This routine handles ioctls to the audio device for the IGS-5050.** RETURNS: OK when operation was successful; otherwise ERROR** ERRNO: N/A** SEE ALSO: */static int igsSndIoctl ( int devId, /* device control structure */ int function, /* function to perform */ int arg /* function argument */ ) { SND_FD *pSnd = (SND_FD *)devId; if (pSnd->fdIoctl == NULL) { errno = S_ioLib_UNKNOWN_REQUEST; return(ERROR); } else return(pSnd->fdIoctl (devId, function, arg)); }/******************************************************************************* audioInterrupt - audio interrupt handler ** This routine processes audio interrupts for the IGS-5050.** RETURNS: N/A** ERRNO: N/A** SEE ALSO: */static void audioInterrupt ( SND_DEV *pDev /* device control structure */ ) { UINT8 GRIndex; UINT8 GRData; UINT32 aint0; UINT32 misint0; UINT32 cspf; DSP_FD *pDsp = (DSP_FD *)pDev->pDsp; /* Save the current GR index */ GRIndex = igsIn(GR_INDEX); /* Get interrupt status */ igsOut(GR_INDEX, 0x1A); GRData = igsIn(GR_DATA); igsOut(GR_INDEX, GRIndex); /* Is it audio specific interrupt? */ if (!(GRData & 0x04)) return; /* yes, get the address interrupt status */ aint0 = sndIgsAudioIn32 (pDev->pBaseIOAdrs, AINT0); /* get the miscellaneous interrupt & status and mask out the * interrupt status bits */ misint0 = sndIgsAudioIn32 (pDev->pBaseIOAdrs, MISCINT0); misint0 &= 0x010000FF; /* any interrupt pending? */ if (misint0 == 0) return; /* if address engine interrupt, then get current sample position */ if (misint0 & ADDRESS_IRQ) { cspf = sndIgsAudioIn32 (pDev->pBaseIOAdrs, CSPF); } else { logMsg ("IGS interrupt ???? \n",0,0,0,0,0,0); return; } /* identify buffer that was emptied and signal writer */ if (cspf & aint0) { pDsp->buf1Empty = TRUE; } else { pDsp->buf2Empty = TRUE; } /* Wakeup any pending task */ semGive (pDev->intSem); selWakeupAll (&pDev->selList, SELWRITE); /* If no buffer available, turn off output */ if ((pDsp->buf1Empty) && (pDsp->buf2Empty)) { pDev->mode &= ~DSP_PLAY; sndIgsAddrEngIntDisable (pDev->pBaseIOAdrs); sndIgsAudioOut32 (pDev->pBaseIOAdrs, AUDSTOP, aint0); sndIgsAudioOut32 (pDev->pBaseIOAdrs, AINTEN, ~aint0); sndIgsAudioOut32 (pDev->pBaseIOAdrs, AINT0, aint0); } else /* Reset interrupt */ sndIgsAudioOut32 (pDev->pBaseIOAdrs, AINT0, aint0); /* Increment interrupt counter */ pDev->intCount++; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -