patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / usb / core / devio.c
index ed1296a..2979912 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/usbdevice_fs.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
+#include <linux/moduleparam.h>
 
 #include "hcd.h"       /* for usbcore internals */
 #include "usb.h"
@@ -54,12 +55,28 @@ struct async {
        struct dev_state *ps;
        struct task_struct *task;
        unsigned int signr;
-       unsigned int intf;
+       unsigned int ifnum;
        void __user *userbuffer;
        void __user *userurb;
        struct urb *urb;
 };
 
+static int usbfs_snoop = 0;
+module_param (usbfs_snoop, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic");
+
+#define snoop(dev, format, arg...)                             \
+       do {                                                    \
+               if (usbfs_snoop)                                \
+                       dev_info( dev , format , ## arg);       \
+       } while (0)
+
+
+static inline int connected (struct usb_device *dev)
+{
+       return dev->state != USB_STATE_NOTATTACHED;
+}
+
 static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
 {
        loff_t ret;
@@ -87,14 +104,15 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
 static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
 {
        struct dev_state *ps = (struct dev_state *)file->private_data;
+       struct usb_device *dev = ps->dev;
        ssize_t ret = 0;
        unsigned len;
        loff_t pos;
        int i;
 
        pos = *ppos;
-       down_read(&ps->devsem);
-       if (!ps->dev) {
+       down(&dev->serialize);
+       if (!connected(dev)) {
                ret = -ENODEV;
                goto err;
        } else if (pos < 0) {
@@ -106,7 +124,7 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
                len = sizeof(struct usb_device_descriptor) - pos;
                if (len > nbytes)
                        len = nbytes;
-               if (copy_to_user(buf, ((char *)&ps->dev->descriptor) + pos, len)) {
+               if (copy_to_user(buf, ((char *)&dev->descriptor) + pos, len)) {
                        ret = -EFAULT;
                        goto err;
                }
@@ -118,9 +136,9 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
        }
 
        pos = sizeof(struct usb_device_descriptor);
-       for (i = 0; nbytes && i < ps->dev->descriptor.bNumConfigurations; i++) {
+       for (i = 0; nbytes && i < dev->descriptor.bNumConfigurations; i++) {
                struct usb_config_descriptor *config =
-                       (struct usb_config_descriptor *)ps->dev->rawdescriptors[i];
+                       (struct usb_config_descriptor *)dev->rawdescriptors[i];
                unsigned int length = le16_to_cpu(config->wTotalLength);
 
                if (*ppos < pos + length) {
@@ -128,7 +146,7 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
                        /* The descriptor may claim to be longer than it
                         * really is.  Here is the actual allocated length. */
                        unsigned alloclen =
-                               ps->dev->config[i].desc.wTotalLength;
+                               dev->config[i].desc.wTotalLength;
 
                        len = length - (*ppos - pos);
                        if (len > nbytes)
@@ -138,7 +156,7 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
                        if (alloclen > (*ppos - pos)) {
                                alloclen -= (*ppos - pos);
                                if (copy_to_user(buf,
-                                   ps->dev->rawdescriptors[i] + (*ppos - pos),
+                                   dev->rawdescriptors[i] + (*ppos - pos),
                                    min(len, alloclen))) {
                                        ret = -EFAULT;
                                        goto err;
@@ -155,35 +173,10 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
        }
 
 err:
-       up_read(&ps->devsem);
+       up(&dev->serialize);
        return ret;
 }
 
-extern inline unsigned int ld2(unsigned int x)
-{
-        unsigned int r = 0;
-        
-        if (x >= 0x10000) {
-                x >>= 16;
-                r += 16;
-        }
-        if (x >= 0x100) {
-                x >>= 8;
-                r += 8;
-        }
-        if (x >= 0x10) {
-                x >>= 4;
-                r += 4;
-        }
-        if (x >= 4) {
-                x >>= 2;
-                r += 2;
-        }
-        if (x >= 2)
-                r++;
-        return r;
-}
-
 /*
  * async list handling
  */
@@ -213,7 +206,7 @@ static void free_async(struct async *as)
         kfree(as);
 }
 
-extern __inline__ void async_newpending(struct async *as)
+static inline void async_newpending(struct async *as)
 {
         struct dev_state *ps = as->ps;
         unsigned long flags;
@@ -223,7 +216,7 @@ extern __inline__ void async_newpending(struct async *as)
         spin_unlock_irqrestore(&ps->lock, flags);
 }
 
-extern __inline__ void async_removepending(struct async *as)
+static inline void async_removepending(struct async *as)
 {
         struct dev_state *ps = as->ps;
         unsigned long flags;
@@ -233,7 +226,7 @@ extern __inline__ void async_removepending(struct async *as)
         spin_unlock_irqrestore(&ps->lock, flags);
 }
 
-extern __inline__ struct async *async_getcompleted(struct dev_state *ps)
+static inline struct async *async_getcompleted(struct dev_state *ps)
 {
         unsigned long flags;
         struct async *as = NULL;
@@ -247,7 +240,7 @@ extern __inline__ struct async *async_getcompleted(struct dev_state *ps)
         return as;
 }
 
-extern __inline__ struct async *async_getpending(struct dev_state *ps, void __user *userurb)
+static inline struct async *async_getpending(struct dev_state *ps, void __user *userurb)
 {
         unsigned long flags;
         struct async *as;
@@ -301,7 +294,7 @@ static void destroy_async (struct dev_state *ps, struct list_head *list)
                free_async(as);
 }
 
-static void destroy_async_on_interface (struct dev_state *ps, unsigned int intf)
+static void destroy_async_on_interface (struct dev_state *ps, unsigned int ifnum)
 {
        struct list_head *p, *q, hitlist;
        unsigned long flags;
@@ -309,13 +302,13 @@ static void destroy_async_on_interface (struct dev_state *ps, unsigned int intf)
        INIT_LIST_HEAD(&hitlist);
        spin_lock_irqsave(&ps->lock, flags);
        list_for_each_safe(p, q, &ps->async_pending)
-               if (intf == list_entry(p, struct async, asynclist)->intf)
+               if (ifnum == list_entry(p, struct async, asynclist)->ifnum)
                        list_move_tail(p, &hitlist);
        spin_unlock_irqrestore(&ps->lock, flags);
        destroy_async(ps, &hitlist);
 }
 
-extern __inline__ void destroy_all_async(struct dev_state *ps)
+static inline void destroy_all_async(struct dev_state *ps)
 {
                destroy_async(ps, &ps->async_pending);
 }
@@ -335,6 +328,7 @@ static int driver_probe (struct usb_interface *intf,
 static void driver_disconnect(struct usb_interface *intf)
 {
        struct dev_state *ps = usb_get_intfdata (intf);
+       unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber;
 
        if (!ps)
                return;
@@ -343,13 +337,15 @@ static void driver_disconnect(struct usb_interface *intf)
         * all pending I/O requests; 2.6 does that.
         */
 
-       /* prevent new I/O requests */
-       ps->dev = 0;
-       clear_bit(intf->cur_altsetting->desc.bInterfaceNumber, &ps->ifclaimed);
+       if (likely(ifnum < 8*sizeof(ps->ifclaimed)))
+               clear_bit(ifnum, &ps->ifclaimed);
+       else
+               warn("interface number %u out of range", ifnum);
+
        usb_set_intfdata (intf, NULL);
 
        /* force async requests to complete */
-       destroy_all_async (ps);
+       destroy_async_on_interface(ps, ifnum);
 }
 
 struct usb_driver usbdevfs_driver = {
@@ -359,71 +355,70 @@ struct usb_driver usbdevfs_driver = {
        .disconnect =   driver_disconnect,
 };
 
-static int claimintf(struct dev_state *ps, unsigned int intf)
+static int claimintf(struct dev_state *ps, unsigned int ifnum)
 {
        struct usb_device *dev = ps->dev;
-       struct usb_interface *iface;
+       struct usb_interface *intf;
        int err;
 
-       if (intf >= 8*sizeof(ps->ifclaimed) || !dev
-                       || intf >= dev->actconfig->desc.bNumInterfaces)
+       if (ifnum >= 8*sizeof(ps->ifclaimed))
                return -EINVAL;
        /* already claimed */
-       if (test_bit(intf, &ps->ifclaimed))
+       if (test_bit(ifnum, &ps->ifclaimed))
                return 0;
-       iface = dev->actconfig->interface[intf];
-       err = -EBUSY;
 
        /* lock against other changes to driver bindings */
        down_write(&usb_bus_type.subsys.rwsem);
-       if (!usb_interface_claimed(iface)) {
-               usb_driver_claim_interface(&usbdevfs_driver, iface, ps);
-               set_bit(intf, &ps->ifclaimed);
-               err = 0;
-       }
+       intf = usb_ifnum_to_if(dev, ifnum);
+       if (!intf)
+               err = -ENOENT;
+       else
+               err = usb_driver_claim_interface(&usbdevfs_driver, intf, ps);
        up_write(&usb_bus_type.subsys.rwsem);
+       if (err == 0)
+               set_bit(ifnum, &ps->ifclaimed);
        return err;
 }
 
-static int releaseintf(struct dev_state *ps, unsigned int intf)
+static int releaseintf(struct dev_state *ps, unsigned int ifnum)
 {
        struct usb_device *dev;
-       struct usb_interface *iface;
+       struct usb_interface *intf;
        int err;
 
-       if (intf >= 8*sizeof(ps->ifclaimed))
-               return -EINVAL;
        err = -EINVAL;
+       if (ifnum >= 8*sizeof(ps->ifclaimed))
+               return err;
        dev = ps->dev;
-       down(&dev->serialize);
        /* lock against other changes to driver bindings */
        down_write(&usb_bus_type.subsys.rwsem);
-       if (test_and_clear_bit(intf, &ps->ifclaimed)) {
-               iface = dev->actconfig->interface[intf];
-               usb_driver_release_interface(&usbdevfs_driver, iface);
+       intf = usb_ifnum_to_if(dev, ifnum);
+       if (!intf)
+               err = -ENOENT;
+       else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) {
+               usb_driver_release_interface(&usbdevfs_driver, intf);
                err = 0;
        }
        up_write(&usb_bus_type.subsys.rwsem);
-       up(&dev->serialize);
        return err;
 }
 
-static int checkintf(struct dev_state *ps, unsigned int intf)
+static int checkintf(struct dev_state *ps, unsigned int ifnum)
 {
-       if (intf >= 8*sizeof(ps->ifclaimed))
+       if (ifnum >= 8*sizeof(ps->ifclaimed))
                return -EINVAL;
-       if (test_bit(intf, &ps->ifclaimed))
+       if (test_bit(ifnum, &ps->ifclaimed))
                return 0;
        /* if not yet claimed, claim it for the driver */
-       printk(KERN_WARNING "usbfs: process %d (%s) did not claim interface %u before use\n",
-              current->pid, current->comm, intf);
-       return claimintf(ps, intf);
+       dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim interface %u before use\n",
+              current->pid, current->comm, ifnum);
+       return claimintf(ps, ifnum);
 }
 
 static int findintfep(struct usb_device *dev, unsigned int ep)
 {
        unsigned int i, j, e;
-        struct usb_interface *iface;
+        struct usb_interface *intf;
        struct usb_host_interface *alts;
        struct usb_endpoint_descriptor *endpt;
 
@@ -432,58 +427,38 @@ static int findintfep(struct usb_device *dev, unsigned int ep)
        if (!dev->actconfig)
                return -ESRCH;
        for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
-               iface = dev->actconfig->interface[i];
-               for (j = 0; j < iface->num_altsetting; j++) {
-                        alts = &iface->altsetting[j];
+               intf = dev->actconfig->interface[i];
+               for (j = 0; j < intf->num_altsetting; j++) {
+                        alts = &intf->altsetting[j];
                        for (e = 0; e < alts->desc.bNumEndpoints; e++) {
                                endpt = &alts->endpoint[e].desc;
                                if (endpt->bEndpointAddress == ep)
-                                       return i;
+                                       return alts->desc.bInterfaceNumber;
                        }
                }
        }
        return -ENOENT; 
 }
 
-static int findintfif(struct usb_device *dev, unsigned int ifn)
-{
-       unsigned int i;
-
-       if (ifn & ~0xff)
-               return -EINVAL;
-       if (!dev->actconfig)
-               return -ESRCH;
-       for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
-               if (dev->actconfig->interface[i]->
-                               altsetting[0].desc.bInterfaceNumber == ifn)
-                       return i;
-       }
-       return -ENOENT; 
-}
-
 static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsigned int index)
 {
-       int ret;
+       int ret = 0;
 
        if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
                return 0;
 
+       index &= 0xff;
        switch (requesttype & USB_RECIP_MASK) {
        case USB_RECIP_ENDPOINT:
-               if ((ret = findintfep(ps->dev, index & 0xff)) < 0)
-                       return ret;
-               if ((ret = checkintf(ps, ret)))
-                       return ret;
+               if ((ret = findintfep(ps->dev, index)) >= 0)
+                       ret = checkintf(ps, ret);
                break;
 
        case USB_RECIP_INTERFACE:
-               if ((ret = findintfif(ps->dev, index & 0xff)) < 0)
-                       return ret;
-               if ((ret = checkintf(ps, ret)))
-                       return ret;
+               ret = checkintf(ps, index);
                break;
        }
-       return 0;
+       return ret;
 }
 
 /*
@@ -496,8 +471,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
        int ret;
 
        /* 
-        * no locking necessary here, as both sys_open (actually filp_open)
-        * and the hub thread have the kernel lock
+        * no locking necessary here, as chrdev_open has the kernel lock
         * (still acquire the kernel lock for safety)
         */
        ret = -ENOMEM;
@@ -506,7 +480,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
 
        lock_kernel();
        ret = -ENOENT;
-       dev = inode->u.generic_ip;
+       dev = usb_get_dev(inode->u.generic_ip);
        if (!dev) {
                kfree(ps);
                goto out;
@@ -518,7 +492,6 @@ static int usbdev_open(struct inode *inode, struct file *file)
        INIT_LIST_HEAD(&ps->async_pending);
        INIT_LIST_HEAD(&ps->async_completed);
        init_waitqueue_head(&ps->wait);
-       init_rwsem(&ps->devsem);
        ps->discsignr = 0;
        ps->disctask = current;
        ps->disccontext = NULL;
@@ -535,18 +508,21 @@ static int usbdev_open(struct inode *inode, struct file *file)
 static int usbdev_release(struct inode *inode, struct file *file)
 {
        struct dev_state *ps = (struct dev_state *)file->private_data;
-       unsigned int i;
+       struct usb_device *dev = ps->dev;
+       unsigned int ifnum;
 
-       lock_kernel();
+       down(&dev->serialize);
        list_del_init(&ps->list);
 
-       if (ps->dev) {
-               for (i = 0; ps->ifclaimed && i < 8*sizeof(ps->ifclaimed); i++)
-                       if (test_bit(i, &ps->ifclaimed))
-                               releaseintf(ps, i);
+       if (connected(dev)) {
+               for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed); ifnum++)
+                       if (test_bit(ifnum, &ps->ifclaimed))
+                               releaseintf(ps, ifnum);
+               destroy_all_async(ps);
        }
-       unlock_kernel();
-       destroy_all_async(ps);
+       up(&dev->serialize);
+       usb_put_dev(dev);
+       ps->dev = NULL;
        kfree(ps);
         return 0;
 }
@@ -557,7 +533,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)
        struct usbdevfs_ctrltransfer ctrl;
        unsigned int tmo;
        unsigned char *tbuf;
-       int i, ret;
+       int i, j, ret;
 
        if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
                return -EFAULT;
@@ -573,9 +549,18 @@ static int proc_control(struct dev_state *ps, void __user *arg)
                        free_page((unsigned long)tbuf);
                        return -EINVAL;
                }
+               snoop(&dev->dev, "control read: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", 
+                       ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex);
+
                i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
                                       ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
                if ((i > 0) && ctrl.wLength) {
+                       if (usbfs_snoop) {
+                               dev_info(&dev->dev, "control read: data ");
+                               for (j = 0; j < ctrl.wLength; ++j)
+                                       printk ("%02x ", (unsigned char)((char *)ctrl.data)[j]);
+                               printk("\n");
+                       }
                        if (copy_to_user(ctrl.data, tbuf, ctrl.wLength)) {
                                free_page((unsigned long)tbuf);
                                return -EFAULT;
@@ -588,15 +573,23 @@ static int proc_control(struct dev_state *ps, void __user *arg)
                                return -EFAULT;
                        }
                }
+               snoop(&dev->dev, "control write: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", 
+                       ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex);
+               if (usbfs_snoop) {
+                       dev_info(&dev->dev, "control write: data: ");
+                       for (j = 0; j < ctrl.wLength; ++j)
+                               printk ("%02x ", (unsigned char)((char *)ctrl.data)[j]);
+                       printk("\n");
+               }
                i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
                                       ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
        }
        free_page((unsigned long)tbuf);
        if (i<0) {
-               printk(KERN_DEBUG "usbfs: USBDEVFS_CONTROL failed "
-                       "cmd %s dev %d rqt %u rq %u len %u ret %d\n", 
-                       current->comm,
-                      dev->devnum, ctrl.bRequestType, ctrl.bRequest, ctrl.wLength, i);
+               dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "
+                          "failed cmd %s rqt %u rq %u len %u ret %d\n",
+                          current->comm, ctrl.bRequestType, ctrl.bRequest,
+                          ctrl.wLength, i);
        }
        return i;
 }
@@ -649,8 +642,8 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
        }
        kfree(tbuf);
        if (i < 0) {
-               printk(KERN_WARNING "usbfs: USBDEVFS_BULK failed dev %d ep 0x%x len %u ret %d\n", 
-                      dev->devnum, bulk.ep, bulk.len, i);
+               dev_warn(&dev->dev, "usbfs: USBDEVFS_BULK failed "
+                        "ep 0x%x len %u ret %d\n", bulk.ep, bulk.len, i);
                return i;
        }
        return len2;
@@ -695,20 +688,22 @@ static int proc_clearhalt(struct dev_state *ps, void __user *arg)
 static int proc_getdriver(struct dev_state *ps, void __user *arg)
 {
        struct usbdevfs_getdriver gd;
-       struct usb_interface *interface;
+       struct usb_interface *intf;
        int ret;
 
        if (copy_from_user(&gd, arg, sizeof(gd)))
                return -EFAULT;
-       if ((ret = findintfif(ps->dev, gd.interface)) < 0)
-               return ret;
-       interface = ps->dev->actconfig->interface[ret];
-       if (!interface->dev.driver)
-               return -ENODATA;
-       strncpy(gd.driver, interface->dev.driver->name, sizeof(gd.driver));
-       if (copy_to_user(arg, &gd, sizeof(gd)))
-               return -EFAULT;
-       return 0;
+       down_read(&usb_bus_type.subsys.rwsem);
+       intf = usb_ifnum_to_if(ps->dev, gd.interface);
+       if (!intf || !intf->dev.driver)
+               ret = -ENODATA;
+       else {
+               strncpy(gd.driver, intf->dev.driver->name,
+                               sizeof(gd.driver));
+               ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);
+       }
+       up_read(&usb_bus_type.subsys.rwsem);
+       return ret;
 }
 
 static int proc_connectinfo(struct dev_state *ps, void __user *arg)
@@ -724,31 +719,21 @@ static int proc_connectinfo(struct dev_state *ps, void __user *arg)
 
 static int proc_resetdevice(struct dev_state *ps)
 {
-       /* FIXME when usb_reset_device() is fixed we'll need to grab
-        * ps->dev->serialize before calling it.
-        */
-       return usb_reset_device(ps->dev);
+       return __usb_reset_device(ps->dev);
 
 }
 
 static int proc_setintf(struct dev_state *ps, void __user *arg)
 {
        struct usbdevfs_setinterface setintf;
-       struct usb_interface *interface;
        int ret;
 
        if (copy_from_user(&setintf, arg, sizeof(setintf)))
                return -EFAULT;
-       if ((ret = findintfif(ps->dev, setintf.interface)) < 0)
+       if ((ret = checkintf(ps, setintf.interface)))
                return ret;
-       interface = ps->dev->actconfig->interface[ret];
-       if (interface->dev.driver) {
-               if ((ret = checkintf(ps, ret)))
-                       return ret;
-       }
-       if (usb_set_interface(ps->dev, setintf.interface, setintf.altsetting))
-               return -EINVAL;
-       return 0;
+       return usb_set_interface(ps->dev, setintf.interface,
+                       setintf.altsetting);
 }
 
 static int proc_setconfig(struct dev_state *ps, void __user *arg)
@@ -760,7 +745,6 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
        if (get_user(u, (unsigned int __user *)arg))
                return -EFAULT;
 
-       down(&ps->dev->serialize);
        actconfig = ps->dev->actconfig;
  
        /* Don't touch the device if any interfaces are claimed.
@@ -796,7 +780,6 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
                else
                        status = usb_set_configuration(ps->dev, u);
        }
-       up(&ps->dev->serialize);
 
        return status;
 }
@@ -809,7 +792,7 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
        struct async *as;
        struct usb_ctrlrequest *dr = NULL;
        unsigned int u, totlen, isofrmlen;
-       int ret, interval = 0, intf = -1;
+       int ret, interval = 0, ifnum = -1;
 
        if (copy_from_user(&uurb, arg, sizeof(uurb)))
                return -EFAULT;
@@ -821,9 +804,9 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
        if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX))
                return -EINVAL;
        if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
-               if ((intf = findintfep(ps->dev, uurb.endpoint)) < 0)
-                       return intf;
-               if ((ret = checkintf(ps, intf)))
+               if ((ifnum = findintfep(ps->dev, uurb.endpoint)) < 0)
+                       return ifnum;
+               if ((ret = checkintf(ps, ifnum)))
                        return ret;
        }
        switch(uurb.type) {
@@ -873,10 +856,13 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
                /* arbitrary limit */
                if (uurb.number_of_packets < 1 || uurb.number_of_packets > 128)
                        return -EINVAL;
+               if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint)))
+                       return -ENOENT;
+               interval = 1 << min (15, ep_desc->bInterval - 1);
                isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb.number_of_packets;
                if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
                        return -ENOMEM;
-               if (copy_from_user(isopkt, &((struct usbdevfs_urb *)arg)->iso_frame_desc, isofrmlen)) {
+               if (copy_from_user(isopkt, &((struct usbdevfs_urb __user *)arg)->iso_frame_desc, isofrmlen)) {
                        kfree(isopkt);
                        return -EFAULT;
                }
@@ -898,7 +884,10 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
                uurb.number_of_packets = 0;
                if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint)))
                        return -ENOENT;
-               interval = ep_desc->bInterval;
+               if (ps->dev->speed == USB_SPEED_HIGH)
+                       interval = 1 << min (15, ep_desc->bInterval - 1);
+               else
+                       interval = ep_desc->bInterval;
                if (uurb.buffer_length > 16384)
                        return -EINVAL;
                if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
@@ -947,7 +936,7 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
        else
                as->userbuffer = NULL;
        as->signr = uurb.signr;
-       as->intf = intf;
+       as->ifnum = ifnum;
        as->task = current;
        if (!(uurb.endpoint & USB_DIR_IN)) {
                if (copy_from_user(as->urb->transfer_buffer, uurb.buffer, as->urb->transfer_buffer_length)) {
@@ -957,7 +946,7 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
        }
         async_newpending(as);
         if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
-               printk(KERN_DEBUG "usbfs: usb_submit_urb returned %d\n", ret);
+               dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret);
                 async_removepending(as);
                 free_async(as);
                 return ret;
@@ -1012,18 +1001,19 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg)
         DECLARE_WAITQUEUE(wait, current);
        struct async *as = NULL;
        void __user *addr;
+       struct usb_device *dev = ps->dev;
        int ret;
 
        add_wait_queue(&ps->wait, &wait);
-       while (ps->dev) {
+       while (connected(dev)) {
                __set_current_state(TASK_INTERRUPTIBLE);
                if ((as = async_getcompleted(ps)))
                        break;
                if (signal_pending(current))
                        break;
-               up_read(&ps->devsem);
+               up(&dev->serialize);
                schedule();
-               down_read(&ps->devsem);
+               down(&dev->serialize);
        }
        remove_wait_queue(&ps->wait, &wait);
        set_current_state(TASK_RUNNING);
@@ -1033,7 +1023,7 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg)
                free_async(as);
                if (ret)
                        return ret;
-               if (put_user(addr, (void **)arg))
+               if (put_user(addr, (void __user * __user *)arg))
                        return -EFAULT;
                return 0;
        }
@@ -1055,7 +1045,7 @@ static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)
        free_async(as);
        if (ret)
                return ret;
-       if (put_user(addr, (void **)arg))
+       if (put_user(addr, (void __user * __user *)arg))
                return -EFAULT;
        return 0;
 }
@@ -1075,28 +1065,23 @@ static int proc_disconnectsignal(struct dev_state *ps, void __user *arg)
 
 static int proc_claiminterface(struct dev_state *ps, void __user *arg)
 {
-       unsigned int intf;
-       int ret;
+       unsigned int ifnum;
 
-       if (get_user(intf, (unsigned int __user *)arg))
+       if (get_user(ifnum, (unsigned int __user *)arg))
                return -EFAULT;
-       if ((ret = findintfif(ps->dev, intf)) < 0)
-               return ret;
-       return claimintf(ps, ret);
+       return claimintf(ps, ifnum);
 }
 
 static int proc_releaseinterface(struct dev_state *ps, void __user *arg)
 {
-       unsigned int intf;
+       unsigned int ifnum;
        int ret;
 
-       if (get_user(intf, (unsigned int __user *)arg))
+       if (get_user(ifnum, (unsigned int __user *)arg))
                return -EFAULT;
-       if ((ret = findintfif(ps->dev, intf)) < 0)
-               return ret;
-       if ((ret = releaseintf(ps, intf)) < 0)
+       if ((ret = releaseintf(ps, ifnum)) < 0)
                return ret;
-       destroy_async_on_interface (ps, intf);
+       destroy_async_on_interface (ps, ifnum);
        return 0;
 }
 
@@ -1106,7 +1091,7 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
        int                     size;
        void                    *buf = 0;
        int                     retval = 0;
-       struct usb_interface    *ifp = 0;
+       struct usb_interface    *intf = 0;
        struct usb_driver       *driver = 0;
 
        /* get input parameters and alloc buffer */
@@ -1125,26 +1110,25 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
                }
        }
 
-       if (!ps->dev) {
+       if (!connected(ps->dev)) {
                if (buf)
                        kfree(buf);
                return -ENODEV;
        }
 
-       down(&ps->dev->serialize);
        if (ps->dev->state != USB_STATE_CONFIGURED)
                retval = -ENODEV;
-       else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
+       else if (!(intf = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
                retval = -EINVAL;
        else switch (ctrl.ioctl_code) {
 
        /* disconnect kernel driver from interface */
        case USBDEVFS_DISCONNECT:
                down_write(&usb_bus_type.subsys.rwsem);
-               if (ifp->dev.driver) {
-                       driver = to_usb_driver(ifp->dev.driver);
-                       dev_dbg (&ifp->dev, "disconnect by usbfs\n");
-                       usb_driver_release_interface(driver, ifp);
+               if (intf->dev.driver) {
+                       driver = to_usb_driver(intf->dev.driver);
+                       dev_dbg (&intf->dev, "disconnect by usbfs\n");
+                       usb_driver_release_interface(driver, intf);
                } else
                        retval = -ENODATA;
                up_write(&usb_bus_type.subsys.rwsem);
@@ -1152,24 +1136,23 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
 
        /* let kernel drivers try to (re)bind to the interface */
        case USBDEVFS_CONNECT:
-               bus_rescan_devices(ifp->dev.bus);
+               bus_rescan_devices(intf->dev.bus);
                break;
 
        /* talk directly to the interface's driver */
        default:
                down_read(&usb_bus_type.subsys.rwsem);
-               if (ifp->dev.driver)
-                       driver = to_usb_driver(ifp->dev.driver);
+               if (intf->dev.driver)
+                       driver = to_usb_driver(intf->dev.driver);
                if (driver == 0 || driver->ioctl == 0) {
                        retval = -ENOTTY;
                } else {
-                       retval = driver->ioctl (ifp, ctrl.ioctl_code, buf);
+                       retval = driver->ioctl (intf, ctrl.ioctl_code, buf);
                        if (retval == -ENOIOCTLCMD)
                                retval = -ENOTTY;
                }
                up_read(&usb_bus_type.subsys.rwsem);
        }
-       up(&ps->dev->serialize);
 
        /* cleanup and return */
        if (retval >= 0
@@ -1190,95 +1173,115 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
 static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct dev_state *ps = (struct dev_state *)file->private_data;
+       struct usb_device *dev = ps->dev;
+       void __user *p = (void __user *)arg;
        int ret = -ENOTTY;
 
        if (!(file->f_mode & FMODE_WRITE))
                return -EPERM;
-       down_read(&ps->devsem);
-       if (!ps->dev) {
-               up_read(&ps->devsem);
+       down(&dev->serialize);
+       if (!connected(dev)) {
+               up(&dev->serialize);
                return -ENODEV;
        }
+
        switch (cmd) {
        case USBDEVFS_CONTROL:
-               ret = proc_control(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: CONTROL\n", __FUNCTION__);
+               ret = proc_control(ps, p);
                if (ret >= 0)
                        inode->i_mtime = CURRENT_TIME;
                break;
 
        case USBDEVFS_BULK:
-               ret = proc_bulk(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: BULK\n", __FUNCTION__);
+               ret = proc_bulk(ps, p);
                if (ret >= 0)
                        inode->i_mtime = CURRENT_TIME;
                break;
 
        case USBDEVFS_RESETEP:
-               ret = proc_resetep(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: RESETEP\n", __FUNCTION__);
+               ret = proc_resetep(ps, p);
                if (ret >= 0)
                        inode->i_mtime = CURRENT_TIME;
                break;
 
        case USBDEVFS_RESET:
+               snoop(&dev->dev, "%s: RESET\n", __FUNCTION__);
                ret = proc_resetdevice(ps);
                break;
 
        case USBDEVFS_CLEAR_HALT:
-               ret = proc_clearhalt(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: CLEAR_HALT\n", __FUNCTION__);
+               ret = proc_clearhalt(ps, p);
                if (ret >= 0)
                        inode->i_mtime = CURRENT_TIME;
                break;
 
        case USBDEVFS_GETDRIVER:
-               ret = proc_getdriver(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: GETDRIVER\n", __FUNCTION__);
+               ret = proc_getdriver(ps, p);
                break;
 
        case USBDEVFS_CONNECTINFO:
-               ret = proc_connectinfo(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: CONNECTINFO\n", __FUNCTION__);
+               ret = proc_connectinfo(ps, p);
                break;
 
        case USBDEVFS_SETINTERFACE:
-               ret = proc_setintf(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: SETINTERFACE\n", __FUNCTION__);
+               ret = proc_setintf(ps, p);
                break;
 
        case USBDEVFS_SETCONFIGURATION:
-               ret = proc_setconfig(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: SETCONFIGURATION\n", __FUNCTION__);
+               ret = proc_setconfig(ps, p);
                break;
 
        case USBDEVFS_SUBMITURB:
-               ret = proc_submiturb(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: SUBMITURB\n", __FUNCTION__);
+               ret = proc_submiturb(ps, p);
                if (ret >= 0)
                        inode->i_mtime = CURRENT_TIME;
                break;
 
        case USBDEVFS_DISCARDURB:
-               ret = proc_unlinkurb(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: DISCARDURB\n", __FUNCTION__);
+               ret = proc_unlinkurb(ps, p);
                break;
 
        case USBDEVFS_REAPURB:
-               ret = proc_reapurb(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: REAPURB\n", __FUNCTION__);
+               ret = proc_reapurb(ps, p);
                break;
 
        case USBDEVFS_REAPURBNDELAY:
-               ret = proc_reapurbnonblock(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: REAPURBDELAY\n", __FUNCTION__);
+               ret = proc_reapurbnonblock(ps, p);
                break;
 
        case USBDEVFS_DISCSIGNAL:
-               ret = proc_disconnectsignal(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: DISCSIGNAL\n", __FUNCTION__);
+               ret = proc_disconnectsignal(ps, p);
                break;
 
        case USBDEVFS_CLAIMINTERFACE:
-               ret = proc_claiminterface(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __FUNCTION__);
+               ret = proc_claiminterface(ps, p);
                break;
 
        case USBDEVFS_RELEASEINTERFACE:
-               ret = proc_releaseinterface(ps, (void __user *)arg);
+               snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __FUNCTION__);
+               ret = proc_releaseinterface(ps, p);
                break;
 
        case USBDEVFS_IOCTL:
-               ret = proc_ioctl(ps, (void __user *) arg);
+               snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
+               ret = proc_ioctl(ps, p);
                break;
        }
-       up_read(&ps->devsem);
+       up(&dev->serialize);
        if (ret >= 0)
                inode->i_atime = CURRENT_TIME;
        return ret;
@@ -1293,7 +1296,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai
        poll_wait(file, &ps->wait, wait);
        if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
                mask |= POLLOUT | POLLWRNORM;
-       if (!ps->dev)
+       if (!connected(ps->dev))
                mask |= POLLERR | POLLHUP;
        return mask;
 }