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

📄 vx_pcm.c

📁 鼎力推荐!本程序是基于嵌入式LUNUX系统开发的源程序代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ }/* * vx_alloc_pipe - allocate a pipe and initialize the pipe instance * @capture: 0 = playback, 1 = capture operation * @audioid: the audio id to be assigned * @num_audio: number of audio channels * @pipep: the returned pipe instance * * return 0 on success, or a negative error code. */static int vx_alloc_pipe(vx_core_t *chip, int capture,			 int audioid, int num_audio,			 vx_pipe_t **pipep){	int err;	vx_pipe_t *pipe;	struct vx_rmh rmh;	int data_mode;	*pipep = NULL;	vx_init_rmh(&rmh, CMD_RES_PIPE);	vx_set_pipe_cmd_params(&rmh, capture, audioid, num_audio);#if 0	// NYI	if (underrun_skip_sound)		rmh.Cmd[0] |= BIT_SKIP_SOUND;#endif	// NYI	data_mode = (chip->uer_bits & IEC958_AES0_NONAUDIO) != 0;	if (! capture && data_mode)		rmh.Cmd[0] |= BIT_DATA_MODE;	err = vx_send_msg(chip, &rmh);	if (err < 0)		return err;	/* initialize the pipe record */	pipe = kcalloc(1, sizeof(*pipe), GFP_KERNEL);	if (! pipe) {		/* release the pipe */		vx_init_rmh(&rmh, CMD_FREE_PIPE);		vx_set_pipe_cmd_params(&rmh, capture, audioid, 0);		vx_send_msg(chip, &rmh);		return -ENOMEM;	}	/* the pipe index should be identical with the audio index */	pipe->number = audioid;	pipe->is_capture = capture;	pipe->channels = num_audio;	pipe->differed_type = 0;	pipe->pcx_time = 0;	pipe->data_mode = data_mode;	*pipep = pipe;	return 0;}/* * vx_free_pipe - release a pipe * @pipe: pipe to be released */static int vx_free_pipe(vx_core_t *chip, vx_pipe_t *pipe){	struct vx_rmh rmh;	vx_init_rmh(&rmh, CMD_FREE_PIPE);	vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0);	vx_send_msg(chip, &rmh);	kfree(pipe);	return 0;}/* * vx_start_stream - start the stream * * called from trigger callback only */static int vx_start_stream(vx_core_t *chip, vx_pipe_t *pipe){	struct vx_rmh rmh;	vx_init_rmh(&rmh, CMD_START_ONE_STREAM);	vx_set_stream_cmd_params(&rmh, pipe->is_capture, pipe->number);	vx_set_differed_time(chip, &rmh, pipe);	return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ }/* * vx_stop_stream - stop the stream * * called from trigger callback only */static int vx_stop_stream(vx_core_t *chip, vx_pipe_t *pipe){	struct vx_rmh rmh;	vx_init_rmh(&rmh, CMD_STOP_STREAM);	vx_set_stream_cmd_params(&rmh, pipe->is_capture, pipe->number);	return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ }/* * playback hw information */static snd_pcm_hardware_t vx_pcm_playback_hw = {	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID |				 SNDRV_PCM_INFO_RESUME),	.formats =		/*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		5000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	126,	.period_bytes_max =	(128*1024),	.periods_min =		2,	.periods_max =		VX_MAX_PERIODS,	.fifo_size =		126,};static void vx_pcm_delayed_start(unsigned long arg);/* * vx_pcm_playback_open - open callback for playback */static int vx_pcm_playback_open(snd_pcm_substream_t *subs){	snd_pcm_runtime_t *runtime = subs->runtime;	vx_core_t *chip = snd_pcm_substream_chip(subs);	vx_pipe_t *pipe = NULL;	unsigned int audio;	int err;	if (chip->chip_status & VX_STAT_IS_STALE)		return -EBUSY;	audio = subs->pcm->device * 2;	snd_assert(audio < chip->audio_outs, return -EINVAL);		/* playback pipe may have been already allocated for monitoring */	pipe = chip->playback_pipes[audio];	if (! pipe) {		/* not allocated yet */		err = vx_alloc_pipe(chip, 0, audio, 2, &pipe); /* stereo playback */		if (err < 0)			return err;		chip->playback_pipes[audio] = pipe;	}	/* open for playback */	pipe->references++;	pipe->substream = subs;	tasklet_init(&pipe->start_tq, vx_pcm_delayed_start, (unsigned long)subs);	chip->playback_pipes[audio] = pipe;	runtime->hw = vx_pcm_playback_hw;	runtime->hw.period_bytes_min = chip->ibl.size;	runtime->private_data = pipe;	/* align to 4 bytes (otherwise will be problematic when 24bit is used) */ 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4);	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);	return 0;}/* * vx_pcm_playback_close - close callback for playback */static int vx_pcm_playback_close(snd_pcm_substream_t *subs){	vx_core_t *chip = snd_pcm_substream_chip(subs);	vx_pipe_t *pipe;	if (! subs->runtime->private_data)		return -EINVAL;	pipe = subs->runtime->private_data;	if (--pipe->references == 0) {		chip->playback_pipes[pipe->number] = NULL;		vx_free_pipe(chip, pipe);	}	return 0;}/* * vx_notify_end_of_buffer - send "end-of-buffer" notifier at the given pipe * @pipe: the pipe to notify * * NB: call with a certain lock. */static int vx_notify_end_of_buffer(vx_core_t *chip, vx_pipe_t *pipe){	int err;	struct vx_rmh rmh;  /* use a temporary rmh here */	/* Toggle Dsp Host Interface into Message mode */	vx_send_rih_nolock(chip, IRQ_PAUSE_START_CONNECT);	vx_init_rmh(&rmh, CMD_NOTIFY_END_OF_BUFFER);	vx_set_stream_cmd_params(&rmh, 0, pipe->number);	err = vx_send_msg_nolock(chip, &rmh);	if (err < 0)		return err;	/* Toggle Dsp Host Interface back to sound transfer mode */	vx_send_rih_nolock(chip, IRQ_PAUSE_START_CONNECT);	return 0;}/* * vx_pcm_playback_transfer_chunk - transfer a single chunk * @subs: substream * @pipe: the pipe to transfer * @size: chunk size in bytes * * transfer a single buffer chunk.  EOB notificaton is added after that. * called from the interrupt handler, too. * * return 0 if ok. */static int vx_pcm_playback_transfer_chunk(vx_core_t *chip, snd_pcm_runtime_t *runtime, vx_pipe_t *pipe, int size){	int space, err = 0;	space = vx_query_hbuffer_size(chip, pipe);	if (space < 0) {		/* disconnect the host, SIZE_HBUF command always switches to the stream mode */		vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);		snd_printd("error hbuffer\n");		return space;	}	if (space < size) {		vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);		snd_printd("no enough hbuffer space %d\n", space);		return -EIO; /* XRUN */	}			/* we don't need irqsave here, because this function	 * is called from either trigger callback or irq handler	 */	spin_lock(&chip->lock); 	vx_pseudo_dma_write(chip, runtime, pipe, size);	err = vx_notify_end_of_buffer(chip, pipe);	/* disconnect the host, SIZE_HBUF command always switches to the stream mode */	vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);	spin_unlock(&chip->lock);	return err;}/* * update the position of the given pipe. * pipe->position is updated and wrapped within the buffer size. * pipe->transferred is updated, too, but the size is not wrapped, * so that the caller can check the total transferred size later * (to call snd_pcm_period_elapsed). */static int vx_update_pipe_position(vx_core_t *chip, snd_pcm_runtime_t *runtime, vx_pipe_t *pipe){	struct vx_rmh rmh;	int err, update;	u64 count;	vx_init_rmh(&rmh, CMD_STREAM_SAMPLE_COUNT);	vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0);	err = vx_send_msg(chip, &rmh);	if (err < 0)		return err;	count = ((u64)(rmh.Stat[0] & 0xfffff) << 24) | (u64)rmh.Stat[1];	update = (int)(count - pipe->cur_count);	pipe->cur_count = count;	pipe->position += update;	if (pipe->position >= (int)runtime->buffer_size)		pipe->position %= runtime->buffer_size;	pipe->transferred += update;	return 0;}/* * transfer the pending playback buffer data to DSP * called from interrupt handler */static void vx_pcm_playback_transfer(vx_core_t *chip, snd_pcm_substream_t *subs, vx_pipe_t *pipe, int nchunks){	int i, err;	snd_pcm_runtime_t *runtime = subs->runtime;	if (! pipe->prepared || (chip->chip_status & VX_STAT_IS_STALE))		return;	for (i = 0; i < nchunks; i++) {		if ((err = vx_pcm_playback_transfer_chunk(chip, runtime, pipe,							  chip->ibl.size)) < 0)			return;	}}/* * update the playback position and call snd_pcm_period_elapsed() if necessary * called from interrupt handler */static void vx_pcm_playback_update(vx_core_t *chip, snd_pcm_substream_t *subs, vx_pipe_t *pipe){	int err;	snd_pcm_runtime_t *runtime = subs->runtime;	if (pipe->running && ! (chip->chip_status & VX_STAT_IS_STALE)) {		if ((err = vx_update_pipe_position(chip, runtime, pipe)) < 0)			return;		if (pipe->transferred >= (int)runtime->period_size) {			pipe->transferred %= runtime->period_size;			snd_pcm_period_elapsed(subs);		}	}}/* * start the stream and pipe. * this function is called from tasklet, which is invoked by the trigger * START callback. */static void vx_pcm_delayed_start(unsigned long arg){	snd_pcm_substream_t *subs = (snd_pcm_substream_t *)arg;	vx_core_t *chip = subs->pcm->private_data;	vx_pipe_t *pipe = subs->runtime->private_data;	int err;	/*  printk( KERN_DEBUG "DDDD tasklet delayed start jiffies = %ld\n", jiffies);*/	if ((err = vx_start_stream(chip, pipe)) < 0) {		snd_printk(KERN_ERR "vx: cannot start stream\n");		return;	}	if ((err = vx_toggle_pipe(chip, pipe, 1)) < 0) {		snd_printk(KERN_ERR "vx: cannot start pipe\n");		return;	}	/*   printk( KERN_DEBUG "dddd tasklet delayed start jiffies = %ld \n", jiffies);*/}/* * vx_pcm_playback_trigger - trigger callback for playback */static int vx_pcm_trigger(snd_pcm_substream_t *subs, int cmd){	vx_core_t *chip = snd_pcm_substream_chip(subs);	vx_pipe_t *pipe = subs->runtime->private_data;	int err;	if (chip->chip_status & VX_STAT_IS_STALE)		return -EBUSY;			switch (cmd) {	case SNDRV_PCM_TRIGGER_START:	case SNDRV_PCM_TRIGGER_RESUME:		if (! pipe->is_capture)			vx_pcm_playback_transfer(chip, subs, pipe, 2);		/* FIXME:		 * we trigger the pipe using tasklet, so that the interrupts are		 * issued surely after the trigger is completed.		 */ 		tasklet_hi_schedule(&pipe->start_tq);		chip->pcm_running++;		pipe->running = 1;		break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_SUSPEND:		vx_toggle_pipe(chip, pipe, 0);		vx_stop_pipe(chip, pipe);		vx_stop_stream(chip, pipe);		chip->pcm_running--;		pipe->running = 0;		break;	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:		if ((err = vx_toggle_pipe(chip, pipe, 0)) < 0)			return err;		break;	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:		if ((err = vx_toggle_pipe(chip, pipe, 1)) < 0)			return err;		break;	default:		return -EINVAL;	}	return 0;}/* * vx_pcm_playback_pointer - pointer callback for playback */static snd_pcm_uframes_t vx_pcm_playback_pointer(snd_pcm_substream_t *subs){	snd_pcm_runtime_t *runtime = subs->runtime;	vx_pipe_t *pipe = runtime->private_data;	return pipe->position;}/* * vx_pcm_hw_params - hw_params callback for playback and capture */static int vx_pcm_hw_params(snd_pcm_substream_t *subs,				     snd_pcm_hw_params_t *hw_params){	return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params));}/* * vx_pcm_hw_free - hw_free callback for playback and capture */static int vx_pcm_hw_free(snd_pcm_substream_t *subs){	return snd_pcm_free_vmalloc_buffer(subs);}/* * vx_pcm_prepare - prepare callback for playback and capture */static int vx_pcm_prepare(snd_pcm_substream_t *subs){	vx_core_t *chip = snd_pcm_substream_chip(subs);	snd_pcm_runtime_t *runtime = subs->runtime;	vx_pipe_t *pipe = runtime->private_data;	int err, data_mode;	// int max_size, nchunks;

⌨️ 快捷键说明

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