Annotation of uae/src/dos-sb.c, revision 1.1.1.1

1.1       root        1:  /*
                      2:   * UAE - The Un*x Amiga Emulator
                      3:   *
                      4:   * DOS Sound Blaster interface.
                      5:   *
                      6:   * (c) 1996 Peter Remmers
                      7:   */
                      8: 
                      9: #include "sysconfig.h"
                     10: #include "sysdeps.h"
                     11: 
                     12: #include <stdlib.h>
                     13: #include <stdio.h>
                     14: #include <string.h>
                     15: #include <ctype.h>
                     16: #include <dos.h>
                     17: #include <pc.h>
                     18: #include <sys/farptr.h>
                     19: #include <dpmi.h>
                     20: #include <go32.h>
                     21: 
                     22: #include "dos-sb.h"
                     23: #include "dos-dma.h"   
                     24: 
                     25: /* some useful macros */
                     26: #define LOBYTE(x) ((UBYTE)(((UWORD)(x)) &  0xFF))
                     27: #define HIBYTE(x) ((UBYTE)(((UWORD)(x)) >> 8))
                     28: #define LOWORD(x) ((UWORD)(((ULONG)(x)) & 0xFFFF))
                     29: #define HIWORD(x) ((UWORD)(((ULONG)(x)) >> 16))
                     30: #define NUMPARAS(bytesize) (((bytesize)+15) >> 4)
                     31: 
                     32: #ifndef TRUE
                     33: #define TRUE 1
                     34: #endif
                     35: #ifndef FALSE
                     36: #define FALSE 0
                     37: #endif
                     38: 
                     39: /* Offsets relative to base I/O address. */
                     40: #define SB_MIXER_ADDRESS        0x04
                     41: #define SB_MIXER_DATA           0x05
                     42: #define SB_DSP_RESET            0x06
                     43: #define SB_DSP_READ_DATA        0x0A
                     44: #define SB_DSP_WRITE_DATA       0x0C
                     45: #define SB_DSP_WRITE_STATUS     0x0C
                     46: #define SB_DSP_DATA_AVAIL       0x0E
                     47: #define SB_DSP_INT_CLEAR        0x0F
                     48: 
                     49: /* DSP Commands */
                     50: #define CMD_PLAY_8BIT                0x14
                     51: #define CMD_SET_TIME_CONSTANT        0x40
                     52: #define CMD_DEFINE_SILENCE_BLOCK     0x80
                     53: #define CMD_PAUSE_8BIT_DMA           0xD0
                     54: #define CMD_CONTINUE_8BIT_DMA        0xD4
                     55: #define CMD_SPEAKER_ON               0xD1
                     56: #define CMD_SPEAKER_OFF              0xD3
                     57: #define CMD_GET_SPEAKER_SETTING      0xD8
                     58: #define CMD_DSP_VER                  0xE1
                     59: 
                     60: /* SbPro-only commands */
                     61: #define CMD_SET_BLOCK_SIZE           0x48
                     62: #define CMD_PLAY_8BIT_HISPEED        0x91
                     63: 
                     64: /* SB16-only commands */
                     65: #define CMD_SET_OUTPUT_RATE          0x41
                     66: #define CMD_PLAY_16BIT_SINGLE        0xB0
                     67: #define CMD_PLAY_16BIT_AUTOINIT      0xB6
                     68: #define CMD_PLAY_8BIT_SINGLE         0xC0
                     69: #define CMD_PLAY_8BIT_AUTOINIT       0xC6
                     70: #define CMD_PAUSE_16BIT_DMA          0xD5
                     71: #define CMD_CONTINUE_16BIT_DMA       0xD6
                     72: 
                     73: #define DMA_BUF_SIZE     14700 /* absolute maximum (FIFO_BUF_SIZE / 3) */
                     74: #define FIFO_BUF_SIZE    58800 /* max size for 1/4th second sound at   */
                     75:                                /* 44100Hz 16Bits Stereo                */
                     76: #define DESIRED_INT_RATE 70 /* The interrupt rate in Hz. The block size is  */
                     77:                             /* calculated from sampling rate and this value */
                     78: 
                     79: typedef void (*tPlayProc)(UWORD bytes);
                     80: typedef struct
                     81: {
                     82:   ULONG Data;
                     83:   UWORD Size;
                     84: }
                     85: tDMABuffer;
                     86: 
                     87: tSBType SB_Type;
                     88: 
                     89: UWORD SB_Base;      /* the Base Address  e.g. 220h                         */
                     90: UWORD SB_IRQ;       /* The IRQ           e.g. 5                            */
                     91: UWORD SB_DMAlo;     /* Low DMA channel   e.g. 1                            */
                     92: UWORD SB_DMAhi;     /* high DMA channel  e.g. 5                            */
                     93: UWORD SB_INT;       /* The Interrupt vector corresponding to IRQ e.g. 0Dh  */
                     94: UWORD SB_DMA;       /* The current DMA channel                             */
                     95:                     /* (depends on if we're playing 8Bit or 16Bit sound)   */
                     96: UBYTE SB_VersMaj;   /* Major DSP Version byte                              */
                     97: UBYTE SB_VersMin;   /* Minor DSP Version byte                              */
                     98: UBYTE SB_ModeByte;  /* Mode Byte for SB16 (Mono/Stereo, Signed/Unsigned )  */
                     99: UBYTE SB_StopByte;  /* DSP command to stop DMA                             */
                    100: UBYTE SB_ContByte;  /* DSP command to continue DMA                         */
                    101: UWORD SB_IntClearPort; /* SB Port to read from to acknoledge interrupt     */
                    102: 
                    103: tPlayProc SB_Single_Play_Proc; /* single-cycle        play function */
                    104: tPlayProc SB_Play_Proc;        /* autoinitialized DMA play function */
                    105: 
                    106: volatile int           SB_Playing;      /* Sound is currently playing    */
                    107: volatile unsigned long SB_Bytes_Played; /* number of bytes played so far */
                    108: 
                    109: volatile tDMABuffer dma_buf[2]; /* the two DMA buffers                  */
                    110: volatile UBYTE active_buf;      /* the currently playing buffer         */
                    111: volatile UBYTE last_buf;        /* last buffer to play                  */
                    112: volatile UWORD last_block_size; /* size of the previously played block  */
                    113: UWORD dma_block_size;           /* size of one DMA block                */
                    114: 
                    115: UBYTE fifobuf[FIFO_BUF_SIZE];   /* a ring buffer for sound buffering      */
                    116: UWORD fifo_max;                 /* max fill size of fifo buffer           */
                    117: UWORD fifo_write_index;         /* the index to write to the fifo buffer  */
                    118: UWORD fifo_read_index;          /* the index to read from the fifo buffer */
                    119: volatile UWORD fifo_size;       /* the current fill size                  */
                    120: 
                    121: BOOL  SB_Autoinit;    /* we're currently using autoinitialized DMA mode   */
                    122: BOOL  SB_Stopped;     /* Sound is stopped                                 */
                    123: BOOL  SB_16Bit;       /* we're playing in 16 Bits                         */
                    124: BOOL  SB_Stereo;      /* we're playing in stereo                          */
                    125: UWORD SB_Active_Rate; /* the active sampling rate                         */
                    126: 
                    127: volatile UBYTE IRQ_Detected; /* the detected IRQ number                   */
                    128: 
                    129: _go32_dpmi_registers cb_regs;    /* the registers for the int handler */
                    130: _go32_dpmi_seginfo   old_pmint;  /* the old interrupt handler         */
                    131: _go32_dpmi_seginfo   pm_wrapper; /* the new interrupt handler         */
                    132: _go32_dpmi_seginfo   dma_mem;    /* info for DMA memory               */
                    133: 
                    134: /* Reset SB at SB_Base, returns TRUE if it worked */
                    135: BOOL SB_Reset(void)
                    136: {
                    137:   outportb (SB_Base+SB_DSP_RESET, 1);
                    138:   delay(10);
                    139:   outportb (SB_Base+SB_DSP_RESET, 0);
                    140:   delay(100);
                    141:   return (inportb(SB_Base+SB_DSP_READ_DATA) == 0xAA);
                    142: }
                    143: 
                    144: /* Write a command to DSP chip */
                    145: void SB_WriteDSP (UBYTE value)
                    146: {
                    147:   while (inportb(SB_Base + SB_DSP_WRITE_STATUS) & 0x80);
                    148:   outportb (SB_Base + SB_DSP_WRITE_DATA, value);
                    149: }
                    150: 
                    151: /* read a byte from DSP chip */
                    152: UBYTE SB_ReadDSP (void)
                    153: {
                    154:   while (!(inportb (SB_Base + SB_DSP_DATA_AVAIL) & 0x80));
                    155:   return  (inportb (SB_Base + SB_DSP_READ_DATA));
                    156: }
                    157: 
                    158: /* write a value to the mixer chip */
                    159: void SB_WriteMixer (UBYTE reg, UBYTE data)
                    160: {
                    161:   outportb (SB_Base + SB_MIXER_ADDRESS, reg);
                    162:   outportb (SB_Base + SB_MIXER_DATA,    data);
                    163: }
                    164: 
                    165: /* read a value from the mixer chip */
                    166: UBYTE SB_ReadMixer (UBYTE reg)
                    167: {
                    168:   outportb (SB_Base + SB_MIXER_ADDRESS, reg);
                    169:   return (inportb (SB_Base + SB_MIXER_DATA));
                    170: }
                    171: 
                    172: /* try to detect, if SB has a mixer chip, returns TRUE if found */
                    173: BOOL SB_DetectMixer (void)
                    174: {
                    175:   UBYTE orgval;
                    176:   
                    177:   orgval = SB_ReadMixer (0x22);
                    178:   
                    179:   SB_WriteMixer (0x22, 0);
                    180:   if (SB_ReadMixer (0x22) != 0) return (FALSE);
                    181:   
                    182:   SB_WriteMixer (0x22, 0xEE);
                    183:   if (SB_ReadMixer (0x22) != 0xEE) return (FALSE);
                    184:   
                    185:   SB_WriteMixer (0x22, orgval);
                    186:   
                    187:   return (TRUE);
                    188: }
                    189: 
                    190: /* read a byte from the fifo buffer */
                    191: UBYTE fifo_read (void)
                    192: {
                    193:   UBYTE ret;
                    194:   
                    195:   if (fifo_size == 0) return(0);
                    196:   ret = fifobuf[fifo_read_index++];
                    197:   if (fifo_read_index == fifo_max) fifo_read_index = 0;
                    198:   fifo_size--;
                    199:   
                    200:   return (ret);
                    201: }
                    202: 
                    203: /* write a byte to the fifo buffer */
                    204: void fifo_write (UBYTE val)
                    205: {
                    206:   if (fifo_size == fifo_max) return;
                    207:   fifobuf[fifo_write_index++] = val;
                    208:   if (fifo_write_index == fifo_max) fifo_write_index = 0;
                    209:   fifo_size++;
                    210: }
                    211: 
                    212: /* fill a DMA buffer with data from the fifo buffer   */
                    213: /* if fifo buffer is empty after this, the DMA buffer */
                    214: /* is marked to be the last one to be played          */
                    215: void fill_buffer (UBYTE buf)
                    216: {
                    217:   register int   i;
                    218:   register UWORD size;
                    219:   register ULONG p;
                    220:   
                    221:   if (fifo_size == 0) return;
                    222: 
                    223:   disable();
                    224: 
                    225:   if (fifo_size < dma_block_size) size = fifo_size;
                    226:                              else size = dma_block_size;
                    227:   dma_buf[buf].Size = size;
                    228: 
                    229:   p = dma_buf[buf].Data;
                    230: 
                    231:   _farsetsel (_dos_ds);
                    232:   for (i=0; i < size; i++) _farnspokeb (p++, fifo_read());
                    233: 
                    234:   if (fifo_size == 0) last_buf = buf;
                    235: 
                    236:   enable ();
                    237: }
                    238: 
                    239: /* play a block in 8 Bits on a Standard SB */
                    240: void SB_Play_8Bit_Std (UWORD bytes)
                    241: {
                    242:   SB_WriteDSP (CMD_PLAY_8BIT);
                    243:   SB_WriteDSP (LOBYTE (bytes-1));
                    244:   SB_WriteDSP (HIBYTE (bytes-1));
                    245: }
                    246: 
                    247: /* Play a block in 8 Bits on an SB PRO */
                    248: void SB_Play_8Bit_SbPro (UWORD bytes)
                    249: {
                    250:   if (bytes != last_block_size)
                    251:   {
                    252:     SB_WriteDSP (CMD_SET_BLOCK_SIZE);
                    253:     SB_WriteDSP (LOBYTE (bytes-1));
                    254:     SB_WriteDSP (HIBYTE (bytes-1));
                    255:     last_block_size = bytes;
                    256:   }
                    257:   SB_WriteDSP (CMD_PLAY_8BIT_HISPEED);
                    258: }
                    259: 
                    260: /* play a block in 8 Bits on an SB 16 */
                    261: void SB_Play_8Bit_SB16 (UWORD bytes)
                    262: {
                    263:   SB_WriteDSP (CMD_PLAY_8BIT_SINGLE);
                    264:   SB_WriteDSP (SB_ModeByte);
                    265:   SB_WriteDSP (LOBYTE (bytes-1));
                    266:   SB_WriteDSP (HIBYTE (bytes-1));
                    267: }
                    268: 
                    269: /* play a block in 8 Bits on an SB 16 using autoinitialized DMA */
                    270: void SB_Play_8Bit_SB16_Autoinit (UWORD bytes)
                    271: {
                    272:   SB_WriteDSP (CMD_PLAY_8BIT_AUTOINIT);
                    273:   SB_WriteDSP (SB_ModeByte);
                    274:   SB_WriteDSP (LOBYTE (bytes-1));
                    275:   SB_WriteDSP (HIBYTE (bytes-1));
                    276: }
                    277: 
                    278: /* play a block in 16 Bits on an SB 16 */
                    279: void SB_Play_16Bit (UWORD bytes)
                    280: {
                    281:   SB_WriteDSP (CMD_PLAY_16BIT_SINGLE);
                    282:   SB_WriteDSP (SB_ModeByte);
                    283:   SB_WriteDSP (LOBYTE ((bytes>>1) -1));
                    284:   SB_WriteDSP (HIBYTE ((bytes>>1) -1));
                    285: }
                    286: 
                    287: /* play a block in 16 Bits on an SB 16 using autoinitialized DMA */
                    288: void SB_Play_16Bit_Autoinit (UWORD bytes)
                    289: {
                    290:   SB_WriteDSP (CMD_PLAY_16BIT_AUTOINIT);
                    291:   SB_WriteDSP (SB_ModeByte);
                    292:   SB_WriteDSP (LOBYTE ((bytes>>1) -1));
                    293:   SB_WriteDSP (HIBYTE ((bytes>>1) -1));
                    294: }
                    295: 
                    296: /* the interrupt handler for playing in single-cycle mode */
                    297: void SB_IntHandler_Single (void)
                    298: {
                    299:   UBYTE h = 1-active_buf;
                    300: 
                    301:   if (last_buf != 0xFF && fifo_size > 0)
                    302:   {
                    303:     last_buf        = 0xFF;
                    304:     last_block_size = 0;
                    305: 
                    306:     /* if we just played the last block and there's already new data */
                    307:     /* in the fifo buffer, then continue playing with the new data   */
                    308:     if (active_buf == last_buf)
                    309:     {
                    310:       fill_buffer (0);
                    311:       DMA_InitTransfer (SB_DMA, DMA_READ_AUTOINIT,
                    312:                         dma_buf[0].Data, dma_block_size*2);
                    313:       h = 0;
                    314:     }
                    315:   }
                    316: 
                    317:   (*SB_Single_Play_Proc) (dma_buf[h].Size);
                    318:   fill_buffer (active_buf);
                    319:   active_buf = h;
                    320: }
                    321: 
                    322: /* interrupt handler for playing in autoinitialized DMA mode */
                    323: void SB_IntHandler_Autoinit (void)
                    324: {
                    325:   if (last_buf != 0xFF)
                    326:   {
                    327:     if (active_buf == last_buf && fifo_size > 0)
                    328:     {
                    329:       last_buf   = 0xFF;
                    330:       active_buf = 0;
                    331: 
                    332:       DMA_InitTransfer (SB_DMA, DMA_READ_AUTOINIT,
                    333:                         dma_buf[0].Data, dma_block_size*2);
                    334: 
                    335:       fill_buffer (0);
                    336:       if (fifo_size == 0)
                    337:         (*SB_Single_Play_Proc) (dma_buf[0].Size);
                    338:       else
                    339:       {
                    340:         (*SB_Play_Proc) (dma_block_size);
                    341:         fill_buffer(1);
                    342:         if (fifo_size == 0)
                    343:           (*SB_Single_Play_Proc) (dma_buf[1].Size);
                    344:       }
                    345:     }
                    346:     else active_buf = 1 - active_buf;
                    347:   }
                    348:   else
                    349:   {
                    350:     fill_buffer (active_buf);
                    351:   
                    352:     if (active_buf == last_buf)
                    353:       (*SB_Single_Play_Proc) (dma_buf[active_buf].Size);
                    354:   
                    355:     active_buf = 1 - active_buf;
                    356:   }
                    357: }
                    358: 
                    359: /* the main interrupt handler */
                    360: void SB_IntHandler (void)
                    361: {
                    362:   SB_Bytes_Played += dma_buf[active_buf].Size;
                    363:   
                    364:   if (active_buf == last_buf && fifo_size == 0) SB_Playing = FALSE;
                    365:   else if (SB_Autoinit)                         SB_IntHandler_Autoinit();
                    366:   else                                          SB_IntHandler_Single();
                    367: 
                    368:   inportb (SB_IntClearPort);
                    369:   if (SB_IRQ > 7) outportb (0xA0, 0x20);
                    370: 
                    371:   outportb (0x20, 0x20);
                    372:   enable();
                    373: }
                    374: 
                    375: /* set sampling rate on a standard SB */
                    376: void SB_SetRate_LoSpeed (UWORD rate)
                    377: {
                    378:   SB_WriteDSP (CMD_SET_TIME_CONSTANT);
                    379:   SB_WriteDSP (0x100 - 1000000 / rate);
                    380: }
                    381: 
                    382: /* set sampling rate on a SB PRO */
                    383: void SB_SetRate_HiSpeed (UWORD rate)
                    384: {
                    385:   SB_WriteDSP (CMD_SET_TIME_CONSTANT);
                    386:   SB_WriteDSP (HIBYTE (0x10000 - 256000000 / rate));
                    387: }
                    388: 
                    389: /* set sampling rate on an SB 16 */
                    390: void SB_SetRate_SB16 (UWORD rate)
                    391: {
                    392:   SB_WriteDSP (CMD_SET_OUTPUT_RATE);
                    393:   SB_WriteDSP (HIBYTE (rate));
                    394:   SB_WriteDSP (LOBYTE (rate));
                    395: }
                    396: 
                    397: /* calculates the DMA block size and the fifo size   */
                    398: /* from sampling rate and the desired interrupt rate */
                    399: void calculate_buf_sizes(void)
                    400: {
                    401:   ULONG rate;
                    402: 
                    403:   rate = SB_Active_Rate;
                    404:   if (SB_16Bit)  rate <<= 1;
                    405:   if (SB_Stereo) rate <<= 1;
                    406:   /* rate is now bytes per second */
                    407:   dma_block_size = (rate / DESIRED_INT_RATE) & ~3; /* make multiples of 4 */
                    408:   dma_buf[1].Data = dma_buf[0].Data + dma_block_size;
                    409:   fifo_max = rate / 4; /* make fifo size 1/4th second of sound */
                    410: }
                    411: 
                    412: /* set the sampling rate */
                    413: int SB_SetRate (unsigned short rate)
                    414: {
                    415:   if (rate > 23000 && SB_Type < SB_Type_SbPro) return(FALSE);
                    416: 
                    417:   switch (SB_Type)
                    418:   {
                    419:   case SB_Type_StdSB: SB_SetRate_LoSpeed (rate); break;
                    420:   case SB_Type_SbPro: SB_SetRate_HiSpeed (rate); break;
                    421:   case SB_Type_SB16:  SB_SetRate_SB16    (rate); break;
                    422:   }
                    423: 
                    424:   SB_Active_Rate = rate;
                    425:   
                    426:   calculate_buf_sizes();
                    427: 
                    428:   return (TRUE);
                    429: }
                    430: 
                    431: /* set the number of bits, i.e. 8 Bit / 16 Bit mode */
                    432: int SB_SetBits (unsigned char bits)
                    433: {
                    434:   if (bits==16 && SB_Type < SB_Type_SB16) return (FALSE);
                    435: 
                    436:   if (SB_Type == SB_Type_SB16)
                    437:   {
                    438:     if (bits==16)
                    439:     {
                    440:       SB_Play_Proc        = SB_Play_16Bit_Autoinit;
                    441:       SB_Single_Play_Proc = SB_Play_16Bit;
                    442:       SB_IntClearPort     = SB_Base + SB_DSP_INT_CLEAR;
                    443:       SB_DMA              = SB_DMAhi;
                    444:       SB_StopByte         = CMD_PAUSE_16BIT_DMA;
                    445:       SB_ContByte         = CMD_CONTINUE_16BIT_DMA;
                    446:       SB_16Bit            = TRUE;
                    447:     }
                    448:     else
                    449:     {
                    450:       SB_Play_Proc        = SB_Play_8Bit_SB16_Autoinit;
                    451:       SB_Single_Play_Proc = SB_Play_8Bit_SB16;
                    452:       SB_IntClearPort     = SB_Base + SB_DSP_DATA_AVAIL;
                    453:       SB_DMA              = SB_DMAlo;
                    454:       SB_StopByte         = CMD_PAUSE_8BIT_DMA;
                    455:       SB_ContByte         = CMD_CONTINUE_8BIT_DMA;
                    456:       SB_16Bit            = FALSE;
                    457:     }
                    458:   }
                    459: 
                    460:   calculate_buf_sizes();
                    461: 
                    462:   return (TRUE);
                    463: }
                    464: 
                    465: /* set the number of channels, i.e. Mono / Stereo */
                    466: int SB_SetChannels (unsigned char channels)
                    467: {
                    468:   if (channels==2 && SB_Type < SB_Type_SbPro) return (FALSE);
                    469: 
                    470:   switch (SB_Type)
                    471:   {
                    472:   case SB_Type_StdSB: break;
                    473:   
                    474:   case SB_Type_SbPro:
                    475:     if (channels==2) SB_WriteMixer (0x0E, SB_ReadMixer (0x0E) | 0x02);
                    476:                 else SB_WriteMixer (0x0E, SB_ReadMixer (0x0E) & 0xFD);
                    477:     break;
                    478:     
                    479:   case SB_Type_SB16:
                    480:     if (channels==2) SB_ModeByte |= 0x20;
                    481:                 else SB_ModeByte &= 0xDF;
                    482:     break;
                    483:   }
                    484:   SB_Stereo = (channels==2);
                    485: 
                    486:   calculate_buf_sizes();
                    487: 
                    488:   return (TRUE);
                    489: }
                    490: 
                    491: /* set Signed / Unsigned mode (only on SB 16) */
                    492: int SB_SetSigned (int sign)
                    493: {
                    494:   if (sign && SB_Type < SB_Type_SB16) return (FALSE);
                    495:   
                    496:   if (SB_Type == SB_Type_SB16)
                    497:   {
                    498:     if (sign) SB_ModeByte |= 0x10;
                    499:          else SB_ModeByte &= 0xEF;
                    500:   }
                    501:   return (TRUE);
                    502: }
                    503: 
                    504: /* turn speaker off (doesn't seem to work on SB 16) */
                    505: void SB_SpeakerOff(void)
                    506: {
                    507:   SB_WriteDSP(CMD_SPEAKER_OFF);
                    508: }
                    509: 
                    510: /* turn speaker on (doesn't seem to work on SB 16) */
                    511: void SB_SpeakerOn(void)
                    512: {
                    513:   SB_WriteDSP(CMD_SPEAKER_ON);
                    514: }
                    515: 
                    516: /* start playing the sound data in the fifo buffer */
                    517: void SB_Play (void)
                    518: {
                    519:   if (fifo_size == 0) return;
                    520:   
                    521:   active_buf      = 0;
                    522:   last_buf        = 0xFF;
                    523:   last_block_size = 0;
                    524:   
                    525:   DMA_InitTransfer (SB_DMA, DMA_READ_AUTOINIT,
                    526:                     dma_buf[0].Data, dma_block_size*2);
                    527:   if (SB_Autoinit)
                    528:   {
                    529:     fill_buffer (0);
                    530:     if (fifo_size == 0)
                    531:       (*SB_Single_Play_Proc) (dma_buf[0].Size);
                    532:     else
                    533:     {
                    534:       (*SB_Play_Proc) (dma_block_size);
                    535:       fill_buffer(1);
                    536:       if (fifo_size == 0) (*SB_Single_Play_Proc) (dma_buf[1].Size);
                    537:     }
                    538:   }
                    539:   else
                    540:   {
                    541:     fill_buffer(0);
                    542:     (*SB_Single_Play_Proc) (dma_buf[0].Size);
                    543:     fill_buffer(1);
                    544:   }
                    545:   
                    546:   SB_Playing = TRUE;  
                    547: }
                    548: 
                    549: /* interrupt handler functions used for IRQ/DMA detection */
                    550: void irq2 (void)
                    551: {
                    552:   IRQ_Detected = 2;
                    553:   inportb (SB_IntClearPort);
                    554:   outportb (0x20, 0x20);
                    555: }
                    556: void irq5 (void)
                    557: {
                    558:   IRQ_Detected = 5;
                    559:   inportb (SB_IntClearPort);
                    560:   outportb (0x20, 0x20);
                    561: }
                    562: void irq7 (void)
                    563: {
                    564:   IRQ_Detected = 7;
                    565:   inportb (SB_IntClearPort);
                    566:   outportb (0x20, 0x20);
                    567: }
                    568: void irq10 (void)
                    569: {
                    570:   IRQ_Detected = 10;
                    571:   inportb (SB_IntClearPort);
                    572:   outportb (0xA0, 0x20);
                    573:   outportb (0x20, 0x20);
                    574: }
                    575: 
                    576: /* detect the sound blaster Base/IRQ/DMA settings (may hang computer) */
                    577: int SB_Detect (unsigned short *base, unsigned short *irq, 
                    578:                unsigned short *dmalo, unsigned short *dmahi)
                    579: {
                    580: #define TESTBUFSIZE 0x80
                    581:   static const UBYTE lowdma[3]  = { 1,3,0 };
                    582:   static const UBYTE highdma[3] = { 5,6,7 };
                    583:   
                    584:   UBYTE old21,oldA1,old0F,oldDE;
                    585:   _go32_dpmi_seginfo oldirq2,oldirq5,oldirq7,oldirq10;
                    586:   _go32_dpmi_seginfo newirq2,newirq5,newirq7,newirq10;
                    587:   _go32_dpmi_seginfo testbuf_info;
                    588:   ULONG testbuf;
                    589:   int   ret1,ret2,ret3,ret4;
                    590:   UBYTE i;
                    591:   BOOL  found;
                    592: 
                    593:   found = FALSE;
                    594: 
                    595:   *base  = 0;
                    596:   *irq   = 0;
                    597:   *dmalo = 0;
                    598:   *dmahi = 0;
                    599:   
                    600:   SB_Base = 0x210;
                    601:   while (SB_Base != 0x290)
                    602:   {
                    603:     if (SB_Reset()) break;
                    604:     SB_Base += 0x10;
                    605:   }
                    606:   if (SB_Base == 0x290) return (FALSE);
                    607:   *base = SB_Base;
                    608:   
                    609:   /* install detection interrupt handlers */
                    610:   newirq2.pm_offset  = (int) irq2;
                    611:   newirq5.pm_offset  = (int) irq5;
                    612:   newirq7.pm_offset  = (int) irq7;
                    613:   newirq10.pm_offset = (int) irq10;
                    614:   
                    615:   ret1 = _go32_dpmi_allocate_iret_wrapper (&newirq2);
                    616:   ret2 = _go32_dpmi_allocate_iret_wrapper (&newirq5);
                    617:   ret3 = _go32_dpmi_allocate_iret_wrapper (&newirq7);
                    618:   ret4 = _go32_dpmi_allocate_iret_wrapper (&newirq10);
                    619:   
                    620:   if (ret1|ret2|ret3|ret4)
                    621:   {
                    622:     if (!ret1) _go32_dpmi_free_iret_wrapper (&newirq2);
                    623:     if (!ret2) _go32_dpmi_free_iret_wrapper (&newirq5);
                    624:     if (!ret3) _go32_dpmi_free_iret_wrapper (&newirq7);
                    625:     if (!ret4) _go32_dpmi_free_iret_wrapper (&newirq10);
                    626:     return (FALSE);
                    627:   }
                    628:   _go32_dpmi_lock_code (irq2, (int)SB_Detect - (int)irq2);
                    629:   _go32_dpmi_lock_data ((void*)&IRQ_Detected,    sizeof(IRQ_Detected));
                    630:   _go32_dpmi_lock_data (&SB_IntClearPort, sizeof(SB_IntClearPort));
                    631: 
                    632:   _go32_dpmi_get_protected_mode_interrupt_vector (0x0A, &oldirq2);
                    633:   _go32_dpmi_get_protected_mode_interrupt_vector (0x0D, &oldirq5);
                    634:   _go32_dpmi_get_protected_mode_interrupt_vector (0x0F, &oldirq7);
                    635:   _go32_dpmi_get_protected_mode_interrupt_vector (0x72, &oldirq10);
                    636: 
                    637:   _go32_dpmi_set_protected_mode_interrupt_vector (0x0A, &newirq2);
                    638:   _go32_dpmi_set_protected_mode_interrupt_vector (0x0D, &newirq5);
                    639:   _go32_dpmi_set_protected_mode_interrupt_vector (0x0F, &newirq7);
                    640:   _go32_dpmi_set_protected_mode_interrupt_vector (0x72, &newirq10);
                    641: 
                    642:   testbuf_info.size = NUMPARAS(TESTBUFSIZE);
                    643:   testbuf = DMA_AllocDMABuf (&testbuf_info);
                    644: 
                    645:   /* turn on interrupts 2,5,7 and 10 */
                    646:   old21 = inportb (0x21);
                    647:   oldA1 = inportb (0xA1);
                    648:   outportb (0x21, old21 & 0x5B);
                    649:   outportb (0xA1, oldA1 & 0xFB);
                    650:   
                    651:   /* turn off DMA 0,1,3,5,6 and 7 */
                    652:   old0F = inportb (0x0F);
                    653:   oldDE = inportb (0xDE);
                    654:   outportb (0x0F, old0F | 0x0B);
                    655:   outportb (0xDE, oldDE | 0x0E);
                    656:   
                    657:   /* fill testbuffer with silence */
                    658:   _farsetsel (_dos_ds);
                    659:   for (i=0; i<TESTBUFSIZE; i++) _farnspokeb (testbuf+i, 128);
                    660:   
                    661:   /* detect low DMA and IRQ */
                    662:   SB_IntClearPort = SB_Base + SB_DSP_DATA_AVAIL;
                    663:   SB_SetRate_LoSpeed (22050);
                    664:   /* program SB to play testbuffer, will start playing */
                    665:   /* when we hit the right DMA channel                 */
                    666:   SB_Play_8Bit_Std (TESTBUFSIZE);
                    667:                                   
                    668:   /* test all DMA channels */
                    669:   IRQ_Detected = 0;
                    670:   for (i=0; i<3; i++)
                    671:   {
                    672:     DMA_InitTransfer (lowdma[i], DMA_READ, testbuf, TESTBUFSIZE);
                    673:     delay (TESTBUFSIZE*2000 / 22050);
                    674:     if (IRQ_Detected)
                    675:     {
                    676:       *dmalo = lowdma[i];
                    677:       *irq   = IRQ_Detected;
                    678:       break;
                    679:     }
                    680:   }
                    681:   
                    682:   if (IRQ_Detected)
                    683:   {
                    684:     found = TRUE;
                    685: 
                    686:     SB_WriteDSP (CMD_DSP_VER);
                    687:     SB_VersMaj = SB_ReadDSP();
                    688:     SB_VersMin = SB_ReadDSP();
                    689:     
                    690:     /* if SoundBlaster is an SB16 then test high DMA channel */
                    691:     if (SB_VersMaj >= 4)
                    692:     {
                    693:       outportb (0x0F, old0F | 0x0B);
                    694:       outportb (0xDE, oldDE | 0x0E);
                    695:       
                    696:       _farsetsel (_dos_ds);
                    697:       for (i=0; i<TESTBUFSIZE; i+=2) _farnspokew (testbuf+i, 0x8000);
                    698:   
                    699:       SB_ModeByte = 0x00;
                    700:       SB_IntClearPort = SB_Base + SB_DSP_INT_CLEAR;
                    701:       SB_SetRate_SB16(44100);
                    702:       SB_Play_16Bit(TESTBUFSIZE);
                    703:       
                    704:       IRQ_Detected = 0;
                    705:       for (i=0; i<3; i++)
                    706:       {
                    707:         DMA_InitTransfer (highdma[i], DMA_READ, testbuf, TESTBUFSIZE);
                    708:         delay (TESTBUFSIZE*1000 / 44100);
                    709:         if (IRQ_Detected)
                    710:         {
                    711:           *dmahi = highdma[i];
                    712:           break;
                    713:         }
                    714:       }
                    715:       if (!IRQ_Detected) *dmahi = *dmalo;
                    716:     }
                    717:   }
                    718:   
                    719:   /* clean up */
                    720:   _go32_dpmi_free_dos_memory (&testbuf_info);
                    721:   
                    722:   outportb (0x0F, old0F);
                    723:   outportb (0xDE, oldDE);
                    724:   outportb (0x21, old21);
                    725:   outportb (0xA1, oldA1);
                    726:   
                    727:   _go32_dpmi_set_protected_mode_interrupt_vector (0x0A, &oldirq2);
                    728:   _go32_dpmi_set_protected_mode_interrupt_vector (0x0D, &oldirq5);
                    729:   _go32_dpmi_set_protected_mode_interrupt_vector (0x0F, &oldirq7);
                    730:   _go32_dpmi_set_protected_mode_interrupt_vector (0x72, &oldirq10);
                    731:   
                    732:   _go32_dpmi_free_iret_wrapper (&newirq2);
                    733:   _go32_dpmi_free_iret_wrapper (&newirq5);
                    734:   _go32_dpmi_free_iret_wrapper (&newirq7);
                    735:   _go32_dpmi_free_iret_wrapper (&newirq10);
                    736:   
                    737:   return (found);
                    738: }
                    739: 
                    740: /* init Sound blaster using the given settings */
                    741: int SB_Init (unsigned short base, unsigned short irq, 
                    742:              unsigned short dmalo, unsigned short dmahi)
                    743: {
                    744:   SB_Base  = base;
                    745:   SB_IRQ   = irq;
                    746:   SB_DMAlo = dmalo;
                    747:   SB_DMAhi = dmahi;
                    748: 
                    749:   if (SB_IRQ > 7) SB_INT = 0x68 + SB_IRQ;
                    750:              else SB_INT = 0x08 + SB_IRQ;
                    751: 
                    752: 
                    753:   if (!SB_Reset()) return (FALSE);
                    754: 
                    755:   dma_mem.size = NUMPARAS(DMA_BUF_SIZE);
                    756:   dma_buf[0].Data = DMA_AllocDMABuf (&dma_mem);
                    757:   
                    758:   if (dma_buf[0].Data == NULL)
                    759:   {
                    760:     printf ("Cannot allocate DOS Memory for DMA buffers!\n");
                    761:     return (FALSE);
                    762:   }
                    763:     
                    764:   fifo_write_index = 0;
                    765:   fifo_read_index  = 0;
                    766:   fifo_size        = 0;
                    767: 
                    768:   pm_wrapper.pm_offset = (int) SB_IntHandler;
                    769:   if (_go32_dpmi_allocate_iret_wrapper (&pm_wrapper))
                    770:   {
                    771:     printf ("Cannot allocate protected mode wrapper for SB interrupt!\n");
                    772:     _go32_dpmi_free_dos_memory (&dma_mem);
                    773:     return (FALSE);
                    774:   }
                    775: 
                    776:   _go32_dpmi_lock_code (SB_WriteDSP, (ULONG)SB_WriteMixer - (ULONG)SB_WriteDSP);
                    777:   _go32_dpmi_lock_code (fifo_read, (ULONG)SB_SetRate_LoSpeed - (ULONG)fifo_read);
                    778:   _go32_dpmi_lock_data (&SB_Base, (ULONG)&old_pmint - (ULONG)&SB_Base);
                    779: 
                    780:   _go32_dpmi_get_protected_mode_interrupt_vector (SB_INT, &old_pmint);
                    781:   _go32_dpmi_set_protected_mode_interrupt_vector (SB_INT, &pm_wrapper);
                    782: 
                    783:   if (SB_IRQ>7)
                    784:     outportb(0xA1, inportb(0xA1) & ~(1 << (SB_IRQ-8)));
                    785:   else
                    786:     outportb(0x21, inportb(0x21) & ~(1 << SB_IRQ));
                    787: 
                    788:   SB_Type = SB_Type_StdSB;
                    789:   
                    790:   if (SB_DetectMixer()) SB_Type = SB_Type_SbPro;
                    791:   
                    792:   SB_WriteDSP (CMD_DSP_VER);
                    793:   SB_VersMaj = SB_ReadDSP ();
                    794:   SB_VersMin = SB_ReadDSP ();
                    795:   
                    796:   if (SB_VersMaj >= 4) SB_Type = SB_Type_SB16;
                    797: 
                    798: //  SB_Type = SB_Type_SbPro;  /* for testing */
                    799:   
                    800:   /* initialize SB to default 8Bit Mono 22050Hz */
                    801:   /* (available on all SoundBlaster Versions)   */
                    802:   switch (SB_Type)
                    803:   {
                    804:   case SB_Type_StdSB:
                    805:     SB_Single_Play_Proc = SB_Play_8Bit_Std;
                    806:     SB_Autoinit         = FALSE;
                    807:     SB_SetRate_LoSpeed(22050);
                    808:     break;
                    809:   case SB_Type_SbPro:
                    810:     SB_Single_Play_Proc = SB_Play_8Bit_SbPro;
                    811:     SB_Autoinit         = FALSE;
                    812:     SB_SetRate_HiSpeed(22050);
                    813:     break;
                    814:   case SB_Type_SB16:
                    815:     SB_Single_Play_Proc = SB_Play_8Bit_SB16;
                    816:     SB_Play_Proc        = SB_Play_8Bit_SB16_Autoinit;
                    817:     SB_Autoinit         = TRUE;
                    818:     SB_SetRate_SB16(22050);
                    819:     break;
                    820:   }
                    821:   SB_IntClearPort = SB_Base + SB_DSP_DATA_AVAIL;
                    822:   SB_DMA          = SB_DMAlo;
                    823:   SB_Playing      = FALSE;
                    824:   SB_Stopped      = FALSE;
                    825:   SB_16Bit        = FALSE;
                    826:   SB_Stereo       = FALSE;
                    827:   SB_Active_Rate  = 22050;
                    828:   SB_ModeByte     = 0x00;
                    829:   SB_StopByte     = CMD_PAUSE_8BIT_DMA;
                    830:   SB_ContByte     = CMD_CONTINUE_8BIT_DMA;
                    831:   SB_Bytes_Played = 0;
                    832: 
                    833:   calculate_buf_sizes();
                    834: 
                    835:   return (TRUE);
                    836: }
                    837: 
                    838: /* clean up Sound Blaster */
                    839: void SB_Done (void)
                    840: {
                    841:   SB_Reset ();
                    842:   if (SB_IRQ > 7)
                    843:     outportb (0xA1, inportb(0xA1) | (1 << (SB_IRQ-8)));
                    844:   else
                    845:     outportb (0x21, inportb(0x21) | (1 << SB_IRQ));
                    846: 
                    847:   _go32_dpmi_set_protected_mode_interrupt_vector (SB_INT, &old_pmint);
                    848:   _go32_dpmi_free_iret_wrapper (&pm_wrapper);
                    849:   _go32_dpmi_free_dos_memory (&dma_mem);
                    850: }
                    851: 
                    852: /* write sound data to be played to the fifo buffer */
                    853: void SB_Write (void *buf, unsigned long size)
                    854: {
                    855: #define MIN(a,b) ((a)<(b) ? (a) : (b))
                    856: 
                    857:   UWORD s;
                    858:   int   i;
                    859: 
                    860:   if (SB_Stopped) SB_Continue();
                    861:   while (size > 0)
                    862:   {
                    863:     s = MIN (size, (UWORD) (fifo_max - dma_block_size));
                    864: 
                    865:     while (fifo_size+s > fifo_max);
                    866:     
                    867:     disable ();
                    868:     for (i=0; i<s; i++) fifo_write (*((UBYTE*)buf)++);
                    869:     enable ();
                    870:     
                    871:     if (!SB_Playing && fifo_size > dma_block_size*2) SB_Play();
                    872: 
                    873:     size -= s;
                    874:   }
                    875: }
                    876: 
                    877: /* start any unplayed sound */
                    878: void SB_Flush (void)
                    879: {
                    880:   if (SB_Stopped) SB_Continue();
                    881:   if (fifo_size>0 && !SB_Playing) SB_Play();
                    882: }
                    883: 
                    884: /* stop/pause sound output */
                    885: void SB_Stop (void)
                    886: {
                    887:   if (SB_Stopped) return;
                    888:   SB_WriteDSP (SB_StopByte);
                    889:   SB_Stopped = TRUE;
                    890: }
                    891: 
                    892: /* continue sound output */
                    893: void SB_Continue (void)
                    894: {
                    895:   if (!SB_Stopped) return;
                    896:   SB_WriteDSP (SB_ContByte);
                    897:   SB_Stopped = FALSE;
                    898: }
                    899: 
                    900: /* return thee DSP chip version */
                    901: void SB_GetVersion (unsigned char *Maj, unsigned char *Min)
                    902: {
                    903:   *Maj = SB_VersMaj;
                    904:   *Min = SB_VersMin;
                    905: }
                    906: 
                    907: /* return the current DMA block size */
                    908: unsigned short SB_GetFragmentSize (void)
                    909: {
                    910:   return (dma_block_size);
                    911: }
                    912: 
                    913: /* return the current fifo buffer size (not the fifo fill size) */
                    914: UWORD SB_GetBufferSize (void)
                    915: {
                    916:   return (fifo_max);
                    917: }
                    918: 
                    919: /* Detection Routine */
                    920: int SB_DetectInitSound(int *dspbits, int *dsprate, int *sndbufsize)
                    921: {
                    922:   UWORD base,irq,dmalo,dmahi;
                    923:   char *blaster;
                    924:   char *tok;
                    925:   int have_sound;
                    926:   extern void (*SND_Write)(void *buf, unsigned long size);
                    927: 
                    928:   blaster = getenv ("BLASTER");
                    929:   if (blaster == NULL)
                    930:   {
                    931:     printf ("No BLASTER variable found!\n"
                    932:            "Detecting SoundBlaster Settings...."); fflush (stdout);
                    933:     have_sound = SB_Detect (&base, &irq, &dmalo, &dmahi);
                    934:     if (!have_sound)
                    935:     {
                    936:       printf ("Not found!!\n");
                    937:       return (0);
                    938:     }
                    939:     printf ("Found!  Base: %hx  IRQ: %hd  DMA: %hd,%hd\n",
                    940:                           base,     irq,    dmalo,dmahi);
                    941:   }
                    942:   else
                    943:   {
                    944:     base = 0; irq = 0; dmalo = 0; dmahi = 0;
                    945: 
                    946:     tok = strtok(blaster, " \t");
                    947:     while (tok != NULL)
                    948:     {
                    949:       switch (toupper(*tok))
                    950:       {
                    951:       case 'A': sscanf(tok+1, "%hx", &base);  break;
                    952:       case 'I': sscanf(tok+1, "%hd", &irq);   break;
                    953:       case 'D': sscanf(tok+1, "%hd", &dmalo); break;
                    954:       case 'H': sscanf(tok+1, "%hd", &dmahi); break;
                    955:       default: break;
                    956:       }
                    957:       tok = strtok (NULL, " \t");
                    958:     }
                    959:     printf ("SoundBlaster Settings taken from BLASTER variable:\n"
                    960:            "  Base: %hx  IRQ: %hd  DMA: %hd,%hd\n", base,irq,dmalo,dmahi);
                    961:   }
                    962: 
                    963:   have_sound = SB_Init (base, irq, dmalo, dmahi);
                    964:   if (!have_sound)
                    965:   {
                    966:     printf ("Cannot Initialize Soundblaster!\n");
                    967:     return (0);
                    968:   }
                    969: 
                    970:   if ((*dspbits) == 16 && SB_SetBits (16))
                    971:     SB_SetSigned (1);
                    972:   else
                    973:     *dspbits = 8;
                    974: 
                    975:   SB_SetRate(22050);
                    976: 
                    977:   if ((*dsprate) == 0 && !SB_SetRate(44100))
                    978:   {
                    979:     printf ("SoundCard does not support playing at 44100 Hz, using 22050 Hz\n");
                    980:     SB_SetRate(22050);
                    981:     *dsprate = 1;
                    982:   }
                    983: 
                    984:   *sndbufsize = SB_GetFragmentSize();
                    985: 
                    986:   printf ("SoundBlaster%s found and configured for %d bits at %d Hz,\n"
                    987:          "  Fragment size is %d Bytes, Buffer size is %d bytes.\n",
                    988:           SB_Type==SB_Type_StdSB ? "" :
                    989:          (SB_Type==SB_Type_SbPro ? " PRO" : " 16"),
                    990:           *dspbits, (*dsprate) ? 22050 : 44100, *sndbufsize, SB_GetBufferSize());
                    991: 
                    992:   SND_Write = SB_Write;
                    993: 
                    994:   atexit (SB_Done);
                    995: 
                    996:   return 1;
                    997: }
                    998: 
                    999: /* that's it... */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.