From 36616c5f9ab5a5b269363c7c80bc6395a95f3132 Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Mon, 26 Jun 2023 14:43:24 +0200 Subject: [PATCH] samples: subsys: usb: webusb: Fix Win10 detection This patch refactors the usage of MS OS 2.0 descriptors in the WebUSB sample. The function subset header was removed since it is not allowed for non-composite devices. Also, a new random GUID was added for automatic driver installation. Signed-off-by: Maximilian Deubel --- samples/subsys/usb/webusb/src/main.c | 74 +++++++++++------ samples/subsys/usb/webusb/src/msosv2_defs.h | 92 +++++++++++++++++++++ 2 files changed, 140 insertions(+), 26 deletions(-) create mode 100644 samples/subsys/usb/webusb/src/msosv2_defs.h diff --git a/samples/subsys/usb/webusb/src/main.c b/samples/subsys/usb/webusb/src/main.c index 2f484e3e5c279ec..12ae59f34f07471 100644 --- a/samples/subsys/usb/webusb/src/main.c +++ b/samples/subsys/usb/webusb/src/main.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2016-2019 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,30 +24,49 @@ LOG_MODULE_REGISTER(main); #include "webusb.h" -/* Predefined response to control commands related to MS OS 2.0 descriptors */ -static const uint8_t msos2_descriptor[] = { - /* MS OS 2.0 set header descriptor */ - 0x0A, 0x00, /* Descriptor size (10 bytes) */ - 0x00, 0x00, /* MS_OS_20_SET_HEADER_DESCRIPTOR */ - 0x00, 0x00, 0x03, 0x06, /* Windows version (8.1) (0x06030000) */ - (0x0A + 0x14 + 0x08), 0x00, /* Length of the MS OS 2.0 descriptor set */ - - /* MS OS 2.0 function subset ID descriptor - * This means that the descriptors below will only apply to one - * set of interfaces +#include "msosv2_defs.h" + +/* random GUID {FA611CC3-7057-42EE-9D82-4919639562B3} */ +#define WEBUSB_DEVICE_INTERFACE_GUID \ + '{', 0x00, 'F', 0x00, 'A', 0x00, '6', 0x00, '1', 0x00, '1', 0x00, \ + 'C', 0x00, 'C', 0x00, '3', 0x00, '-', 0x00, '7', 0x00, '0', 0x00, \ + '5', 0x00, '7', 0x00, '-', 0x00, '4', 0x00, '2', 0x00, 'E', 0x00, \ + 'E', 0x00, '-', 0x00, '9', 0x00, 'D', 0x00, '8', 0x00, '2', 0x00, \ + '-', 0x00, '4', 0x00, '9', 0x00, '1', 0x00, '9', 0x00, '6', 0x00, \ + '3', 0x00, '9', 0x00, '5', 0x00, '6', 0x00, '2', 0x00, 'B', 0x00, \ + '3', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00 + +#define COMPATIBLE_ID_WINUSB \ + 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00 + +static struct msosv2_descriptor_t { + struct ms_os_20_descriptor_set_header_descriptor header; + struct ms_os_20_compatible_id_descriptor webusb_compatible_id; + struct ms_os_20_guids_property_descriptor webusb_guids_property; +} __packed msosv2_descriptor = { + /* Microsoft OS 2.0 descriptor set + * This tells Windows what kind of device this is and to install the WinUSB driver. */ - 0x08, 0x00, /* Descriptor size (8 bytes) */ - 0x02, 0x00, /* MS_OS_20_SUBSET_HEADER_FUNCTION */ - 0x02, /* Index of first interface this subset applies to. */ - 0x00, /* reserved */ - (0x08 + 0x14), 0x00, /* Length of the MS OS 2.0 descriptor subset */ - - /* MS OS 2.0 compatible ID descriptor */ - 0x14, 0x00, /* Descriptor size */ - 0x03, 0x00, /* MS_OS_20_FEATURE_COMPATIBLE_ID */ - /* 8-byte compatible ID string, then 8-byte sub-compatible ID string */ - 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .header = { + .wLength = sizeof(struct ms_os_20_descriptor_set_header_descriptor), + .wDescriptorType = MS_OS_20_SET_HEADER_DESCRIPTOR, + .dwWindowsVersion = 0x06030000, + .wTotalLength = sizeof(struct msosv2_descriptor_t), + }, + .webusb_compatible_id = { + .wLength = sizeof(struct ms_os_20_compatible_id_descriptor), + .wDescriptorType = MS_OS_20_FEATURE_COMPATIBLE_ID, + .CompatibleID = {COMPATIBLE_ID_WINUSB}, + }, + .webusb_guids_property = { + .wLength = sizeof(struct ms_os_20_guids_property_descriptor), + .wDescriptorType = MS_OS_20_FEATURE_REG_PROPERTY, + .wPropertyDataType = MS_OS_20_PROPERTY_DATA_REG_MULTI_SZ, + .wPropertyNameLength = 42, + .PropertyName = {DEVICE_INTERFACE_GUIDS_PROPERTY_NAME}, + .wPropertyDataLength = 80, + .bPropertyData = {WEBUSB_DEVICE_INTERFACE_GUID}, + }, }; USB_DEVICE_BOS_DESC_DEFINE_CAP struct usb_bos_webusb_desc { @@ -113,7 +133,7 @@ USB_DEVICE_BOS_DESC_DEFINE_CAP struct usb_bos_msosv2_desc { /* Windows version (8.1) (0x06030000) */ .dwWindowsVersion = sys_cpu_to_le32(0x06030000), .wMSOSDescriptorSetTotalLength = - sys_cpu_to_le16(sizeof(msos2_descriptor)), + sys_cpu_to_le16(sizeof(msosv2_descriptor)), .bMS_VendorCode = 0x02, .bAltEnumCode = 0x00 }, @@ -198,6 +218,8 @@ static const uint8_t msos1_compatid_descriptor[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* reserved */ }; + + /** * @brief Custom handler for standard requests in * order to catch the request and return the @@ -271,8 +293,8 @@ int vendor_handle_req(struct usb_setup_packet *pSetup, } else if (pSetup->bRequest == 0x02 && pSetup->wIndex == 0x07) { /* Get MS OS 2.0 Descriptors request */ /* 0x07 means "MS_OS_20_DESCRIPTOR_INDEX" */ - *data = (uint8_t *)(&msos2_descriptor); - *len = sizeof(msos2_descriptor); + *data = (uint8_t *)(&msosv2_descriptor); + *len = sizeof(msosv2_descriptor); LOG_DBG("Get MS OS Descriptors v2"); diff --git a/samples/subsys/usb/webusb/src/msosv2_defs.h b/samples/subsys/usb/webusb/src/msosv2_defs.h new file mode 100644 index 000000000000000..2f96c2886cd96e6 --- /dev/null +++ b/samples/subsys/usb/webusb/src/msosv2_defs.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief MS OS 2.0 descriptor definitions + * + */ + +#include + +enum ms_os_20_type_t { + MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00, + MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01, + MS_OS_20_SUBSET_HEADER_FUNCTION = 0x02, + MS_OS_20_FEATURE_COMPATIBLE_ID = 0x03, + MS_OS_20_FEATURE_REG_PROPERTY = 0x04, + MS_OS_20_FEATURE_MIN_RESUME_TIME = 0x05, + MS_OS_20_FEATURE_MODEL_ID = 0x06, + MS_OS_20_FEATURE_CCGP_DEVICE = 0x07, + MS_OS_20_FEATURE_VENDOR_REVISION = 0x08 +}; + +enum ms_os_20_property_data_type_t { + MS_OS_20_PROPERTY_DATA_RESERVED = 0, + MS_OS_20_PROPERTY_DATA_REG_SZ = 1, + MS_OS_20_PROPERTY_DATA_REG_EXPAND_SZ = 2, + MS_OS_20_PROPERTY_DATA_REG_BINARY = 3, + MS_OS_20_PROPERTY_DATA_REG_DWORD_LITTLE_ENDIAN = 4, + MS_OS_20_PROPERTY_DATA_REG_DWORD_BIG_ENDIAN = 5, + MS_OS_20_PROPERTY_DATA_REG_LINK = 6, + MS_OS_20_PROPERTY_DATA_REG_MULTI_SZ = 7 +}; + +/* Microsoft OS 2.0 descriptor set header */ +struct ms_os_20_descriptor_set_header_descriptor { + uint16_t wLength; /* The length of this descriptor in bytes. */ + uint16_t wDescriptorType; /* MS_OS_20_SET_HEADER_DESCRIPTOR */ + uint32_t dwWindowsVersion; /* Windows 8.1: 0x06030000 */ + uint16_t wTotalLength; /* The size of entire MS OS 2.0 descriptor set. */ +} __packed; + +/* Microsoft OS 2.0 configuration subset header + * This is header is for composite devices with multiple configurations. + */ +struct ms_os_20_configuration_subset_header_descriptor { + uint16_t wLength; /* The length of this descriptor in bytes. */ + uint16_t wDescriptorType; /* MS_OS_20_SUBSET_HEADER_CONFIGURATION */ + uint8_t bConfigurationValue; /* Configuration of this subset. */ + uint8_t bReserved; /* 0 */ + uint16_t wTotalLength; /* The size of entire configuration subset including this header. */ +} __packed; + +/* Microsoft OS 2.0 function subset header + * Note: This must be used if your device has multiple interfaces and cannot be used otherwise. + */ +struct ms_os_20_function_subset_header_descriptor { + uint16_t wLength; /* The length of this descriptor in bytes. */ + uint16_t wDescriptorType; /* MS_OS_20_SUBSET_HEADER_FUNCTION */ + uint8_t bFirstInterface; /* First USB interface of this subset. */ + uint8_t bReserved; /* 0 */ + uint16_t wSubsetLength; /* The size of entire function subset including this header.*/ +} __packed; + +/* Microsoft OS 2.0 compatible ID descriptor */ +struct ms_os_20_compatible_id_descriptor { + uint16_t wLength; /* The length of this descriptor in bytes. */ + uint16_t wDescriptorType; /* MS_OS_20_FEATURE_COMPATIBLE_ID */ + uint8_t CompatibleID[8]; /* Compatible ID String */ + uint8_t SubCompatibleID[8]; /* Sub-compatible ID String */ +} __packed; + +/* Microsoft OS 2.0 Registry property descriptor: DeviceInterfaceGUIDs */ +struct ms_os_20_guids_property_descriptor { + uint16_t wLength; /* The length of this descriptor in bytes. */ + uint16_t wDescriptorType; /* MS_OS_20_FEATURE_REG_PROPERTY */ + uint16_t wPropertyDataType; /* MS_OS_20_PROPERTY_DATA_REG_MULTI_SZ */ + uint16_t wPropertyNameLength; /* 42 */ + uint8_t PropertyName[42]; /* "DeviceInterfaceGUIDs\0" in UTF-16 */ + uint16_t wPropertyDataLength; /* 80 */ + uint8_t bPropertyData[80]; /* “{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\0” */ +} __packed; + +/* DeviceInterfaceGUIDs */ +#define DEVICE_INTERFACE_GUIDS_PROPERTY_NAME \ + 'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, \ + 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00, \ + 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, \ + 'D', 0x00, 's', 0x00, 0x00, 0x00