Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c0d19a7 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'topic/pcm-drain-nonblock' into for-linus

* topic/pcm-drain-nonblock:
  ALSA: pcm - Increase protocol version
  ALSA: pcm - Fix drain behavior in non-blocking mode
parents 05a33e3d 5a53a764
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -138,7 +138,7 @@ struct snd_hwdep_dsp_image {
 *                                                                           *
 *****************************************************************************/

#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 9)
#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 10)

typedef unsigned long snd_pcm_uframes_t;
typedef signed long snd_pcm_sframes_t;
+8 −4
Original line number Diff line number Diff line
@@ -197,13 +197,17 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
		avail = snd_pcm_capture_avail(runtime);
	if (avail > runtime->avail_max)
		runtime->avail_max = avail;
	if (avail >= runtime->stop_threshold) {
		if (substream->runtime->status->state == SNDRV_PCM_STATE_DRAINING)
	if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
		if (avail >= runtime->buffer_size) {
			snd_pcm_drain_done(substream);
		else
			return -EPIPE;
		}
	} else {
		if (avail >= runtime->stop_threshold) {
			xrun(substream);
			return -EPIPE;
		}
	}
	if (avail >= runtime->control->avail_min)
		wake_up(&runtime->sleep);
	return 0;
+29 −23
Original line number Diff line number Diff line
@@ -1343,8 +1343,6 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,

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;
}
@@ -1392,7 +1390,6 @@ static struct action_ops snd_pcm_action_drain_init = {
struct drain_rec {
	struct snd_pcm_substream *substream;
	wait_queue_t wait;
	snd_pcm_uframes_t stop_threshold;
};

static int snd_pcm_drop(struct snd_pcm_substream *substream);
@@ -1404,13 +1401,15 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream);
 * After this call, all streams are supposed to be either SETUP or DRAINING
 * (capture only) state.
 */
static int snd_pcm_drain(struct snd_pcm_substream *substream)
static int snd_pcm_drain(struct snd_pcm_substream *substream,
			 struct file *file)
{
	struct snd_card *card;
	struct snd_pcm_runtime *runtime;
	struct snd_pcm_substream *s;
	int result = 0;
	int i, num_drecs;
	int nonblock = 0;
	struct drain_rec *drec, drec_tmp, *d;

	card = substream->pcm->card;
@@ -1428,6 +1427,15 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
		}
	}

	if (file) {
		if (file->f_flags & O_NONBLOCK)
			nonblock = 1;
	} else if (substream->f_flags & O_NONBLOCK)
		nonblock = 1;

	if (nonblock)
		goto lock; /* no need to allocate waitqueues */

	/* allocate temporary record for drain sync */
	down_read(&snd_pcm_link_rwsem);
	if (snd_pcm_stream_linked(substream)) {
@@ -1449,16 +1457,11 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
			d->substream = s;
			init_waitqueue_entry(&d->wait, current);
			add_wait_queue(&runtime->sleep, &d->wait);
			/* stop_threshold fixup to avoid endless loop when
			 * stop_threshold > buffer_size
			 */
			d->stop_threshold = runtime->stop_threshold;
			if (runtime->stop_threshold > runtime->buffer_size)
				runtime->stop_threshold = runtime->buffer_size;
		}
	}
	up_read(&snd_pcm_link_rwsem);

 lock:
	snd_pcm_stream_lock_irq(substream);
	/* resume pause */
	if (substream->runtime->status->state == SNDRV_PCM_STATE_PAUSED)
@@ -1466,9 +1469,12 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)

	/* pre-start/stop - all running streams are changed to DRAINING state */
	result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0);
	if (result < 0) {
		snd_pcm_stream_unlock_irq(substream);
		goto _error;
	if (result < 0)
		goto unlock;
	/* in non-blocking, we don't wait in ioctl but let caller poll */
	if (nonblock) {
		result = -EAGAIN;
		goto unlock;
	}

	for (;;) {
@@ -1504,18 +1510,18 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
		}
	}

 unlock:
	snd_pcm_stream_unlock_irq(substream);

 _error:
	if (!nonblock) {
		for (i = 0; i < num_drecs; i++) {
			d = &drec[i];
			runtime = d->substream->runtime;
			remove_wait_queue(&runtime->sleep, &d->wait);
		runtime->stop_threshold = d->stop_threshold;
		}

		if (drec != &drec_tmp)
			kfree(drec);
	}
	snd_power_unlock(card);

	return result;
@@ -2544,7 +2550,7 @@ static int snd_pcm_common_ioctl1(struct file *file,
		return snd_pcm_hw_params_old_user(substream, arg);
#endif
	case SNDRV_PCM_IOCTL_DRAIN:
		return snd_pcm_drain(substream);
		return snd_pcm_drain(substream, file);
	case SNDRV_PCM_IOCTL_DROP:
		return snd_pcm_drop(substream);
	case SNDRV_PCM_IOCTL_PAUSE: