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

📄 pcm_native.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 * @state: PCM state after stopping the stream * * Try to stop all running streams in the substream group. * The state of each stream is changed to the given value after that unconditionally. */int snd_pcm_stop(struct snd_pcm_substream *substream, int state){	return snd_pcm_action(&snd_pcm_action_stop, substream, state);}EXPORT_SYMBOL(snd_pcm_stop);/** * snd_pcm_drain_done * @substream: the PCM substream * * Stop the DMA only when the given stream is playback. * The state is changed to SETUP. * Unlike snd_pcm_stop(), this affects only the given stream. */int snd_pcm_drain_done(struct snd_pcm_substream *substream){	return snd_pcm_action_single(&snd_pcm_action_stop, substream,				     SNDRV_PCM_STATE_SETUP);}/* * pause callbacks */static int snd_pcm_pre_pause(struct snd_pcm_substream *substream, int push){	struct snd_pcm_runtime *runtime = substream->runtime;	if (!(runtime->info & SNDRV_PCM_INFO_PAUSE))		return -ENOSYS;	if (push) {		if (runtime->status->state != SNDRV_PCM_STATE_RUNNING)			return -EBADFD;	} else if (runtime->status->state != SNDRV_PCM_STATE_PAUSED)		return -EBADFD;	runtime->trigger_master = substream;	return 0;}static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push){	if (substream->runtime->trigger_master != substream)		return 0;	return substream->ops->trigger(substream,				       push ? SNDRV_PCM_TRIGGER_PAUSE_PUSH :					      SNDRV_PCM_TRIGGER_PAUSE_RELEASE);}static void snd_pcm_undo_pause(struct snd_pcm_substream *substream, int push){	if (substream->runtime->trigger_master == substream)		substream->ops->trigger(substream,					push ? SNDRV_PCM_TRIGGER_PAUSE_RELEASE :					SNDRV_PCM_TRIGGER_PAUSE_PUSH);}static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push){	struct snd_pcm_runtime *runtime = substream->runtime;	snd_pcm_trigger_tstamp(substream);	if (push) {		runtime->status->state = SNDRV_PCM_STATE_PAUSED;		if (substream->timer)			snd_timer_notify(substream->timer,					 SNDRV_TIMER_EVENT_MPAUSE,					 &runtime->trigger_tstamp);		snd_pcm_tick_set(substream, 0);		wake_up(&runtime->sleep);	} else {		runtime->status->state = SNDRV_PCM_STATE_RUNNING;		if (runtime->sleep_min)			snd_pcm_tick_prepare(substream);		if (substream->timer)			snd_timer_notify(substream->timer,					 SNDRV_TIMER_EVENT_MCONTINUE,					 &runtime->trigger_tstamp);	}}static struct action_ops snd_pcm_action_pause = {	.pre_action = snd_pcm_pre_pause,	.do_action = snd_pcm_do_pause,	.undo_action = snd_pcm_undo_pause,	.post_action = snd_pcm_post_pause};/* * Push/release the pause for all linked streams. */static int snd_pcm_pause(struct snd_pcm_substream *substream, int push){	return snd_pcm_action(&snd_pcm_action_pause, substream, push);}#ifdef CONFIG_PM/* suspend */static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)		return -EBUSY;	runtime->trigger_master = substream;	return 0;}static int snd_pcm_do_suspend(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	if (runtime->trigger_master != substream)		return 0;	if (! snd_pcm_running(substream))		return 0;	substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND);	return 0; /* suspend unconditionally */}static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	snd_pcm_trigger_tstamp(substream);	if (substream->timer)		snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND,				 &runtime->trigger_tstamp);	runtime->status->suspended_state = runtime->status->state;	runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;	snd_pcm_tick_set(substream, 0);	wake_up(&runtime->sleep);}static struct action_ops snd_pcm_action_suspend = {	.pre_action = snd_pcm_pre_suspend,	.do_action = snd_pcm_do_suspend,	.post_action = snd_pcm_post_suspend};/** * snd_pcm_suspend * @substream: the PCM substream * * Trigger SUSPEND to all linked streams. * After this call, all streams are changed to SUSPENDED state. */int snd_pcm_suspend(struct snd_pcm_substream *substream){	int err;	unsigned long flags;	if (! substream)		return 0;	snd_pcm_stream_lock_irqsave(substream, flags);	err = snd_pcm_action(&snd_pcm_action_suspend, substream, 0);	snd_pcm_stream_unlock_irqrestore(substream, flags);	return err;}EXPORT_SYMBOL(snd_pcm_suspend);/** * snd_pcm_suspend_all * @pcm: the PCM instance * * Trigger SUSPEND to all substreams in the given pcm. * After this call, all streams are changed to SUSPENDED state. */int snd_pcm_suspend_all(struct snd_pcm *pcm){	struct snd_pcm_substream *substream;	int stream, err = 0;	if (! pcm)		return 0;	for (stream = 0; stream < 2; stream++) {		for (substream = pcm->streams[stream].substream;		     substream; substream = substream->next) {			/* FIXME: the open/close code should lock this as well */			if (substream->runtime == NULL)				continue;			err = snd_pcm_suspend(substream);			if (err < 0 && err != -EBUSY)				return err;		}	}	return 0;}EXPORT_SYMBOL(snd_pcm_suspend_all);/* resume */static int snd_pcm_pre_resume(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	if (!(runtime->info & SNDRV_PCM_INFO_RESUME))		return -ENOSYS;	runtime->trigger_master = substream;	return 0;}static int snd_pcm_do_resume(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	if (runtime->trigger_master != substream)		return 0;	/* DMA not running previously? */	if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING &&	    (runtime->status->suspended_state != SNDRV_PCM_STATE_DRAINING ||	     substream->stream != SNDRV_PCM_STREAM_PLAYBACK))		return 0;	return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_RESUME);}static void snd_pcm_undo_resume(struct snd_pcm_substream *substream, int state){	if (substream->runtime->trigger_master == substream &&	    snd_pcm_running(substream))		substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND);}static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	snd_pcm_trigger_tstamp(substream);	if (substream->timer)		snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME,				 &runtime->trigger_tstamp);	runtime->status->state = runtime->status->suspended_state;	if (runtime->sleep_min)		snd_pcm_tick_prepare(substream);}static struct action_ops snd_pcm_action_resume = {	.pre_action = snd_pcm_pre_resume,	.do_action = snd_pcm_do_resume,	.undo_action = snd_pcm_undo_resume,	.post_action = snd_pcm_post_resume};static int snd_pcm_resume(struct snd_pcm_substream *substream){	struct snd_card *card = substream->pcm->card;	int res;	snd_power_lock(card);	if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)		res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0);	snd_power_unlock(card);	return res;}#elsestatic int snd_pcm_resume(struct snd_pcm_substream *substream){	return -ENOSYS;}#endif /* CONFIG_PM *//* * xrun ioctl * * Change the RUNNING stream(s) to XRUN state. */static int snd_pcm_xrun(struct snd_pcm_substream *substream){	struct snd_card *card = substream->pcm->card;	struct snd_pcm_runtime *runtime = substream->runtime;	int result;	snd_power_lock(card);	if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {		result = snd_power_wait(card, SNDRV_CTL_POWER_D0);		if (result < 0)			goto _unlock;	}	snd_pcm_stream_lock_irq(substream);	switch (runtime->status->state) {	case SNDRV_PCM_STATE_XRUN:		result = 0;	/* already there */		break;	case SNDRV_PCM_STATE_RUNNING:		result = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);		break;	default:		result = -EBADFD;	}	snd_pcm_stream_unlock_irq(substream); _unlock:	snd_power_unlock(card);	return result;}/* * reset ioctl */static int snd_pcm_pre_reset(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	switch (runtime->status->state) {	case SNDRV_PCM_STATE_RUNNING:	case SNDRV_PCM_STATE_PREPARED:	case SNDRV_PCM_STATE_PAUSED:	case SNDRV_PCM_STATE_SUSPENDED:		return 0;	default:		return -EBADFD;	}}static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);	if (err < 0)		return err;	// snd_assert(runtime->status->hw_ptr < runtime->buffer_size, );	runtime->hw_ptr_base = 0;	runtime->hw_ptr_interrupt = runtime->status->hw_ptr -		runtime->status->hw_ptr % runtime->period_size;	runtime->silence_start = runtime->status->hw_ptr;	runtime->silence_filled = 0;	return 0;}static void snd_pcm_post_reset(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	runtime->control->appl_ptr = runtime->status->hw_ptr;	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&	    runtime->silence_size > 0)		snd_pcm_playback_silence(substream, ULONG_MAX);}static struct action_ops snd_pcm_action_reset = {	.pre_action = snd_pcm_pre_reset,	.do_action = snd_pcm_do_reset,	.post_action = snd_pcm_post_reset};static int snd_pcm_reset(struct snd_pcm_substream *substream){	return snd_pcm_action_nonatomic(&snd_pcm_action_reset, substream, 0);}/* * prepare ioctl *//* we use the second argument for updating f_flags */static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream,			       int f_flags){	struct snd_pcm_runtime *runtime = substream->runtime;	if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||	    runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)		return -EBADFD;	if (snd_pcm_running(substream))		return -EBUSY;	substream->f_flags = f_flags;	return 0;}static int snd_pcm_do_prepare(struct snd_pcm_substream *substream, int state){	int err;	err = substream->ops->prepare(substream);	if (err < 0)		return err;	return snd_pcm_do_reset(substream, 0);}static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	runtime->control->appl_ptr = runtime->status->hw_ptr;	runtime->status->state = SNDRV_PCM_STATE_PREPARED;}static struct action_ops snd_pcm_action_prepare = {	.pre_action = snd_pcm_pre_prepare,	.do_action = snd_pcm_do_prepare,	.post_action = snd_pcm_post_prepare};/** * snd_pcm_prepare * @substream: the PCM substream instance * @file: file to refer f_flags * * Prepare the PCM substream to be triggerable. */static int snd_pcm_prepare(struct snd_pcm_substream *substream,			   struct file *file){	int res;	struct snd_card *card = substream->pcm->card;	int f_flags;	if (file)		f_flags = file->f_flags;	else		f_flags = substream->f_flags;	snd_power_lock(card);	if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)		res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare,					       substream, f_flags);	snd_power_unlock(card);	return res;}/* * drain ioctl */static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state){	if (substream->f_flags & O_NONBLOCK)		return -EAGAIN;	substream->runtime->trigger_master = substream;	return 0;}static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state){	struct snd_pcm_runtime *runtime = substream->runtime;	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {		switch (runtime->status->state) {		case SNDRV_PCM_STATE_PREPARED:			/* start playback stream if possible */			if (! snd_pcm_playback_empty(substream)) {				snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING);				snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING);			}			break;		case SNDRV_PCM_STATE_RUNNING:			runtime->status->state = SNDRV_PCM_STATE_DRAINING;			break;		default:			break;		}	} else {		/* stop running stream */		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) {			int state = snd_pcm_capture_avail(runtime) > 0 ?				SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP;			snd_pcm_do_stop(substream, state);			snd_pcm_post_stop(substream, state);		}	}	return 0;}static void snd_pcm_post_drain_init(struct snd_pcm_substream *substream, int state){}static struct action_ops snd_pcm_action_drain_init = {	.pre_action = snd_pcm_pre_drain_init,	.do_action = snd_pcm_do_drain_init,	.post_action = snd_pcm_post_drain_init};struct drain_rec {	struct snd_pcm_substream *substream;	wait_queue_t wait;

⌨️ 快捷键说明

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