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_XRUN:
|
||||||
case SNDRV_PCM_IOCTL_LINK:
|
case SNDRV_PCM_IOCTL_LINK:
|
||||||
case SNDRV_PCM_IOCTL_UNLINK:
|
case SNDRV_PCM_IOCTL_UNLINK:
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
return snd_pcm_common_ioctl(file, substream, cmd, argp);
|
||||||
return snd_pcm_playback_ioctl1(file, substream, cmd, argp);
|
|
||||||
else
|
|
||||||
return snd_pcm_capture_ioctl1(file, substream, cmd, argp);
|
|
||||||
case SNDRV_PCM_IOCTL_HW_REFINE32:
|
case SNDRV_PCM_IOCTL_HW_REFINE32:
|
||||||
return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
|
return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
|
||||||
case SNDRV_PCM_IOCTL_HW_PARAMS32:
|
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;
|
runtime->tstamp_type = arg;
|
||||||
return 0;
|
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,
|
struct snd_pcm_substream *substream,
|
||||||
unsigned int cmd, void __user *arg)
|
unsigned int cmd, void __user *arg)
|
||||||
{
|
{
|
||||||
struct snd_pcm_file *pcm_file = file->private_data;
|
struct snd_pcm_file *pcm_file = file->private_data;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
if (PCM_RUNTIME_CHECK(substream))
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
res = snd_power_wait(substream->pcm->card, SNDRV_CTL_POWER_D0);
|
res = snd_power_wait(substream->pcm->card, SNDRV_CTL_POWER_D0);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
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,
|
return snd_pcm_action_lock_irq(&snd_pcm_action_pause,
|
||||||
substream,
|
substream,
|
||||||
(int)(unsigned long)arg);
|
(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);
|
pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd);
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_pcm_playback_ioctl1(struct file *file,
|
static long snd_pcm_ioctl(struct file *file, unsigned int cmd,
|
||||||
struct snd_pcm_substream *substream,
|
unsigned long arg)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
struct snd_pcm_file *pcm_file;
|
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')
|
if (((cmd >> 8) & 0xff) != 'A')
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
|
|
||||||
return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd,
|
return snd_pcm_common_ioctl(file, pcm_file->substream, cmd,
|
||||||
(void __user *)arg);
|
(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3775,7 +3700,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
|
||||||
.release = snd_pcm_release,
|
.release = snd_pcm_release,
|
||||||
.llseek = no_llseek,
|
.llseek = no_llseek,
|
||||||
.poll = snd_pcm_playback_poll,
|
.poll = snd_pcm_playback_poll,
|
||||||
.unlocked_ioctl = snd_pcm_playback_ioctl,
|
.unlocked_ioctl = snd_pcm_ioctl,
|
||||||
.compat_ioctl = snd_pcm_ioctl_compat,
|
.compat_ioctl = snd_pcm_ioctl_compat,
|
||||||
.mmap = snd_pcm_mmap,
|
.mmap = snd_pcm_mmap,
|
||||||
.fasync = snd_pcm_fasync,
|
.fasync = snd_pcm_fasync,
|
||||||
|
@ -3789,7 +3714,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
|
||||||
.release = snd_pcm_release,
|
.release = snd_pcm_release,
|
||||||
.llseek = no_llseek,
|
.llseek = no_llseek,
|
||||||
.poll = snd_pcm_capture_poll,
|
.poll = snd_pcm_capture_poll,
|
||||||
.unlocked_ioctl = snd_pcm_capture_ioctl,
|
.unlocked_ioctl = snd_pcm_ioctl,
|
||||||
.compat_ioctl = snd_pcm_ioctl_compat,
|
.compat_ioctl = snd_pcm_ioctl_compat,
|
||||||
.mmap = snd_pcm_mmap,
|
.mmap = snd_pcm_mmap,
|
||||||
.fasync = snd_pcm_fasync,
|
.fasync = snd_pcm_fasync,
|
||||||
|
|
Loading…
Reference in New Issue