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

📄 emupcm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (rpcm)		*rpcm = NULL;	if ((err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm)) < 0)		return err;	pcm->private_data = emu;	pcm->private_free = snd_emu10k1_pcm_free;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_efx_playback_ops);	pcm->info_flags = 0;	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;	strcpy(pcm->name, "Multichannel Playback");	emu->pcm = pcm;	for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)		if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0)			return err;	if (rpcm)		*rpcm = pcm;	return 0;}static snd_pcm_ops_t snd_emu10k1_capture_mic_ops = {	.open =			snd_emu10k1_capture_mic_open,	.close =		snd_emu10k1_capture_mic_close,	.ioctl =		snd_pcm_lib_ioctl,	.hw_params =		snd_emu10k1_capture_hw_params,	.hw_free =		snd_emu10k1_capture_hw_free,	.prepare =		snd_emu10k1_capture_prepare,	.trigger =		snd_emu10k1_capture_trigger,	.pointer =		snd_emu10k1_capture_pointer,};static void snd_emu10k1_pcm_mic_free(snd_pcm_t *pcm){	emu10k1_t *emu = pcm->private_data;	emu->pcm_mic = NULL;	snd_pcm_lib_preallocate_free_for_all(pcm);}int __devinit snd_emu10k1_pcm_mic(emu10k1_t * emu, int device, snd_pcm_t ** rpcm){	snd_pcm_t *pcm;	int err;	if (rpcm)		*rpcm = NULL;	if ((err = snd_pcm_new(emu->card, "emu10k1 mic", device, 0, 1, &pcm)) < 0)		return err;	pcm->private_data = emu;	pcm->private_free = snd_emu10k1_pcm_mic_free;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_mic_ops);	pcm->info_flags = 0;	strcpy(pcm->name, "Mic Capture");	emu->pcm_mic = pcm;	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);	if (rpcm)		*rpcm = pcm;	return 0;}static int snd_emu10k1_pcm_efx_voices_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);	int nefx = emu->audigy ? 64 : 32;	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = nefx;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;}static int snd_emu10k1_pcm_efx_voices_mask_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);	int nefx = emu->audigy ? 64 : 32;	int idx;		spin_lock_irq(&emu->reg_lock);	for (idx = 0; idx < nefx; idx++)		ucontrol->value.integer.value[idx] = (emu->efx_voices_mask[idx / 32] & (1 << (idx % 32))) ? 1 : 0;	spin_unlock_irq(&emu->reg_lock);	return 0;}static int snd_emu10k1_pcm_efx_voices_mask_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);	unsigned int nval[2], bits;	int nefx = emu->audigy ? 64 : 32;	int nefxb = emu->audigy ? 7 : 6;	int change, idx;		nval[0] = nval[1] = 0;	for (idx = 0, bits = 0; idx < nefx; idx++)		if (ucontrol->value.integer.value[idx]) {			nval[idx / 32] |= 1 << (idx % 32);			bits++;		}			for (idx = 0; idx < nefxb; idx++)		if (1 << idx == bits)			break;		if (idx >= nefxb)		return -EINVAL;	spin_lock_irq(&emu->reg_lock);	change = (nval[0] != emu->efx_voices_mask[0]) ||		(nval[1] != emu->efx_voices_mask[1]);	emu->efx_voices_mask[0] = nval[0];	emu->efx_voices_mask[1] = nval[1];	spin_unlock_irq(&emu->reg_lock);	return change;}static snd_kcontrol_new_t snd_emu10k1_pcm_efx_voices_mask = {	.iface = SNDRV_CTL_ELEM_IFACE_PCM,	.name = "Captured FX8010 Outputs",	.info = snd_emu10k1_pcm_efx_voices_mask_info,	.get = snd_emu10k1_pcm_efx_voices_mask_get,	.put = snd_emu10k1_pcm_efx_voices_mask_put};static snd_pcm_ops_t snd_emu10k1_capture_efx_ops = {	.open =			snd_emu10k1_capture_efx_open,	.close =		snd_emu10k1_capture_efx_close,	.ioctl =		snd_pcm_lib_ioctl,	.hw_params =		snd_emu10k1_capture_hw_params,	.hw_free =		snd_emu10k1_capture_hw_free,	.prepare =		snd_emu10k1_capture_prepare,	.trigger =		snd_emu10k1_capture_trigger,	.pointer =		snd_emu10k1_capture_pointer,};/* EFX playback */#define INITIAL_TRAM_SHIFT     14#define INITIAL_TRAM_POS(size) ((((size) / 2) - INITIAL_TRAM_SHIFT) - 1)static void snd_emu10k1_fx8010_playback_irq(emu10k1_t *emu, void *private_data){	snd_pcm_substream_t *substream = private_data;	snd_pcm_period_elapsed(substream);}static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left,						   unsigned short *dst_right,						   unsigned short *src,						   unsigned int count,						   unsigned int tram_shift){	// printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count);	if ((tram_shift & 1) == 0) {		while (count--) {			*dst_left-- = *src++;			*dst_right-- = *src++;		}	} else {		while (count--) {			*dst_right-- = *src++;			*dst_left-- = *src++;		}	}}static void fx8010_pb_trans_copy(snd_pcm_substream_t *substream,				 snd_pcm_indirect_t *rec, size_t bytes){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number];	unsigned int tram_size = pcm->buffer_size;	unsigned short *src = (unsigned short *)(substream->runtime->dma_area + rec->sw_data);	unsigned int frames = bytes >> 2, count;	unsigned int tram_pos = pcm->tram_pos;	unsigned int tram_shift = pcm->tram_shift;	while (frames > tram_pos) {		count = tram_pos + 1;		snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + tram_pos,						       (unsigned short *)emu->fx8010.etram_pages.area + tram_pos + tram_size / 2,						       src, count, tram_shift);		src += count * 2;		frames -= count;		tram_pos = (tram_size / 2) - 1;		tram_shift++;	}	snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + tram_pos,					       (unsigned short *)emu->fx8010.etram_pages.area + tram_pos + tram_size / 2,					       src, frames, tram_shift);	tram_pos -= frames;	pcm->tram_pos = tram_pos;	pcm->tram_shift = tram_shift;}static int snd_emu10k1_fx8010_playback_transfer(snd_pcm_substream_t *substream){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number];	snd_pcm_indirect_playback_transfer(substream, &pcm->pcm_rec, fx8010_pb_trans_copy);	return 0;}static int snd_emu10k1_fx8010_playback_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_fx8010_playback_hw_free(snd_pcm_substream_t * substream){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number];	unsigned int i;	for (i = 0; i < pcm->channels; i++)		snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, 0);	snd_pcm_lib_free_pages(substream);	return 0;}static int snd_emu10k1_fx8010_playback_prepare(snd_pcm_substream_t * substream){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number];	unsigned int i;		// printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2);	memset(&pcm->pcm_rec, 0, sizeof(pcm->pcm_rec));	pcm->pcm_rec.hw_buffer_size = pcm->buffer_size * 2; /* byte size */	pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);	pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size);	pcm->tram_shift = 0;	snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_running, 0, 0);	/* reset */	snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0);	/* reset */	snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_size, 0, runtime->buffer_size);	snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_ptr, 0, 0);		/* reset ptr number */	snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_count, 0, runtime->period_size);	snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_tmpcount, 0, runtime->period_size);	for (i = 0; i < pcm->channels; i++)		snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, (TANKMEMADDRREG_READ|TANKMEMADDRREG_ALIGN) + i * (runtime->buffer_size / pcm->channels));	return 0;}static int snd_emu10k1_fx8010_playback_trigger(snd_pcm_substream_t * substream, int cmd){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number];	int result = 0;	spin_lock(&emu->reg_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		/* follow thru */	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:#ifdef EMU10K1_SET_AC3_IEC958	{		int i;		for (i = 0; i < 3; i++) {			unsigned int bits;			bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |			       SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS |			       0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT | SPCS_NOTAUDIODATA;			snd_emu10k1_ptr_write(emu, SPCS0 + i, 0, bits);		}	}#endif		result = snd_emu10k1_fx8010_register_irq_handler(emu, snd_emu10k1_fx8010_playback_irq, pcm->gpr_running, substream, &pcm->irq);		if (result < 0)			goto __err;		snd_emu10k1_fx8010_playback_transfer(substream);	/* roll the ball */		snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 1);		break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:		snd_emu10k1_fx8010_unregister_irq_handler(emu, pcm->irq); pcm->irq = NULL;		snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0);		pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size);		pcm->tram_shift = 0;		break;	default:		result = -EINVAL;		break;	}      __err:	spin_unlock(&emu->reg_lock);	return result;}static snd_pcm_uframes_t snd_emu10k1_fx8010_playback_pointer(snd_pcm_substream_t * substream){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number];	size_t ptr; /* byte pointer */	if (!snd_emu10k1_ptr_read(emu, emu->gpr_base + pcm->gpr_trigger, 0))		return 0;	ptr = snd_emu10k1_ptr_read(emu, emu->gpr_base + pcm->gpr_ptr, 0) << 2;	return snd_pcm_indirect_playback_pointer(substream, &pcm->pcm_rec, ptr);}static snd_pcm_hardware_t snd_emu10k1_fx8010_playback ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE),	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_48000,	.rate_min =		48000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		1,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	1024,	.period_bytes_max =	(128*1024),	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};static int snd_emu10k1_fx8010_playback_open(snd_pcm_substream_t * substream){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number];	runtime->hw = snd_emu10k1_fx8010_playback;	runtime->hw.channels_min = runtime->hw.channels_max = pcm->channels;	runtime->hw.period_bytes_max = (pcm->buffer_size * 2) / 2;	spin_lock_irq(&emu->reg_lock);	if (pcm->valid == 0) {		spin_unlock_irq(&emu->reg_lock);		return -ENODEV;	}	pcm->opened = 1;	spin_unlock_irq(&emu->reg_lock);	return 0;}static int snd_emu10k1_fx8010_playback_close(snd_pcm_substream_t * substream){	emu10k1_t *emu = snd_pcm_substream_chip(substream);	snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number];	spin_lock_irq(&emu->reg_lock);	pcm->opened = 0;	spin_unlock_irq(&emu->reg_lock);	return 0;}static snd_pcm_ops_t snd_emu10k1_fx8010_playback_ops = {	.open =			snd_emu10k1_fx8010_playback_open,	.close =		snd_emu10k1_fx8010_playback_close,	.ioctl =		snd_pcm_lib_ioctl,	.hw_params =		snd_emu10k1_fx8010_playback_hw_params,	.hw_free =		snd_emu10k1_fx8010_playback_hw_free,	.prepare =		snd_emu10k1_fx8010_playback_prepare,	.trigger =		snd_emu10k1_fx8010_playback_trigger,	.pointer =		snd_emu10k1_fx8010_playback_pointer,	.ack =			snd_emu10k1_fx8010_playback_transfer,};static void snd_emu10k1_pcm_efx_free(snd_pcm_t *pcm){	emu10k1_t *emu = pcm->private_data;	emu->pcm_efx = NULL;	snd_pcm_lib_preallocate_free_for_all(pcm);}int __devinit snd_emu10k1_pcm_efx(emu10k1_t * emu, int device, snd_pcm_t ** rpcm){	snd_pcm_t *pcm;	snd_kcontrol_t *kctl;	int err;	if (rpcm)		*rpcm = NULL;	if ((err = snd_pcm_new(emu->card, "emu10k1 efx", device, 8, 1, &pcm)) < 0)		return err;	pcm->private_data = emu;	pcm->private_free = snd_emu10k1_pcm_efx_free;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_fx8010_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_efx_ops);	pcm->info_flags = 0;	strcpy(pcm->name, "Multichannel Capture/PT Playback");	emu->pcm_efx = pcm;	if (rpcm)		*rpcm = pcm;	/* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs 	 * to these	 */			/* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */	if (emu->audigy) {		emu->efx_voices_mask[0] = 0;		emu->efx_voices_mask[1] = 0xffff;	} else {		emu->efx_voices_mask[0] = 0xffff0000;		emu->efx_voices_mask[1] = 0;	}	kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu);	if (!kctl)		return -ENOMEM;	kctl->id.device = device;	snd_ctl_add(emu->card, kctl);	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);	return 0;}

⌨️ 快捷键说明

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