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