Annotation of quake1/snd_gus.c, revision 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.