[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