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

📄 vx_pcm.c

📁 鼎力推荐!本程序是基于嵌入式LUNUX系统开发的源程序代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (chip->chip_status & VX_STAT_IS_STALE)		return -EBUSY;	data_mode = (chip->uer_bits & IEC958_AES0_NONAUDIO) != 0;	if (data_mode != pipe->data_mode && ! pipe->is_capture) {		/* IEC958 status (raw-mode) was changed */		/* we reopen the pipe */		struct vx_rmh rmh;		snd_printdd(KERN_DEBUG "reopen the pipe with data_mode = %d\n", data_mode);		vx_init_rmh(&rmh, CMD_FREE_PIPE);		vx_set_pipe_cmd_params(&rmh, 0, pipe->number, 0);		if ((err = vx_send_msg(chip, &rmh)) < 0)			return err;		vx_init_rmh(&rmh, CMD_RES_PIPE);		vx_set_pipe_cmd_params(&rmh, 0, pipe->number, pipe->channels);		if (data_mode)			rmh.Cmd[0] |= BIT_DATA_MODE;		if ((err = vx_send_msg(chip, &rmh)) < 0)			return err;		pipe->data_mode = data_mode;	}	if (chip->pcm_running && chip->freq != runtime->rate) {		snd_printk(KERN_ERR "vx: cannot set different clock %d from the current %d\n", runtime->rate, chip->freq);		return -EINVAL;	}	vx_set_clock(chip, runtime->rate);	if ((err = vx_set_format(chip, pipe, runtime)) < 0)		return err;	if (vx_is_pcmcia(chip)) {		pipe->align = 2; /* 16bit word */	} else {		pipe->align = 4; /* 32bit word */	}	pipe->buffer_bytes = frames_to_bytes(runtime, runtime->buffer_size);	pipe->period_bytes = frames_to_bytes(runtime, runtime->period_size);	pipe->hw_ptr = 0;	/* set the timestamp */	vx_update_pipe_position(chip, runtime, pipe);	/* clear again */	pipe->transferred = 0;	pipe->position = 0;	pipe->prepared = 1;	return 0;}/* * operators for PCM playback */static snd_pcm_ops_t vx_pcm_playback_ops = {	.open =		vx_pcm_playback_open,	.close =	vx_pcm_playback_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	vx_pcm_hw_params,	.hw_free =	vx_pcm_hw_free,	.prepare =	vx_pcm_prepare,	.trigger =	vx_pcm_trigger,	.pointer =	vx_pcm_playback_pointer,	.page =		snd_pcm_get_vmalloc_page,};/* * playback hw information */static snd_pcm_hardware_t vx_pcm_capture_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,};/* * vx_pcm_capture_open - open callback for capture */static int vx_pcm_capture_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;	vx_pipe_t *pipe_out_monitoring = 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_ins, return -EINVAL);	err = vx_alloc_pipe(chip, 1, audio, 2, &pipe);	if (err < 0)		return err;	pipe->substream = subs;	tasklet_init(&pipe->start_tq, vx_pcm_delayed_start, (unsigned long)subs);	chip->capture_pipes[audio] = pipe;	/* check if monitoring is needed */	if (chip->audio_monitor_active[audio]) {		pipe_out_monitoring = chip->playback_pipes[audio];		if (! pipe_out_monitoring) {			/* allocate a pipe */			err = vx_alloc_pipe(chip, 0, audio, 2, &pipe_out_monitoring);			if (err < 0)				return err;			chip->playback_pipes[audio] = pipe_out_monitoring;		}		pipe_out_monitoring->references++;		/* 		   if an output pipe is available, it's audios still may need to be 		   unmuted. hence we'll have to call a mixer entry point.		*/		vx_set_monitor_level(chip, audio, chip->audio_monitor[audio], chip->audio_monitor_active[audio]);		/* assuming stereo */		vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1], chip->audio_monitor_active[audio+1]); 	}	pipe->monitoring_pipe = pipe_out_monitoring; /* default value NULL */	runtime->hw = vx_pcm_capture_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_capture_close - close callback for capture */static int vx_pcm_capture_close(snd_pcm_substream_t *subs){	vx_core_t *chip = snd_pcm_substream_chip(subs);	vx_pipe_t *pipe;	vx_pipe_t *pipe_out_monitoring;		if (! subs->runtime->private_data)		return -EINVAL;	pipe = subs->runtime->private_data;	chip->capture_pipes[pipe->number] = NULL;	pipe_out_monitoring = pipe->monitoring_pipe;	/*	  if an output pipe is attached to this input, 	  check if it needs to be released.	*/	if (pipe_out_monitoring) {		if (--pipe_out_monitoring->references == 0) {			vx_free_pipe(chip, pipe_out_monitoring);			chip->playback_pipes[pipe->number] = NULL;			pipe->monitoring_pipe = NULL;		}	}		vx_free_pipe(chip, pipe);	return 0;}#define DMA_READ_ALIGN	6	/* hardware alignment for read *//* * vx_pcm_capture_update - update the capture buffer */static void vx_pcm_capture_update(vx_core_t *chip, snd_pcm_substream_t *subs, vx_pipe_t *pipe){	int size, space, count;	snd_pcm_runtime_t *runtime = subs->runtime;	if (! pipe->prepared || (chip->chip_status & VX_STAT_IS_STALE))		return;	size = runtime->buffer_size - snd_pcm_capture_avail(runtime);	if (! size)		return;	size = frames_to_bytes(runtime, size);	space = vx_query_hbuffer_size(chip, pipe);	if (space < 0)		goto _error;	if (size > space)		size = space;	size = (size / 3) * 3; /* align to 3 bytes */	if (size < DMA_READ_ALIGN)		goto _error;	/* keep the last 6 bytes, they will be read after disconnection */	count = size - DMA_READ_ALIGN;	/* read bytes until the current pointer reaches to the aligned position	 * for word-transfer	 */	while (count > 0) {		if ((pipe->hw_ptr % pipe->align) == 0)			break;		if (vx_wait_for_rx_full(chip) < 0)			goto _error;		vx_pcm_read_per_bytes(chip, runtime, pipe);		count -= 3;	}	if (count > 0) {		/* ok, let's accelerate! */		int align = pipe->align * 3;		space = (count / align) * align;		vx_pseudo_dma_read(chip, runtime, pipe, space);		count -= space;	}	/* read the rest of bytes */	while (count > 0) {		if (vx_wait_for_rx_full(chip) < 0)			goto _error;		vx_pcm_read_per_bytes(chip, runtime, pipe);		count -= 3;	}	/* disconnect the host, SIZE_HBUF command always switches to the stream mode */	vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);	/* read the last pending 6 bytes */	count = DMA_READ_ALIGN;	while (count > 0) {		vx_pcm_read_per_bytes(chip, runtime, pipe);		count -= 3;	}	/* update the position */	pipe->transferred += size;	if (pipe->transferred >= pipe->period_bytes) {		pipe->transferred %= pipe->period_bytes;		snd_pcm_period_elapsed(subs);	}	return; _error:	/* disconnect the host, SIZE_HBUF command always switches to the stream mode */	vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);	return;}/* * vx_pcm_capture_pointer - pointer callback for capture */static snd_pcm_uframes_t vx_pcm_capture_pointer(snd_pcm_substream_t *subs){	snd_pcm_runtime_t *runtime = subs->runtime;	vx_pipe_t *pipe = runtime->private_data;	return bytes_to_frames(runtime, pipe->hw_ptr);}/* * operators for PCM capture */static snd_pcm_ops_t vx_pcm_capture_ops = {	.open =		vx_pcm_capture_open,	.close =	vx_pcm_capture_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	vx_pcm_hw_params,	.hw_free =	vx_pcm_hw_free,	.prepare =	vx_pcm_prepare,	.trigger =	vx_pcm_trigger,	.pointer =	vx_pcm_capture_pointer,	.page =		snd_pcm_get_vmalloc_page,};/* * interrupt handler for pcm streams */void vx_pcm_update_intr(vx_core_t *chip, unsigned int events){	unsigned int i;	vx_pipe_t *pipe;#define EVENT_MASK	(END_OF_BUFFER_EVENTS_PENDING|ASYNC_EVENTS_PENDING)	if (events & EVENT_MASK) {		vx_init_rmh(&chip->irq_rmh, CMD_ASYNC);		if (events & ASYNC_EVENTS_PENDING)			chip->irq_rmh.Cmd[0] |= 0x00000001;	/* SEL_ASYNC_EVENTS */		if (events & END_OF_BUFFER_EVENTS_PENDING)			chip->irq_rmh.Cmd[0] |= 0x00000002;	/* SEL_END_OF_BUF_EVENTS */		if (vx_send_msg(chip, &chip->irq_rmh) < 0) {			snd_printdd(KERN_ERR "msg send error!!\n");			return;		}		i = 1;		while (i < chip->irq_rmh.LgStat) {			int p, buf, capture, eob;			p = chip->irq_rmh.Stat[i] & MASK_FIRST_FIELD;			capture = (chip->irq_rmh.Stat[i] & 0x400000) ? 1 : 0;			eob = (chip->irq_rmh.Stat[i] & 0x800000) ? 1 : 0;			i++;			if (events & ASYNC_EVENTS_PENDING)				i++;			buf = 1; /* force to transfer */			if (events & END_OF_BUFFER_EVENTS_PENDING) {				if (eob)					buf = chip->irq_rmh.Stat[i];				i++;			}			if (capture)				continue;			snd_assert(p >= 0 && (unsigned int)p < chip->audio_outs,);			pipe = chip->playback_pipes[p];			if (pipe && pipe->substream) {				vx_pcm_playback_update(chip, pipe->substream, pipe);				vx_pcm_playback_transfer(chip, pipe->substream, pipe, buf);			}		}	}	/* update the capture pcm pointers as frequently as possible */	for (i = 0; i < chip->audio_ins; i++) {		pipe = chip->capture_pipes[i];		if (pipe && pipe->substream)			vx_pcm_capture_update(chip, pipe->substream, pipe);	}}/* * vx_init_audio_io - check the availabe audio i/o and allocate pipe arrays */static int vx_init_audio_io(vx_core_t *chip){	struct vx_rmh rmh;	int preferred;	vx_init_rmh(&rmh, CMD_SUPPORTED);	if (vx_send_msg(chip, &rmh) < 0) {		snd_printk(KERN_ERR "vx: cannot get the supported audio data\n");		return -ENXIO;	}	chip->audio_outs = rmh.Stat[0] & MASK_FIRST_FIELD;	chip->audio_ins = (rmh.Stat[0] >> (FIELD_SIZE*2)) & MASK_FIRST_FIELD;	chip->audio_info = rmh.Stat[1];	/* allocate pipes */	chip->playback_pipes = kmalloc(sizeof(vx_pipe_t *) * chip->audio_outs, GFP_KERNEL);	chip->capture_pipes = kmalloc(sizeof(vx_pipe_t *) * chip->audio_ins, GFP_KERNEL);	if (! chip->playback_pipes || ! chip->capture_pipes)		return -ENOMEM;	memset(chip->playback_pipes, 0, sizeof(vx_pipe_t *) * chip->audio_outs);	memset(chip->capture_pipes, 0, sizeof(vx_pipe_t *) * chip->audio_ins);	preferred = chip->ibl.size;	chip->ibl.size = 0;	vx_set_ibl(chip, &chip->ibl); /* query the info */	if (preferred > 0) {		chip->ibl.size = ((preferred + chip->ibl.granularity - 1) / chip->ibl.granularity) * chip->ibl.granularity;		if (chip->ibl.size > chip->ibl.max_size)			chip->ibl.size = chip->ibl.max_size;	} else		chip->ibl.size = chip->ibl.min_size; /* set to the minimum */	vx_set_ibl(chip, &chip->ibl);	return 0;}/* * free callback for pcm */static void snd_vx_pcm_free(snd_pcm_t *pcm){	vx_core_t *chip = pcm->private_data;	chip->pcm[pcm->device] = NULL;	if (chip->playback_pipes) {		kfree(chip->playback_pipes);		chip->playback_pipes = NULL;	}	if (chip->capture_pipes) {		kfree(chip->capture_pipes);		chip->capture_pipes = NULL;	}}/* * snd_vx_pcm_new - create and initialize a pcm */int snd_vx_pcm_new(vx_core_t *chip){	snd_pcm_t *pcm;	unsigned int i;	int err;	if ((err = vx_init_audio_io(chip)) < 0)		return err;	for (i = 0; i < chip->hw->num_codecs; i++) {		unsigned int outs, ins;		outs = chip->audio_outs > i * 2 ? 1 : 0;		ins = chip->audio_ins > i * 2 ? 1 : 0;		if (! outs && ! ins)			break;		err = snd_pcm_new(chip->card, "VX PCM", i,				  outs, ins, &pcm);		if (err < 0)			return err;		if (outs)			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &vx_pcm_playback_ops);		if (ins)			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &vx_pcm_capture_ops);		pcm->private_data = chip;		pcm->private_free = snd_vx_pcm_free;		pcm->info_flags = 0;		strcpy(pcm->name, chip->card->shortname);		chip->pcm[i] = pcm;	}	return 0;}

⌨️ 快捷键说明

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