diff mbox series

[5/8] usb: gadget: uvc: initialize video format using configfs

Message ID 20230323-uvc-gadget-cleanup-v1-5-e41f0c5d9d8e@pengutronix.de (mailing list archive)
State New, archived
Headers show
Series usb: gadget: uvc: fix errors reported by v4l2-compliance | expand

Commit Message

Michael Tretter March 23, 2023, 11:41 a.m. UTC
The configfs is supported to get a list of valid formats, which will be
checked in TRY_FMT and ENUM_FMT. The device should be initialized with a
valid format instead of some arbitrary format that the user space won't
be able to set.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
 drivers/usb/gadget/function/uvc_v4l2.c | 67 +++++++++++++++++++++++++++++++---
 1 file changed, 62 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index 5620546eb43b..3f728f451ed5 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -90,6 +90,15 @@  static struct uvcg_format *find_format_by_index(struct uvc_device *uvc, int inde
 	return uformat;
 }
 
+static struct uvcg_format *get_default_format(struct uvc_device *uvc)
+{
+	/*
+	 * UVC does not specify which format index shall be used as default.
+	 * Use the first format of the descriptor as default.
+	 */
+	return find_format_by_index(uvc, 1);
+}
+
 static struct uvcg_frame *find_frame_by_index(struct uvc_device *uvc,
 				       struct uvcg_format *uformat,
 				       int index)
@@ -112,6 +121,29 @@  static struct uvcg_frame *find_frame_by_index(struct uvc_device *uvc,
 	return uframe;
 }
 
+static struct uvcg_frame *get_default_frame(struct uvc_device *uvc,
+					    struct uvcg_format *uformat)
+{
+	struct uvcg_frame *frame = NULL;
+	int frame_index = 0;
+
+	if (uformat->type == UVCG_UNCOMPRESSED) {
+		struct uvcg_uncompressed *u;
+
+		u = to_uvcg_uncompressed(&uformat->group.cg_item);
+		frame_index = u->desc.bDefaultFrameIndex;
+	} else if (uformat->type == UVCG_MJPEG) {
+		struct uvcg_mjpeg *u;
+
+		u = to_uvcg_mjpeg(&uformat->group.cg_item);
+		frame_index = u->desc.bDefaultFrameIndex;
+	}
+	if (frame_index != 0)
+		frame = find_frame_by_index(uvc, uformat, frame_index);
+
+	return frame;
+}
+
 static struct uvcg_format *find_format_by_pix(struct uvc_device *uvc,
 					      u32 pixelformat)
 {
@@ -133,12 +165,37 @@  static struct uvcg_format *find_format_by_pix(struct uvc_device *uvc,
 void uvc_init_default_format(struct uvc_device *uvc)
 {
 	struct uvc_video *video = &uvc->video;
+	struct uvcg_format *uformat;
+	struct uvcg_frame *uframe = NULL;
 
-	video->fcc = V4L2_PIX_FMT_YUYV;
-	video->bpp = 16;
-	video->width = 320;
-	video->height = 240;
-	video->imagesize = 320 * 240 * 2;
+	uformat = get_default_format(uvc);
+	if (uformat)
+		uframe = get_default_frame(uvc, uformat);
+
+	/* Fallback on some arbitrary default */
+	if (!uframe) {
+		video->fcc = V4L2_PIX_FMT_YUYV;
+		video->bpp = 16;
+		video->width = 320;
+		video->height = 240;
+		video->imagesize = 320 * 240 * 2;
+
+		return;
+	}
+
+	video->fcc = to_uvc_format(uformat)->fcc;
+
+	if (uformat->type == UVCG_UNCOMPRESSED) {
+		struct uvcg_uncompressed *u;
+
+		u = to_uvcg_uncompressed(&uformat->group.cg_item);
+		video->bpp = u->desc.bBitsPerPixel;
+	} else {
+		video->bpp = 0;
+	}
+	video->width = uframe->frame.w_width;
+	video->height = uframe->frame.w_height;
+	video->imagesize = uvc_get_frame_size(uformat, uframe);
 }
 
 static struct uvcg_frame *find_closest_frame_by_size(struct uvc_device *uvc,