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

Reply via email to