Merge branch 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[pandora-kernel.git] / drivers / media / video / uvc / uvc_driver.c
index 507dc85..04b4783 100644 (file)
@@ -289,10 +289,8 @@ static int uvc_parse_format(struct uvc_device *dev,
        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];
@@ -303,7 +301,7 @@ static int uvc_parse_format(struct uvc_device *dev,
        case VS_FORMAT_FRAME_BASED:
                n = buffer[2] == VS_FORMAT_UNCOMPRESSED ? 27 : 28;
                if (buflen < n) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FORMAT error\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber);
@@ -338,7 +336,7 @@ static int uvc_parse_format(struct uvc_device *dev,
 
        case VS_FORMAT_MJPEG:
                if (buflen < 11) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FORMAT error\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber);
@@ -354,7 +352,7 @@ static int uvc_parse_format(struct uvc_device *dev,
 
        case VS_FORMAT_DV:
                if (buflen < 9) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FORMAT error\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber);
@@ -372,7 +370,7 @@ static int uvc_parse_format(struct uvc_device *dev,
                        strlcpy(format->name, "HD-DV", sizeof format->name);
                        break;
                default:
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d: unknown DV format %u\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber, buffer[8]);
@@ -401,7 +399,7 @@ static int uvc_parse_format(struct uvc_device *dev,
        case VS_FORMAT_STREAM_BASED:
                /* Not supported yet. */
        default:
-               uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+               uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                       "interface %d unsupported format %u\n",
                       dev->udev->devnum, alts->desc.bInterfaceNumber,
                       buffer[2]);
@@ -413,20 +411,11 @@ static int uvc_parse_format(struct uvc_device *dev,
        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
@@ -435,22 +424,12 @@ static int uvc_parse_format(struct uvc_device *dev,
                n = n ? n : 3;
 
                if (buflen < 26 + 4*n) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FRAME error\n", dev->udev->devnum,
                               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];
                frame->wWidth = get_unaligned_le16(&buffer[5]);
@@ -507,6 +486,7 @@ static int uvc_parse_format(struct uvc_device *dev,
                        10000000/frame->dwDefaultFrameInterval,
                        (100000000/frame->dwDefaultFrameInterval)%10);
 
+               format->nframes++;
                buflen -= buffer[0];
                buffer += buffer[0];
        }
@@ -518,7 +498,7 @@ static int uvc_parse_format(struct uvc_device *dev,
 
        if (buflen > 2 && buffer[2] == VS_COLORFORMAT) {
                if (buflen < 6) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d COLORFORMAT error\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber);
@@ -664,7 +644,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        _buflen = buflen;
 
        /* Count the format and frame descriptors. */
-       while (_buflen > 2) {
+       while (_buflen > 2 && _buffer[1] == CS_INTERFACE) {
                switch (_buffer[2]) {
                case VS_FORMAT_UNCOMPRESSED:
                case VS_FORMAT_MJPEG:
@@ -729,7 +709,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        streaming->nformats = nformats;
 
        /* Parse the format descriptors. */
-       while (buflen > 2) {
+       while (buflen > 2 && buffer[1] == CS_INTERFACE) {
                switch (buffer[2]) {
                case VS_FORMAT_UNCOMPRESSED:
                case VS_FORMAT_MJPEG:
@@ -1316,7 +1296,7 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video,
                        continue;
 
                if (forward->extension.bNrInPins != 1) {
-                       uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has"
+                       uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has "
                                "more than 1 input pin.\n", entity->id);
                        return -1;
                }
@@ -1614,6 +1594,7 @@ static int uvc_probe(struct usb_interface *intf,
        INIT_LIST_HEAD(&dev->entities);
        INIT_LIST_HEAD(&dev->streaming);
        kref_init(&dev->kref);
+       atomic_set(&dev->users, 0);
 
        dev->udev = usb_get_dev(udev);
        dev->intf = usb_get_intf(intf);
@@ -1864,11 +1845,29 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
-       /* ViMicro */
-       { .match_flags          = USB_DEVICE_ID_MATCH_VENDOR
+       /* ViMicro Vega */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
          .idVendor             = 0x0ac8,
-         .idProduct            = 0x0000,
+         .idProduct            = 0x332d,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_FIX_BANDWIDTH },
+       /* ViMicro - Minoru3D */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x0ac8,
+         .idProduct            = 0x3410,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_FIX_BANDWIDTH },
+       /* ViMicro Venus - Minoru3D */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x0ac8,
+         .idProduct            = 0x3420,
          .bInterfaceClass      = USB_CLASS_VIDEO,
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
@@ -1927,7 +1926,7 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
-       /* Lenovo Thinkpad SL500 */
+       /* Lenovo Thinkpad SL400/SL500 */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
          .idVendor             = 0x17ef,
@@ -1936,6 +1935,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+       /* Aveo Technology USB 2.0 Camera */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x1871,
+         .idProduct            = 0x0306,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_EXTRAFIELDS },
        /* Ecamm Pico iMage */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1945,6 +1953,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_EXTRAFIELDS },
+       /* FSC WebCam V30S */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x18ec,
+         .idProduct            = 0x3288,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* Bodelin ProScopeHR */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_DEV_HI
@@ -1965,8 +1982,7 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_MINMAX
-                               | UVC_QUIRK_IGNORE_SELECTOR_UNIT
-                               | UVC_QUIRK_PRUNE_CONTROLS },
+                               | UVC_QUIRK_IGNORE_SELECTOR_UNIT },
        /* Generic USB Video Class */
        { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
        {}