^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * pcm emulation on emu8000 wavetable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2002 Takashi Iwai <tiwai@suse.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include "emu8000_local.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/sched/signal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <sound/initval.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * define the following if you want to use this pcm with non-interleaved mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) /* #define USE_NONINTERLEAVE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) /* NOTE: for using the non-interleaved mode with alsa-lib, you have to set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * mmap_emulation flag to 1 in your .asoundrc, such like
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * pcm.emu8k {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * type plug
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * slave.pcm {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * type hw
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * card 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * device 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * mmap_emulation 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * besides, for the time being, the non-interleaved mode doesn't work well on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * alsa-lib...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct snd_emu8k_pcm {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct snd_emu8000 *emu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct snd_pcm_substream *substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) unsigned int allocated_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct snd_util_memblk *block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) unsigned int offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) unsigned int buf_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) unsigned int period_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) unsigned int loop_start[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) unsigned int pitch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) int panning[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) int last_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) int period_pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) int voices;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) unsigned int dram_opened: 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) unsigned int running: 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) unsigned int timer_running: 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct timer_list timer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) spinlock_t timer_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define LOOP_BLANK_SIZE 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * open up channels for the simultaneous data transfer and playback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) emu8k_open_dram_for_pcm(struct snd_emu8000 *emu, int channels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /* reserve up to 2 voices for playback */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) snd_emux_lock_voice(emu->emu, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (channels > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) snd_emux_lock_voice(emu->emu, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /* reserve 28 voices for loading */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) for (i = channels + 1; i < EMU8000_DRAM_VOICES; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) unsigned int mode = EMU8000_RAM_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) snd_emux_lock_voice(emu->emu, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #ifndef USE_NONINTERLEAVE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (channels > 1 && (i & 1) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) mode |= EMU8000_RAM_RIGHT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) snd_emu8000_dma_chan(emu, i, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) /* assign voice 31 and 32 to ROM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) EMU8000_VTFT_WRITE(emu, 30, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) EMU8000_PSST_WRITE(emu, 30, 0x1d8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) EMU8000_CSL_WRITE(emu, 30, 0x1e0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) EMU8000_CCCA_WRITE(emu, 30, 0x1d8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) EMU8000_VTFT_WRITE(emu, 31, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) EMU8000_PSST_WRITE(emu, 31, 0x1d8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) EMU8000_CSL_WRITE(emu, 31, 0x1e0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) EMU8000_CCCA_WRITE(emu, 31, 0x1d8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) snd_emu8000_write_wait(struct snd_emu8000 *emu, int can_schedule)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (can_schedule) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) schedule_timeout_interruptible(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (signal_pending(current))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * close all channels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) emu8k_close_dram(struct snd_emu8000 *emu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) for (i = 0; i < 2; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) snd_emux_unlock_voice(emu->emu, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) for (; i < EMU8000_DRAM_VOICES; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) snd_emu8000_dma_chan(emu, i, EMU8000_RAM_CLOSE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) snd_emux_unlock_voice(emu->emu, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * convert Hz to AWE32 rate offset (see emux/soundfont.c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) #define OFFSET_SAMPLERATE 1011119 /* base = 44100 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) #define SAMPLERATE_RATIO 4096
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static int calc_rate_offset(int hz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return snd_sf_linear_to_log(hz, OFFSET_SAMPLERATE, SAMPLERATE_RATIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) static const struct snd_pcm_hardware emu8k_pcm_hw = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) #ifdef USE_NONINTERLEAVE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) .info = SNDRV_PCM_INFO_NONINTERLEAVED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) .info = SNDRV_PCM_INFO_INTERLEAVED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) .formats = SNDRV_PCM_FMTBIT_S16_LE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) .rate_min = 4000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) .rate_max = 48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) .channels_min = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) .channels_max = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .buffer_bytes_max = (128*1024),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .period_bytes_min = 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) .period_bytes_max = (128*1024),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) .periods_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .periods_max = 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .fifo_size = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * get the current position at the given channel from CCCA register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static inline int emu8k_get_curpos(struct snd_emu8k_pcm *rec, int ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) int val = EMU8000_CCCA_READ(rec->emu, ch) & 0xfffffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) val -= rec->loop_start[ch] - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * timer interrupt handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * check the current position and update the period if necessary.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) static void emu8k_pcm_timer_func(struct timer_list *t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) struct snd_emu8k_pcm *rec = from_timer(rec, t, timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) int ptr, delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) spin_lock(&rec->timer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) /* update the current pointer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) ptr = emu8k_get_curpos(rec, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (ptr < rec->last_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) delta = ptr + rec->buf_size - rec->last_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) delta = ptr - rec->last_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) rec->period_pos += delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) rec->last_ptr = ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /* reprogram timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) mod_timer(&rec->timer, jiffies + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) /* update period */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (rec->period_pos >= (int)rec->period_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) rec->period_pos %= rec->period_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) spin_unlock(&rec->timer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) snd_pcm_period_elapsed(rec->substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) spin_unlock(&rec->timer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) * open pcm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * creating an instance here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) static int emu8k_pcm_open(struct snd_pcm_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) struct snd_emu8000 *emu = snd_pcm_substream_chip(subs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) struct snd_emu8k_pcm *rec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) struct snd_pcm_runtime *runtime = subs->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) rec = kzalloc(sizeof(*rec), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (! rec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) rec->emu = emu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) rec->substream = subs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) runtime->private_data = rec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) spin_lock_init(&rec->timer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) timer_setup(&rec->timer, emu8k_pcm_timer_func, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) runtime->hw = emu8k_pcm_hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) runtime->hw.buffer_bytes_max = emu->mem_size - LOOP_BLANK_SIZE * 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) runtime->hw.period_bytes_max = runtime->hw.buffer_bytes_max / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) /* use timer to update periods.. (specified in msec) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) (1000000 + HZ - 1) / HZ, UINT_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) static int emu8k_pcm_close(struct snd_pcm_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) struct snd_emu8k_pcm *rec = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) kfree(rec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) subs->runtime->private_data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * calculate pitch target
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) static int calc_pitch_target(int pitch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) int ptarget = 1 << (pitch >> 12);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (pitch & 0x800) ptarget += (ptarget * 0x102e) / 0x2710;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (pitch & 0x400) ptarget += (ptarget * 0x764) / 0x2710;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (pitch & 0x200) ptarget += (ptarget * 0x389) / 0x2710;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) ptarget += (ptarget >> 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (ptarget > 0xffff) ptarget = 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return ptarget;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) * set up the voice
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) static void setup_voice(struct snd_emu8k_pcm *rec, int ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) struct snd_emu8000 *hw = rec->emu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) unsigned int temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) /* channel to be silent and idle */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) EMU8000_DCYSUSV_WRITE(hw, ch, 0x0080);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) EMU8000_VTFT_WRITE(hw, ch, 0x0000FFFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) EMU8000_CVCF_WRITE(hw, ch, 0x0000FFFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) EMU8000_PTRX_WRITE(hw, ch, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) EMU8000_CPF_WRITE(hw, ch, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /* pitch offset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) EMU8000_IP_WRITE(hw, ch, rec->pitch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) /* set envelope parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) EMU8000_ENVVAL_WRITE(hw, ch, 0x8000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) EMU8000_ATKHLD_WRITE(hw, ch, 0x7f7f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) EMU8000_DCYSUS_WRITE(hw, ch, 0x7f7f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) EMU8000_ENVVOL_WRITE(hw, ch, 0x8000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) EMU8000_ATKHLDV_WRITE(hw, ch, 0x7f7f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /* decay/sustain parameter for volume envelope is used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) for triggerg the voice */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) /* modulation envelope heights */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) EMU8000_PEFE_WRITE(hw, ch, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) /* lfo1/2 delay */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) EMU8000_LFO1VAL_WRITE(hw, ch, 0x8000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) EMU8000_LFO2VAL_WRITE(hw, ch, 0x8000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) /* lfo1 pitch & cutoff shift */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) EMU8000_FMMOD_WRITE(hw, ch, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) /* lfo1 volume & freq */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) EMU8000_TREMFRQ_WRITE(hw, ch, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) /* lfo2 pitch & freq */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) EMU8000_FM2FRQ2_WRITE(hw, ch, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) /* pan & loop start */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) temp = rec->panning[ch];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) temp = (temp <<24) | ((unsigned int)rec->loop_start[ch] - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) EMU8000_PSST_WRITE(hw, ch, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /* chorus & loop end (chorus 8bit, MSB) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) temp = 0; // chorus
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) temp = (temp << 24) | ((unsigned int)rec->loop_start[ch] + rec->buf_size - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) EMU8000_CSL_WRITE(hw, ch, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) /* Q & current address (Q 4bit value, MSB) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) temp = 0; // filterQ
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) temp = (temp << 28) | ((unsigned int)rec->loop_start[ch] - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) EMU8000_CCCA_WRITE(hw, ch, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) /* clear unknown registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) EMU8000_00A0_WRITE(hw, ch, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) EMU8000_0080_WRITE(hw, ch, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) * trigger the voice
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) static void start_voice(struct snd_emu8k_pcm *rec, int ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) struct snd_emu8000 *hw = rec->emu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) unsigned int temp, aux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) int pt = calc_pitch_target(rec->pitch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) /* cutoff and volume */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) EMU8000_IFATN_WRITE(hw, ch, 0xff00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) EMU8000_VTFT_WRITE(hw, ch, 0xffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) EMU8000_CVCF_WRITE(hw, ch, 0xffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) /* trigger envelope */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) EMU8000_DCYSUSV_WRITE(hw, ch, 0x7f7f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) /* set reverb and pitch target */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) temp = 0; // reverb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (rec->panning[ch] == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) aux = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) aux = (-rec->panning[ch]) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) temp = (temp << 8) | (pt << 16) | aux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) EMU8000_PTRX_WRITE(hw, ch, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) EMU8000_CPF_WRITE(hw, ch, pt << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) /* start timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) spin_lock_irqsave(&rec->timer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) if (! rec->timer_running) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) mod_timer(&rec->timer, jiffies + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) rec->timer_running = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) spin_unlock_irqrestore(&rec->timer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) * stop the voice immediately
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) static void stop_voice(struct snd_emu8k_pcm *rec, int ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) struct snd_emu8000 *hw = rec->emu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) EMU8000_DCYSUSV_WRITE(hw, ch, 0x807F);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) /* stop timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) spin_lock_irqsave(&rec->timer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if (rec->timer_running) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) del_timer(&rec->timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) rec->timer_running = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) spin_unlock_irqrestore(&rec->timer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) static int emu8k_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) struct snd_emu8k_pcm *rec = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) int ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) case SNDRV_PCM_TRIGGER_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) for (ch = 0; ch < rec->voices; ch++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) start_voice(rec, ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) rec->running = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) case SNDRV_PCM_TRIGGER_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) rec->running = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) for (ch = 0; ch < rec->voices; ch++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) stop_voice(rec, ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) * copy / silence ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) * this macro should be inserted in the copy/silence loops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) * to reduce the latency. without this, the system will hang up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) * during the whole loop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) #define CHECK_SCHEDULER() \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) cond_resched();\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) if (signal_pending(current))\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return -EAGAIN;\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) COPY_USER, COPY_KERNEL, FILL_SILENCE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) #define GET_VAL(sval, buf, mode) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) switch (mode) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) case FILL_SILENCE: \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) sval = 0; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) break; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) case COPY_KERNEL: \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) sval = *buf++; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) break; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) default: \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) if (get_user(sval, (unsigned short __user *)buf)) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) return -EFAULT; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) buf++; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) break; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) #ifdef USE_NONINTERLEAVE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) #define LOOP_WRITE(rec, offset, _buf, count, mode) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) struct snd_emu8000 *emu = (rec)->emu; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) unsigned short *buf = (__force unsigned short *)(_buf); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) snd_emu8000_write_wait(emu, 1); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) EMU8000_SMALW_WRITE(emu, offset); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) while (count > 0) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) unsigned short sval; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) CHECK_SCHEDULER(); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) GET_VAL(sval, buf, mode); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) EMU8000_SMLD_WRITE(emu, sval); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) count--; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) /* copy one channel block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) static int emu8k_pcm_copy(struct snd_pcm_substream *subs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) int voice, unsigned long pos,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) void __user *src, unsigned long count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) struct snd_emu8k_pcm *rec = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) /* convert to word unit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) pos = (pos << 1) + rec->loop_start[voice];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) count <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) LOOP_WRITE(rec, pos, src, count, COPY_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) static int emu8k_pcm_copy_kernel(struct snd_pcm_substream *subs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) int voice, unsigned long pos,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) void *src, unsigned long count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) struct snd_emu8k_pcm *rec = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) /* convert to word unit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) pos = (pos << 1) + rec->loop_start[voice];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) count <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) LOOP_WRITE(rec, pos, src, count, COPY_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) /* make a channel block silence */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) static int emu8k_pcm_silence(struct snd_pcm_substream *subs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) int voice, unsigned long pos, unsigned long count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) struct snd_emu8k_pcm *rec = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) /* convert to word unit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) pos = (pos << 1) + rec->loop_start[voice];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) count <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) LOOP_WRITE(rec, pos, NULL, count, FILL_SILENCE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) #else /* interleave */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) #define LOOP_WRITE(rec, pos, _buf, count, mode) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) struct snd_emu8000 *emu = rec->emu; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) unsigned short *buf = (__force unsigned short *)(_buf); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) snd_emu8000_write_wait(emu, 1); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) EMU8000_SMALW_WRITE(emu, pos + rec->loop_start[0]); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) if (rec->voices > 1) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) EMU8000_SMARW_WRITE(emu, pos + rec->loop_start[1]); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) while (count > 0) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) unsigned short sval; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) CHECK_SCHEDULER(); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) GET_VAL(sval, buf, mode); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) EMU8000_SMLD_WRITE(emu, sval); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (rec->voices > 1) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) CHECK_SCHEDULER(); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) GET_VAL(sval, buf, mode); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) EMU8000_SMRD_WRITE(emu, sval); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) count--; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) * copy the interleaved data can be done easily by using
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) * DMA "left" and "right" channels on emu8k engine.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) static int emu8k_pcm_copy(struct snd_pcm_substream *subs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) int voice, unsigned long pos,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) void __user *src, unsigned long count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) struct snd_emu8k_pcm *rec = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) /* convert to frames */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) pos = bytes_to_frames(subs->runtime, pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) count = bytes_to_frames(subs->runtime, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) LOOP_WRITE(rec, pos, src, count, COPY_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) static int emu8k_pcm_copy_kernel(struct snd_pcm_substream *subs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) int voice, unsigned long pos,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) void *src, unsigned long count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) struct snd_emu8k_pcm *rec = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) /* convert to frames */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) pos = bytes_to_frames(subs->runtime, pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) count = bytes_to_frames(subs->runtime, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) LOOP_WRITE(rec, pos, src, count, COPY_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) static int emu8k_pcm_silence(struct snd_pcm_substream *subs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) int voice, unsigned long pos, unsigned long count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) struct snd_emu8k_pcm *rec = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) /* convert to frames */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) pos = bytes_to_frames(subs->runtime, pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) count = bytes_to_frames(subs->runtime, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) LOOP_WRITE(rec, pos, NULL, count, FILL_SILENCE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) * allocate a memory block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) static int emu8k_pcm_hw_params(struct snd_pcm_substream *subs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) struct snd_pcm_hw_params *hw_params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) struct snd_emu8k_pcm *rec = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) if (rec->block) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) /* reallocation - release the old block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) snd_util_mem_free(rec->emu->memhdr, rec->block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) rec->block = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) rec->allocated_bytes = params_buffer_bytes(hw_params) + LOOP_BLANK_SIZE * 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) rec->block = snd_util_mem_alloc(rec->emu->memhdr, rec->allocated_bytes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) if (! rec->block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) rec->offset = EMU8000_DRAM_OFFSET + (rec->block->offset >> 1); /* in word */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) /* at least dma_bytes must be set for non-interleaved mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) subs->dma_buffer.bytes = params_buffer_bytes(hw_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) * free the memory block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) static int emu8k_pcm_hw_free(struct snd_pcm_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) struct snd_emu8k_pcm *rec = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (rec->block) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) int ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) for (ch = 0; ch < rec->voices; ch++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) stop_voice(rec, ch); // to be sure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if (rec->dram_opened)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) emu8k_close_dram(rec->emu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) snd_util_mem_free(rec->emu->memhdr, rec->block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) rec->block = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) static int emu8k_pcm_prepare(struct snd_pcm_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) struct snd_emu8k_pcm *rec = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) rec->pitch = 0xe000 + calc_rate_offset(subs->runtime->rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) rec->last_ptr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) rec->period_pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) rec->buf_size = subs->runtime->buffer_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) rec->period_size = subs->runtime->period_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) rec->voices = subs->runtime->channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) rec->loop_start[0] = rec->offset + LOOP_BLANK_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) if (rec->voices > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) rec->loop_start[1] = rec->loop_start[0] + rec->buf_size + LOOP_BLANK_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) if (rec->voices > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) rec->panning[0] = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) rec->panning[1] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) rec->panning[0] = 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) if (! rec->dram_opened) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) int err, i, ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) snd_emux_terminate_all(rec->emu->emu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if ((err = emu8k_open_dram_for_pcm(rec->emu, rec->voices)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) rec->dram_opened = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) /* clear loop blanks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) snd_emu8000_write_wait(rec->emu, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) EMU8000_SMALW_WRITE(rec->emu, rec->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) for (i = 0; i < LOOP_BLANK_SIZE; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) EMU8000_SMLD_WRITE(rec->emu, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) for (ch = 0; ch < rec->voices; ch++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) EMU8000_SMALW_WRITE(rec->emu, rec->loop_start[ch] + rec->buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) for (i = 0; i < LOOP_BLANK_SIZE; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) EMU8000_SMLD_WRITE(rec->emu, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) setup_voice(rec, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) if (rec->voices > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) setup_voice(rec, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) static snd_pcm_uframes_t emu8k_pcm_pointer(struct snd_pcm_substream *subs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) struct snd_emu8k_pcm *rec = subs->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) if (rec->running)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) return emu8k_get_curpos(rec, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) static const struct snd_pcm_ops emu8k_pcm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) .open = emu8k_pcm_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) .close = emu8k_pcm_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) .hw_params = emu8k_pcm_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) .hw_free = emu8k_pcm_hw_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) .prepare = emu8k_pcm_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) .trigger = emu8k_pcm_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) .pointer = emu8k_pcm_pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) .copy_user = emu8k_pcm_copy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) .copy_kernel = emu8k_pcm_copy_kernel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) .fill_silence = emu8k_pcm_silence,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) static void snd_emu8000_pcm_free(struct snd_pcm *pcm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) struct snd_emu8000 *emu = pcm->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) emu->pcm = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) int snd_emu8000_pcm_new(struct snd_card *card, struct snd_emu8000 *emu, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) struct snd_pcm *pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) if ((err = snd_pcm_new(card, "Emu8000 PCM", index, 1, 0, &pcm)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) pcm->private_data = emu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) pcm->private_free = snd_emu8000_pcm_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &emu8k_pcm_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) emu->pcm = pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) snd_device_register(card, pcm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) }