X-Git-Url: http://git.onelab.eu/?p=linux-2.6.git;a=blobdiff_plain;f=drivers%2Fusb%2Fcore%2Fdevio.c;h=29799129af3ef7534f0268c17aad77132f6d3ffb;hp=ed1296ad92f7d3cb825ee2964de5038abb77b122;hb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;hpb=c449269f45c2cdf53af08c8d0af37472f66539d9 diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index ed1296ad9..29799129a 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -45,6 +45,7 @@ #include #include #include +#include #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; }