summaryrefslogtreecommitdiffstats
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.c1705
1 files changed, 1301 insertions, 404 deletions
diff --git a/sys/i386/isa/sound/gus_wave.c b/sys/i386/isa/sound/gus_wave.c
index deb3a15..7c625e2 100644
--- a/sys/i386/isa/sound/gus_wave.c
+++ b/sys/i386/isa/sound/gus_wave.c
@@ -1,6 +1,6 @@
-/*
- * linux/kernel/chr_drv/sound/gus_wave.c
+/*
+ * sound/gus_wave.c
*
* Driver for the Gravis UltraSound wave table synth.
*
@@ -28,15 +28,19 @@
*
*/
-/* #define GUS_LINEAR_VOLUME */
-
#include "sound_config.h"
+#ifdef linux
+#include <linux/ultrasound.h>
+#elif __FreeBSD__
#include <machine/ultrasound.h>
+#else
+#include "ultrasound.h"
+#endif
#include "gus_hw.h"
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
-#define MAX_SAMPLE 256
+#define MAX_SAMPLE 128
#define MAX_PATCH 256
struct voice_info
@@ -57,16 +61,22 @@ struct voice_info
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];
- /*
+ /*
* 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;
+
};
extern int gus_base;
@@ -77,24 +87,31 @@ extern int snd_raw_count[MAX_DSP_DEV];
static long gus_mem_size = 0;
static long free_mem_ptr = 0;
static int gus_busy = 0;
-static int nr_voices = 0; /* Number of currently allowed voices */
+static int nr_voices = 0;
static int gus_devnum = 0;
static int volume_base, volume_scale, volume_method;
+static int gus_line_vol = 100, gus_mic_vol = 0;
+static int gus_recmask = SOUND_MASK_MIC;
+static int recording_active = 0;
#define VOL_METHOD_ADAGIO 1
-int gus_wave_volume = 60; /* Master wolume for wave (0 to 100) */
+int gus_wave_volume = 60;
+int gus_pcm_volume = 80;
static unsigned char mix_image = 0x00;
-/*
- * Current version of this_one driver doesn't allow synth and PCM functions
+/*
+ * 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;
-#define GUS_DEV_WAVE 1 /* Wave table synth */
-#define GUS_DEV_PCM_DONE 2 /* PCM device, transfer done */
-#define GUS_DEV_PCM_CONTINUE 3 /* PCM device, transfer the second
- * chn */
+#define GUS_DEV_WAVE 1 /*
+ * * * Wave table synth */
+#define GUS_DEV_PCM_DONE 2 /*
+ * * * PCM device, transfer done */
+#define GUS_DEV_PCM_CONTINUE 3 /*
+ * * * PCM device, transfer the
+ * second * * * chn */
static int gus_sampling_speed;
static int gus_sampling_channels;
@@ -102,16 +119,37 @@ static int gus_sampling_bits;
DEFINE_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
-/*
+/*
* Variables and buffers for PCM output
*/
-#define MAX_PCM_BUFFERS 32 /* Don't change */
-static int pcm_bsize, /* Current blocksize */
- pcm_nblk, /* Current # of blocks */
- pcm_banksize; /* # bytes allocated for channels */
-static int pcm_datasize[MAX_PCM_BUFFERS]; /* Actual # of bytes in blk */
-static volatile int pcm_head, pcm_tail, pcm_qlen; /* DRAM queue */
+#define MAX_PCM_BUFFERS (32*MAX_REALTIME_FACTOR) /*
+ * * * Don't
+ * * * change
+ *
+ */
+
+static int pcm_bsize, /*
+ * Current blocksize
+ */
+ pcm_nblk, /*
+ * Current # of blocks
+ */
+ pcm_banksize; /*
+
+
+ * * * * # bytes allocated for channels */
+static int pcm_datasize[MAX_PCM_BUFFERS]; /*
+
+
+ * * * * Actual # of bytes
+ * in blk * */
+static volatile int pcm_head, pcm_tail, pcm_qlen; /*
+
+
+ * * * * DRAM queue
+ * */
static volatile int pcm_active;
+static int pcm_opened = 0;
static int pcm_current_dev;
static int pcm_current_block;
static unsigned long pcm_current_buf;
@@ -122,28 +160,66 @@ 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[MAX_SAMPLE + 1];
+static struct patch_info *samples;
static long sample_ptrs[MAX_SAMPLE + 1];
static int sample_map[32];
static int free_sample;
@@ -159,9 +235,13 @@ 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);
static void compute_volume (int voice, int volume);
+static void do_volume_irq (int voice);
+static void set_input_volumes (void);
-#define INSTANT_RAMP -1 /* Dont use ramping */
-#define FAST_RAMP 0 /* Fastest possible ramp */
+#define INSTANT_RAMP -1 /*
+ * * * Dont use ramping */
+#define FAST_RAMP 0 /*
+ * * * Fastest possible ramp */
static void
reset_sample_memory (void)
@@ -175,7 +255,9 @@ reset_sample_memory (void)
for (i = 0; i < 32; i++)
patch_map[i] = -1;
- gus_poke (0, 0); /* Put silence here */
+ gus_poke (0, 0); /*
+ * Put silence here
+ */
gus_poke (1, 0);
free_mem_ptr = 2;
@@ -230,14 +312,14 @@ gus_peek (long addr)
}
void
-gus_write8 (int reg, unsigned char data)
+gus_write8 (int reg, unsigned int data)
{
unsigned long flags;
DISABLE_INTR (flags);
OUTB (reg, u_Command);
- OUTB (data, u_DataHi);
+ OUTB ((unsigned char) (data & 0xff), u_DataHi);
RESTORE_INTR (flags);
}
@@ -271,7 +353,7 @@ gus_look8 (int reg)
}
void
-gus_write16 (int reg, unsigned short data)
+gus_write16 (int reg, unsigned int data)
{
unsigned long flags;
@@ -279,8 +361,8 @@ gus_write16 (int reg, unsigned short data)
OUTB (reg, u_Command);
- OUTB (data & 0xff, u_DataLo);
- OUTB ((data >> 8) & 0xff, u_DataHi);
+ OUTB ((unsigned char) (data & 0xff), u_DataLo);
+ OUTB ((unsigned char) ((data >> 8) & 0xff), u_DataHi);
RESTORE_INTR (flags);
}
@@ -310,7 +392,7 @@ gus_write_addr (int reg, unsigned long address, int is16bit)
if (is16bit)
{
- /*
+ /*
* Special processing required for 16 bit patches
*/
@@ -347,11 +429,11 @@ gus_select_max_voices (int nvoices)
}
static void
-gus_voice_on (unsigned char mode)
+gus_voice_on (unsigned int mode)
{
- gus_write8 (0x00, mode & 0xfc);
+ gus_write8 (0x00, (unsigned char) (mode & 0xfc));
gus_delay ();
- gus_write8 (0x00, mode & 0xfc);
+ gus_write8 (0x00, (unsigned char) (mode & 0xfc));
}
static void
@@ -361,10 +443,18 @@ gus_voice_off (void)
}
static void
-gus_voice_mode (unsigned char mode)
-{
- gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); /* Don't start or stop
- * voice */
+gus_voice_mode (unsigned int m)
+{
+ unsigned char mode = (unsigned char) (m & 0xff);
+
+ gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); /*
+ * Don't
+ * start
+ * or
+ * stop
+ * *
+ * voice
+ */
gus_delay ();
gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));
}
@@ -382,44 +472,56 @@ gus_voice_freq (unsigned long freq)
}
static void
-gus_voice_volume (unsigned short vol)
+gus_voice_volume (unsigned int vol)
{
- gus_write8 (0x0d, 0x03); /* Stop ramp before setting volume */
- gus_write16 (0x09, vol << 4);
+ gus_write8 (0x0d, 0x03); /*
+ * Stop ramp before setting volume
+ */
+ gus_write16 (0x09, (unsigned short) (vol << 4));
}
static void
-gus_voice_balance (unsigned char balance)
+gus_voice_balance (unsigned int balance)
{
- gus_write8 (0x0c, balance);
+ gus_write8 (0x0c, (unsigned char) (balance & 0xff));
}
static void
-gus_ramp_range (unsigned short low, unsigned short high)
+gus_ramp_range (unsigned int low, unsigned int high)
{
- gus_write8 (0x07, (low >> 4) & 0xff);
- gus_write8 (0x08, (high >> 4) & 0xff);
+ gus_write8 (0x07, (unsigned char) ((low >> 4) & 0xff));
+ gus_write8 (0x08, (unsigned char) ((high >> 4) & 0xff));
}
static void
-gus_ramp_rate (unsigned char scale, unsigned char rate)
+gus_ramp_rate (unsigned int scale, unsigned int rate)
{
- gus_write8 (0x06, ((scale & 0x03) << 6) | (rate & 0x3f));
+ gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));
}
static void
-gus_rampon (unsigned char mode)
+gus_rampon (unsigned int m)
{
+ unsigned char mode = (unsigned char) (m & 0xff);
+
gus_write8 (0x0d, mode & 0xfc);
gus_delay ();
gus_write8 (0x0d, mode & 0xfc);
}
static void
-gus_ramp_mode (unsigned char mode)
-{
- gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); /* Don't start or stop
- * ramping */
+gus_ramp_mode (unsigned int m)
+{
+ unsigned char mode = (unsigned char) (m & 0xff);
+
+ gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); /*
+ * Don't
+ * start
+ * or
+ * stop
+ * *
+ * ramping
+ */
gus_delay ();
gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));
}
@@ -431,6 +533,20 @@ gus_rampoff (void)
}
static void
+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);
+}
+
+static void
gus_voice_init (int voice)
{
unsigned long flags;
@@ -438,11 +554,22 @@ gus_voice_init (int voice)
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 */
+ gus_write_addr (0x0a, 0, 0); /*
+ * Set current position to 0
+ */
+ gus_write8 (0x00, 0x03); /*
+ * Voice off
+ */
+ gus_write8 (0x0d, 0x03); /*
+ * Ramping off
+ */
RESTORE_INTR (flags);
+}
+
+static void
+gus_voice_init2 (int voice)
+{
voices[voice].panning = 0;
voices[voice].mode = 0;
voices[voice].orig_freq = 20000;
@@ -459,6 +586,7 @@ gus_voice_init (int voice)
voices[voice].main_vol = 127;
voices[voice].patch_vol = 127;
voices[voice].expression_vol = 127;
+ voices[voice].sample_pending = -1;
}
static void
@@ -470,12 +598,14 @@ step_envelope (int voice)
if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)
{
gus_rampoff ();
- return; /* Sustain */
+ return; /*
+ * Sustain
+ */
}
if (voices[voice].env_phase >= 5)
{
- /*
+ /*
* Shoot the voice off
*/
@@ -491,13 +621,19 @@ step_envelope (int voice)
vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
rate = voices[voice].env_rate[phase];
- gus_write8 (0x06, rate); /* Ramping rate */
+ gus_write8 (0x06, rate); /*
+ * Ramping rate
+ */
voices[voice].volume_irq_mode = VMODE_ENVELOPE;
- if (((vol - prev_vol) / 64) == 0) /* No significant volume change */
+ if (((vol - prev_vol) / 64) == 0) /*
+ * No significant volume change
+ */
{
- step_envelope (voice); /* Continue with the next phase */
+ step_envelope (voice); /*
+ * Continue with the next phase
+ */
return;
}
@@ -506,14 +642,18 @@ step_envelope (int voice)
if (vol >= (4096 - 64))
vol = 4096 - 65;
gus_ramp_range (0, vol);
- gus_rampon (0x20); /* Increasing, irq */
+ gus_rampon (0x20); /*
+ * Increasing, irq
+ */
}
else
{
if (vol <= 64)
vol = 65;
- gus_ramp_range (vol, 4095);
- gus_rampon (0x60); /* Decreasing, irq */
+ gus_ramp_range (vol, 4030);
+ gus_rampon (0x60); /*
+ * Decreasing, irq
+ */
}
voices[voice].current_volume = vol;
}
@@ -531,13 +671,19 @@ static void
start_release (int voice)
{
if (gus_read8 (0x00) & 0x03)
- return; /* Voice already stopped */
+ 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].initial_volume =
- gus_read16 (0x09) >> 4; /* Get current volume */
+ gus_read16 (0x09) >> 4; /*
+ * Get current volume
+ */
voices[voice].mode &= ~WAVE_SUSTAIN_ON;
gus_rampoff ();
@@ -551,11 +697,17 @@ gus_voice_fade (int voice)
if (instr_no < 0 || instr_no > MAX_SAMPLE)
{
- gus_write8 (0x00, 0x03); /* Hard stop */
+ gus_write8 (0x00, 0x03); /*
+ * Hard stop
+ */
return;
}
- is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bit samples */
+ is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /*
+ * 8 or 16
+ * bit
+ * samples
+ */
if (voices[voice].mode & WAVE_ENVELOPES)
{
@@ -563,10 +715,12 @@ gus_voice_fade (int voice)
return;
}
- /*
+ /*
* Ramp the volume down but not too quickly.
*/
- if ((gus_read16 (0x09) >> 4) < 100) /* Get current volume */
+ if ((gus_read16 (0x09) >> 4) < 100) /*
+ * Get current volume
+ */
{
gus_voice_off ();
gus_rampoff ();
@@ -574,9 +728,11 @@ gus_voice_fade (int voice)
return;
}
- gus_ramp_range (65, 4095);
+ gus_ramp_range (65, 4030);
gus_ramp_rate (2, 4);
- gus_rampon (0x40 | 0x20); /* Down, once, irq */
+ gus_rampon (0x40 | 0x20); /*
+ * Down, once, irq
+ */
voices[voice].volume_irq_mode = VMODE_HALT;
}
@@ -592,14 +748,25 @@ gus_reset (void)
for (i = 0; i < 32; i++)
{
- gus_voice_init (i); /* Turn voice off */
+ 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_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
+ */
}
@@ -617,59 +784,86 @@ gus_initialize (void)
DISABLE_INTR (flags);
- gus_write8 (0x4c, 0); /* Reset GF1 */
+ gus_write8 (0x4c, 0); /*
+ * Reset GF1
+ */
gus_delay ();
gus_delay ();
- gus_write8 (0x4c, 1); /* Release Reset */
+ 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 */
+ gus_write8 (0x41, 0); /*
+ * DMA control
+ */
+ gus_write8 (0x45, 0); /*
+ * Timer control
+ */
+ gus_write8 (0x49, 0); /*
+ * Sample control
+ */
gus_select_max_voices (24);
- INB (u_Status); /* Touch the status register */
-
- 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_look8 (0x41); /* Clear any pending DMA IRQs */
- gus_look8 (0x49); /* Clear any pending sample IRQs */
- gus_read8 (0x0f); /* Clear pending IRQs */
-
- gus_write8 (0x4c, 7); /* Master reset | DAC enable | IRQ enable */
-
- /*
+ INB (u_Status); /*
+ * Touch the status register
+ */
+
+ 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_look8 (0x41); /*
+ * Clear any pending DMA IRQs
+ */
+ gus_look8 (0x49); /*
+ * Clear any pending sample IRQs
+ */
+ gus_read8 (0x0f); /*
+ * Clear pending IRQs
+ */
+
+ gus_write8 (0x4c, 7); /*
+ * Master reset | DAC enable | IRQ enable
+ */
+
+ /*
* Set up for Digital ASIC
*/
OUTB (0x05, gus_base + 0x0f);
- mix_image |= 0x02; /* Disable line out */
+ mix_image |= 0x02; /*
+ * Disable line out
+ */
OUTB (mix_image, u_Mixer);
OUTB (0x00, u_IRQDMAControl);
OUTB (0x00, gus_base + 0x0f);
- /*
+ /*
* Now set up the DMA and IRQ interface
*
* The GUS supports two IRQs and two DMAs.
*
- * If GUS_MIDI_IRQ is defined and if it's != GUS_IRQ, separate Midi IRQ is set
- * up. Otherwise the same IRQ is shared by the both devices.
- *
* 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.
@@ -680,63 +874,89 @@ gus_initialize (void)
if (!tmp)
printk ("Warning! GUS IRQ not selected\n");
irq_image |= tmp;
+ irq_image |= 0x40; /*
+ * Combine IRQ1 (GF1) and IRQ2 (Midi)
+ */
- if (GUS_MIDI_IRQ != gus_irq)
- { /* The midi irq was defined and != wave irq */
- tmp = gus_irq_map[GUS_MIDI_IRQ];
- tmp <<= 3;
-
- if (!tmp)
- printk ("Warning! GUS Midi IRQ not selected\n");
- else
- gus_set_midi_irq (GUS_MIDI_IRQ);
-
- irq_image |= tmp;
- }
- else
- irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */
-
- dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */
+ 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;
- /*
+ /*
* For some reason the IRQ and DMA addresses must be written twice
*/
- /* Doing it first time */
-
- OUTB (mix_image, u_Mixer); /* Select DMA control */
- OUTB (dma_image, u_IRQDMAControl); /* Set DMA address */
-
- OUTB (mix_image | 0x40, u_Mixer); /* Select IRQ control */
- OUTB (irq_image, u_IRQDMAControl); /* Set IRQ address */
-
- /* Doing it second time */
-
- OUTB (mix_image, u_Mixer); /* Select DMA control */
- OUTB (dma_image, u_IRQDMAControl); /* Set DMA address */
-
- OUTB (mix_image | 0x40, u_Mixer); /* Select IRQ control */
- OUTB (irq_image, u_IRQDMAControl); /* Set IRQ address */
-
- 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 */
+ /*
+ * Doing it first time
+ */
- gus_select_voice (0); /* This disables writes to IRQ/DMA reg */
+ OUTB (mix_image, u_Mixer); /*
+ * Select DMA control
+ */
+ OUTB (dma_image | 0x80, u_IRQDMAControl); /*
+ * Set DMA address
+ */
+
+ OUTB (mix_image | 0x40, u_Mixer); /*
+ * Select IRQ control
+ */
+ OUTB (irq_image, u_IRQDMAControl); /*
+ * Set IRQ address
+ */
+
+ /*
+ * Doing it second time
+ */
- gusintr (0); /* Serve pending interrupts */
+ OUTB (mix_image, u_Mixer); /*
+ * Select DMA control
+ */
+ OUTB (dma_image, u_IRQDMAControl); /*
+ * Set DMA address
+ */
+
+ OUTB (mix_image | 0x40, u_Mixer); /*
+ * Select IRQ control
+ */
+ OUTB (irq_image, u_IRQDMAControl); /*
+ * Set IRQ address
+ */
+
+ 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.
+ */
+
+ gus_select_voice (0); /*
+ * This disables writes to IRQ/DMA reg
+ */
+
+ gusintr (0); /*
+ * Serve pending interrupts
+ */
RESTORE_INTR (flags);
}
int
gus_wave_detect (int baseaddr)
{
+ unsigned long i;
+ unsigned long loc;
+
gus_base = baseaddr;
gus_write8 (0x4c, 0); /* Reset GF1 */
@@ -747,31 +967,37 @@ gus_wave_detect (int baseaddr)
gus_delay ();
gus_delay ();
- gus_poke (0x000, 0xaa);
- gus_poke (0x100, 0x55);
-
- if (gus_peek (0x000) != 0xaa)
- return 0;
- if (gus_peek (0x100) != 0x55)
- return 0;
+ /* See if there is first block there.... */
+ gus_poke (0L, 0xaa);
+ if (gus_peek (0L) != 0xaa)
+ return (0);
- gus_mem_size = 0x40000; /* 256k */
- gus_poke (0x40000, 0xaa);
- if (gus_peek (0x40000) != 0xaa)
- return 1;
+ /* Now zero it out so that I can check for mirroring .. */
+ gus_poke (0L, 0x00);
+ for (i = 1L; i < 1024L; i++)
+ {
+ int n, failed;
- gus_mem_size = 0x80000; /* 512k */
- gus_poke (0x80000, 0xaa);
- if (gus_peek (0x80000) != 0xaa)
- return 1;
+ /* check for mirroring ... */
+ if (gus_peek (0L) != 0)
+ break;
+ loc = i << 10;
- gus_mem_size = 0xc0000; /* 768k */
- gus_poke (0xc0000, 0xaa);
- if (gus_peek (0xc0000) != 0xaa)
- return 1;
+ for (n = loc - 1, failed = 0; n <= loc; n++)
+ {
+ gus_poke (loc, 0xaa);
+ if (gus_peek (loc) != 0xaa)
+ failed = 1;
- gus_mem_size = 0x100000; /* 1M */
+ gus_poke (loc, 0x55);
+ if (gus_peek (loc) != 0x55)
+ failed = 1;
+ }
+ if (failed)
+ break;
+ }
+ gus_mem_size = i << 10;
return 1;
}
@@ -816,16 +1042,26 @@ guswave_set_instr (int dev, int voice, int instr_no)
if (voice < 0 || voice > 31)
return RET_ERROR (EINVAL);
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ {
+ voices[voice].sample_pending = instr_no;
+ return 0;
+ }
+
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 */
+ return RET_ERROR (EINVAL); /*
+ * Patch not defined
+ */
}
- if (sample_ptrs[sample_no] == -1) /* Sample not loaded */
+ 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);
@@ -837,13 +1073,22 @@ guswave_set_instr (int dev, int voice, int instr_no)
}
static int
+#ifdef FUTURE_VERSION
+guswave_kill_note (int dev, int voice, int note, int velocity)
+#else
guswave_kill_note (int dev, int voice, int velocity)
+#endif
{
unsigned long flags;
DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_fade (voice);
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ voices[voice].kill_pending = 1;
+ else
+ {
+ gus_select_voice (voice);
+ gus_voice_fade (voice);
+ }
RESTORE_INTR (flags);
return 0;
@@ -855,20 +1100,26 @@ guswave_aftertouch (int dev, int voice, int pressure)
short lo_limit, hi_limit;
unsigned long flags;
- return; /* Currently disabled */
+ return; /*
+ * 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 */
+ 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 */
+ compute_and_set_volume (voice, 255, 0); /*
+ * Back to original volume
+ */
RESTORE_INTR (flags);
return;
}
@@ -887,7 +1138,9 @@ guswave_aftertouch (int dev, int voice, int pressure)
}
gus_ramp_range (lo_limit, hi_limit);
gus_ramp_rate (3, 8);
- gus_rampon (0x58); /* Bidirectional, Down, Loop */
+ gus_rampon (0x58); /*
+ * Bidirectional, Down, Loop
+ */
RESTORE_INTR (flags);
}
@@ -902,31 +1155,38 @@ static void
compute_volume (int voice, int volume)
{
if (volume < 128)
- {
- voices[voice].midi_volume = volume;
+ voices[voice].midi_volume = volume;
- switch (volume_method)
- {
- case VOL_METHOD_ADAGIO:
- voices[voice].initial_volume =
- gus_adagio_vol (volume, voices[voice].main_vol,
- voices[voice].expression_vol,
- voices[voice].patch_vol);
- break;
+ 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;
- default:
- voices[voice].initial_volume = volume_base + (volume * volume_scale);
- }
+ default:
+ voices[voice].initial_volume = volume_base +
+ (voices[voice].midi_volume * volume_scale);
}
- if (voices[voice].initial_volume > 4095)
- voices[voice].initial_volume = 4095;
+ if (voices[voice].initial_volume > 4030)
+ voices[voice].initial_volume = 4030;
}
static void
compute_and_set_volume (int voice, int volume, int ramp_time)
{
int current, target, rate;
+ unsigned 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;
@@ -938,6 +1198,7 @@ compute_and_set_volume (int voice, int volume, int ramp_time)
{
gus_rampoff ();
gus_voice_volume (target);
+ RESTORE_INTR (flags);
return;
}
@@ -947,10 +1208,13 @@ compute_and_set_volume (int voice, int volume, int ramp_time)
rate = 16;
gus_ramp_rate (0, rate);
- if ((target - current) / 64 == 0) /* Too close */
+ if ((target - current) / 64 == 0) /*
+ * Too close
+ */
{
gus_rampoff ();
gus_voice_volume (target);
+ RESTORE_INTR (flags);
return;
}
@@ -959,7 +1223,9 @@ compute_and_set_volume (int voice, int volume, int ramp_time)
if (target > (4095 - 65))
target = 4095 - 65;
gus_ramp_range (current, target);
- gus_rampon (0x00); /* Ramp up, once, no irq */
+ gus_rampon (0x00); /*
+ * Ramp up, once, no irq
+ */
}
else
{
@@ -967,8 +1233,11 @@ compute_and_set_volume (int voice, int volume, int ramp_time)
target = 65;
gus_ramp_range (target, current);
- gus_rampon (0x40); /* Ramp down, once, no irq */
+ gus_rampon (0x40); /*
+ * Ramp down, once, no irq
+ */
}
+ RESTORE_INTR (flags);
}
static void
@@ -979,11 +1248,15 @@ dynamic_volume_change (int voice)
DISABLE_INTR (flags);
gus_select_voice (voice);
- status = gus_read8 (0x00); /* Voice status */
+ status = gus_read8 (0x00); /*
+ * Voice status
+ */
RESTORE_INTR (flags);
if (status & 0x03)
- return; /* Voice not started */
+ return; /*
+ * Voice not started
+ */
if (!(voices[voice].mode & WAVE_ENVELOPES))
{
@@ -991,16 +1264,20 @@ dynamic_volume_change (int voice)
return;
}
- /*
+ /*
* Voice is running and has envelopes.
*/
DISABLE_INTR (flags);
gus_select_voice (voice);
- status = gus_read8 (0x0d); /* Ramping status */
+ status = gus_read8 (0x0d); /*
+ * Ramping status
+ */
RESTORE_INTR (flags);
- if (status & 0x03) /* Sustain phase? */
+ if (status & 0x03) /*
+ * Sustain phase?
+ */
{
compute_and_set_volume (voice, voices[voice].midi_volume, 1);
return;
@@ -1011,9 +1288,12 @@ dynamic_volume_change (int voice)
compute_volume (voice, voices[voice].midi_volume);
-#if 0 /* Is this really required */
+#if 0 /*
+ * * * Is this really required */
voices[voice].current_volume =
- gus_read16 (0x09) >> 4; /* Get current volume */
+ gus_read16 (0x09) >> 4; /*
+ * Get current volume
+ */
voices[voice].env_phase--;
step_envelope (voice);
@@ -1033,38 +1313,58 @@ guswave_controller (int dev, int voice, int ctrl_num, int value)
{
case CTRL_PITCH_BENDER:
voices[voice].bender = value;
- 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);
+ 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;
-
+#ifdef FUTURE_VERSION
+ case CTL_EXPRESSION:
+ value /= 128;
+#endif
case CTRL_EXPRESSION:
volume_method = VOL_METHOD_ADAGIO;
voices[voice].expression_vol = value;
- dynamic_volume_change (voice);
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+ dynamic_volume_change (voice);
+ break;
+
+#ifdef FUTURE_VERSION
+ case CTL_PAN:
+ voices[voice].panning = (value * 2) - 128;
break;
+ case CTL_MAIN_VOLUME:
+ value = (value * 100) / 16383;
+#endif
+
case CTRL_MAIN_VOLUME:
volume_method = VOL_METHOD_ADAGIO;
voices[voice].main_vol = value;
- dynamic_volume_change (voice);
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+ dynamic_volume_change (voice);
break;
- default: /* Ignore */
+ default: /*
+ * Ignore
+ */
break;
}
}
static int
-guswave_start_note (int dev, int voice, int note_num, int volume)
+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;
@@ -1102,7 +1402,7 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
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.
*/
@@ -1123,7 +1423,9 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
if (samples[samplep].low_note <= note_freq && note_freq <= samples[samplep].high_note)
sample = samplep;
else
- samplep = samples[samplep].key; /* Follow link */
+ samplep = samples[samplep].key; /*
+ * Follow link
+ */
}
if (sample == -1)
sample = best_sample;
@@ -1131,10 +1433,16 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
if (sample == -1)
{
printk ("GUS: Patch %d not defined for note %d\n", patch, note_num);
- return 0; /* Should play default patch ??? */
+ return 0; /*
+ * Should play default patch ???
+ */
}
- is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bit samples */
+ is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; /*
+ * 8 or 16
+ * bit
+ * samples
+ */
voices[voice].mode = samples[sample].mode;
voices[voice].patch_vol = samples[sample].volume;
@@ -1151,14 +1459,16 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
sample_map[voice] = sample;
- base_note = samples[sample].base_note / 100; /* To avoid overflows */
+ base_note = samples[sample].base_note / 100; /*
+ * To avoid overflows
+ */
note_freq /= 100;
freq = samples[sample].base_freq * note_freq / base_note;
voices[voice].orig_freq = freq;
- /*
+ /*
* Since the pitch bender may have been set before playing the note, we
* have to calculate the bending now.
*/
@@ -1175,19 +1485,23 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
if (samples[sample].mode & WAVE_16_BITS)
{
- mode |= 0x04; /* 16 bits */
+ mode |= 0x04; /*
+ * 16 bits
+ */
if ((sample_ptrs[sample] >> 18) !=
((sample_ptrs[sample] + samples[sample].len) >> 18))
printk ("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 (); /* It may still be running */
+ gus_voice_off (); /*
+ * It may still be running
+ */
gus_rampoff ();
if (voices[voice].mode & WAVE_ENVELOPES)
{
@@ -1198,35 +1512,62 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
compute_and_set_volume (voice, volume, 0);
if (samples[sample].mode & WAVE_LOOP_BACK)
- gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len, is16bits); /* Sample start=end */
+ gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len -
+ voices[voice].offset_pending, is16bits); /* Sample
+ * start=end */
else
- gus_write_addr (0x0a, sample_ptrs[sample], is16bits); /* Sample start=begin */
+ gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending,
+ is16bits); /* Sample start=begin */
if (samples[sample].mode & WAVE_LOOPING)
{
- mode |= 0x08; /* Looping on */
+ mode |= 0x08; /*
+ * Looping on
+ */
if (samples[sample].mode & WAVE_BIDIR_LOOP)
- mode |= 0x10; /* Bidirectional looping on */
+ mode |= 0x10; /*
+ * Bidirectional looping on
+ */
if (samples[sample].mode & WAVE_LOOP_BACK)
{
- gus_write_addr (0x0a, /* Put the current location = loop_end */
- sample_ptrs[sample] + samples[sample].loop_end, is16bits);
- mode |= 0x40; /* Loop backwards */
+ 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 it down at the
- * end */
+ mode |= 0x20; /*
+ * Loop irq at the end
+ */
+ voices[voice].loop_irq_mode = LMODE_FINISH; /*
+ * Ramp it 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, is16bits); /* Loop end location */
+ 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);
@@ -1236,13 +1577,76 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
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. */
+
+static int
+guswave_start_note (int dev, int voice, int note_num, int volume)
+{
+ long int flags;
+ int mode;
+ int ret_val = 0;
+
+ DISABLE_INTR (flags);
+ if (note_num == 255)
+ {
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ voices[voice].volume_pending = volume;
+ else
+ ret_val = guswave_start_note2 (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)
+ {
+ guswave_set_instr (voices[voice].dev_pending, voice,
+ voices[voice].sample_pending);
+ voices[voice].sample_pending = -1;
+ }
+
+ if ((mode & 0x01) || ((gus_read16 (0x09) >> 4) < 2065))
+ {
+ ret_val = guswave_start_note2 (dev, voice, note_num, volume);
+ }
+ else
+ {
+ voices[voice].dev_pending = dev;
+ voices[voice].note_pending = note_num;
+ voices[voice].volume_pending = volume;
+ voices[voice].volume_irq_mode = VMODE_START_NOTE;
+
+ gus_rampoff ();
+ gus_ramp_range (2000, 4065);
+ gus_ramp_rate (0, 63); /* Fastest possible rate */
+ gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */
+ }
+ }
+ RESTORE_INTR (flags);
+ return ret_val;
+}
+
static void
guswave_reset (int dev)
{
int i;
for (i = 0; i < 32; i++)
- gus_voice_init (i);
+ {
+ gus_voice_init (i);
+ gus_voice_init2 (i);
+ }
}
static int
@@ -1253,9 +1657,12 @@ guswave_open (int dev, int mode)
if (gus_busy)
return RET_ERROR (EBUSY);
+ gus_initialize ();
+
if ((err = DMAbuf_open_dma (gus_devnum)))
return err;
+ RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
gus_busy = 1;
active_device = GUS_DEV_WAVE;
@@ -1280,22 +1687,29 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
{
struct patch_info patch;
int instr;
+ long sizeof_patch;
unsigned long blk_size, blk_end, left, src_offs, target;
+ sizeof_patch = (long) &patch.data[0] - (long) &patch; /*
+ * Size of
+ * the header
+ * * info
+ */
+
if (format != GUS_PATCH)
{
- printk ("GUS Error: Invalid patch format (key) 0x%04x\n", format);
+ printk ("GUS Error: Invalid patch format (key) 0x%x\n", format);
return RET_ERROR (EINVAL);
}
- if (count < sizeof (patch))
+ if (count < sizeof_patch)
{
printk ("GUS Error: Patch header too short\n");
return RET_ERROR (EINVAL);
}
- count -= sizeof (patch);
+ count -= sizeof_patch;
if (free_sample >= MAX_SAMPLE)
{
@@ -1303,12 +1717,12 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
return RET_ERROR (ENOSPC);
}
- /*
+ /*
* 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);
+ COPY_FROM_USER (&((char *) &patch)[offs], addr, offs, sizeof_patch - offs);
instr = patch.instr_no;
@@ -1321,13 +1735,13 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
if (count < patch.len)
{
printk ("GUS Warning: Patch record too short (%d<%d)\n",
- count, patch.len);
+ count, (int) patch.len);
patch.len = count;
}
if (patch.len <= 0 || patch.len > gus_mem_size)
{
- printk ("GUS: Invalid sample length %d\n", patch.len);
+ printk ("GUS: Invalid sample length %d\n", (int) patch.len);
return RET_ERROR (EINVAL);
}
@@ -1346,31 +1760,37 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
}
}
- free_mem_ptr = (free_mem_ptr + 31) & ~31; /* Alignment 32 bytes */
+ free_mem_ptr = (free_mem_ptr + 31) & ~31; /*
+ * Alignment 32 bytes
+ */
#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", patch.len);
+ printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len);
return RET_ERROR (ENOSPC);
}
if ((free_mem_ptr / GUS_BANK_SIZE) !=
((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
{
- unsigned long tmp_mem = /* Align to 256K*N */
+ unsigned long tmp_mem = /*
+ * Align to 256K*N
+ */
((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
if ((tmp_mem + patch.len) > gus_mem_size)
return RET_ERROR (ENOSPC);
- free_mem_ptr = tmp_mem; /* This leaves unusable memory */
+ free_mem_ptr = tmp_mem; /*
+ * This leaves unusable memory
+ */
}
}
@@ -1379,21 +1799,23 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
sample_ptrs[free_sample] = free_mem_ptr;
- /* Tremolo is not possible with envelopes */
+ /*
+ * Tremolo is not possible with envelopes
+ */
if (patch.mode & WAVE_ENVELOPES)
patch.mode &= ~WAVE_TREMOLO;
- memcpy ((char *) &samples[free_sample], &patch, sizeof (patch));
+ 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
*/
@@ -1401,26 +1823,30 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
src_offs = 0;
target = free_mem_ptr;
- while (left) /* Not all moved */
+ while (left) /*
+ * Not all moved
+ */
{
blk_size = sound_buffsizes[gus_devnum];
if (blk_size > left)
blk_size = left;
- /*
+ /*
* DMA cannot cross 256k bank boundaries. Check for that.
*/
blk_end = target + blk_size;
if ((target >> 18) != (blk_end >> 18))
- { /* Have to split the block */
+ { /*
+ * Have to split the block
+ */
blk_end &= ~(256 * 1024 - 1);
blk_size = blk_end - target;
}
-#ifdef GUS_NO_DMA
- /*
+#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA)
+ /*
* For some reason the DMA is not possible. We have to use PIO.
*/
{
@@ -1429,28 +1855,39 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
for (i = 0; i < blk_size; i++)
{
- GET_BYTE_FROM_USER (data, addr, sizeof (patch) + i);
+ GET_BYTE_FROM_USER (data, addr, sizeof_patch + i);
+ if (patch.mode & WAVE_UNSIGNED)
+
+ if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
+ data ^= 0x80; /*
+ * Convert to signed
+ */
gus_poke (target + i, data);
}
}
-#else /* GUS_NO_DMA */
+#else /*
+ * * * GUS_NO_DMA */
{
unsigned long address, hold_address;
unsigned char dma_command;
+ unsigned long flags;
- /*
+ /*
* OK, move now. First in and then out.
*/
COPY_FROM_USER (snd_raw_buf[gus_devnum][0],
- addr, sizeof (patch) + src_offs,
+ addr, sizeof_patch + src_offs,
blk_size);
- gus_write8 (0x41, 0); /* Disable GF1 DMA */
+ DISABLE_INTR (flags); /******** INTERRUPTS DISABLED NOW ********/
+ gus_write8 (0x41, 0); /*
+ * Disable GF1 DMA
+ */
DMAbuf_start_dma (gus_devnum, snd_raw_buf_phys[gus_devnum][0],
blk_size, DMA_MODE_WRITE);
- /*
+ /*
* Set the DRAM address for the wave data
*/
@@ -1464,32 +1901,48 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
address |= (hold_address & 0x000c0000L);
}
- gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
+ gus_write16 (0x42, (address >> 4) & 0xffff); /*
+ * DRAM DMA address
+ */
- /*
+ /*
* Start the DMA transfer
*/
- dma_command = 0x21; /* IRQ enable, DMA start */
+ dma_command = 0x21; /*
+ * IRQ enable, DMA start
+ */
if (patch.mode & WAVE_UNSIGNED)
- dma_command |= 0x80; /* Invert MSB */
+ dma_command |= 0x80; /*
+ * Invert MSB
+ */
if (patch.mode & WAVE_16_BITS)
- dma_command |= 0x40; /* 16 bit _DATA_ */
+ dma_command |= 0x40; /*
+ * 16 bit _DATA_
+ */
if (sound_dsp_dmachan[gus_devnum] > 3)
- dma_command |= 0x04; /* 16 bit DMA channel */
+ dma_command |= 0x04; /*
+ * 16 bit DMA channel
+ */
- gus_write8 (0x41, dma_command); /* Let's go luteet (=bugs) */
+ gus_write8 (0x41, dma_command); /*
+ * Let's go luteet (=bugs)
+ */
- /*
+ /*
* Sleep here until the DRAM DMA done interrupt is served
*/
active_device = GUS_DEV_WAVE;
- INTERRUPTIBLE_SLEEP_ON (dram_sleeper, dram_sleep_flag);
+ 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 */
+#endif /*
+ * * * GUS_NO_DMA */
- /*
+ /*
* Now the next part
*/
@@ -1497,7 +1950,9 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
src_offs += blk_size;
target += blk_size;
- gus_write8 (0x41, 0); /* Stop DMA */
+ gus_write8 (0x41, 0); /*
+ * Stop DMA
+ */
}
free_mem_ptr += patch.len;
@@ -1521,6 +1976,10 @@ guswave_hw_control (int dev, unsigned char *event)
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)
{
@@ -1538,7 +1997,9 @@ guswave_hw_control (int dev, unsigned char *event)
case _GUS_VOICEON:
DISABLE_INTR (flags);
gus_select_voice (voice);
- p1 &= ~0x20; /* Disable intr */
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
gus_voice_on (p1);
RESTORE_INTR (flags);
break;
@@ -1560,7 +2021,9 @@ guswave_hw_control (int dev, unsigned char *event)
case _GUS_VOICEMODE:
DISABLE_INTR (flags);
gus_select_voice (voice);
- p1 &= ~0x20; /* Disable intr */
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
gus_voice_mode (p1);
RESTORE_INTR (flags);
break;
@@ -1586,14 +2049,18 @@ guswave_hw_control (int dev, unsigned char *event)
RESTORE_INTR (flags);
break;
- case _GUS_VOICEVOL2: /* Just update the voice value */
+ case _GUS_VOICEVOL2: /*
+ * Just update the voice value
+ */
voices[voice].initial_volume =
voices[voice].current_volume = p1;
break;
case _GUS_RAMPRANGE:
if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
+ break; /*
+ * NO-NO
+ */
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_ramp_range (p1, p2);
@@ -1602,7 +2069,9 @@ guswave_hw_control (int dev, unsigned char *event)
case _GUS_RAMPRATE:
if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
+ break; /*
+ * NO-NO
+ */
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_ramp_rate (p1, p2);
@@ -1611,27 +2080,37 @@ guswave_hw_control (int dev, unsigned char *event)
case _GUS_RAMPMODE:
if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
+ break; /*
+ * NO-NO
+ */
DISABLE_INTR (flags);
gus_select_voice (voice);
- p1 &= ~0x20; /* Disable intr */
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
gus_ramp_mode (p1);
RESTORE_INTR (flags);
break;
case _GUS_RAMPON:
if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
+ break; /*
+ * NO-NO
+ */
DISABLE_INTR (flags);
gus_select_voice (voice);
- p1 &= ~0x20; /* Disable intr */
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
gus_rampon (p1);
RESTORE_INTR (flags);
break;
case _GUS_RAMPOFF:
if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
+ break; /*
+ * NO-NO
+ */
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_rampoff ();
@@ -1643,6 +2122,13 @@ guswave_hw_control (int dev, unsigned char *event)
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:;
}
}
@@ -1710,6 +2196,8 @@ gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
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;
@@ -1730,7 +2218,9 @@ gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
return gus_sampling_bits;
return IOCTL_OUT (arg, gus_sampling_bits);
- case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */
+ case SOUND_PCM_WRITE_FILTER: /*
+ * NOT YET IMPLEMENTED
+ */
return IOCTL_OUT (arg, RET_ERROR (EINVAL));
break;
@@ -1760,6 +2250,8 @@ gus_sampling_open (int dev, int mode)
if (gus_busy)
return RET_ERROR (EBUSY);
+ gus_initialize ();
+
gus_busy = 1;
active_device = 0;
@@ -1767,10 +2259,13 @@ gus_sampling_open (int dev, int mode)
reset_sample_memory ();
gus_select_max_voices (14);
- gus_sampling_set_bits (8);
- gus_sampling_set_channels (1);
- gus_sampling_set_speed (DSP_DEFAULT_SPEED);
pcm_active = 0;
+ pcm_opened = 1;
+ if (mode & OPEN_READ)
+ {
+ recording_active = 1;
+ set_input_volumes ();
+ }
return 0;
}
@@ -1780,7 +2275,31 @@ gus_sampling_close (int dev)
{
gus_reset ();
gus_busy = 0;
+ pcm_opened = 0;
active_device = 0;
+
+ if (recording_active)
+ set_input_volumes ();
+
+ recording_active = 0;
+}
+
+static 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);
}
static void
@@ -1800,18 +2319,24 @@ play_next_pcm_block (void)
for (chn = 0; chn < gus_sampling_channels; chn++)
{
mode[chn] = 0x00;
- ramp_mode[chn] = 0x03; /* Ramping and rollover off */
+ ramp_mode[chn] = 0x03; /*
+ * Ramping and rollover off
+ */
if (chn == 0)
{
- mode[chn] |= 0x20; /* Loop irq */
+ 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 */
+ mode[chn] |= 0x04; /*
+ * 16 bit data
+ */
}
else
is16bits = 0;
@@ -1819,15 +2344,23 @@ play_next_pcm_block (void)
dram_loc = this_one * pcm_bsize;
dram_loc += chn * pcm_banksize;
- if (this_one == (pcm_nblk - 1)) /* Last of the DRAM buffers */
+ if (this_one == (pcm_nblk - 1)) /*
+ * Last of the DRAM buffers
+ */
{
- mode[chn] |= 0x08; /* Enable loop */
- ramp_mode[chn] = 0x03;/* Disable rollover */
+ mode[chn] |= 0x08; /*
+ * Enable loop
+ */
+ ramp_mode[chn] = 0x03; /*
+ * Disable rollover
+ */
}
else
{
if (chn == 0)
- ramp_mode[chn] = 0x04; /* Enable rollover bit */
+ ramp_mode[chn] = 0x04; /*
+ * Enable rollover bit
+ */
}
DISABLE_INTR (flags);
@@ -1835,53 +2368,90 @@ play_next_pcm_block (void)
gus_voice_freq (speed);
if (gus_sampling_channels == 1)
- gus_voice_balance (7); /* mono */
+ gus_voice_balance (7); /*
+ * mono
+ */
else if (chn == 0)
- gus_voice_balance (0); /* left */
+ gus_voice_balance (0); /*
+ * left
+ */
else
- gus_voice_balance (15); /* right */
+ gus_voice_balance (15); /*
+ * right
+ */
- if (!pcm_active) /* Voice not started yet */
+ if (!pcm_active) /*
+ * Voice not started yet
+ */
{
- /*
+ /*
* 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 (); /* It could already be running */
+ gus_voice_off (); /*
+ * It could already be running
+ */
gus_rampoff ();
- gus_voice_volume (4000);
- gus_ramp_range (65, 4030);
+ 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 location */
+ gus_write_addr (0x0a, dram_loc, is16bits); /*
+ * Starting position
+ */
+ gus_write_addr (0x02, chn * pcm_banksize, is16bits); /*
+ * Loop start
+ * location
+ */
if (chn != 0)
gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk),
- is16bits); /* Loop end location */
+ is16bits); /*
+ * Loop end location
+ */
}
if (chn == 0)
- gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* Loop end location */
+ gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /*
+ * Loop
+ * end
+ * location
+ */
else
- mode[chn] |= 0x08; /* Enable loop */
+ mode[chn] |= 0x08; /*
+ * Enable loop
+ */
if (pcm_datasize[this_one] != pcm_bsize)
{
- /* Incomplete block. Possibly the last one. */
+ /*
+ * Incomplete block. Possibly the last one.
+ */
if (chn == 0)
{
- mode[chn] &= ~0x08; /* Disable loop */
- mode[chn] |= 0x20;/* Enable loop IRQ */
+ mode[chn] &= ~0x08; /*
+ * Disable loop
+ */
+ mode[chn] |= 0x20; /*
+ * Enable loop IRQ
+ */
voices[0].loop_irq_mode = LMODE_PCM_STOP;
- ramp_mode[chn] = 0x03; /* No rollover bit */
+ 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 loop */
+ gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /*
+ * Loop
+ * end
+ * location
+ */
+ mode[chn] &= ~0x08; /*
+ * Disable loop
+ */
}
}
@@ -1904,7 +2474,7 @@ static void
gus_transfer_output_block (int dev, unsigned 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.
@@ -1935,7 +2505,9 @@ gus_transfer_output_block (int dev, unsigned long buf,
else
this_one = pcm_current_block;
- gus_write8 (0x41, 0); /* Disable GF1 DMA */
+ gus_write8 (0x41, 0); /*
+ * Disable GF1 DMA
+ */
DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE);
address = this_one * pcm_bsize;
@@ -1949,38 +2521,56 @@ gus_transfer_output_block (int dev, unsigned long buf,
address |= (hold_address & 0x000c0000L);
}
- gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
+ gus_write16 (0x42, (address >> 4) & 0xffff); /*
+ * DRAM DMA address
+ */
- dma_command = 0x21; /* IRQ enable, DMA start */
+ dma_command = 0x21; /*
+ * IRQ enable, DMA start
+ */
if (gus_sampling_bits != 8)
- dma_command |= 0x40; /* 16 bit _DATA_ */
+ dma_command |= 0x40; /*
+ * 16 bit _DATA_
+ */
else
- dma_command |= 0x80; /* Invert MSB */
+ dma_command |= 0x80; /*
+ * Invert MSB
+ */
if (sound_dsp_dmachan[dev] > 3)
- dma_command |= 0x04; /* 16 bit DMA channel */
+ dma_command |= 0x04; /*
+ * 16 bit DMA channel
+ */
- gus_write8 (0x41, dma_command); /* Kick on */
+ gus_write8 (0x41, dma_command); /*
+ * Kick on
+ */
- if (chn == (gus_sampling_channels - 1)) /* Last channel */
+ if (chn == (gus_sampling_channels - 1)) /*
+ * Last channel
+ */
{
- /* Last (right or mono) channel data */
+ /*
+ * Last (right or mono) channel data
+ */
active_device = GUS_DEV_PCM_DONE;
if (!pcm_active && (pcm_qlen > 2 || count < pcm_bsize))
{
play_next_pcm_block ();
}
}
- else /* Left channel data. The right channel is
- * transferred after DMA interrupt */
+ else /*
+ * * * Left channel data. The right channel
+ * is * * * transferred after DMA interrupt */
active_device = GUS_DEV_PCM_CONTINUE;
RESTORE_INTR (flags);
}
static void
-gus_sampling_output_block (int dev, unsigned long buf, int total_count, int intrflag)
+gus_sampling_output_block (int dev, unsigned long buf, int total_count,
+ int intrflag, int restart_dma)
{
pcm_current_buf = buf;
pcm_current_count = total_count;
@@ -1990,7 +2580,8 @@ gus_sampling_output_block (int dev, unsigned long buf, int total_count, int intr
}
static void
-gus_sampling_start_input (int dev, unsigned long buf, int count, int intrflag)
+gus_sampling_start_input (int dev, unsigned long buf, int count,
+ int intrflag, int restart_dma)
{
unsigned long flags;
unsigned char mode;
@@ -1999,13 +2590,21 @@ gus_sampling_start_input (int dev, unsigned long buf, int count, int intrflag)
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
- mode = 0xa0; /* DMA IRQ enable, invert MSB */
+ mode = 0xa0; /*
+ * DMA IRQ enable, invert MSB
+ */
if (sound_dsp_dmachan[dev] > 3)
- mode |= 0x04; /* 16 bit DMA channel */
+ mode |= 0x04; /*
+ * 16 bit DMA channel
+ */
if (gus_sampling_channels > 1)
- mode |= 0x02; /* Stereo */
- mode |= 0x01; /* DMA enable */
+ mode |= 0x02; /*
+ * Stereo
+ */
+ mode |= 0x01; /*
+ * DMA enable
+ */
gus_write8 (0x49, mode);
@@ -2019,7 +2618,9 @@ gus_sampling_prepare_for_input (int dev, int bsize, int bcount)
rate = (9878400 / (gus_sampling_speed + 2)) / 16;
- gus_write8 (0x48, rate & 0xff); /* Set sampling frequency */
+ gus_write8 (0x48, rate & 0xff); /*
+ * Set sampling frequency
+ */
if (gus_sampling_bits != 8)
{
@@ -2072,7 +2673,9 @@ 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);
+ {
+ COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len);
+ }
else if (gus_sampling_bits == 8)
{
int in_left = useroffs;
@@ -2119,19 +2722,37 @@ gus_copy_from_user (int dev, char *localbuf, int localoffs,
static struct audio_operations gus_sampling_operations =
{
"Gravis UltraSound",
- 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, /* halt_xfer */
+ 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_has_output_drained,
gus_copy_from_user
};
+#ifdef FUTURE_VERSION
+static void
+guswave_bender (int dev, int voice, int value)
+{
+ 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;
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_voice_freq (freq);
+ RESTORE_INTR (flags);
+}
+#endif
+
static int
guswave_patchmgr (int dev, struct patmgr_info *rec)
{
@@ -2161,7 +2782,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
while (ptr >= 0 && ptr < free_sample)
{
rec->data.data8[i]++;
- ptr = samples[ptr].key; /* Follow link */
+ ptr = samples[ptr].key; /*
+ * Follow link
+ */
}
}
return 0;
@@ -2176,7 +2799,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
while (ptr >= 0 && ptr < free_sample)
{
rec->data.data32[n++] = ptr;
- ptr = samples[ptr].key; /* Follow link */
+ ptr = samples[ptr].key; /*
+ * Follow link
+ */
}
}
rec->parm1 = n;
@@ -2196,8 +2821,12 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
pat = (struct patch_info *) rec->data.data8;
- pat->key = GUS_PATCH; /* Restore patch type */
- rec->parm1 = sample_ptrs[ptr]; /* DRAM address */
+ pat->key = GUS_PATCH; /*
+ * Restore patch type
+ */
+ rec->parm1 = sample_ptrs[ptr]; /*
+ * DRAM address
+ */
rec->parm2 = sizeof (struct patch_info);
}
return 0;
@@ -2213,10 +2842,14 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
pat = (struct patch_info *) rec->data.data8;
- if (pat->len > samples[ptr].len) /* Cannot expand sample */
+ if (pat->len > samples[ptr].len) /*
+ * Cannot expand sample
+ */
return RET_ERROR (EINVAL);
- pat->key = samples[ptr].key; /* Ensure the link is correct */
+ pat->key = samples[ptr].key; /*
+ * Ensure the link is correct
+ */
memcpy ((char *) &samples[ptr], rec->data.data8,
sizeof (struct patch_info));
@@ -2226,7 +2859,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
return 0;
break;
- case PM_READ_PATCH: /* Returns a block of wave data from the DRAM */
+ case PM_READ_PATCH: /*
+ * Returns a block of wave data from the DRAM
+ */
{
int sample = rec->parm1;
int n;
@@ -2237,9 +2872,13 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
return RET_ERROR (EINVAL);
if (offs < 0 || offs >= samples[sample].len)
- return RET_ERROR (EINVAL); /* Invalid offset */
+ return RET_ERROR (EINVAL); /*
+ * Invalid offset
+ */
- n = samples[sample].len - offs; /* Nr of bytes left */
+ n = samples[sample].len - offs; /*
+ * Nr of bytes left
+ */
if (l > n)
l = n;
@@ -2248,18 +2887,26 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
l = sizeof (rec->data.data8);
if (l <= 0)
- return RET_ERROR (EINVAL); /* Was there a bug? */
+ return RET_ERROR (EINVAL); /*
+ * Was there a bug?
+ */
- offs += sample_ptrs[sample]; /* Begin offsess + offset to DRAM */
+ 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 */
+ rec->parm1 = n; /*
+ * Nr of bytes copied
+ */
}
return 0;
break;
- case PM_WRITE_PATCH: /* Writes a block of wave data to the DRAM */
+ case PM_WRITE_PATCH: /*
+ * Writes a block of wave data to the DRAM
+ */
{
int sample = rec->parm1;
int n;
@@ -2270,9 +2917,13 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
return RET_ERROR (EINVAL);
if (offs < 0 || offs >= samples[sample].len)
- return RET_ERROR (EINVAL); /* Invalid offset */
+ return RET_ERROR (EINVAL); /*
+ * Invalid offset
+ */
- n = samples[sample].len - offs; /* Nr of bytes left */
+ n = samples[sample].len - offs; /*
+ * Nr of bytes left
+ */
if (l > n)
l = n;
@@ -2281,13 +2932,19 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
l = sizeof (rec->data.data8);
if (l <= 0)
- return RET_ERROR (EINVAL); /* Was there a bug? */
+ return RET_ERROR (EINVAL); /*
+ * Was there a bug?
+ */
- offs += sample_ptrs[sample]; /* Begin offsess + offset to DRAM */
+ 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 */
+ rec->parm1 = n; /*
+ * Nr of bytes copied
+ */
}
return 0;
break;
@@ -2300,6 +2957,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
static struct synth_operations guswave_operations =
{
&gus_info,
+#ifdef FUTURE_VERSION
+ 0,
+#endif
SYNTH_TYPE_SAMPLE,
SAMPLE_TYPE_GUS,
guswave_open,
@@ -2314,13 +2974,188 @@ static struct synth_operations guswave_operations =
guswave_aftertouch,
guswave_controller,
guswave_panning,
- guswave_patchmgr
+ guswave_patchmgr,
+#ifdef FUTURE_VERSION
+ guswave_bender
+#endif
+};
+
+static void
+set_input_volumes (void)
+{
+ unsigned long flags;
+ unsigned char mask = 0xff & ~0x06; /* Just line out enabled */
+
+ DISABLE_INTR (flags);
+
+/*
+ * 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;
+ }
+
+ mix_image &= ~0x07;
+ mix_image |= mask & 0x07;
+ OUTB (mix_image, u_Mixer);
+
+ RESTORE_INTR (flags);
+}
+
+static int
+gus_mixer_ioctl (int dev, unsigned int cmd, unsigned int 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));
+ }
+ break;
+
+ 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_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_SYNTH:
+ {
+ int voice;
+
+ gus_wave_volume = IOCTL_IN (arg) & 0xff;
+
+ if (gus_wave_volume < 0)
+ gus_wave_volume = 0;
+ if (gus_wave_volume > 100)
+ gus_wave_volume = 100;
+
+ if (active_device == GUS_DEV_WAVE)
+ for (voice = 0; voice < nr_voices; voice++)
+ dynamic_volume_change (voice); /*
+ * Apply the new
+ * volume
+ */
+
+ return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
+ }
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ else
+ switch (cmd & 0xff) /*
+ * Return parameters
+ */
+ {
+
+ case SOUND_MIXER_RECSRC:
+ return IOCTL_OUT (arg, gus_recmask);
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return IOCTL_OUT (arg, MIX_DEVS);
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return IOCTL_OUT (arg, 0);
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return IOCTL_OUT (arg, 0);
+ break;
+
+ 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;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ }
+ else
+ return RET_ERROR (EINVAL);
+}
+
+static struct mixer_operations gus_mixer_operations =
+{
+ gus_mixer_ioctl
};
long
gus_wave_init (long mem_start, int irq, int dma)
{
- printk ("snd4: <Gravis UltraSound %dk>", gus_mem_size / 1024);
+ printk ("snd4: <Gravis UltraSound %dk>", (int) gus_mem_size / 1024);
if (irq < 0 || irq > 15)
{
@@ -2342,6 +3177,9 @@ gus_wave_init (long mem_start, int irq, int dma)
else
synth_devs[num_synths++] = &guswave_operations;
+ PERMANENT_MALLOC (struct patch_info *, samples,
+ (MAX_SAMPLE + 1) * sizeof (*samples), mem_start);
+
reset_sample_memory ();
gus_initialize ();
@@ -2357,6 +3195,12 @@ gus_wave_init (long mem_start, int irq, int dma)
else
printk ("GUS: Too many PCM devices available\n");
+ if (num_mixers < MAX_MIXER_DEV) /*
+ * Don't install if there is another
+ * mixer
+ */
+ mixer_devs[num_mixers++] = &gus_mixer_operations;
+
return mem_start;
}
@@ -2371,7 +3215,9 @@ do_loop_irq (int voice)
gus_select_voice (voice);
tmp = gus_read8 (0x00);
- tmp &= ~0x20; /* Disable wave IRQ for this_one voice */
+ tmp &= ~0x20; /*
+ * Disable wave IRQ for this_one voice
+ */
gus_write8 (0x00, tmp);
mode = voices[voice].loop_irq_mode;
@@ -2381,23 +3227,33 @@ do_loop_irq (int voice)
switch (mode)
{
- case LMODE_FINISH: /* Final loop finished, shoot volume down */
+ case LMODE_FINISH: /*
+ * Final loop finished, shoot volume down
+ */
- if ((gus_read16 (0x09) >> 4) < 100) /* Get current volume */
+ if ((gus_read16 (0x09) >> 4) < 100) /*
+ * Get current volume
+ */
{
gus_voice_off ();
gus_rampoff ();
gus_voice_init (voice);
- return;
+ break;
}
gus_ramp_range (65, 4065);
- gus_ramp_rate (0, 63); /* Fastest possible rate */
- gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */
+ 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; /* Requires extensive processing */
+ pcm_active = 0; /*
+ * Requires extensive processing
+ */
case LMODE_PCM:
{
int orig_qlen = pcm_qlen;
@@ -2409,7 +3265,9 @@ do_loop_irq (int voice)
play_next_pcm_block ();
}
else
- { /* Out of data. Just stop the voice */
+ { /*
+ * Out of data. Just stop the voice
+ */
gus_voice_off ();
gus_rampoff ();
pcm_active = 0;
@@ -2417,7 +3275,7 @@ do_loop_irq (int voice)
if (orig_qlen == pcm_nblk)
{
- DMAbuf_outputintr (gus_devnum);
+ DMAbuf_outputintr (gus_devnum, 0);
}
}
break;
@@ -2439,7 +3297,9 @@ do_volume_irq (int voice)
gus_select_voice (voice);
tmp = gus_read8 (0x0d);
- tmp &= ~0x20; /* Disable volume ramp IRQ */
+ tmp &= ~0x20; /*
+ * Disable volume ramp IRQ
+ */
gus_write8 (0x0d, tmp);
mode = voices[voice].volume_irq_mode;
@@ -2448,7 +3308,9 @@ do_volume_irq (int voice)
switch (mode)
{
- case VMODE_HALT: /* Decay phase finished */
+ case VMODE_HALT: /*
+ * Decay phase finished
+ */
gus_voice_init (voice);
break;
@@ -2457,6 +3319,19 @@ do_volume_irq (int voice)
step_envelope (voice);
break;
+ case VMODE_START_NOTE:
+ 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, 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:;
}
@@ -2473,24 +3348,38 @@ gus_voice_irq (void)
while (1)
{
- src = gus_read8 (0x0f); /* Get source info */
+ src = gus_read8 (0x0f); /*
+ * Get source info
+ */
voice = src & 0x1f;
src &= 0xc0;
if (src == (0x80 | 0x40))
- return; /* No interrupt */
+ return; /*
+ * No interrupt
+ */
voice_bit = 1 << voice;
- if (!(src & 0x80)) /* Wave IRQ pending */
- if (!(wave_ignore & voice_bit) && voice < nr_voices) /* Not done yet */
+ if (!(src & 0x80)) /*
+ * Wave IRQ pending
+ */
+ if (!(wave_ignore & voice_bit) && 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) && voice < nr_voices) /* Not done yet */
+ if (!(src & 0x40)) /*
+ * Volume IRQ pending
+ */
+ if (!(volume_ignore & voice_bit) && voice < nr_voices) /*
+ * Not done
+ * yet
+ */
{
volume_ignore |= voice_bit;
do_volume_irq (voice);
@@ -2503,13 +3392,17 @@ guswave_dma_irq (void)
{
unsigned char status;
- status = gus_look8 (0x41); /* Get DMA IRQ Status */
- if (status & 0x40) /* DMA Irq pending */
+ status = gus_look8 (0x41); /*
+ * Get DMA IRQ Status
+ */
+ if (status & 0x40) /*
+ * DMA Irq pending
+ */
switch (active_device)
{
case GUS_DEV_WAVE:
- if (dram_sleep_flag)
- WAKE_UP (dram_sleeper);
+ if (SOMEONE_WAITING (dram_sleeper, dram_sleep_flag))
+ WAKE_UP (dram_sleeper, dram_sleep_flag);
break;
case GUS_DEV_PCM_CONTINUE:
@@ -2521,15 +3414,19 @@ guswave_dma_irq (void)
case GUS_DEV_PCM_DONE:
if (pcm_qlen < pcm_nblk)
{
- DMAbuf_outputintr (gus_devnum);
+ DMAbuf_outputintr (gus_devnum, pcm_qlen == 0);
}
break;
default:;
}
- status = gus_look8 (0x49); /* Get Sampling IRQ Status */
- if (status & 0x40) /* Sampling Irq pending */
+ status = gus_look8 (0x49); /*
+ * Get Sampling IRQ Status
+ */
+ if (status & 0x40) /*
+ * Sampling Irq pending
+ */
{
DMAbuf_inputintr (gus_devnum);
}
OpenPOWER on IntegriCloud