cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

emu8000_pcm.c (17178B)


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