* [PATCH] uvcvideo: RESET_ON_TIMOUT Quirk [Against HG]
@ 2008-07-14 4:38 pat-lkml
2008-07-14 4:41 ` pat-lkml
0 siblings, 1 reply; 3+ messages in thread
From: pat-lkml @ 2008-07-14 4:38 UTC (permalink / raw)
To: Linux and Kernel Video
[-- Attachment #1: Type: text/plain, Size: 635 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 updated it so that, aside from the last_urb
field, there are no differences in the code executed for non Quirk
devices. Also, I fixed the whitespace issues that had crept into my
previous patch. There are still some if/else nests that could be
simplified, but I'll save that for another night. I've tested it and it
works for me with my Quickcam Orbit MP. This version is likely safe for
inclusion into the tree.
Signed-off-by: Pat Erley <pat-lkml@erley.org>
[-- Attachment #2: reset_on_timeout_quirk_hg.diff --]
[-- Type: text/plain, Size: 9338 bytes --]
diff -r 0ebffe1cc136 linux/drivers/media/video/uvc/uvc_driver.c
--- a/linux/drivers/media/video/uvc/uvc_driver.c Sat Jul 12 16:50:43 2008 -0300
+++ b/linux/drivers/media/video/uvc/uvc_driver.c Sun Jul 13 20:21:53 2008 -0400
@@ -142,6 +142,47 @@ static __u32 uvc_colorspace(const __u8 p
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
@@ -1444,9 +1485,23 @@ static int uvc_register_video(struct uvc
* parameters.
*/
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, "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. */
@@ -1560,6 +1615,7 @@ static int uvc_probe(struct usb_interfac
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 +1806,8 @@ static struct usb_device_id uvc_ids[] =
.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 0ebffe1cc136 linux/drivers/media/video/uvc/uvc_status.c
--- a/linux/drivers/media/video/uvc/uvc_status.c Sat Jul 12 16:50:43 2008 -0300
+++ b/linux/drivers/media/video/uvc/uvc_status.c Sun Jul 13 20:32:38 2008 -0400
@@ -161,9 +161,24 @@ static void uvc_status_complete(struct u
/* 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(dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT)
+ {
+ uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
+ ret);
+ } else {
+ if (ret == -EL2NSYNC) {
+ if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
+ ret);
+ }
+ } else {
+ uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
+ ret);
+
+ }
+ }
+ }
+ dev->last_urb = jiffies;
}
int uvc_status_init(struct uvc_device *dev)
@@ -171,6 +186,7 @@ int uvc_status_init(struct uvc_device *d
struct usb_host_endpoint *ep = dev->int_ep;
unsigned int pipe;
int interval;
+ int ret = 0;
if (ep == NULL)
return 0;
@@ -195,7 +211,21 @@ int uvc_status_init(struct uvc_device *d
dev->status, sizeof dev->status, uvc_status_complete,
dev, interval);
- return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+ if(dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT) {
+ 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);
+ }
+ }
+ }
+
+ } else {
+ ret = usb_submit_urb(dev->int_urb, GFP_KERNEL);
+ }
+ dev->last_urb = jiffies;
+ return ret;
}
void uvc_status_cleanup(struct uvc_device *dev)
@@ -213,9 +243,25 @@ int uvc_status_suspend(struct uvc_device
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);
-}
-
+ return ret;
+
+ if(dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT) {
+ 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);
+ }
+ }
+ }
+
+ } else {
+ ret = usb_submit_urb(dev->int_urb, GFP_NOIO);
+ }
+
+ dev->last_urb = jiffies;
+ return ret;
+}
+
diff -r 0ebffe1cc136 linux/drivers/media/video/uvc/uvc_v4l2.c
--- a/linux/drivers/media/video/uvc/uvc_v4l2.c Sat Jul 12 16:50:43 2008 -0300
+++ b/linux/drivers/media/video/uvc/uvc_v4l2.c Sun Jul 13 20:33:54 2008 -0400
@@ -456,6 +456,13 @@ static int uvc_v4l2_release(struct inode
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 0ebffe1cc136 linux/drivers/media/video/uvc/uvc_video.c
--- a/linux/drivers/media/video/uvc/uvc_video.c Sat Jul 12 16:50:43 2008 -0300
+++ b/linux/drivers/media/video/uvc/uvc_video.c Sun Jul 13 20:44:41 2008 -0400
@@ -37,18 +37,36 @@ static int __uvc_query_ctrl(struct uvc_d
__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->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT) && (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 (dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT){
+ 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 (ret == -ETIMEDOUT) // reset the device in case of -110 error
+ dev->state |= UVC_DEV_IOERROR;
+ }
return -EIO;
}
@@ -548,9 +566,23 @@ static void uvc_video_complete(struct ur
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 (dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT) {
+ if (ret == -EL2NSYNC) {
+ if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
+ ret);
+ }
+ } else {
+ uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
+ ret);
+
+ }
+ } else {
+ uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
+ ret);
+ }
+ }
+ video->dev->last_urb = jiffies;
}
/*
@@ -802,6 +834,7 @@ static int uvc_init_video(struct uvc_vid
return ret;
}
}
+ video->dev->last_urb = jiffies;
return 0;
}
diff -r 0ebffe1cc136 linux/drivers/media/video/uvc/uvcvideo.h
--- a/linux/drivers/media/video/uvc/uvcvideo.h Sat Jul 12 16:50:43 2008 -0300
+++ b/linux/drivers/media/video/uvc/uvcvideo.h Sun Jul 13 20:46:40 2008 -0400
@@ -314,6 +314,7 @@ struct uvc_xu_control {
#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
@@ -610,6 +611,7 @@ struct uvc_video_device {
enum uvc_device_state {
UVC_DEV_DISCONNECTED = 1,
+ UVC_DEV_IOERROR = 2,
};
struct uvc_device {
@@ -620,6 +622,7 @@ struct uvc_device {
char name[32];
enum uvc_device_state state;
+ unsigned long last_urb;
struct kref kref;
struct list_head list;
@@ -789,6 +792,9 @@ extern struct usb_host_endpoint *uvc_fin
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);
[-- 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] 3+ messages in thread
* Re: [PATCH] uvcvideo: RESET_ON_TIMOUT Quirk [Against HG]
2008-07-14 4:38 [PATCH] uvcvideo: RESET_ON_TIMOUT Quirk [Against HG] pat-lkml
@ 2008-07-14 4:41 ` pat-lkml
2008-07-14 4:44 ` pat-lkml
0 siblings, 1 reply; 3+ messages in thread
From: pat-lkml @ 2008-07-14 4:41 UTC (permalink / raw)
To: Linux and Kernel Video
Wrong patch posted, this one will not build. Correct patch follows shortly.
Pat Erley
--
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] 3+ messages in thread
* Re: [PATCH] uvcvideo: RESET_ON_TIMOUT Quirk [Against HG]
2008-07-14 4:41 ` pat-lkml
@ 2008-07-14 4:44 ` pat-lkml
0 siblings, 0 replies; 3+ messages in thread
From: pat-lkml @ 2008-07-14 4:44 UTC (permalink / raw)
To: Linux and Kernel Video
[-- Attachment #1: Type: text/plain, Size: 629 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 updated it so that, aside from the last_urb
field, there are no differences in the code executed for non Quirk
devices. Also, I fixed the whitespace issues that had crept into my
previous patch. There are still some if/else nests that could be
simplified, but I'll save that for another night. I've tested it and it
works for me with my Quickcam Orbit MP. This version is likely safe for
inclusion into the tree.
Signed-off-by: Pat Erley <pat-lkml@erley.org>
[-- Attachment #2: reset_on_timeout_quirk_hg_corrected.diff --]
[-- Type: text/plain, Size: 9348 bytes --]
diff -r 0ebffe1cc136 linux/drivers/media/video/uvc/uvc_driver.c
--- a/linux/drivers/media/video/uvc/uvc_driver.c Sat Jul 12 16:50:43 2008 -0300
+++ b/linux/drivers/media/video/uvc/uvc_driver.c Sun Jul 13 20:57:37 2008 -0400
@@ -142,6 +142,47 @@ static __u32 uvc_colorspace(const __u8 p
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
@@ -1444,9 +1485,23 @@ static int uvc_register_video(struct uvc
* parameters.
*/
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, "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. */
@@ -1560,6 +1615,7 @@ static int uvc_probe(struct usb_interfac
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 +1806,8 @@ static struct usb_device_id uvc_ids[] =
.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 0ebffe1cc136 linux/drivers/media/video/uvc/uvc_status.c
--- a/linux/drivers/media/video/uvc/uvc_status.c Sat Jul 12 16:50:43 2008 -0300
+++ b/linux/drivers/media/video/uvc/uvc_status.c Sun Jul 13 20:57:37 2008 -0400
@@ -161,9 +161,24 @@ static void uvc_status_complete(struct u
/* 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(dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT)
+ {
+ uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
+ ret);
+ } else {
+ if (ret == -EL2NSYNC) {
+ if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
+ ret);
+ }
+ } else {
+ uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
+ ret);
+
+ }
+ }
+ }
+ dev->last_urb = jiffies;
}
int uvc_status_init(struct uvc_device *dev)
@@ -171,6 +186,7 @@ int uvc_status_init(struct uvc_device *d
struct usb_host_endpoint *ep = dev->int_ep;
unsigned int pipe;
int interval;
+ int ret = 0;
if (ep == NULL)
return 0;
@@ -195,7 +211,21 @@ int uvc_status_init(struct uvc_device *d
dev->status, sizeof dev->status, uvc_status_complete,
dev, interval);
- return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+ if(dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT) {
+ 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);
+ }
+ }
+ }
+
+ } else {
+ ret = usb_submit_urb(dev->int_urb, GFP_KERNEL);
+ }
+ dev->last_urb = jiffies;
+ return ret;
}
void uvc_status_cleanup(struct uvc_device *dev)
@@ -213,9 +243,25 @@ int uvc_status_suspend(struct uvc_device
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);
-}
-
+ return ret;
+
+ if(dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT) {
+ 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);
+ }
+ }
+ }
+
+ } else {
+ ret = usb_submit_urb(dev->int_urb, GFP_NOIO);
+ }
+
+ dev->last_urb = jiffies;
+ return ret;
+}
+
diff -r 0ebffe1cc136 linux/drivers/media/video/uvc/uvc_v4l2.c
--- a/linux/drivers/media/video/uvc/uvc_v4l2.c Sat Jul 12 16:50:43 2008 -0300
+++ b/linux/drivers/media/video/uvc/uvc_v4l2.c Sun Jul 13 20:57:37 2008 -0400
@@ -456,6 +456,13 @@ static int uvc_v4l2_release(struct inode
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 0ebffe1cc136 linux/drivers/media/video/uvc/uvc_video.c
--- a/linux/drivers/media/video/uvc/uvc_video.c Sat Jul 12 16:50:43 2008 -0300
+++ b/linux/drivers/media/video/uvc/uvc_video.c Sun Jul 13 21:05:54 2008 -0400
@@ -37,18 +37,37 @@ static int __uvc_query_ctrl(struct uvc_d
__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->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT) && (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 (dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT){
+ 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 (ret == -ETIMEDOUT) // reset the device in case of -110 error
+ dev->state |= UVC_DEV_IOERROR;
+ }
return -EIO;
}
@@ -548,9 +567,23 @@ static void uvc_video_complete(struct ur
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 (video->dev->quirks & UVC_QUIRK_DEV_RESET_ON_TIMEOUT) {
+ if (ret == -EL2NSYNC) {
+ if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
+ ret);
+ }
+ } else {
+ uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
+ ret);
+
+ }
+ } else {
+ uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
+ ret);
+ }
+ }
+ video->dev->last_urb = jiffies;
}
/*
@@ -802,6 +835,7 @@ static int uvc_init_video(struct uvc_vid
return ret;
}
}
+ video->dev->last_urb = jiffies;
return 0;
}
diff -r 0ebffe1cc136 linux/drivers/media/video/uvc/uvcvideo.h
--- a/linux/drivers/media/video/uvc/uvcvideo.h Sat Jul 12 16:50:43 2008 -0300
+++ b/linux/drivers/media/video/uvc/uvcvideo.h Sun Jul 13 20:57:37 2008 -0400
@@ -314,6 +314,7 @@ struct uvc_xu_control {
#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
@@ -610,6 +611,7 @@ struct uvc_video_device {
enum uvc_device_state {
UVC_DEV_DISCONNECTED = 1,
+ UVC_DEV_IOERROR = 2,
};
struct uvc_device {
@@ -620,6 +622,7 @@ struct uvc_device {
char name[32];
enum uvc_device_state state;
+ unsigned long last_urb;
struct kref kref;
struct list_head list;
@@ -789,6 +792,9 @@ extern struct usb_host_endpoint *uvc_fin
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);
[-- 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] 3+ messages in thread
end of thread, other threads:[~2008-07-14 4:44 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-14 4:38 [PATCH] uvcvideo: RESET_ON_TIMOUT Quirk [Against HG] pat-lkml
2008-07-14 4:41 ` pat-lkml
2008-07-14 4:44 ` pat-lkml
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox