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>
This commit is contained in:
parent
49d0c22b11
commit
e9bcd49b3e
|
@ -76,6 +76,7 @@ CFLAGS += -DLFS1_NO_MALLOC -DLFS1_NO_DEBUG -DLFS1_NO_WARN -DLFS1_NO_ERROR -DLFS1
|
|||
CFLAGS += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT -DLFS2_READONLY
|
||||
CFLAGS += -DBUILDING_MBOOT=$(BUILDING_MBOOT)
|
||||
CFLAGS += -DMICROPY_HW_STM32WB_FLASH_SYNCRONISATION=0
|
||||
CFLAGS += -DUSBD_ENABLE_VENDOR_DEVICE_REQUESTS=1
|
||||
CFLAGS += -DBOOTLOADER_DFU_USB_VID=$(BOOTLOADER_DFU_USB_VID) -DBOOTLOADER_DFU_USB_PID=$(BOOTLOADER_DFU_USB_PID)
|
||||
|
||||
MBOOT_LD_FILES ?= stm32_memory.ld stm32_sections.ld
|
||||
|
|
|
@ -1002,6 +1002,18 @@ typedef struct _pyb_usbdd_obj_t {
|
|||
#define MBOOT_USB_PID BOOTLOADER_DFU_USB_PID
|
||||
#endif
|
||||
|
||||
// Special string descriptor value for Microsoft WCID support.
|
||||
// If the USB device responds to this string with the correct data (see msft100_str_desc)
|
||||
// then the Windows host will request further information about the configuration of
|
||||
// the device (see msft100_id). This allows the device to set a Windows USB driver.
|
||||
// For more details about WCID see:
|
||||
// - https://github.com/pbatard/libwdi/wiki/WCID-Devices
|
||||
// - https://github.com/newaetech/naeusb/blob/main/wcid.md
|
||||
#define MSFT_WCID_STR_DESC_VALUE (0xee)
|
||||
|
||||
// Vendor code, can be anything.
|
||||
#define MSFT100_VENDOR_CODE (0x42)
|
||||
|
||||
#if !MICROPY_HW_USB_IS_MULTI_OTG
|
||||
STATIC const uint8_t usbd_fifo_size[USBD_PMA_NUM_FIFO] = {
|
||||
32, 32, // EP0(out), EP0(in)
|
||||
|
@ -1026,14 +1038,14 @@ __ALIGN_BEGIN static const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __AL
|
|||
static const uint8_t dev_descr[0x12] = {
|
||||
0x12, // bLength
|
||||
0x01, // bDescriptorType: Device
|
||||
0x00, 0x01, // USB version: 1.00
|
||||
0x00, 0x02, // USB version: 2.00
|
||||
0x00, // bDeviceClass
|
||||
0x00, // bDeviceSubClass
|
||||
0x00, // bDeviceProtocol
|
||||
0x40, // bMaxPacketSize
|
||||
LOBYTE(MBOOT_USB_VID), HIBYTE(MBOOT_USB_VID),
|
||||
LOBYTE(MBOOT_USB_PID), HIBYTE(MBOOT_USB_PID),
|
||||
0x00, 0x22, // bcdDevice: 22.00
|
||||
0x00, 0x03, // bcdDevice: 3.00
|
||||
0x01, // iManufacturer
|
||||
0x02, // iProduct
|
||||
0x03, // iSerialNumber
|
||||
|
@ -1047,6 +1059,32 @@ static uint8_t cfg_descr[9 + 9 + 9] =
|
|||
"\x09\x21\x0b\xff\x00\x00\x08\x1a\x01" // \x00\x08 goes with USB_XFER_SIZE
|
||||
;
|
||||
|
||||
__ALIGN_BEGIN static const uint8_t msft100_str_desc[18] __ALIGN_END = {
|
||||
0x12, 0x03,
|
||||
'M', 0x00,
|
||||
'S', 0x00,
|
||||
'F', 0x00,
|
||||
'T', 0x00,
|
||||
'1', 0x00,
|
||||
'0', 0x00,
|
||||
'0', 0x00,
|
||||
MSFT100_VENDOR_CODE,
|
||||
0x00,
|
||||
};
|
||||
|
||||
__ALIGN_BEGIN static const uint8_t msft100_id[40] __ALIGN_END = {
|
||||
0x28, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, // 1.00
|
||||
0x04, 0x00,
|
||||
0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static uint8_t *pyb_usbdd_DeviceDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) {
|
||||
*length = USB_LEN_DEV_DESC;
|
||||
return (uint8_t *)dev_descr;
|
||||
|
@ -1131,6 +1169,10 @@ static uint8_t *pyb_usbdd_StrDescriptor(USBD_HandleTypeDef *pdev, uint8_t idx, u
|
|||
return str_desc;
|
||||
#endif
|
||||
|
||||
case MSFT_WCID_STR_DESC_VALUE:
|
||||
*length = sizeof(msft100_str_desc);
|
||||
return (uint8_t *)msft100_str_desc; // the data should only be read from this buf
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1159,8 +1201,24 @@ static uint8_t pyb_usbdd_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *r
|
|||
self->bRequest = req->bRequest;
|
||||
self->wValue = req->wValue;
|
||||
self->wLength = req->wLength;
|
||||
if (req->bmRequest == 0x21) {
|
||||
// host-to-device request
|
||||
|
||||
if ((req->bmRequest & 0xe0) == 0xc0) {
|
||||
// device-to-host vendor request
|
||||
if (req->wIndex == 0x04 && req->bRequest == MSFT100_VENDOR_CODE) {
|
||||
// WCID: Compatible ID Feature Descriptor
|
||||
#if USE_USB_POLLING
|
||||
self->tx_pending = true;
|
||||
#endif
|
||||
int len = MIN(req->wLength, 40);
|
||||
memcpy(self->tx_buf, msft100_id, len);
|
||||
USBD_CtlSendData(&self->hUSBDDevice, self->tx_buf, len);
|
||||
return USBD_OK;
|
||||
} else {
|
||||
USBD_CtlError(pdev, req);
|
||||
return USBD_OK;
|
||||
}
|
||||
} else if (req->bmRequest == 0x21) {
|
||||
// host-to-device class request
|
||||
if (req->wLength == 0) {
|
||||
// no data, process command straight away
|
||||
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
|
|||
USBD_CtlPrepareRx(pdev, self->rx_buf, req->wLength);
|
||||
}
|
||||
} else if (req->bmRequest == 0xa1) {
|
||||
// device-to-host request
|
||||
// device-to-host class request
|
||||
int len = dfu_handle_tx(self->bRequest, self->wValue, self->wLength, self->tx_buf, USB_XFER_SIZE);
|
||||
if (len >= 0) {
|
||||
#if USE_USB_POLLING
|
||||
|
|
Loading…
Reference in New Issue