zephyr: USB DFU implementation does not work with WinUSB because of missing device reset API

Describe the bug When uploading a signed image using dfu-util on windows, the transfers fails and output “Lost device after RESET ?”.

From what I understood I’m not the only one facing this issue, It has been discussed on Discord both on the general channel but also on the MCUBOOT one.

The SoC I’m using is stm32g474re, but it seems to also affect other vendors. USB DFU works flawlessly on Linux I’m only experiencing the issue on Windows.

What I tried :

  • I made sure that I’m not enabling the USB_COMPOSITE that was known to cause trouble on Windows. #23337
  • I made sure that POLLTIMEOUT is at it’s default value as it seems to be linked to similar issues #15497
  • I tried creating a USB device on Zadig to install WinUSB not only on the runtime, but also on the transfer HWID.

To Reproduce

Prj.conf relevant configuration is

# USB
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_PRODUCT="MCUBOOT"
CONFIG_USB_COMPOSITE_DEVICE=n
CONFIG_USB_CDC_ACM=n
CONFIG_USB_DEVICE_PID=0x0101
CONFIG_USB_DEVICE_DFU_PID=0x0102

#Upgrade with swapping the memory partition without the need of scratch partition
CONFIG_BOOT_SWAP_USING_MOVE=y

# Enable USB Download Firmware Upgrade (DFU)
CONFIG_BOOT_USB_DFU_GPIO=y

I used Zadig v2.7 to load WinUSB v6.1 driver on MCUBOOT run-time dfu (2fe3:0101).

Expected behavior Dfu-util is supposed to be able to reset the USB from run-time to transfer mode.

Impact The project we are working on aims at having end users able to download binaries to the board using dfu-util. Most users are using Windows and this issue is a showstopper for us.

Logs and console output

When listing the DFU capable USB device, we already see that it fails at enumerating correctly.

C:\Users\jal\Downloads\dfu-util-0.9-win64\dfu-util-0.9-win64>dfu-util -l
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

Cannot open DFU device 04f2:b6c6
Found Runtime: [2fe3:0101] ver=0301, devnum=33, cfg=1, intf=0, path="1-5", alt=0, name="UNKNOWN", serial="5056500D00310056"x

When flashing it gives

C:\Users\jal\Downloads\dfu-util-0.9-win64\dfu-util-0.9-win64>dfu-util -v -a 1 -D firmware.signed.bin 
dfu-util 0.9                                                                                                                                                                                                                                                                                                                                            Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/
Invalid DFU suffix signature 
A valid DFU suffix will be required in a future dfu-util release!!!
Cannot open DFU device 04f2:b6c6
Opening DFU capable USB device...
ID 2fe3:0101
Run-time device DFU version 0110
Claiming USB DFU Runtime Interface... Determining device status: state = appIDLE, status = 0                                                                                                                      Device really in Runtime Mode, send DFU detach request... 
Resetting USB...
Lost device after RESET? 

In triple verbosity I get the following :

Resetting USB...
libusb: debug [libusb_reset_device]
libusb: debug [libusb_release_interface] interface 0
libusb: debug [libusb_close]
libusb: debug [libusb_get_device_list]
libusb: debug [windows_get_device_list] found existing device for session [C1] (1.0)
libusb: debug [windows_get_device_list] found existing device for session [239] (2.0)
libusb: debug [get_api_type] driver(s): USBHUB3
libusb: debug [get_api_type] matched driver name against HUB API
libusb: debug [windows_get_device_list] found existing device for session [1EE] (2.1)
libusb: debug [get_api_type] driver(s): USBHUB3
libusb: debug [get_api_type] matched driver name against HUB API
libusb: debug [windows_get_device_list] found existing device for session [328] (1.1)
libusb: debug [windows_get_device_list] found existing device for session [2FC] (1.3)
libusb: debug [windows_get_device_list] found existing device for session [76] (1.4)
libusb: debug [windows_get_device_list] extra GUID: {0767B285-1E08-4A99-ACF8-7452F512DDFC}
libusb: debug [windows_get_device_list] found existing device for session [22B] (1.33)
libusb: debug [windows_get_device_list] found existing device for session [328] (1.1)
libusb: debug [windows_get_device_list] found existing device for session [1EE] (2.1)
libusb: debug [windows_get_device_list] found existing device for session [225] (1.2)
libusb: debug [get_api_type] driver(s): usbccgp
libusb: debug [get_api_type] matched driver name against Composite API
libusb: debug [windows_get_device_list] found existing device for session [76] (1.4)
libusb: debug [get_api_type] driver(s): WUDFRd
libusb: debug [get_api_type] lower filter driver(s): WinUsb
libusb: debug [get_api_type] matched lower filter driver name against WinUSB
libusb: debug [windows_get_device_list] found existing device for session [225] (1.2)
libusb: debug [get_api_type] driver(s): BTHUSB
libusb: debug [get_api_type] lower filter driver(s): ibtusb
libusb: debug [windows_get_device_list] found existing device for session [2FC] (1.3)
libusb: debug [get_api_type] driver(s): WinUSB
libusb: debug [get_api_type] matched driver name against WinUSB
libusb: debug [windows_get_device_list] found existing device for session [22B] (1.33)
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#INT33D2&COL02#6&1061FB50&0&0001' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#INT33D2&COL03#6&1061FB50&0&0002' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#WACF4233&COL03#5&994D12E&0&0002' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#SYNA30B7&COL04#5&B796EAC&0&0003' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#VID_8087&PID_0AC2#6&29A9C256&0&0000' (non USB HID, newly connected, etc.) - ignoring                 
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#WACF4233&COL09#5&994D12E&0&0008' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#CONVERTEDDEVICE&COL02#5&13060E3C&0&0001' (non USB HID, newly connected, etc.) - ignoring             
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#CONVERTEDDEVICE&COL03#5&13060E3C&0&0002' (non USB HID, newly connected, etc.) - ignoring             
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#INTC816&COL02#3&207F9B7F&0&0001' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#VID_8087&PID_0AC2#6&1803663&0&0000' (non USB HID, newly connected, etc.) - ignoring                  
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#WACF4233&COL04#5&994D12E&0&0003' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#INTC816&COL03#3&207F9B7F&0&0002' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#INTC816&COL04#3&207F9B7F&0&0003' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#INTC816&COL05#3&207F9B7F&0&0004' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#CONVERTEDDEVICE&COL01#5&13060E3C&0&0000' (non USB HID, newly connected, etc.) - ignoring             
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#VID_8087&PID_0AC2#6&13825999&0&0000' (non USB HID, newly connected, etc.) - ignoring                 
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#INTC816&COL06#3&207F9B7F&0&0005' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#WACF4233&COL08#5&994D12E&0&0007' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#INTC816&COL01#3&207F9B7F&0&0000' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#INTC816&COL0A#3&207F9B7F&0&0009' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#INTC816&COL07#3&207F9B7F&0&0006' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#WACF4233&COL05#5&994D12E&0&0004' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#VID_8087&PID_0AC2#6&38F5BAE3&0&0000' (non USB HID, newly connected, etc.) - ignoring                 
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#INTC816&COL08#3&207F9B7F&0&0007' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#INTC816&COL09#3&207F9B7F&0&0008' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#HPQ6001#3&9489F59&0&0000' (non USB HID, newly connected, etc.) - ignoring                            
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#SYNA30B7&COL01#5&B796EAC&0&0000' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#WACF4233&COL06#5&994D12E&0&0005' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#WACF4233&COL01#5&994D12E&0&0000' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#INT33D2&COL01#6&1061FB50&0&0000' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#VID_8087&PID_0AC2#6&263C0A3E&0&0000' (non USB HID, newly connected, etc.) - ignoring                 
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#VID_8087&PID_0AC2#6&C8A8F4&0&0000' (non USB HID, newly connected, etc.) - ignoring                   
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#SYNA30B7&COL02#5&B796EAC&0&0001' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#WACF4233&COL07#5&994D12E&0&0006' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#INTC816&COL0B#3&207F9B7F&0&000A' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#WACF4233&COL02#5&994D12E&0&0001' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [windows_get_device_list] unlisted ancestor for '\\.\HID#SYNA30B7&COL03#5&B796EAC&0&0002' (non USB HID, newly connected, etc.) - ignoring                     
libusb: debug [get_api_type] driver(s): WinUSB
libusb: debug [get_api_type] matched driver name against WinUSB
libusb: debug [libusb_get_device_descriptor]
libusb: debug [libusb_get_config_descriptor] index 0
libusb: debug [libusb_get_device_descriptor]
libusb: debug [libusb_get_config_descriptor] index 0
libusb: debug [parse_configuration] skipping descriptor 0xb
libusb: debug [parse_endpoint] skipping descriptor 25
libusb: debug [parse_endpoint] skipping descriptor b
libusb: debug [parse_endpoint] skipping descriptor 25
libusb: debug [parse_endpoint] skipping descriptor b
libusb: debug [libusb_get_device_descriptor]
libusb: debug [libusb_get_config_descriptor] index 0
libusb: debug [libusb_get_device_descriptor]
libusb: debug [libusb_get_config_descriptor] index 0
libusb: debug [libusb_get_device_descriptor]
libusb: debug [libusb_get_config_descriptor] index 0
libusb: debug [libusb_get_device_descriptor]
libusb: debug [libusb_get_config_descriptor] index 0
Lost device after RESET?   

Environment (please complete the following information):

  • OS: Windows 10
  • Toolchain Zephyr SDK
  • Commit SHA or Version used Zephyr 3.1

Additional context Not much more to add AFAIK

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 15

Commits related to this issue

Most upvoted comments

Regarding the WinUSB limitation it is pretty hard to come up with a link to something that does not exist. The winusb.h header documentation lists the API provided by WinUSB.

Well it would be easier if they just write that there is no API for it instead of placing dead links in the code.

Nobody placed dead links in the code. It is just how internet works, the links do become dead over time. So will the links placed in Zephyr code/documentation, especially the ones that point to latest version and not some specific version. This is why besides just a link, there should be enough context for the future reader.

If the comment you are referring to is what you linked earlier then the author did all they could do to provide enough context, that is:

/*
 * from the "How to Use WinUSB to Communicate with a USB Device" Microsoft white paper
 * (http://www.microsoft.com/whdc/connect/usb/winusb_howto.mspx):
 * "WinUSB does not support host-initiated reset port and cycle port operations" and
 * IOCTL_INTERNAL_USB_CYCLE_PORT is only available in kernel mode and the
 * IOCTL_USB_HUB_CYCLE_PORT ioctl was removed from Vista => the best we can do is
 * cycle the pipes (and even then, the control pipe can not be reset using WinUSB)
 */

The “WinUSB does not support host-initiated reset port and cycle port operations” is basically saying there is no API for it. It also provides really good context for people familiar with Windows development that there is basically no hope to implement host initiated reset in user-space.

Anyway, limitations of WinUSB do not seem to be a bug in Zephyr to me.

Then consider WinUSB compatibility as a feature. It is just a taxonomy. The thing is, that the end-user quite often does not make the distinction and instead reports that something does not work and considers this to be a bug. It is easy to notice that something does not work as expected, but it is hard to tell what is the root cause (because otherwise the reporter would just fix the root cause in the first place instead of going through the trouble of reporting).

The average user that buys any peripheral that runs Zephyr and uses USB DFU is likely to use Windows to update the firmware, as Windows currently has about 74% desktop market share. The end user expects the manufacturer to provide working software package that can update the firmware. The lowest maintenance solution is USB DFU with WinUSB WCID descriptors, as it eliminates the driver development, signing and installation problem completely.