1  /*
2   * UAE - The Un*x Amiga Emulator
3   *
4   * DOS Sound Blaster interface.
5   *
6   * (c) 1996 Peter Remmers, Gustavo Goedert
7   *
8   * Bugfixes by Michael Sontheimer
9   */
10 
11 #include "sysconfig.h"
12 #include "sysdeps.h"
13 
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <dos.h>
19 #include <pc.h>
20 #include <sys/farptr.h>
21 #include <dpmi.h>
22 #include <go32.h>
23 
24 #include "sound/sb.h"
25 #include "sound/dma.h"
26 
27 /* some useful macros */
28 #define LOBYTE(x) ((UBYTE)(((UWORD)(x)) &  0xFF))
29 #define HIBYTE(x) ((UBYTE)(((UWORD)(x)) >> 8))
30 #define LOWORD(x) ((UWORD)(((ULONG)(x)) & 0xFFFF))
31 #define HIWORD(x) ((UWORD)(((ULONG)(x)) >> 16))
32 #define NUMPARAS(bytesize) (((bytesize)+15) >> 4)
33 
34 #ifndef TRUE
35 #define TRUE 1
36 #endif
37 #ifndef FALSE
38 #define FALSE 0
39 #endif
40 
41 /* Offsets relative to base I/O address. */
42 #define SB_MIXER_ADDRESS        0x04
43 #define SB_MIXER_DATA           0x05
44 #define SB_DSP_RESET            0x06
45 #define SB_DSP_READ_DATA        0x0A
46 #define SB_DSP_WRITE_DATA       0x0C
47 #define SB_DSP_WRITE_STATUS     0x0C
48 #define SB_DSP_DATA_AVAIL       0x0E
49 #define SB_DSP_INT_CLEAR        0x0F
50 
51 /* DSP Commands */
52 #define CMD_PLAY_8BIT                0x14
53 #define CMD_SET_TIME_CONSTANT        0x40
54 #define CMD_DEFINE_SILENCE_BLOCK     0x80
55 #define CMD_PAUSE_8BIT_DMA           0xD0
56 #define CMD_CONTINUE_8BIT_DMA        0xD4
57 #define CMD_SPEAKER_ON               0xD1
58 #define CMD_SPEAKER_OFF              0xD3
59 #define CMD_GET_SPEAKER_SETTING      0xD8
60 #define CMD_DSP_VER                  0xE1
61 
62 /* SbPro-only commands */
63 #define CMD_SET_BLOCK_SIZE           0x48
64 #define CMD_PLAY_8BIT_HISPEED        0x91
65 
66 /* SB16-only commands */
67 #define CMD_SET_OUTPUT_RATE          0x41
68 #define CMD_PLAY_16BIT_SINGLE        0xB0
69 #define CMD_PLAY_16BIT_AUTOINIT      0xB6
70 #define CMD_PLAY_8BIT_SINGLE         0xC0
71 #define CMD_PLAY_8BIT_AUTOINIT       0xC6
72 #define CMD_PAUSE_16BIT_DMA          0xD5
73 #define CMD_CONTINUE_16BIT_DMA       0xD6
74 
75 typedef void (*tPlayProc)(UWORD bytes);
76 
77 typedef struct
78 {
79   ULONG Data;
80   _go32_dpmi_seginfo dma_mem; /* info for DMA memory */
81 }
82 tDMABuffer;
83 
84 tSBType SB_Type;
85 
86 UWORD SB_Base;      /* the Base Address  e.g. 220h                         */
87 UWORD SB_IRQ;       /* The IRQ           e.g. 5                            */
88 UWORD SB_DMAlo;     /* Low DMA channel   e.g. 1                            */
89 UWORD SB_DMAhi;     /* high DMA channel  e.g. 5                            */
90 UWORD SB_INT;       /* The Interrupt vector corresponding to IRQ e.g. 0Dh  */
91 UWORD SB_DMA;       /* The current DMA channel                             */
92 		    /* (depends on if we're playing 8Bit or 16Bit sound)   */
93 UBYTE SB_VersMaj;   /* Major DSP Version byte                              */
94 UBYTE SB_VersMin;   /* Minor DSP Version byte                              */
95 UBYTE SB_ModeByte;  /* Mode Byte for SB16 (Mono/Stereo, Signed/Unsigned )  */
96 UWORD SB_IntClearPort; /* SB Port to read from to acknoledge interrupt     */
97 
98 tPlayProc SB_Play_Proc;        /* function */
99 tDMABuffer dma_buf[2];         /* the two DMA buffers */
100 
101 BOOL  SB_16Bit;       /* we're playing in 16 Bits                          */
102 BOOL  SB_Stereo;      /* we're playing in stereo                           */
103 UWORD SB_Active_Rate; /* the active sampling rate                          */
104 
105 volatile UBYTE IRQ_Detected;    /* the detected IRQ number                 */
106 
107 _go32_dpmi_seginfo   old_pmint;  /* the old interrupt handler         */
108 _go32_dpmi_seginfo   pm_wrapper; /* the new interrupt handler         */
109 
110 /* Reset SB at SB_Base, returns TRUE if it worked */
SB_Reset(void)111 BOOL SB_Reset (void)
112 {
113   outportb (SB_Base+SB_DSP_RESET, 1);
114   delay(100);
115   outportb (SB_Base+SB_DSP_RESET, 0);
116   delay(100);
117   return (inportb(SB_Base+SB_DSP_READ_DATA) == 0xAA);
118 }
119 
120 /* Write a command to DSP chip */
SB_WriteDSP(UBYTE value)121 inline void SB_WriteDSP (UBYTE value)
122 {
123   while (inportb(SB_Base + SB_DSP_WRITE_STATUS) & 0x80);
124   outportb (SB_Base + SB_DSP_WRITE_DATA, value);
125 }
126 
127 /* read a byte from DSP chip */
SB_ReadDSP(void)128 inline UBYTE SB_ReadDSP (void)
129 {
130   while (!(inportb (SB_Base + SB_DSP_DATA_AVAIL) & 0x80));
131   return  (inportb (SB_Base + SB_DSP_READ_DATA));
132 }
133 
134 /* write a value to the mixer chip */
SB_WriteMixer(UBYTE reg,UBYTE data)135 inline void SB_WriteMixer (UBYTE reg, UBYTE data)
136 {
137   outportb (SB_Base + SB_MIXER_ADDRESS, reg);
138   outportb (SB_Base + SB_MIXER_DATA,    data);
139 }
140 
141 /* read a value from the mixer chip */
SB_ReadMixer(UBYTE reg)142 inline UBYTE SB_ReadMixer (UBYTE reg)
143 {
144   outportb (SB_Base + SB_MIXER_ADDRESS, reg);
145   return (inportb (SB_Base + SB_MIXER_DATA));
146 }
147 
148 /* try to detect, if SB has a mixer chip, returns TRUE if found */
SB_DetectMixer(void)149 BOOL SB_DetectMixer (void)
150 {
151   UBYTE orgval;
152 
153   orgval = SB_ReadMixer (0x22);
154 
155   // Some SB-Pro-clones always set the bit 0 and 4, if reading
156   // the volume (the bit 0 and 4 aren't used for setting the volume)
157 
158   SB_WriteMixer (0x22, 0);
159   delay(200);
160   if ((SB_ReadMixer (0x22)&(0xEE)) != 0)
161     return (FALSE);
162 
163   SB_WriteMixer (0x22, 0xEE);
164   delay(200);
165   if ((SB_ReadMixer (0x22)&(0xEE)) != 0xEE)
166     return (FALSE);
167 
168 //  SB_WriteMixer (0x22, orgval);   // Why not setting the volume to maximum ?
169 
170   return (TRUE);
171 }
172 
173 /* play a block in 8 Bits on a Standard SB */
SB_Play_8Bit_Std(UWORD bytes)174 void SB_Play_8Bit_Std (UWORD bytes)
175 {
176   SB_WriteDSP (CMD_PLAY_8BIT);
177   SB_WriteDSP (LOBYTE (bytes-1));
178   SB_WriteDSP (HIBYTE (bytes-1));
179 }
180 
181 /* Play a block in 8 Bits on an SB PRO */
SB_Play_8Bit_SbPro(UWORD bytes)182 void SB_Play_8Bit_SbPro (UWORD bytes)
183 {
184   SB_WriteDSP (CMD_SET_BLOCK_SIZE);
185   SB_WriteDSP (LOBYTE (bytes-1));
186   SB_WriteDSP (HIBYTE (bytes-1));
187   SB_WriteDSP (CMD_PLAY_8BIT_HISPEED);
188 }
189 
190 /* play a block in 8 Bits on an SB 16 */
SB_Play_8Bit_SB16(UWORD bytes)191 void SB_Play_8Bit_SB16 (UWORD bytes)
192 {
193   SB_WriteDSP (CMD_PLAY_8BIT_SINGLE);
194   SB_WriteDSP (SB_ModeByte);
195   SB_WriteDSP (LOBYTE (bytes-1));
196   SB_WriteDSP (HIBYTE (bytes-1));
197 }
198 
199 /* play a block in 16 Bits on an SB 16 */
SB_Play_16Bit(UWORD bytes)200 void SB_Play_16Bit (UWORD bytes)
201 {
202   SB_WriteDSP (CMD_PLAY_16BIT_SINGLE);
203   SB_WriteDSP (SB_ModeByte);
204   SB_WriteDSP (LOBYTE ((bytes>>1) -1));
205   SB_WriteDSP (HIBYTE ((bytes>>1) -1));
206 }
207 
208 /* the main interrupt handler */
SB_IntHandler(void)209 void SB_IntHandler (void)
210 {
211   IsPlaying = FALSE;
212 
213   inportb (SB_IntClearPort);
214   if (SB_IRQ > 7) outportb (0xA0, 0x20);
215 
216   outportb (0x20, 0x20);
217   enable();
218 }
219 
220 /* set sampling rate on a standard SB */
SB_SetRate_LoSpeed(UWORD rate)221 void SB_SetRate_LoSpeed (UWORD rate)
222 {
223   SB_WriteDSP (CMD_SET_TIME_CONSTANT);
224   SB_WriteDSP (0x100 - 1000000 / rate);
225 }
226 
227 /* set sampling rate on a SB PRO */
SB_SetRate_HiSpeed(UWORD rate)228 void SB_SetRate_HiSpeed (UWORD rate)
229 {
230   SB_WriteDSP (CMD_SET_TIME_CONSTANT);
231   SB_WriteDSP (HIBYTE (0x10000 - 256000000 / rate));
232 }
233 
234 /* set sampling rate on an SB 16 */
SB_SetRate_SB16(UWORD rate)235 void SB_SetRate_SB16 (UWORD rate)
236 {
237   SB_WriteDSP (CMD_SET_OUTPUT_RATE);
238   SB_WriteDSP (HIBYTE (rate));
239   SB_WriteDSP (LOBYTE (rate));
240 }
241 
242 /* set the sampling rate */
SB_SetRate(unsigned short rate)243 int SB_SetRate (unsigned short rate)
244 {
245   if (rate > 23000 && SB_Type < SB_Type_SbPro) return(FALSE);
246 
247   switch (SB_Type)
248   {
249   case SB_Type_StdSB: SB_SetRate_LoSpeed (rate); break;
250   case SB_Type_SbPro: SB_SetRate_HiSpeed (rate); break;
251   case SB_Type_SB16:  SB_SetRate_SB16    (rate); break;
252   }
253 
254   SB_Active_Rate = rate;
255 
256   return (TRUE);
257 }
258 
259 /* set the number of bits, i.e. 8 Bit / 16 Bit mode */
SB_SetBits(unsigned char bits)260 int SB_SetBits (unsigned char bits)
261 {
262   if (bits==16 && SB_Type < SB_Type_SB16) return (FALSE);
263 
264   if (SB_Type == SB_Type_SB16)
265   {
266     if (bits==16)
267     {
268       SB_Play_Proc        = SB_Play_16Bit;
269       SB_IntClearPort     = SB_Base + SB_DSP_INT_CLEAR;
270       SB_DMA              = SB_DMAhi;
271       SB_16Bit            = TRUE;
272     }
273     else
274     {
275       SB_Play_Proc        = SB_Play_8Bit_SB16;
276       SB_IntClearPort     = SB_Base + SB_DSP_DATA_AVAIL;
277       SB_DMA              = SB_DMAlo;
278       SB_16Bit            = FALSE;
279     }
280   }
281 
282   return (TRUE);
283 }
284 
285 /* set the number of channels, i.e. Mono / Stereo */
SB_SetChannels(unsigned char channels)286 int SB_SetChannels (unsigned char channels)
287 {
288   if (channels==2 && SB_Type < SB_Type_SbPro) return (FALSE);
289 
290   switch (SB_Type)
291   {
292   case SB_Type_StdSB: break;
293 
294   case SB_Type_SbPro:
295     if (channels==2) SB_WriteMixer (0x0E, SB_ReadMixer (0x0E) | 0x02);
296 		else SB_WriteMixer (0x0E, SB_ReadMixer (0x0E) & 0xFD);
297     break;
298 
299   case SB_Type_SB16:
300     if (channels==2) SB_ModeByte |= 0x20;
301 		else SB_ModeByte &= 0xDF;
302     break;
303   }
304   SB_Stereo = (channels==2);
305 
306   return (TRUE);
307 }
308 
309 /* set Signed / Unsigned mode (only on SB 16) */
SB_SetSigned(int sign)310 int SB_SetSigned (int sign)
311 {
312   if (sign && SB_Type < SB_Type_SB16) return (FALSE);
313 
314   if (SB_Type == SB_Type_SB16)
315   {
316     if (sign) SB_ModeByte |= 0x10;
317 	 else SB_ModeByte &= 0xEF;
318   }
319   return (TRUE);
320 }
321 
322 /* turn speaker off (doesn't seem to work on SB 16) */
SB_SpeakerOff(void)323 void SB_SpeakerOff(void)
324 {
325   SB_WriteDSP(CMD_SPEAKER_OFF);
326 }
327 
328 /* turn speaker on (doesn't seem to work on SB 16) */
SB_SpeakerOn(void)329 void SB_SpeakerOn(void)
330 {
331   SB_WriteDSP(CMD_SPEAKER_ON);
332 }
333 
334 /* set sound blaster master volume, range from 0 to 7 */
SB_SetVolume(UBYTE vol)335 void SB_SetVolume(UBYTE vol)
336 {
337 
338   /* no mixer on standard sb */
339   if (SB_Type < SB_Type_SbPro)
340       return;
341 
342   if (vol>7)
343       vol = 7;
344   vol = (vol<<1);
345   if (SB_Type == SB_Type_SbPro)
346       vol = vol | 1;
347   vol = vol | (vol<<4);
348 
349   SB_WriteMixer (0x22, vol);
350 }
351 
352 /* interrupt handler functions used for IRQ/DMA detection */
irq2(void)353 void irq2 (void)
354 {
355   IRQ_Detected = 2;
356   inportb (SB_IntClearPort);
357   outportb (0x20, 0x20);
358 }
irq5(void)359 void irq5 (void)
360 {
361   IRQ_Detected = 5;
362   inportb (SB_IntClearPort);
363   outportb (0x20, 0x20);
364 }
irq7(void)365 void irq7 (void)
366 {
367   IRQ_Detected = 7;
368   inportb (SB_IntClearPort);
369   outportb (0x20, 0x20);
370 }
irq10(void)371 void irq10 (void)
372 {
373   IRQ_Detected = 10;
374   inportb (SB_IntClearPort);
375   outportb (0xA0, 0x20);
376   outportb (0x20, 0x20);
377 }
378 
379 /* detect the sound blaster Base/IRQ/DMA settings (may hang computer) */
SB_Detect(unsigned short * base,unsigned short * irq,unsigned short * dmalo,unsigned short * dmahi)380 int SB_Detect (unsigned short *base, unsigned short *irq,
381 	       unsigned short *dmalo, unsigned short *dmahi)
382 {
383 #define TESTBUFSIZE 0x80
384   static const UBYTE lowdma[3]  = { 1,3,0 };
385   static const UBYTE highdma[3] = { 5,6,7 };
386 
387   UBYTE old21,oldA1,old0F,oldDE;
388   _go32_dpmi_seginfo oldirq2,oldirq5,oldirq7,oldirq10;
389   _go32_dpmi_seginfo newirq2,newirq5,newirq7,newirq10;
390   _go32_dpmi_seginfo testbuf_info;
391   ULONG testbuf;
392   int   ret1,ret2,ret3,ret4;
393   UBYTE i;
394   BOOL  found;
395 
396   found = FALSE;
397 
398   *base  = 0;
399   *irq   = 0;
400   *dmalo = 0;
401   *dmahi = 0;
402 
403   SB_Base = 0x210;
404   while (SB_Base != 0x290)
405   {
406     if (SB_Reset()) break;
407     SB_Base += 0x10;
408   }
409   if (SB_Base == 0x290) return (FALSE);
410   *base = SB_Base;
411 
412   /* install detection interrupt handlers */
413   newirq2.pm_offset  = (int) irq2;
414   newirq5.pm_offset  = (int) irq5;
415   newirq7.pm_offset  = (int) irq7;
416   newirq10.pm_offset = (int) irq10;
417 
418   ret1 = _go32_dpmi_allocate_iret_wrapper (&newirq2);
419   ret2 = _go32_dpmi_allocate_iret_wrapper (&newirq5);
420   ret3 = _go32_dpmi_allocate_iret_wrapper (&newirq7);
421   ret4 = _go32_dpmi_allocate_iret_wrapper (&newirq10);
422 
423   if (ret1|ret2|ret3|ret4)
424   {
425     if (!ret1) _go32_dpmi_free_iret_wrapper (&newirq2);
426     if (!ret2) _go32_dpmi_free_iret_wrapper (&newirq5);
427     if (!ret3) _go32_dpmi_free_iret_wrapper (&newirq7);
428     if (!ret4) _go32_dpmi_free_iret_wrapper (&newirq10);
429     return (FALSE);
430   }
431   _go32_dpmi_lock_code (irq2, (int)SB_Detect - (int)irq2);
432   _go32_dpmi_lock_data ((void*)&IRQ_Detected,    sizeof(IRQ_Detected));
433   _go32_dpmi_lock_data (&SB_IntClearPort, sizeof(SB_IntClearPort));
434 
435   _go32_dpmi_get_protected_mode_interrupt_vector (0x0A, &oldirq2);
436   _go32_dpmi_get_protected_mode_interrupt_vector (0x0D, &oldirq5);
437   _go32_dpmi_get_protected_mode_interrupt_vector (0x0F, &oldirq7);
438   _go32_dpmi_get_protected_mode_interrupt_vector (0x72, &oldirq10);
439 
440   _go32_dpmi_set_protected_mode_interrupt_vector (0x0A, &newirq2);
441   _go32_dpmi_set_protected_mode_interrupt_vector (0x0D, &newirq5);
442   _go32_dpmi_set_protected_mode_interrupt_vector (0x0F, &newirq7);
443   _go32_dpmi_set_protected_mode_interrupt_vector (0x72, &newirq10);
444 
445   testbuf_info.size = NUMPARAS(TESTBUFSIZE);
446   testbuf = DMA_AllocDMABuf (&testbuf_info);
447 
448   /* turn on interrupts 2,5,7 and 10 */
449   old21 = inportb (0x21);
450   oldA1 = inportb (0xA1);
451   outportb (0x21, old21 & 0x5B);
452   outportb (0xA1, oldA1 & 0xFB);
453 
454   /* turn off DMA 0,1,3,5,6 and 7 */
455   old0F = inportb (0x0F);
456   oldDE = inportb (0xDE);
457   outportb (0x0F, old0F | 0x0B);
458   outportb (0xDE, oldDE | 0x0E);
459 
460   /* fill testbuffer with silence */
461   for (i=0; i<TESTBUFSIZE; i++) _farnspokeb (testbuf+i, 128);
462 
463   /* detect low DMA and IRQ */
464   SB_IntClearPort = SB_Base + SB_DSP_DATA_AVAIL;
465   SB_SetRate_LoSpeed (22050);
466   /* program SB to play testbuffer, will start playing */
467   /* when we hit the right DMA channel                 */
468   SB_Play_8Bit_Std (TESTBUFSIZE);
469 
470   /* test all DMA channels */
471   IRQ_Detected = 0;
472   for (i=0; i<3; i++)
473   {
474     DMA_InitTransfer (lowdma[i], DMA_READ, testbuf, TESTBUFSIZE);
475     delay (TESTBUFSIZE*2000 / 22050);
476     if (IRQ_Detected)
477     {
478       *dmalo = lowdma[i];
479       *irq   = IRQ_Detected;
480       break;
481     }
482   }
483 
484   if (IRQ_Detected)
485   {
486     found = TRUE;
487 
488     SB_WriteDSP (CMD_DSP_VER);
489     SB_VersMaj = SB_ReadDSP();
490     SB_VersMin = SB_ReadDSP();
491 
492     /* if SoundBlaster is an SB16 then test high DMA channel */
493     if (SB_VersMaj >= 4)
494     {
495       outportb (0x0F, old0F | 0x0B);
496       outportb (0xDE, oldDE | 0x0E);
497 
498       for (i=0; i<TESTBUFSIZE; i+=2) _farnspokew (testbuf+i, 0x8000);
499 
500       SB_ModeByte = 0x00;
501       SB_IntClearPort = SB_Base + SB_DSP_INT_CLEAR;
502       SB_SetRate_SB16(44100);
503       SB_Play_16Bit(TESTBUFSIZE);
504 
505       IRQ_Detected = 0;
506       for (i=0; i<3; i++)
507       {
508 	DMA_InitTransfer (highdma[i], DMA_READ, testbuf, TESTBUFSIZE);
509 	delay (TESTBUFSIZE*1000 / 44100);
510 	if (IRQ_Detected)
511 	{
512 	  *dmahi = highdma[i];
513 	  break;
514 	}
515       }
516       if (!IRQ_Detected) *dmahi = *dmalo;
517     }
518   }
519 
520   /* clean up */
521   _go32_dpmi_free_dos_memory (&testbuf_info);
522 
523   outportb (0x0F, old0F);
524   outportb (0xDE, oldDE);
525   outportb (0x21, old21);
526   outportb (0xA1, oldA1);
527 
528   _go32_dpmi_set_protected_mode_interrupt_vector (0x0A, &oldirq2);
529   _go32_dpmi_set_protected_mode_interrupt_vector (0x0D, &oldirq5);
530   _go32_dpmi_set_protected_mode_interrupt_vector (0x0F, &oldirq7);
531   _go32_dpmi_set_protected_mode_interrupt_vector (0x72, &oldirq10);
532 
533   _go32_dpmi_free_iret_wrapper (&newirq2);
534   _go32_dpmi_free_iret_wrapper (&newirq5);
535   _go32_dpmi_free_iret_wrapper (&newirq7);
536   _go32_dpmi_free_iret_wrapper (&newirq10);
537 
538   return (found);
539 }
540 
SB_InitBuffers(int bufsize)541 int SB_InitBuffers(int bufsize)
542 {
543   dma_buf[0].dma_mem.size = NUMPARAS(bufsize);
544   dma_buf[0].Data = DMA_AllocDMABuf (&dma_buf[0].dma_mem);
545 
546   dma_buf[1].dma_mem.size = NUMPARAS(bufsize);
547   dma_buf[1].Data = DMA_AllocDMABuf (&dma_buf[1].dma_mem);
548 
549   if ((dma_buf[0].Data == NULL) || (dma_buf[1].Data == NULL))
550     return (FALSE);
551 
552   return (TRUE);
553 }
554 
555 
556 /* init Sound blaster using the given settings */
SB_Init(unsigned short base,unsigned short irq,unsigned short dmalo,unsigned short dmahi)557 int SB_Init (unsigned short base, unsigned short irq,
558 	     unsigned short dmalo, unsigned short dmahi)
559 {
560   SB_Base  = base;
561   SB_IRQ   = irq;
562   SB_DMAlo = dmalo;
563   SB_DMAhi = dmahi;
564 
565   if (SB_IRQ > 7) SB_INT = 0x68 + SB_IRQ;
566 	     else SB_INT = 0x08 + SB_IRQ;
567 
568   if (!SB_Reset()) return (FALSE);
569 
570   pm_wrapper.pm_offset = (int) SB_IntHandler;
571   if (_go32_dpmi_allocate_iret_wrapper (&pm_wrapper))
572   {
573     printf ("Cannot allocate protected mode wrapper for SB interrupt!\n");
574     _go32_dpmi_free_dos_memory (&dma_buf[0].dma_mem);
575     _go32_dpmi_free_dos_memory (&dma_buf[1].dma_mem);
576     return (FALSE);
577   }
578 
579   _go32_dpmi_lock_code (SB_WriteDSP, (ULONG)SB_WriteMixer - (ULONG)SB_WriteDSP);
580   _go32_dpmi_lock_data (&SB_Base, (ULONG)&old_pmint - (ULONG)&SB_Base);
581 
582   _go32_dpmi_get_protected_mode_interrupt_vector (SB_INT, &old_pmint);
583   _go32_dpmi_set_protected_mode_interrupt_vector (SB_INT, &pm_wrapper);
584 
585   if (SB_IRQ>7)
586     outportb(0xA1, inportb(0xA1) & ~(1 << (SB_IRQ-8)));
587   else
588     outportb(0x21, inportb(0x21) & ~(1 << SB_IRQ));
589 
590   SB_Type = SB_Type_StdSB;
591 
592   if( SB_DetectMixer() != FALSE )
593     SB_Type = SB_Type_SbPro;
594 
595   SB_WriteDSP (CMD_DSP_VER);
596   SB_VersMaj = SB_ReadDSP ();
597   SB_VersMin = SB_ReadDSP ();
598 
599   if (SB_VersMaj >= 4) SB_Type = SB_Type_SB16;
600 
601 //  SB_Type = SB_Type_SbPro;  /* for testing */
602 
603   /* initialize SB to default 8Bit Mono 22050Hz */
604   /* (available on all SoundBlaster Versions)   */
605   switch (SB_Type)
606   {
607   case SB_Type_StdSB:
608     SB_Play_Proc = SB_Play_8Bit_Std;
609     SB_SetRate_LoSpeed(22050);
610     break;
611   case SB_Type_SbPro:
612     SB_Play_Proc = SB_Play_8Bit_SbPro;
613     SB_SetRate_HiSpeed(22050);
614     break;
615   case SB_Type_SB16:
616     SB_Play_Proc = SB_Play_8Bit_SB16;
617     SB_SetRate_SB16(22050);
618     break;
619   }
620   SB_IntClearPort = SB_Base + SB_DSP_DATA_AVAIL;
621   SB_DMA          = SB_DMAlo;
622   IsPlaying       = FALSE;
623   SB_16Bit        = FALSE;
624   SB_Stereo       = FALSE;
625   SB_Active_Rate  = 22050;
626   SB_ModeByte     = 0x00;
627 
628   SB_SpeakerOn();
629   SB_SetVolume(6);
630 
631   return (TRUE);
632 }
633 
634 /* clean up Sound Blaster */
SB_Done(void)635 void SB_Done (void)
636 {
637   SB_Reset ();
638   if (SB_IRQ > 7)
639     outportb (0xA1, inportb(0xA1) | (1 << (SB_IRQ-8)));
640   else
641     outportb (0x21, inportb(0x21) | (1 << SB_IRQ));
642 
643   _go32_dpmi_set_protected_mode_interrupt_vector (SB_INT, &old_pmint);
644   _go32_dpmi_free_iret_wrapper (&pm_wrapper);
645   _go32_dpmi_free_dos_memory (&dma_buf[0].dma_mem);
646   _go32_dpmi_free_dos_memory (&dma_buf[1].dma_mem);
647 }
648 
649 /* write sound data to be played to the fifo buffer */
SB_DirectWrite(unsigned int size,int freq)650 void SB_DirectWrite(unsigned int size, int freq)
651 {
652     DMA_InitTransfer (SB_DMA, DMA_READ, dma_buf[CurrentBuffer].Data, size);
653     (*SB_Play_Proc) (size);
654     IsPlaying  = TRUE;
655     if (freq != SB_Active_Rate)
656 	SB_SetRate(freq);
657 }
658 
659 /* return thee DSP chip version */
SB_GetVersion(unsigned char * Maj,unsigned char * Min)660 void SB_GetVersion (unsigned char *Maj, unsigned char *Min)
661 {
662   *Maj = SB_VersMaj;
663   *Min = SB_VersMin;
664 }
665 
666 /* Detection Routine */
SB_DetectInitSound(int * dspbits,int * dsprate,int * sndbufsize,unsigned int * direct_buffers,int * stereo_sound)667 int SB_DetectInitSound(int *dspbits, int *dsprate, int *sndbufsize, unsigned int *direct_buffers, int *stereo_sound)
668 {
669   UWORD base,irq,dmalo,dmahi;
670   char *blaster;
671   char *tok;
672   int have_sound;
673   extern void (*SND_DirectWrite)(unsigned int size, int freq);
674 
675   if ((*sndbufsize) > 65536)
676       *sndbufsize = 65536;
677   if ((*sndbufsize) < 4)
678       *sndbufsize = 4;
679   *sndbufsize = ((*sndbufsize)>>2)<<2;
680 
681   blaster = getenv ("BLASTER");
682   if (blaster == NULL)
683   {
684     printf ("No BLASTER variable found!\n"
685 	    "Detecting SoundBlaster Settings...."); fflush (stdout);
686     have_sound = SB_Detect (&base, &irq, &dmalo, &dmahi);
687     if (!have_sound)
688     {
689       printf ("Not found!!\n");
690       return (0);
691     }
692     printf ("Found!  Base: %hx  IRQ: %hd  DMA: %hd,%hd\n",
693 			   base,     irq,    dmalo,dmahi);
694   }
695   else
696   {
697     base = 0; irq = 0; dmalo = 0; dmahi = 0;
698 
699     tok = strtok(blaster, " \t");
700     while (tok != NULL)
701     {
702       switch (toupper(*tok))
703       {
704       case 'A': sscanf(tok+1, "%hx", &base);  break;
705       case 'I': sscanf(tok+1, "%hd", &irq);   break;
706       case 'D': sscanf(tok+1, "%hd", &dmalo); break;
707       case 'H': sscanf(tok+1, "%hd", &dmahi); break;
708       default: break;
709       }
710       tok = strtok (NULL, " \t");
711     }
712     printf ("SoundBlaster Settings taken from BLASTER variable:\n"
713 	    "  Base: %hx  IRQ: %hd  DMA: %hd,%hd\n", base,irq,dmalo,dmahi);
714   }
715 
716   if (!SB_InitBuffers(*sndbufsize))
717   {
718       fprintf(stderr, "Can't set sound buffers to %d!\n", *sndbufsize);
719       return(0);
720   }
721 
722   have_sound = SB_Init (base, irq, dmalo, dmahi);
723   if (!have_sound)
724   {
725     printf ("Cannot Initialize Soundblaster!\n");
726     return (0);
727   }
728 
729   if (((*dspbits) == 16) && (SB_SetBits (16)))
730     SB_SetSigned (1);
731   else
732     *dspbits = 8;
733 
734   if (*stereo_sound) {
735      *stereo_sound = SB_SetChannels(2);
736      if (!(*stereo_sound))
737 	 fprintf(stderr, "Warning, stereo not suporeted!\n");
738   }
739 
740   if (!SB_SetRate(*dsprate))
741   {
742       fprintf(stderr, "SoundBlaster%s can't use sample rate %d!\n",
743 	       SB_Type==SB_Type_StdSB ? "" :
744 	      (SB_Type==SB_Type_SbPro ? " PRO" : " 16"),
745 	      *dsprate);
746       return(0);
747   }
748 
749   printf ("SoundBlaster%s found.\n",
750 	   SB_Type==SB_Type_StdSB ? "" :
751 	  (SB_Type==SB_Type_SbPro ? " PRO" : " 16"));
752 
753   SND_DirectWrite = SB_DirectWrite;
754   direct_buffers[0] = dma_buf[0].Data;
755   direct_buffers[1] = dma_buf[1].Data;
756 
757   atexit (SB_Done);
758 
759   return 1;
760 }
761 
762 /* that's it... */
763