The patch number 9571 was added via Mauro Carvalho Chehab <[EMAIL PROTECTED]>
to http://linuxtv.org/hg/v4l-dvb master development tree.

Kernel patches in this development tree may be modified to be backward
compatible with older kernels. Compatibility modifications will be
removed before inclusion into the mainstream Kernel

If anyone has any objections, please let us know by sending a message to:
        [EMAIL PROTECTED]

------

From: Mauro Carvalho Chehab  <[EMAIL PROTECTED]>
merge: http://linuxtv.org/hg/~pinchartl/uvcvideo


Priority: normal

Signed-off-by: Mauro Carvalho Chehab <[EMAIL PROTECTED]>


---

 linux/drivers/media/video/uvc/uvc_driver.c |  169 ++++-----------------
 linux/drivers/media/video/uvc/uvc_v4l2.c   |    4 
 linux/drivers/media/video/uvc/uvc_video.c  |   65 ++++++--
 linux/drivers/media/video/uvc/uvcvideo.h   |   14 +
 4 files changed, 107 insertions(+), 145 deletions(-)

diff -r 7f45620b4431 -r b51362e40204 linux/drivers/media/video/uvc/uvc_driver.c
--- a/linux/drivers/media/video/uvc/uvc_driver.c        Mon Nov 10 19:05:58 
2008 -0200
+++ b/linux/drivers/media/video/uvc/uvc_driver.c        Mon Nov 10 19:26:55 
2008 -0200
@@ -288,8 +288,10 @@ static int uvc_parse_format(struct uvc_d
        struct uvc_format_desc *fmtdesc;
        struct uvc_frame *frame;
        const unsigned char *start = buffer;
+       unsigned char *_buffer;
        unsigned int interval;
        unsigned int i, n;
+       int _buflen;
        __u8 ftype;
 
        format->type = buffer[2];
@@ -410,12 +412,20 @@ static int uvc_parse_format(struct uvc_d
        buflen -= buffer[0];
        buffer += buffer[0];
 
+       /* Count the number of frame descriptors to test the bFrameIndex
+        * field when parsing the descriptors. We can't rely on the
+        * bNumFrameDescriptors field as some cameras don't initialize it
+        * properly.
+        */
+       for (_buflen = buflen, _buffer = buffer;
+            _buflen > 2 && _buffer[2] == ftype;
+            _buflen -= _buffer[0], _buffer += _buffer[0])
+               format->nframes++;
+
        /* Parse the frame descriptors. Only uncompressed, MJPEG and frame
         * based formats have frame descriptors.
         */
        while (buflen > 2 && buffer[2] == ftype) {
-               frame = &format->frame[format->nframes];
-
                if (ftype != VS_FRAME_FRAME_BASED)
                        n = buflen > 25 ? buffer[25] : 0;
                else
@@ -429,6 +439,16 @@ static int uvc_parse_format(struct uvc_d
                               alts->desc.bInterfaceNumber);
                        return -EINVAL;
                }
+
+               if (buffer[3] - 1 >= format->nframes) {
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                              "interface %d frame index %u out of range\n",
+                              dev->udev->devnum, alts->desc.bInterfaceNumber,
+                              buffer[3]);
+                       return -EINVAL;
+               }
+
+               frame = &format->frame[buffer[3] - 1];
 
                frame->bFrameIndex = buffer[3];
                frame->bmCapabilities = buffer[4];
@@ -486,7 +506,6 @@ static int uvc_parse_format(struct uvc_d
                        10000000/frame->dwDefaultFrameInterval,
                        (100000000/frame->dwDefaultFrameInterval)%10);
 
-               format->nframes++;
                buflen -= buffer[0];
                buffer += buffer[0];
        }
@@ -1709,24 +1728,6 @@ static int uvc_reset_resume(struct usb_i
  * though they are compliant.
  */
 static struct usb_device_id uvc_ids[] = {
-       /* ALi M5606 (Clevo M540SR) */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x0402,
-         .idProduct            = 0x5606,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Creative Live! Optia */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x041e,
-         .idProduct            = 0x4057,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* Microsoft Lifecam NX-6000 */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1812,15 +1813,6 @@ static struct usb_device_id uvc_ids[] = 
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
-       /* Silicon Motion SM371 */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x090c,
-         .idProduct            = 0xb371,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* MT6227 */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1839,6 +1831,15 @@ static struct usb_device_id uvc_ids[] = 
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+       /* Syntek (Samsung Q310) */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x174f,
+         .idProduct            = 0x5931,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_STREAM_NO_FID },
        /* Asus F9SG */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1853,6 +1854,15 @@ static struct usb_device_id uvc_ids[] = 
                                | USB_DEVICE_ID_MATCH_INT_INFO,
          .idVendor             = 0x174f,
          .idProduct            = 0x8a33,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+       /* Lenovo Thinkpad SL500 */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x17ef,
+         .idProduct            = 0x480b,
          .bInterfaceClass      = USB_CLASS_VIDEO,
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
@@ -1887,105 +1897,6 @@ static struct usb_device_id uvc_ids[] = 
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_MINMAX
                                | UVC_QUIRK_IGNORE_SELECTOR_UNIT},
-       /* Acer OEM Webcam - Unknown vendor */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0100,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Packard Bell OEM Webcam - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0101,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Acer Crystal Eye webcam - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0102,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Compaq Presario B1200 - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0104,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Acer Travelmate 7720 - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0105,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Medion Akoya Mini E1210 - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0141,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Acer OrbiCam - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0200,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /*  Fujitsu Amilo SI2636 - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0202,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /*  Advent 4211 - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0203,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0300,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Clevo M570TU - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0303,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* Generic USB Video Class */
        { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
        {}
diff -r 7f45620b4431 -r b51362e40204 linux/drivers/media/video/uvc/uvc_v4l2.c
--- a/linux/drivers/media/video/uvc/uvc_v4l2.c  Mon Nov 10 19:05:58 2008 -0200
+++ b/linux/drivers/media/video/uvc/uvc_v4l2.c  Mon Nov 10 19:26:55 2008 -0200
@@ -252,7 +252,7 @@ static int uvc_v4l2_set_format(struct uv
        if (ret < 0)
                return ret;
 
-       if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
+       if ((ret = uvc_commit_video(video, &probe)) < 0)
                return ret;
 
        memcpy(&video->streaming->ctrl, &probe, sizeof probe);
@@ -316,7 +316,7 @@ static int uvc_v4l2_set_streamparm(struc
                return ret;
 
        /* Commit the new settings. */
-       if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
+       if ((ret = uvc_commit_video(video, &probe)) < 0)
                return ret;
 
        memcpy(&video->streaming->ctrl, &probe, sizeof probe);
diff -r 7f45620b4431 -r b51362e40204 linux/drivers/media/video/uvc/uvc_video.c
--- a/linux/drivers/media/video/uvc/uvc_video.c Mon Nov 10 19:05:58 2008 -0200
+++ b/linux/drivers/media/video/uvc/uvc_video.c Mon Nov 10 19:26:55 2008 -0200
@@ -36,15 +36,22 @@ static int __uvc_query_ctrl(struct uvc_d
 {
        __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
        unsigned int pipe;
-       int ret;
 
        pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0)
                              : usb_sndctrlpipe(dev->udev, 0);
        type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
 
-       ret = usb_control_msg(dev->udev, pipe, query, type, cs << 8,
+       return usb_control_msg(dev->udev, pipe, query, type, cs << 8,
                        unit << 8 | intfnum, data, size, timeout);
-
+}
+
+int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+                       __u8 intfnum, __u8 cs, void *data, __u16 size)
+{
+       int ret;
+
+       ret = __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
+                               UVC_CTRL_CONTROL_TIMEOUT);
        if (ret != size) {
                uvc_printk(KERN_ERR, "Failed to query (%u) UVC control %u "
                        "(unit %u) : %d (exp. %u).\n", query, cs, unit, ret,
@@ -55,13 +62,6 @@ static int __uvc_query_ctrl(struct uvc_d
        return 0;
 }
 
-int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
-                       __u8 intfnum, __u8 cs, void *data, __u16 size)
-{
-       return __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
-                               UVC_CTRL_CONTROL_TIMEOUT);
-}
-
 static void uvc_fixup_buffer_size(struct uvc_video_device *video,
        struct uvc_streaming_control *ctrl)
 {
@@ -102,8 +102,36 @@ static int uvc_get_video_ctrl(struct uvc
        ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum,
                probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
                UVC_CTRL_STREAMING_TIMEOUT);
-       if (ret < 0)
+
+       if ((query == GET_MIN || query == GET_MAX) && ret == 2) {
+               /* Some cameras, mostly based on Bison Electronics chipsets,
+                * answer a GET_MIN or GET_MAX request with the wCompQuality
+                * field only.
+                */
+               uvc_warn_once(video->dev, UVC_WARN_MINMAX, "UVC non "
+                       "compliance - GET_MIN/MAX(PROBE) incorrectly "
+                       "supported. Enabling workaround.\n");
+               memset(ctrl, 0, sizeof ctrl);
+               ctrl->wCompQuality = le16_to_cpup((__le16 *)data);
+               ret = 0;
                goto out;
+       } else if (query == GET_DEF && probe == 1) {
+               /* Many cameras don't support the GET_DEF request on their
+                * video probe control. Warn once and return, the caller will
+                * fall back to GET_CUR.
+                */
+               uvc_warn_once(video->dev, UVC_WARN_PROBE_DEF, "UVC non "
+                       "compliance - GET_DEF(PROBE) not supported. "
+                       "Enabling workaround.\n");
+               ret = -EIO;
+               goto out;
+       } else if (ret != size) {
+               uvc_printk(KERN_ERR, "Failed to query (%u) UVC %s control : "
+                       "%d (exp. %u).\n", query, probe ? "probe" : "commit",
+                       ret, size);
+               ret = -EIO;
+               goto out;
+       }
 
        ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]);
        ctrl->bFormatIndex = data[2];
@@ -138,13 +166,14 @@ static int uvc_get_video_ctrl(struct uvc
         * Try to get the value from the format and frame descriptor.
         */
        uvc_fixup_buffer_size(video, ctrl);
+       ret = 0;
 
 out:
        kfree(data);
        return ret;
 }
 
-int uvc_set_video_ctrl(struct uvc_video_device *video,
+static int uvc_set_video_ctrl(struct uvc_video_device *video,
        struct uvc_streaming_control *ctrl, int probe)
 {
        __u8 *data;
@@ -186,6 +215,12 @@ int uvc_set_video_ctrl(struct uvc_video_
                video->streaming->intfnum,
                probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
                UVC_CTRL_STREAMING_TIMEOUT);
+       if (ret != size) {
+               uvc_printk(KERN_ERR, "Failed to set UVC %s control : "
+                       "%d (exp. %u).\n", probe ? "probe" : "commit",
+                       ret, size);
+               ret = -EIO;
+       }
 
        kfree(data);
        return ret;
@@ -250,6 +285,12 @@ done:
 done:
        mutex_unlock(&video->streaming->mutex);
        return ret;
+}
+
+int uvc_commit_video(struct uvc_video_device *video,
+       struct uvc_streaming_control *probe)
+{
+       return uvc_set_video_ctrl(video, probe, 0);
 }
 
 /* ------------------------------------------------------------------------
diff -r 7f45620b4431 -r b51362e40204 linux/drivers/media/video/uvc/uvcvideo.h
--- a/linux/drivers/media/video/uvc/uvcvideo.h  Mon Nov 10 19:05:58 2008 -0200
+++ b/linux/drivers/media/video/uvc/uvcvideo.h  Mon Nov 10 19:26:55 2008 -0200
@@ -617,6 +617,7 @@ struct uvc_device {
 struct uvc_device {
        struct usb_device *udev;
        struct usb_interface *intf;
+       unsigned long warnings;
        __u32 quirks;
        int intfnum;
        char name[32];
@@ -679,12 +680,21 @@ struct uvc_driver {
 #define UVC_TRACE_SUSPEND      (1 << 8)
 #define UVC_TRACE_STATUS       (1 << 9)
 
+#define UVC_WARN_MINMAX                0
+#define UVC_WARN_PROBE_DEF     1
+
 extern unsigned int uvc_trace_param;
 
 #define uvc_trace(flag, msg...) \
        do { \
                if (uvc_trace_param & flag) \
                        printk(KERN_DEBUG "uvcvideo: " msg); \
+       } while (0)
+
+#define uvc_warn_once(dev, warn, msg...) \
+       do { \
+               if (!test_and_set_bit(warn, &dev->warnings)) \
+                       printk(KERN_INFO "uvcvideo: " msg); \
        } while (0)
 
 #define uvc_printk(level, msg...) \
@@ -740,10 +750,10 @@ extern int uvc_video_enable(struct uvc_v
 extern int uvc_video_enable(struct uvc_video_device *video, int enable);
 extern int uvc_probe_video(struct uvc_video_device *video,
                struct uvc_streaming_control *probe);
+extern int uvc_commit_video(struct uvc_video_device *video,
+               struct uvc_streaming_control *ctrl);
 extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
                __u8 intfnum, __u8 cs, void *data, __u16 size);
-extern int uvc_set_video_ctrl(struct uvc_video_device *video,
-               struct uvc_streaming_control *ctrl, int probe);
 
 /* Status */
 extern int uvc_status_init(struct uvc_device *dev);


---

Patch is available at: 
http://linuxtv.org/hg/v4l-dvb/rev/b51362e4020402b3d22bec855c30fc413bbb0289

_______________________________________________
linuxtv-commits mailing list
linuxtv-commits@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

Reply via email to