Understanding USB, on windows and linux in order to use DfuSe from STM.

Olof Astrand
10 min readAug 18, 2023

This describes how the USB configuration descriptor is used by windows and linux in order to find the matching driver. Specifically we look at how the ST DFU drivers are used under windows. This is important as ST microelectronics has updated their DFU drivers under windows and made the old DfuSe software kit unusable .

Understanding USB

When a USB device is plugged in, the host will request a device descriptor.

Exploring the USB tree in windows

By using the folowing example program, we can query the descriptors of the usb-tree. Same information can also be viewed with the Device Manager.

USB has a process called “enumeration” where each device, including hubs, is assigned an 7-bit number used to identify it to the host. When a hub is attached, it is enumerated and then each device downstream is enumerated.

This is the reason that no more than 127 devices may be attached at any time.

Enumeration on the lowest level

  1. Device Connection: When you plug in a USB device, an electrical presence is detected on the bus.
  2. Reset Signal: The host (your computer) issues a ‘reset’ to the device. This is a signal to ensure that the device is in a known state and is ready to communicate.
  3. Default Address: After the reset, every USB device starts with a default address (usually address 0). Devices must be at this address to properly communicate during the initial stages of enumeration.
  4. Request for Device Descriptor: The host will request the Device Descriptor from the device. This descriptor provides basic information about the device, such as Vendor ID, Product ID, etc.
  5. Address Assignment: The host then assigns a unique address to the device. From this point onward, the device will use this address for all communications on the bus. The device releases address 0 after this, making it available for the next device.
  6. Further Descriptor Requests: Now that the device has a unique address, the host can request more descriptors, such as Configuration, Interface, and Endpoint Descriptors. This helps the host understand the device’s capabilities and requirements.
  7. Driver Assignment: Using information from the descriptors (primarily Vendor ID and Product ID), Windows determines the appropriate driver for the device and loads it. If it doesn’t have a built-in driver, it might attempt to fetch one from Windows Update or prompt the user for the driver.
  8. Hub Specifics: If the device you plugged in is a hub:
  • The hub itself goes through the enumeration process.
  • Once the hub is enumerated and a driver is loaded for it (usually a generic hub driver provided by Windows), any devices subsequently connected to the hub will also undergo enumeration.
  • Each port on the hub is monitored for device connections, and when devices are connected to those ports, they go through the same enumeration process.

https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-device-specific-registry-settings

Windows driver matching

  1. Device Descriptor Examination: The system extracts vital information from the descriptor, especially the Vendor ID (VID) and Product ID (PID).
  2. INF File Lookup:
  • Windows will look through its collection of INF files to find a match for the VID and PID of the connected device.
  • The relevant information in an INF file is usually in the [Models] or [Standard] sections, where specific VID and PID combinations are listed along with a reference to the driver to be loaded.

3. Driver Installation & Loading:

  • If Windows finds a matching INF file, it proceeds to install the driver if it hasn’t been installed yet. After installation, the driver is loaded to handle the device.
  • If there’s no local match in the INF files already on the system, Windows 11, with the user’s permission, can search online (e.g., via Windows Update) for a suitable driver.

4. Fallbacks: If no specific VID/PID match is found, Windows might resort to class-based drivers. For instance, generic drivers exist for certain types of devices like keyboards, mice, and mass storage devices. This allows many basic devices to work even if a specific driver isn’t installed.

5. Driver Store: Starting with Windows Vista and continuing into Windows 11, Microsoft introduced the “Driver Store.” This is a trusted collection of driver packages on the local disk. When a new device is plugged in, Windows first checks the Driver Store for a suitable driver before attempting to search elsewhere.

6. User Interaction: If Windows can’t find a driver automatically, it might prompt the user to provide driver media or point to a location where the driver can be found. However, with the expansive driver database on Windows Update, most common devices have drivers available automatically.

https://learn.microsoft.com/en-us/windows-hardware/drivers/install/step-1--the-new-device-is-identified

Linux Driver matching

  1. Device Descriptor Examination: The kernel looks at the Device Descriptor, specifically the Vendor ID and Product ID.
  2. Driver Matching: The kernel then scans through the list of available USB drivers. Each USB driver will have an associated table of usb_device_id entries, indicating the devices that it can support.
  3. Matching Process:
  • The kernel compares the Vendor ID and Product ID from the Device Descriptor with the entries in each driver’s usb_device_id table.
  • If there’s a match, that driver is considered a candidate for handling this device.
  • The matching process can also involve other fields in the usb_device_id structure, such as bDeviceClass, bDeviceSubClass, and bDeviceProtocol, which allow drivers to match against device classes rather than specific VID/PID combinations. For example, a generic USB keyboard driver might match against the HID class rather than a specific VID/PID.

4. Driver Binding: If a match is found, the kernel attempts to bind that driver to the device. If successful, the driver will manage the device from this point onwards.

https://static.lwn.net/images/pdf/LDD3/ch13.pdf

Useful commands,

> lsusb
> dmesg -w
> udevadm monitor

After the kernel has loaded the driver, the udev deamon will look in the /etc/udev/rules.d/ database to set symlinks and group permissions.

STM DFU windows Drivers

ST updated the drivers to use WINUSB.sys instead of their own version of the driver. This ishow it looks in the device manager.

When examinig the drivers used, we see these driver files.

WinUSB was developed concurrently with the Windows Driver Foundation (WDF) and is available for Windows XP and later versions of Windows. It includes a kernel‐mode driver, WinUsb.sys, which is an integral part of WDF user‐mode driver framework (UMDF) support for USB drivers. However, for USB devices that are accessed by only a single application, vendors can often install WinUsb.sys as their device’s function
driver instead of implementing a custom driver. The application can then configure the device and access its endpoints by using the WinUSB API.

https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/system-supplied-usb-drivers

If you still want to install the old drivers in order to be able to use the DfuSe software kit. You would have to install dpinst_amd64.exe on a 64 bit system. You can find them here C:\Program Files (x86)\STMicroelectronics\Software\DfuSe v3.0.6\Bin\Driver. They are installed by the DfuSe software kit.

You will now have the ST usb driver instead,

The following registry string is now used,

Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\STTub30

DfuSe

DfuSe (DFU with ST Microsystems extensions) is a protocol based on DFU 1.1. However, in expanding the functionality of the DFU protocol, ST Microsystems broke all compatibility with the DFU 1.1 standard. DfuSe devices report the DFU version as “1.1a”.

DfuSe can be used to download firmware and other data from a host computer to a conforming device (or upload in the opposite direction) over USB similar to standard DFU.

The main difference from standard DFU is that the target address in the device (flash) memory is specified by the host, so that a download can be performed to parts of the device memory. The host program is also responsible for erasing flash pages before they are written to.

.dfu files

A special file format is defined by ST Microsystems to carry firmware for DfuSe devices. The file contains target information such as address and alternate interface information in addition to the binary data. Several blocks of binary data can be combined in one .dfu file.

Alternate USB interfaces

Different memory locations of the device may have different characteristics that the host program has to take into considerations, such as flash memory page size, read-only versus read-write segments, the need to erase, and so on. These parameters are reported by the device in the string descriptors meant for describing the USB interfaces. The host program decodes these strings to build a memory map of the device. Different memory units or address spaces are listed in separate alternate interface settings that must be selected according to the memory unit to access.

DfuSe special commands

DfuSe special commands are used by the host program during normal downloads or uploads, such as SET_ADDRESS and ERASE_PAGE. Also the normal DFU_DNLOAD and DFU_UPLOAD commands have special implementations in DfuSe. Many DfuSe devices also support commands to leave DFU mode, read unprotect the flash memory or mass erase the flash memory.

Dump of the descriptors,

[Port6]  :  STM Device in DFU Mode


Is Port User Connectable: yes
Is Port Debug Capable: no
Companion Port Number: 14
Companion Hub Symbolic Link Name: USB#ROOT_HUB30#4&24d2f46c&0&0#{f18a0e88-c30c-11d0-8815-00a0c906bed8}
Protocols Supported:
USB 1.1: yes
USB 2.0: yes
USB 3.0: no

Device Power State: PowerDeviceD0

---===>Device Information<===---
English product name: "STM32 BOOTLOADER"

ConnectionStatus:
Current Config Value: 0x01 -> Device Bus Speed: Full (is not SuperSpeed or higher capable)
Device Address: 0x09
Open Pipes: 0
*!*ERROR: No open pipes!

===>Device Descriptor<===
bLength: 0x12
bDescriptorType: 0x01
bcdUSB: 0x0100
bDeviceClass: 0x00 -> This is an Interface Class Defined Device
bDeviceSubClass: 0x00
bDeviceProtocol: 0x00
bMaxPacketSize0: 0x40 = (64) Bytes
idVendor: 0x0483 = STMicroelectronics
idProduct: 0xDF11
bcdDevice: 0x2200
iManufacturer: 0x01
English (United States) "STMicroelectronics"
iProduct: 0x02
English (United States) "STM32 BOOTLOADER"
iSerialNumber: 0x03
English (United States) "339C35543236"
bNumConfigurations: 0x01

---===>Full Configuration Descriptor<===---

===>Configuration Descriptor<===
bLength: 0x09
bDescriptorType: 0x02
wTotalLength: 0x0036 -> Validated
bNumInterfaces: 0x01
bConfigurationValue: 0x01
iConfiguration: 0x00
bmAttributes: 0xC0 -> Self Powered
-> Bus Powered
MaxPower: 0x32 = 100 mA

===>Interface Descriptor<===
bLength: 0x09
bDescriptorType: 0x04
bInterfaceNumber: 0x00
bAlternateSetting: 0x00
bNumEndpoints: 0x00
bInterfaceClass: 0xFE -> This is an Application Specific USB Device Interface Class
-> This is a Device Firmware Application Specific USB Device Interface Class
bInterfaceSubClass: 0x01
bInterfaceProtocol: 0x02
iInterface: 0x04
English (United States) "@Internal Flash /0x08000000/04*016Kg,01*064Kg,01*128Kg"

===>Interface Descriptor<===
bLength: 0x09
bDescriptorType: 0x04
bInterfaceNumber: 0x00
bAlternateSetting: 0x01
bNumEndpoints: 0x00
bInterfaceClass: 0xFE -> This is an Application Specific USB Device Interface Class
-> This is a Device Firmware Application Specific USB Device Interface Class
bInterfaceSubClass: 0x01
bInterfaceProtocol: 0x02
iInterface: 0x05
English (United States) "@Option Bytes /0x1FFFC000/01*016 e"

===>Interface Descriptor<===
bLength: 0x09
bDescriptorType: 0x04
bInterfaceNumber: 0x00
bAlternateSetting: 0x02
bNumEndpoints: 0x00
bInterfaceClass: 0xFE -> This is an Application Specific USB Device Interface Class
-> This is a Device Firmware Application Specific USB Device Interface Class
bInterfaceSubClass: 0x01
bInterfaceProtocol: 0x02
iInterface: 0x06
English (United States) "@OTP Memory /0x1FFF7800/01*512 e,01*016 e"

===>Interface Descriptor<===
bLength: 0x09
bDescriptorType: 0x04
bInterfaceNumber: 0x00
bAlternateSetting: 0x03
bNumEndpoints: 0x00
bInterfaceClass: 0xFE -> This is an Application Specific USB Device Interface Class
-> This is a Device Firmware Application Specific USB Device Interface Class
bInterfaceSubClass: 0x01
bInterfaceProtocol: 0x02
iInterface: 0x07
English (United States) "@Device Feature/0xFFFF0000/01*004 e"

===>HID Descriptor<===
bLength: 0x09
bDescriptorType: 0x21
bcdHID: 0xFF0B
bCountryCode: 0x00
bNumDescriptors: 0x00

DfuSe extracts the descriptor information (“@Internal Flash /0x08000000/04*016Kg,01*064Kg,01*128Kg”) to the following,

Connecting to usb devices from WSL2

A way to get usb to work from within WSL2, you can use usbipd. Note that this reqires a newer WSL linux kernel, or that you build it with usbipd support.

Installing on Ubuntu WSL

> sudo apt install linux-tools-virtual hwdata
> sudo update-alternatives - install /usr/local/bin/usbip usbip `ls /usr/lib/linux-tools/*/usbip | tail -n1` 20

Then as an administrator,

C:\windows\system32> usbipd wsl list

BUSID VID:PID DEVICE
8–2 0483:374b ST-Link Debug, USB Mass Storage Device, STMicroelectronic… Not attached

C:\ usbipd wsl attach - busid <busid>
Always call usbipd wsl attach --busid <busid> from powershell terminal and NOT from WSL terminal.

For more information, see

Note that this may change in the future. Notably in version 4.0 https://github.com/dorssel/usbipd-win

--

--