usbdevfs: move compat_ioctl handling to devio.c
authorArnd Bergmann <arnd@arndb.de>
Sat, 14 Nov 2009 01:28:05 +0000 (02:28 +0100)
committerArnd Bergmann <arnd@arndb.de>
Thu, 10 Dec 2009 21:55:37 +0000 (22:55 +0100)
Half the compat_ioctl handling is in devio.c, the other
half is in fs/compat_ioctl.c. This moves everything into
one place for consistency.

As a positive side-effect, push down the BKL into the
ioctl methods.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Oliver Neukum <oliver@neukum.org>
Cc: Alon Bar-Lev <alon.barlev@gmail.com>
Cc: David Vrabel <david.vrabel@csr.com>
Cc: linux-usb@vger.kernel.org
drivers/usb/core/devio.c
fs/compat_ioctl.c
include/linux/usbdevice_fs.h

index 181f78c84105c090df4689b44845638472ccb8ef..6e8bcdfd23b41ee8435efbbb5e6bfadeb8095eb3 100644 (file)
@@ -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)
index 598763fd207f4f5a3a9be685bfd48ef186412f09..278020d2449c749a0457064e4c3e1caf4aa65f52 100644 (file)
@@ -742,94 +742,6 @@ static int serial_struct_ioctl(unsigned fd, unsigned cmd,
         return err;
 }
 
-struct usbdevfs_ctrltransfer32 {
-        u8 bRequestType;
-        u8 bRequest;
-        u16 wValue;
-        u16 wIndex;
-        u16 wLength;
-        u32 timeout;  /* in milliseconds */
-        compat_caddr_t data;
-};
-
-#define USBDEVFS_CONTROL32           _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
-
-static int do_usbdevfs_control(unsigned int fd, unsigned int cmd,
-                       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 sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)p);
-}
-
-
-struct usbdevfs_bulktransfer32 {
-        compat_uint_t ep;
-        compat_uint_t len;
-        compat_uint_t timeout; /* in milliseconds */
-        compat_caddr_t data;
-};
-
-#define USBDEVFS_BULK32              _IOWR('U', 2, struct usbdevfs_bulktransfer32)
-
-static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd,
-                       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 sys_ioctl(fd, USBDEVFS_BULK, (unsigned long)p);
-}
-
-
-/*
- *  USBDEVFS_SUBMITURB, USBDEVFS_REAPURB and USBDEVFS_REAPURBNDELAY
- *  are handled in usbdevfs core.                      -Christopher Li
- */
-
-struct usbdevfs_disconnectsignal32 {
-        compat_int_t signr;
-        compat_caddr_t context;
-};
-
-#define USBDEVFS_DISCSIGNAL32      _IOR('U', 14, struct usbdevfs_disconnectsignal32)
-
-static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd,
-                       struct usbdevfs_disconnectsignal32 __user *udis)
-{
-        struct usbdevfs_disconnectsignal kdis;
-        mm_segment_t old_fs;
-        u32 uctx;
-        int err;
-
-        if (get_user(kdis.signr, &udis->signr) ||
-            __get_user(uctx, &udis->context))
-                return -EFAULT;
-
-        kdis.context = compat_ptr(uctx);
-
-        old_fs = get_fs();
-        set_fs(KERNEL_DS);
-        err = sys_ioctl(fd, USBDEVFS_DISCSIGNAL, (unsigned long) &kdis);
-        set_fs(old_fs);
-
-        return err;
-}
-
 /*
  * I2C layer ioctls
  */
@@ -1471,21 +1383,6 @@ COMPATIBLE_IOCTL(PCIIOC_CONTROLLER)
 COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
 COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
 COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE)
-/* USB */
-COMPATIBLE_IOCTL(USBDEVFS_RESETEP)
-COMPATIBLE_IOCTL(USBDEVFS_SETINTERFACE)
-COMPATIBLE_IOCTL(USBDEVFS_SETCONFIGURATION)
-COMPATIBLE_IOCTL(USBDEVFS_GETDRIVER)
-COMPATIBLE_IOCTL(USBDEVFS_DISCARDURB)
-COMPATIBLE_IOCTL(USBDEVFS_CLAIMINTERFACE)
-COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE)
-COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO)
-COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO)
-COMPATIBLE_IOCTL(USBDEVFS_RESET)
-COMPATIBLE_IOCTL(USBDEVFS_SUBMITURB32)
-COMPATIBLE_IOCTL(USBDEVFS_REAPURB32)
-COMPATIBLE_IOCTL(USBDEVFS_REAPURBNDELAY32)
-COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT)
 /* NBD */
 COMPATIBLE_IOCTL(NBD_DO_IT)
 COMPATIBLE_IOCTL(NBD_CLEAR_SOCK)
@@ -1604,8 +1501,6 @@ COMPATIBLE_IOCTL(TIOCSLTC)
 COMPATIBLE_IOCTL(TIOCSTART)
 COMPATIBLE_IOCTL(TIOCSTOP)
 #endif
-/* Usbdevfs */
-COMPATIBLE_IOCTL(USBDEVFS_IOCTL32)
 
 /* fat 'r' ioctls. These are handled by fat with ->compat_ioctl,
    but we don't want warnings on other file systems. So declare
@@ -1677,13 +1572,6 @@ static long do_ioctl_trans(int fd, unsigned int cmd,
        case TIOCGSERIAL:
        case TIOCSSERIAL:
                return serial_struct_ioctl(fd, cmd, argp);
-       /* Usbdevfs */
-       case USBDEVFS_CONTROL32:
-               return do_usbdevfs_control(fd, cmd, argp);
-       case USBDEVFS_BULK32:
-               return do_usbdevfs_bulk(fd, cmd, argp);
-       case USBDEVFS_DISCSIGNAL32:
-               return do_usbdevfs_discsignal(fd, cmd, argp);
        /* i2c */
        case I2C_FUNCS:
                return w_long(fd, cmd, argp);
index b2a7d8ba6ee3d6c7ee7435bd43eedd6640243a26..15591d2ea4004a86599e940ec4583bb12a1be341 100644 (file)
@@ -128,6 +128,29 @@ struct usbdevfs_hub_portinfo {
 #ifdef __KERNEL__
 #ifdef CONFIG_COMPAT
 #include <linux/compat.h>
+
+struct usbdevfs_ctrltransfer32 {
+        u8 bRequestType;
+        u8 bRequest;
+        u16 wValue;
+        u16 wIndex;
+        u16 wLength;
+        u32 timeout;  /* in milliseconds */
+        compat_caddr_t data;
+};
+
+struct usbdevfs_bulktransfer32 {
+        compat_uint_t ep;
+        compat_uint_t len;
+        compat_uint_t timeout; /* in milliseconds */
+        compat_caddr_t data;
+};
+
+struct usbdevfs_disconnectsignal32 {
+        compat_int_t signr;
+        compat_caddr_t context;
+};
+
 struct usbdevfs_urb32 {
        unsigned char type;
        unsigned char endpoint;
@@ -153,7 +176,9 @@ struct usbdevfs_ioctl32 {
 #endif /* __KERNEL__ */
 
 #define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)
+#define USBDEVFS_CONTROL32           _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
 #define USBDEVFS_BULK              _IOWR('U', 2, struct usbdevfs_bulktransfer)
+#define USBDEVFS_BULK32              _IOWR('U', 2, struct usbdevfs_bulktransfer32)
 #define USBDEVFS_RESETEP           _IOR('U', 3, unsigned int)
 #define USBDEVFS_SETINTERFACE      _IOR('U', 4, struct usbdevfs_setinterface)
 #define USBDEVFS_SETCONFIGURATION  _IOR('U', 5, unsigned int)
@@ -166,6 +191,7 @@ struct usbdevfs_ioctl32 {
 #define USBDEVFS_REAPURBNDELAY     _IOW('U', 13, void *)
 #define USBDEVFS_REAPURBNDELAY32   _IOW('U', 13, __u32)
 #define USBDEVFS_DISCSIGNAL        _IOR('U', 14, struct usbdevfs_disconnectsignal)
+#define USBDEVFS_DISCSIGNAL32      _IOR('U', 14, struct usbdevfs_disconnectsignal32)
 #define USBDEVFS_CLAIMINTERFACE    _IOR('U', 15, unsigned int)
 #define USBDEVFS_RELEASEINTERFACE  _IOR('U', 16, unsigned int)
 #define USBDEVFS_CONNECTINFO       _IOW('U', 17, struct usbdevfs_connectinfo)