[PATCH v2] uvcvideo: Add DEV_RESET_ON_TIMEOUT Quirk

DORMANTno replies

From: Pat Erley <hidden>
Date: 2009-03-14 05:26:20

This patch provides a quirk that causes uvcvideo to reset certain
devices on -ETIMEOUT.  This is required for my Quickcam Orbit MP 
to function.  This is based on a patch provided by Michel Stempin
in January of 2008.  I've reworked it to be less intrusive for 
other devices.

Tested with:
 Philips SPC 1300NC Webcam (0471:0331)
 Logitech Quickcam Orbit MP (046d:08c2)
 
Signed-off-by: Pat Erley <redacted>
---
I've been using/updating this patch for 6 months regularly with
both tested devices, and have not had a problem with it.  


diff -r 39c257ae5063 linux/drivers/media/video/uvc/uvc_driver.c
--- a/linux/drivers/media/video/uvc/uvc_driver.c	Tue Mar 10 18:32:24 2009 -0300
+++ b/linux/drivers/media/video/uvc/uvc_driver.c	Sat Mar 14 01:01:08 2009 -0400
@@ -1510,7 +1510,25 @@
 	if ((ret = uvc_video_init(&dev->video)) < 0) {
 		uvc_printk(KERN_ERR, "Failed to initialize the device "
 			"(%d).\n", ret);
-		return ret;
+		if(dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT) {
+			uvc_printk(KERN_ERR, "Trying to reset\n");
+			
+			if ((ret = uvc_usb_reset(dev))) {
+				uvc_printk(KERN_ERR, 
+						"Reset failed (%d)\n",
+						ret);
+				return ret;
+			}
+
+			if ((ret = uvc_video_init(&dev->video)) < 0) {
+				uvc_printk(KERN_ERR, 
+						"Init after reset"
+						" failed(%d)\n", ret);
+				return ret;
+			}
+		} else {
+			return ret;
+		}
 	}
 
 	/* Register the device with V4L. */
@@ -1802,7 +1820,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,
diff -r 39c257ae5063 linux/drivers/media/video/uvc/uvc_v4l2.c
--- a/linux/drivers/media/video/uvc/uvc_v4l2.c	Tue Mar 10 18:32:24 2009 -0300
+++ b/linux/drivers/media/video/uvc/uvc_v4l2.c	Sat Mar 14 01:01:08 2009 -0400
@@ -466,6 +466,13 @@
 		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);
 	kfree(handle);
diff -r 39c257ae5063 linux/drivers/media/video/uvc/uvc_video.c
--- a/linux/drivers/media/video/uvc/uvc_video.c	Tue Mar 10 18:32:24 2009 -0300
+++ b/linux/drivers/media/video/uvc/uvc_video.c	Sat Mar 14 01:01:08 2009 -0400
@@ -55,6 +55,12 @@
 		uvc_printk(KERN_ERR, "Failed to query (%u) UVC control %u "
 			"(unit %u) : %d (exp. %u).\n", query, cs, unit, ret,
 			size);
+		
+		/* Reset 'Quirky' device on timeout (-110) */
+		if((dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT) &&
+		   (ret == -ETIMEDOUT))
+			dev->state |= UVC_DEV_IOERROR;   	
+			
 		return -EIO;
 	}
 
@@ -1160,3 +1166,43 @@
 	return uvc_init_video(video, GFP_KERNEL);
 }
 
+/* 
+ * 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;
+}
diff -r 39c257ae5063 linux/drivers/media/video/uvc/uvcvideo.h
--- a/linux/drivers/media/video/uvc/uvcvideo.h	Tue Mar 10 18:32:24 2009 -0300
+++ b/linux/drivers/media/video/uvc/uvcvideo.h	Sat Mar 14 01:01:08 2009 -0400
@@ -316,6 +316,7 @@
 #define UVC_QUIRK_IGNORE_SELECTOR_UNIT	0x00000020
 #define UVC_QUIRK_PRUNE_CONTROLS	0x00000040
 #define UVC_QUIRK_FIX_BANDWIDTH		0x00000080
+#define UVC_QUIRK_DEV_RESET_ON_TIMEOUT	0x00000100
 
 /* Format flags */
 #define UVC_FMT_FLAG_COMPRESSED		0x00000001
@@ -622,6 +623,7 @@
 
 enum uvc_device_state {
 	UVC_DEV_DISCONNECTED = 1,
+	UVC_DEV_IOERROR = 2,
 };
 
 struct uvc_device {
@@ -815,6 +817,9 @@
 		struct usb_host_interface *alts, __u8 epaddr);
 
 /* Quirks support */
+extern int uvc_video_reinit(struct uvc_video_device *video);
+extern int uvc_usb_reset(struct uvc_device *dev);
+
 void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
 		struct uvc_buffer *buf);
 

--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help