pcm_native.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,359 行 · 第 1/5 页

C
2,359
字号
		err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 					  snd_pcm_hw_rule_rate, hw,					  SNDRV_PCM_HW_PARAM_RATE, -1);		if (err < 0)			return err;	}	/* FIXME: this belong to lowlevel */	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_TICK_TIME,				     1000000 / HZ, 1000000 / HZ);	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);	return 0;}static void snd_pcm_add_file(snd_pcm_str_t *str,			     snd_pcm_file_t *pcm_file){	pcm_file->next = str->files;	str->files = pcm_file;}static void snd_pcm_remove_file(snd_pcm_str_t *str,				snd_pcm_file_t *pcm_file){	snd_pcm_file_t * pcm_file1;	if (str->files == pcm_file) {		str->files = pcm_file->next;	} else {		pcm_file1 = str->files;		while (pcm_file1 && pcm_file1->next != pcm_file)			pcm_file1 = pcm_file1->next;		if (pcm_file1 != NULL)			pcm_file1->next = pcm_file->next;	}}static int snd_pcm_release_file(snd_pcm_file_t * pcm_file){	snd_pcm_substream_t *substream;	snd_pcm_runtime_t *runtime;	snd_pcm_str_t * str;	snd_assert(pcm_file != NULL, return -ENXIO);	substream = pcm_file->substream;	snd_assert(substream != NULL, return -ENXIO);	runtime = substream->runtime;	str = substream->pstr;	snd_pcm_unlink(substream);	if (substream->open_flag) {		if (substream->ops->hw_free != NULL)			substream->ops->hw_free(substream);		substream->ops->close(substream);		substream->open_flag = 0;	}	substream->ffile = NULL;	snd_pcm_remove_file(str, pcm_file);	snd_pcm_release_substream(substream);	kfree(pcm_file);	return 0;}static int snd_pcm_open_file(struct file *file,			     snd_pcm_t *pcm,			     int stream,			     snd_pcm_file_t **rpcm_file){	int err = 0;	snd_pcm_file_t *pcm_file;	snd_pcm_substream_t *substream;	snd_pcm_str_t *str;	snd_assert(rpcm_file != NULL, return -EINVAL);	*rpcm_file = NULL;	pcm_file = kcalloc(1, sizeof(*pcm_file), GFP_KERNEL);	if (pcm_file == NULL) {		return -ENOMEM;	}	if ((err = snd_pcm_open_substream(pcm, stream, &substream)) < 0) {		kfree(pcm_file);		return err;	}	str = substream->pstr;	substream->file = pcm_file;	pcm_file->substream = substream;	snd_pcm_add_file(str, pcm_file);	err = snd_pcm_hw_constraints_init(substream);	if (err < 0) {		snd_printd("snd_pcm_hw_constraints_init failed\n");		snd_pcm_release_file(pcm_file);		return err;	}	if ((err = substream->ops->open(substream)) < 0) {		snd_pcm_release_file(pcm_file);		return err;	}	substream->open_flag = 1;	err = snd_pcm_hw_constraints_complete(substream);	if (err < 0) {		snd_printd("snd_pcm_hw_constraints_complete failed\n");		substream->ops->close(substream);		snd_pcm_release_file(pcm_file);		return err;	}	substream->ffile = file;	file->private_data = pcm_file;	*rpcm_file = pcm_file;	return 0;}int snd_pcm_open(struct inode *inode, struct file *file){	int cardnum = SNDRV_MINOR_CARD(iminor(inode));	int device = SNDRV_MINOR_DEVICE(iminor(inode));	int err;	snd_pcm_t *pcm;	snd_pcm_file_t *pcm_file;	wait_queue_t wait;	snd_runtime_check(device >= SNDRV_MINOR_PCM_PLAYBACK && device < SNDRV_MINOR_DEVICES, return -ENXIO);	pcm = snd_pcm_devices[(cardnum * SNDRV_PCM_DEVICES) + (device % SNDRV_MINOR_PCMS)];	if (pcm == NULL) {		err = -ENODEV;		goto __error1;	}	err = snd_card_file_add(pcm->card, file);	if (err < 0)		goto __error1;	if (!try_module_get(pcm->card->module)) {		err = -EFAULT;		goto __error2;	}	init_waitqueue_entry(&wait, current);	add_wait_queue(&pcm->open_wait, &wait);	down(&pcm->open_mutex);	while (1) {		err = snd_pcm_open_file(file, pcm, device >= SNDRV_MINOR_PCM_CAPTURE ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, &pcm_file);		if (err >= 0)			break;		if (err == -EAGAIN) {			if (file->f_flags & O_NONBLOCK) {				err = -EBUSY;				break;			}		} else			break;		set_current_state(TASK_INTERRUPTIBLE);		up(&pcm->open_mutex);		schedule();		down(&pcm->open_mutex);		if (signal_pending(current)) {			err = -ERESTARTSYS;			break;		}	}	remove_wait_queue(&pcm->open_wait, &wait);	up(&pcm->open_mutex);	if (err < 0)		goto __error;	return err;      __error:	module_put(pcm->card->module);      __error2:      	snd_card_file_remove(pcm->card, file);      __error1:      	return err;}int snd_pcm_release(struct inode *inode, struct file *file){	snd_pcm_t *pcm;	snd_pcm_substream_t *substream;	snd_pcm_file_t *pcm_file;	pcm_file = file->private_data;	substream = pcm_file->substream;	snd_assert(substream != NULL, return -ENXIO);	snd_assert(!atomic_read(&substream->runtime->mmap_count), );	pcm = substream->pcm;	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)		snd_pcm_playback_drop(substream);	else		snd_pcm_capture_drop(substream);	fasync_helper(-1, file, 0, &substream->runtime->fasync);	down(&pcm->open_mutex);	snd_pcm_release_file(pcm_file);	up(&pcm->open_mutex);	wake_up(&pcm->open_wait);	module_put(pcm->card->module);	snd_card_file_remove(pcm->card, file);	return 0;}snd_pcm_sframes_t snd_pcm_playback_rewind(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames){	snd_pcm_runtime_t *runtime = substream->runtime;	snd_pcm_sframes_t appl_ptr;	snd_pcm_sframes_t ret;	snd_pcm_sframes_t hw_avail;	if (frames == 0)		return 0;	snd_pcm_stream_lock_irq(substream);	switch (runtime->status->state) {	case SNDRV_PCM_STATE_PREPARED:		break;	case SNDRV_PCM_STATE_DRAINING:	case SNDRV_PCM_STATE_RUNNING:		if (snd_pcm_update_hw_ptr(substream) >= 0)			break;		/* Fall through */	case SNDRV_PCM_STATE_XRUN:		ret = -EPIPE;		goto __end;	default:		ret = -EBADFD;		goto __end;	}	hw_avail = snd_pcm_playback_hw_avail(runtime);	if (hw_avail <= 0) {		ret = 0;		goto __end;	}	if (frames > (snd_pcm_uframes_t)hw_avail)		frames = hw_avail;	else		frames -= frames % runtime->xfer_align;	appl_ptr = runtime->control->appl_ptr - frames;	if (appl_ptr < 0)		appl_ptr += runtime->boundary;	runtime->control->appl_ptr = appl_ptr;	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&	    runtime->sleep_min)		snd_pcm_tick_prepare(substream);	ret = frames; __end:	snd_pcm_stream_unlock_irq(substream);	return ret;}snd_pcm_sframes_t snd_pcm_capture_rewind(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames){	snd_pcm_runtime_t *runtime = substream->runtime;	snd_pcm_sframes_t appl_ptr;	snd_pcm_sframes_t ret;	snd_pcm_sframes_t hw_avail;	if (frames == 0)		return 0;	snd_pcm_stream_lock_irq(substream);	switch (runtime->status->state) {	case SNDRV_PCM_STATE_PREPARED:	case SNDRV_PCM_STATE_DRAINING:		break;	case SNDRV_PCM_STATE_RUNNING:		if (snd_pcm_update_hw_ptr(substream) >= 0)			break;		/* Fall through */	case SNDRV_PCM_STATE_XRUN:		ret = -EPIPE;		goto __end;	default:		ret = -EBADFD;		goto __end;	}	hw_avail = snd_pcm_capture_hw_avail(runtime);	if (hw_avail <= 0) {		ret = 0;		goto __end;	}	if (frames > (snd_pcm_uframes_t)hw_avail)		frames = hw_avail;	else		frames -= frames % runtime->xfer_align;	appl_ptr = runtime->control->appl_ptr - frames;	if (appl_ptr < 0)		appl_ptr += runtime->boundary;	runtime->control->appl_ptr = appl_ptr;	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&	    runtime->sleep_min)		snd_pcm_tick_prepare(substream);	ret = frames; __end:	snd_pcm_stream_unlock_irq(substream);	return ret;}snd_pcm_sframes_t snd_pcm_playback_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames){	snd_pcm_runtime_t *runtime = substream->runtime;	snd_pcm_sframes_t appl_ptr;	snd_pcm_sframes_t ret;	snd_pcm_sframes_t avail;	if (frames == 0)		return 0;	snd_pcm_stream_lock_irq(substream);	switch (runtime->status->state) {	case SNDRV_PCM_STATE_PREPARED:	case SNDRV_PCM_STATE_PAUSED:		break;	case SNDRV_PCM_STATE_DRAINING:	case SNDRV_PCM_STATE_RUNNING:		if (snd_pcm_update_hw_ptr(substream) >= 0)			break;		/* Fall through */	case SNDRV_PCM_STATE_XRUN:		ret = -EPIPE;		goto __end;	default:		ret = -EBADFD;		goto __end;	}	avail = snd_pcm_playback_avail(runtime);	if (avail <= 0) {		ret = 0;		goto __end;	}	if (frames > (snd_pcm_uframes_t)avail)		frames = avail;	else		frames -= frames % runtime->xfer_align;	appl_ptr = runtime->control->appl_ptr + frames;	if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)		appl_ptr -= runtime->boundary;	runtime->control->appl_ptr = appl_ptr;	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&	    runtime->sleep_min)		snd_pcm_tick_prepare(substream);	ret = frames; __end:	snd_pcm_stream_unlock_irq(substream);	return ret;}snd_pcm_sframes_t snd_pcm_capture_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames){	snd_pcm_runtime_t *runtime = substream->runtime;	snd_pcm_sframes_t appl_ptr;	snd_pcm_sframes_t ret;	snd_pcm_sframes_t avail;	if (frames == 0)		return 0;	snd_pcm_stream_lock_irq(substream);	switch (runtime->status->state) {	case SNDRV_PCM_STATE_PREPARED:	case SNDRV_PCM_STATE_DRAINING:	case SNDRV_PCM_STATE_PAUSED:		break;	case SNDRV_PCM_STATE_RUNNING:		if (snd_pcm_update_hw_ptr(substream) >= 0)			break;		/* Fall through */	case SNDRV_PCM_STATE_XRUN:		ret = -EPIPE;		goto __end;	default:		ret = -EBADFD;		goto __end;	}	avail = snd_pcm_capture_avail(runtime);	if (avail <= 0) {		ret = 0;		goto __end;	}	if (frames > (snd_pcm_uframes_t)avail)		frames = avail;	else		frames -= frames % runtime->xfer_align;	appl_ptr = runtime->control->appl_ptr + frames;	if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)		appl_ptr -= runtime->boundary;	runtime->control->appl_ptr = appl_ptr;	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&	    runtime->sleep_min)		snd_pcm_tick_prepare(substream);	ret = frames; __end:	snd_pcm_stream_unlock_irq(substream);	return ret;}static int snd_pcm_hwsync(snd_pcm_substream_t *substream){	snd_pcm_runtime_t *runtime = substream->runtime;	int err;	snd_pcm_stream_lock_irq(substream);	switch (runtime->status->state) {	case SNDRV_PCM_STATE_DRAINING:		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)			goto __badfd;	case SNDRV_PCM_STATE_RUNNING:		if ((err = snd_pcm_update_hw_ptr(substream)) < 0)			break;		/* Fall through */	case SNDRV_PCM_STATE_PREPARED:	case SNDRV_PCM_STATE_SUSPENDED:		err = 0;		break;	case SNDRV_PCM_STATE_XRUN:		err = -EPIPE;		break;	default:	      __badfd:		err = -EBADFD;		break;	}	snd_pcm_stream_unlock_irq(substream);	return err;}		static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t __user *res){	snd_pcm_runtime_t *runtime = substream->runtime;	int err;	snd_pcm_sframes_t n = 0;	snd_pcm_stream_lock_irq(substream);	switch (runtime->status->state) {	case SNDRV_PCM_STATE_DRAINING:		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)			goto __badfd;	case SNDRV_PCM_STATE_RUNNING:		if ((err = snd_pcm_update_hw_ptr(substream)) < 0)			break;		/* Fall through */	case SNDRV_PCM_STATE_PREPARED:	case SNDRV_PCM_STATE_SUSPENDED:		err = 0;		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)			n = snd_pcm_playback_hw_avail(runtime);		else			n = snd_pcm_capture_avail(runtime);		break;	case SNDRV_PCM_STATE_XRUN:		err = -EPIPE;		break;	default:	      __badfd:		err = -EBADFD;		break;	}	snd_pcm_stream_unlock_irq(substream);	if (!err)		if (put_user(n, res))			err = -EFAULT;	return err;}		static int snd_pcm_sync_ptr(snd_

⌨️ 快捷键说明

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