Only in linux-uvc-0.1.0_pre223-resetpatch: .tmp_versions Only in linux-uvc-0.1.0_pre223-resetpatch: .uvc_ctrl.o.cmd Only in linux-uvc-0.1.0_pre223-resetpatch: .uvc_driver.o.cmd Only in linux-uvc-0.1.0_pre223-resetpatch: .uvc_isight.o.cmd Only in linux-uvc-0.1.0_pre223-resetpatch: .uvc_queue.o.cmd Only in linux-uvc-0.1.0_pre223-resetpatch: .uvc_status.o.cmd Only in linux-uvc-0.1.0_pre223-resetpatch: .uvc_v4l2.o.cmd Only in linux-uvc-0.1.0_pre223-resetpatch: .uvc_video.o.cmd Only in linux-uvc-0.1.0_pre223-resetpatch: .uvcvideo.ko.cmd Only in linux-uvc-0.1.0_pre223-resetpatch: .uvcvideo.mod.o.cmd Only in linux-uvc-0.1.0_pre223-resetpatch: .uvcvideo.o.cmd Only in linux-uvc-0.1.0_pre223-resetpatch: Module.symvers Only in linux-uvc-0.1.0_pre223-resetpatch: modules.order Only in linux-uvc-0.1.0_pre223-resetpatch: quirks Only in linux-uvc-0.1.0_pre223-resetpatch: uvc_ctrl.o diff -u linux-uvc-0.1.0_pre223/uvc_driver.c linux-uvc-0.1.0_pre223-resetpatch/uvc_driver.c --- linux-uvc-0.1.0_pre223/uvc_driver.c 2008-07-05 11:52:01.000000000 -0400 +++ linux-uvc-0.1.0_pre223-resetpatch/uvc_driver.c 2008-07-12 15:42:09.000000000 -0400 @@ -145,6 +145,50 @@ return 0; } +/* + * Reset and Re-Initialize video device + */ +int uvc_video_reinit(struct uvc_video_device *video) +{ + int ret; + + if ((ret = uvc_usb_reset(video->dev)) < 0) + return ret; + + if ((ret = uvc_set_video_ctrl(video, &video->streaming->ctrl, 0)) < 0) { + uvc_printk(KERN_DEBUG, "uvc_video_reinit: Unable to commit format " + "(%d).\n", ret); + return ret; + } + + return 0; +} + + +int uvc_usb_reset(struct uvc_device *dev) +{ + int l, ret; + + l = usb_lock_device_for_reset(dev->udev, dev->intf); + + if (l >= 0) { + ret = usb_reset_device(dev->udev); + if (l) + usb_unlock_device(dev->udev); + } + else + ret = -EBUSY; + + if (ret) + uvc_printk(KERN_DEBUG, "uvc_usb_reset: Unable to reset usb device" + "(%d).\n", ret); + else + dev->state &= ~UVC_DEV_IOERROR; + + return ret; +} + + /* Simplify a fraction using a simple continued fraction decomposition. The * idea here is to convert fractions such as 333333/10000000 to 1/30 using * 32 bit arithmetic only. The algorithm is not perfect and relies upon two @@ -1447,9 +1491,24 @@ * parameters. */ if ((ret = uvc_video_init(&dev->video)) < 0) { + if(dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT) + { + uvc_printk(KERN_ERR, "Failed to initialize the device, " + "(%d). trying to reset ...\n", ret); + + if ((ret = uvc_usb_reset(dev))) + return ret; + + if ((ret = uvc_video_init(&dev->video)) < 0) { + uvc_printk(KERN_ERR, "Failed to initialize the device " + "(%d).\n", ret); + return ret; + } + } else { uvc_printk(KERN_ERR, "Failed to initialize the device " "(%d).\n", ret); return ret; + } } /* Register the device with V4L. */ @@ -1563,6 +1622,7 @@ dev->udev = usb_get_dev(udev); dev->intf = usb_get_intf(intf); dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber; + dev->last_urb = 0; dev->quirks = id->driver_info | uvc_quirks_param; if (udev->product != NULL) @@ -1750,7 +1810,8 @@ .idProduct = 0x08c2, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0 }, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_DEV_RESET_ON_TIMEOUT}, /* Logitech Quickcam Pro for Notebook */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, Only in linux-uvc-0.1.0_pre223-resetpatch: uvc_driver.o Only in linux-uvc-0.1.0_pre223-resetpatch: uvc_isight.o Only in linux-uvc-0.1.0_pre223-resetpatch: uvc_queue.o diff -u linux-uvc-0.1.0_pre223/uvc_status.c linux-uvc-0.1.0_pre223-resetpatch/uvc_status.c --- linux-uvc-0.1.0_pre223/uvc_status.c 2008-07-05 11:52:01.000000000 -0400 +++ linux-uvc-0.1.0_pre223-resetpatch/uvc_status.c 2008-07-07 21:26:37.000000000 -0400 @@ -160,9 +160,15 @@ /* Resubmit the URB. */ urb->interval = dev->int_ep->desc.bInterval; if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n", - ret); + if (ret == -EL2NSYNC) { + if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { + uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n", + ret); + } + } + } + dev->last_urb = jiffies; } int uvc_status_init(struct uvc_device *dev) @@ -170,6 +176,7 @@ struct usb_host_endpoint *ep = dev->int_ep; unsigned int pipe; int interval; + int ret = 0; if (ep == NULL) return 0; @@ -194,7 +201,16 @@ dev->status, sizeof dev->status, uvc_status_complete, dev, interval); - return usb_submit_urb(dev->int_urb, GFP_KERNEL); + if ((ret = usb_submit_urb(dev->int_urb, GFP_KERNEL)) < 0) { + if (ret == -EL2NSYNC) { + if ((ret = usb_submit_urb(dev->int_urb, GFP_KERNEL)) < 0) { + uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n", + ret); + } + } + } + dev->last_urb = jiffies; + return ret; } void uvc_status_cleanup(struct uvc_device *dev) @@ -212,9 +228,19 @@ int uvc_status_resume(struct uvc_device *dev) { + int ret = 0; if (dev->int_urb == NULL) return 0; - return usb_submit_urb(dev->int_urb, GFP_NOIO); + if ((ret = usb_submit_urb(dev->int_urb, GFP_KERNEL)) < 0) { + if (ret == -EL2NSYNC) { + if ((ret = usb_submit_urb(dev->int_urb, GFP_KERNEL)) < 0) { + uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n", + ret); + } + } + } + dev->last_urb = jiffies; + return ret; } Only in linux-uvc-0.1.0_pre223-resetpatch: uvc_status.o diff -u linux-uvc-0.1.0_pre223/uvc_v4l2.c linux-uvc-0.1.0_pre223-resetpatch/uvc_v4l2.c --- linux-uvc-0.1.0_pre223/uvc_v4l2.c 2008-07-05 11:52:01.000000000 -0400 +++ linux-uvc-0.1.0_pre223-resetpatch/uvc_v4l2.c 2008-07-12 15:42:24.000000000 -0400 @@ -457,6 +457,13 @@ "free buffers.\n"); mutex_unlock(&video->queue.mutex); } + + if(video->dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT) + { + /* leave usb device in a clean state */ + if (video->dev->state & UVC_DEV_IOERROR) + uvc_video_reinit(video); + } /* Release the file handle. */ uvc_dismiss_privileges(handle); Only in linux-uvc-0.1.0_pre223-resetpatch: uvc_v4l2.o diff -u linux-uvc-0.1.0_pre223/uvc_video.c linux-uvc-0.1.0_pre223-resetpatch/uvc_video.c --- linux-uvc-0.1.0_pre223/uvc_video.c 2008-07-05 11:52:01.000000000 -0400 +++ linux-uvc-0.1.0_pre223-resetpatch/uvc_video.c 2008-07-12 15:42:49.000000000 -0400 @@ -39,18 +39,40 @@ __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; unsigned int pipe; int ret; + int delayed = 0; pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0) : usb_sndctrlpipe(dev->udev, 0); type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT; + if (dev->last_urb) { + while (time_before(jiffies,dev->last_urb + 2)) { + schedule(); + delayed = 1; + } + } + ret = usb_control_msg(dev->udev, pipe, query, type, cs << 8, unit << 8 | intfnum, data, size, timeout); + dev->last_urb = jiffies; + if (ret != size) { uvc_printk(KERN_ERR, "Failed to query (%u) UVC control %u " "(unit %u) : %d (exp. %u).\n", query, cs, unit, ret, size); + if (delayed) { + uvc_printk(KERN_ERR,"usb_control_msg was delayed\n"); + } else { + uvc_printk(KERN_ERR,"usb_control_msg was NOT delayed\n"); + } + if (dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT) + { + if (ret == -ETIMEDOUT) // reset the device in case of -110 error + dev->state |= UVC_DEV_IOERROR; + } + + return -EIO; } @@ -554,9 +576,15 @@ video->decode(urb, video, buf); if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n", - ret); - } + + if (ret == -EL2NSYNC) { + if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { + uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n", + ret); + } + } + } + video->dev->last_urb = jiffies; } /* @@ -808,6 +836,7 @@ return ret; } } + video->dev->last_urb = jiffies; return 0; } Only in linux-uvc-0.1.0_pre223-resetpatch: uvc_video.o diff -u linux-uvc-0.1.0_pre223/uvcvideo.h linux-uvc-0.1.0_pre223-resetpatch/uvcvideo.h --- linux-uvc-0.1.0_pre223/uvcvideo.h 2008-07-05 11:52:01.000000000 -0400 +++ linux-uvc-0.1.0_pre223-resetpatch/uvcvideo.h 2008-07-12 15:43:13.000000000 -0400 @@ -315,11 +315,13 @@ #define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008 #define UVC_QUIRK_STREAM_NO_FID 0x00000010 #define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020 +#define UVC_QUIRK_DEV_RESET_ON_TIMEOUT 0x00000040 /* Format flags */ #define UVC_FMT_FLAG_COMPRESSED 0x00000001 #define UVC_FMT_FLAG_STREAM 0x00000002 + /* ------------------------------------------------------------------------ * Structures. */ @@ -611,6 +613,7 @@ enum uvc_device_state { UVC_DEV_DISCONNECTED = 1, + UVC_DEV_IOERROR = 2, }; struct uvc_device { @@ -621,6 +624,7 @@ char name[32]; enum uvc_device_state state; + unsigned long last_urb; struct kref kref; struct list_head list; @@ -790,6 +794,9 @@ extern struct usb_host_endpoint *uvc_find_endpoint( struct usb_host_interface *alts, __u8 epaddr); +extern int uvc_video_reinit(struct uvc_video_device *video); +extern int uvc_usb_reset(struct uvc_device *dev); + /* Quirks support */ void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video, struct uvc_buffer *buf); Only in linux-uvc-0.1.0_pre223-resetpatch: uvcvideo.ko Only in linux-uvc-0.1.0_pre223-resetpatch: uvcvideo.mod.c Only in linux-uvc-0.1.0_pre223-resetpatch: uvcvideo.mod.o Only in linux-uvc-0.1.0_pre223-resetpatch: uvcvideo.o Only in linux-uvc-0.1.0_pre223-resetpatch: version.h