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

Commit 67616fed authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: pcm: Unify ioctl functions for playback and capture streams



Some ioctl functions are implemented individually for both playback
and capture streams although most of the codes are identical with just
a few different stream-specific function calls.  This patch unifies
these places, removes the superfluous trivial check and flattens the
call paths as a cleanup.  Meanwhile, for better readability, some
codes (e.g. xfer ioctls or forward/rewind ioctls) are factored out as
functions.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 7d8e8292
Loading
Loading
Loading
Loading
+1 −4
Original line number Diff line number Diff line
@@ -689,10 +689,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
	case SNDRV_PCM_IOCTL_XRUN:
	case SNDRV_PCM_IOCTL_LINK:
	case SNDRV_PCM_IOCTL_UNLINK:
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
			return snd_pcm_playback_ioctl1(file, substream, cmd, argp);
		else
			return snd_pcm_capture_ioctl1(file, substream, cmd, argp);
		return snd_pcm_common_ioctl(file, substream, cmd, argp);
	case SNDRV_PCM_IOCTL_HW_REFINE32:
		return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
	case SNDRV_PCM_IOCTL_HW_PARAMS32:
+104 −179
Original line number Diff line number Diff line
@@ -2762,13 +2762,102 @@ static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg)
	return 0;
}

static int snd_pcm_common_ioctl1(struct file *file,
static int snd_pcm_xferi_frames_ioctl(struct snd_pcm_substream *substream,
				      struct snd_xferi __user *_xferi)
{
	struct snd_xferi xferi;
	struct snd_pcm_runtime *runtime = substream->runtime;
	snd_pcm_sframes_t result;

	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;
	if (put_user(0, &_xferi->result))
		return -EFAULT;
	if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
		return -EFAULT;
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames);
	else
		result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames);
	__put_user(result, &_xferi->result);
	return result < 0 ? result : 0;
}

static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
				      struct snd_xfern __user *_xfern)
{
	struct snd_xfern xfern;
	struct snd_pcm_runtime *runtime = substream->runtime;
	void *bufs;
	snd_pcm_sframes_t result;

	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;
	if (runtime->channels > 128)
		return -EINVAL;
	if (put_user(0, &_xfern->result))
		return -EFAULT;
	if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
		return -EFAULT;

	bufs = memdup_user(xfern.bufs, sizeof(void *) * runtime->channels);
	if (IS_ERR(bufs))
		return PTR_ERR(bufs);
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
	else
		result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
	kfree(bufs);
	__put_user(result, &_xfern->result);
	return result < 0 ? result : 0;
}

static int snd_pcm_rewind_ioctl(struct snd_pcm_substream *substream,
				snd_pcm_uframes_t __user *_frames)
{
	snd_pcm_uframes_t frames;
	snd_pcm_sframes_t result;

	if (get_user(frames, _frames))
		return -EFAULT;
	if (put_user(0, _frames))
		return -EFAULT;
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		result = snd_pcm_playback_rewind(substream, frames);
	else
		result = snd_pcm_capture_rewind(substream, frames);
	__put_user(result, _frames);
	return result < 0 ? result : 0;
}

static int snd_pcm_forward_ioctl(struct snd_pcm_substream *substream,
				 snd_pcm_uframes_t __user *_frames)
{
	snd_pcm_uframes_t frames;
	snd_pcm_sframes_t result;

	if (get_user(frames, _frames))
		return -EFAULT;
	if (put_user(0, _frames))
		return -EFAULT;
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		result = snd_pcm_playback_forward(substream, frames);
	else
		result = snd_pcm_capture_forward(substream, frames);
	__put_user(result, _frames);
	return result < 0 ? result : 0;
}

static int snd_pcm_common_ioctl(struct file *file,
				 struct snd_pcm_substream *substream,
				 unsigned int cmd, void __user *arg)
{
	struct snd_pcm_file *pcm_file = file->private_data;
	int res;

	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;

	res = snd_power_wait(substream->pcm->card, SNDRV_CTL_POWER_D0);
	if (res < 0)
		return res;
@@ -2844,186 +2933,22 @@ static int snd_pcm_common_ioctl1(struct file *file,
		return snd_pcm_action_lock_irq(&snd_pcm_action_pause,
					       substream,
					       (int)(unsigned long)arg);
	}
	pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd);
	return -ENOTTY;
}

static int snd_pcm_playback_ioctl1(struct file *file,
				   struct snd_pcm_substream *substream,
				   unsigned int cmd, void __user *arg)
{
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
	if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK))
		return -EINVAL;
	switch (cmd) {
	case SNDRV_PCM_IOCTL_WRITEI_FRAMES:
	{
		struct snd_xferi xferi;
		struct snd_xferi __user *_xferi = arg;
		struct snd_pcm_runtime *runtime = substream->runtime;
		snd_pcm_sframes_t result;
		if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
			return -EBADFD;
		if (put_user(0, &_xferi->result))
			return -EFAULT;
		if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
			return -EFAULT;
		result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames);
		__put_user(result, &_xferi->result);
		return result < 0 ? result : 0;
	}
	case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
	{
		struct snd_xfern xfern;
		struct snd_xfern __user *_xfern = arg;
		struct snd_pcm_runtime *runtime = substream->runtime;
		void __user **bufs;
		snd_pcm_sframes_t result;
		if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
			return -EBADFD;
		if (runtime->channels > 128)
			return -EINVAL;
		if (put_user(0, &_xfern->result))
			return -EFAULT;
		if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
			return -EFAULT;

		bufs = memdup_user(xfern.bufs,
				   sizeof(void *) * runtime->channels);
		if (IS_ERR(bufs))
			return PTR_ERR(bufs);
		result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
		kfree(bufs);
		__put_user(result, &_xfern->result);
		return result < 0 ? result : 0;
	}
	case SNDRV_PCM_IOCTL_REWIND:
	{
		snd_pcm_uframes_t frames;
		snd_pcm_uframes_t __user *_frames = arg;
		snd_pcm_sframes_t result;
		if (get_user(frames, _frames))
			return -EFAULT;
		if (put_user(0, _frames))
			return -EFAULT;
		result = snd_pcm_playback_rewind(substream, frames);
		__put_user(result, _frames);
		return result < 0 ? result : 0;
	}
	case SNDRV_PCM_IOCTL_FORWARD:
	{
		snd_pcm_uframes_t frames;
		snd_pcm_uframes_t __user *_frames = arg;
		snd_pcm_sframes_t result;
		if (get_user(frames, _frames))
			return -EFAULT;
		if (put_user(0, _frames))
			return -EFAULT;
		result = snd_pcm_playback_forward(substream, frames);
		__put_user(result, _frames);
		return result < 0 ? result : 0;
	}
	}
	return snd_pcm_common_ioctl1(file, substream, cmd, arg);
}

static int snd_pcm_capture_ioctl1(struct file *file,
				  struct snd_pcm_substream *substream,
				  unsigned int cmd, void __user *arg)
{
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
	if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE))
		return -EINVAL;
	switch (cmd) {
	case SNDRV_PCM_IOCTL_READI_FRAMES:
	{
		struct snd_xferi xferi;
		struct snd_xferi __user *_xferi = arg;
		struct snd_pcm_runtime *runtime = substream->runtime;
		snd_pcm_sframes_t result;
		if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
			return -EBADFD;
		if (put_user(0, &_xferi->result))
			return -EFAULT;
		if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
			return -EFAULT;
		result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames);
		__put_user(result, &_xferi->result);
		return result < 0 ? result : 0;
	}
		return snd_pcm_xferi_frames_ioctl(substream, arg);
	case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
	case SNDRV_PCM_IOCTL_READN_FRAMES:
	{
		struct snd_xfern xfern;
		struct snd_xfern __user *_xfern = arg;
		struct snd_pcm_runtime *runtime = substream->runtime;
		void *bufs;
		snd_pcm_sframes_t result;
		if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
			return -EBADFD;
		if (runtime->channels > 128)
			return -EINVAL;
		if (put_user(0, &_xfern->result))
			return -EFAULT;
		if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
			return -EFAULT;

		bufs = memdup_user(xfern.bufs,
				   sizeof(void *) * runtime->channels);
		if (IS_ERR(bufs))
			return PTR_ERR(bufs);
		result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
		kfree(bufs);
		__put_user(result, &_xfern->result);
		return result < 0 ? result : 0;
	}
		return snd_pcm_xfern_frames_ioctl(substream, arg);
	case SNDRV_PCM_IOCTL_REWIND:
	{
		snd_pcm_uframes_t frames;
		snd_pcm_uframes_t __user *_frames = arg;
		snd_pcm_sframes_t result;
		if (get_user(frames, _frames))
			return -EFAULT;
		if (put_user(0, _frames))
			return -EFAULT;
		result = snd_pcm_capture_rewind(substream, frames);
		__put_user(result, _frames);
		return result < 0 ? result : 0;
	}
		return snd_pcm_rewind_ioctl(substream, arg);
	case SNDRV_PCM_IOCTL_FORWARD:
	{
		snd_pcm_uframes_t frames;
		snd_pcm_uframes_t __user *_frames = arg;
		snd_pcm_sframes_t result;
		if (get_user(frames, _frames))
			return -EFAULT;
		if (put_user(0, _frames))
			return -EFAULT;
		result = snd_pcm_capture_forward(substream, frames);
		__put_user(result, _frames);
		return result < 0 ? result : 0;
	}
		return snd_pcm_forward_ioctl(substream, arg);
	}
	return snd_pcm_common_ioctl1(file, substream, cmd, arg);
}

static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd,
				   unsigned long arg)
{
	struct snd_pcm_file *pcm_file;

	pcm_file = file->private_data;

	if (((cmd >> 8) & 0xff) != 'A')
	pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd);
	return -ENOTTY;

	return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd,
				       (void __user *)arg);
}

static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
static long snd_pcm_ioctl(struct file *file, unsigned int cmd,
			  unsigned long arg)
{
	struct snd_pcm_file *pcm_file;
@@ -3033,7 +2958,7 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
	if (((cmd >> 8) & 0xff) != 'A')
		return -ENOTTY;

	return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd,
	return snd_pcm_common_ioctl(file, pcm_file->substream, cmd,
				     (void __user *)arg);
}

@@ -3775,7 +3700,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
		.release =		snd_pcm_release,
		.llseek =		no_llseek,
		.poll =			snd_pcm_playback_poll,
		.unlocked_ioctl =	snd_pcm_playback_ioctl,
		.unlocked_ioctl =	snd_pcm_ioctl,
		.compat_ioctl = 	snd_pcm_ioctl_compat,
		.mmap =			snd_pcm_mmap,
		.fasync =		snd_pcm_fasync,
@@ -3789,7 +3714,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
		.release =		snd_pcm_release,
		.llseek =		no_llseek,
		.poll =			snd_pcm_capture_poll,
		.unlocked_ioctl =	snd_pcm_capture_ioctl,
		.unlocked_ioctl =	snd_pcm_ioctl,
		.compat_ioctl = 	snd_pcm_ioctl_compat,
		.mmap =			snd_pcm_mmap,
		.fasync =		snd_pcm_fasync,