public inbox for linux-media@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] uvcvideo: RESET_ON_TIMOUT Quirk
@ 2008-07-12 19:49 pat-lkml
  0 siblings, 0 replies; only message in thread
From: pat-lkml @ 2008-07-12 19:49 UTC (permalink / raw)
  To: Linux and Kernel Video

[-- Attachment #1: Type: text/plain, Size: 416 bytes --]

This patch provides another quirk that causes the driver to reset the 
device on -110.  This is a reworking of the patch provided by Michel 
Stempin in January.  I've tested it and it works for me with my Quickcam 
Orbit MP.  I'm not certain that it's a candidate for inclusion, 
especially in it's current state, but I thought I'd put it out there for 
others to try, and possibly make mainline worthy.


Pat Erley

[-- Attachment #2: reset_on_timeout_quirk.diff --]
[-- Type: text/plain, Size: 10816 bytes --]

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

[-- Attachment #3: Type: text/plain, Size: 164 bytes --]

--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2008-07-12 20:44 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-12 19:49 [PATCH] uvcvideo: RESET_ON_TIMOUT Quirk pat-lkml

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox