Skip to content

Commit 082dd78

Browse files
Benoit Sevensmchehab
authored andcommitted
media: uvcvideo: Refactor frame parsing code into a uvc_parse_frame function
The ftype value does not change in the while loop so we can check it before entering the while loop. Refactoring the frame parsing code into a dedicated uvc_parse_frame function makes this more readable. Signed-off-by: Benoit Sevens <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Laurent Pinchart <[email protected]> Signed-off-by: Laurent Pinchart <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent 840fb2c commit 082dd78

File tree

1 file changed

+122
-107
lines changed

1 file changed

+122
-107
lines changed

drivers/media/usb/uvc/uvc_driver.c

Lines changed: 122 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -220,20 +220,127 @@ static struct uvc_streaming *uvc_stream_new(struct uvc_device *dev,
220220
* Descriptors parsing
221221
*/
222222

223+
static int uvc_parse_frame(struct uvc_device *dev,
224+
struct uvc_streaming *streaming,
225+
struct uvc_format *format, struct uvc_frame *frame,
226+
u32 **intervals, u8 ftype, int width_multiplier,
227+
const unsigned char *buffer, int buflen)
228+
{
229+
struct usb_host_interface *alts = streaming->intf->cur_altsetting;
230+
unsigned int maxIntervalIndex;
231+
unsigned int interval;
232+
unsigned int i, n;
233+
234+
if (ftype != UVC_VS_FRAME_FRAME_BASED)
235+
n = buflen > 25 ? buffer[25] : 0;
236+
else
237+
n = buflen > 21 ? buffer[21] : 0;
238+
239+
n = n ? n : 3;
240+
241+
if (buflen < 26 + 4 * n) {
242+
uvc_dbg(dev, DESCR,
243+
"device %d videostreaming interface %d FRAME error\n",
244+
dev->udev->devnum, alts->desc.bInterfaceNumber);
245+
return -EINVAL;
246+
}
247+
248+
frame->bFrameIndex = buffer[3];
249+
frame->bmCapabilities = buffer[4];
250+
frame->wWidth = get_unaligned_le16(&buffer[5]) * width_multiplier;
251+
frame->wHeight = get_unaligned_le16(&buffer[7]);
252+
frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
253+
frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
254+
if (ftype != UVC_VS_FRAME_FRAME_BASED) {
255+
frame->dwMaxVideoFrameBufferSize =
256+
get_unaligned_le32(&buffer[17]);
257+
frame->dwDefaultFrameInterval =
258+
get_unaligned_le32(&buffer[21]);
259+
frame->bFrameIntervalType = buffer[25];
260+
} else {
261+
frame->dwMaxVideoFrameBufferSize = 0;
262+
frame->dwDefaultFrameInterval =
263+
get_unaligned_le32(&buffer[17]);
264+
frame->bFrameIntervalType = buffer[21];
265+
}
266+
267+
/*
268+
* Copy the frame intervals.
269+
*
270+
* Some bogus devices report dwMinFrameInterval equal to
271+
* dwMaxFrameInterval and have dwFrameIntervalStep set to zero. Setting
272+
* all null intervals to 1 fixes the problem and some other divisions
273+
* by zero that could happen.
274+
*/
275+
frame->dwFrameInterval = *intervals;
276+
277+
for (i = 0; i < n; ++i) {
278+
interval = get_unaligned_le32(&buffer[26 + 4 * i]);
279+
(*intervals)[i] = interval ? interval : 1;
280+
}
281+
282+
/*
283+
* Apply more fixes, quirks and workarounds to handle incorrect or
284+
* broken descriptors.
285+
*/
286+
287+
/*
288+
* Several UVC chipsets screw up dwMaxVideoFrameBufferSize completely.
289+
* Observed behaviours range from setting the value to 1.1x the actual
290+
* frame size to hardwiring the 16 low bits to 0. This results in a
291+
* higher than necessary memory usage as well as a wrong image size
292+
* information. For uncompressed formats this can be fixed by computing
293+
* the value from the frame size.
294+
*/
295+
if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
296+
frame->dwMaxVideoFrameBufferSize = format->bpp * frame->wWidth
297+
* frame->wHeight / 8;
298+
299+
/*
300+
* Clamp the default frame interval to the boundaries. A zero
301+
* bFrameIntervalType value indicates a continuous frame interval
302+
* range, with dwFrameInterval[0] storing the minimum value and
303+
* dwFrameInterval[1] storing the maximum value.
304+
*/
305+
maxIntervalIndex = frame->bFrameIntervalType ? n - 1 : 1;
306+
frame->dwDefaultFrameInterval =
307+
clamp(frame->dwDefaultFrameInterval,
308+
frame->dwFrameInterval[0],
309+
frame->dwFrameInterval[maxIntervalIndex]);
310+
311+
/*
312+
* Some devices report frame intervals that are not functional. If the
313+
* corresponding quirk is set, restrict operation to the first interval
314+
* only.
315+
*/
316+
if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) {
317+
frame->bFrameIntervalType = 1;
318+
(*intervals)[0] = frame->dwDefaultFrameInterval;
319+
}
320+
321+
uvc_dbg(dev, DESCR, "- %ux%u (%u.%u fps)\n",
322+
frame->wWidth, frame->wHeight,
323+
10000000 / frame->dwDefaultFrameInterval,
324+
(100000000 / frame->dwDefaultFrameInterval) % 10);
325+
326+
*intervals += n;
327+
328+
return buffer[0];
329+
}
330+
223331
static int uvc_parse_format(struct uvc_device *dev,
224332
struct uvc_streaming *streaming, struct uvc_format *format,
225333
struct uvc_frame *frames, u32 **intervals, const unsigned char *buffer,
226334
int buflen)
227335
{
228-
struct usb_interface *intf = streaming->intf;
229-
struct usb_host_interface *alts = intf->cur_altsetting;
336+
struct usb_host_interface *alts = streaming->intf->cur_altsetting;
230337
const struct uvc_format_desc *fmtdesc;
231338
struct uvc_frame *frame;
232339
const unsigned char *start = buffer;
233340
unsigned int width_multiplier = 1;
234-
unsigned int interval;
235341
unsigned int i, n;
236342
u8 ftype;
343+
int ret;
237344

238345
format->type = buffer[2];
239346
format->index = buffer[3];
@@ -371,111 +478,19 @@ static int uvc_parse_format(struct uvc_device *dev,
371478
* Parse the frame descriptors. Only uncompressed, MJPEG and frame
372479
* based formats have frame descriptors.
373480
*/
374-
while (ftype && buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
375-
buffer[2] == ftype) {
376-
unsigned int maxIntervalIndex;
377-
378-
frame = &frames[format->nframes];
379-
if (ftype != UVC_VS_FRAME_FRAME_BASED)
380-
n = buflen > 25 ? buffer[25] : 0;
381-
else
382-
n = buflen > 21 ? buffer[21] : 0;
383-
384-
n = n ? n : 3;
385-
386-
if (buflen < 26 + 4*n) {
387-
uvc_dbg(dev, DESCR,
388-
"device %d videostreaming interface %d FRAME error\n",
389-
dev->udev->devnum,
390-
alts->desc.bInterfaceNumber);
391-
return -EINVAL;
392-
}
393-
394-
frame->bFrameIndex = buffer[3];
395-
frame->bmCapabilities = buffer[4];
396-
frame->wWidth = get_unaligned_le16(&buffer[5])
397-
* width_multiplier;
398-
frame->wHeight = get_unaligned_le16(&buffer[7]);
399-
frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
400-
frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
401-
if (ftype != UVC_VS_FRAME_FRAME_BASED) {
402-
frame->dwMaxVideoFrameBufferSize =
403-
get_unaligned_le32(&buffer[17]);
404-
frame->dwDefaultFrameInterval =
405-
get_unaligned_le32(&buffer[21]);
406-
frame->bFrameIntervalType = buffer[25];
407-
} else {
408-
frame->dwMaxVideoFrameBufferSize = 0;
409-
frame->dwDefaultFrameInterval =
410-
get_unaligned_le32(&buffer[17]);
411-
frame->bFrameIntervalType = buffer[21];
412-
}
413-
414-
/*
415-
* Copy the frame intervals.
416-
*
417-
* Some bogus devices report dwMinFrameInterval equal to
418-
* dwMaxFrameInterval and have dwFrameIntervalStep set to
419-
* zero. Setting all null intervals to 1 fixes the problem and
420-
* some other divisions by zero that could happen.
421-
*/
422-
frame->dwFrameInterval = *intervals;
423-
424-
for (i = 0; i < n; ++i) {
425-
interval = get_unaligned_le32(&buffer[26+4*i]);
426-
(*intervals)[i] = interval ? interval : 1;
427-
}
428-
429-
/*
430-
* Apply more fixes, quirks and workarounds to handle incorrect
431-
* or broken descriptors.
432-
*/
433-
434-
/*
435-
* Several UVC chipsets screw up dwMaxVideoFrameBufferSize
436-
* completely. Observed behaviours range from setting the
437-
* value to 1.1x the actual frame size to hardwiring the
438-
* 16 low bits to 0. This results in a higher than necessary
439-
* memory usage as well as a wrong image size information. For
440-
* uncompressed formats this can be fixed by computing the
441-
* value from the frame size.
442-
*/
443-
if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
444-
frame->dwMaxVideoFrameBufferSize = format->bpp
445-
* frame->wWidth * frame->wHeight / 8;
446-
447-
/*
448-
* Clamp the default frame interval to the boundaries. A zero
449-
* bFrameIntervalType value indicates a continuous frame
450-
* interval range, with dwFrameInterval[0] storing the minimum
451-
* value and dwFrameInterval[1] storing the maximum value.
452-
*/
453-
maxIntervalIndex = frame->bFrameIntervalType ? n - 1 : 1;
454-
frame->dwDefaultFrameInterval =
455-
clamp(frame->dwDefaultFrameInterval,
456-
frame->dwFrameInterval[0],
457-
frame->dwFrameInterval[maxIntervalIndex]);
458-
459-
/*
460-
* Some devices report frame intervals that are not functional.
461-
* If the corresponding quirk is set, restrict operation to the
462-
* first interval only.
463-
*/
464-
if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) {
465-
frame->bFrameIntervalType = 1;
466-
(*intervals)[0] = frame->dwDefaultFrameInterval;
481+
if (ftype) {
482+
while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
483+
buffer[2] == ftype) {
484+
frame = &frames[format->nframes];
485+
ret = uvc_parse_frame(dev, streaming, format, frame,
486+
intervals, ftype, width_multiplier,
487+
buffer, buflen);
488+
if (ret < 0)
489+
return ret;
490+
format->nframes++;
491+
buflen -= ret;
492+
buffer += ret;
467493
}
468-
469-
uvc_dbg(dev, DESCR, "- %ux%u (%u.%u fps)\n",
470-
frame->wWidth, frame->wHeight,
471-
10000000 / frame->dwDefaultFrameInterval,
472-
(100000000 / frame->dwDefaultFrameInterval) % 10);
473-
474-
format->nframes++;
475-
*intervals += n;
476-
477-
buflen -= buffer[0];
478-
buffer += buffer[0];
479494
}
480495

481496
if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&

0 commit comments

Comments
 (0)