summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-11 20:57:46 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-11 20:57:46 -0800
commit92340ee3198a2afd7664ed2f5472fa072b15fa32 (patch)
treeb77411ace423d8702da51938c953914d341fba80 /drivers
parenta1c36e52068a59374e127d60e4d8f4377072fc98 (diff)
parent637e8a60a7aaf4ef7d46cfdf83bcfac9cf6f0fbd (diff)
Merge branch 'compat-ioctl-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground
* 'compat-ioctl-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground: usbdevfs: move compat_ioctl handling to devio.c lp: move compat_ioctl handling into lp.c compat_ioctl: pass compat pointer directly to handlers compat_ioctl: simplify lookup table compat_ioctl: simplify calling of handlers compat_ioctl: inline all conversion handlers compat_ioctl: Remove BKL compat_ioctl: remove all VT ioctl handling
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/lp.c115
-rw-r--r--drivers/usb/core/devio.c110
2 files changed, 188 insertions, 37 deletions
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index e444c2dba160..938a3a273886 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -127,6 +127,7 @@
#include <linux/wait.h>
#include <linux/jiffies.h>
#include <linux/smp_lock.h>
+#include <linux/compat.h>
#include <linux/parport.h>
#undef LP_STATS
@@ -571,13 +572,11 @@ static int lp_release(struct inode * inode, struct file * file)
return 0;
}
-static int lp_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int lp_do_ioctl(unsigned int minor, unsigned int cmd,
+ unsigned long arg, void __user *argp)
{
- unsigned int minor = iminor(inode);
int status;
int retval = 0;
- void __user *argp = (void __user *)arg;
#ifdef LP_DEBUG
printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg);
@@ -587,9 +586,6 @@ static int lp_ioctl(struct inode *inode, struct file *file,
if ((LP_F(minor) & LP_EXIST) == 0)
return -ENODEV;
switch ( cmd ) {
- struct timeval par_timeout;
- long to_jiffies;
-
case LPTIME:
LP_TIME(minor) = arg * HZ/100;
break;
@@ -652,34 +648,101 @@ static int lp_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
break;
- case LPSETTIMEOUT:
- if (copy_from_user (&par_timeout, argp,
- sizeof (struct timeval))) {
- return -EFAULT;
- }
- /* Convert to jiffies, place in lp_table */
- if ((par_timeout.tv_sec < 0) ||
- (par_timeout.tv_usec < 0)) {
- return -EINVAL;
- }
- to_jiffies = DIV_ROUND_UP(par_timeout.tv_usec, 1000000/HZ);
- to_jiffies += par_timeout.tv_sec * (long) HZ;
- if (to_jiffies <= 0) {
- return -EINVAL;
- }
- lp_table[minor].timeout = to_jiffies;
- break;
-
default:
retval = -EINVAL;
}
return retval;
}
+static int lp_set_timeout(unsigned int minor, struct timeval *par_timeout)
+{
+ long to_jiffies;
+
+ /* Convert to jiffies, place in lp_table */
+ if ((par_timeout->tv_sec < 0) ||
+ (par_timeout->tv_usec < 0)) {
+ return -EINVAL;
+ }
+ to_jiffies = DIV_ROUND_UP(par_timeout->tv_usec, 1000000/HZ);
+ to_jiffies += par_timeout->tv_sec * (long) HZ;
+ if (to_jiffies <= 0) {
+ return -EINVAL;
+ }
+ lp_table[minor].timeout = to_jiffies;
+ return 0;
+}
+
+static long lp_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ unsigned int minor;
+ struct timeval par_timeout;
+ int ret;
+
+ minor = iminor(file->f_path.dentry->d_inode);
+ lock_kernel();
+ switch (cmd) {
+ case LPSETTIMEOUT:
+ if (copy_from_user(&par_timeout, (void __user *)arg,
+ sizeof (struct timeval))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = lp_set_timeout(minor, &par_timeout);
+ break;
+ default:
+ ret = lp_do_ioctl(minor, cmd, arg, (void __user *)arg);
+ break;
+ }
+ unlock_kernel();
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long lp_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ unsigned int minor;
+ struct timeval par_timeout;
+ struct compat_timeval __user *tc;
+ int ret;
+
+ minor = iminor(file->f_path.dentry->d_inode);
+ lock_kernel();
+ switch (cmd) {
+ case LPSETTIMEOUT:
+ tc = compat_ptr(arg);
+ if (get_user(par_timeout.tv_sec, &tc->tv_sec) ||
+ get_user(par_timeout.tv_usec, &tc->tv_usec)) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = lp_set_timeout(minor, &par_timeout);
+ break;
+#ifdef LP_STATS
+ case LPGETSTATS:
+ /* FIXME: add an implementation if you set LP_STATS */
+ ret = -EINVAL;
+ break;
+#endif
+ default:
+ ret = lp_do_ioctl(minor, cmd, arg, compat_ptr(arg));
+ break;
+ }
+ unlock_kernel();
+
+ return ret;
+}
+#endif
+
static const struct file_operations lp_fops = {
.owner = THIS_MODULE,
.write = lp_write,
- .ioctl = lp_ioctl,
+ .unlocked_ioctl = lp_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = lp_compat_ioctl,
+#endif
.open = lp_open,
.release = lp_release,
#ifdef CONFIG_PARPORT_1284
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 181f78c84105..6e8bcdfd23b4 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1388,6 +1388,46 @@ static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)
}
#ifdef CONFIG_COMPAT
+static int proc_control_compat(struct dev_state *ps,
+ struct usbdevfs_ctrltransfer32 __user *p32)
+{
+ struct usbdevfs_ctrltransfer __user *p;
+ __u32 udata;
+ p = compat_alloc_user_space(sizeof(*p));
+ if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) ||
+ get_user(udata, &p32->data) ||
+ put_user(compat_ptr(udata), &p->data))
+ return -EFAULT;
+ return proc_control(ps, p);
+}
+
+static int proc_bulk_compat(struct dev_state *ps,
+ struct usbdevfs_bulktransfer32 __user *p32)
+{
+ struct usbdevfs_bulktransfer __user *p;
+ compat_uint_t n;
+ compat_caddr_t addr;
+
+ p = compat_alloc_user_space(sizeof(*p));
+
+ if (get_user(n, &p32->ep) || put_user(n, &p->ep) ||
+ get_user(n, &p32->len) || put_user(n, &p->len) ||
+ get_user(n, &p32->timeout) || put_user(n, &p->timeout) ||
+ get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data))
+ return -EFAULT;
+
+ return proc_bulk(ps, p);
+}
+static int proc_disconnectsignal_compat(struct dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_disconnectsignal32 ds;
+
+ if (copy_from_user(&ds, arg, sizeof(ds)))
+ return -EFAULT;
+ ps->discsignr = ds.signr;
+ ps->disccontext = compat_ptr(ds.context);
+ return 0;
+}
static int get_urb32(struct usbdevfs_urb *kurb,
struct usbdevfs_urb32 __user *uurb)
@@ -1482,6 +1522,7 @@ static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg)
return processcompl_compat(as, (void __user * __user *)arg);
}
+
#endif
static int proc_disconnectsignal(struct dev_state *ps, void __user *arg)
@@ -1648,12 +1689,12 @@ static int proc_release_port(struct dev_state *ps, void __user *arg)
* are assuming that somehow the configuration has been prevented from
* changing. But there's no mechanism to ensure that...
*/
-static int usbdev_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
+ void __user *p)
{
struct dev_state *ps = file->private_data;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct usb_device *dev = ps->dev;
- void __user *p = (void __user *)arg;
int ret = -ENOTTY;
if (!(file->f_mode & FMODE_WRITE))
@@ -1726,6 +1767,24 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
break;
#ifdef CONFIG_COMPAT
+ case USBDEVFS_CONTROL32:
+ snoop(&dev->dev, "%s: CONTROL32\n", __func__);
+ ret = proc_control_compat(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_BULK32:
+ snoop(&dev->dev, "%s: BULK32\n", __func__);
+ ret = proc_bulk_compat(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_DISCSIGNAL32:
+ snoop(&dev->dev, "%s: DISCSIGNAL32\n", __func__);
+ ret = proc_disconnectsignal_compat(ps, p);
+ break;
case USBDEVFS_SUBMITURB32:
snoop(&dev->dev, "%s: SUBMITURB32\n", __func__);
@@ -1745,7 +1804,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
break;
case USBDEVFS_IOCTL32:
- snoop(&dev->dev, "%s: IOCTL\n", __func__);
+ snoop(&dev->dev, "%s: IOCTL32\n", __func__);
ret = proc_ioctl_compat(ps, ptr_to_compat(p));
break;
#endif
@@ -1801,6 +1860,32 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
return ret;
}
+static long usbdev_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+
+ lock_kernel();
+ ret = usbdev_do_ioctl(file, cmd, (void __user *)arg);
+ unlock_kernel();
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long usbdev_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+
+ lock_kernel();
+ ret = usbdev_do_ioctl(file, cmd, compat_ptr(arg));
+ unlock_kernel();
+
+ return ret;
+}
+#endif
+
/* No kernel lock - fine */
static unsigned int usbdev_poll(struct file *file,
struct poll_table_struct *wait)
@@ -1817,13 +1902,16 @@ static unsigned int usbdev_poll(struct file *file,
}
const struct file_operations usbdev_file_operations = {
- .owner = THIS_MODULE,
- .llseek = usbdev_lseek,
- .read = usbdev_read,
- .poll = usbdev_poll,
- .ioctl = usbdev_ioctl,
- .open = usbdev_open,
- .release = usbdev_release,
+ .owner = THIS_MODULE,
+ .llseek = usbdev_lseek,
+ .read = usbdev_read,
+ .poll = usbdev_poll,
+ .unlocked_ioctl = usbdev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = usbdev_compat_ioctl,
+#endif
+ .open = usbdev_open,
+ .release = usbdev_release,
};
static void usbdev_remove(struct usb_device *udev)