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

📄 emupcm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (epcm->voices[1]) {		snd_emu10k1_voice_free(epcm->emu, epcm->voices[1]);		epcm->voices[1] = NULL;	}	if (epcm->voices[0]) {		snd_emu10k1_voice_free(epcm->emu, epcm->voices[0]);		epcm->voices[0] = NULL;	}	if (epcm->memblk) {		snd_emu10k1_free_pages(emu, epcm->memblk);		epcm->memblk = NULL;		epcm->start_addr = 0;	}	snd_pcm_lib_free_pages(substream);	return 0;}static int snd_emu10k1_efx_playback_hw_free(snd_pcm_substream_t * substream){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	emu10k1_pcm_t *epcm;	int i;	if (runtime->private_data == NULL)		return 0;	epcm = runtime->private_data;	if (epcm->extra) {		snd_emu10k1_voice_free(epcm->emu, epcm->extra);		epcm->extra = NULL;	}	for (i=0; i < NUM_EFX_PLAYBACK; i++) {		if (epcm->voices[i]) {			snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]);			epcm->voices[i] = NULL;		}	}	if (epcm->memblk) {		snd_emu10k1_free_pages(emu, epcm->memblk);		epcm->memblk = NULL;		epcm->start_addr = 0;	}	snd_pcm_lib_free_pages(substream);	return 0;}static int snd_emu10k1_playback_prepare(snd_pcm_substream_t * substream){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	emu10k1_pcm_t *epcm = runtime->private_data;	unsigned int start_addr, end_addr;	start_addr = epcm->start_addr;	end_addr = snd_pcm_lib_period_bytes(substream);	if (runtime->channels == 2) {		start_addr >>= 1;		end_addr >>= 1;	}	end_addr += start_addr;	snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra,				   start_addr, end_addr, NULL);	start_addr = epcm->start_addr;	end_addr = epcm->start_addr + snd_pcm_lib_buffer_bytes(substream);	snd_emu10k1_pcm_init_voice(emu, 1, 0, epcm->voices[0],				   start_addr, end_addr,				   &emu->pcm_mixer[substream->number]);	if (epcm->voices[1])		snd_emu10k1_pcm_init_voice(emu, 0, 0, epcm->voices[1],					   start_addr, end_addr,					   &emu->pcm_mixer[substream->number]);	return 0;}static int snd_emu10k1_efx_playback_prepare(snd_pcm_substream_t * substream){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	emu10k1_pcm_t *epcm = runtime->private_data;	unsigned int start_addr, end_addr;	unsigned int channel_size;	int i;	start_addr = epcm->start_addr;	end_addr = epcm->start_addr + snd_pcm_lib_buffer_bytes(substream);	/*	 * the kX driver leaves some space between voices	 */	channel_size = ( end_addr - start_addr ) / NUM_EFX_PLAYBACK;	snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra,				   start_addr, start_addr + (channel_size / 2), NULL);	/* only difference with the master voice is we use it for the pointer */	snd_emu10k1_pcm_init_voice(emu, 1, 0, epcm->voices[0],				   start_addr, start_addr + channel_size,				   &emu->efx_pcm_mixer[0]);	start_addr += channel_size;	for (i = 1; i < NUM_EFX_PLAYBACK; i++) {		snd_emu10k1_pcm_init_voice(emu, 0, 0, epcm->voices[i],					   start_addr, start_addr + channel_size,					   &emu->efx_pcm_mixer[i]);		start_addr += channel_size;	}	return 0;}static snd_pcm_hardware_t snd_emu10k1_efx_playback ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_NONINTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),	.formats =		SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_48000,	.rate_min =		48000,	.rate_max =		48000,	.channels_min =		NUM_EFX_PLAYBACK,	.channels_max =		NUM_EFX_PLAYBACK,	.buffer_bytes_max =	(64*1024),	.period_bytes_min =	64,	.period_bytes_max =	(64*1024),	.periods_min =		2,	.periods_max =		2,	.fifo_size =		0,};static int snd_emu10k1_capture_hw_params(snd_pcm_substream_t * substream,					 snd_pcm_hw_params_t * hw_params){	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_emu10k1_capture_hw_free(snd_pcm_substream_t * substream){	return snd_pcm_lib_free_pages(substream);}static int snd_emu10k1_capture_prepare(snd_pcm_substream_t * substream){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	emu10k1_pcm_t *epcm = runtime->private_data;	int idx;	/* zeroing the buffer size will stop capture */	snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, 0);	switch (epcm->type) {	case CAPTURE_AC97ADC:		snd_emu10k1_ptr_write(emu, ADCCR, 0, 0);		break;	case CAPTURE_EFX:		if (emu->audigy) {			snd_emu10k1_ptr_write(emu, A_FXWC1, 0, 0);			snd_emu10k1_ptr_write(emu, A_FXWC2, 0, 0);		} else			snd_emu10k1_ptr_write(emu, FXWC, 0, 0);		break;	default:		break;	}		snd_emu10k1_ptr_write(emu, epcm->capture_ba_reg, 0, runtime->dma_addr);	epcm->capture_bufsize = snd_pcm_lib_buffer_bytes(substream);	epcm->capture_bs_val = 0;	for (idx = 0; idx < 31; idx++) {		if (capture_period_sizes[idx] == epcm->capture_bufsize) {			epcm->capture_bs_val = idx + 1;			break;		}	}	if (epcm->capture_bs_val == 0) {		snd_BUG();		epcm->capture_bs_val++;	}	if (epcm->type == CAPTURE_AC97ADC) {		epcm->capture_cr_val = emu->audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE;		if (runtime->channels > 1)			epcm->capture_cr_val |= emu->audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE;		epcm->capture_cr_val |= emu->audigy ?			snd_emu10k1_audigy_capture_rate_reg(runtime->rate) :			snd_emu10k1_capture_rate_reg(runtime->rate);	}	return 0;}static void snd_emu10k1_playback_invalidate_cache(emu10k1_t *emu, int extra, emu10k1_voice_t *evoice){	snd_pcm_runtime_t *runtime;	unsigned int voice, stereo, i, ccis, cra = 64, cs, sample;	if (evoice == NULL)		return;	runtime = evoice->epcm->substream->runtime;	voice = evoice->number;	stereo = (!extra && runtime->channels == 2);	sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080;	ccis = emu10k1_ccis(stereo, sample == 0);	// set cs to 2 * number of cache registers beside the invalidated	cs = (sample == 0) ? (32-ccis) : (64-ccis+1) >> 1;	if (cs > 16) cs = 16;	for (i = 0; i < cs; i++) {		snd_emu10k1_ptr_write(emu, CD0 + i, voice, sample);		if (stereo) {			snd_emu10k1_ptr_write(emu, CD0 + i, voice + 1, sample);		}	}	// reset cache	snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0);	snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra);	if (stereo) {		snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0);		snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra);	}	// fill cache	snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis);	if (stereo) {		snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis);	}}static void snd_emu10k1_playback_prepare_voice(emu10k1_t *emu, emu10k1_voice_t *evoice,					       int master, int extra,					       emu10k1_pcm_mixer_t *mix){	snd_pcm_substream_t *substream;	snd_pcm_runtime_t *runtime;	unsigned int attn, vattn;	unsigned int voice, tmp;	if (evoice == NULL)	/* skip second voice for mono */		return;	substream = evoice->epcm->substream;	runtime = substream->runtime;	voice = evoice->number;	attn = extra ? 0 : 0x00ff;	tmp = runtime->channels == 2 ? (master ? 1 : 2) : 0;	vattn = mix != NULL ? (mix->attn[tmp] << 16) : 0;	snd_emu10k1_ptr_write(emu, IFATN, voice, attn);	snd_emu10k1_ptr_write(emu, VTFT, voice, vattn | 0xffff);	snd_emu10k1_ptr_write(emu, CVCF, voice, vattn | 0xffff);	snd_emu10k1_ptr_write(emu, DCYSUSV, voice, 0x7f7f);	snd_emu10k1_voice_clear_loop_stop(emu, voice);}	static void snd_emu10k1_playback_trigger_voice(emu10k1_t *emu, emu10k1_voice_t *evoice, int master, int extra){	snd_pcm_substream_t *substream;	snd_pcm_runtime_t *runtime;	unsigned int voice, pitch, pitch_target;	if (evoice == NULL)	/* skip second voice for mono */		return;	substream = evoice->epcm->substream;	runtime = substream->runtime;	voice = evoice->number;	pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8;	pitch_target = emu10k1_calc_pitch_target(runtime->rate);	snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target);	if (master || evoice->epcm->type == PLAYBACK_EFX)		snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target);	snd_emu10k1_ptr_write(emu, IP, voice, pitch);	if (extra)		snd_emu10k1_voice_intr_enable(emu, voice);}static void snd_emu10k1_playback_stop_voice(emu10k1_t *emu, emu10k1_voice_t *evoice){	unsigned int voice;	if (evoice == NULL)		return;	voice = evoice->number;	snd_emu10k1_voice_intr_disable(emu, voice);	snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, 0);	snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, 0);	snd_emu10k1_ptr_write(emu, IFATN, voice, 0xffff);	snd_emu10k1_ptr_write(emu, VTFT, voice, 0xffff);	snd_emu10k1_ptr_write(emu, CVCF, voice, 0xffff);	snd_emu10k1_ptr_write(emu, IP, voice, 0);}static int snd_emu10k1_playback_trigger(snd_pcm_substream_t * substream,				        int cmd){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	emu10k1_pcm_t *epcm = runtime->private_data;	emu10k1_pcm_mixer_t *mix;	int result = 0;	// printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream));	spin_lock(&emu->reg_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		snd_emu10k1_playback_invalidate_cache(emu, 1, epcm->extra);	/* do we need this? */		snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[0]);		/* follow thru */	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:		mix = &emu->pcm_mixer[substream->number];		snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix);		snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix);		snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1, NULL);		snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 1, 0);		snd_emu10k1_playback_trigger_voice(emu, epcm->voices[1], 0, 0);		snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1);		epcm->running = 1;		break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:		epcm->running = 0;		snd_emu10k1_playback_stop_voice(emu, epcm->voices[0]);		snd_emu10k1_playback_stop_voice(emu, epcm->voices[1]);		snd_emu10k1_playback_stop_voice(emu, epcm->extra);		break;	default:		result = -EINVAL;		break;	}	spin_unlock(&emu->reg_lock);	return result;}static int snd_emu10k1_capture_trigger(snd_pcm_substream_t * substream,				       int cmd){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	emu10k1_pcm_t *epcm = runtime->private_data;	int result = 0;	spin_lock(&emu->reg_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		// hmm this should cause full and half full interrupt to be raised?  		outl(epcm->capture_ipr, emu->port + IPR);		snd_emu10k1_intr_enable(emu, epcm->capture_inte);		// printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs);		switch (epcm->type) {		case CAPTURE_AC97ADC:			snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val);			break;		case CAPTURE_EFX:			if (emu->audigy) {				snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val);				snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2);			} else				snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val);			break;		default:				break;		}		snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, epcm->capture_bs_val);		epcm->running = 1;		epcm->first_ptr = 1;		break;	case SNDRV_PCM_TRIGGER_STOP:		epcm->running = 0;		snd_emu10k1_intr_disable(emu, epcm->capture_inte);		outl(epcm->capture_ipr, emu->port + IPR);		snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, 0);		switch (epcm->type) {		case CAPTURE_AC97ADC:			snd_emu10k1_ptr_write(emu, ADCCR, 0, 0);			break;		case CAPTURE_EFX:			if (emu->audigy) {				snd_emu10k1_ptr_write(emu, A_FXWC1, 0, 0);				snd_emu10k1_ptr_write(emu, A_FXWC2, 0, 0);			} else				snd_emu10k1_ptr_write(emu, FXWC, 0, 0);			break;		default:			break;		}		break;	default:		result = -EINVAL;	}	spin_unlock(&emu->reg_lock);	return result;}static snd_pcm_uframes_t snd_emu10k1_playback_pointer(snd_pcm_substream_t * substream){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	emu10k1_pcm_t *epcm = runtime->private_data;	unsigned int ptr;	if (!epcm->running)		return 0;	ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->voices[0]->number) & 0x00ffffff;#if 0	/* Perex's code */	ptr += runtime->buffer_size;	ptr -= epcm->ccca_start_addr;	ptr %= runtime->buffer_size;#else	/* EMU10K1 Open Source code from Creative */	if (ptr < epcm->ccca_start_addr)		ptr += runtime->buffer_size - epcm->ccca_start_addr;	else {		ptr -= epcm->ccca_start_addr;		if (ptr >= runtime->buffer_size)			ptr -= runtime->buffer_size;	}#endif	// printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size);	return ptr;}static int snd_emu10k1_efx_playback_trigger(snd_pcm_substream_t * substream,				        int cmd){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	emu10k1_pcm_t *epcm = runtime->private_data;	int i;	int result = 0;	spin_lock(&emu->reg_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		// prepare voices		for (i = 0; i < NUM_EFX_PLAYBACK; i++) {				snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[i]);		}		snd_emu10k1_playback_invalidate_cache(emu, 1, epcm->extra);		/* follow thru */

⌨️ 快捷键说明

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