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

📄 emupcm.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 3 页
字号:
		return 0;	epcm = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO);	if (epcm->extra) {		snd_emu10k1_voice_free(epcm->emu, epcm->extra);		epcm->extra = NULL;	}	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_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 = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO);	unsigned int start_addr, end_addr;	start_addr = epcm->start_addr;	end_addr = snd_pcm_lib_period_bytes(substream);	if (runtime->channels == 2)		end_addr >>= 1;	end_addr += start_addr;	snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra,				   start_addr, end_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);	if (epcm->voices[1])		snd_emu10k1_pcm_init_voice(emu, 0, 0, epcm->voices[1],					   start_addr, end_addr);	return 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 = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO);	int idx;	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:		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, emu10k1_voice_t *evoice){	snd_pcm_runtime_t *runtime;	unsigned int voice, i, ccis, cra = 64, cs, sample;	if (evoice == NULL)		return;	runtime = evoice->epcm->substream->runtime;	voice = evoice->number;	sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080;	if (runtime->channels > 1) {		ccis = 28;		cs = 4;	} else {		ccis = 30;		cs = 2;	}	if (sample == 0)	/* 16-bit */		ccis *= 2;	for (i = 0; i < cs; i++)		snd_emu10k1_ptr_write(emu, CD0 + i, voice, sample);	// reset cache	snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0);	snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra);	if (runtime->channels > 1) {		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);}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;	emu10k1_pcm_mixer_t *mix;	unsigned int voice, pitch, pitch_target, tmp;	unsigned int attn;	if (evoice == NULL)	/* skip second voice for mono */		return;	substream = evoice->epcm->substream;	runtime = substream->runtime;	mix = &emu->pcm_mixer[substream->number];	voice = evoice->number;	pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8;	pitch_target = emu10k1_calc_pitch_target(runtime->rate);	attn = extra ? 0 : 0x00ff;	tmp = runtime->channels == 2 ? (master ? 1 : 2) : 0;	snd_emu10k1_ptr_write(emu, IFATN, voice, attn);	snd_emu10k1_ptr_write(emu, VTFT, voice, (mix->attn[tmp] << 16) | 0xffff);	snd_emu10k1_ptr_write(emu, CVCF, voice, (mix->attn[tmp] << 16) | 0xffff);	snd_emu10k1_voice_clear_loop_stop(emu, voice);			if (extra)		snd_emu10k1_voice_intr_enable(emu, voice);	snd_emu10k1_ptr_write(emu, DCYSUSV, voice, 0x7f7f);	snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target);	if (master)		snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target);	snd_emu10k1_ptr_write(emu, IP, voice, pitch);}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 = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO);	unsigned long flags;	int result = 0;	// printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream));	spin_lock_irqsave(&emu->reg_lock, flags);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		snd_emu10k1_playback_invalidate_cache(emu, epcm->extra);	/* do we need this? */		snd_emu10k1_playback_invalidate_cache(emu, epcm->voices[0]);		/* follow thru */	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:		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_irqrestore(&emu->reg_lock, flags);	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 = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO);	unsigned long flags;	int result = 0;	// printk("trigger - emu10k1 = %p, cmd = %i, pointer = %i\n", emu, cmd, substream->ops->pointer(substream));	spin_lock_irqsave(&emu->reg_lock, flags);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		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:			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;		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:			snd_emu10k1_ptr_write(emu, FXWC, 0, 0);			break;		default:			break;		}		break;	default:		result = -EINVAL;	}	spin_unlock_irqrestore(&emu->reg_lock, flags);	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 = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO);	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;#endif	// printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size);	return ptr;}static snd_pcm_uframes_t snd_emu10k1_capture_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 = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO);	unsigned int ptr;	if (!epcm->running)		return 0;	ptr = snd_emu10k1_ptr_read(emu, epcm->capture_idx_reg, 0) & 0x0000ffff;	return bytes_to_frames(runtime, ptr);}/* *  Playback support device description */static snd_pcm_hardware_t snd_emu10k1_playback ={	info:			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),	formats:		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,	rates:			SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	rate_min:		4000,	rate_max:		48000,	channels_min:		1,	channels_max:		2,	buffer_bytes_max:	(128*1024),	period_bytes_min:	64,	period_bytes_max:	(128*1024),	periods_min:		1,	periods_max:		1024,	fifo_size:		0,};/* *  Capture support device description */static snd_pcm_hardware_t snd_emu10k1_capture ={	info:			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_MMAP_VALID),	formats:		SNDRV_PCM_FMTBIT_S16_LE,	rates:			SNDRV_PCM_RATE_8000_48000,	rate_min:		8000,	rate_max:		48000,	channels_min:		1,	channels_max:		2,	buffer_bytes_max:	(64*1024),	period_bytes_min:	384,	period_bytes_max:	(64*1024),	periods_min:		2,	periods_max:		2,	fifo_size:		0,};/* * */static void snd_emu10k1_pcm_mixer_notify1(snd_card_t *card, snd_kcontrol_t *kctl, int activate){	snd_runtime_check(kctl != NULL, return);	if (activate)		kctl->access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;	else		kctl->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;	snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE |		       SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);}static void snd_emu10k1_pcm_mixer_notify(snd_card_t *card, emu10k1_pcm_mixer_t *mix, int activate){	snd_emu10k1_pcm_mixer_notify1(card, mix->ctl_send_routing, activate);	snd_emu10k1_pcm_mixer_notify1(card, mix->ctl_send_volume, activate);	snd_emu10k1_pcm_mixer_notify1(card, mix->ctl_attn, activate);}static void snd_emu10k1_pcm_free_substream(snd_pcm_runtime_t *runtime){	emu10k1_pcm_t *epcm = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return);	if (epcm)		snd_magic_kfree(epcm);}static int snd_emu10k1_playback_open(snd_pcm_substream_t * substream){

⌨️ 快捷键说明

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