|
|
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.