📄 sb16drv.c
字号:
/* sb16drv.c - Sound Blaster 16 driver implemented for Cyrix MediaGXi CPU *//* $Revision: 1.5 $ *//* Copyright 1999-2001 Wind River Systems, Inc. *//*modification history--------------------01d,21sep01,dat Fix ANSI violations for diab compiler01c,27jan00,dmh Corrected loop bug for audio on small buffers01b,27oct99,spm Sounds clean now, but record is still not implemented.01a,03oct99,spm created. 8 bit sound is still not working right.*/#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 "msgQLib.h"#include "semLib.h"#include "stdlib.h"#include "string.h"#include "taskLib.h"#include "drv/sound/sb16drv.h"/* System function not in any include file. *//* extern char *sysDmaMalloc (int); */char snd_dmaBuffer[MAX_DMA_MSGS * MAX_DMA_SIZE];LOCAL int DrvNum;static const MIXER_INFO mixerTable[] ={ {"master", SB_MIXER_MASTER_DEV, 31, 3, 0}, {"pcm", SB_MIXER_PCM_DEV, 31, 3, 0}, {"synth", SB_MIXER_SYNTH_DEV, 31, 3, 0}, {"cd", SB_MIXER_CD_DEV, 31, 3, 0}, {"line", SB_MIXER_LINE_DEV, 31, 3, 0}, {"mic", SB_MIXER_MIC_DEV, 31, 3, 0}, {"speaker", SB_MIXER_SPEAKER_DEV, 3, 6, 1}, {"igain", SB_MIXER_OGAIN_DEV, 3, 6, 1}, {"ogain", SB_MIXER_IGAIN_DEV, 3, 6, 1}, {"treble", SB_MIXER_TREBLE_DEV, 7, 4, 1}, {"bass", SB_MIXER_BASS_DEV, 7, 4, 1}, {NULL, 0, 0, 0, 0}};/** uLaw to PCM table Used only for uLaw 8 bit.*/char ulaw_dsp[] = { 3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 121, 122, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 124, 125, 125, 125, 125, 125, 125, 126, 126, 126, 126, 126, 126, 126, 126, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 253, 249, 245, 241, 237, 233, 229, 225, 221, 217, 213, 209, 205, 201, 197, 193, 190, 188, 186, 184, 182, 180, 178, 176, 174, 172, 170, 168, 166, 164, 162, 160, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 143, 142, 142, 141, 141, 140, 140, 139, 139, 138, 138, 137, 137, 136, 136, 135, 135, 135, 134, 134, 134, 134, 133, 133, 133, 133, 132, 132, 132, 132, 131, 131, 131, 131, 131, 131, 130, 130, 130, 130, 130, 130, 130, 130, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,};/* Useful macros. */#define IS_16BITS(x) ((x)->info.sampleSize == 16)/* Device Methods... */static int sndCreate (SND_DEV *pDev, char *fileName, int mode);static int sndOpen (SND_DEV *pDev, char *fileName, int flags, int mode);static int sndClose (int devId);static int sndRead (int devId, char *buffer, int maxbytes);static int sndWrite (int devId, char *buffer, int nbytes);static int sndIoctl (int devId, int function, int arg);static int dspClose (int devId);static int dspRead (int devId, char *buffer, int maxbytes);static int dspWrite (int devId, char *buffer, int nbytes);static int dspIoctl (int devId, int function, int arg);static int mixerClose (int devId);static int mixerRead (int devId, char *buffer, int maxbytes);static int mixerWrite (int devId, char *buffer, int nbytes);static int mixerIoctl (int devId, int function, int arg);/* Interrupt handler and Helper task */static void dspInterrupt (SND_DEV *pDev);static int dspHelperTask (SND_DEV *pDev);/* DMA buffer management routines */static int createDmaBuffer (void);static char *getDmaBuffer (SND_DEV *pDev);static void freeDmaBuffer (SND_DEV *pDev);/* Low level register access routines. */static int dsp_init (SND_DEV *pDev);static int dsp_version (SND_DEV *pDev);static int dsp_reset (SND_DEV *pDev);/* OPL3 functions... */static int opl3_init (SND_DEV *pDev);/* Mixer functions... */static int mixer_init (SND_DEV *pDev);/* Inlined small functions */static __inline__ int dsp_command (SND_DEV *pDev, unsigned char val){ int i; for (i = 10000; i; i--) if ((sysInByte (SBP(pDev, STATUS)) & 0x80) == 0) { sysOutByte (SBP(pDev, COMMAND), val); return 1; } return 0;}static __inline__ int opl3_command (unsigned short port, unsigned char reg, unsigned char val){ sysOutByte (port, reg); sysInByte (port); sysInByte (port); sysOutByte (port + 1, val); sysInByte (port + 1); sysInByte (port + 1); return 1;}static __inline__ int dsp_ack_8bit (SND_DEV * pDev){ return sysInByte (SBP(pDev, DATA_AVAIL));}static __inline__ int dsp_ack_16bit (SND_DEV * pDev){ return sysInByte (SBP(pDev, DATA_AVAIL_16));}static __inline__ void mixer_write (SND_DEV *pDev, unsigned char reg, unsigned char data){ sysOutByte (SBP(pDev, MIXER_ADDR), reg); sysOutByte (SBP(pDev, MIXER_DATA), data);}static __inline__ unsigned char mixer_read (SND_DEV *pDev, unsigned char reg){ unsigned char result; sysOutByte (SBP(pDev, MIXER_ADDR), reg); result = sysInByte (SBP(pDev, MIXER_DATA)); return result;}static __inline__ void mixer_set_level (SND_DEV * pDev, char *name, int value){ const MIXER_INFO *info; int lvalue = value%256; int rvalue = value/256; for (info=mixerTable; info->name && strcmp (info->name, name); info++); if (info->name) { if (lvalue > 100) lvalue = 100; else if (lvalue<0) lvalue = 0; lvalue = (lvalue * info->max_value / 100) << info->shift; if (rvalue > 100) rvalue = 100; else if (rvalue<0) rvalue = 0; rvalue = (rvalue * info->max_value / 100) << info->shift; mixer_write (pDev, info->reg, lvalue); mixer_write (pDev, info->reg + 1, rvalue); }}static __inline__ int mixer_get_level (SND_DEV * pDev, char *name){ const MIXER_INFO *info; for (info=mixerTable; info->name && strcmp (info->name, name); info++); if (info->name) { int lvalue = mixer_read (pDev, info->reg) >> info->shift; int rvalue = mixer_read (pDev, info->reg + 1) >> info->shift; lvalue = lvalue * 100 / info->max_value; rvalue = rvalue * 100 / info->max_value; return rvalue << 8 | lvalue; } return 0;}/* Routine to initiate Sound blaster DMAs. */static void dsp_output (DSP_FD *pDsp, int length){ SND_DEV *pDev = pDsp->dev.pDev; unsigned long count; unsigned char format; /* setup the sample rate. */ dsp_command (pDev, SB_DSP_SAMPLE_RATE_IN); dsp_command (pDev, pDsp->info.rate >> 8); dsp_command (pDev, pDsp->info.rate & 0xff); dsp_command (pDev, SB_DSP_SAMPLE_RATE_OUT); dsp_command (pDev, pDsp->info.rate >> 8); dsp_command (pDev, pDsp->info.rate & 0xff); /* Determine the proper format of the output. */ if (IS_16BITS(pDsp)) format = pDsp->info.stereo ? SB_DSP4_MODE_SIGN_STEREO : SB_DSP4_MODE_SIGN_MONO; else format = pDsp->info.stereo ? SB_DSP4_MODE_UNS_STEREO : SB_DSP4_MODE_UNS_MONO; /* Tell the sound hardware how many samples. */ count = (IS_16BITS(pDsp) ? (length >> 1) : length) - 1; dsp_command (pDev, IS_16BITS(pDsp) ? SB_DSP4_OUT16_AI : SB_DSP4_OUT8_AI); dsp_command (pDev, format); dsp_command (pDev, count & 0xff); dsp_command (pDev, count >> 8); dsp_command (pDev, IS_16BITS(pDev->pDsp) ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON);}/* Device creation routines... */STATUS sb16Drv (void){ if (DrvNum > 0) return OK; DrvNum = iosDrvInstall (sndCreate, NULL, sndOpen, sndClose, sndRead, sndWrite, sndIoctl); return (DrvNum == ERROR) ? ERROR : OK;}STATUS sb16DevCreate (char *devName, int port, int irq, int dma8, int dma16){ SND_DEV *pDev; if (DrvNum < 1) { errno = S_ioLib_NO_DRIVER; return ERROR; } pDev = (SND_DEV *)malloc (sizeof(SND_DEV)); if (!pDev) return ERROR; bzero ((char *)pDev, sizeof(SND_DEV)); pDev->port = port; pDev->irq = irq; pDev->dma8 = dma8; pDev->dma16 = dma16; pDev->devSem = semBCreate (SEM_Q_FIFO, SEM_FULL); pDev->intSem = semCCreate (SEM_Q_FIFO, 0); pDev->bufSem = semCCreate (SEM_Q_FIFO, MAX_DMA_MSGS); pDev->dmaQ = msgQCreate (MAX_DMA_MSGS, sizeof (DMA_MSG), MSG_Q_FIFO); pDev->dmaIndex = 0; if (createDmaBuffer () < 0) { free (pDev); return ERROR; } if (dsp_init (pDev) < 0) { free (pDev); return ERROR; } /* This belongs in the mixer device... */ if (mixer_init (pDev) < 0) { free (pDev); return ERROR; } if (iosDevAdd (&pDev->devHdr, devName, DrvNum) == ERROR) { free ((char *)pDev); return ERROR; } pDev->tid = taskSpawn ("tSndTask", TASK_PRIORITY, TASK_OPTIONS, TASK_STACK_SIZE, dspHelperTask, (int)pDev, 0, 0, 0, 0, 0, 0, 0, 0, 0); if (pDev->tid == ERROR) { free (pDev); return ERROR; } intConnect (INUM_TO_IVEC (INT_VEC_GET (irq)), dspInterrupt, (int)pDev); return OK;}/* Device methods... */static int sndCreate (SND_DEV *pDev, char *fileName, int mode){ return ERROR;}static int sndOpen (SND_DEV *pDev, char *fileName, int flags, int mode){ SND_FD *pSnd = NULL; if (semTake (pDev->devSem, 30 * sysClkRateGet())) { errno = S_ioLib_DEVICE_ERROR; return ERROR; } if (strcmp (fileName, "/dsp") == 0) { DSP_FD *pDsp; if (pDev->pDsp) { errno = EBUSY; goto error; } if (! (pDsp = malloc (sizeof(DSP_FD)))) { errno = ENOMEM; goto error; } pDsp->dev.pDev = pDev; pDsp->dev.fdClose = dspClose; pDsp->dev.fdRead = dspRead; pDsp->dev.fdWrite = dspWrite; pDsp->dev.fdIoctl = dspIoctl; pDsp->info.rate = RATE_MAX; pDsp->info.stereo = 1; pDsp->info.sampleSize = 16; pDsp->info.uLaw = 0; /* PCM format is default */ pDev->pDsp = pDsp; pSnd = (SND_FD *)pDsp; } else if (strcmp (fileName, "/mixer") == 0) { MIXER_FD *pMixer; if (pDev->pMixer) { errno = EBUSY; goto error; } if (! (pMixer = malloc (sizeof(MIXER_FD)))) { errno = ENOMEM; goto error; } pMixer->dev.pDev = pDev; pMixer->dev.fdClose = mixerClose; pMixer->dev.fdRead = mixerRead; pMixer->dev.fdWrite = mixerWrite; pMixer->dev.fdIoctl = mixerIoctl; pDev->pMixer = pMixer; pSnd = (SND_FD *)pMixer; } else { errno = ENODEV; goto error; }error: semGive (pDev->devSem); return pSnd ? (int)pSnd : ERROR;}static int sndClose (int devId){ SND_FD *pSnd = (SND_FD *)devId; return pSnd->fdClose (devId);}static int sndRead (int devId, char *buffer, int maxbytes){ SND_FD *pSnd = (SND_FD *)devId; return pSnd->fdRead (devId, buffer, maxbytes);}static int sndWrite (int devId, char *buffer, int nbytes){ SND_FD *pSnd = (SND_FD *)devId; return pSnd->fdWrite (devId, buffer, nbytes);}static int sndIoctl (int devId, int function, int arg){ SND_FD *pSnd = (SND_FD *)devId; return pSnd->fdIoctl (devId, function, arg);}/* DSP device methods. */static int dspClose (int devId){ DSP_FD *pDsp = (DSP_FD *)devId; SND_DEV *pDev = pDsp->dev.pDev; if (semTake (pDev->devSem, 30 * sysClkRateGet())) { errno = S_ioLib_DEVICE_ERROR; return ERROR; } while (pDev->taskBusy) taskDelay (1); pDev->pDsp = NULL; free (pDsp); semGive (pDev->devSem); return OK;}static int dspRead (int devId, char *buffer, int maxbytes){ errno = S_ioLib_UNKNOWN_REQUEST; return ERROR;}static int dspWrite (int devId, char *buffer, int nbytes){ DSP_FD *pDsp = (DSP_FD *)devId; SND_DEV *pDev = pDsp->dev.pDev; int bytesLeft = nbytes; int x; DMA_MSG mDma; /** Convert from uLaw to PCM if needed -- note, we only support 8-bit uLaw */ if (pDsp->info.uLaw) { for (x=0; x<nbytes; x++) { buffer[x] = ulaw_dsp[((unsigned char)buffer[x])]; } /* endfor */ } /* endfor */ /* Check if we were recording. If so, wait till all is clear. */ if (pDev->pDsp->dmaDirection != O_WRONLY) while (pDev->taskBusy) taskDelay (1); while (bytesLeft > 0) { mDma.buffer = getDmaBuffer (pDev); mDma.length = bytesLeft > MAX_DMA_SIZE ? MAX_DMA_SIZE : bytesLeft; mDma.direction = O_WRONLY; memcpy (mDma.buffer, buffer, mDma.length); if (mDma.length<MAX_DMA_SIZE) { bzero(mDma.buffer+mDma.length,MAX_DMA_SIZE-mDma.length); } /* endif */ msgQSend (pDev->dmaQ, (char *)&mDma, sizeof (mDma), WAIT_FOREVER, MSG_PRI_NORMAL); buffer += mDma.length; bytesLeft -= mDma.length; } return nbytes - bytesLeft;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -