⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 emu8000_pcm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
		aux = 0xff;	else		aux = (-rec->panning[ch]) & 0xff;	temp = (temp << 8) | (pt << 16) | aux;	EMU8000_PTRX_WRITE(hw, ch, temp);	EMU8000_CPF_WRITE(hw, ch, pt << 16);	/* start timer */	spin_lock_irqsave(&rec->timer_lock, flags);	if (! rec->timer_running) {		rec->timer.expires = jiffies + 1;		add_timer(&rec->timer);		rec->timer_running = 1;	}	spin_unlock_irqrestore(&rec->timer_lock, flags);}/* * stop the voice immediately */static void stop_voice(emu8k_pcm_t *rec, int ch){	unsigned long flags;	emu8000_t *hw = rec->emu;	EMU8000_DCYSUSV_WRITE(hw, ch, 0x807F);	/* stop timer */	spin_lock_irqsave(&rec->timer_lock, flags);	if (rec->timer_running) {		del_timer(&rec->timer);		rec->timer_running = 0;	}	spin_unlock_irqrestore(&rec->timer_lock, flags);}static int emu8k_pcm_trigger(snd_pcm_substream_t *subs, int cmd){	emu8k_pcm_t *rec = subs->runtime->private_data;	int ch;	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		for (ch = 0; ch < rec->voices; ch++)			start_voice(rec, ch);		rec->running = 1;		break;	case SNDRV_PCM_TRIGGER_STOP:		rec->running = 0;		for (ch = 0; ch < rec->voices; ch++)			stop_voice(rec, ch);		break;	default:		return -EINVAL;	}	return 0;}/* * copy / silence ops *//* * this macro should be inserted in the copy/silence loops * to reduce the latency.  without this, the system will hang up * during the whole loop. */#define CHECK_SCHEDULER() \do { \	cond_resched();\	if (signal_pending(current))\		return -EAGAIN;\} while (0)#ifdef USE_NONINTERLEAVE/* copy one channel block */static int emu8k_transfer_block(emu8000_t *emu, int offset, unsigned short *buf, int count){	EMU8000_SMALW_WRITE(emu, offset);	while (count > 0) {		unsigned short sval;		CHECK_SCHEDULER();		get_user(sval, buf);		EMU8000_SMLD_WRITE(emu, sval);		buf++;		count--;	}	return 0;}static int emu8k_pcm_copy(snd_pcm_substream_t *subs,			  int voice,			  snd_pcm_uframes_t pos,			  void *src,			  snd_pcm_uframes_t count){	emu8k_pcm_t *rec = subs->runtime->private_data;	emu8000_t *emu = rec->emu;	snd_emu8000_write_wait(emu, 1);	if (voice == -1) {		unsigned short *buf = src;		int i, err;		count /= rec->voices;		for (i = 0; i < rec->voices; i++) {			err = emu8k_transfer_block(emu, pos + rec->loop_start[i], buf, count);			if (err < 0)				return err;			buf += count;		}		return 0;	} else {		return emu8k_transfer_block(emu, pos + rec->loop_start[voice], src, count);	}}/* make a channel block silence */static int emu8k_silence_block(emu8000_t *emu, int offset, int count){	EMU8000_SMALW_WRITE(emu, offset);	while (count > 0) {		CHECK_SCHEDULER();		EMU8000_SMLD_WRITE(emu, 0);		count--;	}	return 0;}static int emu8k_pcm_silence(snd_pcm_substream_t *subs,			     int voice,			     snd_pcm_uframes_t pos,			     snd_pcm_uframes_t count){	emu8k_pcm_t *rec = subs->runtime->private_data;	emu8000_t *emu = rec->emu;	snd_emu8000_write_wait(emu, 1);	if (voice == -1 && rec->voices == 1)		voice = 0;	if (voice == -1) {		int err;		err = emu8k_silence_block(emu, pos + rec->loop_start[0], count / 2);		if (err < 0)			return err;		return emu8k_silence_block(emu, pos + rec->loop_start[1], count / 2);	} else {		return emu8k_silence_block(emu, pos + rec->loop_start[voice], count);	}}#else /* interleave *//* * copy the interleaved data can be done easily by using * DMA "left" and "right" channels on emu8k engine. */static int emu8k_pcm_copy(snd_pcm_substream_t *subs,			  int voice,			  snd_pcm_uframes_t pos,			  void __user *src,			  snd_pcm_uframes_t count){	emu8k_pcm_t *rec = subs->runtime->private_data;	emu8000_t *emu = rec->emu;	unsigned short __user *buf = src;	snd_emu8000_write_wait(emu, 1);	EMU8000_SMALW_WRITE(emu, pos + rec->loop_start[0]);	if (rec->voices > 1)		EMU8000_SMARW_WRITE(emu, pos + rec->loop_start[1]);	while (count-- > 0) {		unsigned short sval;		CHECK_SCHEDULER();		get_user(sval, buf);		EMU8000_SMLD_WRITE(emu, sval);		buf++;		if (rec->voices > 1) {			CHECK_SCHEDULER();			get_user(sval, buf);			EMU8000_SMRD_WRITE(emu, sval);			buf++;		}	}	return 0;}static int emu8k_pcm_silence(snd_pcm_substream_t *subs,			     int voice,			     snd_pcm_uframes_t pos,			     snd_pcm_uframes_t count){	emu8k_pcm_t *rec = subs->runtime->private_data;	emu8000_t *emu = rec->emu;	snd_emu8000_write_wait(emu, 1);	EMU8000_SMALW_WRITE(emu, rec->loop_start[0] + pos);	if (rec->voices > 1)		EMU8000_SMARW_WRITE(emu, rec->loop_start[1] + pos);	while (count-- > 0) {		CHECK_SCHEDULER();		EMU8000_SMLD_WRITE(emu, 0);		if (rec->voices > 1) {			CHECK_SCHEDULER();			EMU8000_SMRD_WRITE(emu, 0);		}	}	return 0;}#endif/* * allocate a memory block */static int emu8k_pcm_hw_params(snd_pcm_substream_t *subs,			       snd_pcm_hw_params_t *hw_params){	emu8k_pcm_t *rec = subs->runtime->private_data;	if (rec->block) {		/* reallocation - release the old block */		snd_util_mem_free(rec->emu->memhdr, rec->block);		rec->block = NULL;	}	rec->allocated_bytes = params_buffer_bytes(hw_params) + LOOP_BLANK_SIZE * 4;	rec->block = snd_util_mem_alloc(rec->emu->memhdr, rec->allocated_bytes);	if (! rec->block)		return -ENOMEM;	rec->offset = EMU8000_DRAM_OFFSET + (rec->block->offset >> 1); /* in word */	/* at least dma_bytes must be set for non-interleaved mode */	subs->dma_buffer.bytes = params_buffer_bytes(hw_params);	return 0;}/* * free the memory block */static int emu8k_pcm_hw_free(snd_pcm_substream_t *subs){	emu8k_pcm_t *rec = subs->runtime->private_data;	if (rec->block) {		int ch;		for (ch = 0; ch < rec->voices; ch++)			stop_voice(rec, ch); // to be sure		if (rec->dram_opened)			emu8k_close_dram(rec->emu);		snd_util_mem_free(rec->emu->memhdr, rec->block);		rec->block = NULL;	}	return 0;}/* */static int emu8k_pcm_prepare(snd_pcm_substream_t *subs){	emu8k_pcm_t *rec = subs->runtime->private_data;	rec->pitch = 0xe000 + calc_rate_offset(subs->runtime->rate);	rec->last_ptr = 0;	rec->period_pos = 0;	rec->buf_size = subs->runtime->buffer_size;	rec->period_size = subs->runtime->period_size;	rec->voices = subs->runtime->channels;	rec->loop_start[0] = rec->offset + LOOP_BLANK_SIZE;	if (rec->voices > 1)		rec->loop_start[1] = rec->loop_start[0] + rec->buf_size + LOOP_BLANK_SIZE;	if (rec->voices > 1) {		rec->panning[0] = 0xff;		rec->panning[1] = 0x00;	} else		rec->panning[0] = 0x80;	if (! rec->dram_opened) {		int err, i, ch;		snd_emux_terminate_all(rec->emu->emu);		if ((err = emu8k_open_dram_for_pcm(rec->emu, rec->voices)) != 0)			return err;		rec->dram_opened = 1;		/* clear loop blanks */		snd_emu8000_write_wait(rec->emu, 0);		EMU8000_SMALW_WRITE(rec->emu, rec->offset);		for (i = 0; i < LOOP_BLANK_SIZE; i++)			EMU8000_SMLD_WRITE(rec->emu, 0);		for (ch = 0; ch < rec->voices; ch++) {			EMU8000_SMALW_WRITE(rec->emu, rec->loop_start[ch] + rec->buf_size);			for (i = 0; i < LOOP_BLANK_SIZE; i++)				EMU8000_SMLD_WRITE(rec->emu, 0);		}	}	setup_voice(rec, 0);	if (rec->voices > 1)		setup_voice(rec, 1);	return 0;}static snd_pcm_uframes_t emu8k_pcm_pointer(snd_pcm_substream_t *subs){	emu8k_pcm_t *rec = subs->runtime->private_data;	if (rec->running)		return emu8k_get_curpos(rec, 0);	return 0;}static snd_pcm_ops_t emu8k_pcm_ops = {	.open =		emu8k_pcm_open,	.close =	emu8k_pcm_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	emu8k_pcm_hw_params,	.hw_free =	emu8k_pcm_hw_free,	.prepare =	emu8k_pcm_prepare,	.trigger =	emu8k_pcm_trigger,	.pointer =	emu8k_pcm_pointer,	.copy =		emu8k_pcm_copy,	.silence =	emu8k_pcm_silence,};static void snd_emu8000_pcm_free(snd_pcm_t *pcm){	emu8000_t *emu = pcm->private_data;	emu->pcm = NULL;}int snd_emu8000_pcm_new(snd_card_t *card, emu8000_t *emu, int index){	snd_pcm_t *pcm;	int err;	if ((err = snd_pcm_new(card, "Emu8000 PCM", index, 1, 0, &pcm)) < 0)		return err;	pcm->private_data = emu;	pcm->private_free = snd_emu8000_pcm_free;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &emu8k_pcm_ops);	emu->pcm = pcm;	snd_device_register(card, pcm);	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -