aboutsummaryrefslogtreecommitdiff
path: root/sys/i386/isa/sound/gus_wave.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/i386/isa/sound/gus_wave.c')
-rw-r--r--sys/i386/isa/sound/gus_wave.c6536
1 files changed, 4082 insertions, 2454 deletions
diff --git a/sys/i386/isa/sound/gus_wave.c b/sys/i386/isa/sound/gus_wave.c
index 5f8e39c8ae5b..8cb3419dffa8 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,76 +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 "sound_config.h"
-#include "ultrasound.h"
-#include "gus_hw.h"
+#include <i386/isa/sound/sound_config.h>
+#include <i386/isa/sound/ultrasound.h>
+#include <i386/isa/sound/gus_hw.h>
+#include <i386/isa/sound/iwdefs.h>
+#include <machine/clock.h>
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+/* PnP stuff */
+#define GUS_PNP_ID 0x100561e
-#define MAX_SAMPLE 128
+#define MAX_CARDS 8
+#define MAX_GUS_PNP 12
+
+
+/* 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;
+
+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 = 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;
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;
@@ -105,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
@@ -120,39 +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;
+extern sound_os_info *gus_osp;
+
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];
@@ -161,3086 +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);
}
-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;
}
-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;
}
void
-gus_write16 (int reg, unsigned int data)
-{ /* Writes to an indirect register (16 bit) */
- unsigned long flags;
+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);
}
-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;
}
void
-gus_write_addr (int reg, unsigned long address, int is16bit)
+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_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;
- 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, 1, 3, 0, 2, 0, 4, 0, 0, 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 = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */
- tmp = gus_dma_map[gus_dma];
- if (!tmp)
- printk ("Warning! GUS DMA not selected\n");
- dma_image |= tmp;
+ 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 = 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;
+ }
- /*
- * 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 (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);
+ int sample_no;
- if (voice < 0 || voice > 31)
- return RET_ERROR (EINVAL);
+ if (instr_no < 0 || instr_no > MAX_PATCH)
+ return -(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;
-
- 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);
}
- return 0;
+ splx(flags);
+ return 0;
}
static void
-guswave_aftertouch (int dev, int voice, int pressure)
+guswave_aftertouch(int dev, int voice, int pressure)
{
- short lo_limit, hi_limit;
- unsigned long flags;
-
- return; /* Procedure currently disabled */
-
- 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);
}
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;
-
- compute_volume (voice, volume);
- voices[voice].current_volume = voices[voice].initial_volume;
+ int curr, target, rate;
+ u_long flags;
- DISABLE_INTR (flags);
- /*
- * CAUTION! Interrupts disabled. Enable them before returning
- */
-
- gus_select_voice (voice);
+ compute_volume(voice, volume);
+ voices[voice].current_volume = voices[voice].initial_volume;
- current = gus_read16 (0x09) >> 4;
- target = voices[voice].initial_volume;
+ flags = splhigh();
+ /*
+ * CAUTION! Interrupts disabled. Enable them before returning
+ */
- 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 */
+ flags = splhigh();
+ gus_select_voice(voice);
+ status = gus_read8(0x00); /* Get voice status */
+ splx(flags);
- if (!(voices[voice].mode & WAVE_ENVELOPES))
- {
- compute_and_set_volume (voice, voices[voice].midi_volume, 1);
- return;
- }
+ if (status & 0x03)
+ return; /* Voice was not running */
- /*
- * Voice is running and has envelopes.
- */
-
- 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 */
+ 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 */
}
- 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
- {
- RESTORE_INTR (flags);
- ret_val = guswave_start_note2 (dev, 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);
- guswave_set_instr (voices[voice].dev_pending, voice,
- voices[voice].sample_pending);
- voices[voice].sample_pending = -1;
- DISABLE_INTR (flags);
- }
-
- 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);
+ } 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 */
}
}
- 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 (gus_busy)
- return RET_ERROR (EBUSY);
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return -(EBUSY);
+ }
+ if (audio_devs[dev]->busy)
+ return -(EBUSY);
- gus_initialize ();
+ 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 = 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 = 0;
- active_device = 0;
- gus_reset ();
+ int otherside = audio_devs[dev]->otherside;
- DMAbuf_close_dma (gus_devnum);
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return;
+ }
+ audio_devs[dev]->busy = 0;
+
+ 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;
- 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;
-
- /*
- * Use DMA to transfer the wave data to the DRAM
- */
+ /*
+ * Tremolo is not possible with envelopes
+ */
- left = patch.len;
- src_offs = 0;
- target = free_mem_ptr;
+ if (patch.mode & WAVE_ENVELOPES)
+ patch.mode &= ~WAVE_TREMOLO;
- while (left) /* Not completely transferred yet */
- {
- blk_size = audio_devs[gus_devnum]->buffsize;
- if (blk_size > left)
- blk_size = left;
+ bcopy(&patch, (char *) &samples[free_sample], sizeof_patch);
- /*
- * DMA cannot cross 256k bank boundaries. Check for that.
- */
- blk_end = target + blk_size;
-
- 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 */
-
- /*
- * Now the next part
- */
- left -= blk_size;
- src_offs += blk_size;
- target += blk_size;
+ 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 (dev, 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)
- return gus_sampling_speed;
- if (speed > 44100)
- speed = 44100;
+ if (speed <= 0)
+ speed = gus_sampling_speed;
+
+ RANGE(speed, 4000, 44100);
+ gus_sampling_speed = speed;
- gus_sampling_speed = speed;
- return 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;
}
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;
- default:
- return RET_ERROR (EINVAL);
- }
- 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)
{
-#ifdef GUS_NO_DMA
- printk ("GUS: DMA mode not enabled. Device not supported\n");
- return RET_ERROR (ENXIO);
-#endif
- if (gus_busy)
- return RET_ERROR (EBUSY);
+ int otherside = audio_devs[dev]->otherside;
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return -(EBUSY);
+ }
+ if (audio_devs[dev]->busy)
+ return -(EBUSY);
- gus_initialize ();
- gus_busy = 1;
- active_device = 0;
+ gus_initialize();
- gus_reset ();
- reset_sample_memory ();
- gus_select_max_voices (14);
+ active_device = 0;
- pcm_active = 0;
- dma_active = 0;
- pcm_opened = 1;
- if (mode & OPEN_READ)
- {
- recording_active = 1;
- set_input_volumes ();
- }
+ gus_reset();
+ reset_sample_memory();
+ gus_select_max_voices(14);
- return 0;
+ 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_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;
}
static void
-gus_sampling_close (int dev)
+gus_sampling_close(int dev)
{
- gus_reset ();
- gus_busy = 0;
- pcm_opened = 0;
- active_device = 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();
- recording_active = 0;
+ pcm_opened = 0;
+ active_device = 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;
-
- DISABLE_INTR (flags);
- if (pcm_active && pcm_opened)
- for (voice = 0; voice < gus_sampling_channels; voice++)
- {
- 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),
- is16bits); /* Loop end location */
- }
-
- if (chn == 0)
- gus_write_addr (0x04, dram_loc + pcm_datasize[this_one],
- 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 (dev, 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[dev]->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[dev]->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 = dev;
- gus_transfer_output_block (dev, 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 (dev, 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[dev]->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)
- {
- 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;
+ 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;
+ }
}
- }
- else
- {
- int in_left = useroffs;
- int in_right = useroffs + 1;
- short *out_left, *out_right;
- int i;
-
- len /= 4;
- localoffs /= 4;
-
- out_left = (short *) &localbuf[localoffs];
- out_right = out_left + (pcm_bsize / 2);
-
- for (i = 0; i < len; i++)
- {
- 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;
- }
- }
}
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
+ "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 void
-guswave_bender (int dev, int voice, int value)
+guswave_setup_voice(int dev, int voice, int chn)
{
- int freq;
- unsigned long flags;
-
- voices[voice].bender = value - 8192;
- freq = compute_finetune (voices[voice].orig_freq, value,
- voices[voice].bender_range);
- voices[voice].current_freq = freq;
+ 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;
+}
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_freq (freq);
- RESTORE_INTR (flags);
+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)
+guswave_patchmgr(int dev, struct patmgr_info * rec)
{
- int i, n;
+ int i, n;
- switch (rec->command)
- {
- case PM_GET_DEVTYPE:
- rec->parm1 = PMTYPE_WAVE;
- return 0;
- break;
+ 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_NRPGM:
+ rec->parm1 = MAX_PATCH;
+ return 0;
+ break;
- case PM_GET_PGMMAP:
- rec->parm1 = MAX_PATCH;
+ case PM_GET_PGMMAP:
+ rec->parm1 = MAX_PATCH;
- for (i = 0; i < MAX_PATCH; i++)
- {
- int ptr = patch_table[i];
+ for (i = 0; i < MAX_PATCH; i++) {
+ int ptr = patch_table[i];
- rec->data.data8[i] = 0;
+ rec->data.data8[i] = 0;
- while (ptr >= 0 && ptr < free_sample)
- {
- rec->data.data8[i]++;
- ptr = samples[ptr].key; /* Follow link */
- }
- }
- return 0;
- break;
+ 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 RET_ERROR (EINVAL);
-
- memcpy (rec->data.data8, (char *) &samples[ptr],
- sizeof (struct patch_info));
+ case PM_GET_PGM_PATCHES:
+ {
+ int ptr = patch_table[rec->parm1];
- 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;
+ n = 0;
- default:
- return RET_ERROR (EINVAL);
- }
+ 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 */
+
+ bcopy(rec->data.data8, (char *) &samples[ptr], 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 -(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);
+ }
}
static int
-guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc)
+guswave_alloc(int dev, int chn, int note, struct voice_alloc_info * alloc)
{
- int i, p;
+ int i, p, best = -1, best_time = 0x7fffffff;
- p = alloc->ptr;
- /*
- * First look for a completely stopped voice
- */
+ 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;
+ 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;
}
- p = (p + 1) % alloc->max_voice;
- }
- /*
- * Then look for a releasing voice
- */
+ /*
+ * Then look for a releasing voice
+ */
- for (i = 0; i < alloc->max_voice; i++)
- {
- if (alloc->map[p] == 0xffff)
- {
- alloc->ptr = p;
- return p;
+ for (i = 0; i < alloc->max_voice; i++) {
+ if (alloc->map[p] == 0xffff) {
+ alloc->ptr = p;
+ return p;
+ }
+ p = (p + 1) % alloc->max_voice;
}
- p = (p + 1) % alloc->max_voice;
- }
- printk ("GUS: Out of free voices\n");
- alloc->ptr = p;
- return p;
+ if (best >= 0)
+ p = best;
+
+ alloc->ptr = p;
+ return p;
}
static struct synth_operations guswave_operations =
{
- &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
+ &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
-set_input_volumes (void)
+set_input_volumes(void)
{
- unsigned long flags;
- unsigned char mask = 0xff & ~0x06; /* Just line out enabled */
+ u_long flags;
+ u_char mask = 0xff & ~0x06; /* Just line out enabled */
- DISABLE_INTR (flags);
+ if (have_gus_max) /* Don't disturb GUS MAX */
+ return;
- /*
- * 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;
- }
+ flags = splhigh();
- mix_image &= ~0x07;
- mix_image |= mask & 0x07;
- OUTB (mix_image, u_Mixer);
+ /*
+ * 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);
- RESTORE_INTR (flags);
+ splx(flags);
}
int
-gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+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 = 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;
- 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));
+ 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);
}
- break;
+ else
+ switch (cmd & 0xff) { /* Return parameters */
- 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;
+ case SOUND_MIXER_RECSRC:
+ return *(int *) arg = gus_recmask;
+ break;
- 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;
+ case SOUND_MIXER_DEVMASK:
+ return *(int *) arg = MIX_DEVS;
+ break;
- case SOUND_MIXER_SYNTH:
- {
- int voice;
+ case SOUND_MIXER_STEREODEVS:
+ return *(int *) arg = 0;
+ break;
- gus_wave_volume = IOCTL_IN (arg) & 0xff;
+ case SOUND_MIXER_RECMASK:
+ return *(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE;
+ break;
- if (gus_wave_volume < 0)
- gus_wave_volume = 0;
- if (gus_wave_volume > 100)
- gus_wave_volume = 100;
+ case SOUND_MIXER_CAPS:
+ return *(int *) arg = 0;
+ break;
- if (active_device == GUS_DEV_WAVE)
- for (voice = 0; voice < nr_voices; voice++)
- dynamic_volume_change (voice); /* Apply the new vol */
+ case SOUND_MIXER_MIC:
+ return *(int *) arg = gus_mic_vol | (gus_mic_vol << 8);
+ break;
- return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
+ 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);
}
- break;
+} else
+ return -(EINVAL);
+}
- default:
- return RET_ERROR (EINVAL);
- }
- else
- switch (cmd & 0xff) /*
- * Return parameters
- */
- {
-
- case SOUND_MIXER_RECSRC:
- return IOCTL_OUT (arg, gus_recmask);
- break;
+static struct mixer_operations gus_mixer_operations = {"Gravis Ultrasound", gus_default_mixer_ioctl};
- case SOUND_MIXER_DEVMASK:
- return IOCTL_OUT (arg, MIX_DEVS);
- break;
+static void
+gus_default_mixer_init()
+{
+if (num_mixers < MAX_MIXER_DEV) /* Don't install if there is another
+ * mixer */
+ mixer_devs[num_mixers++] = &gus_mixer_operations;
- case SOUND_MIXER_STEREODEVS:
- return IOCTL_OUT (arg, 0);
- break;
+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);
+}
+}
- case SOUND_MIXER_RECMASK:
- return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
- break;
+/* start of pnp code */
- case SOUND_MIXER_CAPS:
- return IOCTL_OUT (arg, 0);
- break;
+void
+SEND(int d, int r)
+{
+outb(PADDRESS, d);
+outb(PWRITE_DATA, r);
+}
- 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;
- case SOUND_MIXER_PCM:
- return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8));
- break;
- case SOUND_MIXER_SYNTH:
- return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
- break;
+/*
+ * Get the device's serial number. Returns 1 if the serial is valid.
+ */
+int
+get_serial(int rd_port, u_char *data)
+{
+ int i, bit, valid = 0, sum = 0x6a;
- default:
- return RET_ERROR (EINVAL);
- }
- }
- else
- return RET_ERROR (EINVAL);
+ bzero(data, sizeof(char) * 9);
+
+ for (i = 0; i < 72; i++) {
+ bit = inb((rd_port << 2) | 0x3) == 0x55;
+ DELAY(250); /* Delay 250 usec */
+
+ /* Can't Short Circuit the next evaluation, so 'and' is last */
+ bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit;
+ DELAY(250); /* Delay 250 usec */
+
+ valid = valid || bit;
+
+ if (i < 64)
+ sum = (sum >> 1) |
+ (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
+
+ data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
+ }
+ valid = valid && (data[8] == sum);
+
+ return valid;
}
-static struct mixer_operations gus_mixer_operations =
+void
+send_Initiation_LFSR()
{
- gus_default_mixer_ioctl
-};
+ int cur, i;
+
+ /* Reset the LSFR */
+ outb(PADDRESS, 0);
+ outb(PADDRESS, 0);
-static long
-gus_default_mixer_init (long mem_start)
+ cur = 0x6a;
+ outb(PADDRESS, cur);
+
+ for (i = 1; i < 32; i++) {
+ cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
+ outb(PADDRESS, cur);
+ }
+}
+
+
+
+int
+isolation_protocol(int rd_port)
{
- if (num_mixers < MAX_MIXER_DEV) /*
- * Don't install if there is another
- * mixer
- */
- mixer_devs[num_mixers++] = &gus_mixer_operations;
+ int csn;
+ u_char data[9];
+
+ send_Initiation_LFSR();
- return mem_start;
+ /* 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;
+ }
+
+ return 0;
}
-long
-gus_wave_init (long mem_start, int irq, int dma)
+
+
+void
+IwaveDelay(WORD count)
{
- unsigned long flags;
- unsigned char val;
- char *model_num = "2.4";
- int gus_type = 0x24; /* 2.4 */
- int mixer_type = 0;
+ 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;
+ }
+ outb(0x61, portb); /* disable counter */
+}
- /*
- * Try to identify the GUS model.
- *
- * Versions < 3.6 don't have the digital ASIC. Try to probe it first.
+/*
+ * ########################################################################
+ *
+ * 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.
+ * ########################################################################
*/
- DISABLE_INTR (flags);
- OUTB (0x20, gus_base + 0x0f);
- val = INB (gus_base + 0x0f);
- RESTORE_INTR (flags);
+void
+IwaveStopDma(BYTE path)
+{
+ BYTE reg;
- 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.
- */
+ 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;
+}
- val = INB (u_MixSelect);
+/*
+ * ########################################################################
+ *
+ * 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)
+{
+ 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;
+}
+
+void
+IwavePnpSetCfg(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] */
+
+ 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;
+}
+
+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;
+}
- /*
- * 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;
+/* ######################################################################## */
+/* 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;
+
+ /* ############################################### */
+ /* 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);
}
- else if (val < 10)
- {
- model_num = "3.7";
- gus_type = 0x37;
- mixer_type = ICS2101;
+
+}
+
+BYTE
+IwavePnpIsol(PORT * pnpread)
+{
+ 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;
+}
+
+/* ######################################################################## */
+/* */
+/* 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 */
}
- else
- {
- model_num = "MAX";
- gus_type = 0x40;
- mixer_type = CS4231;
-#ifndef EXCLUDE_GUSMAX
- {
- unsigned char max_config = 0x40; /* Codec enable */
+}
+/* ######################################################################## */
+/* */
+/* 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;
- if (dma > 3)
- max_config |= 0x30; /* 16 bit playback and capture DMAs */
+}
+/* ######################################################################## */
+/* */
+/* 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;
- max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */
+ outb(_PIDXR, RANGE_IOCHK); /* select IO range check reg */
- OUTB (max_config, gus_base + 0x106); /* UltraMax control */
- }
+ 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 */
- 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,
- dma);
- }
- else
- printk ("[Where's the CS4231?]");
-#endif
+ outb(_PNPWRP, 0x03); /* must drive 0x55 onto bus */
+ if (inb(portid) != 0x55)
+ return (portid); /* IO conflict detected */
}
- }
- 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.
+ 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 */
+}
+
+/* end of pnp code */
+
+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));
+}
+
+BYTE
+IwaveMemPeek(ADDRESS addr)
+{
+ PORT p3xr;
+
+ p3xr = iw.p3xr;
+
+
+ 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 */
+}
+
+
+void
+IwaveMemPoke(ADDRESS addr, BYTE datum)
+{
+ PORT p3xr;
+ p3xr = iw.p3xr;
+
+
+ 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 */
+}
+
+/* ######################################################################## */
+/* */
+/* 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;
+}
+
+
+/* ######################################################################## */
+/**/
+/* 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;
+}
+
+
+/* ######################################################################### */
+/**/
+/* 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)
+{
+ 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);
+ }
+ }
+}
+
+
+void
+IwaveLineLevel(char level, char index)
+{
+ char reg;
+
+ 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;
+}
+
+void
+IwaveCodecMode(char mode)
+{
+ 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;
+}
+
+void
+IwaveLineMute(BYTE mute, BYTE inx)
+{
+ BYTE reg;
+
+ 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;
+}
+
+void
+Iwaveinitcodec()
+{
+
+ u_short iwl_codec_base = iw.pcodar;
+ u_short iwl_codec_data = iw.pcodar + 1;
+ u_short foo;
+
+
+
+ /*
+ * 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);
- printk (" <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024);
+ /* 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);
-#ifndef SCO
- sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
-#endif
+ foo = CODEC_CFIG3I_DEFAULT;
+ IWL_CODEC_OUT(CONFIG_3, foo);
- if (irq < 0 || irq > 15)
- {
- printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
- return mem_start;
- }
+}
- if (dma < 0 || dma > 7)
- {
- printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma);
- return mem_start;
- }
- gus_irq = irq;
- gus_dma = dma;
- 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;
- }
+int
+IwaveOpen(char voices, char mode, struct address_info * hw)
+{
- PERMANENT_MALLOC (struct patch_info *, samples,
- (MAX_SAMPLE + 1) * sizeof (*samples), mem_start);
+ u_long flags;
+ u_char tmp;
- reset_sample_memory ();
+ flags = splhigh();
- gus_initialize ();
+ iw.pnprdp = 0;
+ if (IwavePnpIsol(&iw.pnprdp)) {
- 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;
- }
- else
- printk ("GUS: Too many PCM devices available\n");
+ iw.vendor = GUS_PNP_ID;
- /*
- * Mixer dependent initialization.
- */
+ iw.csn = IwavePnpPing(iw.vendor);
- 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);
+ IwavePnpKey();
- case CS4231:
- /* Initialized elsewhere (ad1848.c) */
- default:
- return gus_default_mixer_init (mem_start);
- }
+ IwavePnpWake(iw.csn);
+
+ IwavePnpGetCfg();
+ IwavePnpKey();
+
+ IwavePnpWake(iw.csn);
+ }
+ 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;
+
+ iw.midi_irq = hw->irq;
+
+ iw.dma1_chan = hw->dma;
+
+ if (hw->dma2 == -1) {
+ iw.dma2_chan = hw->dma;
+ } else {
+ iw.dma2_chan = hw->dma2;
+ }
+
+
+ } else {
+
+ /* 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;
- return mem_start;
+
+ }
+
+ if (iw.csn > 0 && iw.csn < MAX_GUS_PNP) {
+ gus_pnp_found[iw.csn] = hw->io_base;
+
+ }
+ 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;
- mode = voices[voice].loop_irq_mode;
- voices[voice].loop_irq_mode = 0;
- parm = voices[voice].loop_irq_parm;
+ /*
+ * Try to identify the GUS model.
+ *
+ * Versions < 3.6 don't have the digital ASIC. Try to probe it first.
+ */
- switch (mode)
- {
+ flags = splhigh();
+ outb(gus_base + 0x0f, 0x20);
+ val = inb(gus_base + 0x0f);
+ splx(flags);
- 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 orig_qlen = pcm_qlen;
- int flag; /* 0 or 2 */
-
- pcm_qlen--;
- pcm_head = (pcm_head + 1) % pcm_nblk;
- if (pcm_qlen)
- {
- play_next_pcm_block ();
- }
- else
- { /* Underrun. Just stop the voice */
- gus_voice_off ();
- gus_rampoff ();
- pcm_active = 0;
- }
+ 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);
/*
- * 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 */
+ * 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 (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.
+ */
+ }
- default:;
+ 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;
+
+ 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)
{
- unsigned char tmp;
- int mode, parm;
- unsigned long flags;
+ 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);
+}
- DISABLE_INTR (flags);
+void
+do_volume_irq(int voice)
+{
+ u_char tmp;
+ int mode, parm;
+ u_long flags;
- gus_select_voice (voice);
+ flags = splhigh();
- tmp = gus_read8 (0x0d);
- tmp &= ~0x20; /*
- * Disable volume ramp IRQ
- */
- gus_write8 (0x0d, tmp);
+ gus_select_voice(voice);
- mode = voices[voice].volume_irq_mode;
- voices[voice].volume_irq_mode = 0;
- parm = voices[voice].volume_irq_parm;
+ tmp = gus_read8(0x0d);
+ tmp &= ~0x20; /* Disable volume ramp IRQ */
+ gus_write8(0x0d, tmp);
- 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);
+ mode = voices[voice].volume_irq_mode;
+ voices[voice].volume_irq_mode = 0;
+ parm = voices[voice].volume_irq_parm;
- if (voices[voice].sample_pending >= 0)
- {
- guswave_set_instr (voices[voice].dev_pending, voice,
- voices[voice].sample_pending);
- voices[voice].sample_pending = -1;
+ switch (mode) {
+ case VMODE_HALT: /* Decay phase finished */
+ splx(flags);
+ gus_voice_init(voice);
+ break;
+
+ 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;
- unsigned char src, voice;
+ 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;
- 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);
- }
- }
+ 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 */
+
+ 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
- */
- {
- 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