diff mbox series

usb: gadget: uvc: add different uvc versions support

Message ID 20220223032852.24304-1-3090101217@zju.edu.cn (mailing list archive)
State New, archived
Headers show
Series usb: gadget: uvc: add different uvc versions support | expand

Commit Message

Jing Leng Feb. 23, 2022, 3:28 a.m. UTC
From: Jing Leng <jleng@ambarella.com>

Currently UVC specification has three different versions
(1.0 1.1 and 1.5), they are a little different:

1. UVC 1.5 adds three new selectors in "Camera Terminal Control".
2. UVC 1.5 adds one new selector in "Processing Unit Control".
3. In the "Processing Unit Descriptor", bControlSize is fixed to be 3 in
   UVC 1.5 and is configurable in UVC 1.0/1.1. In addition, UVC 1.1 adds
   an extra member "bmVideoStandards".
4. In the "Video Probe and Commit Controls", the number of the members
   is different in different UVC versions. The length of the structure
   is 26/34/48 in UVC 1.0/1.1/1.5.

Currently, even we can configure the uvc version via bcdUVC, there is no
different processings for UVC 1.0/1.1, and it doesn't have new definitions
of UVC 1.5.
we can simply modify the driver according to the UVC 1.0/1.1/1.5
specifications to support different version UVCs.

Here is an example how to configure the UVC version:
 VERSION=$(( 0x0150 )) # 0x0100 or 0x0110 or 0x0150
 mkdir functions/uvc.usb0/control/header/h
 cd functions/uvc.usb0/control/
 echo $VERSION > header/h/bcdUVC # change the version
 ln -s header/h class/fs
 ln -s header/h class/ss

Signed-off-by: Jing Leng <jleng@ambarella.com>
---
 drivers/usb/gadget/function/f_uvc.c        | 17 ++++++++++++--
 drivers/usb/gadget/function/uvc_configfs.c |  2 +-
 drivers/usb/gadget/legacy/webcam.c         |  7 +++---
 include/uapi/linux/usb/video.h             | 27 ++++++++++++++++++++--
 4 files changed, 45 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 71bb5e477dba..a39f20b952ce 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -589,6 +589,9 @@  uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
 	struct usb_composite_dev *cdev = c->cdev;
 	struct uvc_device *uvc = to_uvc(f);
 	struct usb_string *us;
+	struct uvc_processing_unit_descriptor *pd;
+	struct uvc_descriptor_header **ctl_cls;
+	struct uvc_header_descriptor *desc;
 	unsigned int max_packet_mult;
 	unsigned int max_packet_size;
 	struct usb_ep *ep;
@@ -598,6 +601,15 @@  uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
 	uvcg_info(f, "%s()\n", __func__);
 
 	opts = fi_to_f_uvc_opts(f->fi);
+
+	/* Handle the length of Processing Unit for different UVC versions */
+	ctl_cls = opts->uvc_ss_control_cls;
+	desc = (struct uvc_header_descriptor *)ctl_cls[0];
+	if (desc) {
+		pd = &opts->uvc_processing;
+		pd->bLength = UVC_DT_PROCESSING_UNIT_SIZE(desc->bcdUVC, 3);
+	}
+
 	/* Sanity check the streaming endpoint module parameters.
 	 */
 	opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
@@ -814,15 +826,16 @@  static struct usb_function_instance *uvc_alloc_inst(void)
 	cd->bmControls[2]		= 0;
 
 	pd = &opts->uvc_processing;
-	pd->bLength			= UVC_DT_PROCESSING_UNIT_SIZE(2);
+	pd->bLength			= UVC_DT_PROCESSING_UNIT_SIZE(UVC_VERSION_DEFAULT, 3);
 	pd->bDescriptorType		= USB_DT_CS_INTERFACE;
 	pd->bDescriptorSubType		= UVC_VC_PROCESSING_UNIT;
 	pd->bUnitID			= 2;
 	pd->bSourceID			= 1;
 	pd->wMaxMultiplier		= cpu_to_le16(16*1024);
-	pd->bControlSize		= 2;
+	pd->bControlSize		= 3;
 	pd->bmControls[0]		= 1;
 	pd->bmControls[1]		= 0;
+	pd->bmControls[2]		= 0;
 	pd->iProcessing			= 0;
 	pd->bmVideoStandards		= 0;
 
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 77d64031aa9c..f4cee41b66f0 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -231,7 +231,7 @@  static struct config_item *uvcg_control_header_make(struct config_group *group,
 	h->desc.bLength			= UVC_DT_HEADER_SIZE(1);
 	h->desc.bDescriptorType		= USB_DT_CS_INTERFACE;
 	h->desc.bDescriptorSubType	= UVC_VC_HEADER;
-	h->desc.bcdUVC			= cpu_to_le16(0x0110);
+	h->desc.bcdUVC			= cpu_to_le16(UVC_VERSION_DEFAULT);
 	h->desc.dwClockFrequency	= cpu_to_le32(48000000);
 
 	config_item_init_type_name(&h->item, name, &uvcg_control_header_type);
diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c
index 94e22867da1d..f5f13d39e770 100644
--- a/drivers/usb/gadget/legacy/webcam.c
+++ b/drivers/usb/gadget/legacy/webcam.c
@@ -90,7 +90,7 @@  static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
 	.bLength		= UVC_DT_HEADER_SIZE(1),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
 	.bDescriptorSubType	= UVC_VC_HEADER,
-	.bcdUVC			= cpu_to_le16(0x0110),
+	.bcdUVC			= cpu_to_le16(UVC_VERSION_DEFAULT),
 	.wTotalLength		= 0, /* dynamic */
 	.dwClockFrequency	= cpu_to_le32(48000000),
 	.bInCollection		= 0, /* dynamic */
@@ -115,15 +115,16 @@  static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
 };
 
 static const struct uvc_processing_unit_descriptor uvc_processing = {
-	.bLength		= UVC_DT_PROCESSING_UNIT_SIZE(2),
+	.bLength		= UVC_DT_PROCESSING_UNIT_SIZE(UVC_VERSION_DEFAULT, 3),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
 	.bDescriptorSubType	= UVC_VC_PROCESSING_UNIT,
 	.bUnitID		= 2,
 	.bSourceID		= 1,
 	.wMaxMultiplier		= cpu_to_le16(16*1024),
-	.bControlSize		= 2,
+	.bControlSize		= 3,
 	.bmControls[0]		= 1,
 	.bmControls[1]		= 0,
+	.bmControls[2]		= 0,
 	.iProcessing		= 0,
 	.bmVideoStandards	= 0,
 };
diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h
index bfdae12cdacf..edd1bbde2290 100644
--- a/include/uapi/linux/usb/video.h
+++ b/include/uapi/linux/usb/video.h
@@ -21,6 +21,12 @@ 
  * UVC constants
  */
 
+/* UVC Protocol Version */
+#define UVC_VERSION_1_0					0x0100
+#define UVC_VERSION_1_1					0x0110
+#define UVC_VERSION_1_5					0x0150
+#define UVC_VERSION_DEFAULT				UVC_VERSION_1_1
+
 /* A.2. Video Interface Subclass Codes */
 #define UVC_SC_UNDEFINED				0x00
 #define UVC_SC_VIDEOCONTROL				0x01
@@ -104,6 +110,9 @@ 
 #define UVC_CT_ROLL_ABSOLUTE_CONTROL			0x0f
 #define UVC_CT_ROLL_RELATIVE_CONTROL			0x10
 #define UVC_CT_PRIVACY_CONTROL				0x11
+#define UVC_CT_FOCUS_SIMPLE_CONTROL			0x12
+#define UVC_CT_WINDOW_CONTROL				0x13
+#define UVC_CT_REGION_OF_INTEREST_CONTROL		0x14
 
 /* A.9.5. Processing Unit Control Selectors */
 #define UVC_PU_CONTROL_UNDEFINED			0x00
@@ -125,6 +134,7 @@ 
 #define UVC_PU_HUE_AUTO_CONTROL				0x10
 #define UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL		0x11
 #define UVC_PU_ANALOG_LOCK_STATUS_CONTROL		0x12
+#define UVC_PU_CONTRAST_AUTO_CONTROL			0x13
 
 /* A.9.7. VideoStreaming Interface Control Selectors */
 #define UVC_VS_CONTROL_UNDEFINED			0x00
@@ -300,12 +310,14 @@  struct uvc_processing_unit_descriptor {
 	__u8   bSourceID;
 	__le16 wMaxMultiplier;
 	__u8   bControlSize;
-	__u8   bmControls[2];
+	__u8   bmControls[3];
 	__u8   iProcessing;
+	/* UVC 1.1 adds the following member */
 	__u8   bmVideoStandards;
 } __attribute__((__packed__));
 
-#define UVC_DT_PROCESSING_UNIT_SIZE(n)			(10+(n))
+#define UVC_DT_PROCESSING_UNIT_SIZE(v, n)		((__u8) \
+	(((v) == UVC_VERSION_1_0) ? (9+(n)) : ((10+(n)))))
 
 /* 3.7.2.6. Extension Unit Descriptor */
 struct uvc_extension_unit_descriptor {
@@ -447,13 +459,24 @@  struct uvc_streaming_control {
 	__u16 wDelay;
 	__u32 dwMaxVideoFrameSize;
 	__u32 dwMaxPayloadTransferSize;
+	/* UVC 1.1 adds the following members */
 	__u32 dwClockFrequency;
 	__u8  bmFramingInfo;
 	__u8  bPreferedVersion;
 	__u8  bMinVersion;
 	__u8  bMaxVersion;
+	/* UVC 1.5 adds the following members */
+	__u8  bUsage;
+	__u8  bBitDepthLuma;
+	__u8  bmSettings;
+	__u8  bMaxNumberOfRefFramesPlus1;
+	__u16 bmRateControlModes;
+	__u16 bmLayoutPerStream[4];
 } __attribute__((__packed__));
 
+#define UVC_STREAMING_CONTROL_SIZE(v)			\
+	(((v) == UVC_VERSION_1_0) ? 26 : (((v) == UVC_VERSION_1_1) ? 34 : 48))
+
 /* Uncompressed Payload - 3.1.1. Uncompressed Video Format Descriptor */
 struct uvc_format_uncompressed {
 	__u8  bLength;