Merge tag 'fsnotify_for_v6.5-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / media / usb / uvc / uvc_driver.c
index d631ce4f9f7bb298d2b4c309d0bf242cdbd61a93..08fcd2ffa727b248d7857031a7790341aef5f1a0 100644 (file)
@@ -184,7 +184,7 @@ static void uvc_stream_delete(struct uvc_streaming *stream)
 
        usb_put_intf(stream->intf);
 
-       kfree(stream->format);
+       kfree(stream->formats);
        kfree(stream->header.bmaControls);
        kfree(stream);
 }
@@ -221,7 +221,8 @@ static struct uvc_streaming *uvc_stream_new(struct uvc_device *dev,
 
 static int uvc_parse_format(struct uvc_device *dev,
        struct uvc_streaming *streaming, struct uvc_format *format,
-       u32 **intervals, unsigned char *buffer, int buflen)
+       struct uvc_frame *frames, u32 **intervals, const unsigned char *buffer,
+       int buflen)
 {
        struct usb_interface *intf = streaming->intf;
        struct usb_host_interface *alts = intf->cur_altsetting;
@@ -235,6 +236,7 @@ static int uvc_parse_format(struct uvc_device *dev,
 
        format->type = buffer[2];
        format->index = buffer[3];
+       format->frames = frames;
 
        switch (buffer[2]) {
        case UVC_VS_FORMAT_UNCOMPRESSED:
@@ -339,8 +341,8 @@ static int uvc_parse_format(struct uvc_device *dev,
                ftype = 0;
 
                /* Create a dummy frame descriptor. */
-               frame = &format->frame[0];
-               memset(&format->frame[0], 0, sizeof(format->frame[0]));
+               frame = &frames[0];
+               memset(frame, 0, sizeof(*frame));
                frame->bFrameIntervalType = 1;
                frame->dwDefaultFrameInterval = 1;
                frame->dwFrameInterval = *intervals;
@@ -370,7 +372,9 @@ static int uvc_parse_format(struct uvc_device *dev,
         */
        while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
               buffer[2] == ftype) {
-               frame = &format->frame[format->nframes];
+               unsigned int maxIntervalIndex;
+
+               frame = &frames[format->nframes];
                if (ftype != UVC_VS_FRAME_FRAME_BASED)
                        n = buflen > 25 ? buffer[25] : 0;
                else
@@ -405,8 +409,27 @@ static int uvc_parse_format(struct uvc_device *dev,
                                get_unaligned_le32(&buffer[17]);
                        frame->bFrameIntervalType = buffer[21];
                }
+
+               /*
+                * Copy the frame intervals.
+                *
+                * Some bogus devices report dwMinFrameInterval equal to
+                * dwMaxFrameInterval and have dwFrameIntervalStep set to
+                * zero. Setting all null intervals to 1 fixes the problem and
+                * some other divisions by zero that could happen.
+                */
                frame->dwFrameInterval = *intervals;
 
+               for (i = 0; i < n; ++i) {
+                       interval = get_unaligned_le32(&buffer[26+4*i]);
+                       (*intervals)[i] = interval ? interval : 1;
+               }
+
+               /*
+                * Apply more fixes, quirks and workarounds to handle incorrect
+                * or broken descriptors.
+                */
+
                /*
                 * Several UVC chipsets screw up dwMaxVideoFrameBufferSize
                 * completely. Observed behaviours range from setting the
@@ -421,30 +444,25 @@ static int uvc_parse_format(struct uvc_device *dev,
                                * frame->wWidth * frame->wHeight / 8;
 
                /*
-                * Some bogus devices report dwMinFrameInterval equal to
-                * dwMaxFrameInterval and have dwFrameIntervalStep set to
-                * zero. Setting all null intervals to 1 fixes the problem and
-                * some other divisions by zero that could happen.
+                * Clamp the default frame interval to the boundaries. A zero
+                * bFrameIntervalType value indicates a continuous frame
+                * interval range, with dwFrameInterval[0] storing the minimum
+                * value and dwFrameInterval[1] storing the maximum value.
                 */
-               for (i = 0; i < n; ++i) {
-                       interval = get_unaligned_le32(&buffer[26+4*i]);
-                       *(*intervals)++ = interval ? interval : 1;
-               }
+               maxIntervalIndex = frame->bFrameIntervalType ? n - 1 : 1;
+               frame->dwDefaultFrameInterval =
+                       clamp(frame->dwDefaultFrameInterval,
+                             frame->dwFrameInterval[0],
+                             frame->dwFrameInterval[maxIntervalIndex]);
 
                /*
-                * Make sure that the default frame interval stays between
-                * the boundaries.
+                * Some devices report frame intervals that are not functional.
+                * If the corresponding quirk is set, restrict operation to the
+                * first interval only.
                 */
-               n -= frame->bFrameIntervalType ? 1 : 2;
-               frame->dwDefaultFrameInterval =
-                       min(frame->dwFrameInterval[n],
-                           max(frame->dwFrameInterval[0],
-                               frame->dwDefaultFrameInterval));
-
                if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) {
                        frame->bFrameIntervalType = 1;
-                       frame->dwFrameInterval[0] =
-                               frame->dwDefaultFrameInterval;
+                       (*intervals)[0] = frame->dwDefaultFrameInterval;
                }
 
                uvc_dbg(dev, DESCR, "- %ux%u (%u.%u fps)\n",
@@ -453,6 +471,8 @@ static int uvc_parse_format(struct uvc_device *dev,
                        (100000000 / frame->dwDefaultFrameInterval) % 10);
 
                format->nframes++;
+               *intervals += n;
+
                buflen -= buffer[0];
                buffer += buffer[0];
        }
@@ -493,7 +513,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        struct uvc_format *format;
        struct uvc_frame *frame;
        struct usb_host_interface *alts = &intf->altsetting[0];
-       unsigned char *_buffer, *buffer = alts->extra;
+       const unsigned char *_buffer, *buffer = alts->extra;
        int _buflen, buflen = alts->extralen;
        unsigned int nformats = 0, nframes = 0, nintervals = 0;
        unsigned int size, i, n, p;
@@ -677,7 +697,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        frame = (struct uvc_frame *)&format[nformats];
        interval = (u32 *)&frame[nframes];
 
-       streaming->format = format;
+       streaming->formats = format;
        streaming->nformats = 0;
 
        /* Parse the format descriptors. */
@@ -687,8 +707,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
                case UVC_VS_FORMAT_MJPEG:
                case UVC_VS_FORMAT_DV:
                case UVC_VS_FORMAT_FRAME_BASED:
-                       format->frame = frame;
-                       ret = uvc_parse_format(dev, streaming, format,
+                       ret = uvc_parse_format(dev, streaming, format, frame,
                                &interval, buffer, buflen);
                        if (ret < 0)
                                goto error;
@@ -1147,7 +1166,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
 static int uvc_parse_control(struct uvc_device *dev)
 {
        struct usb_host_interface *alts = dev->intf->cur_altsetting;
-       unsigned char *buffer = alts->extra;
+       const unsigned char *buffer = alts->extra;
        int buflen = alts->extralen;
        int ret;
 
@@ -3011,15 +3030,33 @@ static const struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
-       /* Acer EasyCamera */
+       /* Intel D410/ASR depth camera */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x1180,
+         .idVendor             = 0x8086,
+         .idProduct            = 0x0ad2,
          .bInterfaceClass      = USB_CLASS_VIDEO,
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
-         .driver_info          = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+         .driver_info          = UVC_INFO_META(V4L2_META_FMT_D4XX) },
+       /* Intel D415/ASRC depth camera */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x8086,
+         .idProduct            = 0x0ad3,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_INFO_META(V4L2_META_FMT_D4XX) },
+       /* Intel D430/AWG depth camera */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x8086,
+         .idProduct            = 0x0ad4,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_INFO_META(V4L2_META_FMT_D4XX) },
        /* Intel RealSense D4M */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -3029,6 +3066,42 @@ static const struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_INFO_META(V4L2_META_FMT_D4XX) },
+       /* Intel D435/AWGC depth camera */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x8086,
+         .idProduct            = 0x0b07,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_INFO_META(V4L2_META_FMT_D4XX) },
+       /* Intel D435i depth camera */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x8086,
+         .idProduct            = 0x0b3a,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_INFO_META(V4L2_META_FMT_D4XX) },
+       /* Intel D405 Depth Camera */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x8086,
+         .idProduct            = 0x0b5b,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_INFO_META(V4L2_META_FMT_D4XX) },
+       /* Intel D455 Depth Camera */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x8086,
+         .idProduct            = 0x0b5c,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_INFO_META(V4L2_META_FMT_D4XX) },
        /* Generic USB Video Class */
        { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
        { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) },