Commit 90efff42 authored by Jaroslav Kysela's avatar Jaroslav Kysela

[ALSA] unlocked/compat_ioctl rewrite for hwdep, rawmidi, timer and sequencer API

HWDEP Midlevel,RawMidi Midlevel,Timer Midlevel,ALSA sequencer
The ioctl handler for hwdep, rawmidi, timer and sequencer API are rewritten
using unlocked/compat_ioctl.
The 32bit wrapper is merged to the core module.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 575b149c
...@@ -38,6 +38,7 @@ typedef struct _snd_hwdep_ops { ...@@ -38,6 +38,7 @@ typedef struct _snd_hwdep_ops {
int (*release) (snd_hwdep_t * hw, struct file * file); int (*release) (snd_hwdep_t * hw, struct file * file);
unsigned int (*poll) (snd_hwdep_t * hw, struct file * file, poll_table * wait); unsigned int (*poll) (snd_hwdep_t * hw, struct file * file, poll_table * wait);
int (*ioctl) (snd_hwdep_t * hw, struct file * file, unsigned int cmd, unsigned long arg); int (*ioctl) (snd_hwdep_t * hw, struct file * file, unsigned int cmd, unsigned long arg);
int (*ioctl_compat) (snd_hwdep_t * hw, struct file * file, unsigned int cmd, unsigned long arg);
int (*mmap) (snd_hwdep_t * hw, struct file * file, struct vm_area_struct * vma); int (*mmap) (snd_hwdep_t * hw, struct file * file, struct vm_area_struct * vma);
int (*dsp_status) (snd_hwdep_t * hw, snd_hwdep_dsp_status_t * status); int (*dsp_status) (snd_hwdep_t * hw, snd_hwdep_dsp_status_t * status);
int (*dsp_load) (snd_hwdep_t * hw, snd_hwdep_dsp_image_t * image); int (*dsp_load) (snd_hwdep_t * hw, snd_hwdep_dsp_image_t * image);
......
...@@ -232,8 +232,7 @@ static int snd_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t __user *_in ...@@ -232,8 +232,7 @@ static int snd_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t __user *_in
return 0; return 0;
} }
static inline int _snd_hwdep_ioctl(struct inode *inode, struct file * file, static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
unsigned int cmd, unsigned long arg)
{ {
snd_hwdep_t *hw = file->private_data; snd_hwdep_t *hw = file->private_data;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
...@@ -252,17 +251,6 @@ static inline int _snd_hwdep_ioctl(struct inode *inode, struct file * file, ...@@ -252,17 +251,6 @@ static inline int _snd_hwdep_ioctl(struct inode *inode, struct file * file,
return -ENOTTY; return -ENOTTY;
} }
/* FIXME: need to unlock BKL to allow preemption */
static int snd_hwdep_ioctl(struct inode *inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
int err;
unlock_kernel();
err = _snd_hwdep_ioctl(inode, file, cmd, arg);
lock_kernel();
return err;
}
static int snd_hwdep_mmap(struct file * file, struct vm_area_struct * vma) static int snd_hwdep_mmap(struct file * file, struct vm_area_struct * vma)
{ {
snd_hwdep_t *hw = file->private_data; snd_hwdep_t *hw = file->private_data;
...@@ -315,6 +303,12 @@ static int snd_hwdep_control_ioctl(snd_card_t * card, snd_ctl_file_t * control, ...@@ -315,6 +303,12 @@ static int snd_hwdep_control_ioctl(snd_card_t * card, snd_ctl_file_t * control,
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
#ifdef CONFIG_COMPAT
#include "hwdep_compat.c"
#else
#define snd_hwdep_ioctl_compat NULL
#endif
/* /*
*/ */
...@@ -328,7 +322,8 @@ static struct file_operations snd_hwdep_f_ops = ...@@ -328,7 +322,8 @@ static struct file_operations snd_hwdep_f_ops =
.open = snd_hwdep_open, .open = snd_hwdep_open,
.release = snd_hwdep_release, .release = snd_hwdep_release,
.poll = snd_hwdep_poll, .poll = snd_hwdep_poll,
.ioctl = snd_hwdep_ioctl, .unlocked_ioctl = snd_hwdep_ioctl,
.compat_ioctl = snd_hwdep_ioctl_compat,
.mmap = snd_hwdep_mmap, .mmap = snd_hwdep_mmap,
}; };
...@@ -509,12 +504,14 @@ static int __init alsa_hwdep_init(void) ...@@ -509,12 +504,14 @@ static int __init alsa_hwdep_init(void)
} }
snd_hwdep_proc_entry = entry; snd_hwdep_proc_entry = entry;
snd_ctl_register_ioctl(snd_hwdep_control_ioctl); snd_ctl_register_ioctl(snd_hwdep_control_ioctl);
snd_ctl_register_ioctl_compat(snd_hwdep_control_ioctl);
return 0; return 0;
} }
static void __exit alsa_hwdep_exit(void) static void __exit alsa_hwdep_exit(void)
{ {
snd_ctl_unregister_ioctl(snd_hwdep_control_ioctl); snd_ctl_unregister_ioctl(snd_hwdep_control_ioctl);
snd_ctl_unregister_ioctl_compat(snd_hwdep_control_ioctl);
if (snd_hwdep_proc_entry) { if (snd_hwdep_proc_entry) {
snd_info_unregister(snd_hwdep_proc_entry); snd_info_unregister(snd_hwdep_proc_entry);
snd_hwdep_proc_entry = NULL; snd_hwdep_proc_entry = NULL;
......
/*
* 32bit -> 64bit ioctl wrapper for hwdep API
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* This file is included from hwdep.c */
#include <linux/compat.h>
struct sndrv_hwdep_dsp_image32 {
u32 index;
unsigned char name[64];
u32 image; /* pointer */
u32 length;
u32 driver_data;
} /* don't set packed attribute here */;
static int snd_hwdep_dsp_load_compat(snd_hwdep_t *hw,
struct sndrv_hwdep_dsp_image32 __user *src)
{
struct sndrv_hwdep_dsp_image *dst;
compat_caddr_t ptr;
u32 val;
dst = compat_alloc_user_space(sizeof(*dst));
/* index and name */
if (copy_in_user(dst, src, 4 + 64))
return -EFAULT;
if (get_user(ptr, &src->image) ||
put_user(compat_ptr(ptr), &dst->image))
return -EFAULT;
if (get_user(val, &src->length) ||
put_user(val, &dst->length))
return -EFAULT;
if (get_user(val, &src->driver_data) ||
put_user(val, &dst->driver_data))
return -EFAULT;
return snd_hwdep_dsp_load(hw, dst);
}
enum {
SNDRV_HWDEP_IOCTL_DSP_LOAD32 = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image32)
};
static long snd_hwdep_ioctl_compat(struct file * file, unsigned int cmd, unsigned long arg)
{
snd_hwdep_t *hw = file->private_data;
void __user *argp = compat_ptr(arg);
switch (cmd) {
case SNDRV_HWDEP_IOCTL_PVERSION:
case SNDRV_HWDEP_IOCTL_INFO:
case SNDRV_HWDEP_IOCTL_DSP_STATUS:
return snd_hwdep_ioctl(file, cmd, (unsigned long)argp);
case SNDRV_HWDEP_IOCTL_DSP_LOAD32:
return snd_hwdep_dsp_load_compat(hw, argp);
}
if (hw->ops.ioctl_compat)
return hw->ops.ioctl_compat(hw, file, cmd, arg);
return -ENOIOCTLCMD;
}
...@@ -673,8 +673,7 @@ static int snd_rawmidi_input_status(snd_rawmidi_substream_t * substream, ...@@ -673,8 +673,7 @@ static int snd_rawmidi_input_status(snd_rawmidi_substream_t * substream,
return 0; return 0;
} }
static inline int _snd_rawmidi_ioctl(struct inode *inode, struct file *file, static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned int cmd, unsigned long arg)
{ {
snd_rawmidi_file_t *rfile; snd_rawmidi_file_t *rfile;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
...@@ -784,17 +783,6 @@ static inline int _snd_rawmidi_ioctl(struct inode *inode, struct file *file, ...@@ -784,17 +783,6 @@ static inline int _snd_rawmidi_ioctl(struct inode *inode, struct file *file,
return -ENOTTY; return -ENOTTY;
} }
/* FIXME: need to unlock BKL to allow preemption */
static int snd_rawmidi_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int err;
unlock_kernel();
err = _snd_rawmidi_ioctl(inode, file, cmd, arg);
lock_kernel();
return err;
}
static int snd_rawmidi_control_ioctl(snd_card_t * card, static int snd_rawmidi_control_ioctl(snd_card_t * card,
snd_ctl_file_t * control, snd_ctl_file_t * control,
unsigned int cmd, unsigned int cmd,
...@@ -1277,6 +1265,14 @@ static unsigned int snd_rawmidi_poll(struct file *file, poll_table * wait) ...@@ -1277,6 +1265,14 @@ static unsigned int snd_rawmidi_poll(struct file *file, poll_table * wait)
return mask; return mask;
} }
/*
*/
#ifdef CONFIG_COMPAT
#include "rawmidi_compat.c"
#else
#define snd_rawmidi_ioctl_compat NULL
#endif
/* /*
*/ */
...@@ -1347,7 +1343,8 @@ static struct file_operations snd_rawmidi_f_ops = ...@@ -1347,7 +1343,8 @@ static struct file_operations snd_rawmidi_f_ops =
.open = snd_rawmidi_open, .open = snd_rawmidi_open,
.release = snd_rawmidi_release, .release = snd_rawmidi_release,
.poll = snd_rawmidi_poll, .poll = snd_rawmidi_poll,
.ioctl = snd_rawmidi_ioctl, .unlocked_ioctl = snd_rawmidi_ioctl,
.compat_ioctl = snd_rawmidi_ioctl_compat,
}; };
static snd_minor_t snd_rawmidi_reg = static snd_minor_t snd_rawmidi_reg =
...@@ -1628,6 +1625,7 @@ static int __init alsa_rawmidi_init(void) ...@@ -1628,6 +1625,7 @@ static int __init alsa_rawmidi_init(void)
{ {
snd_ctl_register_ioctl(snd_rawmidi_control_ioctl); snd_ctl_register_ioctl(snd_rawmidi_control_ioctl);
snd_ctl_register_ioctl_compat(snd_rawmidi_control_ioctl);
#ifdef CONFIG_SND_OSSEMUL #ifdef CONFIG_SND_OSSEMUL
{ int i; { int i;
/* check device map table */ /* check device map table */
...@@ -1649,6 +1647,7 @@ static int __init alsa_rawmidi_init(void) ...@@ -1649,6 +1647,7 @@ static int __init alsa_rawmidi_init(void)
static void __exit alsa_rawmidi_exit(void) static void __exit alsa_rawmidi_exit(void)
{ {
snd_ctl_unregister_ioctl(snd_rawmidi_control_ioctl); snd_ctl_unregister_ioctl(snd_rawmidi_control_ioctl);
snd_ctl_unregister_ioctl_compat(snd_rawmidi_control_ioctl);
} }
module_init(alsa_rawmidi_init) module_init(alsa_rawmidi_init)
......
/*
* 32bit -> 64bit ioctl wrapper for raw MIDI API
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* This file included from rawmidi.c */
#include <linux/compat.h>
struct sndrv_rawmidi_params32 {
s32 stream;
u32 buffer_size;
u32 avail_min;
unsigned int no_active_sensing; /* avoid bit-field */
unsigned char reserved[16];
} __attribute__((packed));
static int snd_rawmidi_ioctl_params_compat(snd_rawmidi_file_t *rfile,
struct sndrv_rawmidi_params32 __user *src)
{
snd_rawmidi_params_t params;
unsigned int val;
if (rfile->output == NULL)
return -EINVAL;
if (get_user(params.stream, &src->stream) ||
get_user(params.buffer_size, &src->buffer_size) ||
get_user(params.avail_min, &src->avail_min) ||
get_user(val, &src->no_active_sensing))
return -EFAULT;
params.no_active_sensing = val;
switch (params.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
return snd_rawmidi_output_params(rfile->output, &params);
case SNDRV_RAWMIDI_STREAM_INPUT:
return snd_rawmidi_input_params(rfile->input, &params);
}
return -EINVAL;
}
struct sndrv_rawmidi_status32 {
s32 stream;
struct compat_timespec tstamp;
u32 avail;
u32 xruns;
unsigned char reserved[16];
} __attribute__((packed));
static int snd_rawmidi_ioctl_status_compat(snd_rawmidi_file_t *rfile,
struct sndrv_rawmidi_status32 __user *src)
{
int err;
snd_rawmidi_status_t status;
if (rfile->output == NULL)
return -EINVAL;
if (get_user(status.stream, &src->stream))
return -EFAULT;
switch (status.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
err = snd_rawmidi_output_status(rfile->output, &status);
break;
case SNDRV_RAWMIDI_STREAM_INPUT:
err = snd_rawmidi_input_status(rfile->input, &status);
break;
default:
return -EINVAL;
}
if (err < 0)
return err;
if (put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) ||
put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) ||
put_user(status.avail, &src->avail) ||
put_user(status.xruns, &src->xruns))
return -EFAULT;
return 0;
}
enum {
SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct sndrv_rawmidi_params32),
SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct sndrv_rawmidi_status32),
};
static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
{
snd_rawmidi_file_t *rfile;
void __user *argp = compat_ptr(arg);
rfile = file->private_data;
switch (cmd) {
case SNDRV_RAWMIDI_IOCTL_PVERSION:
case SNDRV_RAWMIDI_IOCTL_INFO:
case SNDRV_RAWMIDI_IOCTL_DROP:
case SNDRV_RAWMIDI_IOCTL_DRAIN:
return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp);
case SNDRV_RAWMIDI_IOCTL_PARAMS32:
return snd_rawmidi_ioctl_params_compat(rfile, argp);
case SNDRV_RAWMIDI_IOCTL_STATUS32:
return snd_rawmidi_ioctl_status_compat(rfile, argp);
}
return -ENOIOCTLCMD;
}
...@@ -2131,21 +2131,20 @@ static int snd_seq_do_ioctl(client_t *client, unsigned int cmd, void __user *arg ...@@ -2131,21 +2131,20 @@ static int snd_seq_do_ioctl(client_t *client, unsigned int cmd, void __user *arg
} }
static int snd_seq_ioctl(struct inode *inode, struct file *file, static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned int cmd, unsigned long arg)
{ {
client_t *client = (client_t *) file->private_data; client_t *client = (client_t *) file->private_data;
int err;
snd_assert(client != NULL, return -ENXIO); snd_assert(client != NULL, return -ENXIO);
/* FIXME: need to unlock BKL to allow preemption */ return snd_seq_do_ioctl(client, cmd, (void __user *) arg);
unlock_kernel();
err = snd_seq_do_ioctl(client, cmd, (void __user *) arg);
lock_kernel();
return err;
} }
#ifdef CONFIG_COMPAT
#include "seq_compat.c"
#else
#define snd_seq_ioctl_compat NULL
#endif
/* -------------------------------------------------------- */ /* -------------------------------------------------------- */
...@@ -2462,7 +2461,8 @@ static struct file_operations snd_seq_f_ops = ...@@ -2462,7 +2461,8 @@ static struct file_operations snd_seq_f_ops =
.open = snd_seq_open, .open = snd_seq_open,
.release = snd_seq_release, .release = snd_seq_release,
.poll = snd_seq_poll, .poll = snd_seq_poll,
.ioctl = snd_seq_ioctl, .unlocked_ioctl = snd_seq_ioctl,
.compat_ioctl = snd_seq_ioctl_compat,
}; };
static snd_minor_t snd_seq_reg = static snd_minor_t snd_seq_reg =
......
/*
* 32bit -> 64bit ioctl wrapper for sequencer API
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* This file included from seq.c */
#include <linux/compat.h>
struct sndrv_seq_port_info32 {
struct sndrv_seq_addr addr; /* client/port numbers */
char name[64]; /* port name */
u32 capability; /* port capability bits */
u32 type; /* port type bits */
s32 midi_channels; /* channels per MIDI port */
s32 midi_voices; /* voices per MIDI port */
s32 synth_voices; /* voices per SYNTH port */
s32 read_use; /* R/O: subscribers for output (from this port) */
s32 write_use; /* R/O: subscribers for input (to this port) */
u32 kernel; /* reserved for kernel use (must be NULL) */
u32 flags; /* misc. conditioning */
unsigned char time_queue; /* queue # for timestamping */
char reserved[59]; /* for future use */
};
static int snd_seq_call_port_info_ioctl(client_t *client, unsigned int cmd,
struct sndrv_seq_port_info32 __user *data32)
{
int err = -EFAULT;
snd_seq_port_info_t *data;
mm_segment_t fs;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (! data)
return -ENOMEM;
if (copy_from_user(data, data32, sizeof(*data32)) ||
get_user(data->flags, &data32->flags) ||
get_user(data->time_queue, &data32->time_queue))
goto error;
data->kernel = NULL;
fs = snd_enter_user();
err = snd_seq_do_ioctl(client, cmd, data);
snd_leave_user(fs);
if (err < 0)
goto error;
if (copy_to_user(data32, data, sizeof(*data32)) ||
put_user(data->flags, &data32->flags) ||
put_user(data->time_queue, &data32->time_queue))
err = -EFAULT;
error:
kfree(data);
return err;
}
/*
*/
enum {
SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct sndrv_seq_port_info32),
SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct sndrv_seq_port_info32),
SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct sndrv_seq_port_info32),
SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct sndrv_seq_port_info32),
SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct sndrv_seq_port_info32),
};
static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
{
client_t *client = (client_t *) file->private_data;
void __user *argp = compat_ptr(arg);
snd_assert(client != NULL, return -ENXIO);
switch (cmd) {
case SNDRV_SEQ_IOCTL_PVERSION:
case SNDRV_SEQ_IOCTL_CLIENT_ID:
case SNDRV_SEQ_IOCTL_SYSTEM_INFO:
case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO:
case SNDRV_SEQ_IOCTL_SET_CLIENT_INFO:
case SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT:
case SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT:
case SNDRV_SEQ_IOCTL_CREATE_QUEUE:
case SNDRV_SEQ_IOCTL_DELETE_QUEUE:
case SNDRV_SEQ_IOCTL_GET_QUEUE_INFO:
case SNDRV_SEQ_IOCTL_SET_QUEUE_INFO:
case SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE:
case SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS:
case SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO:
case SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO:
case SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER:
case SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER:
case SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT:
case SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT:
case SNDRV_SEQ_IOCTL_GET_CLIENT_POOL:
case SNDRV_SEQ_IOCTL_SET_CLIENT_POOL:
case SNDRV_SEQ_IOCTL_REMOVE_EVENTS:
case SNDRV_SEQ_IOCTL_QUERY_SUBS:
case SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION:
case SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT:
case SNDRV_SEQ_IOCTL_RUNNING_MODE:
return snd_seq_do_ioctl(client, cmd, argp);
case SNDRV_SEQ_IOCTL_CREATE_PORT32:
return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, argp);
case SNDRV_SEQ_IOCTL_DELETE_PORT32:
return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_DELETE_PORT, argp);
case SNDRV_SEQ_IOCTL_GET_PORT_INFO32:
return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_GET_PORT_INFO, argp);
case SNDRV_SEQ_IOCTL_SET_PORT_INFO32:
return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_SET_PORT_INFO, argp);
case SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32:
return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, argp);
}
return -ENOIOCTLCMD;
}
...@@ -1653,8 +1653,7 @@ static int snd_timer_user_continue(struct file *file) ...@@ -1653,8 +1653,7 @@ static int snd_timer_user_continue(struct file *file)
return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
} }
static inline int _snd_timer_user_ioctl(struct inode *inode, struct file *file, static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned int cmd, unsigned long arg)
{ {
snd_timer_user_t *tu; snd_timer_user_t *tu;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
...@@ -1701,17 +1700,6 @@ static inline int _snd_timer_user_ioctl(struct inode *inode, struct file *file, ...@@ -1701,17 +1700,6 @@ static inline int _snd_timer_user_ioctl(struct inode *inode, struct file *file,
return -ENOTTY; return -ENOTTY;
} }
/* FIXME: need to unlock BKL to allow preemption */
static int snd_timer_user_ioctl(struct inode *inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
int err;
unlock_kernel();
err = _snd_timer_user_ioctl(inode, file, cmd, arg);
lock_kernel();
return err;
}
static int snd_timer_user_fasync(int fd, struct file * file, int on) static int snd_timer_user_fasync(int fd, struct file * file, int on)
{ {
snd_timer_user_t *tu; snd_timer_user_t *tu;
...@@ -1803,6 +1791,12 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait) ...@@ -1803,6 +1791,12 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait)
return mask; return mask;
} }
#ifdef CONFIG_COMPAT
#include "timer_compat.c"
#else
#define snd_timer_user_ioctl_compat NULL
#endif
static struct file_operations snd_timer_f_ops = static struct file_operations snd_timer_f_ops =
{ {
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -1810,7 +1804,8 @@ static struct file_operations snd_timer_f_ops = ...@@ -1810,7 +1804,8 @@ static struct file_operations snd_timer_f_ops =
.open = snd_timer_user_open, .open = snd_timer_user_open,
.release = snd_timer_user_release, .release = snd_timer_user_release,
.poll = snd_timer_user_poll, .poll = snd_timer_user_poll,
.ioctl = snd_timer_user_ioctl, .unlocked_ioctl = snd_timer_user_ioctl,
.compat_ioctl = snd_timer_user_ioctl_compat,
.fasync = snd_timer_user_fasync, .fasync = snd_timer_user_fasync,
}; };
......
/*
* 32bit -> 64bit ioctl wrapper for timer API
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* This file included from timer.c */
#include <linux/compat.h>
struct sndrv_timer_info32 {
u32 flags;
s32 card;
unsigned char id[64];
unsigned char name[80];
u32 reserved0;
u32 resolution;
unsigned char reserved[64];
};
static int snd_timer_user_info_compat(struct file *file,
struct sndrv_timer_info32 __user *_info)
{
snd_timer_user_t *tu;
struct sndrv_timer_info32 info;
snd_timer_t *t;
tu = file->private_data;
snd_assert(tu->timeri != NULL, return -ENXIO);
t = tu->timeri->timer;
snd_assert(t != NULL, return -ENXIO);
memset(&info, 0, sizeof(info));
info.card = t->card ? t->card->number : -1;
if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
info.flags |= SNDRV_TIMER_FLG_SLAVE;
strlcpy(info.id, t->id, sizeof(info.id));
strlcpy(info.name, t->name, sizeof(info.name));
info.resolution = t->hw.resolution;
if (copy_to_user(_info, &info, sizeof(*_info)))
return -EFAULT;
return 0;
}
struct sndrv_timer_status32 {
struct compat_timespec tstamp;
u32 resolution;
u32 lost;
u32 overrun;
u32 queue;
unsigned char reserved[64];
};
static int snd_timer_user_status_compat(struct file *file,
struct sndrv_timer_status32 __user *_status)
{
snd_timer_user_t *tu;
snd_timer_status_t status;
tu = file->private_data;
snd_assert(tu->timeri != NULL, return -ENXIO);
memset(&status, 0, sizeof(status));
status.tstamp = tu->tstamp;
status.resolution = snd_timer_resolution(tu->timeri);
status.lost = tu->timeri->lost;
status.overrun = tu->overrun;
spin_lock_irq(&tu->qlock);
status.queue = tu->qused;
spin_unlock_irq(&tu->qlock);
if (copy_to_user(_status, &status, sizeof(status)))
return -EFAULT;
return 0;
}
/*
*/
enum {
SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct sndrv_timer_info32),
SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct sndrv_timer_status32),
};
static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *argp = compat_ptr(arg);
switch (cmd) {
case SNDRV_TIMER_IOCTL_PVERSION:
case SNDRV_TIMER_IOCTL_TREAD:
case SNDRV_TIMER_IOCTL_GINFO:
case SNDRV_TIMER_IOCTL_GPARAMS:
case SNDRV_TIMER_IOCTL_GSTATUS:
case SNDRV_TIMER_IOCTL_SELECT:
case SNDRV_TIMER_IOCTL_PARAMS:
case SNDRV_TIMER_IOCTL_START:
case SNDRV_TIMER_IOCTL_STOP:
case SNDRV_TIMER_IOCTL_CONTINUE:
case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
return snd_timer_user_ioctl(file, cmd, (unsigned long)argp);
case SNDRV_TIMER_IOCTL_INFO32:
return snd_timer_user_info_compat(file, argp);
case SNDRV_TIMER_IOCTL_STATUS32:
return snd_timer_user_status_compat(file, argp);
}
return -ENOIOCTLCMD;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment