From 7f7c14b7bce5b84eb27c8122535a96a6f0e5dd77 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Mon, 26 Sep 2022 12:29:27 +0200
Subject: [PATCH 1/3] usb: split driver trait to separate crate.

---
 embassy-nrf/src/usb.rs                        |  17 +--
 embassy-rp/src/usb.rs                         |  27 ++---
 embassy-stm32/src/usb/usb.rs                  |  35 +++---
 embassy-usb-driver/Cargo.toml                 |  16 +++
 .../src/lib.rs                                | 107 +++++++++++++++++-
 embassy-usb/Cargo.toml                        |   4 +
 embassy-usb/src/builder.rs                    |  11 +-
 embassy-usb/src/control.rs                    |   5 +-
 embassy-usb/src/descriptor.rs                 |   7 +-
 embassy-usb/src/descriptor_reader.rs          |   2 +-
 embassy-usb/src/lib.rs                        |  18 +--
 embassy-usb/src/types.rs                      | 105 -----------------
 12 files changed, 189 insertions(+), 165 deletions(-)
 create mode 100644 embassy-usb-driver/Cargo.toml
 rename embassy-usb/src/driver.rs => embassy-usb-driver/src/lib.rs (72%)

diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs
index 0685d419c..20510eb49 100644
--- a/embassy-nrf/src/usb.rs
+++ b/embassy-nrf/src/usb.rs
@@ -10,8 +10,9 @@ use cortex_m::peripheral::NVIC;
 use embassy_hal_common::{into_ref, PeripheralRef};
 use embassy_sync::waitqueue::AtomicWaker;
 pub use embassy_usb;
-use embassy_usb::driver::{self, EndpointError, Event, Unsupported};
-use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
+use embassy_usb::driver::{
+    self, Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
+};
 use pac::usbd::RegisterBlock;
 
 use crate::interrupt::{Interrupt, InterruptExt};
@@ -243,7 +244,7 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P>
         interval: u8,
     ) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
         let index = self.alloc_in.allocate(ep_type)?;
-        let ep_addr = EndpointAddress::from_parts(index, UsbDirection::In);
+        let ep_addr = EndpointAddress::from_parts(index, Direction::In);
         Ok(Endpoint::new(EndpointInfo {
             addr: ep_addr,
             ep_type,
@@ -259,7 +260,7 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P>
         interval: u8,
     ) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
         let index = self.alloc_out.allocate(ep_type)?;
-        let ep_addr = EndpointAddress::from_parts(index, UsbDirection::Out);
+        let ep_addr = EndpointAddress::from_parts(index, Direction::Out);
         Ok(Endpoint::new(EndpointInfo {
             addr: ep_addr,
             ep_type,
@@ -428,8 +429,8 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
         let regs = T::regs();
         let i = ep_addr.index();
         match ep_addr.direction() {
-            UsbDirection::Out => regs.halted.epout[i].read().getstatus().is_halted(),
-            UsbDirection::In => regs.halted.epin[i].read().getstatus().is_halted(),
+            Direction::Out => regs.halted.epout[i].read().getstatus().is_halted(),
+            Direction::In => regs.halted.epin[i].read().getstatus().is_halted(),
         }
     }
 
@@ -442,7 +443,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
         debug!("endpoint_set_enabled {:?} {}", ep_addr, enabled);
 
         match ep_addr.direction() {
-            UsbDirection::In => {
+            Direction::In => {
                 let mut was_enabled = false;
                 regs.epinen.modify(|r, w| {
                     let mut bits = r.bits();
@@ -466,7 +467,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
 
                 In::waker(i).wake();
             }
-            UsbDirection::Out => {
+            Direction::Out => {
                 regs.epouten.modify(|r, w| {
                     let mut bits = r.bits();
                     if enabled {
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index a7ec5fb79..ce473b21d 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -7,8 +7,9 @@ use core::task::Poll;
 use atomic_polyfill::compiler_fence;
 use embassy_hal_common::into_ref;
 use embassy_sync::waitqueue::AtomicWaker;
-use embassy_usb::driver::{self, EndpointAllocError, EndpointError, Event, Unsupported};
-use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
+use embassy_usb::driver::{
+    self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
+};
 
 use crate::interrupt::{Interrupt, InterruptExt};
 use crate::{pac, peripherals, Peripheral, RegExt};
@@ -204,8 +205,8 @@ impl<'d, T: Instance> Driver<'d, T> {
         );
 
         let alloc = match D::dir() {
-            UsbDirection::Out => &mut self.ep_out,
-            UsbDirection::In => &mut self.ep_in,
+            Direction::Out => &mut self.ep_out,
+            Direction::In => &mut self.ep_in,
         };
 
         let index = alloc.iter_mut().enumerate().find(|(i, ep)| {
@@ -254,7 +255,7 @@ impl<'d, T: Instance> Driver<'d, T> {
         };
 
         match D::dir() {
-            UsbDirection::Out => unsafe {
+            Direction::Out => unsafe {
                 T::dpram().ep_out_control(index - 1).write(|w| {
                     w.set_enable(false);
                     w.set_buffer_address(addr);
@@ -262,7 +263,7 @@ impl<'d, T: Instance> Driver<'d, T> {
                     w.set_endpoint_type(ep_type_reg);
                 })
             },
-            UsbDirection::In => unsafe {
+            Direction::In => unsafe {
                 T::dpram().ep_in_control(index - 1).write(|w| {
                     w.set_enable(false);
                     w.set_buffer_address(addr);
@@ -429,14 +430,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
 
         let n = ep_addr.index();
         match ep_addr.direction() {
-            UsbDirection::In => unsafe {
+            Direction::In => unsafe {
                 T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled));
                 T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| {
                     w.set_pid(0, true); // first packet is DATA0, but PID is flipped before
                 });
                 EP_IN_WAKERS[n].wake();
             },
-            UsbDirection::Out => unsafe {
+            Direction::Out => unsafe {
                 T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled));
 
                 T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| {
@@ -474,14 +475,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
 }
 
 trait Dir {
-    fn dir() -> UsbDirection;
+    fn dir() -> Direction;
     fn waker(i: usize) -> &'static AtomicWaker;
 }
 
 pub enum In {}
 impl Dir for In {
-    fn dir() -> UsbDirection {
-        UsbDirection::In
+    fn dir() -> Direction {
+        Direction::In
     }
 
     #[inline]
@@ -492,8 +493,8 @@ impl Dir for In {
 
 pub enum Out {}
 impl Dir for Out {
-    fn dir() -> UsbDirection {
-        UsbDirection::Out
+    fn dir() -> Direction {
+        Direction::Out
     }
 
     #[inline]
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index e5ee1181c..39809a3e1 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -9,8 +9,9 @@ use atomic_polyfill::{AtomicBool, AtomicU8};
 use embassy_hal_common::into_ref;
 use embassy_sync::waitqueue::AtomicWaker;
 use embassy_time::{block_for, Duration};
-use embassy_usb::driver::{self, EndpointAllocError, EndpointError, Event, Unsupported};
-use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
+use embassy_usb::driver::{
+    self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
+};
 use pac::common::{Reg, RW};
 use pac::usb::vals::{EpType, Stat};
 
@@ -279,8 +280,8 @@ impl<'d, T: Instance> Driver<'d, T> {
             }
             let used = ep.used_out || ep.used_in;
             let used_dir = match D::dir() {
-                UsbDirection::Out => ep.used_out,
-                UsbDirection::In => ep.used_in,
+                Direction::Out => ep.used_out,
+                Direction::In => ep.used_in,
             };
             !used || (ep.ep_type == ep_type && !used_dir)
         });
@@ -293,7 +294,7 @@ impl<'d, T: Instance> Driver<'d, T> {
         ep.ep_type = ep_type;
 
         let buf = match D::dir() {
-            UsbDirection::Out => {
+            Direction::Out => {
                 assert!(!ep.used_out);
                 ep.used_out = true;
 
@@ -312,7 +313,7 @@ impl<'d, T: Instance> Driver<'d, T> {
                     _phantom: PhantomData,
                 }
             }
-            UsbDirection::In => {
+            Direction::In => {
                 assert!(!ep.used_in);
                 ep.used_in = true;
 
@@ -504,7 +505,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
         // This can race, so do a retry loop.
         let reg = T::regs().epr(ep_addr.index() as _);
         match ep_addr.direction() {
-            UsbDirection::In => {
+            Direction::In => {
                 loop {
                     let r = unsafe { reg.read() };
                     match r.stat_tx() {
@@ -523,7 +524,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
                 }
                 EP_IN_WAKERS[ep_addr.index()].wake();
             }
-            UsbDirection::Out => {
+            Direction::Out => {
                 loop {
                     let r = unsafe { reg.read() };
                     match r.stat_rx() {
@@ -549,8 +550,8 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
         let regs = T::regs();
         let epr = unsafe { regs.epr(ep_addr.index() as _).read() };
         match ep_addr.direction() {
-            UsbDirection::In => epr.stat_tx() == Stat::STALL,
-            UsbDirection::Out => epr.stat_rx() == Stat::STALL,
+            Direction::In => epr.stat_tx() == Stat::STALL,
+            Direction::Out => epr.stat_rx() == Stat::STALL,
         }
     }
 
@@ -560,7 +561,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
         let reg = T::regs().epr(ep_addr.index() as _);
         trace!("EPR before: {:04x}", unsafe { reg.read() }.0);
         match ep_addr.direction() {
-            UsbDirection::In => {
+            Direction::In => {
                 loop {
                     let want_stat = match enabled {
                         false => Stat::DISABLED,
@@ -576,7 +577,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
                 }
                 EP_IN_WAKERS[ep_addr.index()].wake();
             }
-            UsbDirection::Out => {
+            Direction::Out => {
                 loop {
                     let want_stat = match enabled {
                         false => Stat::DISABLED,
@@ -616,14 +617,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
 }
 
 trait Dir {
-    fn dir() -> UsbDirection;
+    fn dir() -> Direction;
     fn waker(i: usize) -> &'static AtomicWaker;
 }
 
 pub enum In {}
 impl Dir for In {
-    fn dir() -> UsbDirection {
-        UsbDirection::In
+    fn dir() -> Direction {
+        Direction::In
     }
 
     #[inline]
@@ -634,8 +635,8 @@ impl Dir for In {
 
 pub enum Out {}
 impl Dir for Out {
-    fn dir() -> UsbDirection {
-        UsbDirection::Out
+    fn dir() -> Direction {
+        Direction::Out
     }
 
     #[inline]
diff --git a/embassy-usb-driver/Cargo.toml b/embassy-usb-driver/Cargo.toml
new file mode 100644
index 000000000..b525df337
--- /dev/null
+++ b/embassy-usb-driver/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "embassy-usb-driver"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[package.metadata.embassy_docs]
+src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-driver-v$VERSION/embassy-usb/src/"
+src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-driver/src/"
+features = ["defmt"]
+target = "thumbv7em-none-eabi"
+
+[dependencies]
+defmt = { version = "0.3", optional = true }
+log = { version = "0.4.14", optional = true }
\ No newline at end of file
diff --git a/embassy-usb/src/driver.rs b/embassy-usb-driver/src/lib.rs
similarity index 72%
rename from embassy-usb/src/driver.rs
rename to embassy-usb-driver/src/lib.rs
index 7888f1639..051190a48 100644
--- a/embassy-usb/src/driver.rs
+++ b/embassy-usb-driver/src/lib.rs
@@ -1,6 +1,111 @@
+#![no_std]
+
 use core::future::Future;
 
-use super::types::*;
+/// Direction of USB traffic. Note that in the USB standard the direction is always indicated from
+/// the perspective of the host, which is backward for devices, but the standard directions are used
+/// for consistency.
+///
+/// The values of the enum also match the direction bit used in endpoint addresses and control
+/// request types.
+#[repr(u8)]
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum Direction {
+    /// Host to device (OUT)
+    Out = 0x00,
+    /// Device to host (IN)
+    In = 0x80,
+}
+
+impl From<u8> for Direction {
+    fn from(value: u8) -> Self {
+        unsafe { core::mem::transmute(value & 0x80) }
+    }
+}
+
+/// USB endpoint transfer type. The values of this enum can be directly cast into `u8` to get the
+/// transfer bmAttributes transfer type bits.
+#[repr(u8)]
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum EndpointType {
+    /// Control endpoint. Used for device management. Only the host can initiate requests. Usually
+    /// used only endpoint 0.
+    Control = 0b00,
+    /// Isochronous endpoint. Used for time-critical unreliable data. Not implemented yet.
+    Isochronous = 0b01,
+    /// Bulk endpoint. Used for large amounts of best-effort reliable data.
+    Bulk = 0b10,
+    /// Interrupt endpoint. Used for small amounts of time-critical reliable data.
+    Interrupt = 0b11,
+}
+
+/// Type-safe endpoint address.
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct EndpointAddress(u8);
+
+impl From<u8> for EndpointAddress {
+    #[inline]
+    fn from(addr: u8) -> EndpointAddress {
+        EndpointAddress(addr)
+    }
+}
+
+impl From<EndpointAddress> for u8 {
+    #[inline]
+    fn from(addr: EndpointAddress) -> u8 {
+        addr.0
+    }
+}
+
+impl EndpointAddress {
+    const INBITS: u8 = Direction::In as u8;
+
+    /// Constructs a new EndpointAddress with the given index and direction.
+    #[inline]
+    pub fn from_parts(index: usize, dir: Direction) -> Self {
+        EndpointAddress(index as u8 | dir as u8)
+    }
+
+    /// Gets the direction part of the address.
+    #[inline]
+    pub fn direction(&self) -> Direction {
+        if (self.0 & Self::INBITS) != 0 {
+            Direction::In
+        } else {
+            Direction::Out
+        }
+    }
+
+    /// Returns true if the direction is IN, otherwise false.
+    #[inline]
+    pub fn is_in(&self) -> bool {
+        (self.0 & Self::INBITS) != 0
+    }
+
+    /// Returns true if the direction is OUT, otherwise false.
+    #[inline]
+    pub fn is_out(&self) -> bool {
+        (self.0 & Self::INBITS) == 0
+    }
+
+    /// Gets the index part of the endpoint address.
+    #[inline]
+    pub fn index(&self) -> usize {
+        (self.0 & !Self::INBITS) as usize
+    }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct EndpointInfo {
+    pub addr: EndpointAddress,
+    pub ep_type: EndpointType,
+    pub max_packet_size: u16,
+    pub interval: u8,
+}
 
 /// Driver for a specific USB peripheral. Implement this to add support for a new hardware
 /// platform.
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml
index 8cad4d314..660ecc8cc 100644
--- a/embassy-usb/Cargo.toml
+++ b/embassy-usb/Cargo.toml
@@ -9,8 +9,12 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb/s
 features = ["defmt"]
 target = "thumbv7em-none-eabi"
 
+[features]
+defmt = ["dep:defmt", "embassy-usb-driver/defmt"]
+
 [dependencies]
 embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
+embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
 
 defmt = { version = "0.3", optional = true }
 log = { version = "0.4.14", optional = true }
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 6be88bc76..87a8333bb 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -1,11 +1,10 @@
 use heapless::Vec;
 
-use super::control::ControlHandler;
-use super::descriptor::{BosWriter, DescriptorWriter};
-use super::driver::{Driver, Endpoint};
-use super::types::*;
-use super::{DeviceStateHandler, UsbDevice, MAX_INTERFACE_COUNT};
-use crate::{Interface, STRING_INDEX_CUSTOM_START};
+use crate::control::ControlHandler;
+use crate::descriptor::{BosWriter, DescriptorWriter};
+use crate::driver::{Driver, Endpoint, EndpointType};
+use crate::types::*;
+use crate::{DeviceStateHandler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
 
 #[derive(Debug, Copy, Clone)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs
index 3e5749a01..9e0dee888 100644
--- a/embassy-usb/src/control.rs
+++ b/embassy-usb/src/control.rs
@@ -1,7 +1,8 @@
 //! USB control data types.
 use core::mem;
 
-use super::types::*;
+use crate::driver::Direction;
+use crate::types::StringIndex;
 
 /// Control request type.
 #[repr(u8)]
@@ -42,7 +43,7 @@ pub enum Recipient {
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct Request {
     /// Direction of the request.
-    pub direction: UsbDirection,
+    pub direction: Direction,
     /// Type of the request.
     pub request_type: RequestType,
     /// Recipient of the request.
diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs
index b94a4b161..497f03196 100644
--- a/embassy-usb/src/descriptor.rs
+++ b/embassy-usb/src/descriptor.rs
@@ -1,6 +1,7 @@
-use super::builder::Config;
-use super::types::*;
-use super::CONFIGURATION_VALUE;
+use crate::builder::Config;
+use crate::driver::EndpointInfo;
+use crate::types::*;
+use crate::CONFIGURATION_VALUE;
 
 /// Standard descriptor types
 #[allow(missing_docs)]
diff --git a/embassy-usb/src/descriptor_reader.rs b/embassy-usb/src/descriptor_reader.rs
index 0a12b566c..d64bcb73b 100644
--- a/embassy-usb/src/descriptor_reader.rs
+++ b/embassy-usb/src/descriptor_reader.rs
@@ -1,5 +1,5 @@
 use crate::descriptor::descriptor_type;
-use crate::types::EndpointAddress;
+use crate::driver::EndpointAddress;
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index 6f58c953c..e1a99cfae 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -4,23 +4,23 @@
 // This mod MUST go first, so that the others see its macros.
 pub(crate) mod fmt;
 
+pub use embassy_usb_driver as driver;
+
 mod builder;
 pub mod control;
 pub mod descriptor;
 mod descriptor_reader;
-pub mod driver;
 pub mod types;
 
 use embassy_futures::select::{select, Either};
 use heapless::Vec;
 
-pub use self::builder::{Builder, Config};
-use self::control::*;
-use self::descriptor::*;
-use self::driver::{Bus, Driver, Event};
-use self::types::*;
+pub use crate::builder::{Builder, Config};
+use crate::control::*;
+use crate::descriptor::*;
 use crate::descriptor_reader::foreach_endpoint;
-use crate::driver::ControlPipe;
+use crate::driver::{Bus, ControlPipe, Direction, Driver, EndpointAddress, Event};
+use crate::types::*;
 
 /// The global state of the USB device.
 ///
@@ -250,8 +250,8 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
         trace!("control request: {:?}", req);
 
         match req.direction {
-            UsbDirection::In => self.handle_control_in(req).await,
-            UsbDirection::Out => self.handle_control_out(req).await,
+            Direction::In => self.handle_control_in(req).await,
+            Direction::Out => self.handle_control_out(req).await,
         }
 
         if self.inner.set_address_pending {
diff --git a/embassy-usb/src/types.rs b/embassy-usb/src/types.rs
index b8717ffa9..aeab063d1 100644
--- a/embassy-usb/src/types.rs
+++ b/embassy-usb/src/types.rs
@@ -1,108 +1,3 @@
-/// Direction of USB traffic. Note that in the USB standard the direction is always indicated from
-/// the perspective of the host, which is backward for devices, but the standard directions are used
-/// for consistency.
-///
-/// The values of the enum also match the direction bit used in endpoint addresses and control
-/// request types.
-#[repr(u8)]
-#[derive(Copy, Clone, Eq, PartialEq, Debug)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum UsbDirection {
-    /// Host to device (OUT)
-    Out = 0x00,
-    /// Device to host (IN)
-    In = 0x80,
-}
-
-impl From<u8> for UsbDirection {
-    fn from(value: u8) -> Self {
-        unsafe { core::mem::transmute(value & 0x80) }
-    }
-}
-
-/// USB endpoint transfer type. The values of this enum can be directly cast into `u8` to get the
-/// transfer bmAttributes transfer type bits.
-#[repr(u8)]
-#[derive(Copy, Clone, Eq, PartialEq, Debug)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum EndpointType {
-    /// Control endpoint. Used for device management. Only the host can initiate requests. Usually
-    /// used only endpoint 0.
-    Control = 0b00,
-    /// Isochronous endpoint. Used for time-critical unreliable data. Not implemented yet.
-    Isochronous = 0b01,
-    /// Bulk endpoint. Used for large amounts of best-effort reliable data.
-    Bulk = 0b10,
-    /// Interrupt endpoint. Used for small amounts of time-critical reliable data.
-    Interrupt = 0b11,
-}
-
-/// Type-safe endpoint address.
-#[derive(Debug, Clone, Copy, Eq, PartialEq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct EndpointAddress(u8);
-
-impl From<u8> for EndpointAddress {
-    #[inline]
-    fn from(addr: u8) -> EndpointAddress {
-        EndpointAddress(addr)
-    }
-}
-
-impl From<EndpointAddress> for u8 {
-    #[inline]
-    fn from(addr: EndpointAddress) -> u8 {
-        addr.0
-    }
-}
-
-impl EndpointAddress {
-    const INBITS: u8 = UsbDirection::In as u8;
-
-    /// Constructs a new EndpointAddress with the given index and direction.
-    #[inline]
-    pub fn from_parts(index: usize, dir: UsbDirection) -> Self {
-        EndpointAddress(index as u8 | dir as u8)
-    }
-
-    /// Gets the direction part of the address.
-    #[inline]
-    pub fn direction(&self) -> UsbDirection {
-        if (self.0 & Self::INBITS) != 0 {
-            UsbDirection::In
-        } else {
-            UsbDirection::Out
-        }
-    }
-
-    /// Returns true if the direction is IN, otherwise false.
-    #[inline]
-    pub fn is_in(&self) -> bool {
-        (self.0 & Self::INBITS) != 0
-    }
-
-    /// Returns true if the direction is OUT, otherwise false.
-    #[inline]
-    pub fn is_out(&self) -> bool {
-        (self.0 & Self::INBITS) == 0
-    }
-
-    /// Gets the index part of the endpoint address.
-    #[inline]
-    pub fn index(&self) -> usize {
-        (self.0 & !Self::INBITS) as usize
-    }
-}
-
-#[derive(Copy, Clone, Eq, PartialEq, Debug)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct EndpointInfo {
-    pub addr: EndpointAddress,
-    pub ep_type: EndpointType,
-    pub max_packet_size: u16,
-    pub interval: u8,
-}
-
 /// A handle for a USB interface that contains its number.
 #[derive(Copy, Clone, Eq, PartialEq)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]

From f4f58249722bc656a13865e06535d208440c3e4a Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Mon, 26 Sep 2022 12:35:33 +0200
Subject: [PATCH 2/3] usb: do not allow converting Directon to/from u8

---
 embassy-usb-driver/src/lib.rs | 11 ++---------
 embassy-usb/src/control.rs    |  2 +-
 2 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/embassy-usb-driver/src/lib.rs b/embassy-usb-driver/src/lib.rs
index 051190a48..fc29786fc 100644
--- a/embassy-usb-driver/src/lib.rs
+++ b/embassy-usb-driver/src/lib.rs
@@ -8,20 +8,13 @@ use core::future::Future;
 ///
 /// The values of the enum also match the direction bit used in endpoint addresses and control
 /// request types.
-#[repr(u8)]
 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub enum Direction {
     /// Host to device (OUT)
-    Out = 0x00,
+    Out,
     /// Device to host (IN)
-    In = 0x80,
-}
-
-impl From<u8> for Direction {
-    fn from(value: u8) -> Self {
-        unsafe { core::mem::transmute(value & 0x80) }
-    }
+    In,
 }
 
 /// USB endpoint transfer type. The values of this enum can be directly cast into `u8` to get the
diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs
index 9e0dee888..d6d0c6565 100644
--- a/embassy-usb/src/control.rs
+++ b/embassy-usb/src/control.rs
@@ -106,7 +106,7 @@ impl Request {
         let recipient = rt & 0b11111;
 
         Request {
-            direction: rt.into(),
+            direction: if rt & 0x80 == 0 { Direction::Out } else { Direction::In },
             request_type: unsafe { mem::transmute((rt >> 5) & 0b11) },
             recipient: if recipient <= 3 {
                 unsafe { mem::transmute(recipient) }

From f27a47a37b59bf3b9079f4d4d5f43caf7b7872f8 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Mon, 26 Sep 2022 13:00:21 +0200
Subject: [PATCH 3/3] usb: move classes into the `embassy-usb` crate.

---
 embassy-usb-hid/Cargo.toml                    |  24 --
 embassy-usb-hid/src/fmt.rs                    | 225 ------------------
 embassy-usb-ncm/Cargo.toml                    |  17 --
 embassy-usb-ncm/src/fmt.rs                    | 225 ------------------
 embassy-usb-serial/Cargo.toml                 |  17 --
 embassy-usb-serial/src/fmt.rs                 | 225 ------------------
 embassy-usb/Cargo.toml                        |   9 +-
 .../src/class/cdc_acm.rs                      |  15 +-
 .../src/class/cdc_ncm.rs                      |  13 +-
 .../lib.rs => embassy-usb/src/class/hid.rs    |  23 +-
 embassy-usb/src/class/mod.rs                  |   3 +
 embassy-usb/src/lib.rs                        |   1 +
 examples/nrf/Cargo.toml                       |   5 +-
 examples/nrf/src/bin/usb_ethernet.rs          |   2 +-
 examples/nrf/src/bin/usb_hid_keyboard.rs      |   4 +-
 examples/nrf/src/bin/usb_hid_mouse.rs         |   4 +-
 examples/nrf/src/bin/usb_serial.rs            |   2 +-
 examples/nrf/src/bin/usb_serial_multitask.rs  |   2 +-
 examples/rp/Cargo.toml                        |   2 -
 examples/rp/src/bin/usb_ethernet.rs           |   2 +-
 examples/rp/src/bin/usb_serial.rs             |   2 +-
 examples/stm32f1/Cargo.toml                   |   1 -
 examples/stm32f1/src/bin/usb_serial.rs        |   2 +-
 examples/stm32f3/Cargo.toml                   |   2 -
 examples/stm32f3/src/bin/usb_serial.rs        |   2 +-
 examples/stm32l5/Cargo.toml                   |   3 -
 examples/stm32l5/src/bin/usb_ethernet.rs      |   2 +-
 examples/stm32l5/src/bin/usb_hid_mouse.rs     |   4 +-
 examples/stm32l5/src/bin/usb_serial.rs        |   2 +-
 29 files changed, 45 insertions(+), 795 deletions(-)
 delete mode 100644 embassy-usb-hid/Cargo.toml
 delete mode 100644 embassy-usb-hid/src/fmt.rs
 delete mode 100644 embassy-usb-ncm/Cargo.toml
 delete mode 100644 embassy-usb-ncm/src/fmt.rs
 delete mode 100644 embassy-usb-serial/Cargo.toml
 delete mode 100644 embassy-usb-serial/src/fmt.rs
 rename embassy-usb-serial/src/lib.rs => embassy-usb/src/class/cdc_acm.rs (96%)
 rename embassy-usb-ncm/src/lib.rs => embassy-usb/src/class/cdc_ncm.rs (97%)
 rename embassy-usb-hid/src/lib.rs => embassy-usb/src/class/hid.rs (96%)
 create mode 100644 embassy-usb/src/class/mod.rs

diff --git a/embassy-usb-hid/Cargo.toml b/embassy-usb-hid/Cargo.toml
deleted file mode 100644
index 2f7733dc6..000000000
--- a/embassy-usb-hid/Cargo.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-[package]
-name = "embassy-usb-hid"
-version = "0.1.0"
-edition = "2021"
-
-[package.metadata.embassy_docs]
-src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-hid-v$VERSION/embassy-usb-hid/src/"
-src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-hid/src/"
-features = ["defmt"]
-target = "thumbv7em-none-eabi"
-
-[features]
-default = ["usbd-hid"]
-usbd-hid = ["dep:usbd-hid", "ssmarshal"]
-
-[dependencies]
-embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
-embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
-
-defmt = { version = "0.3", optional = true }
-log = { version = "0.4.14", optional = true }
-usbd-hid = { version = "0.6.0", optional = true }
-ssmarshal = { version = "1.0", default-features = false, optional = true }
-futures-util = { version = "0.3.21", default-features = false }
diff --git a/embassy-usb-hid/src/fmt.rs b/embassy-usb-hid/src/fmt.rs
deleted file mode 100644
index 066970813..000000000
--- a/embassy-usb-hid/src/fmt.rs
+++ /dev/null
@@ -1,225 +0,0 @@
-#![macro_use]
-#![allow(unused_macros)]
-
-#[cfg(all(feature = "defmt", feature = "log"))]
-compile_error!("You may not enable both `defmt` and `log` features.");
-
-macro_rules! assert {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::assert!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::assert!($($x)*);
-        }
-    };
-}
-
-macro_rules! assert_eq {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::assert_eq!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::assert_eq!($($x)*);
-        }
-    };
-}
-
-macro_rules! assert_ne {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::assert_ne!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::assert_ne!($($x)*);
-        }
-    };
-}
-
-macro_rules! debug_assert {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::debug_assert!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::debug_assert!($($x)*);
-        }
-    };
-}
-
-macro_rules! debug_assert_eq {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::debug_assert_eq!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::debug_assert_eq!($($x)*);
-        }
-    };
-}
-
-macro_rules! debug_assert_ne {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::debug_assert_ne!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::debug_assert_ne!($($x)*);
-        }
-    };
-}
-
-macro_rules! todo {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::todo!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::todo!($($x)*);
-        }
-    };
-}
-
-macro_rules! unreachable {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::unreachable!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::unreachable!($($x)*);
-        }
-    };
-}
-
-macro_rules! panic {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::panic!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::panic!($($x)*);
-        }
-    };
-}
-
-macro_rules! trace {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::trace!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::trace!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-macro_rules! debug {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::debug!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::debug!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-macro_rules! info {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::info!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::info!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-macro_rules! warn {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::warn!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::warn!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-macro_rules! error {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::error!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::error!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-#[cfg(feature = "defmt")]
-macro_rules! unwrap {
-    ($($x:tt)*) => {
-        ::defmt::unwrap!($($x)*)
-    };
-}
-
-#[cfg(not(feature = "defmt"))]
-macro_rules! unwrap {
-    ($arg:expr) => {
-        match $crate::fmt::Try::into_result($arg) {
-            ::core::result::Result::Ok(t) => t,
-            ::core::result::Result::Err(e) => {
-                ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
-            }
-        }
-    };
-    ($arg:expr, $($msg:expr),+ $(,)? ) => {
-        match $crate::fmt::Try::into_result($arg) {
-            ::core::result::Result::Ok(t) => t,
-            ::core::result::Result::Err(e) => {
-                ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
-            }
-        }
-    }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub struct NoneError;
-
-pub trait Try {
-    type Ok;
-    type Error;
-    fn into_result(self) -> Result<Self::Ok, Self::Error>;
-}
-
-impl<T> Try for Option<T> {
-    type Ok = T;
-    type Error = NoneError;
-
-    #[inline]
-    fn into_result(self) -> Result<T, NoneError> {
-        self.ok_or(NoneError)
-    }
-}
-
-impl<T, E> Try for Result<T, E> {
-    type Ok = T;
-    type Error = E;
-
-    #[inline]
-    fn into_result(self) -> Self {
-        self
-    }
-}
diff --git a/embassy-usb-ncm/Cargo.toml b/embassy-usb-ncm/Cargo.toml
deleted file mode 100644
index 15d3db96f..000000000
--- a/embassy-usb-ncm/Cargo.toml
+++ /dev/null
@@ -1,17 +0,0 @@
-[package]
-name = "embassy-usb-ncm"
-version = "0.1.0"
-edition = "2021"
-
-[package.metadata.embassy_docs]
-src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-ncm-v$VERSION/embassy-usb-ncm/src/"
-src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-ncm/src/"
-features = ["defmt"]
-target = "thumbv7em-none-eabi"
-
-[dependencies]
-embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
-embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
-
-defmt = { version = "0.3", optional = true }
-log = { version = "0.4.14", optional = true }
diff --git a/embassy-usb-ncm/src/fmt.rs b/embassy-usb-ncm/src/fmt.rs
deleted file mode 100644
index 066970813..000000000
--- a/embassy-usb-ncm/src/fmt.rs
+++ /dev/null
@@ -1,225 +0,0 @@
-#![macro_use]
-#![allow(unused_macros)]
-
-#[cfg(all(feature = "defmt", feature = "log"))]
-compile_error!("You may not enable both `defmt` and `log` features.");
-
-macro_rules! assert {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::assert!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::assert!($($x)*);
-        }
-    };
-}
-
-macro_rules! assert_eq {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::assert_eq!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::assert_eq!($($x)*);
-        }
-    };
-}
-
-macro_rules! assert_ne {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::assert_ne!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::assert_ne!($($x)*);
-        }
-    };
-}
-
-macro_rules! debug_assert {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::debug_assert!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::debug_assert!($($x)*);
-        }
-    };
-}
-
-macro_rules! debug_assert_eq {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::debug_assert_eq!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::debug_assert_eq!($($x)*);
-        }
-    };
-}
-
-macro_rules! debug_assert_ne {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::debug_assert_ne!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::debug_assert_ne!($($x)*);
-        }
-    };
-}
-
-macro_rules! todo {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::todo!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::todo!($($x)*);
-        }
-    };
-}
-
-macro_rules! unreachable {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::unreachable!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::unreachable!($($x)*);
-        }
-    };
-}
-
-macro_rules! panic {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::panic!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::panic!($($x)*);
-        }
-    };
-}
-
-macro_rules! trace {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::trace!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::trace!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-macro_rules! debug {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::debug!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::debug!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-macro_rules! info {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::info!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::info!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-macro_rules! warn {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::warn!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::warn!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-macro_rules! error {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::error!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::error!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-#[cfg(feature = "defmt")]
-macro_rules! unwrap {
-    ($($x:tt)*) => {
-        ::defmt::unwrap!($($x)*)
-    };
-}
-
-#[cfg(not(feature = "defmt"))]
-macro_rules! unwrap {
-    ($arg:expr) => {
-        match $crate::fmt::Try::into_result($arg) {
-            ::core::result::Result::Ok(t) => t,
-            ::core::result::Result::Err(e) => {
-                ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
-            }
-        }
-    };
-    ($arg:expr, $($msg:expr),+ $(,)? ) => {
-        match $crate::fmt::Try::into_result($arg) {
-            ::core::result::Result::Ok(t) => t,
-            ::core::result::Result::Err(e) => {
-                ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
-            }
-        }
-    }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub struct NoneError;
-
-pub trait Try {
-    type Ok;
-    type Error;
-    fn into_result(self) -> Result<Self::Ok, Self::Error>;
-}
-
-impl<T> Try for Option<T> {
-    type Ok = T;
-    type Error = NoneError;
-
-    #[inline]
-    fn into_result(self) -> Result<T, NoneError> {
-        self.ok_or(NoneError)
-    }
-}
-
-impl<T, E> Try for Result<T, E> {
-    type Ok = T;
-    type Error = E;
-
-    #[inline]
-    fn into_result(self) -> Self {
-        self
-    }
-}
diff --git a/embassy-usb-serial/Cargo.toml b/embassy-usb-serial/Cargo.toml
deleted file mode 100644
index 9788588e9..000000000
--- a/embassy-usb-serial/Cargo.toml
+++ /dev/null
@@ -1,17 +0,0 @@
-[package]
-name = "embassy-usb-serial"
-version = "0.1.0"
-edition = "2021"
-
-[package.metadata.embassy_docs]
-src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-serial-v$VERSION/embassy-usb-serial/src/"
-src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-serial/src/"
-features = ["defmt"]
-target = "thumbv7em-none-eabi"
-
-[dependencies]
-embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
-embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
-
-defmt = { version = "0.3", optional = true }
-log = { version = "0.4.14", optional = true }
diff --git a/embassy-usb-serial/src/fmt.rs b/embassy-usb-serial/src/fmt.rs
deleted file mode 100644
index 066970813..000000000
--- a/embassy-usb-serial/src/fmt.rs
+++ /dev/null
@@ -1,225 +0,0 @@
-#![macro_use]
-#![allow(unused_macros)]
-
-#[cfg(all(feature = "defmt", feature = "log"))]
-compile_error!("You may not enable both `defmt` and `log` features.");
-
-macro_rules! assert {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::assert!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::assert!($($x)*);
-        }
-    };
-}
-
-macro_rules! assert_eq {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::assert_eq!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::assert_eq!($($x)*);
-        }
-    };
-}
-
-macro_rules! assert_ne {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::assert_ne!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::assert_ne!($($x)*);
-        }
-    };
-}
-
-macro_rules! debug_assert {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::debug_assert!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::debug_assert!($($x)*);
-        }
-    };
-}
-
-macro_rules! debug_assert_eq {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::debug_assert_eq!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::debug_assert_eq!($($x)*);
-        }
-    };
-}
-
-macro_rules! debug_assert_ne {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::debug_assert_ne!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::debug_assert_ne!($($x)*);
-        }
-    };
-}
-
-macro_rules! todo {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::todo!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::todo!($($x)*);
-        }
-    };
-}
-
-macro_rules! unreachable {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::unreachable!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::unreachable!($($x)*);
-        }
-    };
-}
-
-macro_rules! panic {
-    ($($x:tt)*) => {
-        {
-            #[cfg(not(feature = "defmt"))]
-            ::core::panic!($($x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::panic!($($x)*);
-        }
-    };
-}
-
-macro_rules! trace {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::trace!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::trace!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-macro_rules! debug {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::debug!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::debug!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-macro_rules! info {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::info!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::info!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-macro_rules! warn {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::warn!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::warn!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-macro_rules! error {
-    ($s:literal $(, $x:expr)* $(,)?) => {
-        {
-            #[cfg(feature = "log")]
-            ::log::error!($s $(, $x)*);
-            #[cfg(feature = "defmt")]
-            ::defmt::error!($s $(, $x)*);
-            #[cfg(not(any(feature = "log", feature="defmt")))]
-            let _ = ($( & $x ),*);
-        }
-    };
-}
-
-#[cfg(feature = "defmt")]
-macro_rules! unwrap {
-    ($($x:tt)*) => {
-        ::defmt::unwrap!($($x)*)
-    };
-}
-
-#[cfg(not(feature = "defmt"))]
-macro_rules! unwrap {
-    ($arg:expr) => {
-        match $crate::fmt::Try::into_result($arg) {
-            ::core::result::Result::Ok(t) => t,
-            ::core::result::Result::Err(e) => {
-                ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
-            }
-        }
-    };
-    ($arg:expr, $($msg:expr),+ $(,)? ) => {
-        match $crate::fmt::Try::into_result($arg) {
-            ::core::result::Result::Ok(t) => t,
-            ::core::result::Result::Err(e) => {
-                ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
-            }
-        }
-    }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub struct NoneError;
-
-pub trait Try {
-    type Ok;
-    type Error;
-    fn into_result(self) -> Result<Self::Ok, Self::Error>;
-}
-
-impl<T> Try for Option<T> {
-    type Ok = T;
-    type Error = NoneError;
-
-    #[inline]
-    fn into_result(self) -> Result<T, NoneError> {
-        self.ok_or(NoneError)
-    }
-}
-
-impl<T, E> Try for Result<T, E> {
-    type Ok = T;
-    type Error = E;
-
-    #[inline]
-    fn into_result(self) -> Self {
-        self
-    }
-}
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml
index 660ecc8cc..aad54dbaf 100644
--- a/embassy-usb/Cargo.toml
+++ b/embassy-usb/Cargo.toml
@@ -11,11 +11,18 @@ target = "thumbv7em-none-eabi"
 
 [features]
 defmt = ["dep:defmt", "embassy-usb-driver/defmt"]
+usbd-hid = ["dep:usbd-hid", "dep:ssmarshal"]
+default = ["usbd-hid"]
 
 [dependencies]
 embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
 embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
+embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
 
 defmt = { version = "0.3", optional = true }
 log = { version = "0.4.14", optional = true }
-heapless = "0.7.10"
\ No newline at end of file
+heapless = "0.7.10"
+
+# for HID
+usbd-hid = { version = "0.6.0", optional = true }
+ssmarshal = { version = "1.0", default-features = false, optional = true }
diff --git a/embassy-usb-serial/src/lib.rs b/embassy-usb/src/class/cdc_acm.rs
similarity index 96%
rename from embassy-usb-serial/src/lib.rs
rename to embassy-usb/src/class/cdc_acm.rs
index 15c2bb0a7..09bb1cc8d 100644
--- a/embassy-usb-serial/src/lib.rs
+++ b/embassy-usb/src/class/cdc_acm.rs
@@ -1,18 +1,13 @@
-#![no_std]
-#![feature(type_alias_impl_trait)]
-
-// This mod MUST go first, so that the others see its macros.
-pub(crate) mod fmt;
-
 use core::cell::Cell;
 use core::mem::{self, MaybeUninit};
 use core::sync::atomic::{AtomicBool, Ordering};
 
 use embassy_sync::blocking_mutex::CriticalSectionMutex;
-use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request};
-use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
-use embassy_usb::types::*;
-use embassy_usb::Builder;
+
+use crate::control::{self, ControlHandler, InResponse, OutResponse, Request};
+use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
+use crate::types::*;
+use crate::Builder;
 
 /// This should be used as `device_class` when building the `UsbDevice`.
 pub const USB_CLASS_CDC: u8 = 0x02;
diff --git a/embassy-usb-ncm/src/lib.rs b/embassy-usb/src/class/cdc_ncm.rs
similarity index 97%
rename from embassy-usb-ncm/src/lib.rs
rename to embassy-usb/src/class/cdc_ncm.rs
index e796af28f..a39b87e9b 100644
--- a/embassy-usb-ncm/src/lib.rs
+++ b/embassy-usb/src/class/cdc_ncm.rs
@@ -1,15 +1,10 @@
-#![no_std]
-
-// This mod MUST go first, so that the others see its macros.
-pub(crate) mod fmt;
-
 use core::intrinsics::copy_nonoverlapping;
 use core::mem::{size_of, MaybeUninit};
 
-use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request};
-use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
-use embassy_usb::types::*;
-use embassy_usb::Builder;
+use crate::control::{self, ControlHandler, InResponse, OutResponse, Request};
+use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
+use crate::types::*;
+use crate::Builder;
 
 /// This should be used as `device_class` when building the `UsbDevice`.
 pub const USB_CLASS_CDC: u8 = 0x02;
diff --git a/embassy-usb-hid/src/lib.rs b/embassy-usb/src/class/hid.rs
similarity index 96%
rename from embassy-usb-hid/src/lib.rs
rename to embassy-usb/src/class/hid.rs
index 8b181aec8..4d1fa995f 100644
--- a/embassy-usb-hid/src/lib.rs
+++ b/embassy-usb/src/class/hid.rs
@@ -1,23 +1,16 @@
-#![no_std]
-#![feature(type_alias_impl_trait)]
-
-//! Implements HID functionality for a usb-device device.
-
-// This mod MUST go first, so that the others see its macros.
-pub(crate) mod fmt;
-
 use core::mem::MaybeUninit;
 use core::ops::Range;
 use core::sync::atomic::{AtomicUsize, Ordering};
 
-use embassy_usb::control::{ControlHandler, InResponse, OutResponse, Request, RequestType};
-use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
-use embassy_usb::Builder;
 #[cfg(feature = "usbd-hid")]
 use ssmarshal::serialize;
 #[cfg(feature = "usbd-hid")]
 use usbd_hid::descriptor::AsInputReport;
 
+use crate::control::{ControlHandler, InResponse, OutResponse, Request, RequestType};
+use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
+use crate::Builder;
+
 const USB_CLASS_HID: u8 = 0x03;
 const USB_SUBCLASS_NONE: u8 = 0x00;
 const USB_PROTOCOL_NONE: u8 = 0x00;
@@ -204,9 +197,9 @@ pub enum ReadError {
     Sync(Range<usize>),
 }
 
-impl From<embassy_usb::driver::EndpointError> for ReadError {
-    fn from(val: embassy_usb::driver::EndpointError) -> Self {
-        use embassy_usb::driver::EndpointError::*;
+impl From<EndpointError> for ReadError {
+    fn from(val: EndpointError) -> Self {
+        use EndpointError::*;
         match val {
             BufferOverflow => ReadError::BufferOverflow,
             Disabled => ReadError::Disabled,
@@ -437,7 +430,7 @@ impl<'d> ControlHandler for Control<'d> {
         }
     }
 
-    fn control_out(&mut self, req: embassy_usb::control::Request, data: &[u8]) -> OutResponse {
+    fn control_out(&mut self, req: Request, data: &[u8]) -> OutResponse {
         trace!("HID control_out {:?} {=[u8]:x}", req, data);
         if let RequestType::Class = req.request_type {
             match req.request {
diff --git a/embassy-usb/src/class/mod.rs b/embassy-usb/src/class/mod.rs
new file mode 100644
index 000000000..af27577a6
--- /dev/null
+++ b/embassy-usb/src/class/mod.rs
@@ -0,0 +1,3 @@
+pub mod cdc_acm;
+pub mod cdc_ncm;
+pub mod hid;
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index e1a99cfae..661b84119 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -7,6 +7,7 @@ pub(crate) mod fmt;
 pub use embassy_usb_driver as driver;
 
 mod builder;
+pub mod class;
 pub mod control;
 pub mod descriptor;
 mod descriptor_reader;
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml
index dbc659cda..a5d340c69 100644
--- a/examples/nrf/Cargo.toml
+++ b/examples/nrf/Cargo.toml
@@ -5,7 +5,7 @@ version = "0.1.0"
 
 [features]
 default = ["nightly"]
-nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embassy-usb-serial", "embassy-usb-hid", "embassy-usb-ncm", "embedded-io/async", "embassy-net"]
+nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net"]
 
 [dependencies]
 embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
@@ -15,9 +15,6 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
 embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
 embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true }
 embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
-embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"], optional = true }
-embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"], optional = true }
-embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"], optional = true }
 embedded-io = "0.3.0"
 
 defmt = "0.3"
diff --git a/examples/nrf/src/bin/usb_ethernet.rs b/examples/nrf/src/bin/usb_ethernet.rs
index 33ca380ff..de93a2b45 100644
--- a/examples/nrf/src/bin/usb_ethernet.rs
+++ b/examples/nrf/src/bin/usb_ethernet.rs
@@ -15,8 +15,8 @@ use embassy_nrf::usb::{Driver, PowerUsb};
 use embassy_nrf::{interrupt, pac, peripherals};
 use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
 use embassy_sync::channel::Channel;
+use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
 use embassy_usb::{Builder, Config, UsbDevice};
-use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
 use embedded_io::asynch::Write;
 use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs
index 4eb7d37c9..76e198719 100644
--- a/examples/nrf/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf/src/bin/usb_hid_keyboard.rs
@@ -14,9 +14,9 @@ use embassy_nrf::usb::{Driver, PowerUsb};
 use embassy_nrf::{interrupt, pac};
 use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
 use embassy_sync::signal::Signal;
+use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
 use embassy_usb::control::OutResponse;
 use embassy_usb::{Builder, Config, DeviceStateHandler};
-use embassy_usb_hid::{HidReaderWriter, ReportId, RequestHandler, State};
 use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
 use {defmt_rtt as _, panic_probe as _};
 
@@ -67,7 +67,7 @@ async fn main(_spawner: Spawner) {
     );
 
     // Create classes on the builder.
-    let config = embassy_usb_hid::Config {
+    let config = embassy_usb::class::hid::Config {
         report_descriptor: KeyboardReport::desc(),
         request_handler: Some(&request_handler),
         poll_ms: 60,
diff --git a/examples/nrf/src/bin/usb_hid_mouse.rs b/examples/nrf/src/bin/usb_hid_mouse.rs
index 65fbda1cf..4916a38d4 100644
--- a/examples/nrf/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf/src/bin/usb_hid_mouse.rs
@@ -10,9 +10,9 @@ use embassy_futures::join::join;
 use embassy_nrf::usb::{Driver, PowerUsb};
 use embassy_nrf::{interrupt, pac};
 use embassy_time::{Duration, Timer};
+use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
 use embassy_usb::control::OutResponse;
 use embassy_usb::{Builder, Config};
-use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State};
 use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
 use {defmt_rtt as _, panic_probe as _};
 
@@ -59,7 +59,7 @@ async fn main(_spawner: Spawner) {
     );
 
     // Create classes on the builder.
-    let config = embassy_usb_hid::Config {
+    let config = embassy_usb::class::hid::Config {
         report_descriptor: MouseReport::desc(),
         request_handler: Some(&request_handler),
         poll_ms: 60,
diff --git a/examples/nrf/src/bin/usb_serial.rs b/examples/nrf/src/bin/usb_serial.rs
index a740b4e0a..7c9c4184b 100644
--- a/examples/nrf/src/bin/usb_serial.rs
+++ b/examples/nrf/src/bin/usb_serial.rs
@@ -9,9 +9,9 @@ use embassy_executor::Spawner;
 use embassy_futures::join::join;
 use embassy_nrf::usb::{Driver, Instance, PowerUsb, UsbSupply};
 use embassy_nrf::{interrupt, pac};
+use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
 use embassy_usb::driver::EndpointError;
 use embassy_usb::{Builder, Config};
-use embassy_usb_serial::{CdcAcmClass, State};
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
diff --git a/examples/nrf/src/bin/usb_serial_multitask.rs b/examples/nrf/src/bin/usb_serial_multitask.rs
index c646c0bbd..93efc2fe6 100644
--- a/examples/nrf/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf/src/bin/usb_serial_multitask.rs
@@ -8,9 +8,9 @@ use defmt::{info, panic, unwrap};
 use embassy_executor::Spawner;
 use embassy_nrf::usb::{Driver, PowerUsb};
 use embassy_nrf::{interrupt, pac, peripherals};
+use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
 use embassy_usb::driver::EndpointError;
 use embassy_usb::{Builder, Config, UsbDevice};
-use embassy_usb_serial::{CdcAcmClass, State};
 use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 24c3cdd67..3c8f923e7 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -10,9 +10,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
 embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver"] }
 embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
-embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] }
 embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
-embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"] }
 embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
 
 defmt = "0.3"
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
index 166ffe175..1057fe7fd 100644
--- a/examples/rp/src/bin/usb_ethernet.rs
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -13,8 +13,8 @@ use embassy_rp::usb::Driver;
 use embassy_rp::{interrupt, peripherals};
 use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
 use embassy_sync::channel::Channel;
+use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
 use embassy_usb::{Builder, Config, UsbDevice};
-use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
 use embedded_io::asynch::Write;
 use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs
index bf92a1636..b7d6493b4 100644
--- a/examples/rp/src/bin/usb_serial.rs
+++ b/examples/rp/src/bin/usb_serial.rs
@@ -7,9 +7,9 @@ use embassy_executor::Spawner;
 use embassy_futures::join::join;
 use embassy_rp::interrupt;
 use embassy_rp::usb::{Driver, Instance};
+use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
 use embassy_usb::driver::EndpointError;
 use embassy_usb::{Builder, Config};
-use embassy_usb_serial::{CdcAcmClass, State};
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index 895e043dd..e6553789a 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -9,7 +9,6 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"]  }
 embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
-embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] }
 embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
 
 defmt = "0.3"
diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs
index a14e728ba..ad92cdeb2 100644
--- a/examples/stm32f1/src/bin/usb_serial.rs
+++ b/examples/stm32f1/src/bin/usb_serial.rs
@@ -10,9 +10,9 @@ use embassy_stm32::time::Hertz;
 use embassy_stm32::usb::{Driver, Instance};
 use embassy_stm32::{interrupt, Config};
 use embassy_time::{Duration, Timer};
+use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
 use embassy_usb::driver::EndpointError;
 use embassy_usb::Builder;
-use embassy_usb_serial::{CdcAcmClass, State};
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index 27f5c260a..f5b0b880c 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -9,8 +9,6 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"]  }
 embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
-embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] }
-embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"] }
 embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
 
 defmt = "0.3"
diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs
index b9fd20e2b..f6d27c860 100644
--- a/examples/stm32f3/src/bin/usb_serial.rs
+++ b/examples/stm32f3/src/bin/usb_serial.rs
@@ -10,9 +10,9 @@ use embassy_stm32::time::mhz;
 use embassy_stm32::usb::{Driver, Instance};
 use embassy_stm32::{interrupt, Config};
 use embassy_time::{Duration, Timer};
+use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
 use embassy_usb::driver::EndpointError;
 use embassy_usb::Builder;
-use embassy_usb_serial::{CdcAcmClass, State};
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index 05945f6bf..9ebab6476 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -11,9 +11,6 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
 embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"]  }
 embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
-embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] }
-embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"] }
-embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"] }
 embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
 embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
 usbd-hid = "0.6.0"
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index c96a83ead..4f36d3f5a 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -15,8 +15,8 @@ use embassy_stm32::usb::Driver;
 use embassy_stm32::{interrupt, Config};
 use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
 use embassy_sync::channel::Channel;
+use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
 use embassy_usb::{Builder, UsbDevice};
-use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
 use embedded_io::asynch::Write;
 use rand_core::RngCore;
 use static_cell::StaticCell;
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs
index fa92ceae3..d38ed7496 100644
--- a/examples/stm32l5/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs
@@ -9,9 +9,9 @@ use embassy_stm32::rcc::*;
 use embassy_stm32::usb::Driver;
 use embassy_stm32::{interrupt, Config};
 use embassy_time::{Duration, Timer};
+use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
 use embassy_usb::control::OutResponse;
 use embassy_usb::Builder;
-use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State};
 use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
 use {defmt_rtt as _, panic_probe as _};
 
@@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) {
     );
 
     // Create classes on the builder.
-    let config = embassy_usb_hid::Config {
+    let config = embassy_usb::class::hid::Config {
         report_descriptor: MouseReport::desc(),
         request_handler: Some(&request_handler),
         poll_ms: 60,
diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs
index 7484dc832..7562a4e96 100644
--- a/examples/stm32l5/src/bin/usb_serial.rs
+++ b/examples/stm32l5/src/bin/usb_serial.rs
@@ -8,9 +8,9 @@ use embassy_futures::join::join;
 use embassy_stm32::rcc::*;
 use embassy_stm32::usb::{Driver, Instance};
 use embassy_stm32::{interrupt, Config};
+use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
 use embassy_usb::driver::EndpointError;
 use embassy_usb::Builder;
-use embassy_usb_serial::{CdcAcmClass, State};
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]