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: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
7d8e829201
commit
67616feda9
@ -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:
|
||||
|
@ -2761,14 +2761,103 @@ static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg)
|
||||
runtime->tstamp_type = 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,173 +2933,23 @@ static int snd_pcm_common_ioctl1(struct file *file,
|
||||
return snd_pcm_action_lock_irq(&snd_pcm_action_pause,
|
||||
substream,
|
||||
(int)(unsigned long)arg);
|
||||
case SNDRV_PCM_IOCTL_WRITEI_FRAMES:
|
||||
case SNDRV_PCM_IOCTL_READI_FRAMES:
|
||||
return snd_pcm_xferi_frames_ioctl(substream, arg);
|
||||
case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
|
||||
case SNDRV_PCM_IOCTL_READN_FRAMES:
|
||||
return snd_pcm_xfern_frames_ioctl(substream, arg);
|
||||
case SNDRV_PCM_IOCTL_REWIND:
|
||||
return snd_pcm_rewind_ioctl(substream, arg);
|
||||
case SNDRV_PCM_IOCTL_FORWARD:
|
||||
return snd_pcm_forward_ioctl(substream, 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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_common_ioctl1(file, substream, cmd, arg);
|
||||
}
|
||||
|
||||
static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
static long snd_pcm_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct snd_pcm_file *pcm_file;
|
||||
|
||||
@ -3019,22 +2958,8 @@ static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd,
|
||||
if (((cmd >> 8) & 0xff) != 'A')
|
||||
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,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct snd_pcm_file *pcm_file;
|
||||
|
||||
pcm_file = file->private_data;
|
||||
|
||||
if (((cmd >> 8) & 0xff) != 'A')
|
||||
return -ENOTTY;
|
||||
|
||||
return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd,
|
||||
(void __user *)arg);
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user