📄 gus_wave.c
字号:
/* 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -