2022-02-23 03:38:38

by Jing Leng

[permalink] [raw]
Subject: [PATCH] usb: gadget: uvc: add different uvc versions support

From: Jing Leng <[email protected]>

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 <[email protected]>
---
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 --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;
--
2.17.1