Hi, all
Please look at this patch. It contains at least 500 microseconds delay before
сonsistent usb_control_msg() calls. Reset patch is also included, but
disabled by default.
In my test I never get -110 error. -32 returned in case of incorrect control
value (for example changing white balance, when it's in auto mode), but this
must not be a problem and never leads to -110.
Regards, Evgeny
diff -u old/uvc_driver.c new/uvc_driver.c
--- old/uvc_driver.c 2006-11-10 13:33:32.000000000 +0300
+++ new/uvc_driver.c 2006-11-13 03:41:52.000000000 +0300
@@ -147,6 +147,52 @@
return 0;
}
+#ifdef UVC_RESET_ON_TIMEOUT
+/*
+ * 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;
+}
+#endif
+
+
/* 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
@@ -1199,9 +1245,23 @@
* parameters.
*/
if ((ret = uvc_video_init(&dev->video)) < 0) {
+#ifdef UVC_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;
+#endif
}
/* Register the device with V4L. */
@@ -1331,6 +1391,7 @@
dev->udev = usb_get_dev(udev);
dev->intf = usb_get_intf(intf);
dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
+ dev->last_ctrl_msg = 0;
/* Parse the Video Class control descriptor */
if (uvc_parse_control(dev) < 0) {
фПМШЛП Ч new: uvc_driver.c.orig
diff -u old/uvc_v4l2.c new/uvc_v4l2.c
--- old/uvc_v4l2.c 2006-11-04 22:14:32.000000000 +0300
+++ new/uvc_v4l2.c 2006-11-13 03:42:30.000000000 +0300
@@ -434,6 +434,12 @@
mutex_unlock(&video->queue.mutex);
}
+#ifdef UVC_RESET_ON_TIMEOUT
+ /* leave usb device in a clean state */
+ if (video->dev->state & UVC_DEV_IOERROR)
+ uvc_video_reinit(video);
+#endif
+
/* Release the file handle. */
uvc_dismiss_privileges(handle);
kfree(handle);
diff -u old/uvc_video.c new/uvc_video.c
--- old/uvc_video.c 2006-11-04 22:14:32.000000000 +0300
+++ new/uvc_video.c 2006-11-13 03:43:05.000000000 +0300
@@ -38,13 +38,26 @@
: usb_sndctrlpipe(dev->udev, 0);
type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
+ if (time_before(jiffies,dev->last_ctrl_msg + 1)) {
+//At least 500 microseconds delay
+ udelay(500);
+ }
+
ret = usb_control_msg(dev->udev, pipe, query, type, cs << 8,
unit << 8 | intfnum, data, size, UVC_CTRL_TIMEOUT);
+ dev->last_ctrl_msg = 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);
+
+#ifdef UVC_RESET_ON_TIMEOUT
+ if (ret == -ETIMEDOUT) // reset the device in case of -110 error
+ dev->state |= UVC_DEV_IOERROR;
+#endif
+
return -EIO;
}
diff -u old/uvcvideo.h new/uvcvideo.h
--- old/uvcvideo.h 2006-11-04 22:14:32.000000000 +0300
+++ new/uvcvideo.h 2006-11-13 03:46:48.000000000 +0300
@@ -234,6 +234,9 @@
#define UVC_CTRL_TIMEOUT 300
+/* Uncomment this to enable reset-on-timeout*/
+/*#define UVC_RESET_ON_TIMEOUT*/
+
/* ------------------------------------------------------------------------
* Structures.
*/
@@ -511,6 +514,11 @@
enum uvc_device_state {
UVC_DEV_DISCONNECTED = 1,
+
+#ifdef UVC_RESET_ON_TIMEOUT
+ UVC_DEV_IOERROR = 2,
+#endif
+
};
struct uvc_device {
@@ -519,6 +527,7 @@
int intfnum;
enum uvc_device_state state;
+ unsigned long last_ctrl_msg;
struct kref kref;
struct list_head list;
@@ -664,6 +673,14 @@
extern struct usb_host_endpoint *uvc_find_endpoint(
struct usb_host_interface *alts, __u8 epaddr);
+
+#ifdef UVC_RESET_ON_TIMEOUT
+
+extern int uvc_video_reinit(struct uvc_video_device *video);
+extern int uvc_usb_reset(struct uvc_device *dev);
+
+#endif
+
#endif /* __KERNEL__ */
#endif
_______________________________________________
Linux-uvc-devel mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/linux-uvc-devel