URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [sound/] [gus_wave.c] - Rev 1765
Compare with Previous | Blame | View Log
/* * sound/gus_wave.c * * Driver for the Gravis UltraSound wave table synth. * * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. * * * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) * Frank van de Pol : Fixed GUS MAX interrupt handling. Enabled simultanious * usage of CS4231A codec, GUS wave and MIDI for GUS MAX. * Bartlomiej Zolnierkiewicz : added some __init/__exit */ #include <linux/init.h> #include <linux/config.h> #define GUSPNP_AUTODETECT #include "sound_config.h" #include <linux/ultrasound.h> #include "gus.h" #include "gus_hw.h" #define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024)) #define MAX_SAMPLE 150 #define MAX_PATCH 256 #define NOT_SAMPLE 0xffff struct voice_info { unsigned long orig_freq; unsigned long current_freq; unsigned long mode; int fixed_pitch; 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; }; static struct voice_alloc_info *voice_alloc; static struct address_info *gus_hw_config; extern int gus_base; extern int gus_irq, gus_dma; extern int gus_pnp_flag; extern int gus_no_wave_dma; static int gus_dma2 = -1; static int dual_dma_mode = 0; static long gus_mem_size = 0; static long free_mem_ptr = 0; static int gus_busy = 0; static int gus_no_dma = 0; static int nr_voices = 0; static int gus_devnum = 0; static int volume_base, volume_scale, volume_method; static int gus_recmask = SOUND_MASK_MIC; static int recording_active = 0; static int only_read_access = 0; static int only_8_bits = 0; int iw_mode = 0; int gus_wave_volume = 60; int gus_pcm_volume = 80; int have_gus_max = 0; static int gus_line_vol = 100, gus_mic_vol = 0; static unsigned char mix_image = 0x00; int gus_timer_enabled = 0; /* * Current version of this driver doesn't allow synth and PCM functions * at the same time. The active_device specifies the active driver */ 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 done ch. 1/2 */ static int gus_audio_speed; static int gus_audio_channels; static int gus_audio_bits; static int gus_audio_bsize; static char bounce_buf[8 * 1024]; /* Must match value set to max_fragment */ static DECLARE_WAIT_QUEUE_HEAD(dram_sleeper); /* * Variables and buffers for PCM output */ #define MAX_PCM_BUFFERS (128*MAX_REALTIME_FACTOR) /* Don't change */ static int pcm_bsize, pcm_nblk, pcm_banksize; static int pcm_datasize[MAX_PCM_BUFFERS]; static volatile int pcm_head, pcm_tail, pcm_qlen; static volatile int pcm_active; static volatile int dma_active; static int pcm_opened = 0; static int pcm_current_dev; static int pcm_current_block; static unsigned long pcm_current_buf; static int pcm_current_count; static int pcm_current_intrflag; extern int *gus_osp; static 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 = NULL; static long sample_ptrs[MAX_SAMPLE + 1]; static int sample_map[32]; static int free_sample; static int mixer_type = 0; static int patch_table[MAX_PATCH]; static int patch_map[32]; static struct synth_info gus_info = { "Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH }; static void gus_poke(long addr, unsigned char data); static void compute_and_set_volume(int voice, int volume, int ramp_time); extern unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev); extern unsigned short gus_linear_vol(int vol, int mainvol); static void compute_volume(int voice, int volume); static void do_volume_irq(int voice); static void set_input_volumes(void); static void gus_tmr_install(int io_base); #define INSTANT_RAMP -1 /* Instant change. No 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 a silent sample to the beginning */ gus_poke(1, 0); free_mem_ptr = 2; free_sample = 0; for (i = 0; i < MAX_PATCH; i++) patch_table[i] = NOT_SAMPLE; } void gus_delay(void) { int i; for (i = 0; i < 7; i++) inb(u_DRAMIO); } static void gus_poke(long addr, unsigned char data) { /* Writes a byte to the DRAM */ unsigned long flags; save_flags(flags); cli(); 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_flags(flags); } static unsigned char gus_peek(long addr) { /* Reads a byte from the DRAM */ unsigned long flags; unsigned char tmp; save_flags(flags); cli(); 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_flags(flags); return tmp; } void gus_write8(int reg, unsigned int data) { /* Writes to an indirect register (8 bit) */ unsigned long flags; save_flags(flags); cli(); outb((reg), u_Command); outb(((unsigned char) (data & 0xff)), u_DataHi); restore_flags(flags); } static unsigned char gus_read8(int reg) { /* Reads from an indirect register (8 bit). Offset 0x80. */ unsigned long flags; unsigned char val; save_flags(flags); cli(); outb((reg | 0x80), u_Command); val = inb(u_DataHi); restore_flags(flags); return val; } static unsigned char gus_look8(int reg) { /* Reads from an indirect register (8 bit). No additional offset. */ unsigned long flags; unsigned char val; save_flags(flags); cli(); outb((reg), u_Command); val = inb(u_DataHi); restore_flags(flags); return val; } static void gus_write16(int reg, unsigned int data) { /* Writes to an indirect register (16 bit) */ unsigned long flags; save_flags(flags); cli(); outb((reg), u_Command); outb(((unsigned char) (data & 0xff)), u_DataLo); outb(((unsigned char) ((data >> 8) & 0xff)), u_DataHi); restore_flags(flags); } static unsigned short gus_read16(int reg) { /* Reads from an indirect register (16 bit). Offset 0x80. */ unsigned long flags; unsigned char hi, lo; save_flags(flags); cli(); outb((reg | 0x80), u_Command); lo = inb(u_DataLo); hi = inb(u_DataHi); restore_flags(flags); return ((hi << 8) & 0xff00) | lo; } static unsigned short gus_look16(int reg) { /* Reads from an indirect register (16 bit). No additional offset. */ unsigned long flags; unsigned char hi, lo; save_flags(flags); cli(); outb((reg), u_Command); lo = inb(u_DataLo); hi = inb(u_DataHi); restore_flags(flags); return ((hi << 8) & 0xff00) | lo; } static void gus_write_addr(int reg, unsigned long address, int frac, int is16bit) { /* Writes an 24 bit memory address */ unsigned long hold_address; unsigned long flags; save_flags(flags); cli(); if (is16bit) { if (iw_mode) { /* Interwave spesific address translations */ address >>= 1; } else { /* * 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) + (frac << 5)); /* Could writing twice fix problems with GUS_VOICE_POS()? Let's try. */ gus_delay(); gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff)); gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff) + (frac << 5)); restore_flags(flags); } 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 (iw_mode) nvoices = 32; if (nvoices < 14) nvoices = 14; if (nvoices > 32) nvoices = 32; voice_alloc->max_voice = 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 touch last two bits */ 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; /* Interwave plays at 44100 Hz with any number of voices */ if (iw_mode) fc = (unsigned short) (((freq << 9) + (44100 >> 1)) / 44100); else 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)); /* Leave the last 2 bits alone */ 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, 0, samples[sample_no].mode & WAVE_16_BITS); } } } static void gus_voice_init(int voice) { unsigned long flags; save_flags(flags); cli(); gus_select_voice(voice); gus_voice_volume(0); gus_voice_off(); gus_write_addr(0x0a, 0, 0, 0); /* Set current position to 0 */ gus_write8(0x00, 0x03); /* Voice off */ gus_write8(0x0d, 0x03); /* Ramping off */ voice_alloc->map[voice] = 0; voice_alloc->alloc_times[voice] = 0; restore_flags(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; voices[voice].fixed_pitch = 0; } static void step_envelope(int voice) { unsigned vol, prev_vol, phase; unsigned char rate; long int flags; if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) { save_flags(flags); cli(); gus_select_voice(voice); gus_rampoff(); restore_flags(flags); return; /* * Sustain phase begins. Continue envelope after receiving note off. */ } if (voices[voice].env_phase >= 5) { /* Envelope finished. Shoot the voice down */ gus_voice_init(voice); return; } prev_vol = voices[voice].current_volume; phase = ++voices[voice].env_phase; compute_volume(voice, voices[voice].midi_volume); vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255; rate = voices[voice].env_rate[phase]; save_flags(flags); cli(); gus_select_voice(voice); gus_voice_volume(prev_vol); gus_write8(0x06, rate); /* Ramping rate */ voices[voice].volume_irq_mode = VMODE_ENVELOPE; if (((vol - prev_vol) / 64) == 0) /* No significant volume change */ { restore_flags(flags); step_envelope(voice); /* Continue the envelope on the next step */ return; } if (vol > prev_vol) { if (vol >= (4096 - 64)) vol = 4096 - 65; gus_ramp_range(0, vol); gus_rampon(0x20); /* Increasing volume, with IRQ */ } else { if (vol <= 64) vol = 65; gus_ramp_range(vol, 4030); gus_rampon(0x60); /* Decreasing volume, with IRQ */ } voices[voice].current_volume = vol; restore_flags(flags); } 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, long int flags) { 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(); restore_flags(flags); step_envelope(voice); } static void gus_voice_fade(int voice) { int instr_no = sample_map[voice], is16bits; long int flags; save_flags(flags); cli(); gus_select_voice(voice); if (instr_no < 0 || instr_no > MAX_SAMPLE) { gus_write8(0x00, 0x03); /* Hard stop */ voice_alloc->map[voice] = 0; restore_flags(flags); return; } is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */ if (voices[voice].mode & WAVE_ENVELOPES) { start_release(voice, flags); restore_flags(flags); return; } /* * Ramp the volume down but not too quickly. */ if ((int) (gus_read16(0x09) >> 4) < 100) /* Get current volume */ { gus_voice_off(); gus_rampoff(); gus_voice_init(voice); restore_flags(flags); return; } gus_ramp_range(65, 4030); gus_ramp_rate(2, 4); gus_rampon(0x40 | 0x20); /* Down, once, with IRQ */ voices[voice].volume_irq_mode = VMODE_HALT; restore_flags(flags); } 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); } } static void gus_initialize(void) { unsigned long flags; unsigned char dma_image, irq_image, tmp; static unsigned char gus_irq_map[16] = { 0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7 }; static unsigned char gus_dma_map[8] = { 0, 1, 0, 2, 0, 3, 4, 5 }; save_flags(flags); cli(); 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 (for a moment) */ 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 (!gus_pnp_flag && !tmp) printk(KERN_WARNING "Warning! GUS IRQ not selected\n"); irq_image |= tmp; irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */ dual_dma_mode = 1; if (gus_dma2 == gus_dma || gus_dma2 == -1) { dual_dma_mode = 0; dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ tmp = gus_dma_map[gus_dma]; if (!tmp) printk(KERN_WARNING "Warning! GUS DMA not selected\n"); dma_image |= tmp; } else { /* Setup dual DMA channel mode for GUS MAX */ dma_image = gus_dma_map[gus_dma]; if (!dma_image) printk(KERN_WARNING "Warning! GUS DMA not selected\n"); tmp = gus_dma_map[gus_dma2] << 3; if (!tmp) { printk(KERN_WARNING "Warning! Invalid GUS MAX DMA\n"); tmp = 0x40; /* Combine DMA channels */ dual_dma_mode = 0; } dma_image |= tmp; } /* * For some reason the IRQ and DMA addresses must be written twice */ /* * 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(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */ 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 */ if (iw_mode) gus_write8(0x19, gus_read8(0x19) | 0x01); restore_flags(flags); } static void __init pnp_mem_init(void) { #include "iwmem.h" #define CHUNK_SIZE (256*1024) #define BANK_SIZE (4*1024*1024) #define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE) int bank, chunk, addr, total = 0; int bank_sizes[4]; int i, j, bits = -1, testbits = -1, nbanks = 0; /* * This routine determines what kind of RAM is installed in each of the four * SIMM banks and configures the DRAM address decode logic accordingly. */ /* * Place the chip into enhanced mode */ gus_write8(0x19, gus_read8(0x19) | 0x01); gus_write8(0x53, gus_look8(0x53) & ~0x02); /* Select DRAM I/O access */ /* * Set memory configuration to 4 DRAM banks of 4M in each (16M total). */ gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | 0x000c); /* * Perform the DRAM size detection for each bank individually. */ for (bank = 0; bank < 4; bank++) { int size = 0; addr = bank * BANK_SIZE; /* Clean check points of each chunk */ for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) { gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); } /* Write a value to each chunk point and verify the result */ for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) { gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x55); gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0xAA); if (gus_peek(addr + chunk * CHUNK_SIZE + 0L) == 0x55 && gus_peek(addr + chunk * CHUNK_SIZE + 1L) == 0xAA) { /* OK. There is RAM. Now check for possible shadows */ int ok = 1, chunk2; for (chunk2 = 0; ok && chunk2 < chunk; chunk2++) if (gus_peek(addr + chunk2 * CHUNK_SIZE + 0L) || gus_peek(addr + chunk2 * CHUNK_SIZE + 1L)) ok = 0; /* Addressing wraps */ if (ok) size = (chunk + 1) * CHUNK_SIZE; } gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); } bank_sizes[bank] = size; if (size) nbanks = bank + 1; DDB(printk("Interwave: Bank %d, size=%dk\n", bank, size / 1024)); } if (nbanks == 0) /* No RAM - Give up */ { printk(KERN_ERR "Sound: An Interwave audio chip detected but no DRAM\n"); printk(KERN_ERR "Sound: Unable to work with this card.\n"); gus_write8(0x19, gus_read8(0x19) & ~0x01); gus_mem_size = 0; return; } /* * Now we know how much DRAM there is in each bank. The next step is * to find a DRAM size encoding (0 to 12) which is best for the combination * we have. * * First try if any of the possible alternatives matches exactly the amount * of memory we have. */ for (i = 0; bits == -1 && i < 13; i++) { bits = i; for (j = 0; bits != -1 && j < 4; j++) if (mem_decode[i][j] != bank_sizes[j]) bits = -1; /* No hit */ } /* * If necessary, try to find a combination where other than the last * bank matches our configuration and the last bank is left oversized. * In this way we don't leave holes in the middle of memory. */ if (bits == -1) /* No luck yet */ { for (i = 0; bits == -1 && i < 13; i++) { bits = i; for (j = 0; bits != -1 && j < nbanks - 1; j++) if (mem_decode[i][j] != bank_sizes[j]) bits = -1; /* No hit */ if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1]) bits = -1; /* The last bank is too small */ } } /* * The last resort is to search for a combination where the banks are * smaller than the actual SIMMs. This leaves some memory in the banks * unused but doesn't leave holes in the DRAM address space. */ if (bits == -1) /* No luck yet */ { for (i = 0; i < 13; i++) { testbits = i; for (j = 0; testbits != -1 && j < nbanks - 1; j++) if (mem_decode[i][j] > bank_sizes[j]) { testbits = -1; } if(testbits > bits) bits = testbits; } if (bits != -1) { printk(KERN_INFO "Interwave: Can't use all installed RAM.\n"); printk(KERN_INFO "Interwave: Try reordering SIMMS.\n"); } printk(KERN_INFO "Interwave: Can't find working DRAM encoding.\n"); printk(KERN_INFO "Interwave: Defaulting to 256k. Try reordering SIMMS.\n"); bits = 0; } DDB(printk("Interwave: Selecting DRAM addressing mode %d\n", bits)); for (bank = 0; bank < 4; bank++) { DDB(printk(" Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024)); if (bank_sizes[bank] > mem_decode[bits][bank]) total += mem_decode[bits][bank]; else total += bank_sizes[bank]; } DDB(printk("Total %dk of DRAM (enhanced mode)\n", total / 1024)); /* * Set the memory addressing mode. */ gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | bits); /* Leave the chip into enhanced mode. Disable LFO */ gus_mem_size = total; iw_mode = 1; gus_write8(0x19, (gus_read8(0x19) | 0x01) & ~0x02); } int __init gus_wave_detect(int baseaddr) { unsigned long i, max_mem = 1024L; unsigned long loc; unsigned char val; gus_base = baseaddr; gus_write8(0x4c, 0); /* Reset GF1 */ gus_delay(); gus_delay(); gus_write8(0x4c, 1); /* Release Reset */ gus_delay(); gus_delay(); #ifdef GUSPNP_AUTODETECT val = gus_look8(0x5b); /* Version number register */ gus_write8(0x5b, ~val); /* Invert all bits */ if ((gus_look8(0x5b) & 0xf0) == (val & 0xf0)) /* No change */ { if ((gus_look8(0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */ { DDB(printk("Interwave chip version %d detected\n", (val & 0xf0) >> 4)); gus_pnp_flag = 1; } else { DDB(printk("Not an Interwave chip (%x)\n", gus_look8(0x5b))); gus_pnp_flag = 0; } } gus_write8(0x5b, val); /* Restore all bits */ #endif if (gus_pnp_flag) pnp_mem_init(); if (iw_mode) return 1; /* 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 < max_mem; 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, caddr_t arg) { switch (cmd) { case SNDCTL_SYNTH_INFO: gus_info.nr_voices = nr_voices; if (copy_to_user(arg, &gus_info, sizeof(gus_info))) return -EFAULT; return 0; case SNDCTL_SEQ_RESETSAMPLES: reset_sample_memory(); return 0; case SNDCTL_SEQ_PERCMODE: return 0; case SNDCTL_SYNTH_MEMAVL: return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32; default: return -EINVAL; } } static int guswave_set_instr(int dev, int voice, int instr_no) { int sample_no; if (instr_no < 0 || instr_no > MAX_PATCH) instr_no = 0; /* Default to acoustic piano */ if (voice < 0 || voice > 31) return -EINVAL; if (voices[voice].volume_irq_mode == VMODE_START_NOTE) { voices[voice].sample_pending = instr_no; return 0; } sample_no = patch_table[instr_no]; patch_map[voice] = -1; if (sample_no == NOT_SAMPLE) { /* printk("GUS: Undefined patch %d for voice %d\n", instr_no, voice);*/ return -EINVAL; /* Patch not defined */ } if (sample_ptrs[sample_no] == -1) /* Sample not loaded */ { /* printk("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);*/ return -EINVAL; } sample_map[voice] = sample_no; patch_map[voice] = instr_no; return 0; } static int guswave_kill_note(int dev, int voice, int note, int velocity) { unsigned long flags; save_flags(flags); cli(); /* voice_alloc->map[voice] = 0xffff; */ if (voices[voice].volume_irq_mode == VMODE_START_NOTE) { voices[voice].kill_pending = 1; restore_flags(flags); } else { restore_flags(flags); gus_voice_fade(voice); } return 0; } static void guswave_aftertouch(int dev, int voice, int pressure) { } static void guswave_panning(int dev, int voice, int value) { if (voice >= 0 || voice < 32) voices[voice].panning = value; } static void guswave_volume_method(int dev, int mode) { if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO) volume_method = mode; } 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; case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */ voices[voice].initial_volume = gus_linear_vol(volume, voices[voice].main_vol); break; default: voices[voice].initial_volume = volume_base + (voices[voice].midi_volume * volume_scale); } 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 curr, target, rate; unsigned long flags; compute_volume(voice, volume); voices[voice].current_volume = voices[voice].initial_volume; save_flags(flags); cli(); /* * CAUTION! Interrupts disabled. Enable them before returning */ gus_select_voice(voice); curr = gus_read16(0x09) >> 4; target = voices[voice].initial_volume; if (ramp_time == INSTANT_RAMP) { gus_rampoff(); gus_voice_volume(target); restore_flags(flags); return; } if (ramp_time == FAST_RAMP) rate = 63; else rate = 16; gus_ramp_rate(0, rate); if ((target - curr) / 64 == 0) /* Close enough to target. */ { gus_rampoff(); gus_voice_volume(target); restore_flags(flags); return; } if (target > curr) { if (target > (4095 - 65)) target = 4095 - 65; gus_ramp_range(curr, target); gus_rampon(0x00); /* Ramp up, once, no IRQ */ } else { if (target < 65) target = 65; gus_ramp_range(target, curr); gus_rampon(0x40); /* Ramp down, once, no irq */ } restore_flags(flags); } static void dynamic_volume_change(int voice) { unsigned char status; unsigned long flags; save_flags(flags); cli(); gus_select_voice(voice); status = gus_read8(0x00); /* Get voice status */ restore_flags(flags); if (status & 0x03) return; /* Voice was not running */ if (!(voices[voice].mode & WAVE_ENVELOPES)) { compute_and_set_volume(voice, voices[voice].midi_volume, 1); return; } /* * Voice is running and has envelopes. */ save_flags(flags); cli(); gus_select_voice(voice); status = gus_read8(0x0d); /* Ramping status */ restore_flags(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); } 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, 0); voices[voice].current_freq = freq; save_flags(flags); cli(); gus_select_voice(voice); gus_voice_freq(freq); restore_flags(flags); } break; case CTRL_PITCH_BENDER_RANGE: voices[voice].bender_range = value; break; case CTL_EXPRESSION: value /= 128; case CTRL_EXPRESSION: if (volume_method == VOL_METHOD_ADAGIO) { voices[voice].expression_vol = value; if (voices[voice].volume_irq_mode != VMODE_START_NOTE) dynamic_volume_change(voice); } break; case CTL_PAN: voices[voice].panning = (value * 2) - 128; break; case CTL_MAIN_VOLUME: value = (value * 100) / 16383; case CTRL_MAIN_VOLUME: voices[voice].main_vol = value; if (voices[voice].volume_irq_mode != VMODE_START_NOTE) dynamic_volume_change(voice); break; default: break; } } static int guswave_start_note2(int dev, int voice, int note_num, int volume) { int 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 -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 -EINVAL; if ((samplep = patch_table[patch]) == NOT_SAMPLE) { return -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 && samplep != NOT_SAMPLE && 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; /* Link to next sample */ } if (sample == -1) sample = best_sample; if (sample == -1) { /* printk("GUS: Patch %d not defined for note %d\n", patch, note_num);*/ return 0; /* Should play default patch ??? */ } is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; voices[voice].mode = samples[sample].mode; voices[voice].patch_vol = samples[sample].volume; if (iw_mode) gus_write8(0x15, 0x00); /* RAM, Reset voice deactivate bit of SMSI */ 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; if (voices[voice].fixed_pitch) /* Fixed pitch */ { freq = samples[sample].base_freq; } else { base_note = samples[sample].base_note / 100; 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, 0); 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] / GUS_BANK_SIZE) != ((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE)) printk(KERN_ERR "GUS: Sample address error\n"); } /************************************************************************* * CAUTION! Interrupts disabled. Don't return before enabling *************************************************************************/ save_flags(flags); cli(); gus_select_voice(voice); gus_voice_off(); gus_rampoff(); restore_flags(flags); if (voices[voice].mode & WAVE_ENVELOPES) { compute_volume(voice, volume); init_envelope(voice); } else { compute_and_set_volume(voice, volume, 0); } save_flags(flags); cli(); gus_select_voice(voice); if (samples[sample].mode & WAVE_LOOP_BACK) gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len - voices[voice].offset_pending, 0, is16bits); /* start=end */ else gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, 0, is16bits); /* Sample start=begin */ if (samples[sample].mode & WAVE_LOOPING) { mode |= 0x08; if (samples[sample].mode & WAVE_BIDIR_LOOP) mode |= 0x10; if (samples[sample].mode & WAVE_LOOP_BACK) { gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].loop_end - voices[voice].offset_pending, (samples[sample].fractions >> 4) & 0x0f, is16bits); mode |= 0x40; } gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start, samples[sample].fractions & 0x0f, is16bits); /* Loop start location */ gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end, (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */ } else { mode |= 0x20; /* Loop IRQ at the end */ voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ voices[voice].loop_irq_parm = 1; gus_write_addr(0x02, sample_ptrs[sample], 0, is16bits); /* Loop start location */ gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1, (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */ } gus_voice_freq(freq); gus_voice_balance(pan); gus_voice_on(mode); restore_flags(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; save_flags(flags); cli(); if (note_num == 255) { if (voices[voice].volume_irq_mode == VMODE_START_NOTE) { voices[voice].volume_pending = volume; } else { ret_val = guswave_start_note2(dev, voice, note_num, volume); } } else { gus_select_voice(voice); mode = gus_read8(0x00); if (mode & 0x20) gus_write8(0x00, mode & 0xdf); /* No interrupt! */ voices[voice].offset_pending = 0; voices[voice].kill_pending = 0; voices[voice].volume_irq_mode = 0; voices[voice].loop_irq_mode = 0; if (voices[voice].sample_pending >= 0) { restore_flags(flags); /* Run temporarily with interrupts enabled */ guswave_set_instr(voices[voice].dev_pending, voice, voices[voice].sample_pending); voices[voice].sample_pending = -1; save_flags(flags); cli(); gus_select_voice(voice); /* Reselect the voice (just to be sure) */ } if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 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_flags(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 -EBUSY; voice_alloc->timestamp = 0; if (gus_no_wave_dma) { gus_no_dma = 1; } else { if ((err = DMAbuf_open_dma(gus_devnum)) < 0) { /* printk( "GUS: Loading samples without DMA\n"); */ gus_no_dma = 1; /* Upload samples using PIO */ } else gus_no_dma = 0; } init_waitqueue_head(&dram_sleeper); gus_busy = 1; active_device = GUS_DEV_WAVE; gusintr(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */ gus_initialize(); gus_reset(); gusintr(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */ return 0; } static void guswave_close(int dev) { gus_busy = 0; active_device = 0; gus_reset(); if (!gus_no_dma) DMAbuf_close_dma(gus_devnum); } static int guswave_load_patch(int dev, int format, const char *addr, int offs, int count, int pmgr_flag) { struct patch_info patch; int instr; long sizeof_patch; unsigned long blk_sz, blk_end, left, src_offs, target; sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ if (format != GUS_PATCH) { /* printk("GUS Error: Invalid patch format (key) 0x%x\n", format);*/ return -EINVAL; } if (count < sizeof_patch) { /* printk("GUS Error: Patch header too short\n");*/ return -EINVAL; } count -= sizeof_patch; if (free_sample >= MAX_SAMPLE) { /* printk("GUS: Sample table full\n");*/ return -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); if (patch.mode & WAVE_ROM) return -EINVAL; if (gus_mem_size == 0) return -ENOSPC; instr = patch.instr_no; if (instr < 0 || instr > MAX_PATCH) { /* printk(KERN_ERR "GUS: Invalid patch number %d\n", instr);*/ return -EINVAL; } if (count < patch.len) { /* printk(KERN_ERR "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(KERN_ERR "GUS: Invalid sample length %d\n", (int) patch.len);*/ return -EINVAL; } if (patch.mode & WAVE_LOOPING) { if (patch.loop_start < 0 || patch.loop_start >= patch.len) { /* printk(KERN_ERR "GUS: Invalid loop start\n");*/ return -EINVAL; } if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) { /* printk(KERN_ERR "GUS: Invalid loop end\n");*/ return -EINVAL; } } free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */ 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 -ENOSPC; } if ((free_mem_ptr / GUS_BANK_SIZE) != ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) { unsigned long tmp_mem = /* Align to 256K */ ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; if ((tmp_mem + patch.len) > gus_mem_size) return -ENOSPC; free_mem_ptr = tmp_mem; /* This leaves unusable memory */ } } if ((free_mem_ptr + patch.len) > gus_mem_size) return -ENOSPC; sample_ptrs[free_sample] = free_mem_ptr; /* * Tremolo is not possible with envelopes */ if (patch.mode & WAVE_ENVELOPES) patch.mode &= ~WAVE_TREMOLO; if (!(patch.mode & WAVE_FRACTIONS)) { patch.fractions = 0; } 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 completely transferred yet */ { blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use; if (blk_sz > left) blk_sz = left; /* * DMA cannot cross bank (256k) boundaries. Check for that. */ blk_end = target + blk_sz; if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE)) { /* Split the block */ blk_end &= ~(GUS_BANK_SIZE - 1); blk_sz = blk_end - target; } if (gus_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_sz; i++) { get_user(*(unsigned char *) &data, (unsigned char *) &((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 { unsigned long address, hold_address; unsigned char dma_command; unsigned long flags; if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL) { printk(KERN_ERR "GUS: DMA buffer == NULL\n"); return -ENOSPC; } /* * OK, move now. First in and then out. */ copy_from_user(audio_devs[gus_devnum]->dmap_out->raw_buf, &(addr)[sizeof_patch + src_offs], blk_sz); save_flags(flags); cli(); /******** INTERRUPTS DISABLED NOW ********/ gus_write8(0x41, 0); /* Disable GF1 DMA */ DMAbuf_start_dma(gus_devnum, audio_devs[gus_devnum]->dmap_out->raw_buf_phys, blk_sz, DMA_MODE_WRITE); /* * Set the DRAM address for the wave data */ if (iw_mode) { /* Different address translation in enhanced mode */ unsigned char hi; if (gus_dma > 4) address = target >> 1; /* Convert to 16 bit word address */ else address = target; hi = (unsigned char) ((address >> 16) & 0xf0); hi += (unsigned char) (address & 0x0f); gus_write16(0x42, (address >> 4) & 0xffff); /* DMA address (low) */ gus_write8(0x50, hi); } else { address = target; if (audio_devs[gus_devnum]->dmap_out->dma > 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 (audio_devs[gus_devnum]->dmap_out->dma > 3) dma_command |= 0x04; /* 16 bit DMA _channel_ */ gus_write8(0x41, dma_command); /* Lets go luteet (=bugs) */ /* * Sleep here until the DRAM DMA done interrupt is served */ active_device = GUS_DEV_WAVE; if (!interruptible_sleep_on_timeout(&dram_sleeper, HZ)) printk("GUS: DMA Transfer timed out\n"); restore_flags(flags); } /* * Now the next part */ left -= blk_sz; src_offs += blk_sz; target += blk_sz; gus_write8(0x41, 0); /* Stop DMA */ } free_mem_ptr += patch.len; free_sample++; return 0; } static void guswave_hw_control(int dev, unsigned char *event_rec) { int voice, cmd; unsigned short p1, p2; unsigned int plong; unsigned long flags; cmd = event_rec[2]; voice = event_rec[3]; p1 = *(unsigned short *) &event_rec[4]; p2 = *(unsigned short *) &event_rec[6]; plong = *(unsigned int *) &event_rec[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: save_flags(flags); cli(); gus_select_voice(voice); gus_select_max_voices(p1); restore_flags(flags); break; case _GUS_VOICESAMPLE: guswave_set_instr(dev, voice, p1); break; case _GUS_VOICEON: save_flags(flags); cli(); gus_select_voice(voice); p1 &= ~0x20; /* Don't allow interrupts */ gus_voice_on(p1); restore_flags(flags); break; case _GUS_VOICEOFF: save_flags(flags); cli(); gus_select_voice(voice); gus_voice_off(); restore_flags(flags); break; case _GUS_VOICEFADE: gus_voice_fade(voice); break; case _GUS_VOICEMODE: save_flags(flags); cli(); gus_select_voice(voice); p1 &= ~0x20; /* Don't allow interrupts */ gus_voice_mode(p1); restore_flags(flags); break; case _GUS_VOICEBALA: save_flags(flags); cli(); gus_select_voice(voice); gus_voice_balance(p1); restore_flags(flags); break; case _GUS_VOICEFREQ: save_flags(flags); cli(); gus_select_voice(voice); gus_voice_freq(plong); restore_flags(flags); break; case _GUS_VOICEVOL: save_flags(flags); cli(); gus_select_voice(voice); gus_voice_volume(p1); restore_flags(flags); break; case _GUS_VOICEVOL2: /* Just update the software voice level */ voices[voice].initial_volume = voices[voice].current_volume = p1; break; case _GUS_RAMPRANGE: if (voices[voice].mode & WAVE_ENVELOPES) break; /* NO-NO */ save_flags(flags); cli(); gus_select_voice(voice); gus_ramp_range(p1, p2); restore_flags(flags); break; case _GUS_RAMPRATE: if (voices[voice].mode & WAVE_ENVELOPES) break; /* NJET-NJET */ save_flags(flags); cli(); gus_select_voice(voice); gus_ramp_rate(p1, p2); restore_flags(flags); break; case _GUS_RAMPMODE: if (voices[voice].mode & WAVE_ENVELOPES) break; /* NO-NO */ save_flags(flags); cli(); gus_select_voice(voice); p1 &= ~0x20; /* Don't allow interrupts */ gus_ramp_mode(p1); restore_flags(flags); break; case _GUS_RAMPON: if (voices[voice].mode & WAVE_ENVELOPES) break; /* EI-EI */ save_flags(flags); cli(); gus_select_voice(voice); p1 &= ~0x20; /* Don't allow interrupts */ gus_rampon(p1); restore_flags(flags); break; case _GUS_RAMPOFF: if (voices[voice].mode & WAVE_ENVELOPES) break; /* NEJ-NEJ */ save_flags(flags); cli(); gus_select_voice(voice); gus_rampoff(); restore_flags(flags); break; case _GUS_VOLUME_SCALE: volume_base = p1; volume_scale = p2; break; case _GUS_VOICE_POS: save_flags(flags); cli(); gus_select_voice(voice); gus_set_voice_pos(voice, plong); restore_flags(flags); break; default: break; } } static int gus_audio_set_speed(int speed) { if (speed <= 0) speed = gus_audio_speed; if (speed < 4000) speed = 4000; if (speed > 44100) speed = 44100; gus_audio_speed = speed; if (only_read_access) { /* Compute nearest valid recording speed and return it */ /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */ speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; speed = (9878400 / (speed * 16)) - 2; } return speed; } static int gus_audio_set_channels(int channels) { if (!channels) return gus_audio_channels; if (channels > 2) channels = 2; if (channels < 1) channels = 1; gus_audio_channels = channels; return channels; } static int gus_audio_set_bits(int bits) { if (!bits) return gus_audio_bits; if (bits != 8 && bits != 16) bits = 8; if (only_8_bits) bits = 8; gus_audio_bits = bits; return bits; } static int gus_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) { int val; switch (cmd) { case SOUND_PCM_WRITE_RATE: if (get_user(val, (int *)arg)) return -EFAULT; val = gus_audio_set_speed(val); break; case SOUND_PCM_READ_RATE: val = gus_audio_speed; break; case SNDCTL_DSP_STEREO: if (get_user(val, (int *)arg)) return -EFAULT; val = gus_audio_set_channels(val + 1) - 1; break; case SOUND_PCM_WRITE_CHANNELS: if (get_user(val, (int *)arg)) return -EFAULT; val = gus_audio_set_channels(val); break; case SOUND_PCM_READ_CHANNELS: val = gus_audio_channels; break; case SNDCTL_DSP_SETFMT: if (get_user(val, (int *)arg)) return -EFAULT; val = gus_audio_set_bits(val); break; case SOUND_PCM_READ_BITS: val = gus_audio_bits; break; case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ case SOUND_PCM_READ_FILTER: val = -EINVAL; break; default: return -EINVAL; } return put_user(val, (int *)arg); } static void gus_audio_reset(int dev) { if (recording_active) { gus_write8(0x49, 0x00); /* Halt recording */ set_input_volumes(); } } static int saved_iw_mode; /* A hack hack hack */ static int gus_audio_open(int dev, int mode) { if (gus_busy) return -EBUSY; if (gus_pnp_flag && mode & OPEN_READ) { /* printk(KERN_ERR "GUS: Audio device #%d is playback only.\n", dev);*/ return -EIO; } gus_initialize(); gus_busy = 1; active_device = 0; saved_iw_mode = iw_mode; if (iw_mode) { /* There are some problems with audio in enhanced mode so disable it */ gus_write8(0x19, gus_read8(0x19) & ~0x01); /* Disable enhanced mode */ iw_mode = 0; } gus_reset(); reset_sample_memory(); gus_select_max_voices(14); pcm_active = 0; dma_active = 0; pcm_opened = 1; if (mode & OPEN_READ) { recording_active = 1; set_input_volumes(); } only_read_access = !(mode & OPEN_WRITE); only_8_bits = mode & OPEN_READ; if (only_8_bits) audio_devs[dev]->format_mask = AFMT_U8; else audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE; return 0; } static void gus_audio_close(int dev) { iw_mode = saved_iw_mode; gus_reset(); gus_busy = 0; pcm_opened = 0; active_device = 0; if (recording_active) { gus_write8(0x49, 0x00); /* Halt recording */ set_input_volumes(); } recording_active = 0; } static void gus_audio_update_volume(void) { unsigned long flags; int voice; if (pcm_active && pcm_opened) for (voice = 0; voice < gus_audio_channels; voice++) { save_flags(flags); cli(); gus_select_voice(voice); gus_rampoff(); gus_voice_volume(1530 + (25 * gus_pcm_volume)); gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); restore_flags(flags); } } static void play_next_pcm_block(void) { unsigned long flags; int speed = gus_audio_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_audio_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_audio_bits != 8) { is16bits = 1; mode[chn] |= 0x04; /* 16 bit data */ } else is16bits = 0; dram_loc = this_one * pcm_bsize; dram_loc += chn * pcm_banksize; if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */ { mode[chn] |= 0x08; /* Enable loop */ ramp_mode[chn] = 0x03; /* Disable rollover bit */ } else { if (chn == 0) ramp_mode[chn] = 0x04; /* Enable rollover bit */ } save_flags(flags); cli(); gus_select_voice(chn); gus_voice_freq(speed); if (gus_audio_channels == 1) gus_voice_balance(7); /* mono */ else if (chn == 0) gus_voice_balance(0); /* left */ else gus_voice_balance(15); /* right */ if (!pcm_active) /* Playback not already active */ { /* * The playback was not started yet (or there has been a pause). * Start the voice (again) and ask for a rollover irq at the end of * this_one block. If this_one one is last of the buffers, use just * the normal loop with irq. */ gus_voice_off(); gus_rampoff(); gus_voice_volume(1530 + (25 * gus_pcm_volume)); gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); gus_write_addr(0x0a, chn * pcm_banksize, 0, is16bits); /* Starting position */ gus_write_addr(0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */ if (chn != 0) gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, 0, is16bits); /* Loop end location */ } if (chn == 0) gus_write_addr(0x04, dram_loc + pcm_bsize - 1, 0, is16bits); /* Loop end location */ else mode[chn] |= 0x08; /* Enable looping */ restore_flags(flags); } for (chn = 0; chn < gus_audio_channels; chn++) { save_flags(flags); cli(); gus_select_voice(chn); gus_write8(0x0d, ramp_mode[chn]); if (iw_mode) gus_write8(0x15, 0x00); /* Reset voice deactivate bit of SMSI */ gus_voice_on(mode[chn]); restore_flags(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; save_flags(flags); cli(); count = total_count / gus_audio_channels; if (chn == 0) { if (pcm_qlen >= pcm_nblk) printk(KERN_WARNING "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 (audio_devs[dev]->dmap_out->dma > 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_audio_bits != 8) dma_command |= 0x40; /* 16 bit _DATA_ */ else dma_command |= 0x80; /* Invert MSB */ if (audio_devs[dev]->dmap_out->dma > 3) dma_command |= 0x04; /* 16 bit DMA channel */ gus_write8(0x41, dma_command); /* Kick start */ if (chn == (gus_audio_channels - 1)) /* Last channel */ { /* * Last (right or mono) channel data */ dma_active = 1; /* DMA started. There is a unacknowledged buffer */ active_device = GUS_DEV_PCM_DONE; if (!pcm_active && (pcm_qlen > 1 || 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_flags(flags); } static void gus_uninterleave8(char *buf, int l) { /* This routine uninterleaves 8 bit stereo output (LRLRLR->LLLRRR) */ int i, p = 0, halfsize = l / 2; char *buf2 = buf + halfsize, *src = bounce_buf; memcpy(bounce_buf, buf, l); for (i = 0; i < halfsize; i++) { buf[i] = src[p++]; /* Left channel */ buf2[i] = src[p++]; /* Right channel */ } } static void gus_uninterleave16(short *buf, int l) { /* This routine uninterleaves 16 bit stereo output (LRLRLR->LLLRRR) */ int i, p = 0, halfsize = l / 2; short *buf2 = buf + halfsize, *src = (short *) bounce_buf; memcpy(bounce_buf, (char *) buf, l * 2); for (i = 0; i < halfsize; i++) { buf[i] = src[p++]; /* Left channel */ buf2[i] = src[p++]; /* Right channel */ } } static void gus_audio_output_block(int dev, unsigned long buf, int total_count, int intrflag) { struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; dmap->flags |= DMA_NODMA | DMA_NOTIMEOUT; pcm_current_buf = buf; pcm_current_count = total_count; pcm_current_intrflag = intrflag; pcm_current_dev = dev; if (gus_audio_channels == 2) { char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys); if (gus_audio_bits == 8) gus_uninterleave8(b, total_count); else gus_uninterleave16((short *) b, total_count / 2); } gus_transfer_output_block(dev, buf, total_count, intrflag, 0); } static void gus_audio_start_input(int dev, unsigned long buf, int count, int intrflag) { unsigned long flags; unsigned char mode; save_flags(flags); cli(); DMAbuf_start_dma(dev, buf, count, DMA_MODE_READ); mode = 0xa0; /* DMA IRQ enabled, invert MSB */ if (audio_devs[dev]->dmap_in->dma > 3) mode |= 0x04; /* 16 bit DMA channel */ if (gus_audio_channels > 1) mode |= 0x02; /* Stereo */ mode |= 0x01; /* DMA enable */ gus_write8(0x49, mode); restore_flags(flags); } static int gus_audio_prepare_for_input(int dev, int bsize, int bcount) { unsigned int rate; gus_audio_bsize = bsize; audio_devs[dev]->dmap_in->flags |= DMA_NODMA; rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; gus_write8(0x48, rate & 0xff); /* Set sampling rate */ if (gus_audio_bits != 8) { /* printk("GUS Error: 16 bit recording not supported\n");*/ return -EINVAL; } return 0; } static int gus_audio_prepare_for_output(int dev, int bsize, int bcount) { int i; long mem_ptr, mem_size; audio_devs[dev]->dmap_out->flags |= DMA_NODMA | DMA_NOTIMEOUT; mem_ptr = 0; mem_size = gus_mem_size / gus_audio_channels; if (mem_size > (256 * 1024)) mem_size = 256 * 1024; pcm_bsize = bsize / gus_audio_channels; pcm_head = pcm_tail = pcm_qlen = 0; pcm_nblk = 2; /* 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_audio_bits != 8 && pcm_banksize == (256 * 1024)) pcm_nblk--; gus_write8(0x41, 0); /* Disable GF1 DMA */ return 0; } static int gus_local_qlen(int dev) { return pcm_qlen; } static struct audio_driver gus_audio_driver = { owner: THIS_MODULE, open: gus_audio_open, close: gus_audio_close, output_block: gus_audio_output_block, start_input: gus_audio_start_input, ioctl: gus_audio_ioctl, prepare_for_input: gus_audio_prepare_for_input, prepare_for_output: gus_audio_prepare_for_output, halt_io: gus_audio_reset, local_qlen: gus_local_qlen, }; static void guswave_setup_voice(int dev, int voice, int chn) { struct channel_info *info = &synth_devs[dev]->chn_info[chn]; guswave_set_instr(dev, voice, info->pgm_num); voices[voice].expression_vol = info->controllers[CTL_EXPRESSION]; /* Just MSB */ voices[voice].main_vol = (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; voices[voice].panning = (info->controllers[CTL_PAN] * 2) - 128; voices[voice].bender = 0; voices[voice].bender_range = info->bender_range; if (chn == 9) voices[voice].fixed_pitch = 1; } 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 - 8192, voices[voice].bender_range, 0); voices[voice].current_freq = freq; save_flags(flags); cli(); gus_select_voice(voice); gus_voice_freq(freq); restore_flags(flags); } static int guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc) { int i, p, best = -1, best_time = 0x7fffffff; p = alloc->ptr; /* * First look for a completely stopped voice */ for (i = 0; i < alloc->max_voice; i++) { if (alloc->map[p] == 0) { alloc->ptr = p; return p; } if (alloc->alloc_times[p] < best_time) { best = p; best_time = alloc->alloc_times[p]; } p = (p + 1) % alloc->max_voice; } /* * Then look for a releasing voice */ for (i = 0; i < alloc->max_voice; i++) { if (alloc->map[p] == 0xffff) { alloc->ptr = p; return p; } p = (p + 1) % alloc->max_voice; } if (best >= 0) p = best; alloc->ptr = p; return p; } static struct synth_operations guswave_operations = { owner: THIS_MODULE, id: "GUS", info: &gus_info, midi_dev: 0, synth_type: SYNTH_TYPE_SAMPLE, synth_subtype: SAMPLE_TYPE_GUS, open: guswave_open, close: guswave_close, ioctl: guswave_ioctl, kill_note: guswave_kill_note, start_note: guswave_start_note, set_instr: guswave_set_instr, reset: guswave_reset, hw_control: guswave_hw_control, load_patch: guswave_load_patch, aftertouch: guswave_aftertouch, controller: guswave_controller, panning: guswave_panning, volume_method: guswave_volume_method, bender: guswave_bender, alloc_voice: guswave_alloc, setup_voice: guswave_setup_voice }; static void set_input_volumes(void) { unsigned long flags; unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ if (have_gus_max) /* Don't disturb GUS MAX */ return; save_flags(flags); cli(); /* * Enable channels having vol > 10% * Note! bit 0x01 means the line in DISABLED while 0x04 means * the mic in ENABLED. */ if (gus_line_vol > 10) mask &= ~0x01; if (gus_mic_vol > 10) mask |= 0x04; if (recording_active) { /* * Disable channel, if not selected for recording */ if (!(gus_recmask & SOUND_MASK_LINE)) mask |= 0x01; if (!(gus_recmask & SOUND_MASK_MIC)) mask &= ~0x04; } mix_image &= ~0x07; mix_image |= mask & 0x07; outb((mix_image), u_Mixer); restore_flags(flags); } #define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \ SOUND_MASK_SYNTH|SOUND_MASK_PCM) int gus_default_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { int vol, val; if (((cmd >> 8) & 0xff) != 'M') return -EINVAL; if (!access_ok(VERIFY_WRITE, (int *)arg, sizeof(int))) return -EFAULT; if (_SIOC_DIR(cmd) & _SIOC_WRITE) { if (__get_user(val, (int *) arg)) return -EFAULT; switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: gus_recmask = val & 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 */ val = gus_recmask; break; case SOUND_MIXER_MIC: vol = val & 0xff; if (vol < 0) vol = 0; if (vol > 100) vol = 100; gus_mic_vol = vol; set_input_volumes(); val = vol | (vol << 8); break; case SOUND_MIXER_LINE: vol = val & 0xff; if (vol < 0) vol = 0; if (vol > 100) vol = 100; gus_line_vol = vol; set_input_volumes(); val = vol | (vol << 8); break; case SOUND_MIXER_PCM: gus_pcm_volume = val & 0xff; if (gus_pcm_volume < 0) gus_pcm_volume = 0; if (gus_pcm_volume > 100) gus_pcm_volume = 100; gus_audio_update_volume(); val = gus_pcm_volume | (gus_pcm_volume << 8); break; case SOUND_MIXER_SYNTH: gus_wave_volume = val & 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) { int voice; for (voice = 0; voice < nr_voices; voice++) dynamic_volume_change(voice); /* Apply the new vol */ } val = gus_wave_volume | (gus_wave_volume << 8); break; default: return -EINVAL; } } else { switch (cmd & 0xff) { /* * Return parameters */ case SOUND_MIXER_RECSRC: val = gus_recmask; break; case SOUND_MIXER_DEVMASK: val = MIX_DEVS; break; case SOUND_MIXER_STEREODEVS: val = 0; break; case SOUND_MIXER_RECMASK: val = SOUND_MASK_MIC | SOUND_MASK_LINE; break; case SOUND_MIXER_CAPS: val = 0; break; case SOUND_MIXER_MIC: val = gus_mic_vol | (gus_mic_vol << 8); break; case SOUND_MIXER_LINE: val = gus_line_vol | (gus_line_vol << 8); break; case SOUND_MIXER_PCM: val = gus_pcm_volume | (gus_pcm_volume << 8); break; case SOUND_MIXER_SYNTH: val = gus_wave_volume | (gus_wave_volume << 8); break; default: return -EINVAL; } } return __put_user(val, (int *)arg); } static struct mixer_operations gus_mixer_operations = { owner: THIS_MODULE, id: "GUS", name: "Gravis Ultrasound", ioctl: gus_default_mixer_ioctl }; static int __init gus_default_mixer_init(void) { int n; if ((n = sound_alloc_mixerdev()) != -1) { /* * Don't install if there is another * mixer */ mixer_devs[n] = &gus_mixer_operations; } if (have_gus_max) { /* * Enable all mixer channels on the GF1 side. Otherwise recording will * not be possible using GUS MAX. */ mix_image &= ~0x07; mix_image |= 0x04; /* All channels enabled */ outb((mix_image), u_Mixer); } return n; } void __init gus_wave_init(struct address_info *hw_config) { unsigned long flags; unsigned char val; char *model_num = "2.4"; char tmp[64], tmp2[64]; int gus_type = 0x24; /* 2.4 */ int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2; int sdev; hw_config->slots[0] = -1; /* No wave */ hw_config->slots[1] = -1; /* No ad1848 */ hw_config->slots[4] = -1; /* No audio */ hw_config->slots[5] = -1; /* No mixer */ if (!gus_pnp_flag) { if (irq < 0 || irq > 15) { printk(KERN_ERR "ERROR! Invalid IRQ#%d. GUS Disabled", irq); return; } } if (dma < 0 || dma > 7 || dma == 4) { printk(KERN_ERR "ERROR! Invalid DMA#%d. GUS Disabled", dma); return; } gus_irq = irq; gus_dma = dma; gus_dma2 = dma2; gus_hw_config = hw_config; if (gus_dma2 == -1) gus_dma2 = dma; /* * Try to identify the GUS model. * * Versions < 3.6 don't have the digital ASIC. Try to probe it first. */ save_flags(flags); cli(); outb((0x20), gus_base + 0x0f); val = inb(gus_base + 0x0f); restore_flags(flags); if (gus_pnp_flag || (val != 0xff && (val & 0x06))) /* Should be 0x02?? */ { int ad_flags = 0; if (gus_pnp_flag) ad_flags = 0x12345678; /* Interwave "magic" */ /* * It has the digital ASIC so the card is at least v3.4. * Next try to detect the true model. */ if (gus_pnp_flag) /* Hack hack hack */ val = 10; else val = inb(u_MixSelect); /* * Value 255 means pre-3.7 which don't have mixer. * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer. * 10 and above is GUS MAX which has the CS4231 codec/mixer. * */ if (val == 255 || val < 5) { model_num = "3.4"; gus_type = 0x34; } else if (val < 10) { model_num = "3.7"; gus_type = 0x37; mixer_type = ICS2101; request_region(u_MixSelect, 1, "GUS mixer"); } else { model_num = "MAX"; gus_type = 0x40; mixer_type = CS4231; #ifdef CONFIG_SOUND_GUSMAX { unsigned char max_config = 0x40; /* Codec enable */ if (gus_dma2 == -1) gus_dma2 = gus_dma; if (gus_dma > 3) max_config |= 0x10; /* 16 bit capture DMA */ if (gus_dma2 > 3) max_config |= 0x20; /* 16 bit playback DMA */ max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */ outb((max_config), gus_base + 0x106); /* UltraMax control */ } if (ad1848_detect(gus_base + 0x10c, &ad_flags, hw_config->osp)) { char *name = "GUS MAX"; int old_num_mixers = num_mixers; if (gus_pnp_flag) name = "GUS PnP"; gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; gus_wave_volume = 90; have_gus_max = 1; if (hw_config->name) name = hw_config->name; hw_config->slots[1] = ad1848_init(name, gus_base + 0x10c, -irq, gus_dma2, /* Playback DMA */ gus_dma, /* Capture DMA */ 1, /* Share DMA channels with GF1 */ hw_config->osp, THIS_MODULE); if (num_mixers > old_num_mixers) { /* GUS has it's own mixer map */ AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH); AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE); } } else printk(KERN_WARNING "GUS: No CS4231 ??"); #else printk(KERN_ERR "GUS MAX found, but not compiled in\n"); #endif } } else { /* * ASIC not detected so the card must be 2.2 or 2.4. * There could still be the 16-bit/mixer daughter card. */ } if (hw_config->name) { strncpy(tmp, hw_config->name, 45); tmp[45] = 0; sprintf(tmp2, "%s (%dk)", tmp, (int) gus_mem_size / 1024); tmp2[sizeof(tmp2) - 1] = 0; } else if (gus_pnp_flag) { sprintf(tmp2, "Gravis UltraSound PnP (%dk)", (int) gus_mem_size / 1024); } else sprintf(tmp2, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024); samples = (struct patch_info *)vmalloc((MAX_SAMPLE + 1) * sizeof(*samples)); if (samples == NULL) { printk(KERN_WARNING "gus_init: Cant allocate memory for instrument tables\n"); return; } conf_printf(tmp2, hw_config); tmp2[sizeof(gus_info.name) - 1] = 0; strcpy(gus_info.name, tmp2); if ((sdev = sound_alloc_synthdev()) == -1) printk(KERN_WARNING "gus_init: Too many synthesizers\n"); else { voice_alloc = &guswave_operations.alloc; if (iw_mode) guswave_operations.id = "IWAVE"; hw_config->slots[0] = sdev; synth_devs[sdev] = &guswave_operations; sequencer_init(); gus_tmr_install(gus_base + 8); } reset_sample_memory(); gus_initialize(); if ((gus_mem_size > 0) && !gus_no_wave_dma) { hw_config->slots[4] = -1; if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION, "Ultrasound", &gus_audio_driver, sizeof(struct audio_driver), NEEDS_RESTART | ((!iw_mode && dma2 != dma && dma2 != -1) ? DMA_DUPLEX : 0), AFMT_U8 | AFMT_S16_LE, NULL, dma, dma2)) < 0) { return; } hw_config->slots[4] = gus_devnum; audio_devs[gus_devnum]->min_fragment = 9; /* 512k */ audio_devs[gus_devnum]->max_fragment = 11; /* 8k (must match size of bounce_buf */ audio_devs[gus_devnum]->mixer_dev = -1; /* Next mixer# */ audio_devs[gus_devnum]->flags |= DMA_HARDSTOP; } /* * Mixer dependent initialization. */ switch (mixer_type) { case ICS2101: gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; gus_wave_volume = 90; request_region(u_MixSelect, 1, "GUS mixer"); hw_config->slots[5] = ics2101_mixer_init(); audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5]; /* Next mixer# */ return; case CS4231: /* Initialized elsewhere (ad1848.c) */ default: hw_config->slots[5] = gus_default_mixer_init(); audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5]; /* Next mixer# */ return; } } void __exit gus_wave_unload(struct address_info *hw_config) { #ifdef CONFIG_SOUND_GUSMAX if (have_gus_max) { ad1848_unload(gus_base + 0x10c, -gus_irq, gus_dma2, /* Playback DMA */ gus_dma, /* Capture DMA */ 1); /* Share DMA channels with GF1 */ } #endif if (mixer_type == ICS2101) { release_region(u_MixSelect, 1); } if (hw_config->slots[0] != -1) sound_unload_synthdev(hw_config->slots[0]); if (hw_config->slots[1] != -1) sound_unload_audiodev(hw_config->slots[1]); if (hw_config->slots[2] != -1) sound_unload_mididev(hw_config->slots[2]); if (hw_config->slots[4] != -1) sound_unload_audiodev(hw_config->slots[4]); if (hw_config->slots[5] != -1) sound_unload_mixerdev(hw_config->slots[5]); if(samples) vfree(samples); samples=NULL; } static void do_loop_irq(int voice) { unsigned char tmp; int mode, parm; unsigned long flags; save_flags(flags); cli(); gus_select_voice(voice); tmp = gus_read8(0x00); tmp &= ~0x20; /* * Disable wave IRQ for this_one voice */ gus_write8(0x00, tmp); if (tmp & 0x03) /* Voice stopped */ voice_alloc->map[voice] = 0; mode = voices[voice].loop_irq_mode; voices[voice].loop_irq_mode = 0; parm = voices[voice].loop_irq_parm; switch (mode) { case LMODE_FINISH: /* * Final loop finished, shoot volume down */ if ((int) (gus_read16(0x09) >> 4) < 100) /* * Get current volume */ { gus_voice_off(); gus_rampoff(); gus_voice_init(voice); break; } gus_ramp_range(65, 4065); gus_ramp_rate(0, 63); /* * Fastest possible rate */ gus_rampon(0x20 | 0x40); /* * Ramp down, once, irq */ voices[voice].volume_irq_mode = VMODE_HALT; break; case LMODE_PCM_STOP: pcm_active = 0; /* Signal to the play_next_pcm_block routine */ case LMODE_PCM: { pcm_qlen--; pcm_head = (pcm_head + 1) % pcm_nblk; if (pcm_qlen && pcm_active) { play_next_pcm_block(); } else { /* Underrun. Just stop the voice */ gus_select_voice(0); /* Left channel */ gus_voice_off(); gus_rampoff(); gus_select_voice(1); /* Right channel */ gus_voice_off(); gus_rampoff(); pcm_active = 0; } /* * If the queue was full before this interrupt, the DMA transfer was * suspended. Let it continue now. */ if (audio_devs[gus_devnum]->dmap_out->qlen > 0) DMAbuf_outputintr(gus_devnum, 0); } break; default: break; } restore_flags(flags); } static void do_volume_irq(int voice) { unsigned char tmp; int mode, parm; unsigned long flags; save_flags(flags); cli(); 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 */ if (iw_mode) gus_write8(0x15, 0x02); /* Set voice deactivate bit of SMSI */ restore_flags(flags); gus_voice_init(voice); break; case VMODE_ENVELOPE: gus_rampoff(); restore_flags(flags); step_envelope(voice); break; case VMODE_START_NOTE: restore_flags(flags); guswave_start_note2(voices[voice].dev_pending, voice, voices[voice].note_pending, voices[voice].volume_pending); if (voices[voice].kill_pending) guswave_kill_note(voices[voice].dev_pending, voice, voices[voice].note_pending, 0); if (voices[voice].sample_pending >= 0) { guswave_set_instr(voices[voice].dev_pending, voice, voices[voice].sample_pending); voices[voice].sample_pending = -1; } break; default: restore_flags(flags); } restore_flags(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) && (int) voice < nr_voices) /* * Not done * yet */ { wave_ignore |= voice_bit; do_loop_irq(voice); } if (!(src & 0x40)) /* * Volume IRQ pending */ if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /* * Not done * yet */ { volume_ignore |= voice_bit; do_volume_irq(voice); } } } void guswave_dma_irq(void) { unsigned char status; status = gus_look8(0x41); /* Get DMA IRQ Status */ if (status & 0x40) /* DMA interrupt pending */ switch (active_device) { case GUS_DEV_WAVE: wake_up(&dram_sleeper); break; case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */ gus_write8(0x41, 0); /* Disable GF1 DMA */ gus_transfer_output_block(pcm_current_dev, pcm_current_buf, pcm_current_count, pcm_current_intrflag, 1); break; case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */ gus_write8(0x41, 0); /* Disable GF1 DMA */ if (pcm_qlen < pcm_nblk) { dma_active = 0; if (gus_busy) { if (audio_devs[gus_devnum]->dmap_out->qlen > 0) DMAbuf_outputintr(gus_devnum, 0); } } break; default: break; } status = gus_look8(0x49); /* * Get Sampling IRQ Status */ if (status & 0x40) /* * Sampling Irq pending */ { DMAbuf_inputintr(gus_devnum); } } /* * Timer stuff */ static volatile int select_addr, data_addr; static volatile int curr_timer = 0; void gus_timer_command(unsigned int addr, unsigned int val) { int i; outb(((unsigned char) (addr & 0xff)), select_addr); for (i = 0; i < 2; i++) inb(select_addr); outb(((unsigned char) (val & 0xff)), data_addr); for (i = 0; i < 2; i++) inb(select_addr); } static void arm_timer(int timer, unsigned int interval) { curr_timer = timer; if (timer == 1) { gus_write8(0x46, 256 - interval); /* Set counter for timer 1 */ gus_write8(0x45, 0x04); /* Enable timer 1 IRQ */ gus_timer_command(0x04, 0x01); /* Start timer 1 */ } else { gus_write8(0x47, 256 - interval); /* Set counter for timer 2 */ gus_write8(0x45, 0x08); /* Enable timer 2 IRQ */ gus_timer_command(0x04, 0x02); /* Start timer 2 */ } gus_timer_enabled = 1; } static unsigned int gus_tmr_start(int dev, unsigned int usecs_per_tick) { int timer_no, resolution; int divisor; if (usecs_per_tick > (256 * 80)) { timer_no = 2; resolution = 320; /* usec */ } else { timer_no = 1; resolution = 80; /* usec */ } divisor = (usecs_per_tick + (resolution / 2)) / resolution; arm_timer(timer_no, divisor); return divisor * resolution; } static void gus_tmr_disable(int dev) { gus_write8(0x45, 0); /* Disable both timers */ gus_timer_enabled = 0; } static void gus_tmr_restart(int dev) { if (curr_timer == 1) gus_write8(0x45, 0x04); /* Start timer 1 again */ else gus_write8(0x45, 0x08); /* Start timer 2 again */ gus_timer_enabled = 1; } static struct sound_lowlev_timer gus_tmr = { 0, 1, gus_tmr_start, gus_tmr_disable, gus_tmr_restart }; static void gus_tmr_install(int io_base) { struct sound_lowlev_timer *tmr; select_addr = io_base; data_addr = io_base + 1; tmr = &gus_tmr; #ifdef THIS_GETS_FIXED sound_timer_init(&gus_tmr, "GUS"); #endif }