> I really love this patch! It works much better than the reset patch for me.
> I am able to
> record alot more times
Nice to read this. Thank you for participation in this work.
> before I get an error, but now I get a new, exciting
> one. This is
> the output from "dmesg | tail":
> uvcvideo: Failed to resubmit isoc URB (-45).
Please try the next version attached.
-45 error seems to be related to usbaudio and audio stream capture. The
solution provided is to resend URB in case of EL2NSYNC error. There are patch
for 2.6.19-rc kernels, that fixed this issue. For older kernels we have to
fix it in driver code.
Please note, that attached patch must be applied to the last revision of split
branch (revision 68)
Feel free to report your results. All we need this driver to be as stable as
possible.
>
> I hope this helps somehow, keep up the great work!
Definitely. I really need testers for this patch.
>
> Regards, Vidar
Regards, Evgeny Marchenko
diff -u old/uvc_driver.c new/uvc_driver.c
--- old/uvc_driver.c 2006-11-16 13:01:31.000000000 +0300
+++ new/uvc_driver.c 2006-11-16 13:58:17.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
@@ -1155,9 +1201,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. */
@@ -1269,6 +1329,7 @@
dev->udev = usb_get_dev(udev);
dev->intf = usb_get_intf(intf);
dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
+ dev->last_urb = 0;
/* Parse the Video Class control descriptor */
if (uvc_parse_control(dev) < 0) {
diff -u old/uvc_v4l2.c new/uvc_v4l2.c
--- old/uvc_v4l2.c 2006-11-16 13:01:31.000000000 +0300
+++ new/uvc_v4l2.c 2006-11-16 13:46:23.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-16 13:01:31.000000000 +0300
+++ new/uvc_video.c 2006-11-16 14:25:53.000000000 +0300
@@ -33,18 +33,35 @@
__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;
+ 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, UVC_CTRL_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");
+ }
+#ifdef UVC_RESET_ON_TIMEOUT
+ if (ret == -ETIMEDOUT) // reset the device in case of -110 error
+ dev->state |= UVC_DEV_IOERROR;
+#endif
+
return -EIO;
}
@@ -351,9 +368,14 @@
/* 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;
}
/*
@@ -442,9 +464,15 @@
}
if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- uvc_printk(KERN_ERR, "Failed to resubmit isoc URB (%d).\n",
- ret);
+
+ if (ret == -EL2NSYNC) {
+ if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ uvc_printk(KERN_ERR, "Failed to resubmit isoc URB (%d).\n",
+ ret);
+ }
}
+ }
+ video->dev->last_urb = jiffies;
}
/*
@@ -543,6 +571,7 @@
return ret;
}
}
+ video->dev->last_urb = jiffies;
return 0;
}
diff -u old/uvcvideo.h new/uvcvideo.h
--- old/uvcvideo.h 2006-11-16 13:01:31.000000000 +0300
+++ new/uvcvideo.h 2006-11-16 14:04:44.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_urb;
struct kref kref;
struct list_head list;
@@ -665,6 +674,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