aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2025-05-19 15:30:22 +0200
committerGitHub <[email protected]>2025-05-19 15:30:22 +0200
commitf915903f0e0db45049197d49b3aadd8e3c50f111 (patch)
treee73af2d6c132f1ae69a0a760d7eee99733d2ea71
parent3ad9b73dd52d21cab8357f551fb82e281ff2aaa6 (diff)
parent2bbc2045a4a6cb1e489295d258ac0cdb6338f90a (diff)
Merge pull request #4188 from Gerharddc/dfu-msos
[embassy-usb-dfu] support function level WinUSB GUIDs
-rw-r--r--embassy-usb-dfu/src/application.rs8
-rw-r--r--embassy-usb-dfu/src/dfu.rs8
-rw-r--r--examples/boot/application/stm32wb-dfu/src/main.rs30
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/src/main.rs17
4 files changed, 56 insertions, 7 deletions
diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs
index 6ad07a78c..4b7b72073 100644
--- a/embassy-usb-dfu/src/application.rs
+++ b/embassy-usb-dfu/src/application.rs
@@ -2,7 +2,7 @@ use embassy_boot::BlockingFirmwareState;
2use embassy_time::{Duration, Instant}; 2use embassy_time::{Duration, Instant};
3use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; 3use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
4use embassy_usb::driver::Driver; 4use embassy_usb::driver::Driver;
5use embassy_usb::{Builder, Handler}; 5use embassy_usb::{Builder, FunctionBuilder, Handler};
6use embedded_storage::nor_flash::NorFlash; 6use embedded_storage::nor_flash::NorFlash;
7 7
8use crate::consts::{ 8use crate::consts::{
@@ -130,8 +130,14 @@ pub fn usb_dfu<'d, D: Driver<'d>, MARK: DfuMarker, RST: Reset>(
130 builder: &mut Builder<'d, D>, 130 builder: &mut Builder<'d, D>,
131 handler: &'d mut Control<MARK, RST>, 131 handler: &'d mut Control<MARK, RST>,
132 timeout: Duration, 132 timeout: Duration,
133 func_modifier: impl Fn(&mut FunctionBuilder<'_, 'd, D>),
133) { 134) {
134 let mut func = builder.function(0x00, 0x00, 0x00); 135 let mut func = builder.function(0x00, 0x00, 0x00);
136
137 // Here we give users the opportunity to add their own function level MSOS headers for instance.
138 // This is useful when DFU functionality is part of a composite USB device.
139 func_modifier(&mut func);
140
135 let mut iface = func.interface(); 141 let mut iface = func.interface();
136 let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_RT, None); 142 let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_RT, None);
137 let timeout = timeout.as_millis() as u16; 143 let timeout = timeout.as_millis() as u16;
diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs
index a98d6ab40..0f39d906b 100644
--- a/embassy-usb-dfu/src/dfu.rs
+++ b/embassy-usb-dfu/src/dfu.rs
@@ -1,7 +1,7 @@
1use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterError}; 1use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterError};
2use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; 2use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
3use embassy_usb::driver::Driver; 3use embassy_usb::driver::Driver;
4use embassy_usb::{Builder, Handler}; 4use embassy_usb::{Builder, FunctionBuilder, Handler};
5use embedded_storage::nor_flash::{NorFlash, NorFlashErrorKind}; 5use embedded_storage::nor_flash::{NorFlash, NorFlashErrorKind};
6 6
7use crate::consts::{ 7use crate::consts::{
@@ -186,8 +186,14 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha
186pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize>( 186pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize>(
187 builder: &mut Builder<'d, D>, 187 builder: &mut Builder<'d, D>,
188 handler: &'d mut Control<'d, DFU, STATE, RST, BLOCK_SIZE>, 188 handler: &'d mut Control<'d, DFU, STATE, RST, BLOCK_SIZE>,
189 func_modifier: impl Fn(&mut FunctionBuilder<'_, 'd, D>),
189) { 190) {
190 let mut func = builder.function(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU); 191 let mut func = builder.function(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU);
192
193 // Here we give users the opportunity to add their own function level MSOS headers for instance.
194 // This is useful when DFU functionality is part of a composite USB device.
195 func_modifier(&mut func);
196
191 let mut iface = func.interface(); 197 let mut iface = func.interface();
192 let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU, None); 198 let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU, None);
193 alt.descriptor( 199 alt.descriptor(
diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs
index dda2b795b..5e7b71f5a 100644
--- a/examples/boot/application/stm32wb-dfu/src/main.rs
+++ b/examples/boot/application/stm32wb-dfu/src/main.rs
@@ -13,7 +13,7 @@ use embassy_stm32::usb::{self, Driver};
13use embassy_stm32::{bind_interrupts, peripherals}; 13use embassy_stm32::{bind_interrupts, peripherals};
14use embassy_sync::blocking_mutex::Mutex; 14use embassy_sync::blocking_mutex::Mutex;
15use embassy_time::Duration; 15use embassy_time::Duration;
16use embassy_usb::Builder; 16use embassy_usb::{msos, Builder};
17use embassy_usb_dfu::consts::DfuAttributes; 17use embassy_usb_dfu::consts::DfuAttributes;
18use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; 18use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate};
19use panic_reset as _; 19use panic_reset as _;
@@ -22,6 +22,11 @@ bind_interrupts!(struct Irqs {
22 USB_LP => usb::InterruptHandler<peripherals::USB>; 22 USB_LP => usb::InterruptHandler<peripherals::USB>;
23}); 23});
24 24
25// This is a randomly generated GUID to allow clients on Windows to find your device.
26//
27// N.B. update to a custom GUID for your own device!
28const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"];
29
25#[embassy_executor::main] 30#[embassy_executor::main]
26async fn main(_spawner: Spawner) { 31async fn main(_spawner: Spawner) {
27 let mut config = embassy_stm32::Config::default(); 32 let mut config = embassy_stm32::Config::default();
@@ -54,7 +59,28 @@ async fn main(_spawner: Spawner) {
54 &mut control_buf, 59 &mut control_buf,
55 ); 60 );
56 61
57 usb_dfu(&mut builder, &mut state, Duration::from_millis(2500)); 62 // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows.
63 // Otherwise users need to do this manually using a tool like Zadig.
64 //
65 // It seems these always need to be at added at the device level for this to work and for
66 // composite devices they also need to be added on the function level (as shown later).
67 //
68 builder.msos_descriptor(msos::windows_version::WIN8_1, 2);
69 builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
70 builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
71 "DeviceInterfaceGUIDs",
72 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
73 ));
74
75 usb_dfu(&mut builder, &mut state, Duration::from_millis(2500), |func| {
76 // You likely don't have to add these function level headers if your USB device is not composite
77 // (i.e. if your device does not expose another interface in addition to DFU)
78 func.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
79 func.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
80 "DeviceInterfaceGUIDs",
81 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
82 ));
83 });
58 84
59 let mut dev = builder.build(); 85 let mut dev = builder.build();
60 dev.run().await 86 dev.run().await
diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
index 28216806e..0b643079f 100644
--- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs
+++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
@@ -20,7 +20,9 @@ bind_interrupts!(struct Irqs {
20 USB_LP => usb::InterruptHandler<peripherals::USB>; 20 USB_LP => usb::InterruptHandler<peripherals::USB>;
21}); 21});
22 22
23// This is a randomly generated GUID to allow clients on Windows to find our device 23// This is a randomly generated GUID to allow clients on Windows to find your device.
24//
25// N.B. update to a custom GUID for your own device!
24const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"]; 26const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"];
25 27
26#[entry] 28#[entry]
@@ -68,7 +70,8 @@ fn main() -> ! {
68 // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows. 70 // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows.
69 // Otherwise users need to do this manually using a tool like Zadig. 71 // Otherwise users need to do this manually using a tool like Zadig.
70 // 72 //
71 // It seems it is important for the DFU class that these headers be on the Device level. 73 // It seems these always need to be at added at the device level for this to work and for
74 // composite devices they also need to be added on the function level (as shown later).
72 // 75 //
73 builder.msos_descriptor(msos::windows_version::WIN8_1, 2); 76 builder.msos_descriptor(msos::windows_version::WIN8_1, 2);
74 builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); 77 builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
@@ -77,7 +80,15 @@ fn main() -> ! {
77 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), 80 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
78 )); 81 ));
79 82
80 usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state); 83 usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state, |func| {
84 // You likely don't have to add these function level headers if your USB device is not composite
85 // (i.e. if your device does not expose another interface in addition to DFU)
86 func.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
87 func.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
88 "DeviceInterfaceGUIDs",
89 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
90 ));
91 });
81 92
82 let mut dev = builder.build(); 93 let mut dev = builder.build();
83 embassy_futures::block_on(dev.run()); 94 embassy_futures::block_on(dev.run());