Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c9535db3 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (9569): uvcvideo: Sort the frame descriptors during parsing



The UVC specification does not require frame descriptors to be sorted by
bFrameIndex. At least one camera (145f:013e) is known not to sort the
descriptors properly, so they need to be sorted during parsing as the driver
then accesses them by index.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@skynet.be>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 2f38483b
Loading
Loading
Loading
Loading
+22 −3
Original line number Diff line number Diff line
@@ -288,8 +288,10 @@ 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];
@@ -410,12 +412,20 @@ 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
@@ -430,6 +440,16 @@ static int uvc_parse_format(struct uvc_device *dev,
			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 = le16_to_cpup((__le16 *)&buffer[5]);
@@ -486,7 +506,6 @@ static int uvc_parse_format(struct uvc_device *dev,
			10000000/frame->dwDefaultFrameInterval,
			(100000000/frame->dwDefaultFrameInterval)%10);

		format->nframes++;
		buflen -= buffer[0];
		buffer += buffer[0];
	}