Skip to content

Commit

Permalink
samples: subsys: usb: webusb: Fix Win10 detection
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
maxd-nordic committed Jun 26, 2023
1 parent 8042218 commit 36616c5
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 26 deletions.
74 changes: 48 additions & 26 deletions samples/subsys/usb/webusb/src/main.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2016-2019 Intel Corporation
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -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 {
Expand Down Expand Up @@ -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
},
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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");

Expand Down
92 changes: 92 additions & 0 deletions samples/subsys/usb/webusb/src/msosv2_defs.h
Original file line number Diff line number Diff line change
@@ -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 <stdint.h>

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

0 comments on commit 36616c5

Please sign in to comment.