Annotation of quake1/snd_gus.c, revision 1.1.1.1

1.1       root        1: //=============================================================================
                      2: // Routines for GUS support in QUAKE
                      3: //
                      4: // Author(s): Jayeson Lee-Steere
                      5: //=============================================================================
                      6: 
                      7: #include "quakedef.h"
                      8: #include "dosisms.h"
                      9: 
                     10: //=============================================================================
                     11: // Author(s): Jayeson Lee-Steere
                     12: 
                     13: #define INI_STRING_SIZE 0x100
                     14: 
                     15: FILE *ini_fopen(const char *filename, const char *modes);
                     16: int ini_fclose(FILE *f);
                     17: void ini_fgets(FILE *f, const char *section, const char *field, char *s);
                     18: 
                     19: // Routines for reading from .INI files
                     20: // The read routines are fairly efficient.
                     21: //
                     22: // Author(s): Jayeson Lee-Steere
                     23: 
                     24: #define MAX_SECTION_WIDTH 20
                     25: #define MAX_FIELD_WIDTH 20
                     26: 
                     27: #define NUM_SECTION_BUFFERS 10
                     28: #define NUM_FIELD_BUFFERS 20
                     29: 
                     30: struct section_buffer
                     31: {
                     32:    long offset;
                     33:    char name[MAX_SECTION_WIDTH+1];
                     34: };
                     35: 
                     36: struct field_buffer
                     37: {
                     38:    long offset;
                     39:    int  section;
                     40:    char name[MAX_FIELD_WIDTH+1];
                     41: };
                     42: 
                     43: static FILE *current_file=NULL;
                     44: static int   current_section;
                     45: 
                     46: static int current_section_buffer=0;
                     47: static int current_field_buffer=0;
                     48: 
                     49: static struct section_buffer section_buffers[NUM_SECTION_BUFFERS];
                     50: static struct field_buffer field_buffers[NUM_FIELD_BUFFERS];
                     51: //***************************************************************************
                     52: // Internal routines
                     53: //***************************************************************************
                     54: static char toupper(char c)
                     55: {
                     56:    if (c>='a' && c<='z')
                     57:       c-=('a'-'A');
                     58:    return(c);
                     59: }
                     60: 
                     61: static void reset_buffer(FILE *f)
                     62: {
                     63:    int i;
                     64: 
                     65:    for (i=0;i<NUM_SECTION_BUFFERS;i++)
                     66:       section_buffers[i].name[0]=0;
                     67:    for (i=0;i<NUM_FIELD_BUFFERS;i++)
                     68:       field_buffers[i].name[0]=0;
                     69: 
                     70:    current_file=f;
                     71: }
                     72: 
                     73: // Sees if the current string is section "name" (i.e. ["name"]).
                     74: // If "name"=="*", sees if the current string is any section
                     75: // (i.e. [....]). Returns 1 if true else 0 if false.
                     76: static int is_section(char *s,const char *name)
                     77: {
                     78:    int wild=0;
                     79: 
                     80:    // See if wild search
                     81:    if (strcmp("*",name)==0)
                     82:       wild=1;
                     83: 
                     84:    // Skip leading spaces
                     85:    while (s[0]==' ')
                     86:       s++;
                     87:    // Look for leading "["
                     88:    if (s[0]!='[')
                     89:       return(0);
                     90:    s++;
                     91:    // Make sure name matches
                     92:    while (s[0]!=']' && s[0]!=13 && s[0]!=10 && s[0]!=0 && name[0]!=0)
                     93:    {
                     94:       if (!wild)
                     95:          if (toupper(s[0])!=toupper(name[0]))
                     96:             return(0);
                     97:       s++;
                     98:       if (!wild)
                     99:          name++;
                    100:    }
                    101:    if (!wild)
                    102:       if (name[0]!=0)
                    103:          return(0);
                    104:    // Skip trailing spaces
                    105:    while (s[0]==' ')
                    106:       s++;
                    107:    // Make sure we have trailing "]"
                    108:    if (s[0]!=']')
                    109:       return(0);
                    110:    return(1);
                    111: }
                    112: 
                    113: // Sees if the current string is field "name" (i.e. "name"=...).
                    114: // If "name"=="*", sees if the current string is any field
                    115: // (i.e. ...=...). Returns 1 if true else 0 if false.
                    116: static int is_field(char *s,const char *name)
                    117: {
                    118:    int wild=0;
                    119: 
                    120:    // See if wild search
                    121:    if (strcmp("*",name)==0)
                    122:       wild=1;
                    123: 
                    124:    // Skip leading spaces
                    125:    while (s[0]==' ')
                    126:       s++;
                    127: 
                    128:    // Make sure name matches
                    129:    while (s[0]!='=' && s[0]!=13 && s[0]!=10 && s[0]!=0 && name[0]!=0)
                    130:    {
                    131:       if (!wild)
                    132:          if (toupper(s[0])!=toupper(name[0]))
                    133:             return(0);
                    134:       s++;
                    135:       if (!wild)
                    136:          name++;
                    137:    }
                    138:    if (!wild)
                    139:       if (name[0]!=0)
                    140:          return(0);
                    141:    // Skip trailing spaces
                    142:    while (s[0]==' ')
                    143:       s++;
                    144:    // Make sure we have an "="
                    145:    if (s[0]!='=')
                    146:       return(0);
                    147: 
                    148:    return(1);
                    149: }
                    150: 
                    151: // Extracts the section name from a section heading
                    152: // e.g. in="[hey man]" gives out="hey man"
                    153: static void get_section_name(char *out, char *in)
                    154: {
                    155:    int i=0;
                    156: 
                    157:    // Skip spaces before '['
                    158:    while (in[0]==' ')
                    159:       in++;
                    160:    // Make sure there is a '['
                    161:    if (in[0]!='[')
                    162:    {
                    163:       out[0]=0;
                    164:       return;
                    165:    }
                    166:    // Skip past '['
                    167:    in++;
                    168:    // Copy string if any to output string.
                    169:    while (in[0]!=']' && in[0]!=13 && in[0]!=10 && in[0]!=0)
                    170:    {
                    171:       if (i<MAX_SECTION_WIDTH)
                    172:       {
                    173:          out[i]=in[0];
                    174:          i++;
                    175:       }
                    176:       in++;
                    177:    }
                    178:    // Make sure string was terminated with ']'
                    179:    if (in[0]!=']')
                    180:    {
                    181:       out[0]=0;
                    182:       return;
                    183:    }
                    184:    // Remove trailing spaces
                    185:    while (i>0 && out[i-1]==' ')
                    186:       i--;
                    187:    // Null terminate the output string.
                    188:    out[i]=0;
                    189: }
                    190: 
                    191: // Extracts the field name from a field line
                    192: // e.g. in="sooty=life be in it" gives out="sooty"
                    193: static void get_field_name(char *out, char *in)
                    194: {
                    195:    int i=0;
                    196: 
                    197:    // Skip leading spaces
                    198:    while (in[0]==' ')
                    199:       in++;
                    200:    // Copy name to output string
                    201:    while (in[0]!='=' && in[0]!=13 && in[0]!=10 && in[0]!=0)
                    202:    {
                    203:       if (i<MAX_FIELD_WIDTH)
                    204:       {
                    205:          out[i]=in[0];
                    206:          i++;
                    207:       }
                    208:       in++;
                    209:    }
                    210:    // Make sure we stopped on "="
                    211:    if (in[0]!='=')
                    212:    {
                    213:       out[0]=0;
                    214:       return;
                    215:    }
                    216:    // Remove trailing spaces
                    217:    while (i>0 && out[i-1]==' ')
                    218:       i--;
                    219:    // Null terminate the output string.
                    220:    out[i]=0;
                    221: }
                    222: 
                    223: // Returns the field data from string s.
                    224: // e.g. in="wally = golly man" gives out="golly man"
                    225: static void get_field_string(char *out, char *in)
                    226: {
                    227:    int i=0;
                    228: 
                    229:    // Find '=' if it exists
                    230:    while (in[0]!='=' && in[0]!=13 && in[0]!=10 && in[0]!=0)
                    231:       in++;
                    232:    // If there is an '=', skip past it.
                    233:    if (in[0]=='=')
                    234:       in++;
                    235:    // Skip any spaces between the '=' and string.
                    236:    while (in[0]==' ' || in[0]=='[')
                    237:       in++;
                    238:    // Copy string, if there is one, to the output string.
                    239:    while (in[0]!=13 && in[0]!=10 && in[0]!=0 && i<(INI_STRING_SIZE-1))
                    240:    {
                    241:       out[i]=in[0];
                    242:       in++;
                    243:       i++;
                    244:    }
                    245:    // Null terminate the output string.
                    246:    out[i]=0;
                    247: }
                    248: 
                    249: // Adds a section to the buffer
                    250: static int add_section(char *instring, long offset)
                    251: {
                    252:    int i;
                    253:    char section[MAX_SECTION_WIDTH+1];
                    254: 
                    255:    // Extract section name
                    256:    get_section_name(section,instring);
                    257:    // See if section already exists.
                    258:    for (i=0;i<NUM_SECTION_BUFFERS;i++)
                    259:       if (stricmp(section,section_buffers[i].name)==0)
                    260:          return(i);
                    261:    // Increment current_section_buffer
                    262:    current_section_buffer++;
                    263:    if (current_section_buffer>NUM_SECTION_BUFFERS)
                    264:       current_section_buffer=0;
                    265:    // Delete any field buffers that correspond to this section
                    266:    for (i=0;i<NUM_FIELD_BUFFERS;i++)
                    267:       if (field_buffers[i].section==current_section_buffer)
                    268:          field_buffers[i].name[0]=0;
                    269:    // Set buffer information
                    270:    strcpy(section_buffers[current_section_buffer].name,section);
                    271:    section_buffers[current_section_buffer].offset=offset;
                    272:    return(current_section_buffer);
                    273: }
                    274: 
                    275: // Adds a field to the buffer
                    276: static void add_field(char *instring, int section, long offset)
                    277: {
                    278:    int i;
                    279:    char field[MAX_FIELD_WIDTH+1];
                    280: 
                    281:    // Extract field name
                    282:    get_field_name(field,instring);
                    283:    // See if field already exists
                    284:    for (i=0;i<NUM_FIELD_BUFFERS;i++)
                    285:       if (field_buffers[i].section==section)
                    286:          if (stricmp(field_buffers[i].name,field)==0)
                    287:             return;
                    288:    // Increment current_field_buffer
                    289:    current_field_buffer++;
                    290:    if (current_field_buffer>NUM_FIELD_BUFFERS)
                    291:       current_field_buffer=0;
                    292:    // Set buffer information
                    293:    strcpy(field_buffers[current_field_buffer].name,field);
                    294:    field_buffers[current_field_buffer].section=section;
                    295:    field_buffers[current_field_buffer].offset=offset;
                    296: }
                    297: 
                    298: // Identical to fgets except the string is trucated at the first ';',
                    299: // carriage return or line feed.
                    300: static char *stripped_fgets(char *s, int n, FILE *f)
                    301: {
                    302:    int i=0;
                    303: 
                    304:    if (fgets(s,n,f)==NULL)
                    305:       return(NULL);
                    306: 
                    307:    while (s[i]!=';' && s[i]!=13 && s[i]!=10 && s[i]!=0)
                    308:       i++;
                    309:    s[i]=0;
                    310: 
                    311:    return(s);
                    312: }
                    313: 
                    314: //***************************************************************************
                    315: // Externally accessable routines
                    316: //***************************************************************************
                    317: // Opens an .INI file. Works like fopen
                    318: FILE *ini_fopen(const char *filename, const char *modes)
                    319: {
                    320:    return(fopen(filename,modes));
                    321: }
                    322: 
                    323: // Closes a .INI file. Works like fclose
                    324: int ini_fclose(FILE *f)
                    325: {
                    326:    if (f==current_file)
                    327:       reset_buffer(NULL);
                    328:    return(fclose(f));
                    329: }
                    330: 
                    331: // Puts "field" from "section" from .ini file "f" into "s".
                    332: // If "section" does not exist or "field" does not exist in
                    333: // section then s="";
                    334: void ini_fgets(FILE *f, const char *section, const char *field, char *s)
                    335: {
                    336:    int i;
                    337:    long start_pos,string_start_pos;
                    338:    char ts[INI_STRING_SIZE*2];
                    339: 
                    340:    if (f!=current_file)
                    341:       reset_buffer(f);
                    342: 
                    343:    // Default to "Not found"
                    344:    s[0]=0;
                    345: 
                    346:    // See if section is in buffer
                    347:    for (i=0;i<NUM_SECTION_BUFFERS;i++)
                    348:       if (strnicmp(section_buffers[i].name,section,MAX_SECTION_WIDTH)==0)
                    349:          break;
                    350: 
                    351:    // If section is in buffer, seek to it if necessary
                    352:    if (i<NUM_SECTION_BUFFERS)
                    353:    {
                    354:       if (i!=current_section)
                    355:       {
                    356:          current_section=i;
                    357:          fseek(f,section_buffers[i].offset,SEEK_SET);
                    358:       }
                    359:    }
                    360:    // else look through .ini file for it.
                    361:    else
                    362:    {
                    363:       // Make sure we are not at eof or this will cause trouble.
                    364:       if (feof(f))
                    365:          rewind(f);
                    366:       start_pos=ftell(f);
                    367:       while (1)
                    368:       {
                    369:          stripped_fgets(ts,INI_STRING_SIZE*2,f);
                    370:          // If it is a section, add it to the section buffer
                    371:          if (is_section(ts,"*"))
                    372:             current_section=add_section(ts,ftell(f));
                    373:          // If it is the section we are looking for, break.
                    374:          if (is_section(ts,section))
                    375:             break;
                    376:          // If we reach the end of the file, rewind to the start.
                    377:          if (feof(f))
                    378:             rewind(f);
                    379:          if (ftell(f)==start_pos)
                    380:             return;
                    381:       }
                    382:    }
                    383: 
                    384:    // See if field is in buffer
                    385:    for (i=0;i<NUM_FIELD_BUFFERS;i++)
                    386:       if (field_buffers[i].section==current_section)
                    387:          if (strnicmp(field_buffers[i].name,field,MAX_FIELD_WIDTH)==0)
                    388:             break;
                    389: 
                    390:    // If field is in buffer, seek to it and read it
                    391:    if (i<NUM_FIELD_BUFFERS)
                    392:    {
                    393:       fseek(f,field_buffers[i].offset,SEEK_SET);
                    394:       stripped_fgets(ts,INI_STRING_SIZE*2,f);
                    395:       get_field_string(s,ts);
                    396:    }
                    397:    else
                    398:    // else search through section for field.
                    399:    {
                    400:       // Make sure we do not start at eof or this will cause problems.
                    401:       if (feof(f))
                    402:          fseek(f,section_buffers[current_section].offset,SEEK_SET);
                    403:       start_pos=ftell(f);
                    404:       while (1)
                    405:       {
                    406:          string_start_pos=ftell(f);
                    407:          stripped_fgets(ts,INI_STRING_SIZE*2,f);
                    408:          // If it is a field, add it to the buffer
                    409:          if (is_field(ts,"*"))
                    410:             add_field(ts,current_section,string_start_pos);
                    411:          // If it is the field we are looking for, save it
                    412:          if (is_field(ts,field))
                    413:          {
                    414:             get_field_string(s,ts);
                    415:             break;
                    416:          }
                    417:          // If we reach the end of the section, start over
                    418:          if (feof(f) || is_section(ts,"*"))
                    419:             fseek(f,section_buffers[current_section].offset,SEEK_SET);
                    420:          if (ftell(f)==start_pos)
                    421:             return;
                    422:       }
                    423:    }
                    424: }
                    425: 
                    426: //=============================================================================
                    427: 
                    428: #define BYTE unsigned char
                    429: #define WORD unsigned short
                    430: #define DWORD unsigned long
                    431: 
                    432: #define BUFFER_SIZE 4096
                    433: 
                    434: #define CODEC_ADC_INPUT_CONTROL_LEFT   0x00
                    435: #define CODEC_ADC_INPUT_CONTROL_RIGHT  0x01
                    436: #define CODEC_AUX1_INPUT_CONTROL_LEFT  0x02
                    437: #define CODEC_AUX1_INPUT_CONTROL_RIGHT 0x03
                    438: #define CODEC_AUX2_INPUT_CONTROL_LEFT  0x04
                    439: #define CODEC_AUX2_INPUT_CONTROL_RIGHT 0x05
                    440: #define CODEC_DAC_OUTPUT_CONTROL_LEFT  0x06
                    441: #define CODEC_DAC_OUTPUT_CONTROL_RIGHT 0x07
                    442: #define CODEC_FS_FORMAT                        0x08
                    443: #define CODEC_INTERFACE_CONFIG         0x09
                    444: #define CODEC_PIN_CONTROL              0x0A
                    445: #define CODEC_ERROR_STATUS_AND_INIT    0x0B
                    446: #define CODEC_MODE_AND_ID              0x0C
                    447: #define CODEC_LOOPBACK_CONTROL         0x0D
                    448: #define CODEC_PLAYBACK_UPPER_BASE_COUNT        0x0E
                    449: #define CODEC_PLAYBACK_LOWER_BASE_COUNT        0x0F
                    450: 
                    451: struct CodecRateStruct
                    452: {
                    453:    WORD Rate;
                    454:    BYTE FSVal;
                    455: };
                    456: 
                    457: //=============================================================================
                    458: // Reference variables in SND_DOS.C
                    459: //=============================================================================
                    460: extern short *dma_buffer;
                    461: extern dma_t theshm;
                    462: 
                    463: //=============================================================================
                    464: // GUS-only variables
                    465: //=============================================================================
                    466: static WORD CodecRegisterSelect;
                    467: static WORD CodecData;
                    468: static WORD CodecStatus;
                    469: 
                    470: static BYTE DmaChannel;
                    471: 
                    472: static BYTE PageRegs[] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
                    473: static BYTE AddrRegs[] = { 0, 2, 4, 6, 0xc0, 0xc4, 0xc8, 0xcc };
                    474: static BYTE CountRegs[] = { 1, 3, 5, 7, 0xc2, 0xc6, 0xca, 0xce };
                    475: 
                    476: static WORD AddrReg;
                    477: static WORD CountReg;
                    478: static WORD ModeReg;
                    479: static WORD DisableReg;
                    480: static WORD ClearReg;
                    481: 
                    482: static struct CodecRateStruct CodecRates[]=
                    483: {
                    484:    { 5512,0x01},
                    485:    { 6620,0x0F},
                    486:    { 8000,0x00},
                    487:    { 9600,0x0E},
                    488:    {11025,0x03},
                    489:    {16000,0x02},
                    490:    {18900,0x05},
                    491:    {22050,0x07},
                    492:    {27420,0x04},
                    493:    {32000,0x06},
                    494:    {33075,0x0D},
                    495:    {37800,0x09},
                    496:    {44100,0x0B},
                    497:    {48000,0x0C},
                    498:    {    0,0x00} // End marker
                    499: };
                    500: 
                    501: //=============================================================================
                    502: // Get Interwave (UltraSound PnP) configuration if any
                    503: //=============================================================================
                    504: static qboolean GUS_GetIWData(void)
                    505: {
                    506:    char *Interwave,s[INI_STRING_SIZE];
                    507:    FILE *IwFile;
                    508:    int  CodecBase,CodecDma,i;
                    509: 
                    510:    Interwave=getenv("INTERWAVE");
                    511:    if (Interwave==NULL)
                    512:       return(false);
                    513: 
                    514:    // Open IW.INI
                    515:    IwFile=ini_fopen(Interwave,"rt");
                    516:    if (IwFile==NULL)
                    517:       return(false);
                    518: 
                    519:    // Read codec base and codec DMA
                    520:    ini_fgets(IwFile,"setup 0","CodecBase",s);
                    521:    sscanf(s,"%X",&CodecBase);
                    522:    ini_fgets(IwFile,"setup 0","DMA2",s);
                    523:    sscanf(s,"%i",&CodecDma);
                    524: 
                    525:    ini_fclose(IwFile);
                    526: 
                    527:    // Make sure numbers OK
                    528:    if (CodecBase==0 || CodecDma==0)
                    529:       return(false);
                    530: 
                    531:    CodecRegisterSelect=CodecBase;
                    532:    CodecData=CodecBase+1;
                    533:    CodecStatus=CodecBase+2;
                    534:    DmaChannel=CodecDma;
                    535: 
                    536:    // Make sure there is a CODEC at the CODEC base
                    537: 
                    538:    // Clear any pending IRQs
                    539:    dos_inportb(CodecStatus);
                    540:    dos_outportb(CodecStatus,0);
                    541: 
                    542:    // Wait for 'INIT' bit to clear
                    543:    for (i=0;i<0xFFFF;i++)
                    544:       if ((dos_inportb(CodecRegisterSelect) & 0x80) == 0)
                    545:          break;
                    546:    if (i==0xFFFF)
                    547:       return(false);
                    548: 
                    549:    // Get chip revision - can not be zero
                    550:    dos_outportb(CodecRegisterSelect,CODEC_MODE_AND_ID);
                    551:    if ((dos_inportb(CodecRegisterSelect) & 0x7F) != CODEC_MODE_AND_ID)
                    552:       return(false);
                    553:    if ((dos_inportb(CodecData) & 0x0F) == 0)
                    554:       return(false);
                    555: 
                    556:    return(true);
                    557: }
                    558: 
                    559: //=============================================================================
                    560: // Get UltraSound MAX configuration if any
                    561: //=============================================================================
                    562: static qboolean GUS_GetMAXData(void)
                    563: {
                    564:    char *Ultrasnd,*Ultra16;
                    565:    int  i;
                    566:    int  GusBase,Dma1,Dma2,Irq1,Irq2;
                    567:    int  CodecBase,CodecDma,CodecIrq,CodecType;
                    568:    BYTE MaxVal;
                    569: 
                    570:    Ultrasnd=getenv("ULTRASND");
                    571:    Ultra16=getenv("ULTRA16");
                    572:    if (Ultrasnd==NULL || Ultra16==NULL)
                    573:       return(false);
                    574: 
                    575:    sscanf(Ultrasnd,"%x,%i,%i,%i,%i",&GusBase,&Dma1,&Dma2,&Irq1,&Irq2);
                    576:    sscanf(Ultra16,"%x,%i,%i,%i",&CodecBase,&CodecDma,&CodecIrq,&CodecType);
                    577: 
                    578:    if (CodecType==0 && CodecDma!=0)
                    579:       DmaChannel=CodecDma & 0x07;
                    580:    else
                    581:       DmaChannel=Dma2 & 0x07;
                    582: 
                    583:    // Make sure there is a GUS at GUS base
                    584:    dos_outportb(GusBase+0x08,0x55);
                    585:    if (dos_inportb(GusBase+0x0A)!=0x55)
                    586:       return(false);
                    587:    dos_outportb(GusBase+0x08,0xAA);
                    588:    if (dos_inportb(GusBase+0x0A)!=0xAA)
                    589:       return(false);
                    590: 
                    591:    // Program CODEC control register
                    592:    MaxVal=((CodecBase & 0xF0)>>4) | 0x40;
                    593:    if (Dma1 > 3)
                    594:       MaxVal|=0x10;
                    595:    if (Dma2 > 3)
                    596:       MaxVal|=0x20;
                    597:    dos_outportb(GusBase+0x106,MaxVal);
                    598: 
                    599:    CodecRegisterSelect=CodecBase;
                    600:    CodecData=CodecBase+1;
                    601:    CodecStatus=CodecBase+2;
                    602: 
                    603:    // Make sure there is a CODEC at the CODEC base
                    604: 
                    605:    // Clear any pending IRQs
                    606:    dos_inportb(CodecStatus);
                    607:    dos_outportb(CodecStatus,0);
                    608: 
                    609:    // Wait for 'INIT' bit to clear
                    610:    for (i=0;i<0xFFFF;i++)
                    611:       if ((dos_inportb(CodecRegisterSelect) & 0x80) == 0)
                    612:          break;
                    613:    if (i==0xFFFF)
                    614:       return(false);
                    615: 
                    616:    // Get chip revision - can not be zero
                    617:    dos_outportb(CodecRegisterSelect,CODEC_MODE_AND_ID);
                    618:    if ((dos_inportb(CodecRegisterSelect) & 0x7F) != CODEC_MODE_AND_ID)
                    619:       return(false);
                    620:    if ((dos_inportb(CodecData) & 0x0F) == 0)
                    621:       return(false);
                    622: 
                    623:    return(true);
                    624: }
                    625: 
                    626: //=============================================================================
                    627: // Programs the DMA controller to start DMAing in Auto-init mode
                    628: //=============================================================================
                    629: static void GUS_StartDMA(BYTE DmaChannel,short *dma_buffer,int count)
                    630: {
                    631:    int mode;
                    632:    int RealAddr;
                    633: 
                    634:    RealAddr = ptr2real(dma_buffer);
                    635: 
                    636:    if (DmaChannel <= 3)
                    637:    {
                    638:       ModeReg = 0x0B;
                    639:       DisableReg = 0x0A;
                    640:       ClearReg = 0x0E;
                    641:    }
                    642:    else
                    643:    {
                    644:       ModeReg = 0xD6;
                    645:       DisableReg = 0xD4;
                    646:       ClearReg = 0xDC;
                    647:    }
                    648:    CountReg=CountRegs[DmaChannel];
                    649:    AddrReg=AddrRegs[DmaChannel];
                    650: 
                    651:    dos_outportb(DisableReg, DmaChannel | 4);   // disable channel
                    652: 
                    653:    // set mode- see "undocumented pc", p.876
                    654:    mode = (1<<6)               // single-cycle
                    655:           +(0<<5)              // address increment
                    656:          +(1<<4)               // auto-init dma
                    657:          +(2<<2)               // read
                    658:          +(DmaChannel & 0x03); // channel #
                    659:    dos_outportb(ModeReg, mode);
                    660: 
                    661:    // set page
                    662:    dos_outportb(PageRegs[DmaChannel], RealAddr >> 16);
                    663: 
                    664:    if (DmaChannel <= 3)
                    665:    {   // address is in bytes
                    666:       dos_outportb(0x0C, 0);           // prepare to send 16-bit value
                    667:       dos_outportb(AddrReg, RealAddr & 0xff);
                    668:       dos_outportb(AddrReg, (RealAddr>>8) & 0xff);
                    669: 
                    670:       dos_outportb(0x0C, 0);           // prepare to send 16-bit value
                    671:       dos_outportb(CountReg, (count-1) & 0xff);
                    672:       dos_outportb(CountReg, (count-1) >> 8);
                    673:    }
                    674:    else
                    675:    {   // address is in words
                    676:       dos_outportb(0xD8, 0);           // prepare to send 16-bit value
                    677:       dos_outportb(AddrReg, (RealAddr>>1) & 0xff);
                    678:       dos_outportb(AddrReg, (RealAddr>>9) & 0xff);
                    679: 
                    680:       dos_outportb(0xD8, 0);           // prepare to send 16-bit value
                    681:       dos_outportb(CountReg, ((count>>1)-1) & 0xff);
                    682:       dos_outportb(CountReg, ((count>>1)-1) >> 8);
                    683:    }
                    684: 
                    685:    dos_outportb(ClearReg, 0);          // clear write mask
                    686:    dos_outportb(DisableReg, DmaChannel & ~4);
                    687: }
                    688: 
                    689: //=============================================================================
                    690: // Starts the CODEC playing
                    691: //=============================================================================
                    692: static void GUS_StartCODEC(int count,BYTE FSVal)
                    693: {
                    694:    int i,j;
                    695: 
                    696:    // Clear any pending IRQs
                    697:    dos_inportb(CodecStatus);
                    698:    dos_outportb(CodecStatus,0);
                    699: 
                    700:    // Set mode to 2
                    701:    dos_outportb(CodecRegisterSelect,CODEC_MODE_AND_ID);
                    702:    dos_outportb(CodecData,0xC0);
                    703: 
                    704:    // Stop any playback or capture which may be happening
                    705:    dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
                    706:    dos_outportb(CodecData,dos_inportb(CodecData) & 0xFC);
                    707: 
                    708:    // Set FS
                    709:    dos_outportb(CodecRegisterSelect,CODEC_FS_FORMAT | 0x40);
                    710:    dos_outportb(CodecData,FSVal | 0x50); // Or in stereo and 16 bit bits
                    711: 
                    712:    // Wait a bit
                    713:    for (i=0;i<10;i++)
                    714:       dos_inportb(CodecData);
                    715: 
                    716:    // Routine 1 to counter CODEC bug - wait for init bit to clear and then a
                    717:    // bit longer (i=min loop count, j=timeout
                    718:    for (i=0,j=0;i<1000 && j<0x7FFFF;j++)
                    719:       if ((dos_inportb(CodecRegisterSelect) & 0x80)==0)
                    720:          i++;
                    721: 
                    722:    // Routine 2 to counter CODEC bug - this is from Forte's code. For me it
                    723:    // does not seem to cure the problem, but is added security
                    724:    // Waits till we can modify index register
                    725:    for (j=0;j<0x7FFFF;j++)
                    726:    {
                    727:       dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
                    728:       if (dos_inportb(CodecRegisterSelect)==(CODEC_INTERFACE_CONFIG | 0x40))
                    729:          break;
                    730:    }
                    731: 
                    732:    // Perform ACAL
                    733:    dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
                    734:    dos_outportb(CodecData,0x08);
                    735: 
                    736:    // Clear MCE bit - this makes ACAL happen
                    737:    dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
                    738: 
                    739:    // Wait for ACAL to finish
                    740:    for (j=0;j<0x7FFFF;j++)
                    741:    {
                    742:       if ((dos_inportb(CodecRegisterSelect) & 0x80) != 0)
                    743:          continue;
                    744:       dos_outportb(CodecRegisterSelect,CODEC_ERROR_STATUS_AND_INIT);
                    745:       if ((dos_inportb(CodecData) & 0x20) == 0)
                    746:          break;
                    747:    }
                    748: 
                    749:    // Clear ACAL bit
                    750:    dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG | 0x40);
                    751:    dos_outportb(CodecData,0x00);
                    752:    dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
                    753: 
                    754:    // Set some other junk
                    755:    dos_outportb(CodecRegisterSelect,CODEC_LOOPBACK_CONTROL);
                    756:    dos_outportb(CodecData,0x00);
                    757:    dos_outportb(CodecRegisterSelect,CODEC_PIN_CONTROL);
                    758:    dos_outportb(CodecData,0x08); // IRQ is disabled in PIN control
                    759: 
                    760:    // Set count (it doesn't really matter what value we stuff in here
                    761:    dos_outportb(CodecRegisterSelect,CODEC_PLAYBACK_LOWER_BASE_COUNT);
                    762:    dos_outportb(CodecData,count & 0xFF);
                    763:    dos_outportb(CodecRegisterSelect,CODEC_PLAYBACK_UPPER_BASE_COUNT);
                    764:    dos_outportb(CodecData,count >> 8);
                    765: 
                    766:    // Start playback
                    767:    dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
                    768:    dos_outportb(CodecData,0x01);
                    769: }
                    770: 
                    771: //=============================================================================
                    772: // Figures out what kind of UltraSound we have, if any, and starts it playing
                    773: //=============================================================================
                    774: qboolean GUS_Init(void)
                    775: {
                    776:    int rc;
                    777:    int RealAddr;
                    778:    BYTE FSVal;
                    779:    struct CodecRateStruct *CodecRate;
                    780: 
                    781:    // See what kind of UltraSound we have, if any
                    782:    if (GUS_GetIWData()==false)
                    783:       if (GUS_GetMAXData()==false)
                    784:          return(false);
                    785: 
                    786:    shm = &theshm;
                    787: 
                    788:    // do 11khz sampling rate unless command line parameter wants different
                    789:    shm->speed = 11025;
                    790:    FSVal = 0x02;
                    791:    rc = COM_CheckParm("-sspeed");
                    792:    if (rc)
                    793:    {
                    794:       shm->speed = Q_atoi(com_argv[rc+1]);
                    795: 
                    796:       // Make sure rate not too high
                    797:       if (shm->speed>48000)
                    798:          shm->speed=48000;
                    799: 
                    800:       // Adjust speed to match one of the possible CODEC rates
                    801:       for (CodecRate=CodecRates;CodecRate->Rate!=0;CodecRate++)
                    802:       {
                    803:          if (shm->speed <= CodecRate->Rate)
                    804:          {
                    805:             shm->speed=CodecRate->Rate;
                    806:             FSVal=CodecRate->FSVal;
                    807:             break;
                    808:          }
                    809:       }
                    810:    }
                    811: 
                    812:    // Always do 16 bit stereo
                    813:    shm->channels = 2;
                    814:    shm->samplebits = 16;
                    815: 
                    816:    // allocate buffer twice the size we need so we can get aligned buffer
                    817:    dma_buffer = dos_getmemory(BUFFER_SIZE*2);
                    818:    if (dma_buffer==NULL)
                    819:    {
                    820:       Con_Printf("Couldn't allocate sound dma buffer");
                    821:       return false;
                    822:    }
                    823: 
                    824:    RealAddr = ptr2real(dma_buffer);
                    825:    RealAddr = (RealAddr + BUFFER_SIZE) & ~(BUFFER_SIZE-1);
                    826:    dma_buffer = (short *) real2ptr(RealAddr);
                    827: 
                    828:    // Zero off DMA buffer
                    829:    memset(dma_buffer, 0, BUFFER_SIZE);
                    830: 
                    831:    shm->soundalive = true;
                    832:    shm->splitbuffer = false;
                    833: 
                    834:    shm->samplepos = 0;
                    835:    shm->submission_chunk = 1;
                    836:    shm->buffer = (unsigned char *) dma_buffer;
                    837:    shm->samples = BUFFER_SIZE/(shm->samplebits/8);
                    838: 
                    839:    GUS_StartDMA(DmaChannel,dma_buffer,BUFFER_SIZE);
                    840:    GUS_StartCODEC(BUFFER_SIZE,FSVal);
                    841: 
                    842:    return(true);
                    843: }
                    844: 
                    845: //=============================================================================
                    846: // Returns the current playback position
                    847: //=============================================================================
                    848: int GUS_GetDMAPos(void)
                    849: {
                    850:    int count;
                    851: 
                    852:    // clear 16-bit reg flip-flop
                    853:    // load the current dma count register
                    854:    if (DmaChannel < 4)
                    855:    {
                    856:       dos_outportb(0x0C, 0);
                    857:       count = dos_inportb(CountReg);
                    858:       count += dos_inportb(CountReg) << 8;
                    859:       if (shm->samplebits == 16)
                    860:          count /= 2;
                    861:       count = shm->samples - (count+1);
                    862:    }
                    863:    else
                    864:    {
                    865:       dos_outportb(0xD8, 0);
                    866:       count = dos_inportb(CountReg);
                    867:       count += dos_inportb(CountReg) << 8;
                    868:       if (shm->samplebits == 8)
                    869:          count *= 2;
                    870:       count = shm->samples - (count+1);
                    871:    }
                    872: 
                    873:    shm->samplepos = count & (shm->samples-1);
                    874:    return(shm->samplepos);
                    875: }
                    876: 
                    877: //=============================================================================
                    878: // Stops the UltraSound playback
                    879: //=============================================================================
                    880: void GUS_Shutdown (void)
                    881: {
                    882:    // Stop CODEC
                    883:    dos_outportb(CodecRegisterSelect,CODEC_INTERFACE_CONFIG);
                    884:    dos_outportb(CodecData,0x01);
                    885: 
                    886:    dos_outportb(DisableReg, DmaChannel | 4); // disable dma channel
                    887: }

unix.superglobalmegacorp.com

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