diff --git a/libs/audio/targets/snd_gus.c b/libs/audio/targets/snd_gus.c deleted file mode 100644 index 200b3f198..000000000 --- a/libs/audio/targets/snd_gus.c +++ /dev/null @@ -1,1281 +0,0 @@ - -/* - snd_gus.c - - @description@ - - Copyright (C) 1996-1997 Id Software, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - - $Id$ -*/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "dosisms.h" - -//============================================================================= -// Author(s): Jayeson Lee-Steere - -#define INI_STRING_SIZE 0x100 - -VFile *ini_fopen (const char *filename, const char *modes); -int ini_fclose (VFile *f); -void ini_fgets (VFile *f, const char *section, const char *field, - - char *s); - -// Routines for reading from .INI files -// The read routines are fairly efficient. -// -// Author(s): Jayeson Lee-Steere - -#define MAX_SECTION_WIDTH 20 -#define MAX_FIELD_WIDTH 20 - -#define NUM_SECTION_BUFFERS 10 -#define NUM_FIELD_BUFFERS 20 - -struct section_buffer { - long offset; - char name[MAX_SECTION_WIDTH + 1]; -}; - -struct field_buffer { - long offset; - int section; - char name[MAX_FIELD_WIDTH + 1]; -}; - -static VFile *current_file = NULL; -static int current_section; - -static int current_section_buffer = 0; -static int current_field_buffer = 0; - -static struct section_buffer section_buffers[NUM_SECTION_BUFFERS]; -static struct field_buffer field_buffers[NUM_FIELD_BUFFERS]; - -//*************************************************************************** -// Internal routines -//*************************************************************************** -static char -toupper (char c) -{ - if (c >= 'a' && c <= 'z') - c -= ('a' - 'A'); - return (c); -} - -static void -reset_buffer (VFile *f) -{ - int i; - - for (i = 0; i < NUM_SECTION_BUFFERS; i++) - section_buffers[i].name[0] = 0; - for (i = 0; i < NUM_FIELD_BUFFERS; i++) - field_buffers[i].name[0] = 0; - - current_file = f; -} - -// Sees if the current string is section "name" (i.e. ["name"]). -// If "name"=="*", sees if the current string is any section -// (i.e. [....]). Returns 1 if true else 0 if false. -static int -is_section (char *s, const char *name) -{ - int wild = 0; - - // See if wild search - if (strcmp ("*", name) == 0) - wild = 1; - - // Skip leading spaces - while (s[0] == ' ') - s++; - // Look for leading "[" - if (s[0] != '[') - return (0); - s++; - // Make sure name matches - while (s[0] != ']' && s[0] != 13 && s[0] != 10 && s[0] != 0 && name[0] != 0) { - if (!wild) - if (toupper (s[0]) != toupper (name[0])) - return (0); - s++; - if (!wild) - name++; - } - if (!wild) - if (name[0] != 0) - return (0); - // Skip trailing spaces - while (s[0] == ' ') - s++; - // Make sure we have trailing "]" - if (s[0] != ']') - return (0); - return (1); -} - -// Sees if the current string is field "name" (i.e. "name"=...). -// If "name"=="*", sees if the current string is any field -// (i.e. ...=...). Returns 1 if true else 0 if false. -static int -is_field (char *s, const char *name) -{ - int wild = 0; - - // See if wild search - if (strcmp ("*", name) == 0) - wild = 1; - - // Skip leading spaces - while (s[0] == ' ') - s++; - - // Make sure name matches - while (s[0] != '=' && s[0] != 13 && s[0] != 10 && s[0] != 0 && name[0] != 0) { - if (!wild) - if (toupper (s[0]) != toupper (name[0])) - return (0); - s++; - if (!wild) - name++; - } - if (!wild) - if (name[0] != 0) - return (0); - // Skip trailing spaces - while (s[0] == ' ') - s++; - // Make sure we have an "=" - if (s[0] != '=') - return (0); - - return (1); -} - -// Extracts the section name from a section heading -// e.g. in="[hey man]" gives out="hey man" -static void -get_section_name (char *out, char *in) -{ - int i = 0; - - // Skip spaces before '[' - while (in[0] == ' ') - in++; - // Make sure there is a '[' - if (in[0] != '[') { - out[0] = 0; - return; - } - // Skip past '[' - in++; - // Copy string if any to output string. - while (in[0] != ']' && in[0] != 13 && in[0] != 10 && in[0] != 0) { - if (i < MAX_SECTION_WIDTH) { - out[i] = in[0]; - i++; - } - in++; - } - // Make sure string was terminated with ']' - if (in[0] != ']') { - out[0] = 0; - return; - } - // Remove trailing spaces - while (i > 0 && out[i - 1] == ' ') - i--; - // Null terminate the output string. - out[i] = 0; -} - -// Extracts the field name from a field line -// e.g. in="sooty=life be in it" gives out="sooty" -static void -get_field_name (char *out, char *in) -{ - int i = 0; - - // Skip leading spaces - while (in[0] == ' ') - in++; - // Copy name to output string - while (in[0] != '=' && in[0] != 13 && in[0] != 10 && in[0] != 0) { - if (i < MAX_FIELD_WIDTH) { - out[i] = in[0]; - i++; - } - in++; - } - // Make sure we stopped on "=" - if (in[0] != '=') { - out[0] = 0; - return; - } - // Remove trailing spaces - while (i > 0 && out[i - 1] == ' ') - i--; - // Null terminate the output string. - out[i] = 0; -} - -// Returns the field data from string s. -// e.g. in="wally = golly man" gives out="golly man" -static void -get_field_string (char *out, char *in) -{ - int i = 0; - - // Find '=' if it exists - while (in[0] != '=' && in[0] != 13 && in[0] != 10 && in[0] != 0) - in++; - // If there is an '=', skip past it. - if (in[0] == '=') - in++; - // Skip any spaces between the '=' and string. - while (in[0] == ' ' || in[0] == '[') - in++; - // Copy string, if there is one, to the output string. - while (in[0] != 13 && in[0] != 10 && in[0] != 0 - && i < (INI_STRING_SIZE - 1)) { - out[i] = in[0]; - in++; - i++; - } - // Null terminate the output string. - out[i] = 0; -} - -// Adds a section to the buffer -static int -add_section (char *instring, long offset) -{ - int i; - char section[MAX_SECTION_WIDTH + 1]; - - // Extract section name - get_section_name (section, instring); - // See if section already exists. - for (i = 0; i < NUM_SECTION_BUFFERS; i++) - if (strcasecmp (section, section_buffers[i].name) == 0) - return (i); - // Increment current_section_buffer - current_section_buffer++; - if (current_section_buffer > NUM_SECTION_BUFFERS) - current_section_buffer = 0; - // Delete any field buffers that correspond to this section - for (i = 0; i < NUM_FIELD_BUFFERS; i++) - if (field_buffers[i].section == current_section_buffer) - field_buffers[i].name[0] = 0; - // Set buffer information - strcpy (section_buffers[current_section_buffer].name, section); - section_buffers[current_section_buffer].offset = offset; - return (current_section_buffer); -} - -// Adds a field to the buffer -static void -add_field (char *instring, int section, long offset) -{ - int i; - char field[MAX_FIELD_WIDTH + 1]; - - // Extract field name - get_field_name (field, instring); - // See if field already exists - for (i = 0; i < NUM_FIELD_BUFFERS; i++) - if (field_buffers[i].section == section) - if (strcasecmp (field_buffers[i].name, field) == 0) - return; - // Increment current_field_buffer - current_field_buffer++; - if (current_field_buffer > NUM_FIELD_BUFFERS) - current_field_buffer = 0; - // Set buffer information - strcpy (field_buffers[current_field_buffer].name, field); - field_buffers[current_field_buffer].section = section; - field_buffers[current_field_buffer].offset = offset; -} - -// Identical to fgets except the string is trucated at the first ';', -// carriage return or line feed. -static char * -stripped_fgets (char *s, int n, VFile *f) -{ - int i = 0; - - if (fgets (s, n, f) == NULL) - return (NULL); - - while (s[i] != ';' && s[i] != 13 && s[i] != 10 && s[i] != 0) - i++; - s[i] = 0; - - return (s); -} - -//*************************************************************************** -// Externally accessable routines -//*************************************************************************** -// Opens an .INI file. Works like fopen -VFile * -ini_fopen (const char *filename, const char *modes) -{ - return (Qopen (filename, modes)); -} - -// Closes a .INI file. Works like fclose -int -ini_fclose (VFile *f) -{ - if (f == current_file) - reset_buffer (NULL); - return (Qclose (f)); -} - -// Puts "field" from "section" from .ini file "f" into "s". -// If "section" does not exist or "field" does not exist in -// section then s=""; -void -ini_fgets (VFile *f, const char *section, const char *field, char *s) -{ - int i; - long start_pos, string_start_pos; - char ts[INI_STRING_SIZE * 2]; - - if (f != current_file) - reset_buffer (f); - - // Default to "Not found" - s[0] = 0; - - // See if section is in buffer - for (i = 0; i < NUM_SECTION_BUFFERS; i++) - if (strnicmp (section_buffers[i].name, section, MAX_SECTION_WIDTH) == 0) - break; - - // If section is in buffer, seek to it if necessary - if (i < NUM_SECTION_BUFFERS) { - if (i != current_section) { - current_section = i; - fseek (f, section_buffers[i].offset, SEEK_SET); - } - } - // else look through .ini file for it. - else { - // Make sure we are not at eof or this will cause trouble. - if (feof (f)) - rewind (f); - start_pos = ftell (f); - while (1) { - stripped_fgets (ts, INI_STRING_SIZE * 2, f); - // If it is a section, add it to the section buffer - if (is_section (ts, "*")) - current_section = add_section (ts, ftell (f)); - // If it is the section we are looking for, break. - if (is_section (ts, section)) - break; - // If we reach the end of the file, rewind to the start. - if (feof (f)) - rewind (f); - if (ftell (f) == start_pos) - return; - } - } - - // See if field is in buffer - for (i = 0; i < NUM_FIELD_BUFFERS; i++) - if (field_buffers[i].section == current_section) - if (strnicmp (field_buffers[i].name, field, MAX_FIELD_WIDTH) == 0) - break; - - // If field is in buffer, seek to it and read it - if (i < NUM_FIELD_BUFFERS) { - fseek (f, field_buffers[i].offset, SEEK_SET); - stripped_fgets (ts, INI_STRING_SIZE * 2, f); - get_field_string (s, ts); - } else - // else search through section for field. - { - // Make sure we do not start at eof or this will cause problems. - if (feof (f)) - fseek (f, section_buffers[current_section].offset, SEEK_SET); - start_pos = ftell (f); - while (1) { - string_start_pos = ftell (f); - stripped_fgets (ts, INI_STRING_SIZE * 2, f); - // If it is a field, add it to the buffer - if (is_field (ts, "*")) - add_field (ts, current_section, string_start_pos); - // If it is the field we are looking for, save it - if (is_field (ts, field)) { - get_field_string (s, ts); - break; - } - // If we reach the end of the section, start over - if (feof (f) || is_section (ts, "*")) - fseek (f, section_buffers[current_section].offset, SEEK_SET); - if (ftell (f) == start_pos) - return; - } - } -} - -//============================================================================= - -#define BYTE unsigned char -#define WORD unsigned short -#define DWORD unsigned long - -#define BUFFER_SIZE 4096 - -#define CODEC_ADC_INPUT_CONTROL_LEFT 0x00 -#define CODEC_ADC_INPUT_CONTROL_RIGHT 0x01 -#define CODEC_AUX1_INPUT_CONTROL_LEFT 0x02 -#define CODEC_AUX1_INPUT_CONTROL_RIGHT 0x03 -#define CODEC_AUX2_INPUT_CONTROL_LEFT 0x04 -#define CODEC_AUX2_INPUT_CONTROL_RIGHT 0x05 -#define CODEC_DAC_OUTPUT_CONTROL_LEFT 0x06 -#define CODEC_DAC_OUTPUT_CONTROL_RIGHT 0x07 -#define CODEC_FS_FORMAT 0x08 -#define CODEC_INTERFACE_CONFIG 0x09 -#define CODEC_PIN_CONTROL 0x0A -#define CODEC_ERROR_STATUS_AND_INIT 0x0B -#define CODEC_MODE_AND_ID 0x0C -#define CODEC_LOOPBACK_CONTROL 0x0D -#define CODEC_PLAYBACK_UPPER_BASE_COUNT 0x0E -#define CODEC_PLAYBACK_LOWER_BASE_COUNT 0x0F - -#define SET_CONTROL 0x00 -#define SET_FREQUENCY 0x01 -#define SET_START_HIGH 0x02 -#define SET_START_LOW 0x03 -#define SET_END_HIGH 0x04 -#define SET_END_LOW 0x05 -#define SET_VOLUME_RATE 0x06 -#define SET_VOLUME_START 0x07 -#define SET_VOLUME_END 0x08 -#define SET_CURR_VOLUME 0x09 -#define SET_VOLUME 0x09 -#define SET_ACC_HIGH 0x0A -#define SET_ACC_LOW 0x0B -#define SET_BALANCE 0x0C -#define SET_VOLUME_CONTROL 0x0D -#define SET_VOICES 0x0E - -#define DMA_CONTROL 0x41 -#define SET_DMA_ADDRESS 0x42 -#define SET_DRAM_LOW 0x43 -#define SET_DRAM_HIGH 0x44 -#define ADLIB_CONTROL 0x45 -#define ADLIB_TIMER1 0x46 -#define ADLIB_TIMER2 0x47 -#define SET_RECORD_RATE 0x48 -#define RECORD_CONTROL 0x49 -#define SET_JOYSTICK 0x4B -#define MASTER_RESET 0x4C - -#define GET_CONTROL 0x80 -#define GET_FREQUENCY 0x81 -#define GET_START_HIGH 0x82 -#define GET_START_LOW 0x83 -#define GET_END_HIGH 0x84 -#define GET_END_LOW 0x85 -#define GET_VOLUME_RATE 0x86 -#define GET_VOLUME_START 0x87 -#define GET_VOLUME_END 0x88 -#define GET_VOLUME 0x89 -#define GET_ACC_HIGH 0x8A -#define GET_ACC_LOW 0x8B -#define GET_BALANCE 0x8C -#define GET_VOLUME_CONTROL 0x8D -#define GET_VOICES 0x8E -#define GET_IRQV 0x8F - -struct CodecRateStruct { - WORD Rate; - BYTE FSVal; -}; - -struct Gf1RateStruct { - WORD Rate; - BYTE Voices; -}; - -//============================================================================= -// Reference variables in SND_DOS.C -//============================================================================= -extern short *dma_buffer; - -//============================================================================= -// GUS-only variables -//============================================================================= -static BYTE HaveCodec = 0; - -static WORD CodecRegisterSelect; -static WORD CodecData; -static WORD CodecStatus; -static WORD Gf1TimerControl; -static WORD Gf1PageRegister; -static WORD Gf1RegisterSelect; -static WORD Gf1DataLow; -static WORD Gf1DataHigh; - -static BYTE DmaChannel; - -static BYTE PageRegs[] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a }; -static BYTE AddrRegs[] = { 0, 2, 4, 6, 0xc0, 0xc4, 0xc8, 0xcc }; -static BYTE CountRegs[] = { 1, 3, 5, 7, 0xc2, 0xc6, 0xca, 0xce }; - -static WORD AddrReg; -static WORD CountReg; -static WORD ModeReg; -static WORD DisableReg; -static WORD ClearReg; - -static struct CodecRateStruct CodecRates[] = { - {5512, 0x01}, - {6620, 0x0F}, - {8000, 0x00}, - {9600, 0x0E}, - {11025, 0x03}, - {16000, 0x02}, - {18900, 0x05}, - {22050, 0x07}, - {27420, 0x04}, - {32000, 0x06}, - {33075, 0x0D}, - {37800, 0x09}, - {44100, 0x0B}, - {48000, 0x0C}, - {0, 0x00} // End marker -}; - -static struct Gf1RateStruct Gf1Rates[] = { - {19293, 32}, - {19916, 31}, - {20580, 30}, - {21289, 29}, - {22050, 28}, - {22866, 27}, - {23746, 26}, - {24696, 25}, - {25725, 24}, - {26843, 23}, - {28063, 22}, - {29400, 21}, - {30870, 20}, - {32494, 19}, - {34300, 18}, - {36317, 17}, - {38587, 16}, - {41160, 15}, - {44100, 14}, - {0, 0} -}; - -//============================================================================= -// Basic GF1 functions -//============================================================================= -void -SetGf18 (BYTE reg, BYTE data) -{ - dos_outportb (Gf1RegisterSelect, reg); - dos_outportb (Gf1DataHigh, data); -} - -void -SetGf116 (BYTE reg, WORD data) -{ - dos_outportb (Gf1RegisterSelect, reg); - dos_outportw (Gf1DataLow, data); -} - -BYTE -GetGf18 (BYTE reg) -{ - dos_outportb (Gf1RegisterSelect, reg); - return (dos_inportb (Gf1DataHigh)); -} - -WORD -GetGf116 (BYTE reg) -{ - dos_outportb (Gf1RegisterSelect, reg); - return (dos_inportw (Gf1DataLow)); -} - -void -Gf1Delay (void) -{ - int i; - - for (i = 0; i < 27; i++) - dos_inportb (Gf1TimerControl); -} - -DWORD -ConvertTo16 (DWORD Address) -{ - return (((Address >> 1) & 0x0001FFFF) | (Address & 0x000C0000L)); -} - -void -ClearGf1Ints (void) -{ - int i; - - SetGf18 (DMA_CONTROL, 0x00); - SetGf18 (ADLIB_CONTROL, 0x00); - SetGf18 (RECORD_CONTROL, 0x00); - - GetGf18 (DMA_CONTROL); - GetGf18 (RECORD_CONTROL); - for (i = 0; i < 32; i++); - GetGf18 (GET_IRQV); -} - - -//============================================================================= -// Get Interwave (UltraSound PnP) configuration if any -//============================================================================= -static qboolean -GUS_GetIWData (void) -{ - char *Interwave, s[INI_STRING_SIZE]; - VFile *IwFile; - int CodecBase, CodecDma, i; - - Interwave = getenv ("INTERWAVE"); - if (Interwave == NULL) - return (false); - - // Open IW.INI - IwFile = ini_fopen (Interwave, "rt"); - if (IwFile == NULL) - return (false); - - // Read codec base and codec DMA - ini_fgets (IwFile, "setup 0", "CodecBase", s); - sscanf (s, "%X", &CodecBase); - ini_fgets (IwFile, "setup 0", "DMA2", s); - sscanf (s, "%i", &CodecDma); - - ini_fclose (IwFile); - - // Make sure numbers OK - if (CodecBase == 0 || CodecDma == 0) - return (false); - - CodecRegisterSelect = CodecBase; - CodecData = CodecBase + 1; - CodecStatus = CodecBase + 2; - DmaChannel = CodecDma; - - // Make sure there is a CODEC at the CODEC base - - // Clear any pending IRQs - dos_inportb (CodecStatus); - dos_outportb (CodecStatus, 0); - - // Wait for 'INIT' bit to clear - for (i = 0; i < 0xFFFF; i++) - if ((dos_inportb (CodecRegisterSelect) & 0x80) == 0) - break; - if (i == 0xFFFF) - return (false); - - // Get chip revision - can not be zero - dos_outportb (CodecRegisterSelect, CODEC_MODE_AND_ID); - if ((dos_inportb (CodecRegisterSelect) & 0x7F) != CODEC_MODE_AND_ID) - return (false); - if ((dos_inportb (CodecData) & 0x0F) == 0) - return (false); - - HaveCodec = 1; - Con_Printf ("Sound Card is UltraSound PnP\n"); - return (true); -} - -//============================================================================= -// Get UltraSound MAX configuration if any -//============================================================================= -static qboolean -GUS_GetMAXData (void) -{ - char *Ultrasnd, *Ultra16; - int i; - int GusBase, Dma1, Dma2, Irq1, Irq2; - int CodecBase, CodecDma, CodecIrq, CodecType; - BYTE MaxVal; - - Ultrasnd = getenv ("ULTRASND"); - Ultra16 = getenv ("ULTRA16"); - if (Ultrasnd == NULL || Ultra16 == NULL) - return (false); - - sscanf (Ultrasnd, "%x,%i,%i,%i,%i", &GusBase, &Dma1, &Dma2, &Irq1, &Irq2); - sscanf (Ultra16, "%x,%i,%i,%i", &CodecBase, &CodecDma, &CodecIrq, - &CodecType); - - if (CodecType == 0 && CodecDma != 0) - DmaChannel = CodecDma & 0x07; - else - DmaChannel = Dma2 & 0x07; - - // Make sure there is a GUS at GUS base - dos_outportb (GusBase + 0x08, 0x55); - if (dos_inportb (GusBase + 0x0A) != 0x55) - return (false); - dos_outportb (GusBase + 0x08, 0xAA); - if (dos_inportb (GusBase + 0x0A) != 0xAA) - return (false); - - // Program CODEC control register - MaxVal = ((CodecBase & 0xF0) >> 4) | 0x40; - if (Dma1 > 3) - MaxVal |= 0x10; - if (Dma2 > 3) - MaxVal |= 0x20; - dos_outportb (GusBase + 0x106, MaxVal); - - CodecRegisterSelect = CodecBase; - CodecData = CodecBase + 1; - CodecStatus = CodecBase + 2; - - // Make sure there is a CODEC at the CODEC base - - // Clear any pending IRQs - dos_inportb (CodecStatus); - dos_outportb (CodecStatus, 0); - - // Wait for 'INIT' bit to clear - for (i = 0; i < 0xFFFF; i++) - if ((dos_inportb (CodecRegisterSelect) & 0x80) == 0) - break; - if (i == 0xFFFF) - return (false); - - // Get chip revision - can not be zero - dos_outportb (CodecRegisterSelect, CODEC_MODE_AND_ID); - if ((dos_inportb (CodecRegisterSelect) & 0x7F) != CODEC_MODE_AND_ID) - return (false); - if ((dos_inportb (CodecData) & 0x0F) == 0) - return (false); - - HaveCodec = 1; - Con_Printf ("Sound Card is UltraSound MAX\n"); - return (true); -} - -//============================================================================= -// Get regular UltraSound configuration if any -//============================================================================= -static qboolean -GUS_GetGUSData (void) -{ - char *Ultrasnd; - int GusBase, Dma1, Dma2, Irq1, Irq2, i; - - Ultrasnd = getenv ("ULTRASND"); - if (Ultrasnd == NULL) - return (false); - - sscanf (Ultrasnd, "%x,%i,%i,%i,%i", &GusBase, &Dma1, &Dma2, &Irq1, &Irq2); - - DmaChannel = Dma1 & 0x07; - - // Make sure there is a GUS at GUS base - dos_outportb (GusBase + 0x08, 0x55); - if (dos_inportb (GusBase + 0x0A) != 0x55) - return (false); - dos_outportb (GusBase + 0x08, 0xAA); - if (dos_inportb (GusBase + 0x0A) != 0xAA) - return (false); - - Gf1TimerControl = GusBase + 0x008; - Gf1PageRegister = GusBase + 0x102; - Gf1RegisterSelect = GusBase + 0x103; - Gf1DataLow = GusBase + 0x104; - Gf1DataHigh = GusBase + 0x105; - - // Reset the GUS - SetGf18 (MASTER_RESET, 0x00); - Gf1Delay (); - Gf1Delay (); - SetGf18 (MASTER_RESET, 0x01); - Gf1Delay (); - Gf1Delay (); - - // Set to max (32) voices - SetGf18 (SET_VOICES, 0xDF); - - // Clear any pending IRQ's - ClearGf1Ints (); - - // Set all registers to known values - for (i = 0; i < 32; i++) { - dos_outportb (Gf1PageRegister, i); - SetGf18 (SET_CONTROL, 0x03); - SetGf18 (SET_VOLUME_CONTROL, 0x03); - Gf1Delay (); - SetGf18 (SET_CONTROL, 0x03); - SetGf18 (SET_VOLUME_CONTROL, 0x03); - SetGf116 (SET_START_HIGH, 0); - SetGf116 (SET_START_LOW, 0); - SetGf116 (SET_END_HIGH, 0); - SetGf116 (SET_END_LOW, 0); - SetGf116 (SET_ACC_HIGH, 0); - SetGf116 (SET_ACC_LOW, 0); - SetGf18 (SET_VOLUME_RATE, 63); - SetGf18 (SET_VOLUME_START, 5); - SetGf18 (SET_VOLUME_END, 251); - SetGf116 (SET_VOLUME, 5 << 8); - } - - // Clear any pending IRQ's - ClearGf1Ints (); - - // Enable DAC etc. - SetGf18 (MASTER_RESET, 0x07); - - // Enable line output so we can hear something - dos_outportb (GusBase, 0x08); - - HaveCodec = 0; - Con_Printf ("Sound Card is UltraSound\n"); - return (true); -} - - -//============================================================================= -// Programs the DMA controller to start DMAing in Auto-init mode -//============================================================================= -static void -GUS_StartDMA (BYTE DmaChannel, short *dma_buffer, int count) -{ - int mode; - int RealAddr; - - RealAddr = ptr2real (dma_buffer); - - if (DmaChannel <= 3) { - ModeReg = 0x0B; - DisableReg = 0x0A; - ClearReg = 0x0E; - } else { - ModeReg = 0xD6; - DisableReg = 0xD4; - ClearReg = 0xDC; - } - CountReg = CountRegs[DmaChannel]; - AddrReg = AddrRegs[DmaChannel]; - - dos_outportb (DisableReg, DmaChannel | 4); // disable channel - - // set mode- see "undocumented pc", p.876 - mode = (1 << 6) // single-cycle - + (0 << 5) // address increment - + (1 << 4) // auto-init dma - + (2 << 2) // read - + (DmaChannel & 0x03); // channel # - dos_outportb (ModeReg, mode); - - // set page - dos_outportb (PageRegs[DmaChannel], RealAddr >> 16); - - if (DmaChannel <= 3) { // address is in bytes - dos_outportb (0x0C, 0); // prepare to send 16-bit value - dos_outportb (AddrReg, RealAddr & 0xff); - dos_outportb (AddrReg, (RealAddr >> 8) & 0xff); - - dos_outportb (0x0C, 0); // prepare to send 16-bit value - dos_outportb (CountReg, (count - 1) & 0xff); - dos_outportb (CountReg, (count - 1) >> 8); - } else { // address is in words - dos_outportb (0xD8, 0); // prepare to send 16-bit value - dos_outportb (AddrReg, (RealAddr >> 1) & 0xff); - dos_outportb (AddrReg, (RealAddr >> 9) & 0xff); - - dos_outportb (0xD8, 0); // prepare to send 16-bit value - dos_outportb (CountReg, ((count >> 1) - 1) & 0xff); - dos_outportb (CountReg, ((count >> 1) - 1) >> 8); - } - - dos_outportb (ClearReg, 0); // clear write mask - dos_outportb (DisableReg, DmaChannel & ~4); -} - -//============================================================================= -// Starts the CODEC playing -//============================================================================= -static void -GUS_StartCODEC (int count, BYTE FSVal) -{ - int i, j; - - // Clear any pending IRQs - dos_inportb (CodecStatus); - dos_outportb (CodecStatus, 0); - - // Set mode to 2 - dos_outportb (CodecRegisterSelect, CODEC_MODE_AND_ID); - dos_outportb (CodecData, 0xC0); - - // Stop any playback or capture which may be happening - dos_outportb (CodecRegisterSelect, CODEC_INTERFACE_CONFIG); - dos_outportb (CodecData, dos_inportb (CodecData) & 0xFC); - - // Set FS - dos_outportb (CodecRegisterSelect, CODEC_FS_FORMAT | 0x40); - dos_outportb (CodecData, FSVal | 0x50); // Or in stereo and 16 bit bits - - // Wait a bit - for (i = 0; i < 10; i++) - dos_inportb (CodecData); - - // Routine 1 to counter CODEC bug - wait for init bit to clear and then a - // bit longer (i=min loop count, j=timeout - for (i = 0, j = 0; i < 1000 && j < 0x7FFFF; j++) - if ((dos_inportb (CodecRegisterSelect) & 0x80) == 0) - i++; - - // Routine 2 to counter CODEC bug - this is from Forte's code. For me it - // does not seem to cure the problem, but is added security - // Waits till we can modify index register - for (j = 0; j < 0x7FFFF; j++) { - dos_outportb (CodecRegisterSelect, CODEC_INTERFACE_CONFIG | 0x40); - if (dos_inportb (CodecRegisterSelect) == - (CODEC_INTERFACE_CONFIG | 0x40)) break; - } - - // Perform ACAL - dos_outportb (CodecRegisterSelect, CODEC_INTERFACE_CONFIG | 0x40); - dos_outportb (CodecData, 0x08); - - // Clear MCE bit - this makes ACAL happen - dos_outportb (CodecRegisterSelect, CODEC_INTERFACE_CONFIG); - - // Wait for ACAL to finish - for (j = 0; j < 0x7FFFF; j++) { - if ((dos_inportb (CodecRegisterSelect) & 0x80) != 0) - continue; - dos_outportb (CodecRegisterSelect, CODEC_ERROR_STATUS_AND_INIT); - if ((dos_inportb (CodecData) & 0x20) == 0) - break; - } - - // Clear ACAL bit - dos_outportb (CodecRegisterSelect, CODEC_INTERFACE_CONFIG | 0x40); - dos_outportb (CodecData, 0x00); - dos_outportb (CodecRegisterSelect, CODEC_INTERFACE_CONFIG); - - // Set some other junk - dos_outportb (CodecRegisterSelect, CODEC_LOOPBACK_CONTROL); - dos_outportb (CodecData, 0x00); - dos_outportb (CodecRegisterSelect, CODEC_PIN_CONTROL); - dos_outportb (CodecData, 0x08); // IRQ is disabled in PIN control - - // Set count (it doesn't really matter what value we stuff in here - dos_outportb (CodecRegisterSelect, CODEC_PLAYBACK_LOWER_BASE_COUNT); - dos_outportb (CodecData, count & 0xFF); - dos_outportb (CodecRegisterSelect, CODEC_PLAYBACK_UPPER_BASE_COUNT); - dos_outportb (CodecData, count >> 8); - - // Start playback - dos_outportb (CodecRegisterSelect, CODEC_INTERFACE_CONFIG); - dos_outportb (CodecData, 0x01); -} - -//============================================================================= -// Starts the GF1 playing -//============================================================================= -static void -GUS_StartGf1 (int count, BYTE Voices) -{ - DWORD StartAddressL, EndAddressL, StartAddressR, EndAddressR; - - // Set number of voices to give us the sampling rate we want - SetGf18 (SET_VOICES, 0xC0 | (Voices - 1)); - - // Figure out addresses - StartAddressL = ConvertTo16 (0); - EndAddressL = ConvertTo16 (count - 2 - 2); - StartAddressR = ConvertTo16 (2); - EndAddressR = ConvertTo16 (count - 2); - - // Set left voice addresses - dos_outportb (Gf1PageRegister, 0); - SetGf116 (SET_START_LOW, StartAddressL << 9); - SetGf116 (SET_START_HIGH, StartAddressL >> 7); - SetGf116 (SET_ACC_LOW, StartAddressL << 9); - SetGf116 (SET_ACC_HIGH, StartAddressL >> 7); - SetGf116 (SET_END_LOW, EndAddressL << 9); - SetGf116 (SET_END_HIGH, EndAddressL >> 7); - // Set balance to full left - SetGf18 (SET_BALANCE, 0); - // Set volume to full - SetGf116 (SET_VOLUME, 0xFFF0); - // Set FC to 2 (so we play every second sample) - SetGf116 (SET_FREQUENCY, 0x0800); - - // Set right voice addresses - dos_outportb (Gf1PageRegister, 1); - SetGf116 (SET_START_LOW, StartAddressR << 9); - SetGf116 (SET_START_HIGH, StartAddressR >> 7); - SetGf116 (SET_ACC_LOW, StartAddressR << 9); - SetGf116 (SET_ACC_HIGH, StartAddressR >> 7); - SetGf116 (SET_END_LOW, EndAddressR << 9); - SetGf116 (SET_END_HIGH, EndAddressR >> 7); - // Set balance to full right - SetGf18 (SET_BALANCE, 15); - // Set volume to full - SetGf116 (SET_VOLUME, 0xFFF0); - // Set FC to 2 (so we play every second sample) - SetGf116 (SET_FREQUENCY, 0x0800); - - // Start voices - dos_outportb (Gf1PageRegister, 0); - SetGf18 (SET_CONTROL, 0x0C); - dos_outportb (Gf1PageRegister, 1); - SetGf18 (SET_CONTROL, 0x0C); - Gf1Delay (); - dos_outportb (Gf1PageRegister, 0); - SetGf18 (SET_CONTROL, 0x0C); - dos_outportb (Gf1PageRegister, 1); - SetGf18 (SET_CONTROL, 0x0C); -} - - -//============================================================================= -// Figures out what kind of UltraSound we have, if any, and starts it playing -//============================================================================= -qboolean -GUS_Init (void) -{ - int rc; - int RealAddr; - BYTE FSVal, Voices; - struct CodecRateStruct *CodecRate; - struct Gf1RateStruct *Gf1Rate; - - // See what kind of UltraSound we have, if any - if (GUS_GetIWData () == false) - if (GUS_GetMAXData () == false) - if (GUS_GetGUSData () == false) - return (false); - - shm = &sn; - - if (HaveCodec) { - // do 11khz sampling rate unless command line parameter wants - // different - shm->speed = 11025; - FSVal = 0x03; - rc = COM_CheckParm ("-sspeed"); - if (rc) { - shm->speed = Q_atoi (com_argv[rc + 1]); - - // Make sure rate not too high - if (shm->speed > 48000) - shm->speed = 48000; - - // Adjust speed to match one of the possible CODEC rates - for (CodecRate = CodecRates; CodecRate->Rate != 0; CodecRate++) { - if (shm->speed <= CodecRate->Rate) { - shm->speed = CodecRate->Rate; - FSVal = CodecRate->FSVal; - break; - } - } - } - // Always do 16 bit stereo - shm->channels = 2; - shm->samplebits = 16; - - // allocate buffer twice the size we need so we can get aligned - // buffer - dma_buffer = dos_getmemory (BUFFER_SIZE * 2); - if (dma_buffer == NULL) { - Con_Printf ("Couldn't allocate sound dma buffer"); - return false; - } - - RealAddr = ptr2real (dma_buffer); - RealAddr = (RealAddr + BUFFER_SIZE) & ~(BUFFER_SIZE - 1); - dma_buffer = (short *) real2ptr (RealAddr); - - // Zero off DMA buffer - memset (dma_buffer, 0, BUFFER_SIZE); - - shm->soundalive = true; - shm->splitbuffer = false; - - shm->samplepos = 0; - shm->submission_chunk = 1; - shm->buffer = (unsigned char *) dma_buffer; - shm->samples = BUFFER_SIZE / (shm->samplebits / 8); - - GUS_StartDMA (DmaChannel, dma_buffer, BUFFER_SIZE); - GUS_StartCODEC (BUFFER_SIZE, FSVal); - } else { - // do 19khz sampling rate unless command line parameter wants - // different - shm->speed = 19293; - Voices = 32; - rc = COM_CheckParm ("-sspeed"); - if (rc) { - shm->speed = Q_atoi (com_argv[rc + 1]); - - // Make sure rate not too high - if (shm->speed > 44100) - shm->speed = 44100; - - // Adjust speed to match one of the possible GF1 rates - for (Gf1Rate = Gf1Rates; Gf1Rate->Rate != 0; Gf1Rate++) { - if (shm->speed <= Gf1Rate->Rate) { - shm->speed = Gf1Rate->Rate; - Voices = Gf1Rate->Voices; - break; - } - } - } - // Always do 16 bit stereo - shm->channels = 2; - shm->samplebits = 16; - - // allocate buffer twice the size we need so we can get aligned - // buffer - dma_buffer = dos_getmemory (BUFFER_SIZE * 2); - if (dma_buffer == NULL) { - Con_Printf ("Couldn't allocate sound dma buffer"); - return false; - } - - RealAddr = ptr2real (dma_buffer); - RealAddr = (RealAddr + BUFFER_SIZE) & ~(BUFFER_SIZE - 1); - dma_buffer = (short *) real2ptr (RealAddr); - - // Zero off DMA buffer - memset (dma_buffer, 0, BUFFER_SIZE); - - shm->soundalive = true; - shm->splitbuffer = false; - - shm->samplepos = 0; - shm->submission_chunk = 1; - shm->buffer = (unsigned char *) dma_buffer; - shm->samples = BUFFER_SIZE / (shm->samplebits / 8); - - GUS_StartDMA (DmaChannel, dma_buffer, BUFFER_SIZE); - SetGf116 (SET_DMA_ADDRESS, 0x0000); - if (DmaChannel <= 3) - SetGf18 (DMA_CONTROL, 0x41); - else - SetGf18 (DMA_CONTROL, 0x45); - GUS_StartGf1 (BUFFER_SIZE, Voices); - } - return (true); -} - -//============================================================================= -// Returns the current playback position -//============================================================================= -int -GUS_GetDMAPos (void) -{ - int count; - - if (HaveCodec) { - // clear 16-bit reg flip-flop - // load the current dma count register - if (DmaChannel < 4) { - dos_outportb (0x0C, 0); - count = dos_inportb (CountReg); - count += dos_inportb (CountReg) << 8; - if (shm->samplebits == 16) - count /= 2; - count = shm->samples - (count + 1); - } else { - dos_outportb (0xD8, 0); - count = dos_inportb (CountReg); - count += dos_inportb (CountReg) << 8; - if (shm->samplebits == 8) - count *= 2; - count = shm->samples - (count + 1); - } - - } else { - // Read current position from GF1 - dos_outportb (Gf1PageRegister, 0); - count = (GetGf116 (GET_ACC_HIGH) << 7) & 0xFFFF; - // See which half of buffer we are in. Note that since this is 16 bit - // data we are playing, position is in 16 bit samples - if (GetGf18 (DMA_CONTROL) & 0x40) { - GUS_StartDMA (DmaChannel, dma_buffer, BUFFER_SIZE); - SetGf116 (SET_DMA_ADDRESS, 0x0000); - if (DmaChannel <= 3) - SetGf18 (DMA_CONTROL, 0x41); - else - SetGf18 (DMA_CONTROL, 0x45); - } - } - - shm->samplepos = count & (shm->samples - 1); - return (shm->samplepos); -} - -//============================================================================= -// Stops the UltraSound playback -//============================================================================= -void -GUS_Shutdown (void) -{ - if (HaveCodec) { - // Stop CODEC - dos_outportb (CodecRegisterSelect, CODEC_INTERFACE_CONFIG); - dos_outportb (CodecData, 0x01); - } else { - // Stop Voices - dos_outportb (Gf1PageRegister, 0); - SetGf18 (SET_CONTROL, 0x03); - dos_outportb (Gf1PageRegister, 1); - SetGf18 (SET_CONTROL, 0x03); - Gf1Delay (); - dos_outportb (Gf1PageRegister, 0); - SetGf18 (SET_CONTROL, 0x03); - dos_outportb (Gf1PageRegister, 1); - SetGf18 (SET_CONTROL, 0x03); - - // Stop any DMA - SetGf18 (DMA_CONTROL, 0x00); - GetGf18 (DMA_CONTROL); - } - - dos_outportb (DisableReg, DmaChannel | 4); // disable dma channel -}