diff options
author | markm <markm@FreeBSD.org> | 1997-10-31 06:30:22 +0000 |
---|---|---|
committer | markm <markm@FreeBSD.org> | 1997-10-31 06:30:22 +0000 |
commit | be4808f6e2badf1629d651d8f1d2f5c7707e47a8 (patch) | |
tree | 9a3e498c45ec2bf39c7d1c79c9aa4bab90d109e8 /sys/i386/isa/sound/gus_wave.c | |
parent | 17d7551904f5e100c3f914c00c72350a63a49dfa (diff) | |
download | FreeBSD-src-be4808f6e2badf1629d651d8f1d2f5c7707e47a8.zip FreeBSD-src-be4808f6e2badf1629d651d8f1d2f5c7707e47a8.tar.gz |
Upgrade the sound sources to Amancio Hasty's latest-and-greatest.
This is based on Voxware 3.5, and corresponds to Amancio's `guspnp21'.
Bug reports to Amancio, please!
Diffstat (limited to 'sys/i386/isa/sound/gus_wave.c')
-rw-r--r-- | sys/i386/isa/sound/gus_wave.c | 6731 |
1 files changed, 4080 insertions, 2651 deletions
diff --git a/sys/i386/isa/sound/gus_wave.c b/sys/i386/isa/sound/gus_wave.c index e0f946d6..f1269f5 100644 --- a/sys/i386/isa/sound/gus_wave.c +++ b/sys/i386/isa/sound/gus_wave.c @@ -1,10 +1,10 @@ /* * sound/gus_wave.c - * + * * Driver for the Gravis UltraSound wave table synth. - * + * * Copyright by Hannu Savolainen 1993, 1994 - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright @@ -12,7 +12,7 @@ * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -24,83 +24,109 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * + * */ #include <i386/isa/sound/sound_config.h> -#include <machine/ultrasound.h> +#include <i386/isa/sound/ultrasound.h> #include <i386/isa/sound/gus_hw.h> +#include <i386/isa/sound/iwdefs.h> +#include <machine/clock.h> -static unsigned char gus_look8 __P((int reg)); -static unsigned short gus_read16 __P((int reg)); -static void gus_write_addr __P((int reg, unsigned long address, int is16bit)); -static void gus_write16 __P((int reg, unsigned int data)); +/* PnP stuff */ +#define GUS_PNP_ID 0x100561e -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS) +#define MAX_CARDS 8 +#define MAX_GUS_PNP 8 + + +/* Static ports */ +#define PADDRESS 0x279 +#define PWRITE_DATA 0xa79 +#define SET_CSN 0x06 +#define PSTATUS 0x05 + +/* PnP Registers. Write to ADDRESS and then use WRITE/READ_DATA */ +#define SET_RD_DATA 0x00 +#define SERIAL_ISOLATION 0x01 +#define WAKE 0x03 + +#if defined(CONFIG_GUS) + +IWAVE iw; +#define ENTER_CRITICAL + +#define LEAVE_CRITICAL #define MAX_SAMPLE 150 #define MAX_PATCH 256 -struct voice_info - { - unsigned long orig_freq; - unsigned long current_freq; - unsigned long mode; - int bender; - int bender_range; - int panning; - int midi_volume; - unsigned int initial_volume; - unsigned int current_volume; - int loop_irq_mode, loop_irq_parm; +#define MAX_GUS_PNP 12 +u_int gus_pnp_found[MAX_GUS_PNP] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +struct voice_info { + u_long orig_freq; + u_long current_freq; + u_long mode; + int bender; + int bender_range; + int panning; + int midi_volume; + u_int initial_volume; + u_int current_volume; + int loop_irq_mode, loop_irq_parm; #define LMODE_FINISH 1 #define LMODE_PCM 2 #define LMODE_PCM_STOP 3 - int volume_irq_mode, volume_irq_parm; + int volume_irq_mode, volume_irq_parm; #define VMODE_HALT 1 #define VMODE_ENVELOPE 2 #define VMODE_START_NOTE 3 - int env_phase; - unsigned char env_rate[6]; - unsigned char env_offset[6]; + int env_phase; + u_char env_rate[6]; + u_char env_offset[6]; - /* - * Volume computation parameters for gus_adagio_vol() - */ - int main_vol, expression_vol, patch_vol; + /* + * Volume computation parameters for gus_adagio_vol() + */ + int main_vol, expression_vol, patch_vol; - /* Variables for "Ultraclick" removal */ - int dev_pending, note_pending, volume_pending, sample_pending; - char kill_pending; - long offset_pending; + /* Variables for "Ultraclick" removal */ + int dev_pending, note_pending, volume_pending, sample_pending; + char kill_pending; + long offset_pending; - }; +}; static struct voice_alloc_info *voice_alloc; extern int gus_base; extern int gus_irq, gus_dma; +static int gus_dma2 = -1; +static int dual_dma_mode = 0; static long gus_mem_size = 0; static long free_mem_ptr = 0; -static int gus_busy[MAX_AUDIO_DEV], gus_dspnum=0; -static int gus_dma_read=0; +static int gus_no_dma = 0; static int nr_voices = 0; static int gus_devnum = 0; static int volume_base, volume_scale, volume_method; static int gus_recmask = SOUND_MASK_MIC; static int recording_active = 0; static int only_read_access = 0; +static int only_8_bits = 0; int gus_wave_volume = 60; -static int gus_pcm_volume = 80; +int gus_pcm_volume = 80; int have_gus_max = 0; static int gus_line_vol = 100, gus_mic_vol = 0; -static unsigned char mix_image = 0x00; +static u_char mix_image = 0x00; +int gus_timer_enabled = 0; /* - * Current version of this driver doesn't allow synth and PCM functions - * at the same time. The active_device specifies the active driver + * Current version of this driver doesn't allow synth and PCM functions at + * the same time. The active_device specifies the active driver */ static int active_device = 0; @@ -112,7 +138,9 @@ static int gus_sampling_speed; static int gus_sampling_channels; static int gus_sampling_bits; -DEFINE_WAIT_QUEUE (dram_sleeper, dram_sleep_flag); +static int *dram_sleeper = NULL; +static volatile struct snd_wait dram_sleep_flag = +{0}; /* * Variables and buffers for PCM output @@ -127,43 +155,45 @@ static volatile int dma_active; static int pcm_opened = 0; static int pcm_current_dev; static int pcm_current_block; -static unsigned long pcm_current_buf; +static u_long pcm_current_buf; static int pcm_current_count; static int pcm_current_intrflag; -#if defined(__FreeBSD__) -static char *gus_copy_buf; -#endif +extern sound_os_info *gus_osp; -static struct voice_info voices[32]; +struct voice_info voices[32]; static int freq_div_table[] = { - 44100, /* 14 */ - 41160, /* 15 */ - 38587, /* 16 */ - 36317, /* 17 */ - 34300, /* 18 */ - 32494, /* 19 */ - 30870, /* 20 */ - 29400, /* 21 */ - 28063, /* 22 */ - 26843, /* 23 */ - 25725, /* 24 */ - 24696, /* 25 */ - 23746, /* 26 */ - 22866, /* 27 */ - 22050, /* 28 */ - 21289, /* 29 */ - 20580, /* 30 */ - 19916, /* 31 */ - 19293 /* 32 */ + 44100, /* 14 */ + 41160, /* 15 */ + 38587, /* 16 */ + 36317, /* 17 */ + 34300, /* 18 */ + 32494, /* 19 */ + 30870, /* 20 */ + 29400, /* 21 */ + 28063, /* 22 */ + 26843, /* 23 */ + 25725, /* 24 */ + 24696, /* 25 */ + 23746, /* 26 */ + 22866, /* 27 */ + 22050, /* 28 */ + 21289, /* 29 */ + 20580, /* 30 */ + 19916, /* 31 */ + 19293 /* 32 */ }; static struct patch_info *samples; +struct patch_info *dbg_samples; +int dbg_samplep; + static long sample_ptrs[MAX_SAMPLE + 1]; static int sample_map[32]; static int free_sample; +static int mixer_type = 0; static int patch_table[MAX_PATCH]; @@ -172,3274 +202,4673 @@ static int patch_map[32]; static struct synth_info gus_info = {"Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH}; -static void gus_poke (long addr, unsigned char data); -static void compute_and_set_volume (int voice, int volume, int ramp_time); -extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev); -extern unsigned short gus_linear_vol (int vol, int mainvol); -static void compute_volume (int voice, int volume); -static void do_volume_irq (int voice); -static void set_input_volumes (void); +static void gus_default_mixer_init(void); + +int guswave_start_note2(int dev, int voice, int note_num, int volume); +static void gus_poke(long addr, u_char data); +void compute_and_set_volume(int voice, int volume, int ramp_time); +extern u_short gus_adagio_vol(int vel, int mainv, int xpn, int voicev); +extern u_short gus_linear_vol(int vol, int mainvol); +void compute_volume(int voice, int volume); +void do_volume_irq(int voice); +static void set_input_volumes(void); +static void gus_tmr_install(int io_base); + +void SEND(int d, int r); +int get_serial(int rd_port, u_char *data); +void send_Initiation_LFSR(void); +int isolation_protocol(int rd_port); + #define INSTANT_RAMP -1 /* Instant change. No ramping */ #define FAST_RAMP 0 /* Fastest possible ramp */ + +/* Crystal Select */ +#define CODEC_XTAL2 0x01 /* 16.9344 crystal */ +#define CODEC_XTAL1 0x00 /* 24.576 crystal */ +/************************************************************************/ + +/************************************************************************/ +/* Definitions for CONFIG_1 register */ +#define CODEC_CFIG1I_DEFAULT 0x03 | 0x8 +#define CODEC_CAPTURE_PIO 0x80 /* Capture PIO enable */ +#define CODEC_PLAYBACK_PIO 0x40 /* Playback PIO enable */ +#define CODEC_AUTOCALIB 0x08 /* auto calibrate */ +#define CODEC_SINGLE_DMA 0x04 /* Use single DMA channel */ +#define CODEC_RE 0x02 /* Capture enable */ +#define CODEC_PE 0x01 /* playback enable */ +/************************************************************************/ + +/************************************************************************/ +/* Definitions for CONFIG_2 register */ +#define CODEC_CFIG2I_DEFAULT 0x81 +#define CODEC_OFVS 0x80 /* Output Full Scale Voltage */ +#define CODEC_TE 0x40 /* Timer Enable */ +#define CODEC_RSCD 0x20 /* Recors Sample Counter Disable */ +#define CODEC_PSCD 0x10 /* Playback Sample Counter Disable */ +#define CODEC_DAOF 0x01 /* D/A Ouput Force Enable */ +/************************************************************************/ + +/************************************************************************/ +/* Definitions for CONFIG_3 register */ +/* #define CODEC_CFIG3I_DEFAULT 0xe0 0x02 when synth DACs are working */ + +#define CODEC_CFIG3I_DEFAULT 0xc0 /* 0x02 when synth DACs are working */ +#define CODEC_RPIE 0x80 /* Record FIFO IRQ Enable */ +#define CODEC_PPIE 0x40 /* Playback FIFO IRQ Enable */ +#define CODEC_FT_MASK 0x30 /* FIFO Threshold Select */ +#define CODEC_PVFM 0x04 /* Playback Variable Frequency Mode */ +#define CODEC_SYNA 0x02 /* AUX1/Synth Signal Select */ +/************************************************************************/ + +/************************************************************************/ +/* Definitions for EXTERNAL_CONTROL register */ +#define CODEC_CEXTI_DEFAULT 0x00 +#define CODEC_IRQ_ENABLE 0x02 /* interrupt enable */ +#define CODEC_GPOUT1 0x80 /* external control #1 */ +#define CODEC_GPOUT0 0x40 /* external control #0 */ +/************************************************************************/ + +/************************************************************************/ +/* Definitions for MODE_SELECT_ID register */ +#define CODEC_MODE_DEFAULT 0x40 +#define CODEC_MODE_MASK 0x60 +#define CODEC_ID_BIT4 0x80 +#define CODEC_ID_BIT3_0 0x0F +/************************************************************************/ +#define CONFIG_1 0x09 +#define EXTERNAL_CONTROL 0x0a/* Pin control */ +#define STATUS_2 0x0b/* Test and initialization */ +#define MODE_SELECT_ID 0x0c/* Miscellaneaous information */ +#define LOOPBACK 0x0d/* Digital Mix */ +#define UPPER_PLAY_COUNT 0x0e/* Playback Upper Base Count */ +#define LOWER_PLAY_COUNT 0x0f/* Playback Lower Base Count */ +#define CONFIG_2 0x10 +#define CONFIG_3 0x11 + + +#define IWL_CODEC_OUT(reg, val) \ + { outb(iwl_codec_base, reg); outb(iwl_codec_data, val); } + +#define IWL_CODEC_IN(reg, val) \ + { outb(iwl_codec_base, reg); val = inb(iwl_codec_data); } + + +u_char gus_look8(int reg); + +void gus_write16(int reg, u_int data); + +u_short gus_read16(int reg); + +void gus_write_addr(int reg, u_long address, int is16bit); +void IwaveLineLevel(char level, char index); +void IwaveInputSource(BYTE index, BYTE source); +void IwaveDelay(WORD count); +void IwaveStopDma(BYTE path); +void IwavePnpGetCfg(void); +void IwavePnpDevice(BYTE dev); +void IwavePnpSetCfg(void); +void IwavePnpKey(void); +BYTE IwavePnpIsol(PORT * pnpread); +void IwaveCfgIOSpace(void); + +void IwavePnpSerial(PORT pnprdp, BYTE csn, BYTE * vendor, DWORD * serial); + + +void IwavePnpPeek(PORT pnprdp, WORD bytes, BYTE * data); +void IwavePnpEeprom(BYTE ctrl); +void IwavePnpActivate(BYTE dev, BYTE bool); + +void IwavePnpPower(BYTE mode); +void IwavePnpWake(BYTE csn); +PORT IwavePnpIOcheck(PORT base, BYTE no_ports); + +BYTE IwavePnpGetCSN(DWORD VendorID, BYTE csn_max); +BYTE IwavePnpPing(DWORD VendorID); +WORD IwaveMemSize(void); +BYTE IwaveMemPeek(ADDRESS addr); +void IwaveMemPoke(ADDRESS addr, BYTE datum); +void IwaveMemCfg(DWORD * lpbanks); +void IwaveCodecIrq(BYTE mode); +WORD IwaveRegPeek(DWORD reg_mnem); + +void IwaveRegPoke(DWORD reg_mnem, WORD datum); +void IwaveCodecMode(char mode); +void IwaveLineMute(BYTE mute, BYTE inx); +void Iwaveinitcodec(void); +int IwaveOpen(char voices, char mode, struct address_info * hw); + + static void -reset_sample_memory (void) +reset_sample_memory(void) { - int i; + int i; - for (i = 0; i <= MAX_SAMPLE; i++) - sample_ptrs[i] = -1; - for (i = 0; i < 32; i++) - sample_map[i] = -1; - for (i = 0; i < 32; i++) - patch_map[i] = -1; + for (i = 0; i <= MAX_SAMPLE; i++) + sample_ptrs[i] = -1; + for (i = 0; i < 32; i++) + sample_map[i] = -1; + for (i = 0; i < 32; i++) + patch_map[i] = -1; - gus_poke (0, 0); /* Put a silent sample to the beginning */ - gus_poke (1, 0); - free_mem_ptr = 2; + gus_poke(0, 0); /* Put a silent sample to the beginning */ + gus_poke(1, 0); + free_mem_ptr = 2; - free_sample = 0; + free_sample = 0; - for (i = 0; i < MAX_PATCH; i++) - patch_table[i] = -1; + for (i = 0; i < MAX_PATCH; i++) + patch_table[i] = -1; } void -gus_delay (void) +gus_delay(void) { - int i; + int i; - for (i = 0; i < 7; i++) - INB (u_DRAMIO); + for (i = 0; i < 7; i++) + inb(u_DRAMIO); } static void -gus_poke (long addr, unsigned char data) +gus_poke(long addr, u_char data) { /* Writes a byte to the DRAM */ - unsigned long flags; + u_long flags; - DISABLE_INTR (flags); - OUTB (0x43, u_Command); - OUTB (addr & 0xff, u_DataLo); - OUTB ((addr >> 8) & 0xff, u_DataHi); + flags = splhigh(); + outb(u_Command, 0x43); + outb(u_DataLo, addr & 0xff); + outb(u_DataHi, (addr >> 8) & 0xff); - OUTB (0x44, u_Command); - OUTB ((addr >> 16) & 0xff, u_DataHi); - OUTB (data, u_DRAMIO); - RESTORE_INTR (flags); + outb(u_Command, 0x44); + outb(u_DataHi, (addr >> 16) & 0xff); + outb(u_DRAMIO, data); + splx(flags); } -static unsigned char -gus_peek (long addr) +static u_char +gus_peek(long addr) { /* Reads a byte from the DRAM */ - unsigned long flags; - unsigned char tmp; + u_long flags; + u_char tmp; - DISABLE_INTR (flags); - OUTB (0x43, u_Command); - OUTB (addr & 0xff, u_DataLo); - OUTB ((addr >> 8) & 0xff, u_DataHi); + flags = splhigh(); + outb(u_Command, 0x43); + outb(u_DataLo, addr & 0xff); + outb(u_DataHi, (addr >> 8) & 0xff); - OUTB (0x44, u_Command); - OUTB ((addr >> 16) & 0xff, u_DataHi); - tmp = INB (u_DRAMIO); - RESTORE_INTR (flags); + outb(u_Command, 0x44); + outb(u_DataHi, (addr >> 16) & 0xff); + tmp = inb(u_DRAMIO); + splx(flags); - return tmp; + return tmp; } void -gus_write8 (int reg, unsigned int data) +gus_write8(int reg, u_int data) { /* Writes to an indirect register (8 bit) */ - unsigned long flags; + u_long flags; - DISABLE_INTR (flags); - - OUTB (reg, u_Command); - OUTB ((unsigned char) (data & 0xff), u_DataHi); - - RESTORE_INTR (flags); + flags = splhigh(); + outb(u_Command, reg); + outb(u_DataHi, (u_char) (data & 0xff)); + splx(flags); } -static unsigned char -gus_read8 (int reg) -{ /* Reads from an indirect register (8 bit). Offset 0x80. */ - unsigned long flags; - unsigned char val; +u_char +gus_read8(int reg) +{ /* Reads from an indirect register (8 bit). Offset 0x80. */ + u_long flags; + u_char val; - DISABLE_INTR (flags); - OUTB (reg | 0x80, u_Command); - val = INB (u_DataHi); - RESTORE_INTR (flags); + flags = splhigh(); + outb(u_Command, reg | 0x80); + val = inb(u_DataHi); + splx(flags); - return val; + return val; } -static unsigned char -gus_look8 (int reg) -{ /* Reads from an indirect register (8 bit). No additional offset. */ - unsigned long flags; - unsigned char val; +u_char +gus_look8(int reg) +{ /* Reads from an indirect register (8 bit). No additional offset. */ + u_long flags; + u_char val; - DISABLE_INTR (flags); - OUTB (reg, u_Command); - val = INB (u_DataHi); - RESTORE_INTR (flags); + flags = splhigh(); + outb(u_Command, reg); + val = inb(u_DataHi); + splx(flags); - return val; + return val; } -static void -gus_write16 (int reg, unsigned int data) -{ /* Writes to an indirect register (16 bit) */ - unsigned long flags; +void +gus_write16(int reg, u_int data) +{ /* Writes to an indirect register (16 bit) */ + u_long flags; - DISABLE_INTR (flags); + flags = splhigh(); - OUTB (reg, u_Command); + outb(u_Command, reg); - OUTB ((unsigned char) (data & 0xff), u_DataLo); - OUTB ((unsigned char) ((data >> 8) & 0xff), u_DataHi); + outb(u_DataLo, (u_char) (data & 0xff)); + outb(u_DataHi, (u_char) ((data >> 8) & 0xff)); - RESTORE_INTR (flags); + splx(flags); } -static unsigned short -gus_read16 (int reg) -{ /* Reads from an indirect register (16 bit). Offset 0x80. */ - unsigned long flags; - unsigned char hi, lo; +u_short +gus_read16(int reg) +{ /* Reads from an indirect register (16 bit). Offset 0x80. */ + u_long flags; + u_char hi, lo; - DISABLE_INTR (flags); + flags = splhigh(); - OUTB (reg | 0x80, u_Command); + outb(u_Command, reg | 0x80); - lo = INB (u_DataLo); - hi = INB (u_DataHi); + lo = inb(u_DataLo); + hi = inb(u_DataHi); - RESTORE_INTR (flags); + splx(flags); - return ((hi << 8) & 0xff00) | lo; + return ((hi << 8) & 0xff00) | lo; } -static void -gus_write_addr (int reg, unsigned long address, int is16bit) +void +gus_write_addr(int reg, u_long address, int is16bit) { /* Writes an 24 bit memory address */ - unsigned long hold_address; - unsigned long flags; + u_long hold_address; + u_long flags; - DISABLE_INTR (flags); - if (is16bit) - { - /* - * Special processing required for 16 bit patches - */ - - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } + flags = splhigh(); + if (is16bit) { + /* + * Special processing required for 16 bit patches + */ - gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); - gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff)); - /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */ - gus_delay (); - gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); - gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff)); - RESTORE_INTR (flags); + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + gus_write16(reg, (u_short) ((address >> 7) & 0xffff)); + gus_write16(reg + 1, (u_short) ((address << 9) & 0xffff)); + /* + * Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... + */ + gus_delay(); + gus_write16(reg, (u_short) ((address >> 7) & 0xffff)); + gus_write16(reg + 1, (u_short) ((address << 9) & 0xffff)); + splx(flags); } static void -gus_select_voice (int voice) +gus_select_voice(int voice) { - if (voice < 0 || voice > 31) - return; + if (voice < 0 || voice > 31) + return; - OUTB (voice, u_Voice); + outb(u_Voice, voice); } static void -gus_select_max_voices (int nvoices) +gus_select_max_voices(int nvoices) { - if (nvoices < 14) - nvoices = 14; - if (nvoices > 32) - nvoices = 32; + if (nvoices < 14) + nvoices = 14; + if (nvoices > 32) + nvoices = 32; - voice_alloc->max_voice = nr_voices = nvoices; + voice_alloc->max_voice = nr_voices = nvoices; - gus_write8 (0x0e, (nvoices - 1) | 0xc0); + gus_write8(0x0e, (nvoices - 1) | 0xc0); } static void -gus_voice_on (unsigned int mode) +gus_voice_on(u_int mode) { - gus_write8 (0x00, (unsigned char) (mode & 0xfc)); - gus_delay (); - gus_write8 (0x00, (unsigned char) (mode & 0xfc)); + gus_write8(0x00, (u_char) (mode & 0xfc)); + gus_delay(); + gus_write8(0x00, (u_char) (mode & 0xfc)); } static void -gus_voice_off (void) +gus_voice_off(void) { - gus_write8 (0x00, gus_read8 (0x00) | 0x03); + gus_write8(0x00, gus_read8(0x00) | 0x03); } static void -gus_voice_mode (unsigned int m) +gus_voice_mode(u_int m) { - unsigned char mode = (unsigned char) (m & 0xff); + u_char mode = (u_char) (m & 0xff); - gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | - (mode & 0xfc)); /* Don't touch last two bits */ - gus_delay (); - gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); + gus_write8(0x00, (gus_read8(0x00) & 0x03) | + (mode & 0xfc)); /* Don't touch last two bits */ + gus_delay(); + gus_write8(0x00, (gus_read8(0x00) & 0x03) | (mode & 0xfc)); } static void -gus_voice_freq (unsigned long freq) +gus_voice_freq(u_long freq) { - unsigned long divisor = freq_div_table[nr_voices - 14]; - unsigned short fc; + u_long divisor = freq_div_table[nr_voices - 14]; + u_short fc; - fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor); - fc = fc << 1; + fc = (u_short) (((freq << 9) + (divisor >> 1)) / divisor); + fc = fc << 1; - gus_write16 (0x01, fc); + gus_write16(0x01, fc); } static void -gus_voice_volume (unsigned int vol) +gus_voice_volume(u_int vol) { - gus_write8 (0x0d, 0x03); /* Stop ramp before setting volume */ - gus_write16 (0x09, (unsigned short) (vol << 4)); + gus_write8(0x0d, 0x03); /* Stop ramp before setting volume */ + gus_write16(0x09, (u_short) (vol << 4)); } static void -gus_voice_balance (unsigned int balance) +gus_voice_balance(u_int balance) { - gus_write8 (0x0c, (unsigned char) (balance & 0xff)); + gus_write8(0x0c, (u_char) (balance & 0xff)); } static void -gus_ramp_range (unsigned int low, unsigned int high) +gus_ramp_range(u_int low, u_int high) { - gus_write8 (0x07, (unsigned char) ((low >> 4) & 0xff)); - gus_write8 (0x08, (unsigned char) ((high >> 4) & 0xff)); + gus_write8(0x07, (u_char) ((low >> 4) & 0xff)); + gus_write8(0x08, (u_char) ((high >> 4) & 0xff)); } static void -gus_ramp_rate (unsigned int scale, unsigned int rate) +gus_ramp_rate(u_int scale, u_int rate) { - gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f))); + gus_write8(0x06, (u_char) (((scale & 0x03) << 6) | (rate & 0x3f))); } static void -gus_rampon (unsigned int m) +gus_rampon(u_int m) { - unsigned char mode = (unsigned char) (m & 0xff); + u_char mode = (u_char) (m & 0xff); - gus_write8 (0x0d, mode & 0xfc); - gus_delay (); - gus_write8 (0x0d, mode & 0xfc); + gus_write8(0x0d, mode & 0xfc); + gus_delay(); + gus_write8(0x0d, mode & 0xfc); } static void -gus_ramp_mode (unsigned int m) +gus_ramp_mode(u_int m) { - unsigned char mode = (unsigned char) (m & 0xff); + u_char mode = (u_char) (m & 0xff); - gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | - (mode & 0xfc)); /* Leave the last 2 bits alone */ - gus_delay (); - gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); + gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | + (mode & 0xfc)); /* Leave the last 2 bits alone */ + gus_delay(); + gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc)); } static void -gus_rampoff (void) +gus_rampoff(void) { - gus_write8 (0x0d, 0x03); + gus_write8(0x0d, 0x03); } static void -gus_set_voice_pos (int voice, long position) +gus_set_voice_pos(int voice, long position) { - int sample_no; - - if ((sample_no = sample_map[voice]) != -1) - if (position < samples[sample_no].len) - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - voices[voice].offset_pending = position; - else - gus_write_addr (0x0a, sample_ptrs[sample_no] + position, - samples[sample_no].mode & WAVE_16_BITS); + int sample_no; + + if ((sample_no = sample_map[voice]) != -1) + if (position < samples[sample_no].len) + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + voices[voice].offset_pending = position; + else + gus_write_addr(0x0a, sample_ptrs[sample_no] + position, + samples[sample_no].mode & WAVE_16_BITS); } static void -gus_voice_init (int voice) +gus_voice_init(int voice) { - unsigned long flags; - - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_voice_volume (0); - gus_voice_off (); - gus_write_addr (0x0a, 0, 0); /* Set current position to 0 */ - gus_write8 (0x00, 0x03); /* Voice off */ - gus_write8 (0x0d, 0x03); /* Ramping off */ - voice_alloc->map[voice] = 0; - voice_alloc->alloc_times[voice] = 0; - RESTORE_INTR (flags); + u_long flags; + + flags = splhigh(); + gus_select_voice(voice); + gus_voice_volume(0); + gus_voice_off(); + gus_write_addr(0x0a, 0, 0); /* Set current position to 0 */ + gus_write8(0x00, 0x03); /* Voice off */ + gus_write8(0x0d, 0x03); /* Ramping off */ + voice_alloc->map[voice] = 0; + voice_alloc->alloc_times[voice] = 0; + splx(flags); } static void -gus_voice_init2 (int voice) -{ - voices[voice].panning = 0; - voices[voice].mode = 0; - voices[voice].orig_freq = 20000; - voices[voice].current_freq = 20000; - voices[voice].bender = 0; - voices[voice].bender_range = 200; - voices[voice].initial_volume = 0; - voices[voice].current_volume = 0; - voices[voice].loop_irq_mode = 0; - voices[voice].loop_irq_parm = 0; - voices[voice].volume_irq_mode = 0; - voices[voice].volume_irq_parm = 0; - voices[voice].env_phase = 0; - voices[voice].main_vol = 127; - voices[voice].patch_vol = 127; - voices[voice].expression_vol = 127; - voices[voice].sample_pending = -1; +gus_voice_init2(int voice) +{ + voices[voice].panning = 0; + voices[voice].mode = 0; + voices[voice].orig_freq = 20000; + voices[voice].current_freq = 20000; + voices[voice].bender = 0; + voices[voice].bender_range = 200; + voices[voice].initial_volume = 0; + voices[voice].current_volume = 0; + voices[voice].loop_irq_mode = 0; + voices[voice].loop_irq_parm = 0; + voices[voice].volume_irq_mode = 0; + voices[voice].volume_irq_parm = 0; + voices[voice].env_phase = 0; + voices[voice].main_vol = 127; + voices[voice].patch_vol = 127; + voices[voice].expression_vol = 127; + voices[voice].sample_pending = -1; } static void -step_envelope (int voice) +step_envelope(int voice) { - unsigned vol, prev_vol, phase; - unsigned char rate; - long int flags; - - if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) - { - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_rampoff (); - RESTORE_INTR (flags); - return; - /* - * Sustain phase begins. Continue envelope after receiving note off. - */ + u_int vol, prev_vol, phase; + u_char rate; + long int flags; + + if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) { + flags = splhigh(); + gus_select_voice(voice); + gus_rampoff(); + splx(flags); + return; + /* + * Sustain phase begins. Continue envelope after receiving + * note off. + */ } - - if (voices[voice].env_phase >= 5) - { /* Envelope finished. Shoot the voice down */ - gus_voice_init (voice); - return; + if (voices[voice].env_phase >= 5) { /* Envelope finished. Shoot + * the voice down */ + gus_voice_init(voice); + return; } - - prev_vol = voices[voice].current_volume; - phase = ++voices[voice].env_phase; - compute_volume (voice, voices[voice].midi_volume); - vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255; - rate = voices[voice].env_rate[phase]; - - DISABLE_INTR (flags); - gus_select_voice (voice); - - gus_voice_volume (prev_vol); - - - gus_write8 (0x06, rate); /* Ramping rate */ - - voices[voice].volume_irq_mode = VMODE_ENVELOPE; - - if (((vol - prev_vol) / 64) == 0) /* No significant volume change */ - { - RESTORE_INTR (flags); - step_envelope (voice); /* Continue the envelope on the next step */ - return; + prev_vol = voices[voice].current_volume; + phase = ++voices[voice].env_phase; + compute_volume(voice, voices[voice].midi_volume); + vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255; + rate = voices[voice].env_rate[phase]; + + flags = splhigh(); + gus_select_voice(voice); + gus_voice_volume(prev_vol); + gus_write8(0x06, rate); /* Ramping rate */ + + voices[voice].volume_irq_mode = VMODE_ENVELOPE; + + if (((vol - prev_vol) / 64) == 0) { /* No significant volume + * change */ + splx(flags); + step_envelope(voice); /* Continue the envelope on the next + * step */ + return; } - - if (vol > prev_vol) - { - if (vol >= (4096 - 64)) - vol = 4096 - 65; - gus_ramp_range (0, vol); - gus_rampon (0x20); /* Increasing volume, with IRQ */ - } - else - { - if (vol <= 64) - vol = 65; - gus_ramp_range (vol, 4030); - gus_rampon (0x60); /* Decreasing volume, with IRQ */ + if (vol > prev_vol) { + if (vol >= (4096 - 64)) + vol = 4096 - 65; + gus_ramp_range(0, vol); + gus_rampon(0x20); /* Increasing volume, with IRQ */ + } else { + if (vol <= 64) + vol = 65; + gus_ramp_range(vol, 4030); + gus_rampon(0x60); /* Decreasing volume, with IRQ */ } - voices[voice].current_volume = vol; - RESTORE_INTR (flags); + voices[voice].current_volume = vol; + splx(flags); } static void -init_envelope (int voice) +init_envelope(int voice) { - voices[voice].env_phase = -1; - voices[voice].current_volume = 64; + voices[voice].env_phase = -1; + voices[voice].current_volume = 64; - step_envelope (voice); + step_envelope(voice); } static void -start_release (int voice, long int flags) +start_release(int voice, long int flags) { - if (gus_read8 (0x00) & 0x03) - return; /* Voice already stopped */ + if (gus_read8(0x00) & 0x03) + return; /* Voice already stopped */ - voices[voice].env_phase = 2; /* Will be incremented by step_envelope */ + voices[voice].env_phase = 2; /* Will be incremented by + * step_envelope */ - voices[voice].current_volume = + voices[voice].current_volume = voices[voice].initial_volume = - gus_read16 (0x09) >> 4; /* Get current volume */ + gus_read16(0x09) >> 4; /* Get current volume */ - voices[voice].mode &= ~WAVE_SUSTAIN_ON; - gus_rampoff (); - RESTORE_INTR (flags); - step_envelope (voice); + voices[voice].mode &= ~WAVE_SUSTAIN_ON; + gus_rampoff(); + splx(flags); + step_envelope(voice); } static void -gus_voice_fade (int voice) +gus_voice_fade(int voice) { - int instr_no = sample_map[voice], is16bits; - long int flags; + int instr_no = sample_map[voice], is16bits; + long int flags; - DISABLE_INTR (flags); - gus_select_voice (voice); + flags = splhigh(); + gus_select_voice(voice); - if (instr_no < 0 || instr_no > MAX_SAMPLE) - { - gus_write8 (0x00, 0x03); /* Hard stop */ - voice_alloc->map[voice] = 0; - RESTORE_INTR (flags); - return; + if (instr_no < 0 || instr_no > MAX_SAMPLE) { + gus_write8(0x00, 0x03); /* Hard stop */ + voice_alloc->map[voice] = 0; + splx(flags); + return; } + is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */ - is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */ - - if (voices[voice].mode & WAVE_ENVELOPES) - { - start_release (voice, flags); - return; + if (voices[voice].mode & WAVE_ENVELOPES) { + start_release(voice, flags); + return; } - - /* - * Ramp the volume down but not too quickly. - */ - if ((int) (gus_read16 (0x09) >> 4) < 100) /* Get current volume */ - { - gus_voice_off (); - gus_rampoff (); - gus_voice_init (voice); - return; + /* + * Ramp the volume down but not too quickly. + */ + if ((int) (gus_read16(0x09) >> 4) < 100) { /* Get current volume */ + gus_voice_off(); + gus_rampoff(); + gus_voice_init(voice); + return; } - - gus_ramp_range (65, 4030); - gus_ramp_rate (2, 4); - gus_rampon (0x40 | 0x20); /* Down, once, with IRQ */ - voices[voice].volume_irq_mode = VMODE_HALT; - RESTORE_INTR (flags); + gus_ramp_range(65, 4030); + gus_ramp_rate(2, 4); + gus_rampon(0x40 | 0x20);/* Down, once, with IRQ */ + voices[voice].volume_irq_mode = VMODE_HALT; + splx(flags); } static void -gus_reset (void) +gus_reset(void) { - int i; + int i; - gus_select_max_voices (24); - volume_base = 3071; - volume_scale = 4; - volume_method = VOL_METHOD_ADAGIO; + gus_select_max_voices(24); + volume_base = 3071; + volume_scale = 4; + volume_method = VOL_METHOD_ADAGIO; - for (i = 0; i < 32; i++) - { - gus_voice_init (i); /* Turn voice off */ - gus_voice_init2 (i); + for (i = 0; i < 32; i++) { + gus_voice_init(i); /* Turn voice off */ + gus_voice_init2(i); } - INB (u_Status); /* Touch the status register */ + inb(u_Status); /* Touch the status register */ - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ + gus_look8(0x41); /* Clear any pending DMA IRQs */ + gus_look8(0x49); /* Clear any pending sample IRQs */ - gus_read8 (0x0f); /* Clear pending IRQs */ + gus_read8(0x0f); /* Clear pending IRQs */ } static void -gus_initialize (void) +gus_initialize(void) { - unsigned long flags; - unsigned char dma_image, irq_image, tmp; + u_long flags; + u_char dma_image, irq_image, tmp; - static unsigned char gus_irq_map[16] = - {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7}; + static u_char gus_irq_map[16] = + {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7}; - static unsigned char gus_dma_map[8] = - {0, 1, 0, 2, 0, 3, 4, 5}; + static u_char gus_dma_map[8] = + {0, 1, 0, 2, 0, 3, 4, 5}; - DISABLE_INTR (flags); - gus_write8 (0x4c, 0); /* Reset GF1 */ - gus_delay (); - gus_delay (); + flags = splhigh(); + gus_write8(0x4c, 0); /* Reset GF1 */ + gus_delay(); + gus_delay(); - gus_write8 (0x4c, 1); /* Release Reset */ - gus_delay (); - gus_delay (); + gus_write8(0x4c, 1); /* Release Reset */ + gus_delay(); + gus_delay(); - /* - * Clear all interrupts - */ - - gus_write8 (0x41, 0); /* DMA control */ - gus_write8 (0x45, 0); /* Timer control */ - gus_write8 (0x49, 0); /* Sample control */ + /* + * Clear all interrupts + */ - gus_select_max_voices (24); + gus_write8(0x41, 0); /* DMA control */ + gus_write8(0x45, 0); /* Timer control */ + gus_write8(0x49, 0); /* Sample control */ - INB (u_Status); /* Touch the status register */ + gus_select_max_voices(24); - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ - gus_read8 (0x0f); /* Clear pending IRQs */ + inb(u_Status); /* Touch the status register */ - gus_reset (); /* Resets all voices */ + gus_look8(0x41); /* Clear any pending DMA IRQs */ + gus_look8(0x49); /* Clear any pending sample IRQs */ + gus_read8(0x0f); /* Clear pending IRQs */ - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ - gus_read8 (0x0f); /* Clear pending IRQs */ + gus_reset(); /* Resets all voices */ - gus_write8 (0x4c, 7); /* Master reset | DAC enable | IRQ enable */ + gus_look8(0x41); /* Clear any pending DMA IRQs */ + gus_look8(0x49); /* Clear any pending sample IRQs */ + gus_read8(0x0f); /* Clear pending IRQs */ - /* - * Set up for Digital ASIC - */ + gus_write8(0x4c, 7); /* Master reset | DAC enable | IRQ enable */ - OUTB (0x05, gus_base + 0x0f); + /* + * Set up for Digital ASIC + */ - mix_image |= 0x02; /* Disable line out */ - OUTB (mix_image, u_Mixer); + outb(gus_base + 0x0f, 0x05); - OUTB (0x00, u_IRQDMAControl); + mix_image |= 0x02; /* Disable line out (for a moment) */ + outb(u_Mixer, mix_image); - OUTB (0x00, gus_base + 0x0f); + outb(u_IRQDMAControl, 0x00); - /* - * Now set up the DMA and IRQ interface - * - * The GUS supports two IRQs and two DMAs. - * - * Just one DMA channel is used. This prevents simultaneous ADC and DAC. - * Adding this support requires significant changes to the dmabuf.c, dsp.c - * and audio.c also. - */ + outb(gus_base + 0x0f, 0x00); - irq_image = 0; - tmp = gus_irq_map[gus_irq]; - if (!tmp) - printk ("Warning! GUS IRQ not selected\n"); - irq_image |= tmp; - irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */ + /* + * Now set up the DMA and IRQ interface + * + * The GUS supports two IRQs and two DMAs. + * + * Just one DMA channel is used. This prevents simultaneous ADC and DAC. + * Adding this support requires significant changes to the dmabuf.c, + * dsp.c and audio.c also. + */ - dma_image = gus_dma_map[gus_dma_read] << 3; - if(!dma_image) - printk ("Warning! GUS DMA read channel not selected.\n"); - if(gus_dma_read == gus_dma) + irq_image = 0; + tmp = gus_irq_map[gus_irq]; + if (!tmp) + printf("Warning! GUS IRQ not selected\n"); + irq_image |= tmp; + irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */ + + dual_dma_mode = 1; + if (gus_dma2 == gus_dma || gus_dma2 == -1) { + dual_dma_mode = 0; + dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ + + tmp = gus_dma_map[gus_dma]; + if (!tmp) + printf("Warning! GUS DMA not selected\n"); + + dma_image |= tmp; + } else + /* Setup dual DMA channel mode for GUS MAX */ { - dma_image = 0x40; /* dual dma inhibited - Combine DMA1 (DRAM) and IRQ2 (ADC) */ + dma_image = gus_dma_map[gus_dma]; + if (!dma_image) + printf("Warning! GUS DMA not selected\n"); + + tmp = gus_dma_map[gus_dma2] << 3; + if (!tmp) { + printf("Warning! Invalid GUS MAX DMA\n"); + tmp = 0x40; /* Combine DMA channels */ + dual_dma_mode = 0; + } + dma_image |= tmp; } - tmp = gus_dma_map[gus_dma]; - if (!tmp) - printk ("Warning! GUS DMA not selected\n"); - dma_image |= tmp; - /* - * For some reason the IRQ and DMA addresses must be written twice - */ + /* + * For some reason the IRQ and DMA addresses must be written twice + */ - /* - * Doing it first time - */ + /* + * Doing it first time + */ - OUTB (mix_image, u_Mixer); /* Select DMA control */ - OUTB (dma_image | 0x80, u_IRQDMAControl); /* Set DMA address */ + outb(u_Mixer, mix_image); /* Select DMA control */ + outb(u_IRQDMAControl, dma_image | 0x80); /* Set DMA address */ - OUTB (mix_image | 0x40, u_Mixer); /* Select IRQ control */ - OUTB (irq_image, u_IRQDMAControl); /* Set IRQ address */ + outb(u_Mixer, mix_image | 0x40); /* Select IRQ control */ + outb(u_IRQDMAControl, irq_image); /* Set IRQ address */ - /* - * Doing it second time - */ + /* + * Doing it second time + */ - OUTB (mix_image, u_Mixer); /* Select DMA control */ - OUTB (dma_image, u_IRQDMAControl); /* Set DMA address */ + outb(u_Mixer, mix_image); /* Select DMA control */ + outb(u_IRQDMAControl, dma_image); /* Set DMA address */ - OUTB (mix_image | 0x40, u_Mixer); /* Select IRQ control */ - OUTB (irq_image, u_IRQDMAControl); /* Set IRQ address */ + outb(u_Mixer, mix_image | 0x40); /* Select IRQ control */ + outb(u_IRQDMAControl, irq_image); /* Set IRQ address */ - gus_select_voice (0); /* This disables writes to IRQ/DMA reg */ + gus_select_voice(0); /* This disables writes to IRQ/DMA reg */ - mix_image &= ~0x02; /* Enable line out */ - mix_image |= 0x08; /* Enable IRQ */ - OUTB (mix_image, u_Mixer); /* - * Turn mixer channels on - * Note! Mic in is left off. - */ + mix_image &= ~0x02; /* Enable line out */ + mix_image |= 0x08; /* Enable IRQ */ + outb(u_Mixer, mix_image); /* Turn mixer channels on Note! Mic + * in is left off. */ - gus_select_voice (0); /* This disables writes to IRQ/DMA reg */ + gus_select_voice(0); /* This disables writes to IRQ/DMA reg */ - gusintr (INT_HANDLER_CALL (0)); /* Serve pending interrupts */ - RESTORE_INTR (flags); + gusintr(0); /* Serve pending interrupts */ + splx(flags); } int -gus_wave_detect (int baseaddr) +gus_wave_detect(int baseaddr) { - unsigned long i; - unsigned long loc; - - gus_base = baseaddr; - - gus_write8 (0x4c, 0); /* Reset GF1 */ - gus_delay (); - gus_delay (); - - gus_write8 (0x4c, 1); /* Release Reset */ - gus_delay (); - gus_delay (); - - /* See if there is first block there.... */ - gus_poke (0L, 0xaa); - if (gus_peek (0L) != 0xaa) - return (0); - - /* Now zero it out so that I can check for mirroring .. */ - gus_poke (0L, 0x00); - for (i = 1L; i < 1024L; i++) - { - int n, failed; - - /* check for mirroring ... */ - if (gus_peek (0L) != 0) - break; - loc = i << 10; - - for (n = loc - 1, failed = 0; n <= loc; n++) - { - gus_poke (loc, 0xaa); - if (gus_peek (loc) != 0xaa) - failed = 1; - - gus_poke (loc, 0x55); - if (gus_peek (loc) != 0x55) - failed = 1; + u_long i; + u_long loc; + gus_base = baseaddr; + + gus_write8(0x4c, 0); /* Reset GF1 */ + gus_delay(); + gus_delay(); + + gus_write8(0x4c, 1); /* Release Reset */ + gus_delay(); + gus_delay(); + + /* See if there is first block there.... */ + gus_poke(0L, 0xaa); + if (gus_peek(0L) != 0xaa) + return (0); + + /* Now zero it out so that I can check for mirroring .. */ + gus_poke(0L, 0x00); + for (i = 1L; i < 1024L; i++) { + int n, failed; + + /* check for mirroring ... */ + if (gus_peek(0L) != 0) + break; + loc = i << 10; + + for (n = loc - 1, failed = 0; n <= loc; n++) { + gus_poke(loc, 0xaa); + if (gus_peek(loc) != 0xaa) + failed = 1; + + gus_poke(loc, 0x55); + if (gus_peek(loc) != 0x55) + failed = 1; + } + + if (failed) + break; } - - if (failed) - break; - } - gus_mem_size = i << 10; - return 1; + gus_mem_size = i << 10; + return 1; } static int -guswave_ioctl (int dev, - unsigned int cmd, unsigned int arg) +guswave_ioctl(int dev, + u_int cmd, ioctl_arg arg) { - switch (cmd) - { + switch (cmd) { case SNDCTL_SYNTH_INFO: - gus_info.nr_voices = nr_voices; - IOCTL_TO_USER ((char *) arg, 0, &gus_info, sizeof (gus_info)); - return 0; - break; + gus_info.nr_voices = nr_voices; + bcopy(&gus_info, &(((char *) arg)[0]), sizeof(gus_info)); + return 0; + break; case SNDCTL_SEQ_RESETSAMPLES: - reset_sample_memory (); - return 0; - break; + reset_sample_memory(); + return 0; + break; case SNDCTL_SEQ_PERCMODE: - return 0; - break; + return 0; + break; case SNDCTL_SYNTH_MEMAVL: - return gus_mem_size - free_mem_ptr - 32; + return gus_mem_size - free_mem_ptr - 32; default: - return RET_ERROR (EINVAL); + return -(EINVAL); } } static int -guswave_set_instr (int dev, int voice, int instr_no) +guswave_set_instr(int dev, int voice, int instr_no) { - int sample_no; - - if (instr_no < 0 || instr_no > MAX_PATCH) - return RET_ERROR (EINVAL); - - if (voice < 0 || voice > 31) - return RET_ERROR (EINVAL); - - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].sample_pending = instr_no; - return 0; - } + int sample_no; - sample_no = patch_table[instr_no]; - patch_map[voice] = -1; + if (instr_no < 0 || instr_no > MAX_PATCH) + return -(EINVAL); - if (sample_no < 0) - { - printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice); - return RET_ERROR (EINVAL); /* Patch not defined */ - } + if (voice < 0 || voice > 31) + return -(EINVAL); - if (sample_ptrs[sample_no] == -1) /* Sample not loaded */ - { - printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n", - sample_no, instr_no, voice); - return RET_ERROR (EINVAL); - } + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) { + voices[voice].sample_pending = instr_no; + return 0; + } + sample_no = patch_table[instr_no]; + patch_map[voice] = -1; - sample_map[voice] = sample_no; - patch_map[voice] = instr_no; - return 0; + if (sample_no < 0) { + printf("GUS: Undefined patch %d for voice %d\n", instr_no, voice); + return -(EINVAL); /* Patch not defined */ + } + if (sample_ptrs[sample_no] == -1) { /* Sample not loaded */ + printf("GUS: Sample #%d not loaded for patch %d (voice %d)\n", + sample_no, instr_no, voice); + return -(EINVAL); + } + sample_map[voice] = sample_no; + patch_map[voice] = instr_no; + return 0; } static int -guswave_kill_note (int dev, int voice, int note, int velocity) +guswave_kill_note(int dev, int voice, int note, int velocity) { - unsigned long flags; - - DISABLE_INTR (flags); - /* voice_alloc->map[voice] = 0xffff; */ - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].kill_pending = 1; - RESTORE_INTR (flags); - } - else - { - RESTORE_INTR (flags); - gus_voice_fade (voice); + u_long flags; + + flags = splhigh(); + /* voice_alloc->map[voice] = 0xffff; */ + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) { + voices[voice].kill_pending = 1; + splx(flags); + } else { + splx(flags); + gus_voice_fade(voice); } - RESTORE_INTR (flags); - return 0; + splx(flags); + return 0; } static void -guswave_aftertouch (int dev, int voice, int pressure) +guswave_aftertouch(int dev, int voice, int pressure) { -#if 0 - short lo_limit, hi_limit; - unsigned long flags; - - if (voice < 0 || voice > 31) - return; - - if (voices[voice].mode & WAVE_ENVELOPES && voices[voice].env_phase != 2) - return; /* Don't mix with envelopes */ - - if (pressure < 32) - { - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_rampoff (); - compute_and_set_volume (voice, 255, 0); /* Back to original volume */ - RESTORE_INTR (flags); - return; - } - - hi_limit = voices[voice].current_volume; - lo_limit = hi_limit * 99 / 100; - if (lo_limit < 65) - lo_limit = 65; - - DISABLE_INTR (flags); - gus_select_voice (voice); - if (hi_limit > (4095 - 65)) - { - hi_limit = 4095 - 65; - gus_voice_volume (hi_limit); - } - gus_ramp_range (lo_limit, hi_limit); - gus_ramp_rate (3, 8); - gus_rampon (0x58); /* Bidirectional, dow, loop */ - RESTORE_INTR (flags); -#endif /* 0 */ } static void -guswave_panning (int dev, int voice, int value) +guswave_panning(int dev, int voice, int value) { - if (voice >= 0 || voice < 32) - voices[voice].panning = value; + if (voice >= 0 || voice < 32) + voices[voice].panning = value; } static void -guswave_volume_method (int dev, int mode) +guswave_volume_method(int dev, int mode) { - if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO) - volume_method = mode; + if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO) + volume_method = mode; } -static void -compute_volume (int voice, int volume) +void +compute_volume(int voice, int volume) { - if (volume < 128) - voices[voice].midi_volume = volume; + if (volume < 128) + voices[voice].midi_volume = volume; - switch (volume_method) - { + switch (volume_method) { case VOL_METHOD_ADAGIO: - voices[voice].initial_volume = - gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol, - voices[voice].expression_vol, - voices[voice].patch_vol); - break; + voices[voice].initial_volume = + gus_adagio_vol(voices[voice].midi_volume, voices[voice].main_vol, + voices[voice].expression_vol, voices[voice].patch_vol); + break; - case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */ - voices[voice].initial_volume = - gus_linear_vol (volume, voices[voice].main_vol); - break; + case VOL_METHOD_LINEAR:/* Totally ignores patch-volume and expression */ + voices[voice].initial_volume = + gus_linear_vol(volume, voices[voice].main_vol); + break; default: - voices[voice].initial_volume = volume_base + - (voices[voice].midi_volume * volume_scale); + voices[voice].initial_volume = volume_base + + (voices[voice].midi_volume * volume_scale); } - if (voices[voice].initial_volume > 4030) - voices[voice].initial_volume = 4030; + if (voices[voice].initial_volume > 4030) + voices[voice].initial_volume = 4030; } -static void -compute_and_set_volume (int voice, int volume, int ramp_time) +void +compute_and_set_volume(int voice, int volume, int ramp_time) { - int current, target, rate; - unsigned long flags; + int curr, target, rate; + u_long flags; - compute_volume (voice, volume); - voices[voice].current_volume = voices[voice].initial_volume; + compute_volume(voice, volume); + voices[voice].current_volume = voices[voice].initial_volume; - DISABLE_INTR (flags); - /* + flags = splhigh(); + /* * CAUTION! Interrupts disabled. Enable them before returning - */ - - gus_select_voice (voice); - - current = gus_read16 (0x09) >> 4; - target = voices[voice].initial_volume; + */ - if (ramp_time == INSTANT_RAMP) - { - gus_rampoff (); - gus_voice_volume (target); - RESTORE_INTR (flags); - return; - } + gus_select_voice(voice); - if (ramp_time == FAST_RAMP) - rate = 63; - else - rate = 16; - gus_ramp_rate (0, rate); + curr = gus_read16(0x09) >> 4; + target = voices[voice].initial_volume; - if ((target - current) / 64 == 0) /* Close enough to target. */ - { - gus_rampoff (); - gus_voice_volume (target); - RESTORE_INTR (flags); - return; + if (ramp_time == INSTANT_RAMP) { + gus_rampoff(); + gus_voice_volume(target); + splx(flags); + return; } - - if (target > current) - { - if (target > (4095 - 65)) - target = 4095 - 65; - gus_ramp_range (current, target); - gus_rampon (0x00); /* Ramp up, once, no IRQ */ + if (ramp_time == FAST_RAMP) + rate = 63; + else + rate = 16; + gus_ramp_rate(0, rate); + + if ((target - curr) / 64 == 0) { /* Close enough to target. */ + gus_rampoff(); + gus_voice_volume(target); + splx(flags); + return; } - else - { - if (target < 65) - target = 65; - - gus_ramp_range (target, current); - gus_rampon (0x40); /* Ramp down, once, no irq */ + if (target > curr) { + if (target > (4095 - 65)) + target = 4095 - 65; + gus_ramp_range(curr, target); + gus_rampon(0x00); /* Ramp up, once, no IRQ */ + } else { + if (target < 65) + target = 65; + + gus_ramp_range(target, curr); + gus_rampon(0x40); /* Ramp down, once, no irq */ } - RESTORE_INTR (flags); + splx(flags); } static void -dynamic_volume_change (int voice) +dynamic_volume_change(int voice) { - unsigned char status; - unsigned long flags; - - DISABLE_INTR (flags); - gus_select_voice (voice); - status = gus_read8 (0x00); /* Get voice status */ - RESTORE_INTR (flags); + u_char status; + u_long flags; - if (status & 0x03) - return; /* Voice was not running */ - - if (!(voices[voice].mode & WAVE_ENVELOPES)) - { - compute_and_set_volume (voice, voices[voice].midi_volume, 1); - return; - } + flags = splhigh(); + gus_select_voice(voice); + status = gus_read8(0x00); /* Get voice status */ + splx(flags); - /* - * Voice is running and has envelopes. - */ + if (status & 0x03) + return; /* Voice was not running */ - DISABLE_INTR (flags); - gus_select_voice (voice); - status = gus_read8 (0x0d); /* Ramping status */ - RESTORE_INTR (flags); + if (!(voices[voice].mode & WAVE_ENVELOPES)) { + compute_and_set_volume(voice, voices[voice].midi_volume, 1); + return; + } + /* + * Voice is running and has envelopes. + */ - if (status & 0x03) /* Sustain phase? */ - { - compute_and_set_volume (voice, voices[voice].midi_volume, 1); - return; - } + flags = splhigh(); + gus_select_voice(voice); + status = gus_read8(0x0d); /* Ramping status */ + splx(flags); - if (voices[voice].env_phase < 0) - return; + if (status & 0x03) { /* Sustain phase? */ + compute_and_set_volume(voice, voices[voice].midi_volume, 1); + return; + } + if (voices[voice].env_phase < 0) + return; - compute_volume (voice, voices[voice].midi_volume); + compute_volume(voice, voices[voice].midi_volume); } static void -guswave_controller (int dev, int voice, int ctrl_num, int value) +guswave_controller(int dev, int voice, int ctrl_num, int value) { - unsigned long flags; - unsigned long freq; - - if (voice < 0 || voice > 31) - return; - - switch (ctrl_num) - { - case CTRL_PITCH_BENDER: - voices[voice].bender = value; - - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - { - freq = compute_finetune (voices[voice].orig_freq, value, - voices[voice].bender_range); - voices[voice].current_freq = freq; - - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_voice_freq (freq); - RESTORE_INTR (flags); - } - break; - - case CTRL_PITCH_BENDER_RANGE: - voices[voice].bender_range = value; - break; - case CTL_EXPRESSION: - value /= 128; - case CTRL_EXPRESSION: - if (volume_method == VOL_METHOD_ADAGIO) - { - voices[voice].expression_vol = value; - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - dynamic_volume_change (voice); - } - break; - - case CTL_PAN: - voices[voice].panning = (value * 2) - 128; - break; - - case CTL_MAIN_VOLUME: - value = (value * 100) / 16383; - - case CTRL_MAIN_VOLUME: - voices[voice].main_vol = value; - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - dynamic_volume_change (voice); - break; - - default: - break; - } + u_long flags; + u_long freq; + + if (voice < 0 || voice > 31) + return; + + switch (ctrl_num) { + case CTRL_PITCH_BENDER: + voices[voice].bender = value; + + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) { + freq = compute_finetune(voices[voice].orig_freq, value, + voices[voice].bender_range); + voices[voice].current_freq = freq; + + flags = splhigh(); + gus_select_voice(voice); + gus_voice_freq(freq); + splx(flags); + } + break; + + case CTRL_PITCH_BENDER_RANGE: + voices[voice].bender_range = value; + break; + case CTL_EXPRESSION: + value /= 128; + case CTRL_EXPRESSION: + if (volume_method == VOL_METHOD_ADAGIO) { + voices[voice].expression_vol = value; + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change(voice); + } + break; + + case CTL_PAN: + voices[voice].panning = (value * 2) - 128; + break; + + case CTL_MAIN_VOLUME: + value = (value * 100) / 16383; + + case CTRL_MAIN_VOLUME: + voices[voice].main_vol = value; + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change(voice); + break; + + default: + break; + } } -static int -guswave_start_note2 (int dev, int voice, int note_num, int volume) +int +guswave_start_note2(int dev, int voice, int note_num, int volume) { - int sample, best_sample, best_delta, delta_freq; - int is16bits, samplep, patch, pan; - unsigned long note_freq, base_note, freq, flags; - unsigned char mode = 0; - - if (voice < 0 || voice > 31) - { - printk ("GUS: Invalid voice\n"); - return RET_ERROR (EINVAL); + int sample, best_sample, best_delta, delta_freq; + int is16bits, samplep, patch, pan; + u_long note_freq, base_note, freq, flags; + u_char mode = 0; + + if (voice < 0 || voice > 31) { + printf("GUS: Invalid voice\n"); + return -(EINVAL); } - - if (note_num == 255) - { - if (voices[voice].mode & WAVE_ENVELOPES) - { - voices[voice].midi_volume = volume; - dynamic_volume_change (voice); - return 0; + if (note_num == 255) { + if (voices[voice].mode & WAVE_ENVELOPES) { + voices[voice].midi_volume = volume; + dynamic_volume_change(voice); + return 0; } - - compute_and_set_volume (voice, volume, 1); - return 0; - } - - if ((patch = patch_map[voice]) == -1) - { - return RET_ERROR (EINVAL); - } - - if ((samplep = patch_table[patch]) == -1) - { - return RET_ERROR (EINVAL); + compute_and_set_volume(voice, volume, 1); + return 0; } + if ((patch = patch_map[voice]) == -1) + return -(EINVAL); + if ((samplep = patch_table[patch]) == -1) + return -(EINVAL); + note_freq = note_to_freq(note_num); - note_freq = note_to_freq (note_num); - - /* - * Find a sample within a patch so that the note_freq is between low_note - * and high_note. - */ - sample = -1; - - best_sample = samplep; - best_delta = 1000000; - while (samplep >= 0 && sample == -1) - { - delta_freq = note_freq - samples[samplep].base_note; - if (delta_freq < 0) - delta_freq = -delta_freq; - if (delta_freq < best_delta) - { - best_sample = samplep; - best_delta = delta_freq; - } - if (samples[samplep].low_note <= note_freq && - note_freq <= samples[samplep].high_note) - sample = samplep; - else - samplep = samples[samplep].key; /* - * Follow link - */ + /* + * Find a sample within a patch so that the note_freq is between + * low_note and high_note. + */ + sample = -1; + + best_sample = samplep; + best_delta = 1000000; + while (samplep >= 0 && sample == -1) { + dbg_samples = samples; + dbg_samplep = samplep; + + delta_freq = note_freq - samples[samplep].base_note; + if (delta_freq < 0) + delta_freq = -delta_freq; + if (delta_freq < best_delta) { + best_sample = samplep; + best_delta = delta_freq; + } + if (samples[samplep].low_note <= note_freq && + note_freq <= samples[samplep].high_note) + sample = samplep; + else + samplep = samples[samplep].key; /* Follow link */ } - if (sample == -1) - sample = best_sample; + if (sample == -1) + sample = best_sample; - if (sample == -1) - { - printk ("GUS: Patch %d not defined for note %d\n", patch, note_num); - return 0; /* Should play default patch ??? */ + if (sample == -1) { + printf("GUS: Patch %d not defined for note %d\n", patch, note_num); + return 0; /* Should play default patch ??? */ } + is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; + voices[voice].mode = samples[sample].mode; + voices[voice].patch_vol = samples[sample].volume; - is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; - voices[voice].mode = samples[sample].mode; - voices[voice].patch_vol = samples[sample].volume; - - if (voices[voice].mode & WAVE_ENVELOPES) - { - int i; + if (voices[voice].mode & WAVE_ENVELOPES) { + int i; - for (i = 0; i < 6; i++) - { - voices[voice].env_rate[i] = samples[sample].env_rate[i]; - voices[voice].env_offset[i] = samples[sample].env_offset[i]; + for (i = 0; i < 6; i++) { + voices[voice].env_rate[i] = samples[sample].env_rate[i]; + voices[voice].env_offset[i] = samples[sample].env_offset[i]; } } + sample_map[voice] = sample; - sample_map[voice] = sample; + base_note = samples[sample].base_note / 100; /* Try to avoid overflows */ + note_freq /= 100; - base_note = samples[sample].base_note / 100; /* Try to avoid overflows */ - note_freq /= 100; + freq = samples[sample].base_freq * note_freq / base_note; - freq = samples[sample].base_freq * note_freq / base_note; + voices[voice].orig_freq = freq; - voices[voice].orig_freq = freq; - - /* - * Since the pitch bender may have been set before playing the note, we - * have to calculate the bending now. - */ - - freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, - voices[voice].bender_range); - voices[voice].current_freq = freq; - - pan = (samples[sample].panning + voices[voice].panning) / 32; - pan += 7; - if (pan < 0) - pan = 0; - if (pan > 15) - pan = 15; + /* + * Since the pitch bender may have been set before playing the note, + * we have to calculate the bending now. + */ - if (samples[sample].mode & WAVE_16_BITS) - { - mode |= 0x04; /* 16 bits */ - if ((sample_ptrs[sample] >> 18) != - ((sample_ptrs[sample] + samples[sample].len) >> 18)) - printk ("GUS: Sample address error\n"); + freq = compute_finetune(voices[voice].orig_freq, voices[voice].bender, + voices[voice].bender_range); + voices[voice].current_freq = freq; + + pan = (samples[sample].panning + voices[voice].panning) / 32; + pan += 7; + if (pan < 0) + pan = 0; + if (pan > 15) + pan = 15; + + if (samples[sample].mode & WAVE_16_BITS) { + mode |= 0x04; /* 16 bits */ + if ((sample_ptrs[sample] >> 18) != + ((sample_ptrs[sample] + samples[sample].len) >> 18)) + printf("GUS: Sample address error\n"); } + /* + * CAUTION! Interrupts disabled. Don't return before enabling + */ - /************************************************************************* - * CAUTION! Interrupts disabled. Don't return before enabling - *************************************************************************/ - - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_voice_off (); - gus_rampoff (); + flags = splhigh(); + gus_select_voice(voice); + gus_voice_off(); + gus_rampoff(); - RESTORE_INTR (flags); + splx(flags); - if (voices[voice].mode & WAVE_ENVELOPES) - { - compute_volume (voice, volume); - init_envelope (voice); + if (voices[voice].mode & WAVE_ENVELOPES) { + compute_volume(voice, volume); + init_envelope(voice); + } else { + compute_and_set_volume(voice, volume, 0); } - else - compute_and_set_volume (voice, volume, 0); - DISABLE_INTR (flags); - gus_select_voice (voice); + flags = splhigh(); + gus_select_voice(voice); - if (samples[sample].mode & WAVE_LOOP_BACK) - gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len - - voices[voice].offset_pending, is16bits); /* start=end */ - else - gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending, - is16bits); /* Sample start=begin */ + if (samples[sample].mode & WAVE_LOOP_BACK) + gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len - + voices[voice].offset_pending, is16bits); /* start=end */ + else + gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, + is16bits); /* Sample start=begin */ - if (samples[sample].mode & WAVE_LOOPING) - { - mode |= 0x08; + if (samples[sample].mode & WAVE_LOOPING) { + mode |= 0x08; - if (samples[sample].mode & WAVE_BIDIR_LOOP) - mode |= 0x10; + if (samples[sample].mode & WAVE_BIDIR_LOOP) + mode |= 0x10; - if (samples[sample].mode & WAVE_LOOP_BACK) - { - gus_write_addr (0x0a, - sample_ptrs[sample] + samples[sample].loop_end - - voices[voice].offset_pending, is16bits); - mode |= 0x40; + if (samples[sample].mode & WAVE_LOOP_BACK) { + gus_write_addr(0x0a, + sample_ptrs[sample] + samples[sample].loop_end - + voices[voice].offset_pending, is16bits); + mode |= 0x40; } - - gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, - is16bits); /* Loop start location */ - gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, - is16bits); /* Loop end location */ - } - else - { - mode |= 0x20; /* Loop IRQ at the end */ - voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ - voices[voice].loop_irq_parm = 1; - gus_write_addr (0x02, sample_ptrs[sample], - is16bits); /* Loop start location */ - gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1, - is16bits); /* Loop end location */ + gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start, + is16bits); /* Loop start location */ + gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end, + is16bits); /* Loop end location */ + } else { + mode |= 0x20; /* Loop IRQ at the end */ + voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ + voices[voice].loop_irq_parm = 1; + gus_write_addr(0x02, sample_ptrs[sample], + is16bits); /* Loop start location */ + gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1, + is16bits); /* Loop end location */ } - gus_voice_freq (freq); - gus_voice_balance (pan); - gus_voice_on (mode); - RESTORE_INTR (flags); + gus_voice_freq(freq); + gus_voice_balance(pan); + gus_voice_on(mode); + splx(flags); - return 0; + return 0; } /* * New guswave_start_note by Andrew J. Robinson attempts to minimize clicking - * when the note playing on the voice is changed. It uses volume - * ramping. + * when the note playing on the voice is changed. It uses volume ramping. */ static int -guswave_start_note (int dev, int voice, int note_num, int volume) +guswave_start_note(int dev, int voice, int note_num, int volume) { - long int flags; - int mode; - int ret_val = 0; - - DISABLE_INTR (flags); - if (note_num == 255) - { - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - voices[voice].volume_pending = volume; - else - { - ret_val = guswave_start_note2 (gus_devnum, voice, note_num, volume); + long int flags; + int mode; + int ret_val = 0; + + flags = splhigh(); + if (note_num == 255) { + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) { + voices[voice].volume_pending = volume; + } else { + ret_val = guswave_start_note2(dev, voice, note_num, volume); } - } - else - { - gus_select_voice (voice); - mode = gus_read8 (0x00); - if (mode & 0x20) - gus_write8 (0x00, mode & 0xdf); /* No interrupt! */ - - voices[voice].offset_pending = 0; - voices[voice].kill_pending = 0; - voices[voice].volume_irq_mode = 0; - voices[voice].loop_irq_mode = 0; - - if (voices[voice].sample_pending >= 0) - { - RESTORE_INTR (flags); /* Run temporarily with interrupts enabled */ - guswave_set_instr (voices[voice].dev_pending, voice, - voices[voice].sample_pending); - voices[voice].sample_pending = -1; - DISABLE_INTR (flags); - gus_select_voice (voice); /* Reselect the voice (just to be sure) */ - } - - if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < 2065)) - { - ret_val = guswave_start_note2 (gus_devnum, voice, note_num, volume); - } - else - { - voices[voice].dev_pending = gus_devnum; - voices[voice].note_pending = note_num; - voices[voice].volume_pending = volume; - voices[voice].volume_irq_mode = VMODE_START_NOTE; - - gus_rampoff (); - gus_ramp_range (2000, 4065); - gus_ramp_rate (0, 63); /* Fastest possible rate */ - gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */ + } else { + gus_select_voice(voice); + mode = gus_read8(0x00); + if (mode & 0x20) + gus_write8(0x00, mode & 0xdf); /* No interrupt! */ + + voices[voice].offset_pending = 0; + voices[voice].kill_pending = 0; + voices[voice].volume_irq_mode = 0; + voices[voice].loop_irq_mode = 0; + + if (voices[voice].sample_pending >= 0) { + splx(flags); /* Run temporarily with interrupts + * enabled */ + guswave_set_instr(voices[voice].dev_pending, voice, + voices[voice].sample_pending); + voices[voice].sample_pending = -1; + flags = splhigh(); + gus_select_voice(voice); /* Reselect the voice + * (just to be sure) */ + } + if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < 2065)) { + ret_val = guswave_start_note2(dev, voice, note_num, volume); + } else { + voices[voice].dev_pending = dev; + voices[voice].note_pending = note_num; + voices[voice].volume_pending = volume; + voices[voice].volume_irq_mode = VMODE_START_NOTE; + + gus_rampoff(); + gus_ramp_range(2000, 4065); + gus_ramp_rate(0, 63); /* Fastest possible rate */ + gus_rampon(0x20 | 0x40); /* Ramp down, once, irq */ } } - RESTORE_INTR (flags); - return ret_val; + splx(flags); + return ret_val; } static void -guswave_reset (int dev) +guswave_reset(int dev) { - int i; + int i; - for (i = 0; i < 32; i++) - { - gus_voice_init (i); - gus_voice_init2 (i); + for (i = 0; i < 32; i++) { + gus_voice_init(i); + gus_voice_init2(i); } } static int -guswave_open (int dev, int mode) +guswave_open(int dev, int mode) { - int err; + int err; + int otherside = audio_devs[dev]->otherside; - if (mode & OPEN_WRITE && gus_busy[gus_devnum] || - mode & OPEN_READ && gus_busy[gus_dspnum]) - return RET_ERROR (EBUSY); + if (otherside != -1) { + if (audio_devs[otherside]->busy) + return -(EBUSY); + } + if (audio_devs[dev]->busy) + return -(EBUSY); - if(gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum] == 0) - gus_initialize (); - voice_alloc->timestamp = 0; + gus_initialize(); + voice_alloc->timestamp = 0; - if ((err = DMAbuf_open_dma (gus_devnum)) < 0) - return err; + if ((err = DMAbuf_open_dma(gus_devnum)) < 0) { + printf("GUS: Loading saples without DMA\n"); + gus_no_dma = 1; /* Upload samples using PIO */ + } else + gus_no_dma = 0; - RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag); - gus_busy[gus_devnum] = 1; - active_device = GUS_DEV_WAVE; + dram_sleep_flag.aborting = 0; + dram_sleep_flag.mode = WK_NONE; + active_device = GUS_DEV_WAVE; - gus_reset (); + audio_devs[dev]->busy = 1; + gus_reset(); - return 0; + return 0; } static void -guswave_close (int dev) +guswave_close(int dev) { - gus_busy[gus_devnum] = 0; - active_device = 0; - gus_reset (); + int otherside = audio_devs[dev]->otherside; + + if (otherside != -1) { + if (audio_devs[otherside]->busy) + return; + } + audio_devs[dev]->busy = 0; - DMAbuf_close_dma (gus_devnum); + active_device = 0; + gus_reset(); + + if (!gus_no_dma) + DMAbuf_close_dma(gus_devnum); } static int -guswave_load_patch (int dev, int format, snd_rw_buf * addr, - int offs, int count, int pmgr_flag) +guswave_load_patch(int dev, int format, snd_rw_buf * addr, + int offs, int count, int pmgr_flag) { - struct patch_info patch; - int instr; - long sizeof_patch; + struct patch_info patch; + int instr; + long sizeof_patch; - unsigned long blk_size, blk_end, left, src_offs, target; + u_long blk_size, blk_end, left, src_offs, target; - sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ + sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ - if (format != GUS_PATCH) - { - printk ("GUS Error: Invalid patch format (key) 0x%x\n", format); - return RET_ERROR (EINVAL); + if (format != GUS_PATCH) { + printf("GUS Error: Invalid patch format (key) 0x%x\n", format); + return -(EINVAL); } - - if (count < sizeof_patch) - { - printk ("GUS Error: Patch header too short\n"); - return RET_ERROR (EINVAL); + if (count < sizeof_patch) { + printf("GUS Error: Patch header too short\n"); + return -(EINVAL); } + count -= sizeof_patch; - count -= sizeof_patch; - - if (free_sample >= MAX_SAMPLE) - { - printk ("GUS: Sample table full\n"); - return RET_ERROR (ENOSPC); + if (free_sample >= MAX_SAMPLE) { + printf("GUS: Sample table full\n"); + return -(ENOSPC); } + /* + * Copy the header from user space but ignore the first bytes which + * have been transferred already. + */ - /* - * Copy the header from user space but ignore the first bytes which have - * been transferred already. - */ - - COPY_FROM_USER (&((char *) &patch)[offs], addr, offs, sizeof_patch - offs); + if (uiomove(&((char *) &patch)[offs], sizeof_patch - offs, addr)) { + printf("audio: Bad copyin()!\n"); + }; - instr = patch.instr_no; + instr = patch.instr_no; - if (instr < 0 || instr > MAX_PATCH) - { - printk ("GUS: Invalid patch number %d\n", instr); - return RET_ERROR (EINVAL); + if (instr < 0 || instr > MAX_PATCH) { + printf("GUS: Invalid patch number %d\n", instr); + return -(EINVAL); } - - if (count < patch.len) - { - printk ("GUS Warning: Patch record too short (%d<%d)\n", - count, (int) patch.len); - patch.len = count; + if (count < patch.len) { + printf("GUS Warning: Patch record too short (%d<%d)\n", + count, (int) patch.len); + patch.len = count; } - - if (patch.len <= 0 || patch.len > gus_mem_size) - { - printk ("GUS: Invalid sample length %d\n", (int) patch.len); - return RET_ERROR (EINVAL); + if (patch.len <= 0 || patch.len > gus_mem_size) { + printf("GUS: Invalid sample length %d\n", (int) patch.len); + return -(EINVAL); } - - if (patch.mode & WAVE_LOOPING) - { - if (patch.loop_start < 0 || patch.loop_start >= patch.len) - { - printk ("GUS: Invalid loop start\n"); - return RET_ERROR (EINVAL); + if (patch.mode & WAVE_LOOPING) { + if (patch.loop_start < 0 || patch.loop_start >= patch.len) { + printf("GUS: Invalid loop start\n"); + return -(EINVAL); } - - if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) - { - printk ("GUS: Invalid loop end\n"); - return RET_ERROR (EINVAL); + if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) { + printf("GUS: Invalid loop end\n"); + return -(EINVAL); } } - - free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */ + free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */ #define GUS_BANK_SIZE (256*1024) - if (patch.mode & WAVE_16_BITS) - { - /* - * 16 bit samples must fit one 256k bank. - */ - if (patch.len >= GUS_BANK_SIZE) - { - printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len); - return RET_ERROR (ENOSPC); + if (patch.mode & WAVE_16_BITS) { + /* + * 16 bit samples must fit one 256k bank. + */ + if (patch.len >= GUS_BANK_SIZE) { + printf("GUS: Sample (16 bit) too long %d\n", (int) patch.len); + return -(ENOSPC); } + if ((free_mem_ptr / GUS_BANK_SIZE) != + ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) { + u_long tmp_mem = /* Aligning to 256K */ + ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; - if ((free_mem_ptr / GUS_BANK_SIZE) != - ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) - { - unsigned long tmp_mem = /* Aling to 256K */ - ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; - - if ((tmp_mem + patch.len) > gus_mem_size) - return RET_ERROR (ENOSPC); + if ((tmp_mem + patch.len) > gus_mem_size) + return -(ENOSPC); - free_mem_ptr = tmp_mem; /* This leaves unusable memory */ + free_mem_ptr = tmp_mem; /* This leaves unusable memory */ } } + if ((free_mem_ptr + patch.len) > gus_mem_size) + return -(ENOSPC); - if ((free_mem_ptr + patch.len) > gus_mem_size) - return RET_ERROR (ENOSPC); - - sample_ptrs[free_sample] = free_mem_ptr; - - /* - * Tremolo is not possible with envelopes - */ - - if (patch.mode & WAVE_ENVELOPES) - patch.mode &= ~WAVE_TREMOLO; - - memcpy ((char *) &samples[free_sample], &patch, sizeof_patch); - - /* - * Link this_one sample to the list of samples for patch 'instr'. - */ - - samples[free_sample].key = patch_table[instr]; - patch_table[instr] = free_sample; + sample_ptrs[free_sample] = free_mem_ptr; - /* - * Use DMA to transfer the wave data to the DRAM - */ - - left = patch.len; - src_offs = 0; - target = free_mem_ptr; + /* + * Tremolo is not possible with envelopes + */ - while (left) /* Not completely transferred yet */ - { - blk_size = audio_devs[gus_devnum]->buffsize; - if (blk_size > left) - blk_size = left; + if (patch.mode & WAVE_ENVELOPES) + patch.mode &= ~WAVE_TREMOLO; - /* - * DMA cannot cross 256k bank boundaries. Check for that. - */ - blk_end = target + blk_size; + bcopy(&patch, (char *) &samples[free_sample], sizeof_patch); - if ((target >> 18) != (blk_end >> 18)) - { /* Split the block */ + /* + * Link this_one sample to the list of samples for patch 'instr'. + */ - blk_end &= ~(256 * 1024 - 1); - blk_size = blk_end - target; - } + samples[free_sample].key = patch_table[instr]; + patch_table[instr] = free_sample; -#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA) - /* - * For some reason the DMA is not possible. We have to use PIO. - */ - { - long i; - unsigned char data; + /* + * Use DMA to transfer the wave data to the DRAM + */ - for (i = 0; i < blk_size; i++) - { - GET_BYTE_FROM_USER (data, addr, sizeof_patch + i); - if (patch.mode & WAVE_UNSIGNED) + left = patch.len; + src_offs = 0; + target = free_mem_ptr; - if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) - data ^= 0x80; /* Convert to signed */ - gus_poke (target + i, data); - } - } -#else /* GUS_NO_DMA */ - { - unsigned long address, hold_address; - unsigned char dma_command; - unsigned long flags; + while (left) { /* Not completely transferred yet */ + /* blk_size = audio_devs[gus_devnum]->buffsize; */ + blk_size = audio_devs[gus_devnum]->dmap_out->bytes_in_use; + if (blk_size > left) + blk_size = left; /* - * OK, move now. First in and then out. + * DMA cannot cross 256k bank boundaries. Check for that. */ + blk_end = target + blk_size; - COPY_FROM_USER (audio_devs[gus_devnum]->dmap->raw_buf[0], - addr, sizeof_patch + src_offs, - blk_size); + if ((target >> 18) != (blk_end >> 18)) { /* Split the block */ + blk_end &= ~(256 * 1024 - 1); + blk_size = blk_end - target; + } + if (gus_no_dma) { + /* + * For some reason the DMA is not possible. We have + * to use PIO. + */ + long i; + u_char data; + + for (i = 0; i < blk_size; i++) { + uiomove((char *) &(data), 1, addr); + if (patch.mode & WAVE_UNSIGNED) + if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) + data ^= 0x80; /* Convert to signed */ + gus_poke(target + i, data); + } + } else { + u_long address, hold_address; + u_char dma_command; + u_long flags; + + /* + * OK, move now. First in and then out. + */ + + if (uiomove(audio_devs[gus_devnum]->dmap_out->raw_buf, blk_size, addr)) { + printf("audio: Bad copyin()!\n"); + }; + + flags = splhigh(); + /******** INTERRUPTS DISABLED NOW ********/ + gus_write8(0x41, 0); /* Disable GF1 DMA */ + DMAbuf_start_dma(gus_devnum, + audio_devs[gus_devnum]->dmap_out->raw_buf_phys, + blk_size, 1); + + /* + * Set the DRAM address for the wave data + */ + + address = target; + + if (audio_devs[gus_devnum]->dmachan1 > 3) { + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ - DISABLE_INTR (flags); -/******** INTERRUPTS DISABLED NOW ********/ - gus_write8 (0x41, 0); /* Disable GF1 DMA */ - DMAbuf_start_dma (gus_devnum, - audio_devs[gus_devnum]->dmap->raw_buf_phys[0], - blk_size, DMA_MODE_WRITE); + /* + * Start the DMA transfer + */ - /* - * Set the DRAM address for the wave data - */ + dma_command = 0x21; /* IRQ enable, DMA start */ + if (patch.mode & WAVE_UNSIGNED) + dma_command |= 0x80; /* Invert MSB */ + if (patch.mode & WAVE_16_BITS) + dma_command |= 0x40; /* 16 bit _DATA_ */ + if (audio_devs[gus_devnum]->dmachan1 > 3) + dma_command |= 0x04; /* 16 bit DMA _channel_ */ - address = target; + gus_write8(0x41, dma_command); /* Lets bo luteet (=bugs) */ - if (audio_devs[gus_devnum]->dmachan > 3) - { - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } + /* + * Sleep here until the DRAM DMA done interrupt is + * served + */ + active_device = GUS_DEV_WAVE; - gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ - /* - * Start the DMA transfer - */ + { + int chn; - dma_command = 0x21; /* IRQ enable, DMA start */ - if (patch.mode & WAVE_UNSIGNED) - dma_command |= 0x80; /* Invert MSB */ - if (patch.mode & WAVE_16_BITS) - dma_command |= 0x40; /* 16 bit _DATA_ */ - if (audio_devs[gus_devnum]->dmachan > 3) - dma_command |= 0x04; /* 16 bit DMA _channel_ */ + dram_sleep_flag.mode = WK_SLEEP; + dram_sleeper = &chn; + DO_SLEEP(chn, dram_sleep_flag, hz); - gus_write8 (0x41, dma_command); /* Lets bo luteet (=bugs) */ + }; + if ((dram_sleep_flag.mode & WK_TIMEOUT)) + printf("GUS: DMA Transfer timed out\n"); + splx(flags); + } /* - * Sleep here until the DRAM DMA done interrupt is served + * Now the next part */ - active_device = GUS_DEV_WAVE; - DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ); - if (TIMED_OUT (dram_sleeper, dram_sleep_flag)) - printk ("GUS: DMA Transfer timed out\n"); - RESTORE_INTR (flags); - } -#endif /* GUS_NO_DMA */ + left -= blk_size; + src_offs += blk_size; + target += blk_size; - /* - * Now the next part - */ - - left -= blk_size; - src_offs += blk_size; - target += blk_size; - - gus_write8 (0x41, 0); /* Stop DMA */ + gus_write8(0x41, 0); /* Stop DMA */ } - free_mem_ptr += patch.len; + free_mem_ptr += patch.len; - if (!pmgr_flag) - pmgr_inform (gus_devnum, PM_E_PATCH_LOADED, instr, free_sample, 0, 0); - free_sample++; - return 0; + if (!pmgr_flag) + pmgr_inform(dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0); + free_sample++; + return 0; } static void -guswave_hw_control (int dev, unsigned char *event) +guswave_hw_control(int dev, u_char *event) { - int voice, cmd; - unsigned short p1, p2; - unsigned long plong, flags; - - cmd = event[2]; - voice = event[3]; - p1 = *(unsigned short *) &event[4]; - p2 = *(unsigned short *) &event[6]; - plong = *(unsigned long *) &event[4]; - - if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) && - (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) - do_volume_irq (voice); - - switch (cmd) - { - - case _GUS_NUMVOICES: - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_select_max_voices (p1); - RESTORE_INTR (flags); - break; - - case _GUS_VOICESAMPLE: - guswave_set_instr (dev, voice, p1); - break; - - case _GUS_VOICEON: - DISABLE_INTR (flags); - gus_select_voice (voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_voice_on (p1); - RESTORE_INTR (flags); - break; - - case _GUS_VOICEOFF: - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_voice_off (); - RESTORE_INTR (flags); - break; - - case _GUS_VOICEFADE: - gus_voice_fade (voice); - break; - - case _GUS_VOICEMODE: - DISABLE_INTR (flags); - gus_select_voice (voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_voice_mode (p1); - RESTORE_INTR (flags); - break; - - case _GUS_VOICEBALA: - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_voice_balance (p1); - RESTORE_INTR (flags); - break; - - case _GUS_VOICEFREQ: - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_voice_freq (plong); - RESTORE_INTR (flags); - break; - - case _GUS_VOICEVOL: - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_voice_volume (p1); - RESTORE_INTR (flags); - break; - - case _GUS_VOICEVOL2: /* Just update the software voice level */ - voices[voice].initial_volume = - voices[voice].current_volume = p1; - break; - - case _GUS_RAMPRANGE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_ramp_range (p1, p2); - RESTORE_INTR (flags); - break; - - case _GUS_RAMPRATE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NJET-NJET */ - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_ramp_rate (p1, p2); - RESTORE_INTR (flags); - break; - - case _GUS_RAMPMODE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ - DISABLE_INTR (flags); - gus_select_voice (voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_ramp_mode (p1); - RESTORE_INTR (flags); - break; - - case _GUS_RAMPON: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* EI-EI */ - DISABLE_INTR (flags); - gus_select_voice (voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_rampon (p1); - RESTORE_INTR (flags); - break; - - case _GUS_RAMPOFF: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NEJ-NEJ */ - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_rampoff (); - RESTORE_INTR (flags); - break; - - case _GUS_VOLUME_SCALE: - volume_base = p1; - volume_scale = p2; - break; - - case _GUS_VOICE_POS: - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_set_voice_pos (voice, plong); - RESTORE_INTR (flags); - break; - - default:; - } + int voice, cmd; + u_short p1, p2; + u_long plong, flags; + + cmd = event[2]; + voice = event[3]; + p1 = *(u_short *) &event[4]; + p2 = *(u_short *) &event[6]; + plong = *(u_long *) &event[4]; + + if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) && + (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) + do_volume_irq(voice); + + switch (cmd) { + + case _GUS_NUMVOICES: + flags = splhigh(); + gus_select_voice(voice); + gus_select_max_voices(p1); + splx(flags); + break; + + case _GUS_VOICESAMPLE: + guswave_set_instr(dev, voice, p1); + break; + + case _GUS_VOICEON: + flags = splhigh(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_voice_on(p1); + splx(flags); + break; + + case _GUS_VOICEOFF: + flags = splhigh(); + gus_select_voice(voice); + gus_voice_off(); + splx(flags); + break; + + case _GUS_VOICEFADE: + gus_voice_fade(voice); + break; + + case _GUS_VOICEMODE: + flags = splhigh(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_voice_mode(p1); + splx(flags); + break; + + case _GUS_VOICEBALA: + flags = splhigh(); + gus_select_voice(voice); + gus_voice_balance(p1); + splx(flags); + break; + + case _GUS_VOICEFREQ: + flags = splhigh(); + gus_select_voice(voice); + gus_voice_freq(plong); + splx(flags); + break; + + case _GUS_VOICEVOL: + flags = splhigh(); + gus_select_voice(voice); + gus_voice_volume(p1); + splx(flags); + break; + + case _GUS_VOICEVOL2: /* Just update the software voice level */ + voices[voice].initial_volume = + voices[voice].current_volume = p1; + break; + + case _GUS_RAMPRANGE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NO-NO */ + flags = splhigh(); + gus_select_voice(voice); + gus_ramp_range(p1, p2); + splx(flags); + break; + + case _GUS_RAMPRATE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NJET-NJET */ + flags = splhigh(); + gus_select_voice(voice); + gus_ramp_rate(p1, p2); + splx(flags); + break; + + case _GUS_RAMPMODE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NO-NO */ + flags = splhigh(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_ramp_mode(p1); + splx(flags); + break; + + case _GUS_RAMPON: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* EI-EI */ + flags = splhigh(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_rampon(p1); + splx(flags); + break; + + case _GUS_RAMPOFF: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NEJ-NEJ */ + flags = splhigh(); + gus_select_voice(voice); + gus_rampoff(); + splx(flags); + break; + + case _GUS_VOLUME_SCALE: + volume_base = p1; + volume_scale = p2; + break; + + case _GUS_VOICE_POS: + flags = splhigh(); + gus_select_voice(voice); + gus_set_voice_pos(voice, plong); + splx(flags); + break; + + default:; + } } static int -gus_sampling_set_speed (int speed) +gus_sampling_set_speed(int speed) { - if (speed <= 0) - speed = gus_sampling_speed; + if (speed <= 0) + speed = gus_sampling_speed; - if (speed < 4000) - speed = 4000; + RANGE(speed, 4000, 44100); + gus_sampling_speed = speed; - if (speed > 44100) - speed = 44100; + if (only_read_access) { + /* Compute nearest valid recording speed and return it */ - gus_sampling_speed = speed; - - if (only_read_access) - { - /* Compute nearest valid recording speed and return it */ - - speed = (9878400 / (gus_sampling_speed + 2)) / 16; - speed = (9878400 / (speed * 16)) - 2; - } - return speed; + speed = (9878400 / (gus_sampling_speed + 2)) / 16; + speed = (9878400 / (speed * 16)) - 2; + } + return speed; } static int -gus_sampling_set_channels (int channels) +gus_sampling_set_channels(int channels) { - if (!channels) - return gus_sampling_channels; - if (channels > 2) - channels = 2; - if (channels < 1) - channels = 1; - gus_sampling_channels = channels; - return channels; + if (!channels) + return gus_sampling_channels; + RANGE(channels, 1, 2); + gus_sampling_channels = channels; + return channels; } static int -gus_sampling_set_bits (int bits) +gus_sampling_set_bits(int bits) { - if (!bits) - return gus_sampling_bits; + if (!bits) + return gus_sampling_bits; + + if (bits != 8 && bits != 16) + bits = 8; - if (bits != 8 && bits != 16) - bits = 8; + if (only_8_bits) + bits = 8; - gus_sampling_bits = bits; - return bits; + gus_sampling_bits = bits; + return bits; } static int -gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) +gus_sampling_ioctl(int dev, u_int cmd, ioctl_arg arg, int local) { - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - if (local) - return gus_sampling_set_speed (arg); - return IOCTL_OUT (arg, gus_sampling_set_speed (IOCTL_IN (arg))); - break; - - case SOUND_PCM_READ_RATE: - if (local) - return gus_sampling_speed; - return IOCTL_OUT (arg, gus_sampling_speed); - break; - - case SNDCTL_DSP_STEREO: - if (local) - return gus_sampling_set_channels (arg + 1) - 1; - return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg) + 1) - 1); - break; - - case SOUND_PCM_WRITE_CHANNELS: - if (local) - return gus_sampling_set_channels (arg); - return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg))); - break; - - case SOUND_PCM_READ_CHANNELS: - if (local) - return gus_sampling_channels; - return IOCTL_OUT (arg, gus_sampling_channels); - break; - - case SNDCTL_DSP_SETFMT: - if (local) - return gus_sampling_set_bits (arg); - return IOCTL_OUT (arg, gus_sampling_set_bits (IOCTL_IN (arg))); - break; - - case SOUND_PCM_READ_BITS: - if (local) - return gus_sampling_bits; - return IOCTL_OUT (arg, gus_sampling_bits); - - case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ - return IOCTL_OUT (arg, RET_ERROR (EINVAL)); - break; - - case SOUND_PCM_READ_FILTER: - return IOCTL_OUT (arg, RET_ERROR (EINVAL)); - break; + switch (cmd) { + case SOUND_PCM_WRITE_RATE: + if (local) + return gus_sampling_set_speed((int) arg); + return *(int *) arg = gus_sampling_set_speed((*(int *) arg)); + break; + + case SOUND_PCM_READ_RATE: + if (local) + return gus_sampling_speed; + return *(int *) arg = gus_sampling_speed; + break; + + case SNDCTL_DSP_STEREO: + if (local) + return gus_sampling_set_channels((int) arg + 1) - 1; + return *(int *) arg = gus_sampling_set_channels((*(int *) arg) + 1) - 1; + break; + + case SOUND_PCM_WRITE_CHANNELS: + if (local) + return gus_sampling_set_channels((int) arg); + return *(int *) arg = gus_sampling_set_channels((*(int *) arg)); + break; + + case SOUND_PCM_READ_CHANNELS: + if (local) + return gus_sampling_channels; + return *(int *) arg = gus_sampling_channels; + break; + + case SNDCTL_DSP_SETFMT: + if (local) + return gus_sampling_set_bits((int) arg); + return *(int *) arg = gus_sampling_set_bits((*(int *) arg)); + break; + + case SOUND_PCM_READ_BITS: + if (local) + return gus_sampling_bits; + return *(int *) arg = gus_sampling_bits; + + case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ + return *(int *) arg = -(EINVAL); + break; + + case SOUND_PCM_READ_FILTER: + return *(int *) arg = -(EINVAL); + break; - } - return RET_ERROR (EINVAL); + } + return -(EINVAL); } static void -gus_sampling_reset (int dev) +gus_sampling_reset(int dev) { + if (recording_active) { + gus_write8(0x49, 0x00); /* Halt recording */ + set_input_volumes(); + } } static int -gus_sampling_open (int dev, int mode) +gus_sampling_open(int dev, int mode) { - int dev_flag; - int init_flag; -#ifdef GUS_NO_DMA - printk ("GUS: DMA mode not enabled. Device not supported\n"); - return RET_ERROR (ENXIO); -#endif - dev_flag = 0; - init_flag = (gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum] == 0); - if(mode & OPEN_WRITE) - { - if (gus_busy[gus_devnum]) - return RET_ERROR(EBUSY); - if(dev != gus_devnum) - return RET_ERROR(ENXIO); - dev_flag = gus_busy[gus_devnum] = 1; - } - if(mode & OPEN_READ) - { - if(gus_busy[gus_dspnum]) { - if (dev_flag) gus_busy[gus_devnum] = 0; - return RET_ERROR(EBUSY); - } - - if(dev != gus_dspnum) { - if (dev_flag) gus_busy[gus_devnum] = 0; - return RET_ERROR(ENXIO); - } - } - - if(init_flag) - { - gus_initialize (); - active_device = 0; + int otherside = audio_devs[dev]->otherside; + if (otherside != -1) { + if (audio_devs[otherside]->busy) + return -(EBUSY); + } + if (audio_devs[dev]->busy) + return -(EBUSY); - gus_reset (); - reset_sample_memory (); - gus_select_max_voices (14); - pcm_active = 0; - dma_active = 0; - pcm_opened = 1; - } - if (mode & OPEN_READ) - { - recording_active = 1; - set_input_volumes (); + gus_initialize(); + + active_device = 0; + + gus_reset(); + reset_sample_memory(); + gus_select_max_voices(14); + + pcm_active = 0; + dma_active = 0; + pcm_opened = 1; + audio_devs[dev]->busy = 1; + + if (mode & OPEN_READ) { + recording_active = 1; + set_input_volumes(); } - only_read_access = !(mode & OPEN_WRITE); + only_read_access = !(mode & OPEN_WRITE); + only_8_bits = mode & OPEN_READ; + if (only_8_bits) + audio_devs[dev]->format_mask = AFMT_U8; + else + audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE; - return 0; + return 0; } static void -gus_sampling_close (int dev) +gus_sampling_close(int dev) { - gus_busy[dev] = 0; - if (gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum] == 0) { - active_device = 0; - gus_reset(); - pcm_opened = 0; - } + int otherside = audio_devs[dev]->otherside; + audio_devs[dev]->busy = 0; - if (recording_active) - set_input_volumes (); + if (otherside != -1) { + if (audio_devs[otherside]->busy) + return; + } + gus_reset(); + + pcm_opened = 0; + active_device = 0; - recording_active = 0; + if (recording_active) { + gus_write8(0x49, 0x00); /* Halt recording */ + set_input_volumes(); + } + recording_active = 0; } static void -gus_sampling_update_volume (void) +gus_sampling_update_volume(void) { - unsigned long flags; - int voice; - - if (pcm_active && pcm_opened) - for (voice = 0; voice < gus_sampling_channels; voice++) - { - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_rampoff (); - gus_voice_volume (1530 + (25 * gus_pcm_volume)); - gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); - RESTORE_INTR (flags); - } + u_long flags; + int voice; + + if (pcm_active && pcm_opened) + for (voice = 0; voice < gus_sampling_channels; voice++) { + flags = splhigh(); + gus_select_voice(voice); + gus_rampoff(); + gus_voice_volume(1530 + (25 * gus_pcm_volume)); + gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); + splx(flags); + } } static void -play_next_pcm_block (void) +play_next_pcm_block(void) { - unsigned long flags; - int speed = gus_sampling_speed; - int this_one, is16bits, chn; - unsigned long dram_loc; - unsigned char mode[2], ramp_mode[2]; + u_long flags; + int speed = gus_sampling_speed; + int this_one, is16bits, chn; + u_long dram_loc; + u_char mode[2], ramp_mode[2]; - if (!pcm_qlen) - return; + if (!pcm_qlen) + return; - this_one = pcm_head; + this_one = pcm_head; - for (chn = 0; chn < gus_sampling_channels; chn++) - { - mode[chn] = 0x00; - ramp_mode[chn] = 0x03; /* Ramping and rollover off */ - - if (chn == 0) - { - mode[chn] |= 0x20; /* Loop IRQ */ - voices[chn].loop_irq_mode = LMODE_PCM; - } - - if (gus_sampling_bits != 8) - { - is16bits = 1; - mode[chn] |= 0x04; /* 16 bit data */ - } - else - is16bits = 0; - - dram_loc = this_one * pcm_bsize; - dram_loc += chn * pcm_banksize; - - if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */ - { - mode[chn] |= 0x08; /* Enable loop */ - ramp_mode[chn] = 0x03; /* Disable rollover bit */ - } - else - { - if (chn == 0) - ramp_mode[chn] = 0x04; /* Enable rollover bit */ - } - - DISABLE_INTR (flags); - gus_select_voice (chn); - gus_voice_freq (speed); - - if (gus_sampling_channels == 1) - gus_voice_balance (7); /* mono */ - else if (chn == 0) - gus_voice_balance (0); /* left */ - else - gus_voice_balance (15); /* right */ - - if (!pcm_active) /* Playback not already active */ - { - /* - * The playback was not started yet (or there has been a pause). - * Start the voice (again) and ask for a rollover irq at the end of - * this_one block. If this_one one is last of the buffers, use just - * the normal loop with irq. - */ - - gus_voice_off (); - gus_rampoff (); - gus_voice_volume (1530 + (25 * gus_pcm_volume)); - gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); - - gus_write_addr (0x0a, dram_loc, is16bits); /* Starting position */ - gus_write_addr (0x02, chn * pcm_banksize, is16bits); /* Loop start */ - - if (chn != 0) - gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, - is16bits); /* Loop end location */ - } - - if (chn == 0) - gus_write_addr (0x04, dram_loc + pcm_datasize[this_one] - 1, - is16bits); /* Loop end location */ - else - mode[chn] |= 0x08; /* Enable looping */ - - if (pcm_datasize[this_one] != pcm_bsize) - { - /* - * Incompletely filled block. Possibly the last one. - */ - if (chn == 0) - { - mode[chn] &= ~0x08; /* Disable looping */ - mode[chn] |= 0x20; /* Enable IRQ at the end */ - voices[0].loop_irq_mode = LMODE_PCM_STOP; - ramp_mode[chn] = 0x03; /* No rollover bit */ - } - else - { - gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], - is16bits); /* Loop end location */ - mode[chn] &= ~0x08; /* Disable looping */ - } + for (chn = 0; chn < gus_sampling_channels; chn++) { + mode[chn] = 0x00; + ramp_mode[chn] = 0x03; /* Ramping and rollover off */ + + if (chn == 0) { + mode[chn] |= 0x20; /* Loop IRQ */ + voices[chn].loop_irq_mode = LMODE_PCM; + } + if (gus_sampling_bits != 8) { + is16bits = 1; + mode[chn] |= 0x04; /* 16 bit data */ + } else + is16bits = 0; + + dram_loc = this_one * pcm_bsize; + dram_loc += chn * pcm_banksize; + + if (this_one == (pcm_nblk - 1)) { /* Last fragment of the + * DRAM buffer */ + mode[chn] |= 0x08; /* Enable loop */ + ramp_mode[chn] = 0x03; /* Disable rollover bit */ + } else { + if (chn == 0) + ramp_mode[chn] = 0x04; /* Enable rollover bit */ } - RESTORE_INTR (flags); + flags = splhigh(); + gus_select_voice(chn); + gus_voice_freq(speed); + + if (gus_sampling_channels == 1) + gus_voice_balance(7); /* mono */ + else if (chn == 0) + gus_voice_balance(0); /* left */ + else + gus_voice_balance(15); /* right */ + + if (!pcm_active) { /* Playback not already active */ + /* + * The playback was not started yet (or there has + * been a pause). Start the voice (again) and ask for + * a rollover irq at the end of this_one block. If + * this_one one is last of the buffers, use just the + * normal loop with irq. + */ + + gus_voice_off(); + gus_rampoff(); + gus_voice_volume(1530 + (25 * gus_pcm_volume)); + gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); + + gus_write_addr(0x0a, dram_loc, is16bits); /* Starting position */ + gus_write_addr(0x02, chn * pcm_banksize, is16bits); /* Loop start */ + + if (chn != 0) + gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, + is16bits); /* Loop end location */ + } + if (chn == 0) + gus_write_addr(0x04, dram_loc + pcm_datasize[this_one] - 1, + is16bits); /* Loop end location */ + else + mode[chn] |= 0x08; /* Enable looping */ + + if (pcm_datasize[this_one] != pcm_bsize) { + /* + * Incompletely filled block. Possibly the last one. + */ + if (chn == 0) { + mode[chn] &= ~0x08; /* Disable looping */ + mode[chn] |= 0x20; /* Enable IRQ at the end */ + voices[0].loop_irq_mode = LMODE_PCM_STOP; + ramp_mode[chn] = 0x03; /* No rollover bit */ + } else { + gus_write_addr(0x04, dram_loc + pcm_datasize[this_one], + is16bits); /* Loop end location */ + mode[chn] &= ~0x08; /* Disable looping */ + } + } + splx(flags); } - for (chn = 0; chn < gus_sampling_channels; chn++) - { - DISABLE_INTR (flags); - gus_select_voice (chn); - gus_write8 (0x0d, ramp_mode[chn]); - gus_voice_on (mode[chn]); - RESTORE_INTR (flags); + for (chn = 0; chn < gus_sampling_channels; chn++) { + flags = splhigh(); + gus_select_voice(chn); + gus_write8(0x0d, ramp_mode[chn]); + gus_voice_on(mode[chn]); + splx(flags); } - pcm_active = 1; + pcm_active = 1; } static void -gus_transfer_output_block (int dev, unsigned long buf, - int total_count, int intrflag, int chn) +gus_transfer_output_block(int dev, u_long buf, + int total_count, int intrflag, int chn) { - /* - * This routine transfers one block of audio data to the DRAM. In mono mode - * it's called just once. When in stereo mode, this_one routine is called - * once for both channels. - * - * The left/mono channel data is transferred to the beginning of dram and the - * right data to the area pointed by gus_page_size. - */ - - int this_one, count; - unsigned long flags; - unsigned char dma_command; - unsigned long address, hold_address; - - DISABLE_INTR (flags); - - count = total_count / gus_sampling_channels; - - if (chn == 0) - { - if (pcm_qlen >= pcm_nblk) - printk ("GUS Warning: PCM buffers out of sync\n"); + /* + * This routine transfers one block of audio data to the DRAM. In + * mono mode it's called just once. When in stereo mode, this_one + * routine is called once for both channels. + * + * The left/mono channel data is transferred to the beginning of dram + * and the right data to the area pointed by gus_page_size. + */ - this_one = pcm_current_block = pcm_tail; - pcm_qlen++; - pcm_tail = (pcm_tail + 1) % pcm_nblk; - pcm_datasize[this_one] = count; - } - else - this_one = pcm_current_block; + int this_one, count; + u_long flags; + u_char dma_command; + u_long address, hold_address; - gus_write8 (0x41, 0); /* Disable GF1 DMA */ - DMAbuf_start_dma (gus_devnum, buf + (chn * count), count, DMA_MODE_WRITE); + flags = splhigh(); - address = this_one * pcm_bsize; - address += chn * pcm_banksize; + count = total_count / gus_sampling_channels; - if (audio_devs[gus_devnum]->dmachan > 3) - { - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } + if (chn == 0) { + if (pcm_qlen >= pcm_nblk) + printf("GUS Warning: PCM buffers out of sync\n"); - gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ + this_one = pcm_current_block = pcm_tail; + pcm_qlen++; + pcm_tail = (pcm_tail + 1) % pcm_nblk; + pcm_datasize[this_one] = count; + } else + this_one = pcm_current_block; - dma_command = 0x21; /* IRQ enable, DMA start */ + gus_write8(0x41, 0); /* Disable GF1 DMA */ + DMAbuf_start_dma(dev, buf + (chn * count), count, 1); - if (gus_sampling_bits != 8) - dma_command |= 0x40; /* 16 bit _DATA_ */ - else - dma_command |= 0x80; /* Invert MSB */ + address = this_one * pcm_bsize; + address += chn * pcm_banksize; - if (audio_devs[gus_devnum]->dmachan > 3) - dma_command |= 0x04; /* 16 bit DMA channel */ + if (audio_devs[dev]->dmachan1 > 3) { + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ - gus_write8 (0x41, dma_command); /* Kickstart */ + dma_command = 0x21; /* IRQ enable, DMA start */ - if (chn == (gus_sampling_channels - 1)) /* Last channel */ - { - /* - * Last (right or mono) channel data - */ - dma_active = 1; /* DMA started. There is a unacknowledged buffer */ - active_device = GUS_DEV_PCM_DONE; - if (!pcm_active && (pcm_qlen > 0 || count < pcm_bsize)) - { - play_next_pcm_block (); + if (gus_sampling_bits != 8) + dma_command |= 0x40; /* 16 bit _DATA_ */ + else + dma_command |= 0x80; /* Invert MSB */ + + if (audio_devs[dev]->dmachan1 > 3) + dma_command |= 0x04; /* 16 bit DMA channel */ + + gus_write8(0x41, dma_command); /* Kickstart */ + + if (chn == (gus_sampling_channels - 1)) { /* Last channel */ + /* + * Last (right or mono) channel data + */ + dma_active = 1; /* DMA started. There is a unacknowledged + * buffer */ + active_device = GUS_DEV_PCM_DONE; + if (!pcm_active && (pcm_qlen > 0 || count < pcm_bsize)) { + play_next_pcm_block(); + } + } else { + /* + * Left channel data. The right channel is transferred after + * DMA interrupt + */ + active_device = GUS_DEV_PCM_CONTINUE; } - } - else - { - /* - * Left channel data. The right channel - * is transferred after DMA interrupt - */ - active_device = GUS_DEV_PCM_CONTINUE; - } - RESTORE_INTR (flags); + splx(flags); } static void -gus_sampling_output_block (int dev, unsigned long buf, int total_count, - int intrflag, int restart_dma) +gus_sampling_output_block(int dev, u_long buf, int total_count, + int intrflag, int restart_dma) { - pcm_current_buf = buf; - pcm_current_count = total_count; - pcm_current_intrflag = intrflag; - pcm_current_dev = gus_devnum; - gus_transfer_output_block (gus_devnum, buf, total_count, intrflag, 0); + pcm_current_buf = buf; + pcm_current_count = total_count; + pcm_current_intrflag = intrflag; + pcm_current_dev = dev; + gus_transfer_output_block(dev, buf, total_count, intrflag, 0); } static void -gus_sampling_start_input (int dev, unsigned long buf, int count, - int intrflag, int restart_dma) +gus_sampling_start_input(int dev, u_long buf, int count, + int intrflag, int restart_dma) { - unsigned long flags; - unsigned char mode; + u_long flags; + u_char mode; - DISABLE_INTR (flags); + flags = splhigh(); - DMAbuf_start_dma (gus_dspnum, buf, count, DMA_MODE_READ); + DMAbuf_start_dma(dev, buf, count, 0); - mode = 0xa0; /* DMA IRQ enabled, invert MSB */ + mode = 0xa0; /* DMA IRQ enabled, invert MSB */ - if (audio_devs[gus_dspnum]->dmachan > 3) - mode |= 0x04; /* 16 bit DMA channel */ - if (gus_sampling_channels > 1) - mode |= 0x02; /* Stereo */ - mode |= 0x01; /* DMA enable */ + if (audio_devs[dev]->dmachan2 > 3) + mode |= 0x04; /* 16 bit DMA channel */ + if (gus_sampling_channels > 1) + mode |= 0x02; /* Stereo */ + mode |= 0x01; /* DMA enable */ - gus_write8 (0x49, mode); + gus_write8(0x49, mode); - RESTORE_INTR (flags); + splx(flags); } static int -gus_sampling_prepare_for_input (int dev, int bsize, int bcount) +gus_sampling_prepare_for_input(int dev, int bsize, int bcount) { - unsigned int rate; + u_int rate; - rate = (9878400 / (gus_sampling_speed + 2)) / 16; + rate = (9878400 / (gus_sampling_speed + 2)) / 16; - gus_write8 (0x48, rate & 0xff); /* Set sampling rate */ + gus_write8(0x48, rate & 0xff); /* Set sampling rate */ - if (gus_sampling_bits != 8) - { - printk ("GUS Error: 16 bit recording not supported\n"); - return RET_ERROR (EINVAL); + if (gus_sampling_bits != 8) { + printf("GUS Error: 16 bit recording not supported\n"); + return -(EINVAL); } - - return 0; + return 0; } static int -gus_sampling_prepare_for_output (int dev, int bsize, int bcount) +gus_sampling_prepare_for_output(int dev, int bsize, int bcount) { - int i; + int i; - long mem_ptr, mem_size; + long mem_ptr, mem_size; - mem_ptr = 0; - mem_size = gus_mem_size / gus_sampling_channels; + mem_ptr = 0; + mem_size = gus_mem_size / gus_sampling_channels; - if (mem_size > (256 * 1024)) - mem_size = 256 * 1024; + if (mem_size > (256 * 1024)) + mem_size = 256 * 1024; - pcm_bsize = bsize / gus_sampling_channels; - pcm_head = pcm_tail = pcm_qlen = 0; + pcm_bsize = bsize / gus_sampling_channels; + pcm_head = pcm_tail = pcm_qlen = 0; - pcm_nblk = MAX_PCM_BUFFERS; - if ((pcm_bsize * pcm_nblk) > mem_size) - pcm_nblk = mem_size / pcm_bsize; + pcm_nblk = MAX_PCM_BUFFERS; + if ((pcm_bsize * pcm_nblk) > mem_size) + pcm_nblk = mem_size / pcm_bsize; - for (i = 0; i < pcm_nblk; i++) - pcm_datasize[i] = 0; + for (i = 0; i < pcm_nblk; i++) + pcm_datasize[i] = 0; - pcm_banksize = pcm_nblk * pcm_bsize; + pcm_banksize = pcm_nblk * pcm_bsize; - if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024)) - pcm_nblk--; + if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024)) + pcm_nblk--; - return 0; + return 0; } static int -gus_local_qlen (int dev) +gus_local_qlen(int dev) { - return pcm_qlen; + return pcm_qlen; } static void -gus_copy_from_user (int dev, char *localbuf, int localoffs, - snd_rw_buf * userbuf, int useroffs, int len) +gus_copy_from_user(int dev, char *localbuf, int localoffs, + snd_rw_buf * userbuf, int useroffs, int len) { - if (gus_sampling_channels == 1) - { - COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len); - } - else if (gus_sampling_bits == 8) -#if defined(__FreeBSD__) - { - char *in_left = gus_copy_buf; - char *in_right = in_left + 1; - char *out_left = localbuf + (localoffs / 2); - char *out_right = out_left + pcm_bsize; - int i; + if (gus_sampling_channels == 1) { + + if (uiomove(&localbuf[localoffs], len, userbuf)) { + printf("audio: Bad copyin()!\n"); + }; + } else if (gus_sampling_bits == 8) { + int in_left = useroffs; + int in_right = useroffs + 1; + char *out_left, *out_right; + int i; + + len /= 2; + localoffs /= 2; + out_left = &localbuf[localoffs]; + out_right = out_left + pcm_bsize; + + for (i = 0; i < len; i++) { + uiomove((char *) &(*out_left++), 1, userbuf); + in_left += 2; + uiomove((char *) &(*out_right++), 1, userbuf); + in_right += 2; + } + } else { + int in_left = useroffs; + int in_right = useroffs + 2; + short *out_left, *out_right; + int i; + + len /= 4; + localoffs /= 2; + + out_left = (short *) &localbuf[localoffs]; + out_right = out_left + (pcm_bsize / 2); + + for (i = 0; i < len; i++) { + uiomove((char *) &(*out_left++), 2, userbuf); + in_left += 2; + uiomove((char *) &(*out_right++), 2, userbuf); + in_right += 2; + } + } +} - COPY_FROM_USER (gus_copy_buf, userbuf, useroffs, len); +static struct audio_operations gus_sampling_operations = +{ + "Gravis UltraSound", + NEEDS_RESTART, + AFMT_U8 | AFMT_S16_LE, + NULL, + gus_sampling_open, + gus_sampling_close, + gus_sampling_output_block, + gus_sampling_start_input, + gus_sampling_ioctl, + gus_sampling_prepare_for_input, + gus_sampling_prepare_for_output, + gus_sampling_reset, + gus_sampling_reset, + gus_local_qlen, + gus_copy_from_user +}; - len /= 2; +static void +guswave_setup_voice(int dev, int voice, int chn) +{ + struct channel_info *info = + &synth_devs[dev]->chn_info[chn]; + + guswave_set_instr(dev, voice, info->pgm_num); + + voices[voice].expression_vol = + info->controllers[CTL_EXPRESSION]; /* Just msb */ + voices[voice].main_vol = + (info->controllers[CTL_MAIN_VOLUME] * 100) / 128; + voices[voice].panning = + (info->controllers[CTL_PAN] * 2) - 128; + voices[voice].bender = info->bender_value; +} - for (i = 0; i < len; i++) - { - *out_left++ = *in_left++; - in_left++; - *out_right++ = *in_right++; - in_right++; - } - } - else - { - short *in_left = (short *)gus_copy_buf; - short *in_right = in_left + 1; - short *out_left = (short *)localbuf + (localoffs / 4); - short *out_right = out_left + (pcm_bsize / 2); - int i; +static void +guswave_bender(int dev, int voice, int value) +{ + int freq; + u_long flags; + + voices[voice].bender = value - 8192; + freq = compute_finetune(voices[voice].orig_freq, value - 8192, + voices[voice].bender_range); + voices[voice].current_freq = freq; + + flags = splhigh(); + gus_select_voice(voice); + gus_voice_freq(freq); + splx(flags); +} + +static int +guswave_patchmgr(int dev, struct patmgr_info * rec) +{ + int i, n; + + switch (rec->command) { + case PM_GET_DEVTYPE: + rec->parm1 = PMTYPE_WAVE; + return 0; + break; + + case PM_GET_NRPGM: + rec->parm1 = MAX_PATCH; + return 0; + break; + + case PM_GET_PGMMAP: + rec->parm1 = MAX_PATCH; + + for (i = 0; i < MAX_PATCH; i++) { + int ptr = patch_table[i]; + + rec->data.data8[i] = 0; + + while (ptr >= 0 && ptr < free_sample) { + rec->data.data8[i]++; + ptr = samples[ptr].key; /* Follow link */ + } + } + return 0; + break; + + case PM_GET_PGM_PATCHES: + { + int ptr = patch_table[rec->parm1]; + + n = 0; + + while (ptr >= 0 && ptr < free_sample) { + rec->data.data32[n++] = ptr; + ptr = samples[ptr].key; /* Follow link */ + } + } + rec->parm1 = n; + return 0; + break; + + case PM_GET_PATCH: + { + int ptr = rec->parm1; + struct patch_info *pat; + + if (ptr < 0 || ptr >= free_sample) + return -(EINVAL); + + bcopy((char *) &samples[ptr], rec->data.data8, sizeof(struct patch_info)); + + pat = (struct patch_info *) rec->data.data8; + + pat->key = GUS_PATCH; /* Restore patch type */ + rec->parm1 = sample_ptrs[ptr]; /* DRAM location */ + rec->parm2 = sizeof(struct patch_info); + } + return 0; + break; + + case PM_SET_PATCH: + { + int ptr = rec->parm1; + struct patch_info *pat; + + if (ptr < 0 || ptr >= free_sample) + return -(EINVAL); + + pat = (struct patch_info *) rec->data.data8; + + if (pat->len > samples[ptr].len) /* Cannot expand sample */ + return -(EINVAL); + + pat->key = samples[ptr].key; /* Ensure the link is + * correct */ - COPY_FROM_USER (gus_copy_buf, userbuf, useroffs, len); + bcopy(rec->data.data8, (char *) &samples[ptr], sizeof(struct patch_info)); - len /= 4; + pat->key = GUS_PATCH; + } + return 0; + break; - for (i = 0; i < len; i++) - { - *out_left++ = *in_left++; - in_left++; - *out_right++ = *in_right++; - in_right++; + case PM_READ_PATCH: /* Returns a block of wave data from the DRAM */ + { + int sample = rec->parm1; + int n; + long offs = rec->parm2; + int l = rec->parm3; + + if (sample < 0 || sample >= free_sample) + return -(EINVAL); + + if (offs < 0 || offs >= samples[sample].len) + return -(EINVAL); /* Invalid offset */ + + n = samples[sample].len - offs; /* Num of bytes left */ + + if (l > n) + l = n; + + if (l > sizeof(rec->data.data8)) + l = sizeof(rec->data.data8); + + if (l <= 0) + return -(EINVAL); /* Was there a bug? */ + + offs += sample_ptrs[sample]; /* Begin offsess + + * offset to DRAM */ + + for (n = 0; n < l; n++) + rec->data.data8[n] = gus_peek(offs++); + rec->parm1 = n; /* Nr of bytes copied */ + } + return 0; + break; + + case PM_WRITE_PATCH: /* Writes a block of wave data to the DRAM */ + { + int sample = rec->parm1; + int n; + long offs = rec->parm2; + int l = rec->parm3; + + if (sample < 0 || sample >= free_sample) + return -(EINVAL); + + if (offs < 0 || offs >= samples[sample].len) + return -(EINVAL); /* Invalid offset */ + + n = samples[sample].len - offs; /* Nr of bytes left */ + + if (l > n) + l = n; + + if (l > sizeof(rec->data.data8)) + l = sizeof(rec->data.data8); + + if (l <= 0) + return -(EINVAL); /* Was there a bug? */ + + offs += sample_ptrs[sample]; /* Begin offsess + + * offset to DRAM */ + + for (n = 0; n < l; n++) + gus_poke(offs++, rec->data.data8[n]); + rec->parm1 = n; /* Nr of bytes copied */ + } + return 0; + break; + + default: + return -(EINVAL); } - } -#else - { - int in_left = useroffs; - int in_right = useroffs + 1; - char *out_left, *out_right; - int i; - - len /= 2; - localoffs /= 2; - out_left = &localbuf[localoffs]; - out_right = out_left + pcm_bsize; - - for (i = 0; i < len; i++) - { - GET_BYTE_FROM_USER (*out_left++, userbuf, in_left); - in_left += 2; - GET_BYTE_FROM_USER (*out_right++, userbuf, in_right); - in_right += 2; +} + +static int +guswave_alloc(int dev, int chn, int note, struct voice_alloc_info * alloc) +{ + int i, p, best = -1, best_time = 0x7fffffff; + + p = alloc->ptr; + /* + * First look for a completely stopped voice + */ + + for (i = 0; i < alloc->max_voice; i++) { + if (alloc->map[p] == 0) { + alloc->ptr = p; + return p; + } + if (alloc->alloc_times[p] < best_time) { + best = p; + best_time = alloc->alloc_times[p]; + } + p = (p + 1) % alloc->max_voice; } - } - else - { - int in_left = useroffs / 2; - int in_right = useroffs / 2 + 1; - short *out_left, *out_right; - int i; - - len /= 4; - localoffs /= 2; - - out_left = (short *) &localbuf[localoffs]; - out_right = out_left + (pcm_bsize / 2); - - for (i = 0; i < len; i++) - { -#ifdef __FreeBSD__ - GET_SHORT_FROM_USER (*out_left++, userbuf, in_left); - in_left += 2; - GET_SHORT_FROM_USER (*out_right++, userbuf, in_right); - in_right += 2; -#else - GET_SHORT_FROM_USER (*out_left++, (short *) userbuf, in_left); - in_left += 2; - GET_SHORT_FROM_USER (*out_right++, (short *) userbuf, in_right); - in_right += 2; -#endif + + /* + * Then look for a releasing voice + */ + + for (i = 0; i < alloc->max_voice; i++) { + if (alloc->map[p] == 0xffff) { + alloc->ptr = p; + return p; + } + p = (p + 1) % alloc->max_voice; } - } -#endif + + if (best >= 0) + p = best; + + alloc->ptr = p; + return p; } -static struct audio_operations gus_sampling_operations = +static struct synth_operations guswave_operations = { - "Gravis UltraSound", - NEEDS_RESTART, - AFMT_U8 | AFMT_S16_LE, - NULL, - gus_sampling_open, - gus_sampling_close, - gus_sampling_output_block, - gus_sampling_start_input, - gus_sampling_ioctl, - gus_sampling_prepare_for_input, - gus_sampling_prepare_for_output, - gus_sampling_reset, - gus_sampling_reset, - gus_local_qlen, - gus_copy_from_user -}; - -static struct audio_operations gus_sampling_operations_read = -{ - "Gravis UltraSound - read only", - NEEDS_RESTART, - AFMT_U8 | AFMT_S16_LE, - NULL, - gus_sampling_open, - gus_sampling_close, - gus_sampling_output_block, - gus_sampling_start_input, - gus_sampling_ioctl, - gus_sampling_prepare_for_input, - gus_sampling_prepare_for_output, - gus_sampling_reset, - gus_sampling_reset, - gus_local_qlen, - gus_copy_from_user + &gus_info, + 0, + SYNTH_TYPE_SAMPLE, + SAMPLE_TYPE_GUS, + guswave_open, + guswave_close, + guswave_ioctl, + guswave_kill_note, + guswave_start_note, + guswave_set_instr, + guswave_reset, + guswave_hw_control, + guswave_load_patch, + guswave_aftertouch, + guswave_controller, + guswave_panning, + guswave_volume_method, + guswave_patchmgr, + guswave_bender, + guswave_alloc, + guswave_setup_voice }; static void -guswave_setup_voice (int dev, int voice, int chn) +set_input_volumes(void) { - struct channel_info *info = - &synth_devs[gus_devnum]->chn_info[chn]; + u_long flags; + u_char mask = 0xff & ~0x06; /* Just line out enabled */ + + if (have_gus_max) /* Don't disturb GUS MAX */ + return; - guswave_set_instr (gus_devnum, voice, info->pgm_num); + flags = splhigh(); - voices[voice].expression_vol = - info->controllers[CTL_EXPRESSION]; /* Just msb */ - voices[voice].main_vol = - (info->controllers[CTL_MAIN_VOLUME] * 100) / 128; - voices[voice].panning = - (info->controllers[CTL_PAN] * 2) - 128; - voices[voice].bender = info->bender_value; + /* + * Enable channels having vol > 10% Note! bit 0x01 means the line in + * DISABLED while 0x04 means the mic in ENABLED. + */ + if (gus_line_vol > 10) + mask &= ~0x01; + if (gus_mic_vol > 10) + mask |= 0x04; + + if (recording_active) { + /* + * Disable channel, if not selected for recording + */ + if (!(gus_recmask & SOUND_MASK_LINE)) + mask |= 0x01; + if (!(gus_recmask & SOUND_MASK_MIC)) + mask &= ~0x04; + } + mix_image &= ~0x07; + mix_image |= mask & 0x07; + outb(u_Mixer, mix_image); + + splx(flags); +} + +int +gus_default_mixer_ioctl(int dev, u_int cmd, ioctl_arg arg) +{ + +#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \ + SOUND_MASK_SYNTH|SOUND_MASK_PCM) + + if (((cmd >> 8) & 0xff) == 'M') { + if (cmd & IOC_IN) + switch (cmd & 0xff) { + case SOUND_MIXER_RECSRC: + gus_recmask = (*(int *) arg) & MIX_DEVS; + if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) + gus_recmask = SOUND_MASK_MIC; + /* + * Note! Input volumes are updated during + * next open for recording + */ + return *(int *) arg = gus_recmask; + break; + + case SOUND_MIXER_MIC: + { + int vol = (*(int *) arg) & 0xff; + + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + gus_mic_vol = vol; + set_input_volumes(); + return *(int *) arg = vol | (vol << 8); + } + break; + + case SOUND_MIXER_LINE: + { + int vol = (*(int *) arg) & 0xff; + + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + gus_line_vol = vol; + set_input_volumes(); + return *(int *) arg = vol | (vol << 8); + } + break; + + case SOUND_MIXER_PCM: + gus_pcm_volume = (*(int *) arg) & 0xff; + RANGE (gus_pcm_volume, 0, 100); + gus_sampling_update_volume(); + return *(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8); + break; + + case SOUND_MIXER_SYNTH: + { + int voice; + + gus_wave_volume = (*(int *) arg) & 0xff; + + RANGE (gus_wave_volume , 0, 100); + + if (active_device == GUS_DEV_WAVE) + for (voice = 0; voice < nr_voices; voice++) + dynamic_volume_change(voice); /* Apply the new vol */ + + return *(int *) arg = gus_wave_volume | (gus_wave_volume << 8); + } + break; + + default: + return -(EINVAL); + } + else + switch (cmd & 0xff) { /* Return parameters */ + + case SOUND_MIXER_RECSRC: + return *(int *) arg = gus_recmask; + break; + + case SOUND_MIXER_DEVMASK: + return *(int *) arg = MIX_DEVS; + break; + + case SOUND_MIXER_STEREODEVS: + return *(int *) arg = 0; + break; + + case SOUND_MIXER_RECMASK: + return *(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE; + break; + + case SOUND_MIXER_CAPS: + return *(int *) arg = 0; + break; + + case SOUND_MIXER_MIC: + return *(int *) arg = gus_mic_vol | (gus_mic_vol << 8); + break; + + case SOUND_MIXER_LINE: + return *(int *) arg = gus_line_vol | (gus_line_vol << 8); + break; + + case SOUND_MIXER_PCM: + return *(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8); + break; + + case SOUND_MIXER_SYNTH: + return *(int *) arg = gus_wave_volume | (gus_wave_volume << 8); + break; + + default: + return -(EINVAL); + } +} else + return -(EINVAL); } +static struct mixer_operations gus_mixer_operations = {"Gravis Ultrasound", gus_default_mixer_ioctl}; + static void -guswave_bender (int dev, int voice, int value) +gus_default_mixer_init() { - int freq; - unsigned long flags; +if (num_mixers < MAX_MIXER_DEV) /* Don't install if there is another + * mixer */ + mixer_devs[num_mixers++] = &gus_mixer_operations; - voices[voice].bender = value - 8192; - freq = compute_finetune (voices[voice].orig_freq, value, - voices[voice].bender_range); - voices[voice].current_freq = freq; +if (have_gus_max) { + /* + * Enable all mixer channels on the GF1 side. Otherwise + * recording will not be possible using GUS MAX. + */ + mix_image &= ~0x07; + mix_image |= 0x04; /* All channels enabled */ + outb(u_Mixer, mix_image); +} +} + +/* start of pnp code */ - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_voice_freq (freq); - RESTORE_INTR (flags); +void +SEND(int d, int r) +{ +outb(PADDRESS, d); +outb(PWRITE_DATA, r); } -static int -guswave_patchmgr (int dev, struct patmgr_info *rec) + + + +/* + * Get the device's serial number. Returns 1 if the serial is valid. + */ +int +get_serial(int rd_port, u_char *data) { - int i, n; + int i, bit, valid = 0, sum = 0x6a; - switch (rec->command) - { - case PM_GET_DEVTYPE: - rec->parm1 = PMTYPE_WAVE; - return 0; - break; + bzero(data, sizeof(char) * 9); - case PM_GET_NRPGM: - rec->parm1 = MAX_PATCH; - return 0; - break; + for (i = 0; i < 72; i++) { + bit = inb((rd_port << 2) | 0x3) == 0x55; + DELAY(250); /* Delay 250 usec */ - case PM_GET_PGMMAP: - rec->parm1 = MAX_PATCH; + /* Can't Short Circuit the next evaluation, so 'and' is last */ + bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit; + DELAY(250); /* Delay 250 usec */ - for (i = 0; i < MAX_PATCH; i++) - { - int ptr = patch_table[i]; + valid = valid || bit; - rec->data.data8[i] = 0; + if (i < 64) + sum = (sum >> 1) | + (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff); - while (ptr >= 0 && ptr < free_sample) - { - rec->data.data8[i]++; - ptr = samples[ptr].key; /* Follow link */ - } + data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0); } - return 0; - break; + valid = valid && (data[8] == sum); + + return valid; +} - case PM_GET_PGM_PATCHES: - { - int ptr = patch_table[rec->parm1]; - - n = 0; - - while (ptr >= 0 && ptr < free_sample) - { - rec->data.data32[n++] = ptr; - ptr = samples[ptr].key; /* Follow link */ - } - } - rec->parm1 = n; - return 0; - break; - - case PM_GET_PATCH: - { - int ptr = rec->parm1; - struct patch_info *pat; - - if (ptr < 0 || ptr >= free_sample) - return RET_ERROR (EINVAL); - - memcpy (rec->data.data8, (char *) &samples[ptr], - sizeof (struct patch_info)); +void +send_Initiation_LFSR() +{ + int cur, i; - pat = (struct patch_info *) rec->data.data8; - - pat->key = GUS_PATCH; /* Restore patch type */ - rec->parm1 = sample_ptrs[ptr]; /* DRAM location */ - rec->parm2 = sizeof (struct patch_info); - } - return 0; - break; - - case PM_SET_PATCH: - { - int ptr = rec->parm1; - struct patch_info *pat; - - if (ptr < 0 || ptr >= free_sample) - return RET_ERROR (EINVAL); - - pat = (struct patch_info *) rec->data.data8; - - if (pat->len > samples[ptr].len) /* Cannot expand sample */ - return RET_ERROR (EINVAL); - - pat->key = samples[ptr].key; /* Ensure the link is correct */ - - memcpy ((char *) &samples[ptr], rec->data.data8, - sizeof (struct patch_info)); - - pat->key = GUS_PATCH; - } - return 0; - break; - - case PM_READ_PATCH: /* Returns a block of wave data from the DRAM */ - { - int sample = rec->parm1; - int n; - long offs = rec->parm2; - int l = rec->parm3; - - if (sample < 0 || sample >= free_sample) - return RET_ERROR (EINVAL); - - if (offs < 0 || offs >= samples[sample].len) - return RET_ERROR (EINVAL); /* Invalid offset */ - - n = samples[sample].len - offs; /* Num of bytes left */ - - if (l > n) - l = n; - - if (l > sizeof (rec->data.data8)) - l = sizeof (rec->data.data8); - - if (l <= 0) - return RET_ERROR (EINVAL); /* - * Was there a bug? - */ - - offs += sample_ptrs[sample]; /* - * Begin offsess + offset to DRAM - */ - - for (n = 0; n < l; n++) - rec->data.data8[n] = gus_peek (offs++); - rec->parm1 = n; /* - * Nr of bytes copied - */ - } - return 0; - break; - - case PM_WRITE_PATCH: /* - * Writes a block of wave data to the DRAM - */ - { - int sample = rec->parm1; - int n; - long offs = rec->parm2; - int l = rec->parm3; - - if (sample < 0 || sample >= free_sample) - return RET_ERROR (EINVAL); - - if (offs < 0 || offs >= samples[sample].len) - return RET_ERROR (EINVAL); /* - * Invalid offset - */ - - n = samples[sample].len - offs; /* - * Nr of bytes left - */ - - if (l > n) - l = n; - - if (l > sizeof (rec->data.data8)) - l = sizeof (rec->data.data8); - - if (l <= 0) - return RET_ERROR (EINVAL); /* - * Was there a bug? - */ - - offs += sample_ptrs[sample]; /* - * Begin offsess + offset to DRAM - */ - - for (n = 0; n < l; n++) - gus_poke (offs++, rec->data.data8[n]); - rec->parm1 = n; /* - * Nr of bytes copied - */ - } - return 0; - break; + /* Reset the LSFR */ + outb(PADDRESS, 0); + outb(PADDRESS, 0); - default: - return RET_ERROR (EINVAL); - } + cur = 0x6a; + outb(PADDRESS, cur); + + for (i = 1; i < 32; i++) { + cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff); + outb(PADDRESS, cur); + } } -static int -guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc) + + +int +isolation_protocol(int rd_port) { - int i, p, best = -1, best_time = 0x7fffffff; + int csn; + u_char data[9]; - p = alloc->ptr; - /* - * First look for a completely stopped voice - */ + send_Initiation_LFSR(); - for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0) - { - alloc->ptr = p; - return p; - } - if (alloc->alloc_times[p] < best_time) - { - best = p; - best_time = alloc->alloc_times[p]; + /* Reset CSN for All Cards */ + SEND(0x02, 0x04); + + for (csn = 1; (csn < MAX_CARDS); csn++) { + /* Wake up cards without a CSN */ + + SEND(WAKE, 0); + SEND(SET_RD_DATA, rd_port); + outb(PADDRESS, SERIAL_ISOLATION); + DELAY(1000); /* Delay 1 msec */ + if (get_serial(rd_port, data)) { + printf("Board Vendor ID: %c%c%c%02x%02x", + ((data[0] & 0x7c) >> 2) + 64, + (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64, + (data[1] & 0x1f) + 64, data[2], data[3]); + printf(" Board Serial Number: %08x\n", *(int *) &(data[4])); + + SEND(SET_CSN, csn); /* Move this out of this + * function XXX */ + outb(PADDRESS, PSTATUS); + + + return rd_port; + } else + break; } - p = (p + 1) % alloc->max_voice; - } - /* - * Then look for a releasing voice - */ + return 0; +} + - for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0xffff) - { - alloc->ptr = p; - return p; + +void +IwaveDelay(WORD count) +{ + WORD cur_cnt = 0, last_cnt; + BYTE reg, portb; + + count = 1193 * count; /* convert number of ms to counter */ + last_cnt = count; + portb = inb(0x61) & 0xFC; + outb(0x61, portb); /* disable counter */ + outb(0x43, 0xB0); /* load LSB first then MSB */ + outb(0x42, (BYTE) count); + outb(0x42, (BYTE) (count >> 8)); + outb(0x61, (BYTE) (portb | 0x01)); /* enable counter */ + while (cur_cnt <= count) { + outb(0x43, 0x80); /* latch counter */ + reg = inb(0x42);/* read latched value */ + cur_cnt = (((WORD) inb(0x42)) << 8) | reg; + if (cur_cnt > last_cnt) + break; + last_cnt = cur_cnt; } - p = (p + 1) % alloc->max_voice; - } + outb(0x61, portb); /* disable counter */ +} - if (best >= 0) - p = best; +/* + * ######################################################################## + * + * FUNCTION: IwaveStopDma + * + * PROFILE: This function stops an active DMA transfer to or from the record or + * playback FIFOs. Set the "path" variable to either PLAYBACK or RECORD. + * ######################################################################## + */ + +void +IwaveStopDma(BYTE path) +{ + BYTE reg; - alloc->ptr = p; - return p; + ENTER_CRITICAL; + reg = inb(iw.pcodar) & 0xE0; + outb(iw.pcodar, reg | _CFIG1I); /* select CFIG1I */ + outb(iw.cdatap, (BYTE) (inb(iw.cdatap) & ~path)); /* disable playback path */ + LEAVE_CRITICAL; } -static struct synth_operations guswave_operations = +/* + * ######################################################################## + * + * FUNCTION : IwaveInputSource + * + * PROFILE: This function allows the calling program to select among any of + * several possible sources to the ADC's. The possible input sources and + * their corresponding symbolic constants are: - Line (LINE_IN) - Aux1 + * (AUX1_IN) - Microphone (MIC_IN) - Mixer (MIX_IN) + * + * Set the first argument to either LEFT_SOURCE or RIGHT_SOURCE. Always use the + * symbolic contants for the arguments. + * + * ######################################################################## + */ +void +IwaveInputSource(BYTE index, BYTE source) { - &gus_info, - 0, - SYNTH_TYPE_SAMPLE, - SAMPLE_TYPE_GUS, - guswave_open, - guswave_close, - guswave_ioctl, - guswave_kill_note, - guswave_start_note, - guswave_set_instr, - guswave_reset, - guswave_hw_control, - guswave_load_patch, - guswave_aftertouch, - guswave_controller, - guswave_panning, - guswave_volume_method, - guswave_patchmgr, - guswave_bender, - guswave_alloc, - guswave_setup_voice -}; + BYTE reg; + + ENTER_CRITICAL; + reg = inb(iw.pcodar) & 0xE0; + outb(iw.pcodar, reg | index); /* select register CLICI or CRICI */ + reg = inb(iw.cdatap) & ~MIX_IN; + source &= MIX_IN; + outb(iw.cdatap, (BYTE) (reg | source)); + LEAVE_CRITICAL; +} +void +IwavePnpGetCfg(void) +{ + WORD val; + + + ENTER_CRITICAL; + IwavePnpDevice(AUDIO); + outb(_PIDXR, 0x60); /* select P2X0HI */ + val = ((WORD) inb(iw.pnprdp)) << 8; /* get P2XR[9:8] */ + outb(_PIDXR, 0x61); /* select P2XRLI */ + iw.p2xr = val + (WORD) inb(iw.pnprdp); /* get P2XR[7:4] */ + + outb(_PIDXR, 0x62); /* select P3X0HI */ + val = ((WORD) inb(iw.pnprdp)) << 8; /* get P3XR[9:8] */ + outb(_PIDXR, 0x63); /* select P3X0LI */ + iw.p3xr = val + (WORD) inb(iw.pnprdp); /* get P3XR[7:3] */ + + outb(_PIDXR, 0x64); /* select PHCAI */ + val = ((WORD) inb(iw.pnprdp)) << 8; /* get PCODAR[9:8] */ + outb(_PIDXR, 0x65); /* select PLCAI */ + iw.pcodar = val + (WORD) inb(iw.pnprdp); /* get PCODAR[7:2] */ + + outb(_PIDXR, 0x70); /* select PUI1SI */ + iw.synth_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* Synth IRQ number */ + + outb(_PIDXR, 0x72); /* select PUI2SI */ + iw.midi_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* MIDI IRQ number */ + + outb(_PIDXR, 0x74); /* select PUD1SI */ + iw.dma1_chan = inb(iw.pnprdp) & 0x07; /* DMA1 chan (LMC/Codec Rec) */ + + outb(_PIDXR, 0x75); /* select PUD2SI */ + iw.dma2_chan = inb(iw.pnprdp) & 0x07; /* DMA2 chan (codec play) */ + + + IwavePnpDevice(EXT); /* select external device */ + outb(_PIDXR, 0x60); /* select PRAHI */ + val = ((WORD) inb(iw.pnprdp)) << 8; /* get PCDRAR[9:8] */ + outb(_PIDXR, 0x61); /* select PRALI */ + iw.pcdrar = val + (WORD) inb(iw.pnprdp); /* get PCDRAR[7:4] */ + outb(_PIDXR, 0x62); /* select PATAHI */ + val = ((WORD) inb(iw.pnprdp)) << 8; /* get PATAAR[9:8] */ + outb(_PIDXR, 0x63); /* select PATALI */ + iw.pataar = val + (WORD) inb(iw.pnprdp); /* get PATAAR[7:1] */ + + outb(_PIDXR, 0x70); /* select PRISI */ + iw.ext_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* Ext Dev IRQ number */ + + outb(_PIDXR, 0x74); /* select PRDSI */ + iw.ext_chan = inb(iw.pnprdp) & 0x07; /* Ext Dev DMA channel */ + + IwavePnpDevice(MPU401); /* Select MPU401 Device */ + outb(_PIDXR, 0x60); /* select P401HI */ + val = ((WORD) inb(iw.pnprdp)) << 8; /* get P401AR[9:8] */ + outb(_PIDXR, 0x61); /* select P401LI */ + iw.p401ar = val + (WORD) inb(iw.pnprdp); /* get P401AR[7:1] */ + + outb(_PIDXR, 0x70); /* select PMISI */ + iw.mpu_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* MPU401 Dev IRQ number */ + + IwavePnpDevice(GAME); /* Select GAME logical Device */ + outb(_PIDXR, 0x60); /* select P201HI */ + val = ((WORD) inb(iw.pnprdp)) << 8; /* get P201AR[9:8] */ + outb(_PIDXR, 0x61); /* select P201LI */ + iw.p201ar = val + (WORD) inb(iw.pnprdp); /* get P201AR[7:6] */ + + IwavePnpDevice(EMULATION); /* Select SB and ADLIB Device */ + outb(_PIDXR, 0x60); /* select P388HI */ + val = ((WORD) inb(iw.pnprdp)) << 8; /* get P388AR[9:8] */ + outb(_PIDXR, 0x61); /* select P388LI */ + iw.p388ar = val + inb(iw.pnprdp); /* get P388AR[7:6] */ + outb(_PIDXR, 0x70); /* select PSBISI */ + iw.emul_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* emulation Dev IRQ + * number */ + LEAVE_CRITICAL; +} -static void -set_input_volumes (void) +void +IwavePnpSetCfg(void) { - unsigned long flags; - unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ + ENTER_CRITICAL; + IwavePnpDevice(AUDIO); /* select audio device */ + outb(_PIDXR, 0x60); /* select P2X0HI */ + outb(_PNPWRP, (BYTE) (iw.p2xr >> 8)); /* set P2XR[9:8] */ + outb(_PIDXR, 0x61); /* select P2X0LI */ + outb(_PNPWRP, (BYTE) iw.p2xr); /* set P2XR[7:4] */ + /* P2XR[3:0]=0 */ + outb(_PIDXR, 0x62); /* select P3X0HI */ + outb(_PNPWRP, (BYTE) (iw.p3xr >> 8)); /* set P3XR[9:8] */ + outb(_PIDXR, 0x63); /* select P3X0LI */ + outb(_PNPWRP, (BYTE) (iw.p3xr)); /* set P3XR[7:3] */ + /* P3XR[2:0]=0 */ + outb(_PIDXR, 0x64); /* select PHCAI */ + outb(_PNPWRP, (BYTE) (iw.pcodar >> 8)); /* set PCODAR[9:8] */ + outb(_PIDXR, 0x65); /* select PLCAI */ + outb(_PNPWRP, (BYTE) iw.pcodar); /* set PCODAR[7:2] */ + + outb(_PIDXR, 0x70); /* select PUI1SI */ + outb(_PNPWRP, (BYTE) (iw.synth_irq & 0x0F)); /* Synth IRQ number */ + outb(_PIDXR, 0x72); /* select PUI2SI */ + outb(_PNPWRP, (BYTE) (iw.midi_irq & 0x0F)); /* MIDI IRQ number */ + + outb(_PIDXR, 0x74); /* select PUD1SI */ + outb(_PNPWRP, (BYTE) (iw.dma1_chan & 0x07)); /* DMA channel 1 */ + outb(_PIDXR, 0x75); /* select PUD2SI */ + outb(_PNPWRP, (BYTE) (iw.dma2_chan & 0x07)); /* DMA channel 2 */ + + IwavePnpDevice(EXT); + outb(_PIDXR, 0x60); /* select PRAHI */ + outb(_PNPWRP, (BYTE) (iw.pcdrar >> 8)); /* set PCDRAR[9:8] */ + outb(_PIDXR, 0x61); /* select PRALI */ + outb(_PNPWRP, (BYTE) iw.pcdrar); /* set PCDRAR[7:3] */ + /* PCDRAR[2:0]=0 */ + outb(_PIDXR, 0x62); /* select PATAHI */ + outb(_PNPWRP, (BYTE) (iw.pataar >> 8)); /* set PATAAR[9:8] */ + outb(_PIDXR, 0x63); /* select PATALI */ + outb(_PNPWRP, (BYTE) iw.pataar); /* set PATAAR[7:1] */ + /* PATAAR[0]=0 */ + outb(_PIDXR, 0x70); /* select PRISI */ + outb(_PNPWRP, (BYTE) (iw.ext_irq & 0x0F)); /* Ext Dev IRQ number */ + outb(_PIDXR, 0x74); /* select PRDSI */ + outb(_PNPWRP, (BYTE) (iw.ext_chan & 0x07)); /* Ext Dev DMA channel */ + + IwavePnpDevice(GAME); + outb(_PIDXR, 0x60); /* select P201HI */ + outb(_PNPWRP, (BYTE) (iw.p201ar >> 8)); /* set P201RAR[9:8] */ + outb(_PIDXR, 0x61); /* select P201LI */ + outb(_PNPWRP, (BYTE) iw.p201ar); /* set P201AR[7:6] */ + + IwavePnpDevice(EMULATION); + outb(_PIDXR, 0x60); /* select P388HI */ + outb(_PNPWRP, (BYTE) (iw.p388ar >> 8)); /* set P388AR[9:8] */ + outb(_PIDXR, 0x61); /* select P388LI */ + outb(_PNPWRP, (BYTE) iw.p388ar); /* set P388AR[7:6] */ + + outb(_PIDXR, 0x70); /* select PSBISI */ + outb(_PNPWRP, (BYTE) (iw.emul_irq & 0x0F)); /* emulation IRQ number */ + + IwavePnpDevice(MPU401); + outb(_PIDXR, 0x60); /* select P401HI */ + outb(_PNPWRP, (BYTE) (iw.p401ar >> 8)); /* set P401AR[9:8] */ + outb(_PIDXR, 0x61); /* select P401LI */ + outb(_PNPWRP, (BYTE) iw.p401ar); /* set P401AR[7:1] */ + + outb(_PIDXR, 0x70); /* select PMISI */ + outb(_PNPWRP, (BYTE) (iw.mpu_irq & 0x0F)); /* MPU emulation IRQ + * number */ + LEAVE_CRITICAL; +} - DISABLE_INTR (flags); +void +IwaveCfgIOSpace(void) +{ + ENTER_CRITICAL; + IwavePnpDevice(AUDIO); /* select audio device */ + outb(_PIDXR, 0x60); /* select P2X0HI */ + outb(_PNPWRP, (BYTE) (iw.p2xr >> 8)); /* set P2XR[9:8] */ + outb(_PIDXR, 0x61); /* select P2X0LI */ + outb(_PNPWRP, (BYTE) iw.p2xr); /* set P2XR[7:4] */ + /* P2XR[3:0]=0 */ + outb(_PIDXR, 0x62); /* select P3X0HI */ + outb(_PNPWRP, (BYTE) (iw.p3xr >> 8)); /* set P3XR[9:8] */ + outb(_PIDXR, 0x63); /* select P3X0LI */ + outb(_PNPWRP, (BYTE) (iw.p3xr)); /* set P3XR[7:3] */ + /* P3XR[2:0]=0 */ + outb(_PIDXR, 0x64); /* select PHCAI */ + outb(_PNPWRP, (BYTE) (iw.pcodar >> 8)); /* set PCODAR[9:8] */ + outb(_PIDXR, 0x65); /* select PLCAI */ + outb(_PNPWRP, (BYTE) iw.pcodar); /* set PCODAR[7:2] */ + + IwavePnpDevice(EXT); + outb(_PIDXR, 0x60); /* select PRAHI */ + outb(_PNPWRP, (BYTE) (iw.pcdrar >> 8)); /* set PCDRAR[9:8] */ + outb(_PIDXR, 0x61); /* select PRALI */ + outb(_PNPWRP, (BYTE) iw.pcdrar); /* set PCDRAR[7:3] */ + /* PCDRAR[2:0]=0 */ + outb(_PIDXR, 0x62); /* select PATAHI */ + outb(_PNPWRP, (BYTE) (iw.pataar >> 8)); /* set PATAAR[9:8] */ + outb(_PIDXR, 0x63); /* select PATALI */ + outb(_PNPWRP, (BYTE) iw.pataar); /* set PATAAR[7:1] */ + /* PATAAR[0]=0 */ + IwavePnpDevice(GAME); + outb(_PIDXR, 0x60); /* select P201HI */ + outb(_PNPWRP, (BYTE) (iw.p201ar >> 8)); /* set P201RAR[9:8] */ + outb(_PIDXR, 0x61); /* select P201LI */ + outb(_PNPWRP, (BYTE) iw.p201ar); /* set P201AR[7:6] */ + + IwavePnpDevice(EMULATION); + outb(_PIDXR, 0x60); /* select P388HI */ + outb(_PNPWRP, (BYTE) (iw.p388ar >> 8)); /* set P388AR[9:8] */ + outb(_PIDXR, 0x61); /* select P388LI */ + outb(_PNPWRP, (BYTE) iw.p388ar); /* set P388AR[7:6] */ + + IwavePnpDevice(MPU401); + outb(_PIDXR, 0x60); /* select P401HI */ + outb(_PNPWRP, (BYTE) (iw.p401ar >> 8)); /* set P401AR[9:8] */ + outb(_PIDXR, 0x61); /* select P401LI */ + outb(_PNPWRP, (BYTE) iw.p401ar); /* set P401AR[7:1] */ + LEAVE_CRITICAL; +} - /* - * Enable channels having vol > 10% - * Note! bit 0x01 means line in DISABLED while 0x04 means - * mic in ENABLED. - */ - if (gus_line_vol > 10) - mask &= ~0x01; - if (gus_mic_vol > 10) - mask |= 0x04; - if (recording_active) - { - /* - * Disable channel, if not selected for recording - */ - if (!(gus_recmask & SOUND_MASK_LINE)) - mask |= 0x01; - if (!(gus_recmask & SOUND_MASK_MIC)) - mask &= ~0x04; - } +/* ######################################################################## */ +/* FILE: iwpnp.c */ +/* */ +/* REMARKS: This file contains the definitions for the InterWave's DDK */ +/* functions dedicated to the configuration of the InterWave */ +/* PNP logic. */ +/* */ +/* UPDATE: 4/07/95 */ +/* ######################################################################## */ +/* */ +/* FUNCTION: IwavePnpKey */ +/* */ +/* PROFILE: This function issues the initiation key that places the PNP */ +/* logic into configuration mode. The PNP logic is quiescent at */ +/* power up and must be enabled by software. This function will */ +/* do 32 I/O writes to the PIDXR (0x0279). The function will */ +/* first reset the LFSR to its initial value by a sequence of two */ +/* write cycles of 0x00 to PIDXR before issuing the key. */ +/* */ +/* ######################################################################## */ +void +IwavePnpKey(void) +{ + /* send_Initiation_LFSR(); */ + + BYTE code = 0x6A; + BYTE msb; + BYTE i; - mix_image &= ~0x07; - mix_image |= mask & 0x07; - OUTB (mix_image, u_Mixer); + /* ############################################### */ + /* Reset Linear Feedback Shift Reg. */ + /* ############################################### */ + outb(0x279, 0x00); + outb(0x279, 0x00); + + outb(0x279, code); /* Initial value */ + + for (i = 1; i < 32; i++) { + msb = ((code & 0x01) ^ ((code & 0x02) >> 1)) << 7; + code = (code >> 1) | msb; + outb(0x279, code); + } - RESTORE_INTR (flags); } -int -gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) +BYTE +IwavePnpIsol(PORT * pnpread) { -#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \ - SOUND_MASK_SYNTH|SOUND_MASK_PCM) - if (((cmd >> 8) & 0xff) == 'M') - { - if (cmd & IOC_IN) - switch (cmd & 0xff) - { - case SOUND_MIXER_RECSRC: - gus_recmask = IOCTL_IN (arg) & MIX_DEVS; - if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) - gus_recmask = SOUND_MASK_MIC; - /* Note! Input volumes are updated during next open for recording */ - return IOCTL_OUT (arg, gus_recmask); - break; + int num_pnp_devs; + int rd_port = 0; + printf("Checking for GUS Plug-n-Play ...\n"); + + /* Try various READ_DATA ports from 0x203-0x3ff */ + for (rd_port = 0x80; (rd_port < 0xff); rd_port += 0x10) { + if (0) + printf("Trying Read_Port at %x\n", + (rd_port << 2) | 0x3); + + num_pnp_devs = isolation_protocol(rd_port); + if (num_pnp_devs) { + *pnpread = rd_port << 2 | 0x3; + break; + } + } + if (!num_pnp_devs) { + printf("No Plug-n-Play devices were found\n"); + return 0; + } + return 1; +} - case SOUND_MIXER_MIC: - { - int vol = IOCTL_IN (arg) & 0xff; - - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - gus_mic_vol = vol; - set_input_volumes (); - return IOCTL_OUT (arg, vol | (vol << 8)); - } - break; +/* ######################################################################## */ +/* */ +/* FUNCTION: IwavePnpSerial */ +/* */ +/* PROFILE: This function reads the first nine bytes of the data from */ +/* the serial EEPROM and returns the Vendor ID and the serial */ +/* number. First, it resets the EEPROM control logic by */ +/* issuing a WAKE[CSN] command. The function will return an */ +/* ASCII string for the vendor ID into the char array pointed */ +/* to by "vendor" in the VVVNNNN format. The serial number */ +/* is placed in the 32-bit variable pointed to by "serial". */ +/* Note that the 9th byte is read but not used as it is invalid */ +/* when the serial identifier is read via PRESDI. */ +/* */ +/* This function assumes that the PNP state machine is not in */ +/* the "wait for key state". Otherwise, unpredictable results */ +/* will be obtained. */ +/* */ +/* ######################################################################## */ +void +IwavePnpSerial(PORT pnprdp, + BYTE csn, + BYTE * vendor, + DWORD * serial) +{ + BYTE presdi, digit, i; + + *serial = 0L; + + /* ####################################### */ + /* Reset Serial EEPROM logic */ + /* ####################################### */ + IwavePnpWake(csn); /* Wake card up */ + + for (i = 1; i <= 4; i++) { + IwavePnpPeek(pnprdp, 1, &presdi); + + switch (i) { + case 1: + *(vendor++) = ((presdi & 0x7C) >> 2) | 0x40; /* 1st char */ + *vendor = (presdi & 0x03) << 3; /* isolate bits[4:3] of + * 2nd char */ + break; + case 2: + *vendor = ((presdi & 0xE0) >> 5) | (*vendor); + *(vendor++) = (*vendor) | 0x40; /* 2nd char */ + *vendor = (presdi & 0x1F) | 0x40; /* 3rd char */ + break; + case 3: + case 4: + digit = (presdi & 0xF0) >> 4; + if (digit <= 0x09) + *(++vendor) = digit + 0x30; /* ASCII of digit */ + else + *(++vendor) = (digit & 0x07) + 0x3F; + digit = presdi & 0x0F; + if (digit <= 0x09) + *(++vendor) = digit + 0x30; + else + *(++vendor) = (digit & 0x07) + 0x3F; + break; + } + } + *(++vendor) = '\0'; + IwavePnpPeek(pnprdp, 4, (BYTE *) serial); + IwavePnpPeek(pnprdp, 1, NULL); /* discard checksum */ +} +/* ######################################################################## */ +/* */ +/* FUNCTION: IwavePnpPeek */ +/* */ +/* PROFILE: This function will return the number of specified bytes of */ +/* resource data from the serial EEPROM. The function will NOT */ +/* reset the serial EEPROM logic to allow reading the entire */ +/* EEPROM by issuing repeated calls. The caller must supply a */ +/* pointer to where the data are to be stored. */ +/* It is assumed that the InterWave is not in either "sleep" */ +/* or "wait for key" states. Note that on the first call, if */ +/* the caller means to read from the beggining of data the */ +/* serial EEPROM logic must be reset. For this, the caller */ +/* should issue a WAKE[CSN] command */ +/* */ +/* ######################################################################## */ +void +IwavePnpPeek(PORT pnprdp, WORD bytes, BYTE * data) +{ + WORD i; + BYTE datum; + + for (i = 1; i <= bytes; i++) { + outb(_PIDXR, 0x05); /* select PRESSI */ + + while (TRUE) { /* wait til new data byte is ready */ + if (inb(pnprdp) & PNP_DATA_RDY) + break; /* new resource byte ready */ + } + outb(_PIDXR, 0x04); /* select PRESDI */ + datum = inb(pnprdp); /* read resource byte */ + if (data != NULL) + *(data++) = datum; /* store it */ + } +} +/* ######################################################################## */ +/* */ +/* FUNCTION: IwavePnpEeprom */ +/* */ +/* PROFILE: This function allows the caller to control the serial */ +/* EEPROM directly while the audio device is inactive. To */ +/* de-activate the audio device issue the call */ +/* IwavePnpActivate(AUDIO,OFF). */ +/* */ +/* ######################################################################## */ +void +IwavePnpEeprom(BYTE ctrl) +{ + ENTER_CRITICAL; + outb(_PIDXR, 0xF1); /* select PSECI */ + outb(_PNPWRP, ctrl); /* write PSECI */ + LEAVE_CRITICAL; +} +/* ######################################################################## */ +/* */ +/* FUNCTION: IwavePnpActivate */ +/* */ +/* PROFILE: This function will activate or de-activate the audio device */ +/* or the external device on the InterWave. Set the "dev" arg */ +/* to AUDIO for the audio device or EXT for the external device. */ +/* Set "bool" to ON or OFF to turn the device on or off the ISA */ +/* bus. Notice that for a logical device to work, it must be */ +/* activated. */ +/* */ +/* ######################################################################## */ +void +IwavePnpActivate(BYTE dev, BYTE bool) +{ + IwavePnpDevice(dev); /* select audio device */ + ENTER_CRITICAL; + outb(_PIDXR, ACTIVATE_DEV); /* select Activate Register */ + outb(_PNPWRP, bool); /* write register */ + LEAVE_CRITICAL; - case SOUND_MIXER_LINE: - { - int vol = IOCTL_IN (arg) & 0xff; - - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - gus_line_vol = vol; - set_input_volumes (); - return IOCTL_OUT (arg, vol | (vol << 8)); - } - break; +} +/* ######################################################################## */ +/* */ +/* FUNCTION: IwavePnpDevice */ +/* */ +/* PROFILE: This function allows the caller to select between five */ +/* logical devices available on the InterWave.It is assumed */ +/* that the PNP state machine is in configuration mode. */ +/* */ +/* ######################################################################## */ +void +IwavePnpDevice(BYTE dev) +{ + ENTER_CRITICAL; + outb(_PIDXR, _PLDNI); /* select PLDNI */ + outb(_PNPWRP, dev); /* write PLDNI */ + LEAVE_CRITICAL; +} +/* ######################################################################## */ +/* */ +/* FUNCTION: IwavePnpPower */ +/* */ +/* PROFILE: This function allows the caller to disable major sections of */ +/* the InterWave to prevent them from consuming power and */ +/* loading the ISA bus. */ +/* */ +/* It is assumed that the PNP state machine is in configuration */ +/* mode. */ +/* */ +/* ######################################################################## */ +void +IwavePnpPower(BYTE mode) +{ + ENTER_CRITICAL; + outb(_PIDXR, _PPWRI); /* select PPWRI */ + outb(_PNPWRP, mode); /* write PPWRI */ + LEAVE_CRITICAL; +} +/* ######################################################################## */ +/* */ +/* FUNCTION: IwavePnpWake */ +/* */ +/* PROFILE: This function issues a WAKE[CSN] command to the InterWave. If */ +/* the CSN matches the PNP state machine will enter the */ +/* configuration state. Otherwise it will enter the sleep mode. */ +/* */ +/* It is assumed that the PNP state machine is not in the */ +/* "wait for key" state. */ +/* */ +/* ######################################################################## */ +void +IwavePnpWake(BYTE csn) +{ + ENTER_CRITICAL; + outb(_PIDXR, _PWAKEI); /* select PWAKEI */ + outb(_PNPWRP, csn); /* write csn */ + LEAVE_CRITICAL; +} +/* ######################################################################## */ +/* */ +/* FUNCTION: IwavePnpIOcheck */ +/* */ +/* PROFILE: This function allows the caller to perform a conflict check */ +/* on an I/O port to be used by a logical device. The function */ +/* receives the base address of the I/O range as well as the */ +/* number of ports in the range and then performs the I/O check */ +/* protocol. It returns the address of the port if a conflict */ +/* is detected or IO_CHK if no conflict is detected. */ +/* */ +/* This function assumes that the logical device has been de- */ +/* activated and that the PNP state machine is in config mode. */ +/* */ +/* ######################################################################## */ +PORT +IwavePnpIOcheck(PORT base, BYTE no_ports) +{ + BYTE i; + PORT portid; - case SOUND_MIXER_PCM: - gus_pcm_volume = IOCTL_IN (arg) & 0xff; - if (gus_pcm_volume < 0) - gus_pcm_volume = 0; - if (gus_pcm_volume > 100) - gus_pcm_volume = 100; - gus_sampling_update_volume (); - return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8)); - break; + outb(_PIDXR, RANGE_IOCHK); /* select IO range check reg */ - case SOUND_MIXER_SYNTH: - { - int voice; + for (i = 0; i < no_ports; i++) { + portid = base + i; /* port to check */ + outb(_PNPWRP, 0x02); /* must drive 0xAA onto bus */ + if (inb(portid) != 0xAA) + return (portid); /* IO conflict detected */ - gus_wave_volume = IOCTL_IN (arg) & 0xff; + outb(_PNPWRP, 0x03); /* must drive 0x55 onto bus */ + if (inb(portid) != 0x55) + return (portid); /* IO conflict detected */ + } + return (IO_OK); +} +/* ######################################################################## */ +/* */ +/* FUNCTION: IwavePnpGetCSN */ +/* */ +/* PROFILE: This function allows the caller to detect an InterWave based */ +/* adapter board and will return its asigned CSN so that an */ +/* an application can access its PnP interface and determine the */ +/* borad's current configuration. In conducting its search for */ +/* the InterWave IC, the function will use the first 32 bits of */ +/* the Serial Identifier called the vendor ID in the PnP ISA */ +/* spec. The last 4 bits in the Vendor ID represent a revision */ +/* number for the particular product and this function gives the */ +/* caller the option of taking this revision number into account */ +/* or not in the search. If the function fails to find the */ +/* InterWave IC it will return FALSE. */ +/* */ +/* ######################################################################## */ +BYTE +IwavePnpGetCSN(DWORD VendorID, BYTE csn_max) +{ + BYTE csn; + DWORD vendor; + + IwavePnpKey(); /* Key to access PnP Interface */ + VendorID &= (0xFFFFFFF0); /* reset 4 least significant bits */ + + for (csn = 1; csn <= csn_max; csn++) { + IwavePnpWake(csn); /* Select card */ + IwavePnpPeek(iw.pnprdp, 4, (BYTE *) & vendor); /* get vendor ID */ + vendor &= (0xFFFFFFF0); + if (vendor == VendorID) { /* If IDs match, InterWave is + * found */ + outb(_PIDXR, 0x02); /* Place all cards in + * wait-for-key state */ + outb(0x0A79, 0x02); + return (csn); + } + } + outb(_PIDXR, 0x02); /* Place all cards in wait-for-key state */ + outb(0x0A79, 0x02); + return (FALSE); /* InterWave IC not found */ +} +/* ######################################################################## */ +/* */ +/* + * FUNCTION: IwavePnpPing + */ +/* */ +/* PROFILE: This function allows the caller to detect an InterWave based */ +/* adapter board and will return its asigned CSN so that an */ +/* an application can access its PnP interface and determine the */ +/* borad's current configuration. In conducting its search for */ +/* the InterWave IC, the function will use the first 32 bits of */ +/* the Serial Identifier called the vendor ID in the PnP ISA */ +/* spec. The last 4 bits in the Vendor ID represent a revision */ +/* number for the particular product and will not be included */ +/* in the search. The function will return the Vendor ID and the */ +/* calling application should check the revision bits to make */ +/* sure they are compatible with the board. */ +/* */ +/* ######################################################################## */ +BYTE +IwavePnpPing(DWORD VendorID) +{ + BYTE csn; + + VendorID &= (0xFFFFFFF0); /* reset 4 least significant bits */ + IwavePnpKey(); /* Key to access PnP Interface */ + while (iw.pnprdp <= 0x23F) { + for (csn = 1; csn <= 10; csn++) { + IwavePnpWake(csn); /* Select card */ + IwavePnpPeek(iw.pnprdp, 4, (BYTE *) & iw.vendor); /* get vendor ID */ + + + if (((iw.vendor) & 0xFFFFFFF0) == VendorID) { /* If IDs match, + * InterWave is found */ + + outb(_PIDXR, 0x02); /* Place all cards in + * wait-for-key state */ + outb(0x0A79, 0x02); + return (csn); + } + } + iw.pnprdp += 0x04; + } + outb(_PIDXR, 0x02); /* Place all cards in wait-for-key state */ + outb(0x0A79, 0x02); + return (FALSE); /* InterWave IC not found */ +} - if (gus_wave_volume < 0) - gus_wave_volume = 0; - if (gus_wave_volume > 100) - gus_wave_volume = 100; +/* end of pnp code */ - if (active_device == GUS_DEV_WAVE) - for (voice = 0; voice < nr_voices; voice++) - dynamic_volume_change (voice); /* Apply the new vol */ +WORD +IwaveMemSize(void) +{ + BYTE datum = 0x55; + ADDRESS local = 0L; + + outb(iw.igidxr, _LMCI); + outb(iw.i8dp, inb(iw.i8dp) & 0xFD); /* DRAM I/O cycles selected */ + + while (TRUE) { + IwaveMemPoke(local, datum); + IwaveMemPoke(local + 1L, datum + 1); + if (IwaveMemPeek(local) != datum || IwaveMemPeek(local + 1L) != (datum + 1) || IwaveMemPeek(0L) != 0x55) + break; + local += RAM_STEP; + datum++; + } + return ((WORD) (local >> 10)); +} - return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8)); - } - break; +BYTE +IwaveMemPeek(ADDRESS addr) +{ + PORT p3xr; - default: - return RET_ERROR (EINVAL); - } - else - switch (cmd & 0xff) /* - * Return parameters - */ - { - - case SOUND_MIXER_RECSRC: - return IOCTL_OUT (arg, gus_recmask); - break; + p3xr = iw.p3xr; - case SOUND_MIXER_DEVMASK: - return IOCTL_OUT (arg, MIX_DEVS); - break; - case SOUND_MIXER_STEREODEVS: - return IOCTL_OUT (arg, 0); - break; + outb(iw.igidxr, 0x43); /* Select LMALI */ + outw(iw.i16dp, (WORD) addr); /* Lower 16 bits of LM */ + outb(iw.igidxr, 0x44); /* Select LMAHI */ + outb(iw.i8dp, (BYTE) (addr >> 16)); /* Upper 8 bits of LM */ + return (inb(iw.lmbdr)); /* return byte from LMBDR */ +} - case SOUND_MIXER_RECMASK: - return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE); - break; - case SOUND_MIXER_CAPS: - return IOCTL_OUT (arg, 0); - break; +void +IwaveMemPoke(ADDRESS addr, BYTE datum) +{ + PORT p3xr; + p3xr = iw.p3xr; - case SOUND_MIXER_MIC: - return IOCTL_OUT (arg, gus_mic_vol | (gus_mic_vol << 8)); - break; - case SOUND_MIXER_LINE: - return IOCTL_OUT (arg, gus_line_vol | (gus_line_vol << 8)); - break; + outb(iw.igidxr, 0x43); /* Select LMALI */ + outw(iw.i16dp, (WORD) addr); /* Lower 16 bits of LM */ + outb(iw.igidxr, 0x44); /* Select LMAHI */ + outb(iw.i8dp, (BYTE) (addr >> 16)); /* Upper 8 bits of LM */ + outb(iw.lmbdr, datum); /* Write byte to LMBDR */ +} - case SOUND_MIXER_PCM: - return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8)); - break; +/* ######################################################################## */ +/* */ +/* FUNCTION: IwaveMemCfg */ +/* */ +/* PROFILE : This function determines the amount of DRAM from its */ +/* configuration accross all banks. It sets the configuration */ +/* into register LMCFI and stores the total amount of DRAM */ +/* into iw.size_mem (Kbytes). */ +/* */ +/* The function first places the IC in enhanced mode to allow */ +/* full access to all DRAM locations. Then it selects full */ +/* addressing span (LMCFI[3:0]=0x0C). Finally, it determines */ +/* the amount of DRAM in each bank and from this the actual */ +/* configuration. */ +/* */ +/* Note that if a configuration other than one indicated in */ +/* the manual is implemented, this function will select */ +/* full addressing span (LMCFI[3:0]=0xC). */ +/* */ +/* ######################################################################## */ +void +IwaveMemCfg(DWORD * lpbanks) +{ + DWORD bank[4] = {0L, 0L, 0L, 0L}; + DWORD addr = 0L, base = 0L, cnt = 0L; + BYTE i, reg, ram = FALSE; + WORD lmcfi; + /* */ + ENTER_CRITICAL; + outb(iw.igidxr, 0x99); + reg = inb(iw.i8dp); /* image of sgmi */ + outb(iw.igidxr, 0x19); + outb(iw.i8dp, (BYTE) (reg | 0x01)); /* enable enhaced mode */ + outb(iw.igidxr, _LMCFI);/* select LM Conf Reg */ + lmcfi = inw(iw.i16dp) & 0xFFF0; + outw(iw.i16dp, lmcfi | 0x000C); /* max addr span */ + /* */ + /* Clear every RAM_STEPth location */ + /* */ + while (addr < RAM_MAX) { + IwaveMemPoke(addr, 0x00); + addr += RAM_STEP; + } + /* */ + /* Determine amount of RAM in each bank */ + /* */ + for (i = 0; i < 4; i++) { + IwaveMemPoke(base, 0xAA); /* mark start of bank */ + IwaveMemPoke(base + 1L, 0x55); + if ((IwaveMemPeek(base) == 0xAA) && (IwaveMemPeek(base + 1L) == 0x55)) + ram = TRUE; + if (ram) { + while (cnt < BANK_MAX) { + bank[i] += RAM_STEP; + cnt += RAM_STEP; + addr = base + cnt; + if (IwaveMemPeek(addr) == 0xAA) + break; + } + } + if (lpbanks != NULL) { + *lpbanks = bank[i]; + lpbanks++; + } + bank[i] = bank[i] >> 10; + base += BANK_MAX; + cnt = 0L; + ram = FALSE; + } + /* */ + iw.flags &= ~DRAM_HOLES; + outb(iw.igidxr, _LMCFI); + if (bank[0] == 256 && bank[1] == 0 && bank[2] == 0 && bank[3] == 0) + outw(iw.i16dp, lmcfi); + else if (bank[0] == 256 && bank[1] == 256 && bank[2] == 0 && bank[3] == 0) + outw(iw.i16dp, lmcfi | 0x01); + else if (bank[0] == 256 && bank[1] == 256 && bank[2] == 256 && bank[3] == 256) + outw(iw.i16dp, lmcfi | 0x02); + else if (bank[0] == 256 && bank[1] == 1024 && bank[2] == 0 && bank[3] == 0) + outw(iw.i16dp, lmcfi | 0x03); + else if (bank[0] == 256 && bank[1] == 1024 && bank[2] == 1024 && bank[3] == 1024) + outw(iw.i16dp, lmcfi | 0x04); + else if (bank[0] == 256 && bank[1] == 256 && bank[2] == 1024 && bank[3] == 0) + outw(iw.i16dp, lmcfi | 0x05); + else if (bank[0] == 256 && bank[1] == 256 && bank[2] == 1024 && bank[3] == 1024) + outw(iw.i16dp, lmcfi | 0x06); + else if (bank[0] == 1024 && bank[1] == 0 && bank[2] == 0 && bank[3] == 0) + outw(iw.i16dp, lmcfi | 0x07); + else if (bank[0] == 1024 && bank[1] == 1024 && bank[2] == 0 && bank[3] == 0) + outw(iw.i16dp, lmcfi | 0x08); + else if (bank[0] == 1024 && bank[1] == 1024 && bank[2] == 1024 && bank[3] == 1024) + outw(iw.i16dp, lmcfi | 0x09); + else if (bank[0] == 4096 && bank[1] == 0 && bank[2] == 0 && bank[3] == 0) + outw(iw.i16dp, lmcfi | 0x0A); + else if (bank[0] == 4096 && bank[1] == 4096 && bank[2] == 0 && bank[3] == 0) + outw(iw.i16dp, lmcfi | 0x0B); + else /* Flag the non-contiguous config of memory */ + iw.flags |= DRAM_HOLES; + /* */ + outb(iw.igidxr, 0x19); /* restore sgmi */ + outb(iw.i8dp, reg); + LEAVE_CRITICAL; +} - case SOUND_MIXER_SYNTH: - return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8)); - break; - default: - return RET_ERROR (EINVAL); - } - } - else - return RET_ERROR (EINVAL); +/* ######################################################################## */ +/**/ +/* FUNCTION: IwaveCodecIrq */ +/**/ +/* PROFILE: This function disables or enables the Codec Interrupts. To */ +/* enable interrupts set CEXTI[2] high thus causing all interrupt */ +/* sources (CSR3I[6:4]) to pass onto the IRQ pin. To disable */ +/* interrupts set CEXTI[1]=0. To enable Code IRQs issue this call: */ +/**/ +/* IwaveCodecIrq(CODEC_IRQ_ENABLE). To disable IRQs issue the call */ +/**/ +/* IwaveCodeIrq(~CODEC_IRQ_ENABLE). */ +/**/ +/* ######################################################################## */ +void +IwaveCodecIrq(BYTE mode) +{ + BYTE reg; + + ENTER_CRITICAL; + reg = inb(iw.pcodar) & 0xE0; + outb(iw.pcodar, reg | _CSR3I); /* select CSR3I */ + outb(iw.cdatap, 0x00); /* clear all interrupts */ + outb(iw.pcodar + 0x02, 0x00); /* clear CSR1R */ + outb(iw.pcodar, reg | _CEXTI); /* select CEXTI */ + reg = inb(iw.cdatap); + if (mode == CODEC_IRQ_ENABLE) /* enable Codec Irqs */ + outb(iw.cdatap, (BYTE) (reg | CODEC_IRQ_ENABLE)); + else /* disable Codec Irqs */ + outb(iw.cdatap, (BYTE) (reg & ~CODEC_IRQ_ENABLE)); + LEAVE_CRITICAL; } -static struct mixer_operations gus_mixer_operations = + +/* ######################################################################### */ +/**/ +/* FUNCTION: IwaveRegPeek */ +/**/ +/* PROFILE : This function returns the value stored in any readable */ +/* InterWave register. It takes as input a pointer to a */ +/* structure containing the addresses of the relocatable I/O */ +/* space as well as a register mnemonic. To correctly use this */ +/* function, the programmer must use the mnemonics defined in */ +/* "iwdefs.h". These mnemonics contain coded information used */ +/* by the function to properly access the desired register. */ +/**/ +/* An attempt to read from a write-only register will return */ +/* meaningless data. */ +/**/ +/* ######################################################################### */ +WORD +IwaveRegPeek(DWORD reg_mnem) { - "Gravis Ultrasound", - gus_default_mixer_ioctl -}; + BYTE index, val; + WORD reg_id, offset; + + offset = (WORD) ((BYTE) reg_mnem); + reg_id = (WORD) (reg_mnem >> 16); + index = (BYTE) (reg_mnem >> 8); + + /* ################################################### */ + /* Logic to read registers in P2XR block & GMCR */ + /* ################################################### */ + + if (reg_id >= 0x0001 && reg_id <= 0x001A) { /* UMCR to GMCR */ + if (reg_id <= 0x000E) /* UMCR to USRR */ + return ((WORD) inb(iw.p2xr + offset)); + + if (reg_id == 0x0019) + return ((WORD) inb(iw.p201ar)); + + else { /* GUS Hidden registers or GMCR */ + BYTE iveri; + + outb(iw.igidxr, 0x5B); /* select IVERI */ + iveri = inb(iw.i8dp); /* read IVERI */ + outb(iw.i8dp, (BYTE) (iveri | 0x09)); /* set IVERI[3,0] */ + if (reg_id == 0x001A) { /* GMCR */ + val = inb(iw.p3xr); + outb(iw.i8dp, iveri); /* restore IVERI */ + return ((WORD) val); + } + val = inb(iw.p2xr + 0x0F); /* read URCR */ + val = (val & 0xF8) | index; /* value for URCR[2:0] */ + outb(iw.p2xr + 0x0F, val); /* set URCR[2:0] */ + + if (reg_mnem == UDCI || reg_mnem == UICI) { + val = inb(iw.p2xr); + if (reg_mnem == UDCI) + outb(iw.p2xr, (BYTE) (val & 0xBF)); + else + outb(iw.p2xr, (BYTE) (val | 0x40)); + } + val = inb(iw.p2xr + 0x0B); + outb(iw.igidxr, 0x5B); /* select IVERI */ + outb(iw.i8dp, iveri); /* restore IVERI */ + return ((WORD) val); /* read register */ + } + } + /* ################################################### */ + /* Logic to read registers in P3XR block */ + /* ################################################### */ + + if (reg_id >= 0x001B && reg_id <= 0x005C) { /* GMSR to LMBDR */ + if (reg_id == 0x005C) /* LMBDR */ + return ((WORD) inb(iw.lmbdr)); + + if (reg_id >= 0x001B && reg_id <= 0x0021) /* GMSR to I8DP */ + if (offset == 0x04) + return (inw(iw.i16dp)); + else + return ((WORD) inb(iw.p3xr + offset)); + else { /* indexed registers */ + + if (reg_id <= 0x003F) + index |= 0x80; /* adjust for reading */ + + outb(iw.igidxr, index); /* select register */ + + if (offset == 0x04) + return (inw(iw.i16dp)); + else + return ((WORD) inb(iw.i8dp)); + } + } + /* #################################################### */ + /* Logic to read registers in PCODAR block */ + /* #################################################### */ + + if (reg_id >= 0x005D && reg_id <= 0x0081) { /* CIDXR to CLRCTI */ + if (reg_id <= 0x0061) + return ((WORD) inb(iw.pcodar + offset)); /* CRDR */ + + else { /* indexed registers */ + BYTE cidxr; + + cidxr = inb(iw.pcodar); + cidxr = (cidxr & 0xE0) + index; + outb(iw.pcodar, cidxr); /* select register */ + return ((WORD) inb(iw.cdatap)); + } + } + /* ##################################################### */ + /* Logic to read the PnP registers */ + /* ##################################################### */ + if (reg_id >= 0x0082 && reg_id <= 0x00B7) { /* PCSNBR to PMITI */ + if (reg_id == 0x0085) + return ((WORD) inb(iw.pnprdp)); + + if (reg_id < 0x0085) + return ((WORD) inb((WORD) reg_mnem)); + + else { /* indexed registers */ + if (reg_id >= 0x008E && reg_id <= 0x00B7) { + outb(0x0279, 0x07); /* select PLDNI */ + outb(0xA79, (BYTE) offset); /* select logical dev */ + } + outb(0x0279, index); /* select the register */ + return ((WORD) inb(iw.pnprdp)); + } + } + return 0; +} +/* ######################################################################### */ +/**/ +/* FUNCTION: IwaveRegPoke */ +/**/ +/* PROFILE : This function writes a value to any writable */ +/* InterWave register. It takes as input a pointer to a */ +/* structure containing the addresses of the relocatable I/O */ +/* space as well as a register mnemonic. To correctly use this */ +/* function, the programmer must use the mnemonics defined in */ +/* "iwdefs.h". These mnemonics contain coded information used */ +/* by the function to properly access the desired register. */ +/**/ +/* This function does not guard against writing to read-only */ +/* registers. It is the programmer's responsibility to ensure */ +/* that the writes are to valid registers. */ +/**/ +/* ######################################################################### */ +void +IwaveRegPoke(DWORD reg_mnem, WORD datum) +{ + BYTE index; + BYTE val; + WORD reg_id; + WORD offset; + + offset = (WORD) ((BYTE) reg_mnem); + reg_id = (WORD) (reg_mnem >> 16); + index = (BYTE) (reg_mnem >> 8); + + + /* ####################################################### */ + /* Logic to write to registers in P2XR block */ + /* ####################################################### */ + if (reg_id >= 0x0001 && reg_id <= 0x0019) { /* UMCR to GGCR */ + if (reg_id <= 0x000E) { /* UMCR to USRR */ + outb(iw.p2xr + offset, (BYTE) datum); + return; + } + if (reg_id == 0x0019) { + outb(iw.p201ar, (BYTE) datum); + return; + } else { /* GUS Hidden registers */ + + BYTE iveri; + + outb(iw.igidxr, 0x5B); /* select IVERI */ + iveri = inb(iw.i8dp); /* read IVERI */ + outb(iw.i8dp, (BYTE) (iveri | 0x09)); /* set IVERI[3,0] */ + val = inb(iw.p2xr + 0x0F); /* read URCR */ + val = (val & 0xF8) | index; /* value for URCR[2:0] */ + outb(iw.p2xr + 0x0F, val); /* set URCR[2:0] */ + + if (reg_mnem == UDCI || reg_mnem == UICI) { + val = inb(iw.p2xr); /* read UMCR */ + if (reg_mnem == UDCI) + outb(iw.p2xr, (BYTE) (val & 0xBF)); /* set UMCR[6]=0 */ + else + outb(iw.p2xr, (BYTE) (val | 0x40)); /* set UMCR[6]=1 */ + } + outb(iw.p2xr + 0x0B, (BYTE) datum); /* write register */ + outb(iw.igidxr, 0x5B); /* select IVERI */ + outb(iw.i8dp, iveri); /* restore IVERI */ + return; + } + } + /* ############################################################# */ + /* Logic to write to registers in P3XR block */ + /* ############################################################# */ + + if (reg_id >= 0x001A && reg_id <= 0x005C) { /* GMCR to LMBDR */ + + if (reg_id == 0x005C) { /* LMBDR */ + outb(iw.lmbdr, (BYTE) datum); + return; + } + if (reg_id == 0x001B) /* GMSR */ + return; + + if (reg_id >= 0x001A && reg_id <= 0x0021) /* GMCR to I8DP */ + if (offset == 0x04) + outw(iw.i16dp, datum); + else + outb(iw.p3xr + offset, (BYTE) datum); + else { /* indexed registers */ + outb(iw.igidxr, index); /* select register */ + + if (offset == 0x04) + outw(iw.i16dp, datum); + else + outb(iw.i8dp, (BYTE) datum); + } + } + /* /################################################### */ + /* Logic to write to registers in PCODAR block */ + /* ################################################### */ + + if (reg_id >= 0x005C && reg_id <= 0x0081) { /* CIDXR to CLRCTI */ + if (reg_id <= 0x0061) + outb(iw.pcodar + offset, (BYTE) datum); + + else { /* one of the indexed registers */ + BYTE cidxr; + + cidxr = inb(iw.pcodar); + cidxr = (cidxr & 0xE0) + index; + outb(iw.pcodar, cidxr); /* select register */ + outb(iw.cdatap, (BYTE) datum); + } + } + /* ###################################################### */ + /* Logic to write to the PnP registers */ + /* ###################################################### */ + if (reg_id >= 0x0082 && reg_id <= 0x00B7) { + if (reg_id == 0x0085) { + outb(iw.pnprdp, (BYTE) datum); + return; + } + if (reg_id < 0x0085) + outb((WORD) reg_mnem, (BYTE) datum); + + else { /* one of the indexed registers */ + if (reg_id >= 0x008E && reg_id <= 0x00B7) { + outb(0x0279, 0x07); /* select PLDNI */ + outb(0xA79, (BYTE) offset); /* select logical dev */ + } + outb(0x0279, index); /* select the register */ + outb(0xA79, (BYTE) datum); + } + } +} -static long -gus_default_mixer_init (long mem_start) + +void +IwaveLineLevel(char level, char index) { - if (num_mixers < MAX_MIXER_DEV) /* - * Don't install if there is another - * mixer - */ - mixer_devs[num_mixers++] = &gus_mixer_operations; + char reg; - return mem_start; + level &= 0x1F; + + ENTER_CRITICAL; + reg = inb(iw.pcodar) & 0xE0; + outb(iw.pcodar, reg | index); /* select register */ + outb(iw.cdatap, (BYTE) ((inb(iw.cdatap) & 0x80) | level)); /* set level */ + LEAVE_CRITICAL; } -long -gus_wave_init (long mem_start, int irq, int dma, int dma_read) +void +IwaveCodecMode(char mode) { - unsigned long flags; - unsigned char val; - char *model_num = "2.4"; - int gus_type = 0x24; /* 2.4 */ - int mixer_type = 0; + char reg; + + ENTER_CRITICAL; + reg = inb(iw.pcodar) & 0xE0; + outb(iw.pcodar, reg | _CMODEI); /* select CMODEI */ + outb(iw.cdatap, mode); + LEAVE_CRITICAL; + iw.cmode = mode; +} - if (irq < 0 || irq > 15) - { - printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq); - return mem_start; - } +void +IwaveLineMute(BYTE mute, BYTE inx) +{ + BYTE reg; - if (dma < 0 || dma > 7) - { - printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma); - return mem_start; - } + ENTER_CRITICAL; + reg = inb(iw.pcodar) & 0xE0; + outb(iw.pcodar, reg | inx); /* select register */ + if (mute == ON) + outb(iw.cdatap, (BYTE) (inb(iw.cdatap) | 0x80)); /* mute */ + else + outb(iw.cdatap, (BYTE) (inb(iw.cdatap) & 0x7F)); /* unmute */ + LEAVE_CRITICAL; +} - if (dma_read == 0) dma_read = dma; - if (dma_read < 0 || dma_read > 7) - { - printk ("ERROR! Invalid DMA#%d. GUS DMA-read disabled", dma_read); - dma_read = dma; - } - /* - * Try to identify the GUS model. - * - * Versions < 3.6 don't have the digital ASIC. Try to probe it first. - */ +void +Iwaveinitcodec() +{ - DISABLE_INTR (flags); - OUTB (0x20, gus_base + 0x0f); - val = INB (gus_base + 0x0f); - RESTORE_INTR (flags); + u_short iwl_codec_base = iw.pcodar; + u_short iwl_codec_data = iw.pcodar + 1; + u_short foo; - if (val != 0xff && (val & 0x06)) /* Should be 0x02?? */ - { - /* - * It has the digital ASIC so the card is at least v3.4. - * Next try to detect the true model. - */ - - val = INB (u_MixSelect); - - /* - * Value 255 means pre-3.7 which don't have mixer. - * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer. - * 10 and above is GUS MAX which has the CS4231 codec/mixer. - * - * Sorry. No GUS max support yet but it should be available - * soon after the SDK for GUS MAX is available. - */ - - if (val == 255 || val < 5) - { - model_num = "3.4"; - gus_type = 0x34; - } - else if (val < 10) - { - model_num = "3.7"; - gus_type = 0x37; - mixer_type = ICS2101; - } - else - { - model_num = "MAX"; - gus_type = 0x40; - mixer_type = CS4231; + + + /* + * Set the CEXTI register foo = CODEC_CEXTI_DEFAULT; + * IWL_CODEC_OUT(EXTERNAL_CONTROL, foo); + */ + /* + * Disable Interrupts iwl_codec_disable_irqs(); + */ + + /* Set the CODEC to Operate in Mode 3 */ + IWL_CODEC_OUT(MODE_SELECT_ID, 0x6C); + foo = inb(iwl_codec_data); + + /* Set the configuration registers to their default values */ + foo = CODEC_CFIG1I_DEFAULT; + IWL_CODEC_OUT(CONFIG_1 | CODEC_MCE, foo); + outb(iwl_codec_base, CONFIG_1); + foo = CODEC_CFIG2I_DEFAULT; + IWL_CODEC_OUT(CONFIG_2, foo); + + foo = CODEC_CFIG3I_DEFAULT; + IWL_CODEC_OUT(CONFIG_3, foo); + +} + + + +int +IwaveOpen(char voices, char mode, struct address_info * hw) +{ + + u_long flags; + u_char tmp; + + flags = splhigh(); + + iw.pnprdp = 0; + if (IwavePnpIsol(&iw.pnprdp)) { + + iw.vendor = GUS_PNP_ID; + + iw.csn = IwavePnpPing(iw.vendor); + + IwavePnpKey(); + + IwavePnpWake(iw.csn); + + IwavePnpGetCfg(); + IwavePnpKey(); + + IwavePnpWake(iw.csn); } - } - else - { - /* - * ASIC not detected so the card must be 2.2 or 2.4. - * There could still be the 16-bit/mixer daughter card. - * It has the same codec/mixer than MAX. - * At this time there is no support for it but it will appear soon. - */ - } + if (hw->irq > 0) { + /* I see the user wants to set the GUS PnP */ + /* Okay lets do it */ + iw.csn = 1; + iw.p2xr = hw->io_base; + iw.p3xr = hw->io_base + 0x100; + iw.pcodar = hw->io_base + 0x10c; + iw.synth_irq = hw->irq; -#if defined(__FreeBSD__) - printk ("gus0: <Gravis UltraSound %s (%dk)>", model_num, - (int) gus_mem_size / 1024); -#else - printk (" <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024); -#endif + iw.midi_irq = hw->irq; - sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024); + iw.dma1_chan = hw->dma; - gus_irq = irq; - gus_dma = dma; - gus_dma_read = dma_read; + if (hw->dma2 == -1) { + iw.dma2_chan = hw->dma; + } else { + iw.dma2_chan = hw->dma2; + } - if (num_synths >= MAX_SYNTH_DEV) - printk ("GUS Error: Too many synthesizers\n"); - else - { - voice_alloc = &guswave_operations.alloc; - synth_devs[num_synths++] = &guswave_operations; - } -#if defined(__FreeBSD__) - PERMANENT_MALLOC (char *, gus_copy_buf, DSP_BUFFSIZE, mem_start); -#endif + } else { - PERMANENT_MALLOC (struct patch_info *, samples, - (MAX_SAMPLE + 1) * sizeof (*samples), mem_start); + /* tell the os what we are doing 8) */ + hw->io_base = iw.p2xr; + hw->irq = iw.synth_irq; + /* + * iw.dma1_chan = 1; iw.dma2_chan = 3 ; + */ + hw->dma = iw.dma1_chan; + hw->dma2 = iw.dma2_chan; - reset_sample_memory (); - gus_initialize (); + } - if (num_audiodevs < MAX_AUDIO_DEV) - { - audio_devs[gus_devnum = num_audiodevs++] = &gus_sampling_operations; - audio_devs[gus_devnum]->dmachan = dma; - audio_devs[gus_devnum]->buffcount = 1; - audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE; - gus_dspnum = gus_devnum; - gus_busy[gus_devnum] = 0; - gus_busy[gus_dspnum] = 0; - } - else - printk ("GUS: Too many PCM devices available\n"); - - if (num_audiodevs < MAX_AUDIO_DEV) - { - if(dma_read && dma != dma_read) - { - audio_devs[gus_dspnum = num_audiodevs++]= &gus_sampling_operations_read; - audio_devs[gus_dspnum]->dmachan = gus_dma_read; - audio_devs[gus_dspnum]->buffcount = 1; - audio_devs[gus_dspnum]->buffsize = DSP_BUFFSIZE; - gus_busy[gus_dspnum] = 0; - } - else - { - gus_dspnum = gus_devnum; - } - } - else - printk ("GUS READ: Too many PCM devices available\n"); - - /* - * Mixer dependent initialization. - */ - switch (mixer_type) - { - case ICS2101: - gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; - gus_wave_volume = 90; - return ics2101_mixer_init (mem_start); + if (iw.csn > 0 && iw.csn < MAX_GUS_PNP) { + gus_pnp_found[iw.csn] = hw->io_base; - case CS4231: - /* Initialized elsewhere (ad1848.c) */ -#ifndef EXCLUDE_GUSMAX - { - unsigned char max_config = 0x40; /* Codec enable */ - long mixer_init_return; - - if (dma > 3) - max_config |= 0x30; /* 16 bit playback and capture DMAs */ - - max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */ - - OUTB (max_config, gus_base + 0x106); /* UltraMax control */ - mixer_init_return = gus_default_mixer_init(mem_start); - - if (ad1848_detect (gus_base + 0x10c)) - { - gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; - gus_wave_volume = 90; - have_gus_max = 1; - ad1848_init ("GUS MAX", gus_base + 0x10c, - -irq, - dma_read, /* read write reversed */ - dma); - } - else - printk ("[Where's the CS4231?]"); - return mixer_init_return; - } -#endif - default: - return gus_default_mixer_init (mem_start); - } + } + iw.cdatap = iw.pcodar + 1; + iw.csr1r = iw.pcodar + 2; + iw.cxdr = iw.pcodar + 3;/* CPDR or CRDR */ + iw.gmxr = iw.p3xr; + iw.gmxdr = iw.p3xr + 1; /* GMTDR or GMRDR */ + iw.svsr = iw.p3xr + 2; + iw.igidxr = iw.p3xr + 3; + iw.i16dp = iw.p3xr + 4; + iw.i8dp = iw.p3xr + 5; + iw.lmbdr = iw.p3xr + 7; + iw.voices = voices; + + if (iw.pnprdp > 0 && iw.csn > 0) { + IwavePnpSetCfg(); + IwavePnpActivate(AUDIO, ON); + IwavePnpActivate(EXT, ON); + } + /* IwavePnpActivate(EMULATION,ON); */ + + + /* reset */ + outb(iw.igidxr, _URSTI);/* Pull reset */ + outb(iw.i8dp, 0x00); + DELAY(1000 * 30); + + outb(iw.i8dp, 0x01); /* Release reset */ + DELAY(1000 * 30); + + /* end of reset */ + + + IwaveMemCfg(NULL); + + + tmp = IwaveRegPeek(IDECI); + + IwaveRegPoke(IDECI, tmp | 0x18); + + IwaveCodecMode(CODEC_MODE2); /* Default codec mode */ + IwaveRegPoke(ICMPTI, 0); + + outb(iw.igidxr, 0x99); + tmp = inb(iw.i8dp); + outb(iw.igidxr, 0x19); + outb(iw.i8dp, tmp); + + + + IwaveCodecIrq(~CODEC_IRQ_ENABLE); + + Iwaveinitcodec(); + + outb(iw.p2xr, 0x0c); /* Disable line in, mic and line out */ + + IwaveRegPoke(CLCI, 0x3f << 2); + + IwaveLineLevel(0, _CLOAI); + IwaveLineLevel(0, _CROAI); + + IwaveLineMute(OFF, _CLOAI); + IwaveLineMute(OFF, _CROAI); + + IwaveLineLevel(0, _CLLICI); + IwaveLineLevel(0, _CRLICI); + IwaveLineMute(OFF, _CLLICI); + IwaveLineMute(OFF, _CRLICI); + + IwaveLineLevel(0, _CLDACI); + IwaveLineLevel(0, _CRDACI); + IwaveLineMute(ON, _CLDACI); + IwaveLineMute(ON, _CRDACI); + + IwaveLineLevel(0, _CLLICI); + IwaveLineLevel(0, _CRLICI); + IwaveLineMute(ON, _CLLICI); + IwaveLineMute(ON, _CRLICI); + + + IwaveInputSource(LEFT_SOURCE, MIC_IN); + IwaveInputSource(RIGHT_SOURCE, MIC_IN); + + outb(iw.pcodar, 0x9 | 0x40); + outb(iw.cdatap, 0); + IwaveCodecIrq(CODEC_IRQ_ENABLE); + outb(iw.pcodar, _CFIG3I | 0x20); + + + outb(iw.cdatap, 0xC2); /* Enable Mode 3 IRQs & Synth */ + + outb(iw.igidxr, _URSTI); + outb(iw.i8dp, GF1_SET | GF1_OUT_ENABLE | GF1_IRQ_ENABLE); + DELAY(1000 * 30); + iw.size_mem = IwaveMemSize(); /* Bytes of RAM in this mode */ + outb(iw.p2xr, 0xc); /* enable output */ + IwaveRegPoke(CLCI, 0x3f << 2); + + IwaveCodecIrq(CODEC_IRQ_ENABLE); + splx(flags); + + DELAY(1000 * 100); + IwaveRegPoke(CPDFI, 0); + + return (TRUE); } -static void -do_loop_irq (int voice) + +void +gus_wave_init(struct address_info * hw_config) { - unsigned char tmp; - int mode, parm; - unsigned long flags; + u_long flags; + u_char val, gus_pnp_seen = 0; + char *model_num = "2.4"; + int gus_type = 0x24; /* 2.4 */ + int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2; + int otherside = -1, i; + + if (irq < 0 || irq > 15) { + printf("ERROR! Invalid IRQ#%d. GUS Disabled", irq); + return; + } + if (dma < 0 || dma > 7) { + printf("ERROR! Invalid DMA#%d. GUS Disabled", dma); + return; + } + for (i = 0; i < MAX_GUS_PNP; i++) { + if (gus_pnp_found[i] != 0 && gus_pnp_found[i] == hw_config->io_base) + gus_pnp_seen = 1; + } +#ifdef NOGUSPNP + gus_pnp_seen = 0; +#endif - DISABLE_INTR (flags); - gus_select_voice (voice); + gus_irq = irq; + gus_dma = dma; + gus_dma2 = dma2; - tmp = gus_read8 (0x00); - tmp &= ~0x20; /* - * Disable wave IRQ for this_one voice - */ - gus_write8 (0x00, tmp); + if (gus_dma2 == -1) + gus_dma2 = dma; - if (tmp & 0x03) /* Voice stopped */ - voice_alloc->map[voice] = 0; + /* + * Try to identify the GUS model. + * + * Versions < 3.6 don't have the digital ASIC. Try to probe it first. + */ - mode = voices[voice].loop_irq_mode; - voices[voice].loop_irq_mode = 0; - parm = voices[voice].loop_irq_parm; + flags = splhigh(); + outb(gus_base + 0x0f, 0x20); + val = inb(gus_base + 0x0f); + splx(flags); - switch (mode) - { + if (val != 0xff && (val & 0x06)) { /* Should be 0x02?? */ + /* + * It has the digital ASIC so the card is at least v3.4. Next + * try to detect the true model. + */ - case LMODE_FINISH: /* - * Final loop finished, shoot volume down - */ - - if ((int) (gus_read16 (0x09) >> 4) < 100) /* - * Get current volume - */ - { - gus_voice_off (); - gus_rampoff (); - gus_voice_init (voice); - break; - } - gus_ramp_range (65, 4065); - gus_ramp_rate (0, 63); /* - * Fastest possible rate - */ - gus_rampon (0x20 | 0x40); /* - * Ramp down, once, irq - */ - voices[voice].volume_irq_mode = VMODE_HALT; - break; - - case LMODE_PCM_STOP: - pcm_active = 0; /* Signal to the play_next_pcm_block routine */ - case LMODE_PCM: - { - int flag; /* 0 or 2 */ - - pcm_qlen--; - pcm_head = (pcm_head + 1) % pcm_nblk; - if (pcm_qlen && pcm_active) - { - play_next_pcm_block (); - } - else - { /* Underrun. Just stop the voice */ - gus_select_voice (0); /* Left channel */ - gus_voice_off (); - gus_rampoff (); - gus_select_voice (1); /* Right channel */ - gus_voice_off (); - gus_rampoff (); - pcm_active = 0; - } + val = inb(u_MixSelect); /* - * If the queue was full before this interrupt, the DMA transfer was - * suspended. Let it continue now. + * Value 255 means pre-3.7 which don't have mixer. Values 5 + * thru 9 mean v3.7 which has a ICS2101 mixer. 10 and above + * is GUS MAX which has the CS4231 codec/mixer. + * */ - if (dma_active) - { - if (pcm_qlen == 0) - flag = 1; /* Underflow */ + + if (gus_pnp_seen) + val = 66; + + if (val == 255 || val < 5) { + model_num = "3.4"; + gus_type = 0x34; + } else if (val < 10) { + model_num = "3.7"; + gus_type = 0x37; + mixer_type = ICS2101; + } else { + if (gus_pnp_seen) + model_num = "PNP"; else - flag = 0; - dma_active = 0; - } - else - flag = 2; /* Just notify the dmabuf.c */ - DMAbuf_outputintr (gus_devnum, flag); - } - break; + model_num = "MAX"; + + gus_type = 0x40; + mixer_type = CS4231; +#ifdef CONFIG_GUSMAX + { + u_char max_config = 0x40; /* Codec enable */ + + if (gus_dma2 == -1) + gus_dma2 = gus_dma; + + if (gus_dma > 3) + max_config |= 0x10; /* 16 bit capture DMA */ + + if (gus_dma2 > 3) + max_config |= 0x20; /* 16 bit playback DMA */ + + max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from + * 2X0 */ + + outb(gus_base + 0x106, max_config); /* UltraMax control */ + } + + if (ad1848_detect(gus_base + 0x10c, NULL, hw_config->osp)) { + + gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; + gus_wave_volume = 90; + have_gus_max = 1; + if (gus_pnp_seen) { + + ad1848_init("GUS PNP", gus_base + 0x10c, + -irq, + gus_dma2, /* Playback DMA */ + gus_dma, /* Capture DMA */ + 1, /* Share DMA channels with GF1 */ + hw_config->osp); + + + } else { + ad1848_init("GUS MAX", gus_base + 0x10c, + -irq, + gus_dma2, /* Playback DMA */ + gus_dma, /* Capture DMA */ + 1, /* Share DMA channels with GF1 */ + hw_config->osp); + } + otherside = num_audiodevs - 1; + + } else + printf("[Where's the CS4231?]"); +#else + printf("\n\n\nGUS MAX support was not compiled in!!!\n\n\n\n"); +#endif + } + } else { + /* + * ASIC not detected so the card must be 2.2 or 2.4. There + * could still be the 16-bit/mixer daughter card. + */ + } + + if (gus_pnp_seen) { + sprintf(gus_info.name, "Gravis %s (%dk)", model_num, (int) gus_mem_size / 1024); + } else { + sprintf(gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024); + } + conf_printf(gus_info.name, hw_config); + + if (num_synths >= MAX_SYNTH_DEV) + printf("GUS Error: Too many synthesizers\n"); + else { + voice_alloc = &guswave_operations.alloc; + synth_devs[num_synths++] = &guswave_operations; +#ifdef CONFIG_SEQUENCER + gus_tmr_install(gus_base + 8); +#endif + } + samples = (struct patch_info *) malloc((MAX_SAMPLE + 1) * sizeof(*samples), M_DEVBUF, M_NOWAIT); + if (!samples) + panic("SOUND: Cannot allocate memory\n"); + + reset_sample_memory(); + + gus_initialize(); + + if (num_audiodevs < MAX_AUDIO_DEV) { + audio_devs[gus_devnum = num_audiodevs++] = &gus_sampling_operations; + audio_devs[gus_devnum]->otherside = otherside; + audio_devs[gus_devnum]->dmachan1 = dma; + audio_devs[gus_devnum]->dmachan2 = dma2; + audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE; + if (otherside != -1) { + /* + * glue logic to prevent people from opening the gus + * max via the gf1 and the cs4231 side . Only the gf1 + * or the cs4231 are allowed to be open + */ + + audio_devs[otherside]->otherside = gus_devnum; + } + if (dma2 != dma && dma2 != -1) + audio_devs[gus_devnum]->flags |= DMA_DUPLEX; + } else + printf("GUS: Too many PCM devices available\n"); + + /* + * Mixer dependent initialization. + */ + + switch (mixer_type) { + case ICS2101: + gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; + gus_wave_volume = 90; + ics2101_mixer_init(); + return; - default:; + case CS4231: + /* Initialized elsewhere (ad1848.c) */ + default: + gus_default_mixer_init(); + return; } - RESTORE_INTR (flags); } static void -do_volume_irq (int voice) +do_loop_irq(int voice) +{ + u_char tmp; + int mode, parm; + u_long flags; + + flags = splhigh(); + gus_select_voice(voice); + + tmp = gus_read8(0x00); + tmp &= ~0x20; /* Disable wave IRQ for this_one voice */ + gus_write8(0x00, tmp); + + if (tmp & 0x03) /* Voice stopped */ + voice_alloc->map[voice] = 0; + + mode = voices[voice].loop_irq_mode; + voices[voice].loop_irq_mode = 0; + parm = voices[voice].loop_irq_parm; + + switch (mode) { + + case LMODE_FINISH: /* Final loop finished, shoot volume down */ + + if ((int) (gus_read16(0x09) >> 4) < 100) { /* Get current volume */ + gus_voice_off(); + gus_rampoff(); + gus_voice_init(voice); + break; + } + gus_ramp_range(65, 4065); + gus_ramp_rate(0, 63); /* Fastest possible rate */ + gus_rampon(0x20 | 0x40); /* Ramp down, once, irq */ + voices[voice].volume_irq_mode = VMODE_HALT; + break; + + case LMODE_PCM_STOP: + pcm_active = 0; /* Signal to the play_next_pcm_block routine */ + case LMODE_PCM: + { + int flag; /* 0 or 2 */ + + pcm_qlen--; + pcm_head = (pcm_head + 1) % pcm_nblk; + if (pcm_qlen && pcm_active) { + play_next_pcm_block(); + } else {/* Underrun. Just stop the voice */ + gus_select_voice(0); /* Left channel */ + gus_voice_off(); + gus_rampoff(); + gus_select_voice(1); /* Right channel */ + gus_voice_off(); + gus_rampoff(); + pcm_active = 0; + } + + /* + * If the queue was full before this interrupt, the + * DMA transfer was suspended. Let it continue now. + */ + if (dma_active) { + if (pcm_qlen == 0) + flag = 1; /* Underflow */ + else + flag = 0; + dma_active = 0; + } else + flag = 2; /* Just notify the dmabuf.c */ + DMAbuf_outputintr(gus_devnum, flag); + } + break; + + default:; + } + splx(flags); +} + +void +do_volume_irq(int voice) { - unsigned char tmp; - int mode, parm; - unsigned long flags; + u_char tmp; + int mode, parm; + u_long flags; - DISABLE_INTR (flags); + flags = splhigh(); - gus_select_voice (voice); + gus_select_voice(voice); - tmp = gus_read8 (0x0d); - tmp &= ~0x20; /* - * Disable volume ramp IRQ - */ - gus_write8 (0x0d, tmp); + tmp = gus_read8(0x0d); + tmp &= ~0x20; /* Disable volume ramp IRQ */ + gus_write8(0x0d, tmp); - mode = voices[voice].volume_irq_mode; - voices[voice].volume_irq_mode = 0; - parm = voices[voice].volume_irq_parm; + mode = voices[voice].volume_irq_mode; + voices[voice].volume_irq_mode = 0; + parm = voices[voice].volume_irq_parm; - switch (mode) - { - case VMODE_HALT: /* - * Decay phase finished - */ - RESTORE_INTR (flags); - gus_voice_init (voice); - break; - - case VMODE_ENVELOPE: - gus_rampoff (); - RESTORE_INTR (flags); - step_envelope (voice); - break; - - case VMODE_START_NOTE: - RESTORE_INTR (flags); - guswave_start_note2 (voices[voice].dev_pending, voice, - voices[voice].note_pending, voices[voice].volume_pending); - if (voices[voice].kill_pending) - guswave_kill_note (voices[voice].dev_pending, voice, - voices[voice].note_pending, 0); + switch (mode) { + case VMODE_HALT: /* Decay phase finished */ + splx(flags); + gus_voice_init(voice); + break; - if (voices[voice].sample_pending >= 0) - { - guswave_set_instr (voices[voice].dev_pending, voice, - voices[voice].sample_pending); - voices[voice].sample_pending = -1; + case VMODE_ENVELOPE: + gus_rampoff(); + splx(flags); + step_envelope(voice); + break; + + case VMODE_START_NOTE: + splx(flags); + guswave_start_note2(voices[voice].dev_pending, voice, + voices[voice].note_pending, voices[voice].volume_pending); + if (voices[voice].kill_pending) + guswave_kill_note(voices[voice].dev_pending, voice, + voices[voice].note_pending, 0); + + if (voices[voice].sample_pending >= 0) { + guswave_set_instr(voices[voice].dev_pending, voice, + voices[voice].sample_pending); + voices[voice].sample_pending = -1; + } + break; + + default:; } - break; +} - default:; - } +void +gus_voice_irq(void) +{ + u_long wave_ignore = 0, volume_ignore = 0; + u_long voice_bit; + + u_char src, voice; + + while (1) { + src = gus_read8(0x0f); /* Get source info */ + voice = src & 0x1f; + src &= 0xc0; + + if (src == (0x80 | 0x40)) + return; /* No interrupt */ + + voice_bit = 1 << voice; + + if (!(src & 0x80)) /* Wave IRQ pending */ + if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) { /* Not done yet */ + wave_ignore |= voice_bit; + do_loop_irq(voice); + } + if (!(src & 0x40)) /* Volume IRQ pending */ + if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) { /* Not done yet */ + volume_ignore |= voice_bit; + do_volume_irq(voice); + } + } } void -gus_voice_irq (void) +guswave_dma_irq(void) { - unsigned long wave_ignore = 0, volume_ignore = 0; - unsigned long voice_bit; + u_char status; + + status = gus_look8(0x41); /* Get DMA IRQ Status */ + if (status & 0x40) /* DMA interrupt pending */ + switch (active_device) { + case GUS_DEV_WAVE: + if ((dram_sleep_flag.mode & WK_SLEEP)) { + dram_sleep_flag.mode = WK_WAKEUP; + wakeup(dram_sleeper); + }; + break; + + case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */ + gus_transfer_output_block(pcm_current_dev, pcm_current_buf, + pcm_current_count, pcm_current_intrflag, 1); + break; - unsigned char src, voice; + case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */ + if (pcm_qlen < pcm_nblk) { + int flag = (1 - dma_active) * 2; /* 0 or 2 */ - while (1) - { - src = gus_read8 (0x0f); /* - * Get source info - */ - voice = src & 0x1f; - src &= 0xc0; - - if (src == (0x80 | 0x40)) - return; /* - * No interrupt - */ - - voice_bit = 1 << voice; - - if (!(src & 0x80)) /* - * Wave IRQ pending - */ - if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /* - * Not done - * yet - */ - { - wave_ignore |= voice_bit; - do_loop_irq (voice); - } - - if (!(src & 0x40)) /* - * Volume IRQ pending - */ - if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /* - * Not done - * yet - */ - { - volume_ignore |= voice_bit; - do_volume_irq (voice); - } - } + if (pcm_qlen == 0) + flag = 1; /* Underrun */ + dma_active = 0; + DMAbuf_outputintr(gus_devnum, flag); + } + break; + + default:; + } + + status = gus_look8(0x49); /* Get Sampling IRQ Status */ + if (status & 0x40) { /* Sampling Irq pending */ + DMAbuf_inputintr(gus_devnum); + } } +#ifdef CONFIG_SEQUENCER +/* + * Timer stuff + */ + +static volatile int select_addr, data_addr; +static volatile int curr_timer = 0; + void -guswave_dma_irq (void) +gus_timer_command(u_int addr, u_int val) { - unsigned char status; + int i; - status = gus_look8 (0x41); /* Get DMA IRQ Status */ - if (status & 0x40) /* DMA interrupt pending */ - switch (active_device) - { - case GUS_DEV_WAVE: - if (SOMEONE_WAITING (dram_sleeper, dram_sleep_flag)) - WAKE_UP (dram_sleeper, dram_sleep_flag); - break; + outb(select_addr, (u_char) (addr & 0xff)); - case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */ - gus_transfer_output_block (pcm_current_dev, pcm_current_buf, - pcm_current_count, - pcm_current_intrflag, 1); - break; + for (i = 0; i < 2; i++) + inb(select_addr); - case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */ - if (pcm_qlen < pcm_nblk) - { - int flag = (1 - dma_active) * 2; /* 0 or 2 */ + outb(data_addr, (u_char) (val & 0xff)); - if (pcm_qlen == 0) - flag = 1; /* Underrun */ - dma_active = 0; - DMAbuf_outputintr (gus_devnum, flag); - } - break; + for (i = 0; i < 2; i++) + inb(select_addr); +} + +static void +arm_timer(int timer, u_int interval) +{ + curr_timer = timer; + + if (timer == 1) { + gus_write8(0x46, 256 - interval); /* Set counter for timer 1 */ + gus_write8(0x45, 0x04); /* Enable timer 1 IRQ */ + gus_timer_command(0x04, 0x01); /* Start timer 1 */ + } else { + gus_write8(0x47, 256 - interval); /* Set counter for timer 2 */ + gus_write8(0x45, 0x08); /* Enable timer 2 IRQ */ + gus_timer_command(0x04, 0x02); /* Start timer 2 */ + } - default:; - } + gus_timer_enabled = 0; +} - status = gus_look8 (0x49); /* - * Get Sampling IRQ Status - */ - if (status & 0x40) /* - * Sampling Irq pending - */ - { - if (gus_dma_read && gus_dma_read != gus_dma) - DMAbuf_inputintr (gus_dspnum); - else - DMAbuf_inputintr (gus_devnum); +static u_int +gus_tmr_start(int dev, u_int usecs_per_tick) +{ + int timer_no, resolution; + int divisor; + + if (usecs_per_tick > (256 * 80)) { + timer_no = 2; + resolution = 320; /* usec */ + } else { + timer_no = 1; + resolution = 80;/* usec */ } + divisor = (usecs_per_tick + (resolution / 2)) / resolution; + + arm_timer(timer_no, divisor); + + return divisor * resolution; +} + +static void +gus_tmr_disable(int dev) +{ + gus_write8(0x45, 0); /* Disable both timers */ + gus_timer_enabled = 0; +} + +static void +gus_tmr_restart(int dev) +{ + if (curr_timer == 1) + gus_write8(0x45, 0x04); /* Start timer 1 again */ + else + gus_write8(0x45, 0x08); /* Start timer 2 again */ } +static struct sound_lowlev_timer gus_tmr = +{ + 0, + gus_tmr_start, + gus_tmr_disable, + gus_tmr_restart +}; + +static void +gus_tmr_install(int io_base) +{ + select_addr = io_base; + data_addr = io_base + 1; + + sound_timer_init(&gus_tmr, "GUS"); +} +#endif #endif |