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

📄 pcm_native.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	if (copy_from_user(params, _params, sizeof(*params))) {		err = -EFAULT;		goto out;	}	err = snd_pcm_hw_params(substream, params);	if (copy_to_user(_params, params, sizeof(*params))) {		if (!err)			err = -EFAULT;	}out:	kfree(params);	return err;}static int snd_pcm_hw_free(struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime;	int result = 0;	snd_assert(substream != NULL, return -ENXIO);	runtime = substream->runtime;	snd_assert(runtime != NULL, return -ENXIO);	snd_pcm_stream_lock_irq(substream);	switch (runtime->status->state) {	case SNDRV_PCM_STATE_SETUP:	case SNDRV_PCM_STATE_PREPARED:		break;	default:		snd_pcm_stream_unlock_irq(substream);		return -EBADFD;	}	snd_pcm_stream_unlock_irq(substream);	if (atomic_read(&substream->mmap_count))		return -EBADFD;	if (substream->ops->hw_free)		result = substream->ops->hw_free(substream);	runtime->status->state = SNDRV_PCM_STATE_OPEN;	remove_acceptable_latency(substream->latency_id);	return result;}static int snd_pcm_sw_params(struct snd_pcm_substream *substream,			     struct snd_pcm_sw_params *params){	struct snd_pcm_runtime *runtime;	snd_assert(substream != NULL, return -ENXIO);	runtime = substream->runtime;	snd_assert(runtime != NULL, return -ENXIO);	snd_pcm_stream_lock_irq(substream);	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {		snd_pcm_stream_unlock_irq(substream);		return -EBADFD;	}	snd_pcm_stream_unlock_irq(substream);	if (params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)		return -EINVAL;	if (params->avail_min == 0)		return -EINVAL;	if (params->xfer_align == 0 ||	    params->xfer_align % runtime->min_align != 0)		return -EINVAL;	if (params->silence_size >= runtime->boundary) {		if (params->silence_threshold != 0)			return -EINVAL;	} else {		if (params->silence_size > params->silence_threshold)			return -EINVAL;		if (params->silence_threshold > runtime->buffer_size)			return -EINVAL;	}	snd_pcm_stream_lock_irq(substream);	runtime->tstamp_mode = params->tstamp_mode;	runtime->sleep_min = params->sleep_min;	runtime->period_step = params->period_step;	runtime->control->avail_min = params->avail_min;	runtime->start_threshold = params->start_threshold;	runtime->stop_threshold = params->stop_threshold;	runtime->silence_threshold = params->silence_threshold;	runtime->silence_size = params->silence_size;	runtime->xfer_align = params->xfer_align;        params->boundary = runtime->boundary;	if (snd_pcm_running(substream)) {		if (runtime->sleep_min)			snd_pcm_tick_prepare(substream);		else			snd_pcm_tick_set(substream, 0);		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&		    runtime->silence_size > 0)			snd_pcm_playback_silence(substream, ULONG_MAX);		wake_up(&runtime->sleep);	}	snd_pcm_stream_unlock_irq(substream);	return 0;}static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,				  struct snd_pcm_sw_params __user * _params){	struct snd_pcm_sw_params params;	int err;	if (copy_from_user(&params, _params, sizeof(params)))		return -EFAULT;	err = snd_pcm_sw_params(substream, &params);	if (copy_to_user(_params, &params, sizeof(params)))		return -EFAULT;	return err;}int snd_pcm_status(struct snd_pcm_substream *substream,		   struct snd_pcm_status *status){	struct snd_pcm_runtime *runtime = substream->runtime;	snd_pcm_stream_lock_irq(substream);	status->state = runtime->status->state;	status->suspended_state = runtime->status->suspended_state;	if (status->state == SNDRV_PCM_STATE_OPEN)		goto _end;	status->trigger_tstamp = runtime->trigger_tstamp;	if (snd_pcm_running(substream)) {		snd_pcm_update_hw_ptr(substream);		if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP)			status->tstamp = runtime->status->tstamp;		else			getnstimeofday(&status->tstamp);	} else		getnstimeofday(&status->tstamp);	status->appl_ptr = runtime->control->appl_ptr;	status->hw_ptr = runtime->status->hw_ptr;	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {		status->avail = snd_pcm_playback_avail(runtime);		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING ||		    runtime->status->state == SNDRV_PCM_STATE_DRAINING)			status->delay = runtime->buffer_size - status->avail;		else			status->delay = 0;	} else {		status->avail = snd_pcm_capture_avail(runtime);		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)			status->delay = status->avail;		else			status->delay = 0;	}	status->avail_max = runtime->avail_max;	status->overrange = runtime->overrange;	runtime->avail_max = 0;	runtime->overrange = 0; _end: 	snd_pcm_stream_unlock_irq(substream);	return 0;}static int snd_pcm_status_user(struct snd_pcm_substream *substream,			       struct snd_pcm_status __user * _status){	struct snd_pcm_status status;	struct snd_pcm_runtime *runtime;	int res;		snd_assert(substream != NULL, return -ENXIO);	runtime = substream->runtime;	memset(&status, 0, sizeof(status));	res = snd_pcm_status(substream, &status);	if (res < 0)		return res;	if (copy_to_user(_status, &status, sizeof(status)))		return -EFAULT;	return 0;}static int snd_pcm_channel_info(struct snd_pcm_substream *substream,				struct snd_pcm_channel_info * info){	struct snd_pcm_runtime *runtime;	unsigned int channel;		snd_assert(substream != NULL, return -ENXIO);	channel = info->channel;	runtime = substream->runtime;	snd_pcm_stream_lock_irq(substream);	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {		snd_pcm_stream_unlock_irq(substream);		return -EBADFD;	}	snd_pcm_stream_unlock_irq(substream);	if (channel >= runtime->channels)		return -EINVAL;	memset(info, 0, sizeof(*info));	info->channel = channel;	return substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info);}static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,				     struct snd_pcm_channel_info __user * _info){	struct snd_pcm_channel_info info;	int res;		if (copy_from_user(&info, _info, sizeof(info)))		return -EFAULT;	res = snd_pcm_channel_info(substream, &info);	if (res < 0)		return res;	if (copy_to_user(_info, &info, sizeof(info)))		return -EFAULT;	return 0;}static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime = substream->runtime;	if (runtime->trigger_master == NULL)		return;	if (runtime->trigger_master == substream) {		getnstimeofday(&runtime->trigger_tstamp);	} else {		snd_pcm_trigger_tstamp(runtime->trigger_master);		runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp;	}	runtime->trigger_master = NULL;}struct action_ops {	int (*pre_action)(struct snd_pcm_substream *substream, int state);	int (*do_action)(struct snd_pcm_substream *substream, int state);	void (*undo_action)(struct snd_pcm_substream *substream, int state);	void (*post_action)(struct snd_pcm_substream *substream, int state);};/* *  this functions is core for handling of linked stream *  Note: the stream state might be changed also on failure *  Note2: call with calling stream lock + link lock */static int snd_pcm_action_group(struct action_ops *ops,				struct snd_pcm_substream *substream,				int state, int do_lock){	struct snd_pcm_substream *s = NULL;	struct snd_pcm_substream *s1;	int res = 0;	snd_pcm_group_for_each_entry(s, substream) {		if (do_lock && s != substream)			spin_lock_nested(&s->self_group.lock,					 SINGLE_DEPTH_NESTING);		res = ops->pre_action(s, state);		if (res < 0)			goto _unlock;	}	snd_pcm_group_for_each_entry(s, substream) {		res = ops->do_action(s, state);		if (res < 0) {			if (ops->undo_action) {				snd_pcm_group_for_each_entry(s1, substream) {					if (s1 == s) /* failed stream */						break;					ops->undo_action(s1, state);				}			}			s = NULL; /* unlock all */			goto _unlock;		}	}	snd_pcm_group_for_each_entry(s, substream) {		ops->post_action(s, state);	} _unlock:	if (do_lock) {		/* unlock streams */		snd_pcm_group_for_each_entry(s1, substream) {			if (s1 != substream)				spin_unlock(&s1->self_group.lock);			if (s1 == s)	/* end */				break;		}	}	return res;}/* *  Note: call with stream lock */static int snd_pcm_action_single(struct action_ops *ops,				 struct snd_pcm_substream *substream,				 int state){	int res;		res = ops->pre_action(substream, state);	if (res < 0)		return res;	res = ops->do_action(substream, state);	if (res == 0)		ops->post_action(substream, state);	else if (ops->undo_action)		ops->undo_action(substream, state);	return res;}/* *  Note: call with stream lock */static int snd_pcm_action(struct action_ops *ops,			  struct snd_pcm_substream *substream,			  int state){	int res;	if (snd_pcm_stream_linked(substream)) {		if (!spin_trylock(&substream->group->lock)) {			spin_unlock(&substream->self_group.lock);			spin_lock(&substream->group->lock);			spin_lock(&substream->self_group.lock);		}		res = snd_pcm_action_group(ops, substream, state, 1);		spin_unlock(&substream->group->lock);	} else {		res = snd_pcm_action_single(ops, substream, state);	}	return res;}/* *  Note: don't use any locks before */static int snd_pcm_action_lock_irq(struct action_ops *ops,				   struct snd_pcm_substream *substream,				   int state){	int res;	read_lock_irq(&snd_pcm_link_rwlock);	if (snd_pcm_stream_linked(substream)) {		spin_lock(&substream->group->lock);		spin_lock(&substream->self_group.lock);		res = snd_pcm_action_group(ops, substream, state, 1);		spin_unlock(&substream->self_group.lock);		spin_unlock(&substream->group->lock);	} else {		spin_lock(&substream->self_group.lock);		res = snd_pcm_action_single(ops, substream, state);		spin_unlock(&substream->self_group.lock);	}	read_unlock_irq(&snd_pcm_link_rwlock);	return res;}/* */static int snd_pcm_action_nonatomic(struct action_ops *ops,				    struct snd_pcm_substream *substream,				    int state){	int res;	down_read(&snd_pcm_link_rwsem);	if (snd_pcm_stream_linked(substream))		res = snd_pcm_action_group(ops, substream, state, 0);	else		res = snd_pcm_action_single(ops, substream, state);	up_read(&snd_pcm_link_rwsem);	return res;}/* * start callbacks */static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	if (runtime->status->state != SNDRV_PCM_STATE_PREPARED)		return -EBADFD;	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&	    !snd_pcm_playback_data(substream))		return -EPIPE;	runtime->trigger_master = substream;	return 0;}static int snd_pcm_do_start(struct snd_pcm_substream *substream, int state){	if (substream->runtime->trigger_master != substream)		return 0;	return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);}static void snd_pcm_undo_start(struct snd_pcm_substream *substream, int state){	if (substream->runtime->trigger_master == substream)		substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);}static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	snd_pcm_trigger_tstamp(substream);	runtime->status->state = state;	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&	    runtime->silence_size > 0)		snd_pcm_playback_silence(substream, ULONG_MAX);	if (runtime->sleep_min)		snd_pcm_tick_prepare(substream);	if (substream->timer)		snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART,				 &runtime->trigger_tstamp);}static struct action_ops snd_pcm_action_start = {	.pre_action = snd_pcm_pre_start,	.do_action = snd_pcm_do_start,	.undo_action = snd_pcm_undo_start,	.post_action = snd_pcm_post_start};/** * snd_pcm_start * @substream: the PCM substream instance * * Start all linked streams. */int snd_pcm_start(struct snd_pcm_substream *substream){	return snd_pcm_action(&snd_pcm_action_start, substream,			      SNDRV_PCM_STATE_RUNNING);}/* * stop callbacks */static int snd_pcm_pre_stop(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)		return -EBADFD;	runtime->trigger_master = substream;	return 0;}static int snd_pcm_do_stop(struct snd_pcm_substream *substream, int state){	if (substream->runtime->trigger_master == substream &&	    snd_pcm_running(substream))		substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);	return 0; /* unconditonally stop all substreams */}static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	if (runtime->status->state != state) {		snd_pcm_trigger_tstamp(substream);		if (substream->timer)			snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP,					 &runtime->trigger_tstamp);		runtime->status->state = state;		snd_pcm_tick_set(substream, 0);	}	wake_up(&runtime->sleep);}static struct action_ops snd_pcm_action_stop = {	.pre_action = snd_pcm_pre_stop,	.do_action = snd_pcm_do_stop,	.post_action = snd_pcm_post_stop};/** * snd_pcm_stop * @substream: the PCM substream instance

⌨️ 快捷键说明

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