--- local_tree.orig/drivers/usb/core/devio.c 2004-07-26 00:55:05.000000000 +0200 +++ local_tree/drivers/usb/core/devio.c 2004-07-26 12:17:18.893769249 +0200 @@ -530,71 +530,152 @@ return 0; } +static void wakeup_completion(struct urb *urb, struct pt_regs *regs) +{ + complete((struct completion *)urb->context); +} + +static void timeout_kill(unsigned long data) +{ + struct urb *urb = (struct urb *) data; + usb_unlink_urb(urb); +} + +static int start_wait_urb(struct usb_device *dev, struct urb *urb, int timeout, int* actual_length) +{ + struct completion done; + struct timer_list timer; + int status; + + init_completion(&done); + urb->context = &done; + urb->complete = wakeup_completion; + urb->transfer_flags |= URB_ASYNC_UNLINK; + urb->actual_length = 0; + status = usb_submit_urb(urb, GFP_NOIO); + + if (status == 0) { + if (timeout > 0) { + init_timer(&timer); + timer.expires = jiffies + timeout; + timer.data = (unsigned long)urb; + timer.function = timeout_kill; + /* grr. timeout _should_ include submit delays. */ + add_timer(&timer); + } + up(&dev->serialize); + wait_for_completion(&done); + down(&dev->serialize); + status = urb->status; + /* note: HCDs return ETIMEDOUT for other reasons too */ + if (status == -ECONNRESET) + status = -ETIMEDOUT; + if (timeout > 0) + del_timer_sync(&timer); + } + + if (actual_length) + *actual_length = urb->actual_length; + return status; +} + static int proc_control(struct dev_state *ps, void __user *arg) { - struct usb_device *dev = ps->dev; struct usbdevfs_ctrltransfer ctrl; - unsigned int tmo; - unsigned char *tbuf; - int i, j, ret; + struct usb_device *dev = ps->dev; + struct usb_ctrlrequest *dr = NULL; + unsigned char *tbuf = NULL; + struct urb *urb = NULL; + int dir_in, j, length, ret; + unsigned int pipe, timeout; if (copy_from_user(&ctrl, arg, sizeof(ctrl))) return -EFAULT; - if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex))) - return ret; - if (ctrl.wLength > PAGE_SIZE) + length = ctrl.wLength; + if (length < 0 || length > PAGE_SIZE) return -EINVAL; if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) return -ENOMEM; - tmo = (ctrl.timeout * HZ + 999) / 1000; - if (ctrl.bRequestType & 0x80) { - if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) { - 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)(tbuf)[j]); - printk("\n"); - } - if (copy_to_user(ctrl.data, tbuf, ctrl.wLength)) { - free_page((unsigned long)tbuf); - return -EFAULT; - } + dir_in = ctrl.bRequestType & USB_DIR_IN; + if (dir_in) { + if (length && !access_ok(VERIFY_WRITE, ctrl.data, length)) { + ret = -EINVAL; + goto out_free; } } else { - if (ctrl.wLength) { - if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) { - free_page((unsigned long)tbuf); - return -EFAULT; + if (length) { + if (copy_from_user(tbuf, ctrl.data, length)) { + ret = -EFAULT; + goto out_free; } } - snoop(&dev->dev, "control write: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", - ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex); + } + snoop(&dev->dev, "control %s: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x wLength=%04x\n", + dir_in ? "read" : "write", ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, ctrl.wLength); + if (usbfs_snoop && !dir_in) { + dev_info(&dev->dev, "control write: data: "); + for (j = 0; j < length; ++j) + printk ("%02x ", tbuf[j]); + printk("\n"); + } + if (!(urb = usb_alloc_urb(0, GFP_KERNEL))) { + ret = -ENOMEM; + goto out_free; + } + if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL))) { + ret = -ENOMEM; + goto out_free; + } + down(&dev->serialize); + if (!connected(dev)) { + ret = -ENODEV; + goto out_release; + } + if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex))) + goto out_release; + if (dir_in) + pipe = usb_rcvctrlpipe(dev, 0); + else + pipe = usb_sndctrlpipe(dev, 0); + timeout = (ctrl.timeout * HZ + 999) / 1000; + dr->bRequestType= ctrl.bRequestType; + dr->bRequest = ctrl.bRequest; + dr->wValue = cpu_to_le16p(&ctrl.wValue); + dr->wIndex = cpu_to_le16p(&ctrl.wIndex); + dr->wLength = cpu_to_le16p(&ctrl.wLength); + usb_fill_control_urb(urb, dev, pipe, (unsigned char*)dr, tbuf, length, NULL, 0); + ret = start_wait_urb(dev, urb, timeout, &length); + up(&dev->serialize); + if (ret < 0) { + dev_warn(&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, ret); + goto out_free; + } + if (dir_in && length) { if (usbfs_snoop) { - dev_info(&dev->dev, "control write: data: "); - for (j = 0; j < ctrl.wLength; ++j) - printk ("%02x ", (unsigned char)(tbuf)[j]); + dev_info(&dev->dev, "control read: data "); + for (j = 0; j < length; ++j) + printk ("%02x ", tbuf[j]); printk("\n"); } - i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, - ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); + if (copy_to_user(ctrl.data, tbuf, length)) { + ret = -EFAULT; + goto out_free; + } } + kfree(dr); + usb_free_urb(urb); free_page((unsigned long)tbuf); - if (i<0) { - 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; + return ret; +out_release: + up(&dev->serialize); +out_free: + kfree(dr); + usb_free_urb(urb); + free_page((unsigned long)tbuf); + return ret; } static int proc_bulk(struct dev_state *ps, void __user *arg) @@ -1287,16 +1368,10 @@ switch (cmd) { case USBDEVFS_CONTROL: - down(&dev->serialize); - if (!connected(dev)) { - up(&dev->serialize); - return -ENODEV; - } snoop(&dev->dev, "%s: CONTROL\n", __FUNCTION__); ret = proc_control(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; - up(&dev->serialize); break; case USBDEVFS_BULK:
------------------------------------------------------- This SF.Net email is sponsored by OSTG. Have you noticed the changes on Linux.com, ITManagersJournal and NewsForge in the past few weeks? Now, one more big change to announce. We are now OSTG- Open Source Technology Group. Come see the changes on the new OSTG site. www.ostg.com _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel