diff options
author | swallace <swallace@FreeBSD.org> | 1994-03-11 10:27:25 +0000 |
---|---|---|
committer | swallace <swallace@FreeBSD.org> | 1994-03-11 10:27:25 +0000 |
commit | 0c4addc896f5d9665b20572130047785a136c047 (patch) | |
tree | afd23eb03a99a10a280a5b897644ade0e01050a8 /sys/i386/isa/sound/gus_wave.c | |
parent | cc04fd6ad5dcc912d19e2422142eb7ba973e88da (diff) | |
download | FreeBSD-src-0c4addc896f5d9665b20572130047785a136c047.zip FreeBSD-src-0c4addc896f5d9665b20572130047785a136c047.tar.gz |
Integrated Hannu Savolainen's new VoxWare sound drivers, version 2.4.
These drivers now have full SoundBlaster 16 support.
Diffstat (limited to 'sys/i386/isa/sound/gus_wave.c')
-rw-r--r-- | sys/i386/isa/sound/gus_wave.c | 1705 |
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); } |