Skip to content

Commit e9bcd49

Browse files
committed
stm32/mboot: Add support for Microsoft WCID.
This adds support to stm32's mboot for the Microsoft WCID USB 0xee string and Compatible ID Feature Descriptor. This allows the USB device to automatically set the default USB driver, so that when the device is plugged in Windows will assign the winusb driver to it. This means that USB DFU mode can be used without installing any drivers. For example this page will work (allow the board to be updated over DFU) with zero install: https://devanlai.github.io/webdfu/dfu-util/ Tested on Windows 10, Windows can read the 0xee string correctly, and requests the second special descriptor, which then configures the USB device to use the winusb driver. Signed-off-by: Damien George <damien@micropython.org>
1 parent 49d0c22 commit e9bcd49

File tree

2 files changed

+64
-5
lines changed

2 files changed

+64
-5
lines changed

ports/stm32/mboot/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ CFLAGS += -DLFS1_NO_MALLOC -DLFS1_NO_DEBUG -DLFS1_NO_WARN -DLFS1_NO_ERROR -DLFS1
7676
CFLAGS += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT -DLFS2_READONLY
7777
CFLAGS += -DBUILDING_MBOOT=$(BUILDING_MBOOT)
7878
CFLAGS += -DMICROPY_HW_STM32WB_FLASH_SYNCRONISATION=0
79+
CFLAGS += -DUSBD_ENABLE_VENDOR_DEVICE_REQUESTS=1
7980
CFLAGS += -DBOOTLOADER_DFU_USB_VID=$(BOOTLOADER_DFU_USB_VID) -DBOOTLOADER_DFU_USB_PID=$(BOOTLOADER_DFU_USB_PID)
8081

8182
MBOOT_LD_FILES ?= stm32_memory.ld stm32_sections.ld

ports/stm32/mboot/main.c

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,18 @@ typedef struct _pyb_usbdd_obj_t {
10021002
#define MBOOT_USB_PID BOOTLOADER_DFU_USB_PID
10031003
#endif
10041004

1005+
// Special string descriptor value for Microsoft WCID support.
1006+
// If the USB device responds to this string with the correct data (see msft100_str_desc)
1007+
// then the Windows host will request further information about the configuration of
1008+
// the device (see msft100_id). This allows the device to set a Windows USB driver.
1009+
// For more details about WCID see:
1010+
// - https://github.com/pbatard/libwdi/wiki/WCID-Devices
1011+
// - https://github.com/newaetech/naeusb/blob/main/wcid.md
1012+
#define MSFT_WCID_STR_DESC_VALUE (0xee)
1013+
1014+
// Vendor code, can be anything.
1015+
#define MSFT100_VENDOR_CODE (0x42)
1016+
10051017
#if !MICROPY_HW_USB_IS_MULTI_OTG
10061018
STATIC const uint8_t usbd_fifo_size[USBD_PMA_NUM_FIFO] = {
10071019
32, 32, // EP0(out), EP0(in)
@@ -1026,14 +1038,14 @@ __ALIGN_BEGIN static const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __AL
10261038
static const uint8_t dev_descr[0x12] = {
10271039
0x12, // bLength
10281040
0x01, // bDescriptorType: Device
1029-
0x00, 0x01, // USB version: 1.00
1041+
0x00, 0x02, // USB version: 2.00
10301042
0x00, // bDeviceClass
10311043
0x00, // bDeviceSubClass
10321044
0x00, // bDeviceProtocol
10331045
0x40, // bMaxPacketSize
10341046
LOBYTE(MBOOT_USB_VID), HIBYTE(MBOOT_USB_VID),
10351047
LOBYTE(MBOOT_USB_PID), HIBYTE(MBOOT_USB_PID),
1036-
0x00, 0x22, // bcdDevice: 22.00
1048+
0x00, 0x03, // bcdDevice: 3.00
10371049
0x01, // iManufacturer
10381050
0x02, // iProduct
10391051
0x03, // iSerialNumber
@@ -1047,6 +1059,32 @@ static uint8_t cfg_descr[9 + 9 + 9] =
10471059
"\x09\x21\x0b\xff\x00\x00\x08\x1a\x01" // \x00\x08 goes with USB_XFER_SIZE
10481060
;
10491061

1062+
__ALIGN_BEGIN static const uint8_t msft100_str_desc[18] __ALIGN_END = {
1063+
0x12, 0x03,
1064+
'M', 0x00,
1065+
'S', 0x00,
1066+
'F', 0x00,
1067+
'T', 0x00,
1068+
'1', 0x00,
1069+
'0', 0x00,
1070+
'0', 0x00,
1071+
MSFT100_VENDOR_CODE,
1072+
0x00,
1073+
};
1074+
1075+
__ALIGN_BEGIN static const uint8_t msft100_id[40] __ALIGN_END = {
1076+
0x28, 0x00, 0x00, 0x00,
1077+
0x00, 0x01, // 1.00
1078+
0x04, 0x00,
1079+
0x01,
1080+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1081+
0x00,
1082+
0x01,
1083+
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
1084+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1085+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1086+
};
1087+
10501088
static uint8_t *pyb_usbdd_DeviceDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) {
10511089
*length = USB_LEN_DEV_DESC;
10521090
return (uint8_t *)dev_descr;
@@ -1131,6 +1169,10 @@ static uint8_t *pyb_usbdd_StrDescriptor(USBD_HandleTypeDef *pdev, uint8_t idx, u
11311169
return str_desc;
11321170
#endif
11331171

1172+
case MSFT_WCID_STR_DESC_VALUE:
1173+
*length = sizeof(msft100_str_desc);
1174+
return (uint8_t *)msft100_str_desc; // the data should only be read from this buf
1175+
11341176
default:
11351177
return NULL;
11361178
}
@@ -1159,8 +1201,24 @@ static uint8_t pyb_usbdd_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *r
11591201
self->bRequest = req->bRequest;
11601202
self->wValue = req->wValue;
11611203
self->wLength = req->wLength;
1162-
if (req->bmRequest == 0x21) {
1163-
// host-to-device request
1204+
1205+
if ((req->bmRequest & 0xe0) == 0xc0) {
1206+
// device-to-host vendor request
1207+
if (req->wIndex == 0x04 && req->bRequest == MSFT100_VENDOR_CODE) {
1208+
// WCID: Compatible ID Feature Descriptor
1209+
#if USE_USB_POLLING
1210+
self->tx_pending = true;
1211+
#endif
1212+
int len = MIN(req->wLength, 40);
1213+
memcpy(self->tx_buf, msft100_id, len);
1214+
USBD_CtlSendData(&self->hUSBDDevice, self->tx_buf, len);
1215+
return USBD_OK;
1216+
} else {
1217+
USBD_CtlError(pdev, req);
1218+
return USBD_OK;
1219+
}
1220+
} else if (req->bmRequest == 0x21) {
1221+
// host-to-device class request
11641222
if (req->wLength == 0) {
11651223
// no data, process command straight away
11661224
dfu_handle_rx(self->bRequest, self->wValue, 0, NULL);
@@ -1169,7 +1227,7 @@ static uint8_t pyb_usbdd_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *r
11691227
USBD_CtlPrepareRx(pdev, self->rx_buf, req->wLength);
11701228
}
11711229
} else if (req->bmRequest == 0xa1) {
1172-
// device-to-host request
1230+
// device-to-host class request
11731231
int len = dfu_handle_tx(self->bRequest, self->wValue, self->wLength, self->tx_buf, USB_XFER_SIZE);
11741232
if (len >= 0) {
11751233
#if USE_USB_POLLING

0 commit comments

Comments
 (0)