X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dosdemo;a=blobdiff_plain;f=libs%2Foldmik%2Fsrc%2Fdrv_sb.c;fp=libs%2Foldmik%2Fsrc%2Fdrv_sb.c;h=6d85d471564aff8a1070bff2c0f892492d038a5f;hp=0000000000000000000000000000000000000000;hb=77db1ca18d5446dcda9e524261399b63c2cd1813;hpb=a714b8c4811627d874934b0a0387b8cb27fc5921 diff --git a/libs/oldmik/src/drv_sb.c b/libs/oldmik/src/drv_sb.c new file mode 100644 index 0000000..6d85d47 --- /dev/null +++ b/libs/oldmik/src/drv_sb.c @@ -0,0 +1,511 @@ +/* + +Name: +DRV_SB.C + +Description: +Mikmod driver for output on Creative Labs Soundblasters & compatibles +(through DSP) + +Portability: + +MSDOS: BC(y) Watcom(y) DJGPP(y) +Win95: n +Os2: n +Linux: n + +(y) - yes +(n) - no (not possible or not useful) +(?) - may be possible, but not tested + +*/ +#include +#include +#include +#include +#include +#ifndef __DJGPP__ +#include +#endif + +#include "mikmod.h" +#include "mdma.h" +#include "mirq.h" + +/*************************************************************************** +>>>>>>>>>>>>>>>>>>>>>>>>> Lowlevel SB stuff <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +***************************************************************************/ + +static UWORD sb_port; /* sb base port */ + +/* + Define some important SB i/o ports: +*/ + +#define MIXER_ADDRESS (sb_port+0x4) +#define MIXER_DATA (sb_port+0x5) +#define DSP_RESET (sb_port+0x6) +#define DSP_READ_DATA (sb_port+0xa) +#define DSP_WRITE_DATA (sb_port+0xc) +#define DSP_WRITE_STATUS (sb_port+0xc) +#define DSP_DATA_AVAIL (sb_port+0xe) + + +static void SB_MixerStereo(void) +/* + Enables stereo output for DSP versions 3.00 >= ver < 4.00 +*/ +{ + outportb(MIXER_ADDRESS,0xe); + outportb(MIXER_DATA,inportb(MIXER_DATA)|2); +} + + + +static void SB_MixerMono(void) +/* + Disables stereo output for DSP versions 3.00 >= ver < 4.00 +*/ +{ + outportb(MIXER_ADDRESS,0xe); + outportb(MIXER_DATA,inportb(MIXER_DATA)&0xfd); +} + + + +static BOOL SB_WaitDSPWrite(void) +/* + Waits until the DSP is ready to be written to. + + returns FALSE on timeout +*/ +{ + UWORD timeout=32767; + + while(timeout--){ + if(!(inportb(DSP_WRITE_STATUS)&0x80)) return 1; + } + return 0; +} + + + +static BOOL SB_WaitDSPRead(void) +/* + Waits until the DSP is ready to read from. + + returns FALSE on timeout +*/ +{ + UWORD timeout=32767; + + while(timeout--){ + if(inportb(DSP_DATA_AVAIL)&0x80) return 1; + } + return 0; +} + + + +static BOOL SB_WriteDSP(UBYTE data) +/* + Writes byte 'data' to the DSP. + + returns FALSE on timeout. +*/ +{ + if(!SB_WaitDSPWrite()) return 0; + outportb(DSP_WRITE_DATA,data); + return 1; +} + + + +static UWORD SB_ReadDSP(void) +/* + Reads a byte from the DSP. + + returns 0xffff on timeout. +*/ +{ + if(!SB_WaitDSPRead()) return 0xffff; + return(inportb(DSP_READ_DATA)); +} + + + +static void SB_SpeakerOn(void) +/* + Enables DAC speaker output. +*/ +{ + SB_WriteDSP(0xd1); +} + + + +static void SB_SpeakerOff(void) +/* + Disables DAC speaker output +*/ +{ + SB_WriteDSP(0xd3); +} + + + +static void SB_ResetDSP(void) +/* + Resets the DSP. +*/ +{ + int t; + /* reset the DSP by sending 1, (delay), then 0 */ + outportb(DSP_RESET,1); + for(t=0;t<8;t++) inportb(DSP_RESET); + outportb(DSP_RESET,0); +} + + + +static BOOL SB_Ping(void) +/* + Checks if a SB is present at the current baseport by + resetting the DSP and checking if it returned the value 0xaa. + + returns: TRUE => SB is present + FALSE => No SB detected +*/ +{ + SB_ResetDSP(); + return(SB_ReadDSP()==0xaa); +} + + + +static UWORD SB_GetDSPVersion(void) +/* + Gets SB-dsp version. returns 0xffff if dsp didn't respond. +*/ +{ + UWORD hi,lo; + + if(!SB_WriteDSP(0xe1)) return 0xffff; + + hi=SB_ReadDSP(); + lo=SB_ReadDSP(); + + return((hi<<8)|lo); +} + + + +/*************************************************************************** +>>>>>>>>>>>>>>>>>>>>>>>>> The actual SB driver <<<<<<<<<<<<<<<<<<<<<<<<<<<<< +***************************************************************************/ + +static DMAMEM *SB_DMAMEM; +static signed char *SB_DMABUF; + +static UBYTE SB_TIMECONSTANT; + +static UBYTE PIC1MSK; +static UBYTE PIC2MSK; + +static UWORD sb_int; /* interrupt vector that belongs to sb_irq */ +static UWORD sb_ver; /* DSP version number */ +static UBYTE sb_irq; /* sb irq */ +static UBYTE sb_lodma; /* 8 bit dma channel (1.0/2.0/pro) */ +static UBYTE sb_hidma; /* 16 bit dma channel (16/16asp) */ +static UBYTE sb_dma; /* current dma channel */ + + +static BOOL SB_IsThere(void) +{ + char *envptr,c; + static char *endptr; + + sb_port =0xffff; + sb_irq =0xff; + sb_lodma=0xff; + sb_hidma=0xff; + + if((envptr=getenv("BLASTER"))==NULL) return 0; + + while(1){ + + /* skip whitespace */ + + do c=*(envptr++); while(c==' ' || c=='\t'); + + /* reached end of string? -> exit */ + + if(c==0) break; + + switch(c){ + + case 'a': + case 'A': + sb_port=strtol(envptr,&endptr,16); + break; + + case 'i': + case 'I': + sb_irq=strtol(envptr,&endptr,10); + break; + + case 'd': + case 'D': + sb_lodma=strtol(envptr,&endptr,10); + break; + + case 'h': + case 'H': + sb_hidma=strtol(envptr,&endptr,10); + break; + + default: + strtol(envptr,&endptr,16); + break; + } + envptr=endptr; + } + + if(sb_port==0xffff || sb_irq==0xff || sb_lodma==0xff) return 0; + + /* determine interrupt vector */ + + sb_int = (sb_irq>7) ? sb_irq+104 : sb_irq+8; + + if(!SB_Ping()) return 0; + + /* get dsp version. */ + + if((sb_ver=SB_GetDSPVersion())==0xffff) return 0; + + return 1; +} + + +static void interrupt newhandler(MIRQARGS) +{ + if(sb_ver<0x200){ + SB_WriteDSP(0x14); + SB_WriteDSP(0xff); + SB_WriteDSP(0xfe); + } + + if(md_mode & DMODE_16BITS) + inportb(sb_port+0xf); + else + inportb(DSP_DATA_AVAIL); + + MIrq_EOI(sb_irq); +} + + +static PVI oldhandler; + + +static BOOL SB_Init(void) +{ + ULONG t; + + if(!SB_IsThere()){ + myerr="No such hardware detected, check your 'BLASTER' env. variable"; + return 0; + } + +/* printf("SB version %x\n",sb_ver); */ +/* if(sb_ver>0x200) sb_ver=0x200; */ + + if(sb_ver>=0x400 && sb_hidma==0xff){ + myerr="High-dma setting in 'BLASTER' variable is required for SB-16"; + return 0; + } + + if(sb_ver<0x400 && md_mode&DMODE_16BITS){ + /* DSP versions below 4.00 can't do 16 bit sound. */ + md_mode&=~DMODE_16BITS; + } + + if(sb_ver<0x300 && md_mode&DMODE_STEREO){ + /* DSP versions below 3.00 can't do stereo sound. */ + md_mode&=~DMODE_STEREO; + } + + /* Use low dma channel for 8 bit, high dma for 16 bit */ + + sb_dma=(md_mode & DMODE_16BITS) ? sb_hidma : sb_lodma; + + if(sb_ver<0x400){ + + t=md_mixfreq; + if(md_mode & DMODE_STEREO) t<<=1; + + SB_TIMECONSTANT=256-(1000000L/t); + + if(sb_ver<0x201){ + if(SB_TIMECONSTANT>210) SB_TIMECONSTANT=210; + } + else{ + if(SB_TIMECONSTANT>233) SB_TIMECONSTANT=233; + } + + md_mixfreq=1000000L/(256-SB_TIMECONSTANT); + if(md_mode & DMODE_STEREO) md_mixfreq>>=1; + } + + if(!VC_Init()) return 0; + + SB_DMAMEM=MDma_AllocMem(md_dmabufsize); + + if(SB_DMAMEM==NULL){ + VC_Exit(); + myerr="Couldn't allocate page-contiguous dma-buffer"; + return 0; + } + + SB_DMABUF=(char *)MDma_GetPtr(SB_DMAMEM); + + oldhandler=MIrq_SetHandler(sb_irq,newhandler); + return 1; +} + + + +static void SB_Exit(void) +{ + MIrq_SetHandler(sb_irq,oldhandler); + MDma_FreeMem(SB_DMAMEM); + VC_Exit(); +} + + +static UWORD last=0; +static UWORD curr=0; + + +static void SB_Update(void) +{ + UWORD todo,index; + + curr=(md_dmabufsize-MDma_Todo(sb_dma))&0xfffc; + + if(curr==last) return; + + if(curr>last){ + todo=curr-last; index=last; + last+=VC_WriteBytes(&SB_DMABUF[index],todo); + MDma_Commit(SB_DMAMEM,index,todo); + if(last>=md_dmabufsize) last=0; + } + else{ + todo=md_dmabufsize-last; + VC_WriteBytes(&SB_DMABUF[last],todo); + MDma_Commit(SB_DMAMEM,last,todo); + last=VC_WriteBytes(SB_DMABUF,curr); + MDma_Commit(SB_DMAMEM,0,curr); + } +} + + + + +static void SB_PlayStart(void) +{ + VC_PlayStart(); + + MIrq_OnOff(sb_irq,1); + + if(sb_ver>=0x300 && sb_ver<0x400){ + if(md_mode & DMODE_STEREO){ + SB_MixerStereo(); + } + else{ + SB_MixerMono(); + } + } + + /* clear the dma buffer */ + + VC_SilenceBytes(SB_DMABUF,md_dmabufsize); + MDma_Commit(SB_DMAMEM,0,md_dmabufsize); + + if(!MDma_Start(sb_dma,SB_DMAMEM,md_dmabufsize,INDEF_WRITE)){ + return; + } + + if(sb_ver<0x400){ + SB_SpeakerOn(); + + SB_WriteDSP(0x40); + SB_WriteDSP(SB_TIMECONSTANT); + + if(sb_ver<0x200){ + SB_WriteDSP(0x14); + SB_WriteDSP(0xff); + SB_WriteDSP(0xfe); + } + else if(sb_ver==0x200){ + SB_WriteDSP(0x48); + SB_WriteDSP(0xff); + SB_WriteDSP(0xfe); + SB_WriteDSP(0x1c); + } + else{ + SB_WriteDSP(0x48); + SB_WriteDSP(0xff); + SB_WriteDSP(0xfe); + SB_WriteDSP(0x90); + } + } + else{ + SB_WriteDSP(0x41); + + SB_WriteDSP(md_mixfreq>>8); + SB_WriteDSP(md_mixfreq&0xff); + + if(md_mode & DMODE_16BITS){ + SB_WriteDSP(0xb6); + SB_WriteDSP((md_mode & DMODE_STEREO) ? 0x30 : 0x10); + } + else{ + SB_WriteDSP(0xc6); + SB_WriteDSP((md_mode & DMODE_STEREO) ? 0x20 : 0x00); + } + + SB_WriteDSP(0xff); + SB_WriteDSP(0xef); + } +} + + +static void SB_PlayStop(void) +{ + VC_PlayStop(); + SB_SpeakerOff(); + SB_ResetDSP(); + SB_ResetDSP(); + MDma_Stop(sb_dma); + MIrq_OnOff(sb_irq,0); +} + + +DRIVER drv_sb={ + NULL, + "Soundblaster & compatibles", + "MikMod Soundblaster Driver v2.1 for 1.0 / 2.0 / Pro / 16", + SB_IsThere, + VC_SampleLoad, + VC_SampleUnload, + SB_Init, + SB_Exit, + SB_PlayStart, + SB_PlayStop, + SB_Update, + VC_VoiceSetVolume, + VC_VoiceSetFrequency, + VC_VoiceSetPanning, + VC_VoicePlay +};