📄 gus_wave.c
字号:
* right data to the area pointed by gus_page_size. */ int this_one, count; unsigned long flags; unsigned char dma_command; unsigned long address, hold_address; DISABLE_INTR (flags); count = total_count / gus_sampling_channels; if (chn == 0) { if (pcm_qlen >= pcm_nblk) printk ("GUS Warning: PCM buffers out of sync\n"); this_one = pcm_current_block = pcm_tail; pcm_qlen++; pcm_tail = (pcm_tail + 1) % pcm_nblk; pcm_datasize[this_one] = count; } else this_one = pcm_current_block; gus_write8 (0x41, 0); /* * Disable GF1 DMA */ DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE); address = this_one * pcm_bsize; address += chn * pcm_banksize; if (sound_dsp_dmachan[dev] > 3) { hold_address = address; address = address >> 1; address &= 0x0001ffffL; address |= (hold_address & 0x000c0000L); } gus_write16 (0x42, (address >> 4) & 0xffff); /* * DRAM DMA address */ dma_command = 0x21; /* * IRQ enable, DMA start */ if (gus_sampling_bits != 8) dma_command |= 0x40; /* * 16 bit _DATA_ */ else dma_command |= 0x80; /* * Invert MSB */ if (sound_dsp_dmachan[dev] > 3) dma_command |= 0x04; /* * 16 bit DMA channel */ gus_write8 (0x41, dma_command); /* * Kick on */ if (chn == (gus_sampling_channels - 1)) /* * Last channel */ { /* * Last (right or mono) channel data */ active_device = GUS_DEV_PCM_DONE; if (!pcm_active && (pcm_qlen > 2 || count < pcm_bsize)) { play_next_pcm_block (); } } else /* * * * Left channel data. The right channel * is * * * transferred after DMA interrupt */ active_device = GUS_DEV_PCM_CONTINUE; RESTORE_INTR (flags);}static voidgus_sampling_output_block (int dev, unsigned long buf, int total_count, int intrflag, int restart_dma){ pcm_current_buf = buf; pcm_current_count = total_count; pcm_current_intrflag = intrflag; pcm_current_dev = dev; gus_transfer_output_block (dev, buf, total_count, intrflag, 0);}static voidgus_sampling_start_input (int dev, unsigned long buf, int count, int intrflag, int restart_dma){ unsigned long flags; unsigned char mode; DISABLE_INTR (flags); DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); mode = 0xa0; /* * DMA IRQ enable, invert MSB */ if (sound_dsp_dmachan[dev] > 3) mode |= 0x04; /* * 16 bit DMA channel */ if (gus_sampling_channels > 1) mode |= 0x02; /* * Stereo */ mode |= 0x01; /* * DMA enable */ gus_write8 (0x49, mode); RESTORE_INTR (flags);}static intgus_sampling_prepare_for_input (int dev, int bsize, int bcount){ unsigned int rate; rate = (9878400 / (gus_sampling_speed + 2)) / 16; gus_write8 (0x48, rate & 0xff); /* * Set sampling frequency */ if (gus_sampling_bits != 8) { printk ("GUS Error: 16 bit recording not supported\n"); return RET_ERROR (EINVAL); } return 0;}static intgus_sampling_prepare_for_output (int dev, int bsize, int bcount){ int i; long mem_ptr, mem_size; mem_ptr = 0; mem_size = gus_mem_size / gus_sampling_channels; if (mem_size > (256 * 1024)) mem_size = 256 * 1024; pcm_bsize = bsize / gus_sampling_channels; pcm_head = pcm_tail = pcm_qlen = 0; pcm_nblk = MAX_PCM_BUFFERS; if ((pcm_bsize * pcm_nblk) > mem_size) pcm_nblk = mem_size / pcm_bsize; for (i = 0; i < pcm_nblk; i++) pcm_datasize[i] = 0; pcm_banksize = pcm_nblk * pcm_bsize; if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024)) pcm_nblk--; return 0;}static intgus_has_output_drained (int dev){ return !pcm_qlen;}static voidgus_copy_from_user (int dev, char *localbuf, int localoffs, snd_rw_buf * userbuf, int useroffs, int len){ if (gus_sampling_channels == 1) { COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len); } else if (gus_sampling_bits == 8) { int in_left = useroffs; int in_right = useroffs + 1; char *out_left, *out_right; int i; len /= 2; localoffs /= 2; out_left = &localbuf[localoffs]; out_right = out_left + pcm_bsize; for (i = 0; i < len; i++) { GET_BYTE_FROM_USER (*out_left++, userbuf, in_left); in_left += 2; GET_BYTE_FROM_USER (*out_right++, userbuf, in_right); in_right += 2; } } else { int in_left = useroffs; int in_right = useroffs + 1; short *out_left, *out_right; int i; len /= 4; localoffs /= 4; out_left = (short *) &localbuf[localoffs]; out_right = out_left + (pcm_bsize / 2); for (i = 0; i < len; i++) { GET_SHORT_FROM_USER (*out_left++, (short *) userbuf, in_left); in_left += 2; GET_SHORT_FROM_USER (*out_right++, (short *) userbuf, in_right); in_right += 2; } }}static struct audio_operations gus_sampling_operations ={ "Gravis UltraSound", gus_sampling_open, gus_sampling_close, gus_sampling_output_block, gus_sampling_start_input, gus_sampling_ioctl, gus_sampling_prepare_for_input, gus_sampling_prepare_for_output, gus_sampling_reset, gus_sampling_reset, gus_has_output_drained, gus_copy_from_user};#ifdef FUTURE_VERSIONstatic voidguswave_bender (int dev, int voice, int value){ int freq; unsigned long flags; voices[voice].bender = value - 8192; freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range); voices[voice].current_freq = freq; DISABLE_INTR (flags); gus_select_voice (voice); gus_voice_freq (freq); RESTORE_INTR (flags);}#endifstatic intguswave_patchmgr (int dev, struct patmgr_info *rec){ int i, n; switch (rec->command) { case PM_GET_DEVTYPE: rec->parm1 = PMTYPE_WAVE; return 0; break; case PM_GET_NRPGM: rec->parm1 = MAX_PATCH; return 0; break; case PM_GET_PGMMAP: rec->parm1 = MAX_PATCH; for (i = 0; i < MAX_PATCH; i++) { int ptr = patch_table[i]; rec->data.data8[i] = 0; while (ptr >= 0 && ptr < free_sample) { rec->data.data8[i]++; ptr = samples[ptr].key; /* * Follow link */ } } return 0; break; case PM_GET_PGM_PATCHES: { int ptr = patch_table[rec->parm1]; n = 0; while (ptr >= 0 && ptr < free_sample) { rec->data.data32[n++] = ptr; ptr = samples[ptr].key; /* * Follow link */ } } rec->parm1 = n; return 0; break; case PM_GET_PATCH: { int ptr = rec->parm1; struct patch_info *pat; if (ptr < 0 || ptr >= free_sample) return RET_ERROR (EINVAL); memcpy (rec->data.data8, (char *) &samples[ptr], sizeof (struct patch_info)); pat = (struct patch_info *) rec->data.data8; pat->key = GUS_PATCH; /* * Restore patch type */ rec->parm1 = sample_ptrs[ptr]; /* * DRAM address */ rec->parm2 = sizeof (struct patch_info); } return 0; break; case PM_SET_PATCH: { int ptr = rec->parm1; struct patch_info *pat; if (ptr < 0 || ptr >= free_sample) return RET_ERROR (EINVAL); pat = (struct patch_info *) rec->data.data8; if (pat->len > samples[ptr].len) /* * Cannot expand sample */ return RET_ERROR (EINVAL); pat->key = samples[ptr].key; /* * Ensure the link is correct */ memcpy ((char *) &samples[ptr], rec->data.data8, sizeof (struct patch_info)); pat->key = GUS_PATCH; } return 0; break; case PM_READ_PATCH: /* * Returns a block of wave data from the DRAM */ { int sample = rec->parm1; int n; long offs = rec->parm2; int l = rec->parm3; if (sample < 0 || sample >= free_sample) return RET_ERROR (EINVAL); if (offs < 0 || offs >= samples[sample].len) return RET_ERROR (EINVAL); /* * Invalid offset */ n = samples[sample].len - offs; /* * Nr of bytes left */ if (l > n) l = n; if (l > sizeof (rec->data.data8)) l = sizeof (rec->data.data8); if (l <= 0) return RET_ERROR (EINVAL); /* * Was there a bug? */ offs += sample_ptrs[sample]; /* * Begin offsess + offset to DRAM */ for (n = 0; n < l; n++) rec->data.data8[n] = gus_peek (offs++); rec->parm1 = n; /* * Nr of bytes copied */ } return 0; break; case PM_WRITE_PATCH: /* * Writes a block of wave data to the DRAM */ { int sample = rec->parm1; int n; long offs = rec->parm2; int l = rec->parm3; if (sample < 0 || sample >= free_sample) return RET_ERROR (EINVAL); if (offs < 0 || offs >= samples[sample].len) return RET_ERROR (EINVAL); /* * Invalid offset */ n = samples[sample].len - offs; /* * Nr of bytes left */ if (l > n) l = n; if (l > sizeof (rec->data.data8)) l = sizeof (rec->data.data8); if (l <= 0) return RET_ERROR (EINVAL); /* * Was there a bug? */ offs += sample_ptrs[sample]; /* * Begin offsess + offset to DRAM */ for (n = 0; n < l; n++) gus_poke (offs++, rec->data.data8[n]); rec->parm1 = n; /* * Nr of bytes copied */ } return 0; break; default: return RET_ERROR (EINVAL); }}static struct synth_operations guswave_operations ={ &gus_info,#ifdef FUTURE_VERSION 0,#endif SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, guswave_open, guswave_close, guswave_ioctl, guswave_kill_note, guswave_start_note, guswave_set_instr, guswave_reset, guswave_hw_control, guswave_load_patch, guswave_aftertouch, guswave_controller, guswave_panning, guswave_patchmgr,#ifdef FUTURE_VERSION guswave_bender#endif};static voidset_input_volumes(void){ unsigned long flags; unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ DISABLE_INTR(flags);/* * Enable channels having vol > 10% * Note! bit 0x01 means line in DISABLED while 0x04 means * mic in ENABLED. */ if (gus_line_vol > 10) mask &= ~0x01; if (gus_mic_vol > 10) mask |= 0x04; if (recording_active) {/* * Disable channel, if not selected for recording */ if (!(gus_recmask & SOUND_MASK_LINE)) mask |= 0x01; if (!(gus_recmask & SOUND_MASK_MIC)) mask &= ~0x04; } mix_image &= ~0x07; mix_image |= mask & 0x07; OUTB (mix_image, u_Mixer); RESTORE_INTR(flags);}static intgus_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg){#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \ SOUND_MASK_SYNTH|SOUND_MASK_PCM) if (((cmd >> 8) & 0xff) == 'M') { if (cmd & IOC_IN) switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: gus_recmask = IOCTL_IN(arg) & MIX_DEVS; if (!(gus_recmask & (SOUND_MASK_MIC|SOUND_MASK_LINE))) gus_recmask = SOUND_MASK_MIC; /* Note! Input volumes are updated during next open for recording */ return IOCTL_OUT (arg, gus_recmask); break; case SOUND_MIXER_MIC: { int vol = IOCTL_IN (arg) & 0xff; if (vol < 0) vol = 0; if (vol > 100) vol = 100; gus_mic_vol = vol; set_input_volumes(); return IOCTL_OUT (arg, vol | (vol << 8)); } break; case SOUND_MIXER_LINE: { int vol = IOCTL_IN (arg) & 0xff; if (vol < 0) vol = 0; if (vol > 100) vol = 100; gus_line_vol = vol; set_input_volumes(); return IOCTL_OUT (arg, vol | (vol << 8)); } break; case SOUND_MIXER_PCM: gus_pcm_volume = IOCTL_IN (arg) & 0xff; if (gus_pcm_volume < 0) gus_pcm_volume = 0; if (gus_pcm_volume > 100) gus_pcm_volume = 100; gus_sampling_update_volume (); return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8)); break; case SOUND_MIXER_SYNTH: { int voice; gus_wave_volume = IOCTL_IN (arg) & 0xff; if (gus_wave_volume < 0) gus_wave_volume = 0; if (gus_wave_volume > 100) gus_wave_volume = 100; if (active_device == GUS_DEV_WAVE) for (voice = 0; voice < nr_voices; voice++) dynamic_volume_change (voice); /* * Apply the new * volume */ return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8)); } break; default: return RET_ERROR (EINVAL); } else switch (cmd & 0xff) /* * Return parameters */ { case SOUND_MIXER_RECSRC: return IOCTL_OUT (arg, gus_recmask); break; case SOUND_MIXER_DEV
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -