diff options
-rw-r--r-- | drivers/media/usb/uvc/uvc_driver.c | 40 |
1 files changed, 25 insertions, 15 deletions
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 9f89c781e885..ef9066dcf535 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -405,8 +405,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)++ = 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 @@ -420,27 +439,18 @@ static int uvc_parse_format(struct uvc_device *dev, frame->dwMaxVideoFrameBufferSize = format->bpp * 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. - */ - for (i = 0; i < n; ++i) { - interval = get_unaligned_le32(&buffer[26+4*i]); - *(*intervals)++ = interval ? interval : 1; - } - - /* - * Make sure that the default frame interval stays between - * the boundaries. - */ + /* Clamp the default frame interval to the boundaries. */ n -= frame->bFrameIntervalType ? 1 : 2; frame->dwDefaultFrameInterval = clamp(frame->dwDefaultFrameInterval, frame->dwFrameInterval[0], frame->dwFrameInterval[n]); + /* + * Some devices report frame intervals that are not functional. + * If the corresponding quirk is set, restrict operation to the + * first interval only. + */ if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) { frame->bFrameIntervalType = 1; frame->dwFrameInterval[0] = |