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

📄 gus_pcm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
{	snd_pcm_runtime_t *runtime = substream->runtime;	gus_pcm_private_t *pcmp = runtime->private_data;	snd_pcm_lib_free_pages(substream);	if (pcmp->pvoices[0]) {		snd_gf1_free_voice(pcmp->gus, pcmp->pvoices[0]);		pcmp->pvoices[0] = NULL;	}	if (pcmp->pvoices[1]) {		snd_gf1_free_voice(pcmp->gus, pcmp->pvoices[1]);		pcmp->pvoices[1] = NULL;	}	if (pcmp->memory > 0) {		snd_gf1_mem_free(&pcmp->gus->gf1.mem_alloc, pcmp->memory);		pcmp->memory = 0;	}	return 0;}static int snd_gf1_pcm_playback_prepare(snd_pcm_substream_t * substream){	snd_pcm_runtime_t *runtime = substream->runtime;	gus_pcm_private_t *pcmp = runtime->private_data;	pcmp->bpos = 0;	pcmp->dma_size = snd_pcm_lib_buffer_bytes(substream);	pcmp->block_size = snd_pcm_lib_period_bytes(substream);	pcmp->blocks = pcmp->dma_size / pcmp->block_size;	return 0;}static int snd_gf1_pcm_playback_trigger(snd_pcm_substream_t * substream,					int cmd){	snd_gus_card_t *gus = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	gus_pcm_private_t *pcmp = runtime->private_data;	int voice;	if (cmd == SNDRV_PCM_TRIGGER_START) {		snd_gf1_pcm_trigger_up(substream);	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {		spin_lock(&pcmp->lock);		pcmp->flags &= ~SNDRV_GF1_PCM_PFLG_ACTIVE;		spin_unlock(&pcmp->lock);		voice = pcmp->pvoices[0]->number;		snd_gf1_stop_voices(gus, voice, voice);		if (pcmp->pvoices[1]) {			voice = pcmp->pvoices[1]->number;			snd_gf1_stop_voices(gus, voice, voice);		}	} else {		return -EINVAL;	}	return 0;}static snd_pcm_uframes_t snd_gf1_pcm_playback_pointer(snd_pcm_substream_t * substream){	snd_gus_card_t *gus = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	gus_pcm_private_t *pcmp = runtime->private_data;	unsigned int pos;	unsigned char voice_ctrl;	pos = 0;	spin_lock(&gus->reg_lock);	if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE) {		snd_gf1_select_voice(gus, pcmp->pvoices[0]->number);		voice_ctrl = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);		pos = (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4) - pcmp->memory;		if (substream->runtime->channels > 1)			pos <<= 1;		pos = bytes_to_frames(runtime, pos);	}	spin_unlock(&gus->reg_lock);	return pos;}static ratnum_t clock = {	.num = 9878400/16,	.den_min = 2,	.den_max = 257,	.den_step = 1,};static snd_pcm_hw_constraint_ratnums_t hw_constraints_clocks  = {	.nrats = 1,	.rats = &clock,};static int snd_gf1_pcm_capture_hw_params(snd_pcm_substream_t * substream,					 snd_pcm_hw_params_t * hw_params){	snd_gus_card_t *gus = snd_pcm_substream_chip(substream);	gus->c_dma_size = params_buffer_bytes(hw_params);	gus->c_period_size = params_period_bytes(hw_params);	gus->c_pos = 0;	gus->gf1.pcm_rcntrl_reg = 0x21;		/* IRQ at end, enable & start */	if (params_channels(hw_params) > 1)		gus->gf1.pcm_rcntrl_reg |= 2;	if (gus->gf1.dma2 > 3)		gus->gf1.pcm_rcntrl_reg |= 4;	if (snd_pcm_format_unsigned(params_format(hw_params)))		gus->gf1.pcm_rcntrl_reg |= 0x80;	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_gf1_pcm_capture_hw_free(snd_pcm_substream_t * substream){	return snd_pcm_lib_free_pages(substream);}static int snd_gf1_pcm_capture_prepare(snd_pcm_substream_t * substream){	snd_gus_card_t *gus = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	snd_gf1_i_write8(gus, SNDRV_GF1_GB_RECORD_RATE, runtime->rate_den - 2);	snd_gf1_i_write8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL, 0);	/* disable sampling */	snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL);	/* Sampling Control Register */	snd_dma_program(gus->gf1.dma2, runtime->dma_addr, gus->c_period_size, DMA_MODE_READ);	return 0;}static int snd_gf1_pcm_capture_trigger(snd_pcm_substream_t * substream,				       int cmd){	snd_gus_card_t *gus = snd_pcm_substream_chip(substream);	int val;		if (cmd == SNDRV_PCM_TRIGGER_START) {		val = gus->gf1.pcm_rcntrl_reg;	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {		val = 0;	} else {		return -EINVAL;	}	spin_lock(&gus->reg_lock);	snd_gf1_write8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL, val);	snd_gf1_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL);	spin_unlock(&gus->reg_lock);	return 0;}static snd_pcm_uframes_t snd_gf1_pcm_capture_pointer(snd_pcm_substream_t * substream){	snd_gus_card_t *gus = snd_pcm_substream_chip(substream);	int pos = snd_dma_pointer(gus->gf1.dma2, gus->c_period_size);	pos = bytes_to_frames(substream->runtime, (gus->c_pos + pos) % gus->c_dma_size);	return pos;}static void snd_gf1_pcm_interrupt_dma_read(snd_gus_card_t * gus){	snd_gf1_i_write8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL, 0);	/* disable sampling */	snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL);	/* Sampling Control Register */	if (gus->pcm_cap_substream != NULL) {		snd_gf1_pcm_capture_prepare(gus->pcm_cap_substream); 		snd_gf1_pcm_capture_trigger(gus->pcm_cap_substream, SNDRV_PCM_TRIGGER_START);		gus->c_pos += gus->c_period_size;		snd_pcm_period_elapsed(gus->pcm_cap_substream);	}}static snd_pcm_hardware_t snd_gf1_pcm_playback ={	.info =			SNDRV_PCM_INFO_NONINTERLEAVED,	.formats		= (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |				 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		5510,	.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,};static snd_pcm_hardware_t snd_gf1_pcm_capture ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_MMAP_VALID),	.formats =		SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8,	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_44100,	.rate_min =		5510,	.rate_max =		44100,	.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,};static void snd_gf1_pcm_playback_free(snd_pcm_runtime_t *runtime){	kfree(runtime->private_data);}static int snd_gf1_pcm_playback_open(snd_pcm_substream_t *substream){	gus_pcm_private_t *pcmp;	snd_gus_card_t *gus = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	int err;	pcmp = kzalloc(sizeof(*pcmp), GFP_KERNEL);	if (pcmp == NULL)		return -ENOMEM;	pcmp->gus = gus;	spin_lock_init(&pcmp->lock);	init_waitqueue_head(&pcmp->sleep);	atomic_set(&pcmp->dma_count, 0);	runtime->private_data = pcmp;	runtime->private_free = snd_gf1_pcm_playback_free;#if 0	printk("playback.buffer = 0x%lx, gf1.pcm_buffer = 0x%lx\n", (long) pcm->playback.buffer, (long) gus->gf1.pcm_buffer);#endif	if ((err = snd_gf1_dma_init(gus)) < 0)		return err;	pcmp->flags = SNDRV_GF1_PCM_PFLG_NONE;	pcmp->substream = substream;	runtime->hw = snd_gf1_pcm_playback;	snd_pcm_limit_isa_dma_size(gus->gf1.dma1, &runtime->hw.buffer_bytes_max);	snd_pcm_limit_isa_dma_size(gus->gf1.dma1, &runtime->hw.period_bytes_max);	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);	return 0;}static int snd_gf1_pcm_playback_close(snd_pcm_substream_t * substream){	snd_gus_card_t *gus = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	gus_pcm_private_t *pcmp = runtime->private_data;		if (!wait_event_timeout(pcmp->sleep, (atomic_read(&pcmp->dma_count) <= 0), 2*HZ))		snd_printk(KERN_ERR "gf1 pcm - serious DMA problem\n");	snd_gf1_dma_done(gus);		return 0;}static int snd_gf1_pcm_capture_open(snd_pcm_substream_t * substream){	snd_pcm_runtime_t *runtime = substream->runtime;	snd_gus_card_t *gus = snd_pcm_substream_chip(substream);	gus->gf1.interrupt_handler_dma_read = snd_gf1_pcm_interrupt_dma_read;	gus->pcm_cap_substream = substream;	substream->runtime->hw = snd_gf1_pcm_capture;	snd_pcm_limit_isa_dma_size(gus->gf1.dma2, &runtime->hw.buffer_bytes_max);	snd_pcm_limit_isa_dma_size(gus->gf1.dma2, &runtime->hw.period_bytes_max);	snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,				      &hw_constraints_clocks);	return 0;}static int snd_gf1_pcm_capture_close(snd_pcm_substream_t * substream){	snd_gus_card_t *gus = snd_pcm_substream_chip(substream);	gus->pcm_cap_substream = NULL;	snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_DMA_READ);	return 0;}static void snd_gf1_pcm_free(snd_pcm_t *pcm){	snd_gus_card_t *gus = pcm->private_data;	gus->pcm = NULL;	snd_pcm_lib_preallocate_free_for_all(pcm);}static int snd_gf1_pcm_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 2;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 127;	return 0;}static int snd_gf1_pcm_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	snd_gus_card_t *gus = snd_kcontrol_chip(kcontrol);	unsigned long flags;		spin_lock_irqsave(&gus->pcm_volume_level_lock, flags);	ucontrol->value.integer.value[0] = gus->gf1.pcm_volume_level_left1;	ucontrol->value.integer.value[1] = gus->gf1.pcm_volume_level_right1;	spin_unlock_irqrestore(&gus->pcm_volume_level_lock, flags);	return 0;}static int snd_gf1_pcm_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	snd_gus_card_t *gus = snd_kcontrol_chip(kcontrol);	unsigned long flags;	int change;	unsigned int idx;	unsigned short val1, val2, vol;	gus_pcm_private_t *pcmp;	snd_gus_voice_t *pvoice;		val1 = ucontrol->value.integer.value[0] & 127;	val2 = ucontrol->value.integer.value[1] & 127;	spin_lock_irqsave(&gus->pcm_volume_level_lock, flags);	change = val1 != gus->gf1.pcm_volume_level_left1 ||	         val2 != gus->gf1.pcm_volume_level_right1;	gus->gf1.pcm_volume_level_left1 = val1;	gus->gf1.pcm_volume_level_right1 = val2;	gus->gf1.pcm_volume_level_left = snd_gf1_lvol_to_gvol_raw(val1 << 9) << 4;	gus->gf1.pcm_volume_level_right = snd_gf1_lvol_to_gvol_raw(val2 << 9) << 4;	spin_unlock_irqrestore(&gus->pcm_volume_level_lock, flags);	/* are we active? */	spin_lock_irqsave(&gus->voice_alloc, flags);	for (idx = 0; idx < 32; idx++) {		pvoice = &gus->gf1.voices[idx];		if (!pvoice->pcm)			continue;		pcmp = pvoice->private_data;		if (!(pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE))			continue;		/* load real volume - better precision */		spin_lock_irqsave(&gus->reg_lock, flags);		snd_gf1_select_voice(gus, pvoice->number);		snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);		vol = pvoice == pcmp->pvoices[0] ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;		snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, vol);		pcmp->final_volume = 1;		spin_unlock_irqrestore(&gus->reg_lock, flags);	}	spin_unlock_irqrestore(&gus->voice_alloc, flags);	return change;}static snd_kcontrol_new_t snd_gf1_pcm_volume_control ={	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "PCM Playback Volume",	.info = snd_gf1_pcm_volume_info,	.get = snd_gf1_pcm_volume_get,	.put = snd_gf1_pcm_volume_put};static snd_kcontrol_new_t snd_gf1_pcm_volume_control1 ={	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "GPCM Playback Volume",	.info = snd_gf1_pcm_volume_info,	.get = snd_gf1_pcm_volume_get,	.put = snd_gf1_pcm_volume_put};static snd_pcm_ops_t snd_gf1_pcm_playback_ops = {	.open =		snd_gf1_pcm_playback_open,	.close =	snd_gf1_pcm_playback_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_gf1_pcm_playback_hw_params,	.hw_free =	snd_gf1_pcm_playback_hw_free,	.prepare =	snd_gf1_pcm_playback_prepare,	.trigger =	snd_gf1_pcm_playback_trigger,	.pointer =	snd_gf1_pcm_playback_pointer,	.copy =		snd_gf1_pcm_playback_copy,	.silence =	snd_gf1_pcm_playback_silence,};static snd_pcm_ops_t snd_gf1_pcm_capture_ops = {	.open =		snd_gf1_pcm_capture_open,	.close =	snd_gf1_pcm_capture_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_gf1_pcm_capture_hw_params,	.hw_free =	snd_gf1_pcm_capture_hw_free,	.prepare =	snd_gf1_pcm_capture_prepare,	.trigger =	snd_gf1_pcm_capture_trigger,	.pointer =	snd_gf1_pcm_capture_pointer,};int snd_gf1_pcm_new(snd_gus_card_t * gus, int pcm_dev, int control_index, snd_pcm_t ** rpcm){	snd_card_t *card;	snd_kcontrol_t *kctl;	snd_pcm_t *pcm;	snd_pcm_substream_t *substream;	int capture, err;	if (rpcm)		*rpcm = NULL;	card = gus->card;	capture = !gus->interwave && !gus->ess_flag && !gus->ace_flag ? 1 : 0;	err = snd_pcm_new(card,			  gus->interwave ? "AMD InterWave" : "GF1",			  pcm_dev,			  gus->gf1.pcm_channels / 2,			  capture,			  &pcm);	if (err < 0)		return err;	pcm->private_data = gus;	pcm->private_free = snd_gf1_pcm_free;	/* playback setup */	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_gf1_pcm_playback_ops);	for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)		snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV,					      snd_dma_isa_data(),					      64*1024, gus->gf1.dma1 > 3 ? 128*1024 : 64*1024);		pcm->info_flags = 0;	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;	if (capture) {		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_gf1_pcm_capture_ops);		if (gus->gf1.dma2 == gus->gf1.dma1)			pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX;		snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,					      SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(),					      64*1024, gus->gf1.dma2 > 3 ? 128*1024 : 64*1024);	}	strcpy(pcm->name, pcm->id);	if (gus->interwave) {		sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A');	}	strcat(pcm->name, " (synth)");	gus->pcm = pcm;	if (gus->codec_flag)		kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control1, gus);	else		kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control, gus);	if ((err = snd_ctl_add(card, kctl)) < 0)		return err;	kctl->id.index = control_index;	if (rpcm)		*rpcm = pcm;	return 0;}

⌨️ 快捷键说明

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