home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * sound/gus_wave.c
- *
- * Driver for the Gravis UltraSound wave table synth.
- *
- * Copyright by Hannu Savolainen 1993
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
- #include "sound_config.h"
- #include <linux/ultrasound.h>
- #include "gus_hw.h"
-
- #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
-
- #define MAX_SAMPLE 128
- #define MAX_PATCH 256
-
- struct voice_info
- {
- unsigned long orig_freq;
- unsigned long current_freq;
- unsigned long mode;
- int bender;
- int bender_range;
- int panning;
- int midi_volume;
- unsigned int initial_volume;
- unsigned int current_volume;
- int loop_irq_mode, loop_irq_parm;
- #define LMODE_FINISH 1
- #define LMODE_PCM 2
- #define LMODE_PCM_STOP 3
- 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;
- extern int gus_irq, gus_dma;
- extern char *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT];
- extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];
- 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;
- 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;
- int gus_pcm_volume = 80;
- static unsigned char mix_image = 0x00;
-
- /*
- * 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 */
-
- static int gus_sampling_speed;
- static int gus_sampling_channels;
- static int gus_sampling_bits;
-
- DEFINE_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
-
- /*
- * Variables and buffers for PCM output
- */
- #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;
- static int pcm_current_count;
- static int pcm_current_intrflag;
-
- 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
- */
- };
-
- static struct patch_info *samples;
- static long sample_ptrs[MAX_SAMPLE + 1];
- static int sample_map[32];
- static int free_sample;
-
-
- static int patch_table[MAX_PATCH];
- static int patch_map[32];
-
- static struct synth_info gus_info =
- {"Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH};
-
- static void gus_poke (long addr, unsigned char data);
- static void compute_and_set_volume (int voice, int volume, int ramp_time);
- extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev);
- 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 */
-
- static void
- reset_sample_memory (void)
- {
- int i;
-
- for (i = 0; i <= MAX_SAMPLE; i++)
- sample_ptrs[i] = -1;
- for (i = 0; i < 32; i++)
- sample_map[i] = -1;
- for (i = 0; i < 32; i++)
- patch_map[i] = -1;
-
- gus_poke (0, 0); /*
- * Put silence here
- */
- gus_poke (1, 0);
-
- free_mem_ptr = 2;
- free_sample = 0;
-
- for (i = 0; i < MAX_PATCH; i++)
- patch_table[i] = -1;
- }
-
- void
- gus_delay (void)
- {
- int i;
-
- for (i = 0; i < 7; i++)
- INB (u_DRAMIO);
- }
-
- static void
- gus_poke (long addr, unsigned char data)
- {
- unsigned long flags;
-
- DISABLE_INTR (flags);
- OUTB (0x43, u_Command);
- OUTB (addr & 0xff, u_DataLo);
- OUTB ((addr >> 8) & 0xff, u_DataHi);
-
- OUTB (0x44, u_Command);
- OUTB ((addr >> 16) & 0xff, u_DataHi);
- OUTB (data, u_DRAMIO);
- RESTORE_INTR (flags);
- }
-
- static unsigned char
- gus_peek (long addr)
- {
- unsigned long flags;
- unsigned char tmp;
-
- DISABLE_INTR (flags);
- OUTB (0x43, u_Command);
- OUTB (addr & 0xff, u_DataLo);
- OUTB ((addr >> 8) & 0xff, u_DataHi);
-
- OUTB (0x44, u_Command);
- OUTB ((addr >> 16) & 0xff, u_DataHi);
- tmp = INB (u_DRAMIO);
- RESTORE_INTR (flags);
-
- return tmp;
- }
-
- void
- gus_write8 (int reg, unsigned int data)
- {
- unsigned long flags;
-
- DISABLE_INTR (flags);
-
- OUTB (reg, u_Command);
- OUTB ((unsigned char) (data & 0xff), u_DataHi);
-
- RESTORE_INTR (flags);
- }
-
- unsigned char
- gus_read8 (int reg)
- {
- unsigned long flags;
- unsigned char val;
-
- DISABLE_INTR (flags);
- OUTB (reg | 0x80, u_Command);
- val = INB (u_DataHi);
- RESTORE_INTR (flags);
-
- return val;
- }
-
- unsigned char
- gus_look8 (int reg)
- {
- unsigned long flags;
- unsigned char val;
-
- DISABLE_INTR (flags);
- OUTB (reg, u_Command);
- val = INB (u_DataHi);
- RESTORE_INTR (flags);
-
- return val;
- }
-
- void
- gus_write16 (int reg, unsigned int data)
- {
- unsigned long flags;
-
- DISABLE_INTR (flags);
-
- OUTB (reg, u_Command);
-
- OUTB ((unsigned char) (data & 0xff), u_DataLo);
- OUTB ((unsigned char) ((data >> 8) & 0xff), u_DataHi);
-
- RESTORE_INTR (flags);
- }
-
- unsigned short
- gus_read16 (int reg)
- {
- unsigned long flags;
- unsigned char hi, lo;
-
- DISABLE_INTR (flags);
-
- OUTB (reg | 0x80, u_Command);
-
- lo = INB (u_DataLo);
- hi = INB (u_DataHi);
-
- RESTORE_INTR (flags);
-
- return ((hi << 8) & 0xff00) | lo;
- }
-
- void
- gus_write_addr (int reg, unsigned long address, int is16bit)
- {
- unsigned long hold_address;
-
- if (is16bit)
- {
- /*
- * Special processing required for 16 bit patches
- */
-
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
-
- gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
- gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
- }
-
- static void
- gus_select_voice (int voice)
- {
- if (voice < 0 || voice > 31)
- return;
-
- OUTB (voice, u_Voice);
- }
-
- static void
- gus_select_max_voices (int nvoices)
- {
- if (nvoices < 14)
- nvoices = 14;
- if (nvoices > 32)
- nvoices = 32;
-
- nr_voices = nvoices;
-
- gus_write8 (0x0e, (nvoices - 1) | 0xc0);
- }
-
- static void
- gus_voice_on (unsigned int mode)
- {
- gus_write8 (0x00, (unsigned char) (mode & 0xfc));
- gus_delay ();
- gus_write8 (0x00, (unsigned char) (mode & 0xfc));
- }
-
- static void
- gus_voice_off (void)
- {
- gus_write8 (0x00, gus_read8 (0x00) | 0x03);
- }
-
- static void
- 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));
- }
-
- static void
- gus_voice_freq (unsigned long freq)
- {
- unsigned long divisor = freq_div_table[nr_voices - 14];
- unsigned short fc;
-
- fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor);
- fc = fc << 1;
-
- gus_write16 (0x01, fc);
- }
-
- static void
- gus_voice_volume (unsigned int vol)
- {
- gus_write8 (0x0d, 0x03); /*
- * Stop ramp before setting volume
- */
- gus_write16 (0x09, (unsigned short) (vol << 4));
- }
-
- static void
- gus_voice_balance (unsigned int balance)
- {
- gus_write8 (0x0c, (unsigned char) (balance & 0xff));
- }
-
- static void
- gus_ramp_range (unsigned int low, unsigned int high)
- {
- gus_write8 (0x07, (unsigned char) ((low >> 4) & 0xff));
- gus_write8 (0x08, (unsigned char) ((high >> 4) & 0xff));
- }
-
- static void
- gus_ramp_rate (unsigned int scale, unsigned int rate)
- {
- gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));
- }
-
- static void
- 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 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));
- }
-
- static void
- gus_rampoff (void)
- {
- gus_write8 (0x0d, 0x03);
- }
-
- 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;
-
- 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
- */
- RESTORE_INTR (flags);
-
- }
-
- static void
- gus_voice_init2 (int voice)
- {
- voices[voice].panning = 0;
- voices[voice].mode = 0;
- voices[voice].orig_freq = 20000;
- voices[voice].current_freq = 20000;
- voices[voice].bender = 0;
- voices[voice].bender_range = 200;
- voices[voice].initial_volume = 0;
- voices[voice].current_volume = 0;
- voices[voice].loop_irq_mode = 0;
- voices[voice].loop_irq_parm = 0;
- voices[voice].volume_irq_mode = 0;
- voices[voice].volume_irq_parm = 0;
- voices[voice].env_phase = 0;
- voices[voice].main_vol = 127;
- voices[voice].patch_vol = 127;
- voices[voice].expression_vol = 127;
- voices[voice].sample_pending = -1;
- }
-
- static void
- step_envelope (int voice)
- {
- unsigned vol, prev_vol, phase;
- unsigned char rate;
-
- if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)
- {
- gus_rampoff ();
- return; /*
- * Sustain
- */
- }
-
- if (voices[voice].env_phase >= 5)
- {
- /*
- * Shoot the voice off
- */
-
- gus_voice_init (voice);
- return;
- }
-
- prev_vol = voices[voice].current_volume;
- gus_voice_volume (prev_vol);
- phase = ++voices[voice].env_phase;
-
- compute_volume (voice, voices[voice].midi_volume);
-
- vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
- rate = voices[voice].env_rate[phase];
- gus_write8 (0x06, rate); /*
- * Ramping rate
- */
-
- voices[voice].volume_irq_mode = VMODE_ENVELOPE;
-
- if (((vol - prev_vol) / 64) == 0) /*
- * No significant volume change
- */
- {
- step_envelope (voice); /*
- * Continue with the next phase
- */
- return;
- }
-
- if (vol > prev_vol)
- {
- if (vol >= (4096 - 64))
- vol = 4096 - 65;
- gus_ramp_range (0, vol);
- gus_rampon (0x20); /*
- * Increasing, irq
- */
- }
- else
- {
- if (vol <= 64)
- vol = 65;
- gus_ramp_range (vol, 4030);
- gus_rampon (0x60); /*
- * Decreasing, irq
- */
- }
- voices[voice].current_volume = vol;
- }
-
- static void
- init_envelope (int voice)
- {
- voices[voice].env_phase = -1;
- voices[voice].current_volume = 64;
-
- step_envelope (voice);
- }
-
- static void
- start_release (int voice)
- {
- if (gus_read8 (0x00) & 0x03)
- return; /*
- * Voice already stopped
- */
-
- 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
- */
-
- voices[voice].mode &= ~WAVE_SUSTAIN_ON;
- gus_rampoff ();
- step_envelope (voice);
- }
-
- static void
- gus_voice_fade (int voice)
- {
- int instr_no = sample_map[voice], is16bits;
-
- if (instr_no < 0 || instr_no > MAX_SAMPLE)
- {
- gus_write8 (0x00, 0x03); /*
- * Hard stop
- */
- return;
- }
-
- is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /*
- * 8 or 16
- * bit
- * samples
- */
-
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- start_release (voice);
- return;
- }
-
- /*
- * Ramp the volume down but not too quickly.
- */
- if ((gus_read16 (0x09) >> 4) < 100) /*
- * Get current volume
- */
- {
- gus_voice_off ();
- gus_rampoff ();
- gus_voice_init (voice);
- return;
- }
-
- gus_ramp_range (65, 4030);
- gus_ramp_rate (2, 4);
- gus_rampon (0x40 | 0x20); /*
- * Down, once, irq
- */
- voices[voice].volume_irq_mode = VMODE_HALT;
- }
-
- static void
- gus_reset (void)
- {
- int i;
-
- gus_select_max_voices (24);
- volume_base = 3071;
- volume_scale = 4;
- volume_method = VOL_METHOD_ADAGIO;
-
- for (i = 0; i < 32; i++)
- {
- gus_voice_init (i); /*
- * Turn voice off
- */
- gus_voice_init2 (i);
- }
-
- 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
- */
-
- }
-
- static void
- gus_initialize (void)
- {
- unsigned long flags;
- unsigned char dma_image, irq_image, tmp;
-
- static unsigned char gus_irq_map[16] =
- {0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7};
-
- static unsigned char gus_dma_map[8] =
- {0, 1, 0, 2, 0, 3, 4, 5};
-
- DISABLE_INTR (flags);
-
- gus_write8 (0x4c, 0); /*
- * Reset GF1
- */
- gus_delay ();
- gus_delay ();
-
- 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_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
- */
-
- /*
- * Set up for Digital ASIC
- */
-
- OUTB (0x05, gus_base + 0x0f);
-
- 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.
- *
- * 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.
- */
-
- irq_image = 0;
- tmp = gus_irq_map[gus_irq];
- if (!tmp)
- printk ("Warning! GUS IRQ not selected\n");
- irq_image |= tmp;
- irq_image |= 0x40; /*
- * Combine IRQ1 (GF1) and IRQ2 (Midi)
- */
-
- 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 | 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
- */
-
- 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 */
- gus_delay ();
- gus_delay ();
-
- gus_write8 (0x4c, 1); /* Release Reset */
- gus_delay ();
- gus_delay ();
-
- /* See if there is first block there.... */
- gus_poke (0L, 0xaa);
- if (gus_peek (0L) != 0xaa)
- return (0);
-
- /* Now zero it out so that I can check for mirroring .. */
- gus_poke (0L, 0x00);
- for (i = 1L; i < 1024L; i++)
- {
- int n, failed;
-
- /* check for mirroring ... */
- if (gus_peek (0L) != 0)
- break;
- loc = i << 10;
-
- for (n = loc - 1, failed = 0; n <= loc; n++)
- {
- gus_poke (loc, 0xaa);
- if (gus_peek (loc) != 0xaa)
- failed = 1;
-
- gus_poke (loc, 0x55);
- if (gus_peek (loc) != 0x55)
- failed = 1;
- }
-
- if (failed)
- break;
- }
- gus_mem_size = i << 10;
- return 1;
- }
-
- static int
- guswave_ioctl (int dev,
- unsigned int cmd, unsigned int arg)
- {
-
- switch (cmd)
- {
- case SNDCTL_SYNTH_INFO:
- gus_info.nr_voices = nr_voices;
- IOCTL_TO_USER ((char *) arg, 0, &gus_info, sizeof (gus_info));
- return 0;
- break;
-
- case SNDCTL_SEQ_RESETSAMPLES:
- reset_sample_memory ();
- return 0;
- break;
-
- case SNDCTL_SEQ_PERCMODE:
- return 0;
- break;
-
- case SNDCTL_SYNTH_MEMAVL:
- return gus_mem_size - free_mem_ptr - 32;
-
- default:
- return RET_ERROR (EINVAL);
- }
- }
-
- static int
- guswave_set_instr (int dev, int voice, int instr_no)
- {
- int sample_no;
-
- if (instr_no < 0 || instr_no > MAX_PATCH)
- return RET_ERROR (EINVAL);
-
- if (voice < 0 || voice > 31)
- return RET_ERROR (EINVAL);
-
- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
- {
- voices[voice].sample_pending = instr_no;
- return 0;
- }
-
- sample_no = patch_table[instr_no];
- patch_map[voice] = -1;
-
- if (sample_no < 0)
- {
- printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
- return RET_ERROR (EINVAL); /*
- * Patch not defined
- */
- }
-
- if (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);
- }
-
- sample_map[voice] = sample_no;
- patch_map[voice] = instr_no;
- return 0;
- }
-
- 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);
- 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;
- }
-
- static void
- guswave_aftertouch (int dev, int voice, int pressure)
- {
- short lo_limit, hi_limit;
- unsigned long flags;
-
- 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
- */
-
- if (pressure < 32)
- {
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_rampoff ();
- compute_and_set_volume (voice, 255, 0); /*
- * Back to original volume
- */
- RESTORE_INTR (flags);
- return;
- }
-
- hi_limit = voices[voice].current_volume;
- lo_limit = hi_limit * 99 / 100;
- if (lo_limit < 65)
- lo_limit = 65;
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- if (hi_limit > (4095 - 65))
- {
- hi_limit = 4095 - 65;
- gus_voice_volume (hi_limit);
- }
- gus_ramp_range (lo_limit, hi_limit);
- gus_ramp_rate (3, 8);
- gus_rampon (0x58); /*
- * Bidirectional, Down, Loop
- */
- RESTORE_INTR (flags);
- }
-
- static void
- guswave_panning (int dev, int voice, int value)
- {
- if (voice >= 0 || voice < 32)
- voices[voice].panning = value;
- }
-
- static void
- compute_volume (int voice, int volume)
- {
- if (volume < 128)
- voices[voice].midi_volume = volume;
-
- 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 +
- (voices[voice].midi_volume * volume_scale);
- }
-
- 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;
-
- current = gus_read16 (0x09) >> 4;
- target = voices[voice].initial_volume;
-
- if (ramp_time == INSTANT_RAMP)
- {
- gus_rampoff ();
- gus_voice_volume (target);
- RESTORE_INTR (flags);
- return;
- }
-
- if (ramp_time == FAST_RAMP)
- rate = 63;
- else
- rate = 16;
- gus_ramp_rate (0, rate);
-
- if ((target - current) / 64 == 0) /*
- * Too close
- */
- {
- gus_rampoff ();
- gus_voice_volume (target);
- RESTORE_INTR (flags);
- return;
- }
-
- if (target > current)
- {
- if (target > (4095 - 65))
- target = 4095 - 65;
- gus_ramp_range (current, target);
- gus_rampon (0x00); /*
- * Ramp up, once, no irq
- */
- }
- else
- {
- if (target < 65)
- target = 65;
-
- gus_ramp_range (target, current);
- gus_rampon (0x40); /*
- * Ramp down, once, no irq
- */
- }
- RESTORE_INTR (flags);
- }
-
- static void
- dynamic_volume_change (int voice)
- {
- unsigned char status;
- unsigned long flags;
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- status = gus_read8 (0x00); /*
- * Voice status
- */
- RESTORE_INTR (flags);
-
- if (status & 0x03)
- return; /*
- * Voice not started
- */
-
- if (!(voices[voice].mode & WAVE_ENVELOPES))
- {
- compute_and_set_volume (voice, voices[voice].midi_volume, 1);
- return;
- }
-
- /*
- * Voice is running and has envelopes.
- */
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- status = gus_read8 (0x0d); /*
- * Ramping status
- */
- RESTORE_INTR (flags);
-
- if (status & 0x03) /*
- * Sustain phase?
- */
- {
- compute_and_set_volume (voice, voices[voice].midi_volume, 1);
- return;
- }
-
- if (voices[voice].env_phase < 0)
- return;
-
- compute_volume (voice, voices[voice].midi_volume);
-
- #if 0 /*
- * * * Is this really required */
- voices[voice].current_volume =
- gus_read16 (0x09) >> 4; /*
- * Get current volume
- */
-
- voices[voice].env_phase--;
- step_envelope (voice);
- #endif
- }
-
- static void
- guswave_controller (int dev, int voice, int ctrl_num, int value)
- {
- unsigned long flags;
- unsigned long freq;
-
- if (voice < 0 || voice > 31)
- return;
-
- switch (ctrl_num)
- {
- case CTRL_PITCH_BENDER:
- voices[voice].bender = value;
-
- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
- {
- freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
- voices[voice].current_freq = freq;
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_freq (freq);
- RESTORE_INTR (flags);
- }
- break;
-
- case CTRL_PITCH_BENDER_RANGE:
- voices[voice].bender_range = value;
- break;
- #ifdef FUTURE_VERSION
- case CTL_EXPRESSION:
- value /= 128;
- #endif
- case CTRL_EXPRESSION:
- volume_method = VOL_METHOD_ADAGIO;
- voices[voice].expression_vol = value;
- 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;
- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
- dynamic_volume_change (voice);
- break;
-
- default: /*
- * Ignore
- */
- break;
- }
- }
-
- static int
- guswave_start_note2 (int dev, int voice, int note_num, int volume)
- {
- int sample, best_sample, best_delta, delta_freq;
- int is16bits, samplep, patch, pan;
- unsigned long note_freq, base_note, freq, flags;
- unsigned char mode = 0;
-
- if (voice < 0 || voice > 31)
- {
- printk ("GUS: Invalid voice\n");
- return RET_ERROR (EINVAL);
- }
-
- if (note_num == 255)
- {
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- voices[voice].midi_volume = volume;
- dynamic_volume_change (voice);
- return 0;
- }
-
- compute_and_set_volume (voice, volume, 1);
- return 0;
- }
-
- if ((patch = patch_map[voice]) == -1)
- {
- return RET_ERROR (EINVAL);
- }
-
- if ((samplep = patch_table[patch]) == -1)
- {
- return RET_ERROR (EINVAL);
- }
-
- note_freq = note_to_freq (note_num);
-
- /*
- * Find a sample within a patch so that the note_freq is between low_note
- * and high_note.
- */
- sample = -1;
-
- best_sample = samplep;
- best_delta = 1000000;
- while (samplep >= 0 && sample == -1)
- {
- delta_freq = note_freq - samples[samplep].base_note;
- if (delta_freq < 0)
- delta_freq = -delta_freq;
- if (delta_freq < best_delta)
- {
- best_sample = samplep;
- best_delta = delta_freq;
- }
- if (samples[samplep].low_note <= note_freq && note_freq <= samples[samplep].high_note)
- sample = samplep;
- else
- samplep = samples[samplep].key; /*
- * Follow link
- */
- }
- if (sample == -1)
- sample = best_sample;
-
- if (sample == -1)
- {
- printk ("GUS: Patch %d not defined for note %d\n", patch, note_num);
- return 0; /*
- * Should play default patch ???
- */
- }
-
- 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;
-
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- int i;
-
- for (i = 0; i < 6; i++)
- {
- voices[voice].env_rate[i] = samples[sample].env_rate[i];
- voices[voice].env_offset[i] = samples[sample].env_offset[i];
- }
- }
-
- sample_map[voice] = sample;
-
- 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.
- */
-
- freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range);
- voices[voice].current_freq = freq;
-
- pan = (samples[sample].panning + voices[voice].panning) / 32;
- pan += 7;
- if (pan < 0)
- pan = 0;
- if (pan > 15)
- pan = 15;
-
- if (samples[sample].mode & WAVE_16_BITS)
- {
- mode |= 0x04; /*
- * 16 bits
- */
- if ((sample_ptrs[sample] >> 18) !=
- ((sample_ptrs[sample] + samples[sample].len) >> 18))
- printk ("GUS: Sample address error\n");
- }
-
- /*************************************************************************
- * CAUTION! Interrupts disabled. Don't return before enabling
- *************************************************************************/
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_off (); /*
- * It may still be running
- */
- gus_rampoff ();
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- compute_volume (voice, volume);
- init_envelope (voice);
- }
- else
- compute_and_set_volume (voice, volume, 0);
-
- if (samples[sample].mode & WAVE_LOOP_BACK)
- 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] + voices[voice].offset_pending,
- is16bits); /* Sample start=begin */
-
- if (samples[sample].mode & WAVE_LOOPING)
- {
- mode |= 0x08; /*
- * Looping on
- */
-
- if (samples[sample].mode & WAVE_BIDIR_LOOP)
- mode |= 0x10; /*
- * Bidirectional looping on
- */
-
- if (samples[sample].mode & WAVE_LOOP_BACK)
- {
- gus_write_addr (0x0a,
- sample_ptrs[sample] + samples[sample].loop_end -
- voices[voice].offset_pending, is16bits);
- mode |= 0x40;
- }
-
- gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, is16bits); /*
- * Loop
- * start
- * location
- */
- gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, is16bits); /*
- * Loop
- * end
- * location
- */
- }
- else
- {
- mode |= 0x20; /*
- * Loop irq at the end
- */
- voices[voice].loop_irq_mode = LMODE_FINISH; /*
- * Ramp 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-1, is16bits); /*
- * Loop
- * end
- * location
- */
- }
- gus_voice_freq (freq);
- gus_voice_balance (pan);
- gus_voice_on (mode);
- RESTORE_INTR (flags);
-
- 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_init2 (i);
- }
- }
-
- static int
- guswave_open (int dev, int mode)
- {
- int err;
-
- 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;
-
- gus_reset ();
-
- return 0;
- }
-
- static void
- guswave_close (int dev)
- {
- gus_busy = 0;
- active_device = 0;
- gus_reset ();
-
- DMAbuf_close_dma (gus_devnum);
- }
-
- static int
- guswave_load_patch (int dev, int format, snd_rw_buf * addr,
- int offs, int count, int pmgr_flag)
- {
- 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%x\n", format);
- return RET_ERROR (EINVAL);
- }
-
- if (count < sizeof_patch)
- {
- printk ("GUS Error: Patch header too short\n");
- return RET_ERROR (EINVAL);
- }
-
- count -= sizeof_patch;
-
- if (free_sample >= MAX_SAMPLE)
- {
- printk ("GUS: Sample table full\n");
- 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);
-
- instr = patch.instr_no;
-
- if (instr < 0 || instr > MAX_PATCH)
- {
- printk ("GUS: Invalid patch number %d\n", instr);
- return RET_ERROR (EINVAL);
- }
-
- if (count < patch.len)
- {
- printk ("GUS Warning: Patch record too short (%d<%d)\n",
- count, (int) patch.len);
- patch.len = count;
- }
-
- if (patch.len <= 0 || patch.len > gus_mem_size)
- {
- printk ("GUS: Invalid sample length %d\n", (int) patch.len);
- return RET_ERROR (EINVAL);
- }
-
- if (patch.mode & WAVE_LOOPING)
- {
- if (patch.loop_start < 0 || patch.loop_start >= patch.len)
- {
- printk ("GUS: Invalid loop start\n");
- return RET_ERROR (EINVAL);
- }
-
- if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)
- {
- printk ("GUS: Invalid loop end\n");
- return RET_ERROR (EINVAL);
- }
- }
-
- 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", (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
- */
- ((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
- */
- }
- }
-
- if ((free_mem_ptr + patch.len) > gus_mem_size)
- return RET_ERROR (ENOSPC);
-
- sample_ptrs[free_sample] = free_mem_ptr;
-
- /*
- * Tremolo is not possible with envelopes
- */
-
- if (patch.mode & WAVE_ENVELOPES)
- patch.mode &= ~WAVE_TREMOLO;
-
- memcpy ((char *) &samples[free_sample], &patch, sizeof_patch);
-
- /*
- * Link this_one sample to the list of samples for patch 'instr'.
- */
-
- samples[free_sample].key = patch_table[instr];
- patch_table[instr] = free_sample;
-
- /*
- * Use DMA to transfer the wave data to the DRAM
- */
-
- left = patch.len;
- src_offs = 0;
- target = free_mem_ptr;
-
- 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
- */
-
- blk_end &= ~(256 * 1024 - 1);
- blk_size = blk_end - target;
- }
-
- #if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA)
- /*
- * For some reason the DMA is not possible. We have to use PIO.
- */
- {
- long i;
- unsigned char data;
-
- for (i = 0; i < blk_size; 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 */
- {
- 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,
- blk_size);
-
- 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
- */
-
- address = target;
-
- if (sound_dsp_dmachan[gus_devnum] > 3)
- {
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
-
- gus_write16 (0x42, (address >> 4) & 0xffff); /*
- * DRAM DMA address
- */
-
- /*
- * Start the DMA transfer
- */
-
- dma_command = 0x21; /*
- * IRQ enable, DMA start
- */
- if (patch.mode & WAVE_UNSIGNED)
- dma_command |= 0x80; /*
- * Invert MSB
- */
- if (patch.mode & WAVE_16_BITS)
- dma_command |= 0x40; /*
- * 16 bit _DATA_
- */
- if (sound_dsp_dmachan[gus_devnum] > 3)
- dma_command |= 0x04; /*
- * 16 bit DMA channel
- */
-
- 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;
-
- DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ);
- if (TIMED_OUT (dram_sleeper, dram_sleep_flag))
- printk ("GUS: DMA Transfer timed out\n");
- RESTORE_INTR (flags);
- }
- #endif /*
- * * * GUS_NO_DMA */
-
- /*
- * Now the next part
- */
-
- left -= blk_size;
- src_offs += blk_size;
- target += blk_size;
-
- gus_write8 (0x41, 0); /*
- * Stop DMA
- */
- }
-
- free_mem_ptr += patch.len;
-
- if (!pmgr_flag)
- pmgr_inform (dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0);
- free_sample++;
- return 0;
- }
-
- static void
- guswave_hw_control (int dev, unsigned char *event)
- {
- int voice, cmd;
- unsigned short p1, p2;
- unsigned long plong, flags;
-
- cmd = event[2];
- voice = event[3];
- p1 = *(unsigned short *) &event[4];
- p2 = *(unsigned short *) &event[6];
- plong = *(unsigned long *) &event[4];
-
- if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&
- (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))
- do_volume_irq (voice);
-
- switch (cmd)
- {
-
- case _GUS_NUMVOICES:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_select_max_voices (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICESAMPLE:
- guswave_set_instr (dev, voice, p1);
- break;
-
- case _GUS_VOICEON:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- p1 &= ~0x20; /*
- * Disable intr
- */
- gus_voice_on (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEOFF:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_off ();
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEFADE:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_fade (voice);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEMODE:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- p1 &= ~0x20; /*
- * Disable intr
- */
- gus_voice_mode (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEBALA:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_balance (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEFREQ:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_freq (plong);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEVOL:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_volume (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEVOL2: /*
- * Just update the voice value
- */
- voices[voice].initial_volume =
- voices[voice].current_volume = p1;
- break;
-
- case _GUS_RAMPRANGE:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /*
- * NO-NO
- */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_ramp_range (p1, p2);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_RAMPRATE:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /*
- * NO-NO
- */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_ramp_rate (p1, p2);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_RAMPMODE:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /*
- * NO-NO
- */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- p1 &= ~0x20; /*
- * Disable intr
- */
- gus_ramp_mode (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_RAMPON:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /*
- * NO-NO
- */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- p1 &= ~0x20; /*
- * Disable intr
- */
- gus_rampon (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_RAMPOFF:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /*
- * NO-NO
- */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_rampoff ();
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOLUME_SCALE:
- volume_base = p1;
- volume_scale = p2;
- break;
-
- case _GUS_VOICE_POS:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_set_voice_pos (voice, plong);
- RESTORE_INTR (flags);
- break;
-
- default:;
- }
- }
-
- static int
- gus_sampling_set_speed (int speed)
- {
- if (speed <= 0)
- return gus_sampling_speed;
-
- if (speed > 44100)
- speed = 44100;
-
- gus_sampling_speed = speed;
- return speed;
- }
-
- static int
- gus_sampling_set_channels (int channels)
- {
- if (!channels)
- return gus_sampling_channels;
- if (channels > 2)
- channels = 2;
- if (channels < 1)
- channels = 1;
- gus_sampling_channels = channels;
- return channels;
- }
-
- static int
- gus_sampling_set_bits (int bits)
- {
- if (!bits)
- return gus_sampling_bits;
-
- if (bits != 8 && bits != 16)
- bits = 8;
-
- gus_sampling_bits = bits;
- return bits;
- }
-
- static int
- gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
- {
- switch (cmd)
- {
- case SOUND_PCM_WRITE_RATE:
- if (local)
- return gus_sampling_set_speed (arg);
- return IOCTL_OUT (arg, gus_sampling_set_speed (IOCTL_IN (arg)));
- break;
-
- case SOUND_PCM_READ_RATE:
- if (local)
- return gus_sampling_speed;
- return IOCTL_OUT (arg, gus_sampling_speed);
- break;
-
- case SNDCTL_DSP_STEREO:
- if (local)
- return gus_sampling_set_channels (arg + 1) - 1;
- return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg) + 1) - 1);
- break;
-
- case SOUND_PCM_WRITE_CHANNELS:
- if (local)
- return gus_sampling_set_channels (arg);
- return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg)));
- break;
-
- case SOUND_PCM_READ_CHANNELS:
- if (local)
- return gus_sampling_channels;
- return IOCTL_OUT (arg, gus_sampling_channels);
- break;
-
- case SNDCTL_DSP_SAMPLESIZE:
- if (local)
- return gus_sampling_set_bits (arg);
- return IOCTL_OUT (arg, gus_sampling_set_bits (IOCTL_IN (arg)));
- break;
-
- case SOUND_PCM_READ_BITS:
- if (local)
- return gus_sampling_bits;
- return IOCTL_OUT (arg, gus_sampling_bits);
-
- case SOUND_PCM_WRITE_FILTER: /*
- * NOT YET IMPLEMENTED
- */
- return IOCTL_OUT (arg, RET_ERROR (EINVAL));
- break;
-
- case SOUND_PCM_READ_FILTER:
- return IOCTL_OUT (arg, RET_ERROR (EINVAL));
- break;
-
- default:
- return RET_ERROR (EINVAL);
- }
- return RET_ERROR (EINVAL);
- }
-
- static void
- gus_sampling_reset (int dev)
- {
- }
-
- static int
- gus_sampling_open (int dev, int mode)
- {
- #ifdef GUS_NO_DMA
- printk ("GUS: DMA mode not enabled. Device not supported\n");
- return RET_ERROR (ENXIO);
- #endif
-
- if (gus_busy)
- return RET_ERROR (EBUSY);
-
- gus_initialize ();
-
- gus_busy = 1;
- active_device = 0;
-
- gus_reset ();
- reset_sample_memory ();
- gus_select_max_voices (14);
-
- pcm_active = 0;
- pcm_opened = 1;
- if (mode & OPEN_READ)
- {
- recording_active = 1;
- set_input_volumes();
- }
-
- return 0;
- }
-
- static void
- 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
- play_next_pcm_block (void)
- {
- unsigned long flags;
- int speed = gus_sampling_speed;
- int this_one, is16bits, chn;
- unsigned long dram_loc;
- unsigned char mode[2], ramp_mode[2];
-
- if (!pcm_qlen)
- return;
-
- this_one = pcm_head;
-
- for (chn = 0; chn < gus_sampling_channels; chn++)
- {
- mode[chn] = 0x00;
- ramp_mode[chn] = 0x03; /*
- * Ramping and rollover off
- */
-
- if (chn == 0)
- {
- mode[chn] |= 0x20; /*
- * Loop irq
- */
- voices[chn].loop_irq_mode = LMODE_PCM;
- }
-
- if (gus_sampling_bits != 8)
- {
- is16bits = 1;
- mode[chn] |= 0x04; /*
- * 16 bit data
- */
- }
- else
- is16bits = 0;
-
- dram_loc = this_one * pcm_bsize;
- dram_loc += chn * pcm_banksize;
-
- if (this_one == (pcm_nblk - 1)) /*
- * Last of the DRAM buffers
- */
- {
- mode[chn] |= 0x08; /*
- * Enable loop
- */
- ramp_mode[chn] = 0x03; /*
- * Disable rollover
- */
- }
- else
- {
- if (chn == 0)
- ramp_mode[chn] = 0x04; /*
- * Enable rollover bit
- */
- }
-
- DISABLE_INTR (flags);
- gus_select_voice (chn);
- gus_voice_freq (speed);
-
- if (gus_sampling_channels == 1)
- gus_voice_balance (7); /*
- * mono
- */
- else if (chn == 0)
- gus_voice_balance (0); /*
- * left
- */
- else
- gus_voice_balance (15); /*
- * right
- */
-
- if (!pcm_active) /*
- * 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_rampoff ();
- gus_voice_volume (1530 + (25 * gus_pcm_volume));
- gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
-
- gus_write_addr (0x0a, dram_loc, is16bits); /*
- * Starting position
- */
- gus_write_addr (0x02, chn * pcm_banksize, is16bits); /*
- * Loop start
- * location
- */
-
- if (chn != 0)
- gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk),
- is16bits); /*
- * Loop end location
- */
- }
-
- if (chn == 0)
- gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /*
- * Loop
- * end
- * location
- */
- else
- mode[chn] |= 0x08; /*
- * Enable loop
- */
-
- if (pcm_datasize[this_one] != pcm_bsize)
- {
- /*
- * Incomplete block. Possibly the last one.
- */
- if (chn == 0)
- {
- 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
- */
- }
- else
- {
- gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /*
- * Loop
- * end
- * location
- */
- mode[chn] &= ~0x08; /*
- * Disable loop
- */
- }
- }
-
- RESTORE_INTR (flags);
- }
-
- for (chn = 0; chn < gus_sampling_channels; chn++)
- {
- DISABLE_INTR (flags);
- gus_select_voice (chn);
- gus_write8 (0x0d, ramp_mode[chn]);
- gus_voice_on (mode[chn]);
- RESTORE_INTR (flags);
- }
-
- pcm_active = 1;
- }
-
- 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.
- *
- * The left/mono channel data is transferred to the beginning of dram and the
- * right data to the area pointed by gus_page_size.
- */
-
- int this_one, count;
- unsigned long flags;
- unsigned char dma_command;
- unsigned long address, hold_address;
-
- DISABLE_INTR (flags);
-
- count = total_count / gus_sampling_channels;
-
- if (chn == 0)
- {
- if (pcm_qlen >= pcm_nblk)
- printk ("GUS Warning: PCM buffers out of sync\n");
-
- this_one = pcm_current_block = pcm_tail;
- pcm_qlen++;
- pcm_tail = (pcm_tail + 1) % pcm_nblk;
- pcm_datasize[this_one] = count;
- }
- else
- this_one = pcm_current_block;
-
- gus_write8 (0x41, 0); /*
- * Disable GF1 DMA
- */
- DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE);
-
- address = this_one * pcm_bsize;
- address += chn * pcm_banksize;
-
- if (sound_dsp_dmachan[dev] > 3)
- {
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
-
- gus_write16 (0x42, (address >> 4) & 0xffff); /*
- * DRAM DMA address
- */
-
- dma_command = 0x21; /*
- * IRQ enable, DMA start
- */
-
- if (gus_sampling_bits != 8)
- dma_command |= 0x40; /*
- * 16 bit _DATA_
- */
- else
- dma_command |= 0x80; /*
- * Invert MSB
- */
-
- if (sound_dsp_dmachan[dev] > 3)
- dma_command |= 0x04; /*
- * 16 bit DMA channel
- */
-
- gus_write8 (0x41, dma_command); /*
- * Kick on
- */
-
- if (chn == (gus_sampling_channels - 1)) /*
- * Last channel
- */
- {
- /*
- * 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 */
- 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, int restart_dma)
- {
- pcm_current_buf = buf;
- pcm_current_count = total_count;
- pcm_current_intrflag = intrflag;
- pcm_current_dev = dev;
- gus_transfer_output_block (dev, buf, total_count, intrflag, 0);
- }
-
- static void
- gus_sampling_start_input (int dev, unsigned long buf, int count,
- int intrflag, int restart_dma)
- {
- unsigned long flags;
- unsigned char mode;
-
- DISABLE_INTR (flags);
-
- DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
-
- mode = 0xa0; /*
- * DMA IRQ enable, invert MSB
- */
-
- if (sound_dsp_dmachan[dev] > 3)
- mode |= 0x04; /*
- * 16 bit DMA channel
- */
- if (gus_sampling_channels > 1)
- mode |= 0x02; /*
- * Stereo
- */
- mode |= 0x01; /*
- * DMA enable
- */
-
- gus_write8 (0x49, mode);
-
- RESTORE_INTR (flags);
- }
-
- static int
- gus_sampling_prepare_for_input (int dev, int bsize, int bcount)
- {
- unsigned int rate;
-
- rate = (9878400 / (gus_sampling_speed + 2)) / 16;
-
- gus_write8 (0x48, rate & 0xff); /*
- * Set sampling frequency
- */
-
- if (gus_sampling_bits != 8)
- {
- printk ("GUS Error: 16 bit recording not supported\n");
- return RET_ERROR (EINVAL);
- }
-
- return 0;
- }
-
- static int
- gus_sampling_prepare_for_output (int dev, int bsize, int bcount)
- {
- int i;
-
- long mem_ptr, mem_size;
-
- mem_ptr = 0;
- mem_size = gus_mem_size / gus_sampling_channels;
-
- if (mem_size > (256 * 1024))
- mem_size = 256 * 1024;
-
- pcm_bsize = bsize / gus_sampling_channels;
- pcm_head = pcm_tail = pcm_qlen = 0;
-
- pcm_nblk = MAX_PCM_BUFFERS;
- if ((pcm_bsize * pcm_nblk) > mem_size)
- pcm_nblk = mem_size / pcm_bsize;
-
- for (i = 0; i < pcm_nblk; i++)
- pcm_datasize[i] = 0;
-
- pcm_banksize = pcm_nblk * pcm_bsize;
-
- if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024))
- pcm_nblk--;
-
- return 0;
- }
-
- static int
- gus_has_output_drained (int dev)
- {
- return !pcm_qlen;
- }
-
- static void
- gus_copy_from_user (int dev, char *localbuf, int localoffs,
- snd_rw_buf * userbuf, int useroffs, int len)
- {
- if (gus_sampling_channels == 1)
- {
- COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len);
- }
- else if (gus_sampling_bits == 8)
- {
- int in_left = useroffs;
- int in_right = useroffs + 1;
- char *out_left, *out_right;
- int i;
-
- len /= 2;
- localoffs /= 2;
- out_left = &localbuf[localoffs];
- out_right = out_left + pcm_bsize;
-
- for (i = 0; i < len; i++)
- {
- GET_BYTE_FROM_USER (*out_left++, userbuf, in_left);
- in_left += 2;
- GET_BYTE_FROM_USER (*out_right++, userbuf, in_right);
- in_right += 2;
- }
- }
- else
- {
- int in_left = useroffs;
- int in_right = useroffs + 1;
- short *out_left, *out_right;
- int i;
-
- len /= 4;
- localoffs /= 4;
-
- out_left = (short *) &localbuf[localoffs];
- out_right = out_left + (pcm_bsize / 2);
-
- for (i = 0; i < len; i++)
- {
- GET_SHORT_FROM_USER (*out_left++, (short *) userbuf, in_left);
- in_left += 2;
- GET_SHORT_FROM_USER (*out_right++, (short *) userbuf, in_right);
- in_right += 2;
- }
- }
- }
-
- static struct audio_operations gus_sampling_operations =
- {
- "Gravis UltraSound",
- 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)
- {
- int i, n;
-
- switch (rec->command)
- {
- case PM_GET_DEVTYPE:
- rec->parm1 = PMTYPE_WAVE;
- return 0;
- break;
-
- case PM_GET_NRPGM:
- rec->parm1 = MAX_PATCH;
- return 0;
- break;
-
- case PM_GET_PGMMAP:
- rec->parm1 = MAX_PATCH;
-
- for (i = 0; i < MAX_PATCH; i++)
- {
- int ptr = patch_table[i];
-
- rec->data.data8[i] = 0;
-
- while (ptr >= 0 && ptr < free_sample)
- {
- rec->data.data8[i]++;
- ptr = samples[ptr].key; /*
- * Follow link
- */
- }
- }
- return 0;
- break;
-
- case PM_GET_PGM_PATCHES:
- {
- int ptr = patch_table[rec->parm1];
-
- n = 0;
-
- while (ptr >= 0 && ptr < free_sample)
- {
- rec->data.data32[n++] = ptr;
- ptr = samples[ptr].key; /*
- * Follow link
- */
- }
- }
- rec->parm1 = n;
- return 0;
- break;
-
- case PM_GET_PATCH:
- {
- int ptr = rec->parm1;
- struct patch_info *pat;
-
- if (ptr < 0 || ptr >= free_sample)
- return RET_ERROR (EINVAL);
-
- memcpy (rec->data.data8, (char *) &samples[ptr],
- sizeof (struct patch_info));
-
- pat = (struct patch_info *) rec->data.data8;
-
- pat->key = GUS_PATCH; /*
- * Restore patch type
- */
- rec->parm1 = sample_ptrs[ptr]; /*
- * DRAM address
- */
- rec->parm2 = sizeof (struct patch_info);
- }
- return 0;
- break;
-
- case PM_SET_PATCH:
- {
- int ptr = rec->parm1;
- struct patch_info *pat;
-
- if (ptr < 0 || ptr >= free_sample)
- return RET_ERROR (EINVAL);
-
- pat = (struct patch_info *) rec->data.data8;
-
- if (pat->len > samples[ptr].len) /*
- * Cannot expand sample
- */
- return RET_ERROR (EINVAL);
-
- pat->key = samples[ptr].key; /*
- * Ensure the link is correct
- */
-
- memcpy ((char *) &samples[ptr], rec->data.data8,
- sizeof (struct patch_info));
-
- pat->key = GUS_PATCH;
- }
- return 0;
- break;
-
- case PM_READ_PATCH: /*
- * Returns a block of wave data from the DRAM
- */
- {
- int sample = rec->parm1;
- int n;
- long offs = rec->parm2;
- int l = rec->parm3;
-
- if (sample < 0 || sample >= free_sample)
- return RET_ERROR (EINVAL);
-
- if (offs < 0 || offs >= samples[sample].len)
- return RET_ERROR (EINVAL); /*
- * Invalid offset
- */
-
- n = samples[sample].len - offs; /*
- * Nr of bytes left
- */
-
- if (l > n)
- l = n;
-
- if (l > sizeof (rec->data.data8))
- l = sizeof (rec->data.data8);
-
- if (l <= 0)
- return RET_ERROR (EINVAL); /*
- * Was there a bug?
- */
-
- offs += sample_ptrs[sample]; /*
- * Begin offsess + offset to DRAM
- */
-
- for (n = 0; n < l; n++)
- rec->data.data8[n] = gus_peek (offs++);
- rec->parm1 = n; /*
- * Nr of bytes copied
- */
- }
- return 0;
- break;
-
- case PM_WRITE_PATCH: /*
- * Writes a block of wave data to the DRAM
- */
- {
- int sample = rec->parm1;
- int n;
- long offs = rec->parm2;
- int l = rec->parm3;
-
- if (sample < 0 || sample >= free_sample)
- return RET_ERROR (EINVAL);
-
- if (offs < 0 || offs >= samples[sample].len)
- return RET_ERROR (EINVAL); /*
- * Invalid offset
- */
-
- n = samples[sample].len - offs; /*
- * Nr of bytes left
- */
-
- if (l > n)
- l = n;
-
- if (l > sizeof (rec->data.data8))
- l = sizeof (rec->data.data8);
-
- if (l <= 0)
- return RET_ERROR (EINVAL); /*
- * Was there a bug?
- */
-
- offs += sample_ptrs[sample]; /*
- * Begin offsess + offset to DRAM
- */
-
- for (n = 0; n < l; n++)
- gus_poke (offs++, rec->data.data8[n]);
- rec->parm1 = n; /*
- * Nr of bytes copied
- */
- }
- return 0;
- break;
-
- default:
- return RET_ERROR (EINVAL);
- }
- }
-
- static struct synth_operations guswave_operations =
- {
- &gus_info,
- #ifdef FUTURE_VERSION
- 0,
- #endif
- SYNTH_TYPE_SAMPLE,
- SAMPLE_TYPE_GUS,
- guswave_open,
- guswave_close,
- guswave_ioctl,
- guswave_kill_note,
- guswave_start_note,
- guswave_set_instr,
- guswave_reset,
- guswave_hw_control,
- guswave_load_patch,
- guswave_aftertouch,
- guswave_controller,
- guswave_panning,
- guswave_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 (" <Gravis UltraSound %dk>", (int) gus_mem_size / 1024);
-
- if (irq < 0 || irq > 15)
- {
- printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
- return mem_start;
- }
-
- if (dma < 0 || dma > 7)
- {
- printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma);
- return mem_start;
- }
-
- gus_irq = irq;
- gus_dma = dma;
-
- if (num_synths >= MAX_SYNTH_DEV)
- printk ("GUS Error: Too many synthesizers\n");
- else
- synth_devs[num_synths++] = &guswave_operations;
-
- PERMANENT_MALLOC (struct patch_info *, samples,
- (MAX_SAMPLE + 1) * sizeof (*samples), mem_start);
-
- reset_sample_memory ();
-
- gus_initialize ();
-
- if (num_dspdevs < MAX_DSP_DEV)
- {
- dsp_devs[gus_devnum = num_dspdevs++] = &gus_sampling_operations;
- sound_dsp_dmachan[gus_devnum] = dma;
- sound_buffcounts[gus_devnum] = 1;
- sound_buffsizes[gus_devnum] = DSP_BUFFSIZE;
- sound_dma_automode[gus_devnum] = 0;
- }
- 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;
- }
-
- static void
- do_loop_irq (int voice)
- {
- unsigned char tmp;
- int mode, parm;
- unsigned long flags;
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
-
- tmp = gus_read8 (0x00);
- tmp &= ~0x20; /*
- * Disable wave IRQ for this_one voice
- */
- gus_write8 (0x00, tmp);
-
- mode = voices[voice].loop_irq_mode;
- voices[voice].loop_irq_mode = 0;
- parm = voices[voice].loop_irq_parm;
-
- switch (mode)
- {
-
- case LMODE_FINISH: /*
- * Final loop finished, shoot volume down
- */
-
- if ((gus_read16 (0x09) >> 4) < 100) /*
- * Get current volume
- */
- {
- gus_voice_off ();
- gus_rampoff ();
- gus_voice_init (voice);
- break;
- }
- gus_ramp_range (65, 4065);
- gus_ramp_rate (0, 63); /*
- * Fastest possible rate
- */
- gus_rampon (0x20 | 0x40); /*
- * Ramp down, once, irq
- */
- voices[voice].volume_irq_mode = VMODE_HALT;
- break;
-
- case LMODE_PCM_STOP:
- pcm_active = 0; /*
- * Requires extensive processing
- */
- case LMODE_PCM:
- {
- int orig_qlen = pcm_qlen;
-
- pcm_qlen--;
- pcm_head = (pcm_head + 1) % pcm_nblk;
- if (pcm_qlen)
- {
- play_next_pcm_block ();
- }
- else
- { /*
- * Out of data. Just stop the voice
- */
- gus_voice_off ();
- gus_rampoff ();
- pcm_active = 0;
- }
-
- if (orig_qlen == pcm_nblk)
- {
- DMAbuf_outputintr (gus_devnum, 0);
- }
- }
- break;
-
- default:;
- }
- RESTORE_INTR (flags);
- }
-
- static void
- do_volume_irq (int voice)
- {
- unsigned char tmp;
- int mode, parm;
- unsigned long flags;
-
- DISABLE_INTR (flags);
-
- gus_select_voice (voice);
-
- tmp = gus_read8 (0x0d);
- tmp &= ~0x20; /*
- * Disable volume ramp IRQ
- */
- gus_write8 (0x0d, tmp);
-
- mode = voices[voice].volume_irq_mode;
- voices[voice].volume_irq_mode = 0;
- parm = voices[voice].volume_irq_parm;
-
- switch (mode)
- {
- case VMODE_HALT: /*
- * Decay phase finished
- */
- gus_voice_init (voice);
- break;
-
- case VMODE_ENVELOPE:
- gus_rampoff ();
- 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:;
- }
-
- RESTORE_INTR (flags);
- }
-
- void
- gus_voice_irq (void)
- {
- unsigned long wave_ignore = 0, volume_ignore = 0;
- unsigned long voice_bit;
-
- unsigned char src, voice;
-
- while (1)
- {
- src = gus_read8 (0x0f); /*
- * Get source info
- */
- voice = src & 0x1f;
- src &= 0xc0;
-
- if (src == (0x80 | 0x40))
- return; /*
- * No interrupt
- */
-
- voice_bit = 1 << voice;
-
- if (!(src & 0x80)) /*
- * Wave IRQ pending
- */
- if (!(wave_ignore & voice_bit) && 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
- */
- {
- volume_ignore |= voice_bit;
- do_volume_irq (voice);
- }
- }
- }
-
- void
- guswave_dma_irq (void)
- {
- unsigned char status;
-
- status = gus_look8 (0x41); /*
- * Get DMA IRQ Status
- */
- if (status & 0x40) /*
- * DMA Irq pending
- */
- switch (active_device)
- {
- case GUS_DEV_WAVE:
- if (SOMEONE_WAITING (dram_sleeper, dram_sleep_flag))
- WAKE_UP (dram_sleeper, dram_sleep_flag);
- break;
-
- case GUS_DEV_PCM_CONTINUE:
- gus_transfer_output_block (pcm_current_dev, pcm_current_buf,
- pcm_current_count,
- pcm_current_intrflag, 1);
- break;
-
- case GUS_DEV_PCM_DONE:
- if (pcm_qlen < pcm_nblk)
- {
- DMAbuf_outputintr (gus_devnum, pcm_qlen == 0);
- }
- break;
-
- default:;
- }
-
- status = gus_look8 (0x49); /*
- * Get Sampling IRQ Status
- */
- if (status & 0x40) /*
- * Sampling Irq pending
- */
- {
- DMAbuf_inputintr (gus_devnum);
- }
-
- }
-
- #endif
-