Skip to content

Commit c91bb99

Browse files
committed
pbio/drv/usb: Deduplicate common descriptors
These descriptors are expected to be the same on all devices, so moving them to a new file reduces duplicate code.
1 parent c2b67a0 commit c91bb99

File tree

8 files changed

+196
-401
lines changed

8 files changed

+196
-401
lines changed

bricks/_common/sources.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\
186186
drv/uart/uart_stm32f0.c \
187187
drv/uart/uart_stm32f4_ll_irq.c \
188188
drv/uart/uart_stm32l4_ll_dma.c \
189+
drv/usb/usb_common_desc.c \
189190
drv/usb/usb_ev3.c \
190191
drv/usb/usb_nxt.c \
191192
drv/usb/usb_stm32.c \

lib/pbio/drv/usb/stm32_usbd/usbd_desc.c

Lines changed: 45 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
#undef EP_TYPE_BULK
6262
#undef EP_TYPE_INTR
6363
#include "../usb_ch9.h"
64+
#include "../usb_common_desc.h"
6465

6566
/* Private typedef -----------------------------------------------------------*/
6667
/* Private define ------------------------------------------------------------*/
@@ -79,7 +80,6 @@
7980

8081
// descriptor sizes
8182
#define USB_SIZ_STRING_SERIAL 26
82-
#define USB_SIZ_BOS_DESC (5 + 28 + 24)
8383

8484
/* USB Standard Device Descriptor */
8585
static
@@ -106,153 +106,49 @@ pbdrv_usb_dev_desc_union_t USBD_DeviceDesc = {
106106
}; /* USB_DeviceDescriptor */
107107

108108
/** BOS descriptor. */
109-
__ALIGN_BEGIN static const uint8_t USBD_BOSDesc[] __ALIGN_END =
110-
{
111-
5, /* bLength */
112-
USB_DESC_TYPE_BOS, /* bDescriptorType = BOS */
113-
LOBYTE(USB_SIZ_BOS_DESC), /* wTotalLength */
114-
HIBYTE(USB_SIZ_BOS_DESC), /* wTotalLength */
115-
2, /* bNumDeviceCaps */
116-
117-
// IMPORTANT: The WebUSB descriptor must be first to make Chromium happy.
118-
119-
24, /* bLength */
120-
USB_DEVICE_CAPABITY_TYPE, /* bDescriptorType = Device Capability */
121-
USB_DEV_CAP_TYPE_PLATFORM, /* bDevCapabilityType */
122-
0x00, /* bReserved */
123-
124-
/*
125-
* PlatformCapabilityUUID
126-
* WebUSB Platform Capability descriptor
127-
* 3408B638-09A9-47A0-8BFD-A0768815B665
128-
* RFC 4122 explains the correct byte ordering
129-
*/
130-
0x38, 0xB6, 0x08, 0x34, /* 32-bit value */
131-
0xA9, 0x09, /* 16-bit value */
132-
0xA0, 0x47, /* 16-bit value */
133-
0x8B, 0xFD,
134-
0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65,
135-
136-
LOBYTE(0x0100), /* bcdVersion */
137-
HIBYTE(0x0100), /* bcdVersion */
138-
USBD_VENDOR_CODE_WEBUSB, /* bVendorCode */
139-
USBD_WEBUSB_LANDING_PAGE_IDX, /* iLandingPage */
140-
141-
// IMPORTANT: The MS OS 2.0 descriptor must be last to make Chromium happy.
142-
143-
28, /* bLength */
144-
USB_DEVICE_CAPABITY_TYPE, /* bDescriptorType = Device Capability */
145-
USB_DEV_CAP_TYPE_PLATFORM, /* bDevCapabilityType */
146-
0x00, /* bReserved */
147-
148-
/*
149-
* PlatformCapabilityUUID
150-
* Microsoft OS 2.0 descriptor platform capability ID
151-
* D8DD60DF-4589-4CC7-9CD2-659D9E648A9F
152-
* RFC 4122 explains the correct byte ordering
153-
*/
154-
0xDF, 0x60, 0xDD, 0xD8, /* 32-bit value */
155-
0x89, 0x45, /* 16-bit value */
156-
0xC7, 0x4C, /* 16-bit value */
157-
0x9C, 0xD2,
158-
0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F,
159-
160-
0x00, 0x00, 0x03, 0x06, /* dwWindowsVersion = 0x06030000 for Windows 8.1 Build */
161-
LOBYTE(USBD_SIZ_MS_OS_DSCRPTR_SET), /* wMSOSDescriptorSetTotalLength */
162-
HIBYTE(USBD_SIZ_MS_OS_DSCRPTR_SET), /* wMSOSDescriptorSetTotalLength */
163-
USBD_VENDOR_CODE_MS, /* bMS_VendorCode */
164-
0x00, /* bAltEnumCode = Does not support alternate enumeration */
165-
};
166-
_Static_assert(USB_SIZ_BOS_DESC == sizeof(USBD_BOSDesc));
167-
168-
__ALIGN_BEGIN const uint8_t USBD_OSDescSet[] __ALIGN_END =
169-
{
170-
0x0A, 0x00, /* wLength = 10 */
171-
0x00, 0x00, /* wDescriptorType = MS_OS_20_SET_HEADER_DESCRIPTOR */
172-
0x00, 0x00, 0x03, 0x06, /* dwWindowsVersion = 0x06030000 for Windows 8.1 Build */
173-
LOBYTE(USBD_SIZ_MS_OS_DSCRPTR_SET), /* wTotalLength */
174-
HIBYTE(USBD_SIZ_MS_OS_DSCRPTR_SET), /* wTotalLength (cont.) */
175-
176-
0x14, 0x00, /* wLength = 20 */
177-
0x03, 0x00, /* wDescriptorType = MS_OS_20_FEATURE_COMPATBLE_ID */
178-
'W', 'I', 'N', 'U', 'S', 'B', /* CompatibleID */
179-
0x00, 0x00, /* CompatibleID (cont.) */
180-
0x00, 0x00, 0x00, 0x00, /* SubCompatibleID */
181-
0x00, 0x00, 0x00, 0x00, /* SubCompatibleID (cont.) */
182-
183-
0x84, 0x00, /* wLength = 132 */
184-
0x04, 0x00, /* wDescriptorType = MS_OS_20_FEATURE_REG_PROPERTY */
185-
0x07, 0x00, /* wStringType = REG_MULTI_SZ */
186-
/* wPropertyNameLength = 42 */
187-
0x2A, 0x00,
188-
/* PropertyName = DeviceInterfaceGUIDs */
189-
'D', '\0',
190-
'e', '\0',
191-
'v', '\0',
192-
'i', '\0',
193-
'c', '\0',
194-
'e', '\0',
195-
'I', '\0',
196-
'n', '\0',
197-
't', '\0',
198-
'e', '\0',
199-
'r', '\0',
200-
'f', '\0',
201-
'a', '\0',
202-
'c', '\0',
203-
'e', '\0',
204-
'G', '\0',
205-
'U', '\0',
206-
'I', '\0',
207-
'D', '\0',
208-
's', '\0',
209-
'\0', '\0',
210-
211-
/* wPropertyDataLength = 80 */
212-
0x50, 0x00,
213-
/* PropertyData = {A5C44A4C-53D4-4389-9821-AE95051908A1} */
214-
'{', '\0',
215-
'A', '\0',
216-
'5', '\0',
217-
'C', '\0',
218-
'4', '\0',
219-
'4', '\0',
220-
'A', '\0',
221-
'4', '\0',
222-
'C', '\0',
223-
'-', '\0',
224-
'5', '\0',
225-
'3', '\0',
226-
'D', '\0',
227-
'4', '\0',
228-
'-', '\0',
229-
'4', '\0',
230-
'3', '\0',
231-
'8', '\0',
232-
'9', '\0',
233-
'-', '\0',
234-
'9', '\0',
235-
'8', '\0',
236-
'2', '\0',
237-
'1', '\0',
238-
'-', '\0',
239-
'A', '\0',
240-
'E', '\0',
241-
'9', '\0',
242-
'5', '\0',
243-
'0', '\0',
244-
'5', '\0',
245-
'1', '\0',
246-
'9', '\0',
247-
'0', '\0',
248-
'8', '\0',
249-
'A', '\0',
250-
'1', '\0',
251-
'}', '\0',
252-
'\0', '\0',
253-
'\0', '\0'
109+
typedef struct PBDRV_PACKED {
110+
pbdrv_usb_bos_desc_t bos;
111+
// WebUSB must occur before Microsoft OS descriptors
112+
pbdrv_usb_webusb_capability_t webusb;
113+
pbdrv_usb_microsoft_20_capability_t ms_20;
114+
} pbdrv_usb_stm32_bos_desc_set_t;
115+
PBDRV_USB_TYPE_PUNNING_HELPER(pbdrv_usb_stm32_bos_desc_set);
116+
117+
static const pbdrv_usb_stm32_bos_desc_set_union_t USBD_BOSDesc = {
118+
.s = {
119+
.bos = {
120+
.bLength = sizeof(pbdrv_usb_bos_desc_t),
121+
.bDescriptorType = DESC_TYPE_BOS,
122+
.wTotalLength = sizeof(pbdrv_usb_stm32_bos_desc_set_t),
123+
.bNumDeviceCaps = 2,
124+
},
125+
.webusb = {
126+
.hdr = {
127+
.bLength = sizeof(pbdrv_usb_webusb_capability_t),
128+
.bDescriptorType = DESC_TYPE_DEVICE_CAPABILITY,
129+
.bDevCapabilityType = USB_DEVICE_CAPABILITY_TYPE_PLATFORM,
130+
.bReserved = 0,
131+
.uuid = USB_PLATFORM_CAP_GUID_WEBUSB,
132+
},
133+
.bcdVersion = 0x0100,
134+
.bVendorCode = USBD_VENDOR_CODE_WEBUSB,
135+
.iLandingPage = USBD_WEBUSB_LANDING_PAGE_IDX,
136+
},
137+
.ms_20 = {
138+
.hdr = {
139+
.bLength = sizeof(pbdrv_usb_microsoft_20_capability_t),
140+
.bDescriptorType = DESC_TYPE_DEVICE_CAPABILITY,
141+
.bDevCapabilityType = USB_DEVICE_CAPABILITY_TYPE_PLATFORM,
142+
.bReserved = 0,
143+
.uuid = USB_PLATFORM_CAP_GUID_MS_20,
144+
},
145+
.dwWindowsVersion = MS_WINDOWS_VERSION_81,
146+
.wMSOSDescriptorSetTotalLength = sizeof(pbdrv_usb_ms_20_desc_set_t),
147+
.bMS_VendorCode = USBD_VENDOR_CODE_MS,
148+
.bAltEnumCode = 0,
149+
}
150+
}
254151
};
255-
_Static_assert(USBD_SIZ_MS_OS_DSCRPTR_SET == sizeof(USBD_OSDescSet));
256152

257153
/* USB Standard Device Descriptor */
258154
__ALIGN_BEGIN static const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = {
@@ -410,8 +306,8 @@ static uint8_t *USBD_Pybricks_BOSDescriptor(USBD_SpeedTypeDef speed, uint16_t *l
410306
/* Prevent unused argument(s) compilation warning */
411307
UNUSED(speed);
412308

413-
*length = USB_SIZ_BOS_DESC;
414-
return (uint8_t *)USBD_BOSDesc;
309+
*length = sizeof(USBD_BOSDesc.s);
310+
return (uint8_t *)&USBD_BOSDesc;
415311
}
416312

417313
USBD_DescriptorsTypeDef USBD_Pybricks_Desc = {

lib/pbio/drv/usb/stm32_usbd/usbd_pybricks.c

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#undef EP_TYPE_BULK
5050
#undef EP_TYPE_INTR
5151
#include "../usb_ch9.h"
52+
#include "../usb_common_desc.h"
5253

5354

5455
/** @addtogroup STM32_USB_DEVICE_LIBRARY
@@ -169,27 +170,6 @@ static pbdrv_usb_stm32_conf_union_t USBD_Pybricks_CfgDesc = {
169170
}
170171
};
171172

172-
__ALIGN_BEGIN static const uint8_t WebUSB_DescSet[] __ALIGN_END =
173-
{
174-
#if PBIO_VERSION_LEVEL_HEX == 0xA
175-
21, /* bLength */
176-
#else
177-
20, /* bLength */
178-
#endif
179-
0x03, /* bDescriptorType = URL */
180-
0x01, /* bScheme = https:// */
181-
182-
/* URL */
183-
#if PBIO_VERSION_LEVEL_HEX == 0xA
184-
'a', 'l', 'p', 'h', 'a',
185-
#elif PBIO_VERSION_LEVEL_HEX == 0xB
186-
'b', 'e', 't', 'a',
187-
#else
188-
'c', 'o', 'd', 'e',
189-
#endif
190-
'.', 'p', 'y', 'b', 'r', 'i', 'c', 'k', 's', '.', 'c', 'o', 'm'
191-
};
192-
193173
/**
194174
* @}
195175
*/
@@ -276,15 +256,15 @@ static USBD_StatusTypeDef USBD_Pybricks_Setup(USBD_HandleTypeDef *pdev,
276256
{
277257
case USBD_VENDOR_CODE_MS:
278258
(void)USBD_CtlSendData(pdev,
279-
(uint8_t *)USBD_OSDescSet,
280-
MIN(sizeof(USBD_OSDescSet), req->wLength));
259+
(uint8_t *)&pbdrv_usb_ms_20_desc_set,
260+
MIN(pbdrv_usb_ms_20_desc_set.s.desc_set_hdr.wTotalLength, req->wLength));
281261
break;
282262

283263
case USBD_VENDOR_CODE_WEBUSB:
284264
if ((req->wValue == USBD_WEBUSB_LANDING_PAGE_IDX) && (req->wIndex == 0x02)) {
285265
(void)USBD_CtlSendData(pdev,
286-
(uint8_t *)WebUSB_DescSet,
287-
MIN(sizeof(WebUSB_DescSet), req->wLength));
266+
(uint8_t *)&pbdrv_usb_webusb_landing_page,
267+
MIN(pbdrv_usb_webusb_landing_page.s.bLength, req->wLength));
288268
}
289269
break;
290270

lib/pbio/drv/usb/stm32_usbd/usbd_pybricks.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,6 @@ typedef struct
120120

121121
extern USBD_ClassTypeDef USBD_Pybricks_ClassDriver;
122122

123-
#define USBD_SIZ_MS_OS_DSCRPTR_SET (10 + 20 + 132)
124-
extern const uint8_t USBD_OSDescSet[USBD_SIZ_MS_OS_DSCRPTR_SET];
125-
126123
/**
127124
* @}
128125
*/

lib/pbio/drv/usb/usb_common_desc.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2025 The Pybricks Authors
3+
4+
// Descriptors which are shared across devices
5+
// (i.e. WebUSB, Microsoft OS descriptors)
6+
7+
#include <pbdrv/config.h>
8+
9+
#if PBDRV_CONFIG_USB
10+
11+
#include "usb_common_desc.h"
12+
13+
#if PBIO_VERSION_LEVEL_HEX == 0xA
14+
#define PYBRICKS_CODE_URL "alpha.code.pybricks.com"
15+
#elif PBIO_VERSION_LEVEL_HEX == 0xB
16+
#define PYBRICKS_CODE_URL "beta.code.pybricks.com"
17+
#else
18+
#define PYBRICKS_CODE_URL "code.pybricks.com"
19+
#endif
20+
const pbdrv_usb_webusb_url_desc_union_t pbdrv_usb_webusb_landing_page = {
21+
.s = {
22+
.bLength = sizeof(pbdrv_usb_webusb_url_desc_t) + sizeof(PYBRICKS_CODE_URL) - 1,
23+
.bDescriptorType = WEBUSB_DESC_TYPE_URL,
24+
.bScheme = WEBUSB_URL_SCHEME_HTTPS,
25+
.url = PYBRICKS_CODE_URL,
26+
},
27+
};
28+
29+
#define MS_20_REGISTRY_DATA_EXTRA_SZ \
30+
2 + 2 * sizeof("DeviceInterfaceGUIDs") + \
31+
2 + 2 * sizeof("{A5C44A4C-53D4-4389-9821-AE95051908A1}") + \
32+
2
33+
34+
const pbdrv_usb_ms_20_desc_set_union_t pbdrv_usb_ms_20_desc_set = {
35+
.s = {
36+
.desc_set_hdr = {
37+
.wLength = sizeof(pbdrv_usb_ms_20_desc_set_header_t),
38+
.wDescriptorType = MS_OS_20_SET_HEADER_DESCRIPTOR,
39+
.dwWindowsVersion = MS_WINDOWS_VERSION_81,
40+
.wTotalLength = sizeof(pbdrv_usb_ms_20_desc_set_t),
41+
},
42+
.compatible = {
43+
.wLength = sizeof(pbdrv_usb_ms_20_compatible_t),
44+
.wDescriptorType = MS_OS_20_FEATURE_COMPATBLE_ID,
45+
.CompatibleID = "WINUSB",
46+
.SubCompatibleID = "",
47+
},
48+
.reg_prop_hdr = {
49+
.wLength = sizeof(pbdrv_usb_ms_20_reg_prop_hdr_t) + MS_20_REGISTRY_DATA_EXTRA_SZ,
50+
.wDescriptorType = MS_OS_20_FEATURE_REG_PROPERTY,
51+
.wPropertyDataType = MS_OS_20_REG_PROP_TYPE_REG_MULTI_SZ,
52+
},
53+
.device_interface_guids = {
54+
2 * sizeof("DeviceInterfaceGUIDs"), /* Length */
55+
'D', 'e', 'v', 'i', 'c', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 'G', 'U', 'I', 'D', 's',
56+
},
57+
.device_interface_guid_val = {
58+
2 * sizeof("{A5C44A4C-53D4-4389-9821-AE95051908A1}"), /* Length */
59+
'{', 'A', '5', 'C', '4', '4', 'A', '4', 'C', '-', '5', '3', 'D', '4', '-', '4', '3', '8', '9',
60+
'-', '9', '8', '2', '1', '-', 'A', 'E', '9', '5', '0', '5', '1', '9', '0', '8', 'A', '1', '}',
61+
}
62+
}
63+
};
64+
65+
#endif // PBDRV_CONFIG_USB

lib/pbio/drv/usb/usb_common_desc.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2025 The Pybricks Authors
3+
4+
// Descriptors which are shared across devices
5+
// (i.e. WebUSB, Microsoft OS descriptors)
6+
7+
#ifndef _INTERNAL_PBDRV_USB_COMMON_DESC_H_
8+
#define _INTERNAL_PBDRV_USB_COMMON_DESC_H_
9+
10+
#include "usb_ch9.h"
11+
12+
// Complete set of Microsoft USB descriptors
13+
typedef struct PBDRV_PACKED {
14+
pbdrv_usb_ms_20_desc_set_header_t desc_set_hdr;
15+
pbdrv_usb_ms_20_compatible_t compatible;
16+
pbdrv_usb_ms_20_reg_prop_hdr_t reg_prop_hdr;
17+
uint16_t device_interface_guids[sizeof("DeviceInterfaceGUIDs") + 1];
18+
uint16_t device_interface_guid_val[sizeof("{A5C44A4C-53D4-4389-9821-AE95051908A1}") + 1];
19+
uint16_t _multi_sz_end;
20+
} pbdrv_usb_ms_20_desc_set_t;
21+
PBDRV_USB_TYPE_PUNNING_HELPER(pbdrv_usb_ms_20_desc_set);
22+
23+
extern const pbdrv_usb_ms_20_desc_set_union_t pbdrv_usb_ms_20_desc_set;
24+
25+
// WebUSB descriptor
26+
extern const pbdrv_usb_webusb_url_desc_union_t pbdrv_usb_webusb_landing_page;
27+
28+
#endif // _INTERNAL_PBDRV_USB_COMMON_DESC_H_

0 commit comments

Comments
 (0)