7 Mikmod driver for output on Creative Labs Soundblasters & compatibles
\r
12 MSDOS: BC(y) Watcom(y) DJGPP(y)
\r
18 (n) - no (not possible or not useful)
\r
19 (?) - may be possible, but not tested
\r
35 /***************************************************************************
\r
36 >>>>>>>>>>>>>>>>>>>>>>>>> Lowlevel SB stuff <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
\r
37 ***************************************************************************/
\r
39 static UWORD sb_port; /* sb base port */
\r
42 Define some important SB i/o ports:
\r
45 #define MIXER_ADDRESS (sb_port+0x4)
\r
46 #define MIXER_DATA (sb_port+0x5)
\r
47 #define DSP_RESET (sb_port+0x6)
\r
48 #define DSP_READ_DATA (sb_port+0xa)
\r
49 #define DSP_WRITE_DATA (sb_port+0xc)
\r
50 #define DSP_WRITE_STATUS (sb_port+0xc)
\r
51 #define DSP_DATA_AVAIL (sb_port+0xe)
\r
54 static void SB_MixerStereo(void)
\r
56 Enables stereo output for DSP versions 3.00 >= ver < 4.00
\r
59 outportb(MIXER_ADDRESS,0xe);
\r
60 outportb(MIXER_DATA,inportb(MIXER_DATA)|2);
\r
65 static void SB_MixerMono(void)
\r
67 Disables stereo output for DSP versions 3.00 >= ver < 4.00
\r
70 outportb(MIXER_ADDRESS,0xe);
\r
71 outportb(MIXER_DATA,inportb(MIXER_DATA)&0xfd);
\r
76 static BOOL SB_WaitDSPWrite(void)
\r
78 Waits until the DSP is ready to be written to.
\r
80 returns FALSE on timeout
\r
83 UWORD timeout=32767;
\r
86 if(!(inportb(DSP_WRITE_STATUS)&0x80)) return 1;
\r
93 static BOOL SB_WaitDSPRead(void)
\r
95 Waits until the DSP is ready to read from.
\r
97 returns FALSE on timeout
\r
100 UWORD timeout=32767;
\r
103 if(inportb(DSP_DATA_AVAIL)&0x80) return 1;
\r
110 static BOOL SB_WriteDSP(UBYTE data)
\r
112 Writes byte 'data' to the DSP.
\r
114 returns FALSE on timeout.
\r
117 if(!SB_WaitDSPWrite()) return 0;
\r
118 outportb(DSP_WRITE_DATA,data);
\r
124 static UWORD SB_ReadDSP(void)
\r
126 Reads a byte from the DSP.
\r
128 returns 0xffff on timeout.
\r
131 if(!SB_WaitDSPRead()) return 0xffff;
\r
132 return(inportb(DSP_READ_DATA));
\r
137 static void SB_SpeakerOn(void)
\r
139 Enables DAC speaker output.
\r
147 static void SB_SpeakerOff(void)
\r
149 Disables DAC speaker output
\r
157 static void SB_ResetDSP(void)
\r
163 /* reset the DSP by sending 1, (delay), then 0 */
\r
164 outportb(DSP_RESET,1);
\r
165 for(t=0;t<8;t++) inportb(DSP_RESET);
\r
166 outportb(DSP_RESET,0);
\r
171 static BOOL SB_Ping(void)
\r
173 Checks if a SB is present at the current baseport by
\r
174 resetting the DSP and checking if it returned the value 0xaa.
\r
176 returns: TRUE => SB is present
\r
177 FALSE => No SB detected
\r
181 return(SB_ReadDSP()==0xaa);
\r
186 static UWORD SB_GetDSPVersion(void)
\r
188 Gets SB-dsp version. returns 0xffff if dsp didn't respond.
\r
193 if(!SB_WriteDSP(0xe1)) return 0xffff;
\r
198 return((hi<<8)|lo);
\r
203 /***************************************************************************
\r
204 >>>>>>>>>>>>>>>>>>>>>>>>> The actual SB driver <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
\r
205 ***************************************************************************/
\r
207 static DMAMEM *SB_DMAMEM;
\r
208 static char *SB_DMABUF;
\r
210 static UBYTE SB_TIMECONSTANT;
\r
212 static UBYTE PIC1MSK;
\r
213 static UBYTE PIC2MSK;
\r
215 static UWORD sb_int; /* interrupt vector that belongs to sb_irq */
\r
216 static UWORD sb_ver; /* DSP version number */
\r
217 static UBYTE sb_irq; /* sb irq */
\r
218 static UBYTE sb_lodma; /* 8 bit dma channel (1.0/2.0/pro) */
\r
219 static UBYTE sb_hidma; /* 16 bit dma channel (16/16asp) */
\r
220 static UBYTE sb_dma; /* current dma channel */
\r
223 static BOOL SB_IsThere(void)
\r
226 static char *endptr;
\r
233 if((envptr=getenv("BLASTER"))==NULL) return 0;
\r
237 /* skip whitespace */
\r
239 do c=*(envptr++); while(c==' ' || c=='\t');
\r
241 /* reached end of string? -> exit */
\r
249 sb_port=strtol(envptr,&endptr,16);
\r
254 sb_irq=strtol(envptr,&endptr,10);
\r
259 sb_lodma=strtol(envptr,&endptr,10);
\r
264 sb_hidma=strtol(envptr,&endptr,10);
\r
268 strtol(envptr,&endptr,16);
\r
274 if(sb_port==0xffff || sb_irq==0xff || sb_lodma==0xff) return 0;
\r
276 /* determine interrupt vector */
\r
278 sb_int = (sb_irq>7) ? sb_irq+104 : sb_irq+8;
\r
280 if(!SB_Ping()) return 0;
\r
282 /* get dsp version. */
\r
284 if((sb_ver=SB_GetDSPVersion())==0xffff) return 0;
\r
290 static void interrupt newhandler(MIRQARGS)
\r
298 if(md_mode & DMODE_16BITS)
\r
299 inportb(sb_port+0xf);
\r
301 inportb(DSP_DATA_AVAIL);
\r
307 static PVI oldhandler;
\r
310 static BOOL SB_Init(void)
\r
315 myerr="No such hardware detected, check your 'BLASTER' env. variable";
\r
319 /* printf("SB version %x\n",sb_ver); */
\r
320 /* if(sb_ver>0x200) sb_ver=0x200; */
\r
322 if(sb_ver>=0x400 && sb_hidma==0xff){
\r
323 myerr="High-dma setting in 'BLASTER' variable is required for SB-16";
\r
327 if(sb_ver<0x400 && md_mode&DMODE_16BITS){
\r
328 /* DSP versions below 4.00 can't do 16 bit sound. */
\r
329 md_mode&=~DMODE_16BITS;
\r
332 if(sb_ver<0x300 && md_mode&DMODE_STEREO){
\r
333 /* DSP versions below 3.00 can't do stereo sound. */
\r
334 md_mode&=~DMODE_STEREO;
\r
337 /* Use low dma channel for 8 bit, high dma for 16 bit */
\r
339 sb_dma=(md_mode & DMODE_16BITS) ? sb_hidma : sb_lodma;
\r
344 if(md_mode & DMODE_STEREO) t<<=1;
\r
346 SB_TIMECONSTANT=256-(1000000L/t);
\r
349 if(SB_TIMECONSTANT>210) SB_TIMECONSTANT=210;
\r
352 if(SB_TIMECONSTANT>233) SB_TIMECONSTANT=233;
\r
355 md_mixfreq=1000000L/(256-SB_TIMECONSTANT);
\r
356 if(md_mode & DMODE_STEREO) md_mixfreq>>=1;
\r
359 if(!VC_Init()) return 0;
\r
361 SB_DMAMEM=MDma_AllocMem(md_dmabufsize);
\r
363 if(SB_DMAMEM==NULL){
\r
365 myerr="Couldn't allocate page-contiguous dma-buffer";
\r
369 SB_DMABUF=(char *)MDma_GetPtr(SB_DMAMEM);
\r
371 oldhandler=MIrq_SetHandler(sb_irq,newhandler);
\r
377 static void SB_Exit(void)
\r
379 MIrq_SetHandler(sb_irq,oldhandler);
\r
380 MDma_FreeMem(SB_DMAMEM);
\r
385 static UWORD last=0;
\r
386 static UWORD curr=0;
\r
389 static void SB_Update(void)
\r
393 curr=(md_dmabufsize-MDma_Todo(sb_dma))&0xfffc;
\r
395 if(curr==last) return;
\r
398 todo=curr-last; index=last;
\r
399 last+=VC_WriteBytes(&SB_DMABUF[index],todo);
\r
400 MDma_Commit(SB_DMAMEM,index,todo);
\r
401 if(last>=md_dmabufsize) last=0;
\r
404 todo=md_dmabufsize-last;
\r
405 VC_WriteBytes(&SB_DMABUF[last],todo);
\r
406 MDma_Commit(SB_DMAMEM,last,todo);
\r
407 last=VC_WriteBytes(SB_DMABUF,curr);
\r
408 MDma_Commit(SB_DMAMEM,0,curr);
\r
415 static void SB_PlayStart(void)
\r
419 MIrq_OnOff(sb_irq,1);
\r
421 if(sb_ver>=0x300 && sb_ver<0x400){
\r
422 if(md_mode & DMODE_STEREO){
\r
430 /* clear the dma buffer */
\r
432 VC_SilenceBytes(SB_DMABUF,md_dmabufsize);
\r
433 MDma_Commit(SB_DMAMEM,0,md_dmabufsize);
\r
435 if(!MDma_Start(sb_dma,SB_DMAMEM,md_dmabufsize,INDEF_WRITE)){
\r
443 SB_WriteDSP(SB_TIMECONSTANT);
\r
450 else if(sb_ver==0x200){
\r
466 SB_WriteDSP(md_mixfreq>>8);
\r
467 SB_WriteDSP(md_mixfreq&0xff);
\r
469 if(md_mode & DMODE_16BITS){
\r
471 SB_WriteDSP((md_mode & DMODE_STEREO) ? 0x30 : 0x10);
\r
475 SB_WriteDSP((md_mode & DMODE_STEREO) ? 0x20 : 0x00);
\r
484 static void SB_PlayStop(void)
\r
491 MIrq_OnOff(sb_irq,0);
\r
497 "Soundblaster & compatibles",
\r
498 "MikMod Soundblaster Driver v2.1 for 1.0 / 2.0 / Pro / 16",
\r
508 VC_VoiceSetFrequency,
\r
509 VC_VoiceSetPanning,
\r