From 2e104170de36295243608fbbebebdc6f52e8f8d0 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Mon, 9 May 2022 02:07:48 +0200
Subject: [PATCH 1/5] usb: remove address arg from endpoint allocation.

---
 embassy-nrf/src/usb.rs                       | 59 +++++++-------------
 embassy-usb/src/builder.rs                   | 14 ++---
 embassy-usb/src/driver.rs                    |  2 -
 examples/nrf/src/bin/usb_hid_keyboard.rs     |  2 +-
 examples/nrf/src/bin/usb_hid_mouse.rs        |  2 +-
 examples/nrf/src/bin/usb_serial.rs           |  2 +-
 examples/nrf/src/bin/usb_serial_multitask.rs |  4 +-
 7 files changed, 32 insertions(+), 53 deletions(-)

diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs
index c032b2cc5..70393532f 100644
--- a/embassy-nrf/src/usb.rs
+++ b/embassy-nrf/src/usb.rs
@@ -143,38 +143,32 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
 
     fn alloc_endpoint_in(
         &mut self,
-        ep_addr: Option<EndpointAddress>,
         ep_type: EndpointType,
-        max_packet_size: u16,
+        packet_size: u16,
         interval: u8,
     ) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
-        let index = self
-            .alloc_in
-            .allocate(ep_addr, ep_type, max_packet_size, interval)?;
+        let index = self.alloc_in.allocate(ep_type, packet_size, interval)?;
         let ep_addr = EndpointAddress::from_parts(index, UsbDirection::In);
         Ok(Endpoint::new(EndpointInfo {
             addr: ep_addr,
             ep_type,
-            max_packet_size,
+            max_packet_size: packet_size,
             interval,
         }))
     }
 
     fn alloc_endpoint_out(
         &mut self,
-        ep_addr: Option<EndpointAddress>,
         ep_type: EndpointType,
-        max_packet_size: u16,
+        packet_size: u16,
         interval: u8,
     ) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
-        let index = self
-            .alloc_out
-            .allocate(ep_addr, ep_type, max_packet_size, interval)?;
+        let index = self.alloc_out.allocate(ep_type, packet_size, interval)?;
         let ep_addr = EndpointAddress::from_parts(index, UsbDirection::Out);
         Ok(Endpoint::new(EndpointInfo {
             addr: ep_addr,
             ep_type,
-            max_packet_size,
+            max_packet_size: packet_size,
             interval,
         }))
     }
@@ -183,8 +177,10 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
         &mut self,
         max_packet_size: u16,
     ) -> Result<Self::ControlPipe, driver::EndpointAllocError> {
-        self.alloc_endpoint_out(Some(0x00.into()), EndpointType::Control, max_packet_size, 0)?;
-        self.alloc_endpoint_in(Some(0x80.into()), EndpointType::Control, max_packet_size, 0)?;
+        self.alloc_in.used |= 0x01;
+        self.alloc_in.lens[0] = max_packet_size as u8;
+        self.alloc_out.used |= 0x01;
+        self.alloc_out.lens[0] = max_packet_size as u8;
         Ok(ControlPipe {
             _phantom: PhantomData,
             max_packet_size,
@@ -681,8 +677,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
             .await;
 
             // Reset shorts
-            regs.shorts
-                .modify(|_, w| w.ep0datadone_ep0status().clear_bit());
+            regs.shorts.write(|w| w);
             regs.events_ep0setup.reset();
 
             let mut buf = [0; 8];
@@ -746,7 +741,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
             }
 
             regs.shorts
-                .modify(|_, w| w.ep0datadone_ep0status().bit(last_packet));
+                .write(|w| w.ep0datadone_ep0status().bit(last_packet));
 
             regs.intenset.write(|w| {
                 w.usbreset().set();
@@ -810,7 +805,6 @@ impl Allocator {
 
     fn allocate(
         &mut self,
-        ep_addr: Option<EndpointAddress>,
         ep_type: EndpointType,
         max_packet_size: u16,
         _interval: u8,
@@ -828,27 +822,16 @@ impl Allocator {
 
         // Endpoint directions are allocated individually.
 
-        let alloc_index = if let Some(ep_addr) = ep_addr {
-            match (ep_addr.index(), ep_type) {
-                (0, EndpointType::Control) => {}
-                (8, EndpointType::Isochronous) => {}
-                (n, EndpointType::Bulk) | (n, EndpointType::Interrupt) if n >= 1 && n <= 7 => {}
-                _ => return Err(driver::EndpointAllocError),
-            }
-
-            ep_addr.index()
-        } else {
-            match ep_type {
-                EndpointType::Isochronous => 8,
-                EndpointType::Control => 0,
-                EndpointType::Interrupt | EndpointType::Bulk => {
-                    // Find rightmost zero bit in 1..=7
-                    let ones = (self.used >> 1).trailing_ones() as usize;
-                    if ones >= 7 {
-                        return Err(driver::EndpointAllocError);
-                    }
-                    ones + 1
+        let alloc_index = match ep_type {
+            EndpointType::Isochronous => 8,
+            EndpointType::Control => return Err(driver::EndpointAllocError),
+            EndpointType::Interrupt | EndpointType::Bulk => {
+                // Find rightmost zero bit in 1..=7
+                let ones = (self.used >> 1).trailing_ones() as usize;
+                if ones >= 7 {
+                    return Err(driver::EndpointAllocError);
                 }
+                ones + 1
             }
         };
 
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 8cf9c82a9..698a5f765 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -372,7 +372,6 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
 
     fn endpoint_in(
         &mut self,
-        ep_addr: Option<EndpointAddress>,
         ep_type: EndpointType,
         max_packet_size: u16,
         interval: u8,
@@ -380,7 +379,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
         let ep = self
             .builder
             .driver
-            .alloc_endpoint_in(ep_addr, ep_type, max_packet_size, interval)
+            .alloc_endpoint_in(ep_type, max_packet_size, interval)
             .expect("alloc_endpoint_in failed");
 
         self.builder.config_descriptor.endpoint(ep.info());
@@ -390,7 +389,6 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
 
     fn endpoint_out(
         &mut self,
-        ep_addr: Option<EndpointAddress>,
         ep_type: EndpointType,
         max_packet_size: u16,
         interval: u8,
@@ -398,7 +396,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
         let ep = self
             .builder
             .driver
-            .alloc_endpoint_out(ep_addr, ep_type, max_packet_size, interval)
+            .alloc_endpoint_out(ep_type, max_packet_size, interval)
             .expect("alloc_endpoint_out failed");
 
         self.builder.config_descriptor.endpoint(ep.info());
@@ -411,7 +409,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
     /// Descriptors are written in the order builder functions are called. Note that some
     /// classes care about the order.
     pub fn endpoint_bulk_in(&mut self, max_packet_size: u16) -> D::EndpointIn {
-        self.endpoint_in(None, EndpointType::Bulk, max_packet_size, 0)
+        self.endpoint_in(EndpointType::Bulk, max_packet_size, 0)
     }
 
     /// Allocate a BULK OUT endpoint and write its descriptor.
@@ -419,7 +417,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
     /// Descriptors are written in the order builder functions are called. Note that some
     /// classes care about the order.
     pub fn endpoint_bulk_out(&mut self, max_packet_size: u16) -> D::EndpointOut {
-        self.endpoint_out(None, EndpointType::Bulk, max_packet_size, 0)
+        self.endpoint_out(EndpointType::Bulk, max_packet_size, 0)
     }
 
     /// Allocate a INTERRUPT IN endpoint and write its descriptor.
@@ -427,11 +425,11 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
     /// Descriptors are written in the order builder functions are called. Note that some
     /// classes care about the order.
     pub fn endpoint_interrupt_in(&mut self, max_packet_size: u16, interval: u8) -> D::EndpointIn {
-        self.endpoint_in(None, EndpointType::Interrupt, max_packet_size, interval)
+        self.endpoint_in(EndpointType::Interrupt, max_packet_size, interval)
     }
 
     /// Allocate a INTERRUPT OUT endpoint and write its descriptor.
     pub fn endpoint_interrupt_out(&mut self, max_packet_size: u16, interval: u8) -> D::EndpointOut {
-        self.endpoint_out(None, EndpointType::Interrupt, max_packet_size, interval)
+        self.endpoint_out(EndpointType::Interrupt, max_packet_size, interval)
     }
 }
diff --git a/embassy-usb/src/driver.rs b/embassy-usb/src/driver.rs
index e552dc7b6..a782b377c 100644
--- a/embassy-usb/src/driver.rs
+++ b/embassy-usb/src/driver.rs
@@ -25,7 +25,6 @@ pub trait Driver<'a> {
     /// * `interval` - Polling interval parameter for interrupt endpoints.
     fn alloc_endpoint_out(
         &mut self,
-        ep_addr: Option<EndpointAddress>,
         ep_type: EndpointType,
         max_packet_size: u16,
         interval: u8,
@@ -33,7 +32,6 @@ pub trait Driver<'a> {
 
     fn alloc_endpoint_in(
         &mut self,
-        ep_addr: Option<EndpointAddress>,
         ep_type: EndpointType,
         max_packet_size: u16,
         interval: u8,
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs
index 3852dd8da..d855a3a57 100644
--- a/examples/nrf/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf/src/bin/usb_hid_keyboard.rs
@@ -71,7 +71,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
     let mut device_descriptor = [0; 256];
     let mut config_descriptor = [0; 256];
     let mut bos_descriptor = [0; 256];
-    let mut control_buf = [0; 16];
+    let mut control_buf = [0; 64];
     let request_handler = MyRequestHandler {};
     let device_state_handler = MyDeviceStateHandler::new();
 
diff --git a/examples/nrf/src/bin/usb_hid_mouse.rs b/examples/nrf/src/bin/usb_hid_mouse.rs
index e70dc51a5..c526c1c6f 100644
--- a/examples/nrf/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf/src/bin/usb_hid_mouse.rs
@@ -50,7 +50,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
     let mut device_descriptor = [0; 256];
     let mut config_descriptor = [0; 256];
     let mut bos_descriptor = [0; 256];
-    let mut control_buf = [0; 16];
+    let mut control_buf = [0; 64];
     let request_handler = MyRequestHandler {};
 
     let mut state = State::new();
diff --git a/examples/nrf/src/bin/usb_serial.rs b/examples/nrf/src/bin/usb_serial.rs
index bc41c2acf..11651f82c 100644
--- a/examples/nrf/src/bin/usb_serial.rs
+++ b/examples/nrf/src/bin/usb_serial.rs
@@ -48,7 +48,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
     let mut device_descriptor = [0; 256];
     let mut config_descriptor = [0; 256];
     let mut bos_descriptor = [0; 256];
-    let mut control_buf = [0; 7];
+    let mut control_buf = [0; 64];
 
     let mut state = State::new();
 
diff --git a/examples/nrf/src/bin/usb_serial_multitask.rs b/examples/nrf/src/bin/usb_serial_multitask.rs
index 31e0af483..d8fac7a24 100644
--- a/examples/nrf/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf/src/bin/usb_serial_multitask.rs
@@ -64,7 +64,7 @@ async fn main(spawner: Spawner, p: Peripherals) {
         device_descriptor: [u8; 256],
         config_descriptor: [u8; 256],
         bos_descriptor: [u8; 256],
-        control_buf: [u8; 7],
+        control_buf: [u8; 64],
         serial_state: State<'static>,
     }
     static RESOURCES: Forever<Resources> = Forever::new();
@@ -72,7 +72,7 @@ async fn main(spawner: Spawner, p: Peripherals) {
         device_descriptor: [0; 256],
         config_descriptor: [0; 256],
         bos_descriptor: [0; 256],
-        control_buf: [0; 7],
+        control_buf: [0; 64],
         serial_state: State::new(),
     });
 

From 7ed462a6575cba95e8f07d2d9516d5e7b33d7196 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Mon, 9 May 2022 02:11:02 +0200
Subject: [PATCH 2/5] usb: simplify control in/out handlng, calling response
 from a single place.

---
 embassy-usb-ncm/src/lib.rs    |  14 +-
 embassy-usb/src/control.rs    |  29 +---
 embassy-usb/src/descriptor.rs |   1 +
 embassy-usb/src/lib.rs        | 270 +++++++++++++++++++---------------
 4 files changed, 158 insertions(+), 156 deletions(-)

diff --git a/embassy-usb-ncm/src/lib.rs b/embassy-usb-ncm/src/lib.rs
index 3a5abee8d..71d0691d4 100644
--- a/embassy-usb-ncm/src/lib.rs
+++ b/embassy-usb-ncm/src/lib.rs
@@ -133,6 +133,7 @@ impl Default for ControlShared {
 struct CommControl<'a> {
     mac_addr_string: StringIndex,
     shared: &'a ControlShared,
+    mac_addr_str: [u8; 12],
 }
 
 impl<'d> ControlHandler for CommControl<'d> {
@@ -178,24 +179,20 @@ impl<'d> ControlHandler for CommControl<'d> {
         }
     }
 
-    fn get_string<'a>(
-        &'a mut self,
-        index: StringIndex,
-        _lang_id: u16,
-        buf: &'a mut [u8],
-    ) -> Option<&'a str> {
+    fn get_string(&mut self, index: StringIndex, _lang_id: u16) -> Option<&str> {
         if index == self.mac_addr_string {
             let mac_addr = self.shared.mac_addr.get();
+            let s = &mut self.mac_addr_str;
             for i in 0..12 {
                 let n = (mac_addr[i / 2] >> ((1 - i % 2) * 4)) & 0xF;
-                buf[i] = match n {
+                s[i] = match n {
                     0x0..=0x9 => b'0' + n,
                     0xA..=0xF => b'A' + n - 0xA,
                     _ => unreachable!(),
                 }
             }
 
-            Some(unsafe { core::str::from_utf8_unchecked(&buf[..12]) })
+            Some(unsafe { core::str::from_utf8_unchecked(s) })
         } else {
             warn!("unknown string index requested");
             None
@@ -244,6 +241,7 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
         iface.handler(state.comm_control.write(CommControl {
             mac_addr_string,
             shared: &control_shared,
+            mac_addr_str: [0; 12],
         }));
         let comm_if = iface.interface_number();
         let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_NCM, CDC_PROTOCOL_NONE);
diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs
index ff42f9d78..4fc65b6a5 100644
--- a/embassy-usb/src/control.rs
+++ b/embassy-usb/src/control.rs
@@ -1,9 +1,7 @@
 use core::mem;
 
-use crate::descriptor::DescriptorWriter;
-use crate::driver::{self, EndpointError};
-
 use super::types::*;
+use crate::driver::{self, EndpointError};
 
 /// Control request type.
 #[repr(u8)]
@@ -191,16 +189,8 @@ pub trait ControlHandler {
     }
 
     /// Called when a GET_DESCRIPTOR STRING control request is received.
-    ///
-    /// Write the response string somewhere (usually to `buf`, but you may use another buffer
-    /// owned by yourself, or a static buffer), then return it.
-    fn get_string<'a>(
-        &'a mut self,
-        index: StringIndex,
-        lang_id: u16,
-        buf: &'a mut [u8],
-    ) -> Option<&'a str> {
-        let _ = (index, lang_id, buf);
+    fn get_string(&mut self, index: StringIndex, lang_id: u16) -> Option<&str> {
+        let _ = (index, lang_id);
         None
     }
 }
@@ -316,19 +306,6 @@ impl<C: driver::ControlPipe> ControlPipe<C> {
         }
     }
 
-    pub(crate) async fn accept_in_writer(
-        &mut self,
-        req: Request,
-        stage: DataInStage,
-        f: impl FnOnce(&mut DescriptorWriter),
-    ) {
-        let mut buf = [0; 256];
-        let mut w = DescriptorWriter::new(&mut buf);
-        f(&mut w);
-        let pos = w.position().min(usize::from(req.length));
-        self.accept_in(&buf[..pos], stage).await
-    }
-
     pub(crate) fn accept(&mut self, _: StatusStage) {
         trace!("  control accept");
         self.control.accept();
diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs
index dce326780..7f23fd921 100644
--- a/embassy-usb/src/descriptor.rs
+++ b/embassy-usb/src/descriptor.rs
@@ -244,6 +244,7 @@ impl<'a> DescriptorWriter<'a> {
     }
 
     /// Writes a string descriptor.
+    #[allow(unused)]
     pub(crate) fn string(&mut self, string: &str) {
         let mut pos = self.position;
 
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index 3bfedc048..690305885 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -100,15 +100,19 @@ struct Interface<'d> {
 }
 
 pub struct UsbDevice<'d, D: Driver<'d>> {
+    control_buf: &'d mut [u8],
+    control: ControlPipe<D::ControlPipe>,
+    inner: Inner<'d, D>,
+}
+
+struct Inner<'d, D: Driver<'d>> {
     bus: D::Bus,
     handler: Option<&'d dyn DeviceStateHandler>,
-    control: ControlPipe<D::ControlPipe>,
 
     config: Config<'d>,
     device_descriptor: &'d [u8],
     config_descriptor: &'d [u8],
     bos_descriptor: &'d [u8],
-    control_buf: &'d mut [u8],
 
     device_state: UsbDeviceState,
     suspended: bool,
@@ -139,20 +143,23 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
         let bus = driver.into_bus();
 
         Self {
-            bus,
-            config,
-            handler,
-            control: ControlPipe::new(control),
-            device_descriptor,
-            config_descriptor,
-            bos_descriptor,
             control_buf,
-            device_state: UsbDeviceState::Disabled,
-            suspended: false,
-            remote_wakeup_enabled: false,
-            self_powered: false,
-            pending_address: 0,
-            interfaces,
+            control: ControlPipe::new(control),
+            inner: Inner {
+                bus,
+                config,
+                handler,
+                device_descriptor,
+                config_descriptor,
+                bos_descriptor,
+
+                device_state: UsbDeviceState::Disabled,
+                suspended: false,
+                remote_wakeup_enabled: false,
+                self_powered: false,
+                pending_address: 0,
+                interfaces,
+            },
         }
     }
 
@@ -176,28 +183,60 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
     /// before calling any other `UsbDevice` methods to fully reset the
     /// peripheral.
     pub async fn run_until_suspend(&mut self) -> () {
-        if self.device_state == UsbDeviceState::Disabled {
-            self.bus.enable().await;
-            self.device_state = UsbDeviceState::Default;
+        if self.inner.device_state == UsbDeviceState::Disabled {
+            self.inner.bus.enable().await;
+            self.inner.device_state = UsbDeviceState::Default;
 
-            if let Some(h) = &self.handler {
+            if let Some(h) = &self.inner.handler {
                 h.enabled(true);
             }
         }
 
         loop {
             let control_fut = self.control.setup();
-            let bus_fut = self.bus.poll();
+            let bus_fut = self.inner.bus.poll();
             match select(bus_fut, control_fut).await {
                 Either::First(evt) => {
-                    self.handle_bus_event(evt);
-                    if self.suspended {
+                    self.inner.handle_bus_event(evt);
+                    if self.inner.suspended {
                         return;
                     }
                 }
                 Either::Second(req) => match req {
-                    Setup::DataIn(req, stage) => self.handle_control_in(req, stage).await,
-                    Setup::DataOut(req, stage) => self.handle_control_out(req, stage).await,
+                    Setup::DataIn(req, mut stage) => {
+                        // If we don't have an address yet, respond with max 1 packet.
+                        // The host doesn't know our EP0 max packet size yet, and might assume
+                        // a full-length packet is a short packet, thinking we're done sending data.
+                        // See https://github.com/hathach/tinyusb/issues/184
+                        const DEVICE_DESCRIPTOR_LEN: u8 = 18;
+                        if self.inner.pending_address == 0
+                            && self.inner.config.max_packet_size_0 < DEVICE_DESCRIPTOR_LEN
+                            && (self.inner.config.max_packet_size_0 as usize) < stage.length
+                        {
+                            trace!("received control req while not addressed: capping response to 1 packet.");
+                            stage.length = self.inner.config.max_packet_size_0 as _;
+                        }
+
+                        match self.inner.handle_control_in(req, &mut self.control_buf) {
+                            InResponse::Accepted(data) => self.control.accept_in(data, stage).await,
+                            InResponse::Rejected => self.control.reject(),
+                        }
+                    }
+                    Setup::DataOut(req, stage) => {
+                        let (data, stage) =
+                            match self.control.data_out(self.control_buf, stage).await {
+                                Ok(data) => data,
+                                Err(_) => {
+                                    warn!("usb: failed to read CONTROL OUT data stage.");
+                                    return;
+                                }
+                            };
+
+                        match self.inner.handle_control_out(req, data) {
+                            OutResponse::Accepted => self.control.accept(stage),
+                            OutResponse::Rejected => self.control.reject(),
+                        }
+                    }
                 },
             }
         }
@@ -205,13 +244,13 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
 
     /// Disables the USB peripheral.
     pub async fn disable(&mut self) {
-        if self.device_state != UsbDeviceState::Disabled {
-            self.bus.disable().await;
-            self.device_state = UsbDeviceState::Disabled;
-            self.suspended = false;
-            self.remote_wakeup_enabled = false;
+        if self.inner.device_state != UsbDeviceState::Disabled {
+            self.inner.bus.disable().await;
+            self.inner.device_state = UsbDeviceState::Disabled;
+            self.inner.suspended = false;
+            self.inner.remote_wakeup_enabled = false;
 
-            if let Some(h) = &self.handler {
+            if let Some(h) = &self.inner.handler {
                 h.enabled(false);
             }
         }
@@ -221,9 +260,9 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
     ///
     /// This future is cancel-safe.
     pub async fn wait_resume(&mut self) {
-        while self.suspended {
-            let evt = self.bus.poll().await;
-            self.handle_bus_event(evt);
+        while self.inner.suspended {
+            let evt = self.inner.bus.poll().await;
+            self.inner.handle_bus_event(evt);
         }
     }
 
@@ -236,11 +275,11 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
     /// After dropping the future, [`UsbDevice::disable()`] should be called
     /// before calling any other `UsbDevice` methods to fully reset the peripheral.
     pub async fn remote_wakeup(&mut self) -> Result<(), RemoteWakeupError> {
-        if self.suspended && self.remote_wakeup_enabled {
-            self.bus.remote_wakeup().await?;
-            self.suspended = false;
+        if self.inner.suspended && self.inner.remote_wakeup_enabled {
+            self.inner.bus.remote_wakeup().await?;
+            self.inner.suspended = false;
 
-            if let Some(h) = &self.handler {
+            if let Some(h) = &self.inner.handler {
                 h.suspended(false);
             }
 
@@ -249,7 +288,9 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
             Err(RemoteWakeupError::InvalidState)
         }
     }
+}
 
+impl<'d, D: Driver<'d>> Inner<'d, D> {
     fn handle_bus_event(&mut self, evt: Event) {
         match evt {
             Event::Reset => {
@@ -288,18 +329,10 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
         }
     }
 
-    async fn handle_control_out(&mut self, req: Request, stage: DataOutStage) {
+    fn handle_control_out(&mut self, req: Request, data: &[u8]) -> OutResponse {
         const CONFIGURATION_NONE_U16: u16 = CONFIGURATION_NONE as u16;
         const CONFIGURATION_VALUE_U16: u16 = CONFIGURATION_VALUE as u16;
 
-        let (data, stage) = match self.control.data_out(self.control_buf, stage).await {
-            Ok(data) => data,
-            Err(_) => {
-                warn!("usb: failed to read CONTROL OUT data stage.");
-                return;
-            }
-        };
-
         match (req.request_type, req.recipient) {
             (RequestType::Standard, Recipient::Device) => match (req.request, req.value) {
                 (Request::CLEAR_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => {
@@ -307,14 +340,14 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
                     if let Some(h) = &self.handler {
                         h.remote_wakeup_enabled(false);
                     }
-                    self.control.accept(stage)
+                    OutResponse::Accepted
                 }
                 (Request::SET_FEATURE, Request::FEATURE_DEVICE_REMOTE_WAKEUP) => {
                     self.remote_wakeup_enabled = true;
                     if let Some(h) = &self.handler {
                         h.remote_wakeup_enabled(true);
                     }
-                    self.control.accept(stage)
+                    OutResponse::Accepted
                 }
                 (Request::SET_ADDRESS, addr @ 1..=127) => {
                     self.pending_address = addr as u8;
@@ -323,7 +356,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
                     if let Some(h) = &self.handler {
                         h.addressed(self.pending_address);
                     }
-                    self.control.accept(stage)
+                    OutResponse::Accepted
                 }
                 (Request::SET_CONFIGURATION, CONFIGURATION_VALUE_U16) => {
                     debug!("SET_CONFIGURATION: configured");
@@ -344,10 +377,10 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
                         h.configured(true);
                     }
 
-                    self.control.accept(stage)
+                    OutResponse::Accepted
                 }
                 (Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => match self.device_state {
-                    UsbDeviceState::Default => self.control.accept(stage),
+                    UsbDeviceState::Default => OutResponse::Accepted,
                     _ => {
                         debug!("SET_CONFIGURATION: unconfigured");
                         self.device_state = UsbDeviceState::Addressed;
@@ -363,15 +396,15 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
                             h.configured(false);
                         }
 
-                        self.control.accept(stage)
+                        OutResponse::Accepted
                     }
                 },
-                _ => self.control.reject(),
+                _ => OutResponse::Rejected,
             },
             (RequestType::Standard, Recipient::Interface) => {
                 let iface = match self.interfaces.get_mut(req.index as usize) {
                     Some(iface) => iface,
-                    None => return self.control.reject(),
+                    None => return OutResponse::Rejected,
                 };
 
                 match req.request {
@@ -380,7 +413,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
 
                         if new_altsetting >= iface.num_alt_settings {
                             warn!("SET_INTERFACE: trying to select alt setting out of range.");
-                            return self.control.reject();
+                            return OutResponse::Rejected;
                         }
 
                         iface.current_alt_setting = new_altsetting;
@@ -402,55 +435,39 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
                         if let Some(handler) = &mut iface.handler {
                             handler.set_alternate_setting(new_altsetting);
                         }
-                        self.control.accept(stage)
+                        OutResponse::Accepted
                     }
-                    _ => self.control.reject(),
+                    _ => OutResponse::Rejected,
                 }
             }
             (RequestType::Standard, Recipient::Endpoint) => match (req.request, req.value) {
                 (Request::SET_FEATURE, Request::FEATURE_ENDPOINT_HALT) => {
                     let ep_addr = ((req.index as u8) & 0x8f).into();
                     self.bus.endpoint_set_stalled(ep_addr, true);
-                    self.control.accept(stage)
+                    OutResponse::Accepted
                 }
                 (Request::CLEAR_FEATURE, Request::FEATURE_ENDPOINT_HALT) => {
                     let ep_addr = ((req.index as u8) & 0x8f).into();
                     self.bus.endpoint_set_stalled(ep_addr, false);
-                    self.control.accept(stage)
+                    OutResponse::Accepted
                 }
-                _ => self.control.reject(),
+                _ => OutResponse::Rejected,
             },
             (RequestType::Class, Recipient::Interface) => {
                 let iface = match self.interfaces.get_mut(req.index as usize) {
                     Some(iface) => iface,
-                    None => return self.control.reject(),
+                    None => return OutResponse::Rejected,
                 };
                 match &mut iface.handler {
-                    Some(handler) => match handler.control_out(req, data) {
-                        OutResponse::Accepted => self.control.accept(stage),
-                        OutResponse::Rejected => self.control.reject(),
-                    },
-                    None => self.control.reject(),
+                    Some(handler) => handler.control_out(req, data),
+                    None => OutResponse::Rejected,
                 }
             }
-            _ => self.control.reject(),
+            _ => OutResponse::Rejected,
         }
     }
 
-    async fn handle_control_in(&mut self, req: Request, mut stage: DataInStage) {
-        // If we don't have an address yet, respond with max 1 packet.
-        // The host doesn't know our EP0 max packet size yet, and might assume
-        // a full-length packet is a short packet, thinking we're done sending data.
-        // See https://github.com/hathach/tinyusb/issues/184
-        const DEVICE_DESCRIPTOR_LEN: u8 = 18;
-        if self.pending_address == 0
-            && self.config.max_packet_size_0 < DEVICE_DESCRIPTOR_LEN
-            && (self.config.max_packet_size_0 as usize) < stage.length
-        {
-            trace!("received control req while not addressed: capping response to 1 packet.");
-            stage.length = self.config.max_packet_size_0 as _;
-        }
-
+    fn handle_control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
         match (req.request_type, req.recipient) {
             (RequestType::Standard, Recipient::Device) => match req.request {
                 Request::GET_STATUS => {
@@ -461,42 +478,41 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
                     if self.remote_wakeup_enabled {
                         status |= 0x0002;
                     }
-                    self.control.accept_in(&status.to_le_bytes(), stage).await
+                    buf[..2].copy_from_slice(&status.to_le_bytes());
+                    InResponse::Accepted(&buf[..2])
                 }
-                Request::GET_DESCRIPTOR => self.handle_get_descriptor(req, stage).await,
+                Request::GET_DESCRIPTOR => self.handle_get_descriptor(req, buf),
                 Request::GET_CONFIGURATION => {
                     let status = match self.device_state {
                         UsbDeviceState::Configured => CONFIGURATION_VALUE,
                         _ => CONFIGURATION_NONE,
                     };
-                    self.control.accept_in(&status.to_le_bytes(), stage).await
+                    buf[0] = status;
+                    InResponse::Accepted(&buf[..1])
                 }
-                _ => self.control.reject(),
+                _ => InResponse::Rejected,
             },
             (RequestType::Standard, Recipient::Interface) => {
                 let iface = match self.interfaces.get_mut(req.index as usize) {
                     Some(iface) => iface,
-                    None => return self.control.reject(),
+                    None => return InResponse::Rejected,
                 };
 
                 match req.request {
                     Request::GET_STATUS => {
                         let status: u16 = 0;
-                        self.control.accept_in(&status.to_le_bytes(), stage).await
+                        buf[..2].copy_from_slice(&status.to_le_bytes());
+                        InResponse::Accepted(&buf[..2])
                     }
                     Request::GET_INTERFACE => {
-                        self.control
-                            .accept_in(&[iface.current_alt_setting], stage)
-                            .await;
+                        buf[0] = iface.current_alt_setting;
+                        InResponse::Accepted(&buf[..1])
                     }
                     Request::GET_DESCRIPTOR => match &mut iface.handler {
-                        Some(handler) => match handler.get_descriptor(req, self.control_buf) {
-                            InResponse::Accepted(data) => self.control.accept_in(data, stage).await,
-                            InResponse::Rejected => self.control.reject(),
-                        },
-                        None => self.control.reject(),
+                        Some(handler) => handler.get_descriptor(req, buf),
+                        None => InResponse::Rejected,
                     },
-                    _ => self.control.reject(),
+                    _ => InResponse::Rejected,
                 }
             }
             (RequestType::Standard, Recipient::Endpoint) => match req.request {
@@ -506,44 +522,40 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
                     if self.bus.endpoint_is_stalled(ep_addr) {
                         status |= 0x0001;
                     }
-                    self.control.accept_in(&status.to_le_bytes(), stage).await
+                    buf[..2].copy_from_slice(&status.to_le_bytes());
+                    InResponse::Accepted(&buf[..2])
                 }
-                _ => self.control.reject(),
+                _ => InResponse::Rejected,
             },
             (RequestType::Class, Recipient::Interface) => {
                 let iface = match self.interfaces.get_mut(req.index as usize) {
                     Some(iface) => iface,
-                    None => return self.control.reject(),
+                    None => return InResponse::Rejected,
                 };
 
                 match &mut iface.handler {
-                    Some(handler) => match handler.control_in(req, self.control_buf) {
-                        InResponse::Accepted(data) => self.control.accept_in(data, stage).await,
-                        InResponse::Rejected => self.control.reject(),
-                    },
-                    None => self.control.reject(),
+                    Some(handler) => handler.control_in(req, buf),
+                    None => InResponse::Rejected,
                 }
             }
-            _ => self.control.reject(),
+            _ => InResponse::Rejected,
         }
     }
 
-    async fn handle_get_descriptor(&mut self, req: Request, stage: DataInStage) {
+    fn handle_get_descriptor<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
         let (dtype, index) = req.descriptor_type_index();
 
         match dtype {
-            descriptor_type::BOS => self.control.accept_in(self.bos_descriptor, stage).await,
-            descriptor_type::DEVICE => self.control.accept_in(self.device_descriptor, stage).await,
-            descriptor_type::CONFIGURATION => {
-                self.control.accept_in(self.config_descriptor, stage).await
-            }
+            descriptor_type::BOS => InResponse::Accepted(self.bos_descriptor),
+            descriptor_type::DEVICE => InResponse::Accepted(self.device_descriptor),
+            descriptor_type::CONFIGURATION => InResponse::Accepted(self.config_descriptor),
             descriptor_type::STRING => {
                 if index == 0 {
-                    self.control
-                        .accept_in_writer(req, stage, |w| {
-                            w.write(descriptor_type::STRING, &lang_id::ENGLISH_US.to_le_bytes());
-                        })
-                        .await
+                    buf[0] = 4; // len
+                    buf[1] = descriptor_type::STRING;
+                    buf[2] = lang_id::ENGLISH_US as u8;
+                    buf[3] = (lang_id::ENGLISH_US >> 8) as u8;
+                    InResponse::Accepted(&buf[..4])
                 } else {
                     let s = match index {
                         STRING_INDEX_MANUFACTURER => self.config.manufacturer,
@@ -565,7 +577,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
                                 if let Some(handler) = &mut iface.handler {
                                     let index = StringIndex::new(index);
                                     let lang_id = req.index;
-                                    handler.get_string(index, lang_id, self.control_buf)
+                                    handler.get_string(index, lang_id)
                                 } else {
                                     warn!("String requested to an interface with no handler.");
                                     None
@@ -578,15 +590,29 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
                     };
 
                     if let Some(s) = s {
-                        self.control
-                            .accept_in_writer(req, stage, |w| w.string(s))
-                            .await
+                        if buf.len() < 2 {
+                            panic!("control buffer too small");
+                        }
+
+                        buf[1] = descriptor_type::STRING;
+                        let mut pos = 2;
+                        for c in s.encode_utf16() {
+                            if pos >= buf.len() {
+                                panic!("control buffer too small");
+                            }
+
+                            buf[pos..pos + 2].copy_from_slice(&c.to_le_bytes());
+                            pos += 2;
+                        }
+
+                        buf[0] = pos as u8;
+                        InResponse::Accepted(&buf[..pos])
                     } else {
-                        self.control.reject()
+                        InResponse::Rejected
                     }
                 }
             }
-            _ => self.control.reject(),
+            _ => InResponse::Rejected,
         }
     }
 }

From 02ae1138e1b67a18a0fea4f1871751ee1ad858c0 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Mon, 9 May 2022 03:25:21 +0200
Subject: [PATCH 3/5] usb: merge Control logic into main code.

Now that control stuff is called from just one place, there's
no need to keep it as a separate struct.
---
 embassy-usb/src/control.rs | 123 ----------------------------------
 embassy-usb/src/lib.rs     | 131 ++++++++++++++++++++++++-------------
 2 files changed, 86 insertions(+), 168 deletions(-)

diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs
index 4fc65b6a5..12e5303c3 100644
--- a/embassy-usb/src/control.rs
+++ b/embassy-usb/src/control.rs
@@ -1,7 +1,6 @@
 use core::mem;
 
 use super::types::*;
-use crate::driver::{self, EndpointError};
 
 /// Control request type.
 #[repr(u8)]
@@ -194,125 +193,3 @@ pub trait ControlHandler {
         None
     }
 }
-
-/// Typestate representing a ControlPipe in the DATA IN stage
-#[derive(Debug)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub(crate) struct DataInStage {
-    pub(crate) length: usize,
-}
-
-/// Typestate representing a ControlPipe in the DATA OUT stage
-#[derive(Debug)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub(crate) struct DataOutStage {
-    length: usize,
-}
-
-/// Typestate representing a ControlPipe in the STATUS stage
-#[derive(Debug)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub(crate) struct StatusStage {}
-
-#[derive(Debug)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub(crate) enum Setup {
-    DataIn(Request, DataInStage),
-    DataOut(Request, DataOutStage),
-}
-
-pub(crate) struct ControlPipe<C: driver::ControlPipe> {
-    control: C,
-}
-
-impl<C: driver::ControlPipe> ControlPipe<C> {
-    pub(crate) fn new(control: C) -> Self {
-        ControlPipe { control }
-    }
-
-    pub(crate) async fn setup(&mut self) -> Setup {
-        let req = self.control.setup().await;
-        trace!("control request: {:02x}", req);
-
-        match (req.direction, req.length) {
-            (UsbDirection::Out, n) => Setup::DataOut(
-                req,
-                DataOutStage {
-                    length: usize::from(n),
-                },
-            ),
-            (UsbDirection::In, n) => Setup::DataIn(
-                req,
-                DataInStage {
-                    length: usize::from(n),
-                },
-            ),
-        }
-    }
-
-    pub(crate) async fn data_out<'a>(
-        &mut self,
-        buf: &'a mut [u8],
-        stage: DataOutStage,
-    ) -> Result<(&'a [u8], StatusStage), EndpointError> {
-        if stage.length == 0 {
-            Ok((&[], StatusStage {}))
-        } else {
-            let req_length = stage.length;
-            let max_packet_size = self.control.max_packet_size();
-            let mut total = 0;
-
-            for chunk in buf.chunks_mut(max_packet_size) {
-                let size = self.control.data_out(chunk).await?;
-                total += size;
-                if size < max_packet_size || total == req_length {
-                    break;
-                }
-            }
-
-            let res = &buf[0..total];
-            #[cfg(feature = "defmt")]
-            trace!("  control out data: {:02x}", res);
-            #[cfg(not(feature = "defmt"))]
-            trace!("  control out data: {:02x?}", res);
-
-            Ok((res, StatusStage {}))
-        }
-    }
-
-    pub(crate) async fn accept_in(&mut self, buf: &[u8], stage: DataInStage) {
-        #[cfg(feature = "defmt")]
-        trace!("  control in accept {:02x}", buf);
-        #[cfg(not(feature = "defmt"))]
-        trace!("  control in accept {:02x?}", buf);
-
-        let req_len = stage.length;
-        let len = buf.len().min(req_len);
-        let max_packet_size = self.control.max_packet_size();
-        let need_zlp = len != req_len && (len % usize::from(max_packet_size)) == 0;
-
-        let mut chunks = buf[0..len]
-            .chunks(max_packet_size)
-            .chain(need_zlp.then(|| -> &[u8] { &[] }));
-
-        while let Some(chunk) = chunks.next() {
-            match self.control.data_in(chunk, chunks.size_hint().0 == 0).await {
-                Ok(()) => {}
-                Err(e) => {
-                    warn!("control accept_in failed: {:?}", e);
-                    return;
-                }
-            }
-        }
-    }
-
-    pub(crate) fn accept(&mut self, _: StatusStage) {
-        trace!("  control accept");
-        self.control.accept();
-    }
-
-    pub(crate) fn reject(&mut self) {
-        trace!("  control reject");
-        self.control.reject();
-    }
-}
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index 690305885..99c0f8237 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -16,6 +16,7 @@ use embassy::util::{select, Either};
 use heapless::Vec;
 
 use crate::descriptor_reader::foreach_endpoint;
+use crate::driver::ControlPipe;
 
 use self::control::*;
 use self::descriptor::*;
@@ -101,7 +102,7 @@ struct Interface<'d> {
 
 pub struct UsbDevice<'d, D: Driver<'d>> {
     control_buf: &'d mut [u8],
-    control: ControlPipe<D::ControlPipe>,
+    control: D::ControlPipe,
     inner: Inner<'d, D>,
 }
 
@@ -144,7 +145,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
 
         Self {
             control_buf,
-            control: ControlPipe::new(control),
+            control,
             inner: Inner {
                 bus,
                 config,
@@ -192,52 +193,12 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
             }
         }
 
-        loop {
+        while !self.inner.suspended {
             let control_fut = self.control.setup();
             let bus_fut = self.inner.bus.poll();
             match select(bus_fut, control_fut).await {
-                Either::First(evt) => {
-                    self.inner.handle_bus_event(evt);
-                    if self.inner.suspended {
-                        return;
-                    }
-                }
-                Either::Second(req) => match req {
-                    Setup::DataIn(req, mut stage) => {
-                        // If we don't have an address yet, respond with max 1 packet.
-                        // The host doesn't know our EP0 max packet size yet, and might assume
-                        // a full-length packet is a short packet, thinking we're done sending data.
-                        // See https://github.com/hathach/tinyusb/issues/184
-                        const DEVICE_DESCRIPTOR_LEN: u8 = 18;
-                        if self.inner.pending_address == 0
-                            && self.inner.config.max_packet_size_0 < DEVICE_DESCRIPTOR_LEN
-                            && (self.inner.config.max_packet_size_0 as usize) < stage.length
-                        {
-                            trace!("received control req while not addressed: capping response to 1 packet.");
-                            stage.length = self.inner.config.max_packet_size_0 as _;
-                        }
-
-                        match self.inner.handle_control_in(req, &mut self.control_buf) {
-                            InResponse::Accepted(data) => self.control.accept_in(data, stage).await,
-                            InResponse::Rejected => self.control.reject(),
-                        }
-                    }
-                    Setup::DataOut(req, stage) => {
-                        let (data, stage) =
-                            match self.control.data_out(self.control_buf, stage).await {
-                                Ok(data) => data,
-                                Err(_) => {
-                                    warn!("usb: failed to read CONTROL OUT data stage.");
-                                    return;
-                                }
-                            };
-
-                        match self.inner.handle_control_out(req, data) {
-                            OutResponse::Accepted => self.control.accept(stage),
-                            OutResponse::Rejected => self.control.reject(),
-                        }
-                    }
-                },
+                Either::First(evt) => self.inner.handle_bus_event(evt),
+                Either::Second(req) => self.handle_control(req).await,
             }
         }
     }
@@ -288,6 +249,86 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
             Err(RemoteWakeupError::InvalidState)
         }
     }
+
+    async fn handle_control(&mut self, req: Request) {
+        trace!("control request: {:02x}", req);
+
+        match req.direction {
+            UsbDirection::In => self.handle_control_in(req).await,
+            UsbDirection::Out => self.handle_control_out(req).await,
+        }
+    }
+
+    async fn handle_control_in(&mut self, req: Request) {
+        let mut resp_length = req.length as usize;
+        let max_packet_size = self.control.max_packet_size();
+
+        // If we don't have an address yet, respond with max 1 packet.
+        // The host doesn't know our EP0 max packet size yet, and might assume
+        // a full-length packet is a short packet, thinking we're done sending data.
+        // See https://github.com/hathach/tinyusb/issues/184
+        const DEVICE_DESCRIPTOR_LEN: usize = 18;
+        if self.inner.pending_address == 0
+            && max_packet_size < DEVICE_DESCRIPTOR_LEN
+            && (max_packet_size as usize) < resp_length
+        {
+            trace!("received control req while not addressed: capping response to 1 packet.");
+            resp_length = max_packet_size;
+        }
+
+        match self.inner.handle_control_in(req, &mut self.control_buf) {
+            InResponse::Accepted(data) => {
+                let len = data.len().min(resp_length);
+                let need_zlp = len != resp_length && (len % usize::from(max_packet_size)) == 0;
+
+                let mut chunks = data[0..len]
+                    .chunks(max_packet_size)
+                    .chain(need_zlp.then(|| -> &[u8] { &[] }));
+
+                while let Some(chunk) = chunks.next() {
+                    match self.control.data_in(chunk, chunks.size_hint().0 == 0).await {
+                        Ok(()) => {}
+                        Err(e) => {
+                            warn!("control accept_in failed: {:?}", e);
+                            return;
+                        }
+                    }
+                }
+            }
+            InResponse::Rejected => self.control.reject(),
+        }
+    }
+
+    async fn handle_control_out(&mut self, req: Request) {
+        let req_length = req.length as usize;
+        let max_packet_size = self.control.max_packet_size();
+        let mut total = 0;
+
+        for chunk in self.control_buf[..req_length].chunks_mut(max_packet_size) {
+            let size = match self.control.data_out(chunk).await {
+                Ok(x) => x,
+                Err(e) => {
+                    warn!("usb: failed to read CONTROL OUT data stage: {:?}", e);
+                    return;
+                }
+            };
+            total += size;
+            if size < max_packet_size || total == req_length {
+                break;
+            }
+        }
+
+        let data = &self.control_buf[0..total];
+        #[cfg(feature = "defmt")]
+        trace!("  control out data: {:02x}", data);
+        #[cfg(not(feature = "defmt"))]
+        trace!("  control out data: {:02x?}", data);
+
+        match self.inner.handle_control_out(req, data) {
+            OutResponse::Accepted => self.control.accept(),
+            OutResponse::Rejected => self.control.reject(),
+        }
+    }
 }
 
 impl<'d, D: Driver<'d>> Inner<'d, D> {

From 6af5f8eb2da6ba9e1eabb67871c3483ba1579dd2 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Tue, 10 May 2022 16:53:42 +0200
Subject: [PATCH 4/5] usb: merge `alloc_control_pipe` and `into_bus` into
 `start`.

This prevents calling `alloc_control_pipe` twice at compile time, which was
always an error.
---
 embassy-nrf/src/usb.rs    | 47 ++++++++++++---------------------------
 embassy-usb/src/driver.rs | 19 ++++++++--------
 embassy-usb/src/lib.rs    | 10 +++------
 3 files changed, 27 insertions(+), 49 deletions(-)

diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs
index 70393532f..1162946a9 100644
--- a/embassy-nrf/src/usb.rs
+++ b/embassy-nrf/src/usb.rs
@@ -147,7 +147,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
         packet_size: u16,
         interval: u8,
     ) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
-        let index = self.alloc_in.allocate(ep_type, packet_size, interval)?;
+        let index = self.alloc_in.allocate(ep_type)?;
         let ep_addr = EndpointAddress::from_parts(index, UsbDirection::In);
         Ok(Endpoint::new(EndpointInfo {
             addr: ep_addr,
@@ -163,7 +163,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
         packet_size: u16,
         interval: u8,
     ) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
-        let index = self.alloc_out.allocate(ep_type, packet_size, interval)?;
+        let index = self.alloc_out.allocate(ep_type)?;
         let ep_addr = EndpointAddress::from_parts(index, UsbDirection::Out);
         Ok(Endpoint::new(EndpointInfo {
             addr: ep_addr,
@@ -173,24 +173,16 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
         }))
     }
 
-    fn alloc_control_pipe(
-        &mut self,
-        max_packet_size: u16,
-    ) -> Result<Self::ControlPipe, driver::EndpointAllocError> {
-        self.alloc_in.used |= 0x01;
-        self.alloc_in.lens[0] = max_packet_size as u8;
-        self.alloc_out.used |= 0x01;
-        self.alloc_out.lens[0] = max_packet_size as u8;
-        Ok(ControlPipe {
-            _phantom: PhantomData,
-            max_packet_size,
-        })
-    }
-
-    fn into_bus(self) -> Self::Bus {
-        Bus {
-            phantom: PhantomData,
-        }
+    fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
+        (
+            Bus {
+                phantom: PhantomData,
+            },
+            ControlPipe {
+                _phantom: PhantomData,
+                max_packet_size: control_max_packet_size,
+            },
+        )
     }
 }
 
@@ -791,24 +783,14 @@ fn dma_end() {
 
 struct Allocator {
     used: u16,
-    // Buffers can be up to 64 Bytes since this is a Full-Speed implementation.
-    lens: [u8; 9],
 }
 
 impl Allocator {
     fn new() -> Self {
-        Self {
-            used: 0,
-            lens: [0; 9],
-        }
+        Self { used: 0 }
     }
 
-    fn allocate(
-        &mut self,
-        ep_type: EndpointType,
-        max_packet_size: u16,
-        _interval: u8,
-    ) -> Result<usize, driver::EndpointAllocError> {
+    fn allocate(&mut self, ep_type: EndpointType) -> Result<usize, driver::EndpointAllocError> {
         // Endpoint addresses are fixed in hardware:
         // - 0x80 / 0x00 - Control        EP0
         // - 0x81 / 0x01 - Bulk/Interrupt EP1
@@ -840,7 +822,6 @@ impl Allocator {
         }
 
         self.used |= 1 << alloc_index;
-        self.lens[alloc_index] = max_packet_size as u8;
 
         Ok(alloc_index)
     }
diff --git a/embassy-usb/src/driver.rs b/embassy-usb/src/driver.rs
index a782b377c..57f2b0656 100644
--- a/embassy-usb/src/driver.rs
+++ b/embassy-usb/src/driver.rs
@@ -14,7 +14,7 @@ pub trait Driver<'a> {
 
     /// Allocates an endpoint and specified endpoint parameters. This method is called by the device
     /// and class implementations to allocate endpoints, and can only be called before
-    /// [`enable`](UsbBus::enable) is called.
+    /// [`start`](UsbBus::start) is called.
     ///
     /// # Arguments
     ///
@@ -37,14 +37,15 @@ pub trait Driver<'a> {
         interval: u8,
     ) -> Result<Self::EndpointIn, EndpointAllocError>;
 
-    fn alloc_control_pipe(
-        &mut self,
-        max_packet_size: u16,
-    ) -> Result<Self::ControlPipe, EndpointAllocError>;
-
-    /// Enables and initializes the USB peripheral. Soon after enabling the device will be reset, so
-    /// there is no need to perform a USB reset in this method.
-    fn into_bus(self) -> Self::Bus;
+    /// Start operation of the USB device.
+    ///
+    /// This returns the `Bus` and `ControlPipe` instances that are used to operate
+    /// the USB device. Additionally, this makes all the previously allocated endpoints
+    /// start operating.
+    ///
+    /// This consumes the `Driver` instance, so it's no longer possible to allocate more
+    /// endpoints.
+    fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe);
 
     /// Indicates that `set_device_address` must be called before accepting the corresponding
     /// control transfer, not after.
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index 99c0f8237..b135f5eb3 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -126,7 +126,7 @@ struct Inner<'d, D: Driver<'d>> {
 
 impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
     pub(crate) fn build(
-        mut driver: D,
+        driver: D,
         config: Config<'d>,
         handler: Option<&'d dyn DeviceStateHandler>,
         device_descriptor: &'d [u8],
@@ -135,13 +135,9 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
         interfaces: Vec<Interface<'d>, MAX_INTERFACE_COUNT>,
         control_buf: &'d mut [u8],
     ) -> UsbDevice<'d, D> {
-        let control = driver
-            .alloc_control_pipe(config.max_packet_size_0 as u16)
-            .expect("failed to alloc control endpoint");
-
-        // Enable the USB bus.
+        // Start the USB bus.
         // This prevent further allocation by consuming the driver.
-        let bus = driver.into_bus();
+        let (bus, control) = driver.start(config.max_packet_size_0 as u16);
 
         Self {
             control_buf,

From 2a7afe4262fd3ff8288c6381598a8794a7beee37 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timo=20Kr=C3=B6ger?= <timo.kroeger@hitachienergy.com>
Date: Thu, 12 May 2022 07:59:33 +0200
Subject: [PATCH 5/5] Make usb_serial examples work on windows

Windows shows `error 10` when using CDC ACM on non composite devices.
Workaround is to use IADS:
https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
---
 examples/nrf/src/bin/usb_serial.rs           | 7 +++++++
 examples/nrf/src/bin/usb_serial_multitask.rs | 7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/examples/nrf/src/bin/usb_serial.rs b/examples/nrf/src/bin/usb_serial.rs
index bc41c2acf..f607781a8 100644
--- a/examples/nrf/src/bin/usb_serial.rs
+++ b/examples/nrf/src/bin/usb_serial.rs
@@ -43,6 +43,13 @@ async fn main(_spawner: Spawner, p: Peripherals) {
     config.max_power = 100;
     config.max_packet_size_0 = 64;
 
+    // Required for windows compatiblity.
+    // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
+    config.device_class = 0xEF;
+    config.device_sub_class = 0x02;
+    config.device_protocol = 0x01;
+    config.composite_with_iads = true;
+
     // Create embassy-usb DeviceBuilder using the driver and config.
     // It needs some buffers for building the descriptors.
     let mut device_descriptor = [0; 256];
diff --git a/examples/nrf/src/bin/usb_serial_multitask.rs b/examples/nrf/src/bin/usb_serial_multitask.rs
index 31e0af483..e165cd434 100644
--- a/examples/nrf/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf/src/bin/usb_serial_multitask.rs
@@ -60,6 +60,13 @@ async fn main(spawner: Spawner, p: Peripherals) {
     config.max_power = 100;
     config.max_packet_size_0 = 64;
 
+    // Required for windows compatiblity.
+    // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
+    config.device_class = 0xEF;
+    config.device_sub_class = 0x02;
+    config.device_protocol = 0x01;
+    config.composite_with_iads = true;
+
     struct Resources {
         device_descriptor: [u8; 256],
         config_descriptor: [u8; 256],