|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.