Linux Audio

Check our new training course

Loading...
v5.9
  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		if ((err = emu8k_open_dram_for_pcm(rec->emu, rec->voices)) != 0)
 
630			return err;
631		rec->dram_opened = 1;
632
633		/* clear loop blanks */
634		snd_emu8000_write_wait(rec->emu, 0);
635		EMU8000_SMALW_WRITE(rec->emu, rec->offset);
636		for (i = 0; i < LOOP_BLANK_SIZE; i++)
637			EMU8000_SMLD_WRITE(rec->emu, 0);
638		for (ch = 0; ch < rec->voices; ch++) {
639			EMU8000_SMALW_WRITE(rec->emu, rec->loop_start[ch] + rec->buf_size);
640			for (i = 0; i < LOOP_BLANK_SIZE; i++)
641				EMU8000_SMLD_WRITE(rec->emu, 0);
642		}
643	}
644
645	setup_voice(rec, 0);
646	if (rec->voices > 1)
647		setup_voice(rec, 1);
648	return 0;
649}
650
651static snd_pcm_uframes_t emu8k_pcm_pointer(struct snd_pcm_substream *subs)
652{
653	struct snd_emu8k_pcm *rec = subs->runtime->private_data;
654	if (rec->running)
655		return emu8k_get_curpos(rec, 0);
656	return 0;
657}
658
659
660static const struct snd_pcm_ops emu8k_pcm_ops = {
661	.open =		emu8k_pcm_open,
662	.close =	emu8k_pcm_close,
663	.hw_params =	emu8k_pcm_hw_params,
664	.hw_free =	emu8k_pcm_hw_free,
665	.prepare =	emu8k_pcm_prepare,
666	.trigger =	emu8k_pcm_trigger,
667	.pointer =	emu8k_pcm_pointer,
668	.copy_user =	emu8k_pcm_copy,
669	.copy_kernel =	emu8k_pcm_copy_kernel,
670	.fill_silence =	emu8k_pcm_silence,
671};
672
673
674static void snd_emu8000_pcm_free(struct snd_pcm *pcm)
675{
676	struct snd_emu8000 *emu = pcm->private_data;
677	emu->pcm = NULL;
678}
679
680int snd_emu8000_pcm_new(struct snd_card *card, struct snd_emu8000 *emu, int index)
681{
682	struct snd_pcm *pcm;
683	int err;
684
685	if ((err = snd_pcm_new(card, "Emu8000 PCM", index, 1, 0, &pcm)) < 0)
 
686		return err;
687	pcm->private_data = emu;
688	pcm->private_free = snd_emu8000_pcm_free;
689	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &emu8k_pcm_ops);
690	emu->pcm = pcm;
691
692	snd_device_register(card, pcm);
693
694	return 0;
695}
v5.14.15
  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}