aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb/src
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-09-26 12:29:27 +0200
committerDario Nieuwenhuis <[email protected]>2022-09-26 12:29:27 +0200
commit7f7c14b7bce5b84eb27c8122535a96a6f0e5dd77 (patch)
treec7481fd07b616128718301de7aafea553cc8dd6f /embassy-usb/src
parenta9efbf18c62186de0581ec72cca90a69340a02a3 (diff)
usb: split driver trait to separate crate.
Diffstat (limited to 'embassy-usb/src')
-rw-r--r--embassy-usb/src/builder.rs11
-rw-r--r--embassy-usb/src/control.rs5
-rw-r--r--embassy-usb/src/descriptor.rs7
-rw-r--r--embassy-usb/src/descriptor_reader.rs2
-rw-r--r--embassy-usb/src/driver.rs232
-rw-r--r--embassy-usb/src/lib.rs18
-rw-r--r--embassy-usb/src/types.rs105
7 files changed, 22 insertions, 358 deletions
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 @@
1use heapless::Vec; 1use heapless::Vec;
2 2
3use super::control::ControlHandler; 3use crate::control::ControlHandler;
4use super::descriptor::{BosWriter, DescriptorWriter}; 4use crate::descriptor::{BosWriter, DescriptorWriter};
5use super::driver::{Driver, Endpoint}; 5use crate::driver::{Driver, Endpoint, EndpointType};
6use super::types::*; 6use crate::types::*;
7use super::{DeviceStateHandler, UsbDevice, MAX_INTERFACE_COUNT}; 7use crate::{DeviceStateHandler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
8use crate::{Interface, STRING_INDEX_CUSTOM_START};
9 8
10#[derive(Debug, Copy, Clone)] 9#[derive(Debug, Copy, Clone)]
11#[cfg_attr(feature = "defmt", derive(defmt::Format))] 10#[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 @@
1//! USB control data types. 1//! USB control data types.
2use core::mem; 2use core::mem;
3 3
4use super::types::*; 4use crate::driver::Direction;
5use crate::types::StringIndex;
5 6
6/// Control request type. 7/// Control request type.
7#[repr(u8)] 8#[repr(u8)]
@@ -42,7 +43,7 @@ pub enum Recipient {
42#[cfg_attr(feature = "defmt", derive(defmt::Format))] 43#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43pub struct Request { 44pub struct Request {
44 /// Direction of the request. 45 /// Direction of the request.
45 pub direction: UsbDirection, 46 pub direction: Direction,
46 /// Type of the request. 47 /// Type of the request.
47 pub request_type: RequestType, 48 pub request_type: RequestType,
48 /// Recipient of the request. 49 /// 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 @@
1use super::builder::Config; 1use crate::builder::Config;
2use super::types::*; 2use crate::driver::EndpointInfo;
3use super::CONFIGURATION_VALUE; 3use crate::types::*;
4use crate::CONFIGURATION_VALUE;
4 5
5/// Standard descriptor types 6/// Standard descriptor types
6#[allow(missing_docs)] 7#[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 @@
1use crate::descriptor::descriptor_type; 1use crate::descriptor::descriptor_type;
2use crate::types::EndpointAddress; 2use crate::driver::EndpointAddress;
3 3
4#[derive(Copy, Clone, PartialEq, Eq, Debug)] 4#[derive(Copy, Clone, PartialEq, Eq, Debug)]
5#[cfg_attr(feature = "defmt", derive(defmt::Format))] 5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
diff --git a/embassy-usb/src/driver.rs b/embassy-usb/src/driver.rs
deleted file mode 100644
index 7888f1639..000000000
--- a/embassy-usb/src/driver.rs
+++ /dev/null
@@ -1,232 +0,0 @@
1use core::future::Future;
2
3use super::types::*;
4
5/// Driver for a specific USB peripheral. Implement this to add support for a new hardware
6/// platform.
7pub trait Driver<'a> {
8 type EndpointOut: EndpointOut + 'a;
9 type EndpointIn: EndpointIn + 'a;
10 type ControlPipe: ControlPipe + 'a;
11 type Bus: Bus + 'a;
12
13 /// Allocates an endpoint and specified endpoint parameters. This method is called by the device
14 /// and class implementations to allocate endpoints, and can only be called before
15 /// [`start`](Self::start) is called.
16 ///
17 /// # Arguments
18 ///
19 /// * `ep_addr` - A static endpoint address to allocate. If Some, the implementation should
20 /// attempt to return an endpoint with the specified address. If None, the implementation
21 /// should return the next available one.
22 /// * `max_packet_size` - Maximum packet size in bytes.
23 /// * `interval` - Polling interval parameter for interrupt endpoints.
24 fn alloc_endpoint_out(
25 &mut self,
26 ep_type: EndpointType,
27 max_packet_size: u16,
28 interval: u8,
29 ) -> Result<Self::EndpointOut, EndpointAllocError>;
30
31 fn alloc_endpoint_in(
32 &mut self,
33 ep_type: EndpointType,
34 max_packet_size: u16,
35 interval: u8,
36 ) -> Result<Self::EndpointIn, EndpointAllocError>;
37
38 /// Start operation of the USB device.
39 ///
40 /// This returns the `Bus` and `ControlPipe` instances that are used to operate
41 /// the USB device. Additionally, this makes all the previously allocated endpoints
42 /// start operating.
43 ///
44 /// This consumes the `Driver` instance, so it's no longer possible to allocate more
45 /// endpoints.
46 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe);
47
48 /// Indicates that `set_device_address` must be called before accepting the corresponding
49 /// control transfer, not after.
50 ///
51 /// The default value for this constant is `false`, which corresponds to the USB 2.0 spec, 9.4.6
52 const QUIRK_SET_ADDRESS_BEFORE_STATUS: bool = false;
53}
54
55pub trait Bus {
56 type EnableFuture<'a>: Future<Output = ()> + 'a
57 where
58 Self: 'a;
59 type DisableFuture<'a>: Future<Output = ()> + 'a
60 where
61 Self: 'a;
62 type PollFuture<'a>: Future<Output = Event> + 'a
63 where
64 Self: 'a;
65 type RemoteWakeupFuture<'a>: Future<Output = Result<(), Unsupported>> + 'a
66 where
67 Self: 'a;
68
69 /// Enables the USB peripheral. Soon after enabling the device will be reset, so
70 /// there is no need to perform a USB reset in this method.
71 fn enable(&mut self) -> Self::EnableFuture<'_>;
72
73 /// Disables and powers down the USB peripheral.
74 fn disable(&mut self) -> Self::DisableFuture<'_>;
75
76 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a>;
77
78 /// Sets the device USB address to `addr`.
79 fn set_address(&mut self, addr: u8);
80
81 /// Enables or disables an endpoint.
82 fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool);
83
84 /// Sets or clears the STALL condition for an endpoint. If the endpoint is an OUT endpoint, it
85 /// should be prepared to receive data again. Only used during control transfers.
86 fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool);
87
88 /// Gets whether the STALL condition is set for an endpoint. Only used during control transfers.
89 fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool;
90
91 /// Simulates a disconnect from the USB bus, causing the host to reset and re-enumerate the
92 /// device.
93 ///
94 /// The default implementation just returns `Unsupported`.
95 ///
96 /// # Errors
97 ///
98 /// * [`Unsupported`](crate::driver::Unsupported) - This UsbBus implementation doesn't support
99 /// simulating a disconnect or it has not been enabled at creation time.
100 fn force_reset(&mut self) -> Result<(), Unsupported> {
101 Err(Unsupported)
102 }
103
104 /// Initiates a remote wakeup of the host by the device.
105 ///
106 /// # Errors
107 ///
108 /// * [`Unsupported`](crate::driver::Unsupported) - This UsbBus implementation doesn't support
109 /// remote wakeup or it has not been enabled at creation time.
110 fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_>;
111}
112
113pub trait Endpoint {
114 type WaitEnabledFuture<'a>: Future<Output = ()> + 'a
115 where
116 Self: 'a;
117
118 /// Get the endpoint address
119 fn info(&self) -> &EndpointInfo;
120
121 /// Waits for the endpoint to be enabled.
122 fn wait_enabled(&mut self) -> Self::WaitEnabledFuture<'_>;
123}
124
125pub trait EndpointOut: Endpoint {
126 type ReadFuture<'a>: Future<Output = Result<usize, EndpointError>> + 'a
127 where
128 Self: 'a;
129
130 /// Reads a single packet of data from the endpoint, and returns the actual length of
131 /// the packet.
132 ///
133 /// This should also clear any NAK flags and prepare the endpoint to receive the next packet.
134 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a>;
135}
136
137pub trait ControlPipe {
138 type SetupFuture<'a>: Future<Output = [u8; 8]> + 'a
139 where
140 Self: 'a;
141 type DataOutFuture<'a>: Future<Output = Result<usize, EndpointError>> + 'a
142 where
143 Self: 'a;
144 type DataInFuture<'a>: Future<Output = Result<(), EndpointError>> + 'a
145 where
146 Self: 'a;
147 type AcceptFuture<'a>: Future<Output = ()> + 'a
148 where
149 Self: 'a;
150 type RejectFuture<'a>: Future<Output = ()> + 'a
151 where
152 Self: 'a;
153
154 /// Maximum packet size for the control pipe
155 fn max_packet_size(&self) -> usize;
156
157 /// Reads a single setup packet from the endpoint.
158 fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a>;
159
160 /// Reads a DATA OUT packet into `buf` in response to a control write request.
161 ///
162 /// Must be called after `setup()` for requests with `direction` of `Out`
163 /// and `length` greater than zero.
164 fn data_out<'a>(&'a mut self, buf: &'a mut [u8], first: bool, last: bool) -> Self::DataOutFuture<'a>;
165
166 /// Sends a DATA IN packet with `data` in response to a control read request.
167 ///
168 /// If `last_packet` is true, the STATUS packet will be ACKed following the transfer of `data`.
169 fn data_in<'a>(&'a mut self, data: &'a [u8], first: bool, last: bool) -> Self::DataInFuture<'a>;
170
171 /// Accepts a control request.
172 ///
173 /// Causes the STATUS packet for the current request to be ACKed.
174 fn accept<'a>(&'a mut self) -> Self::AcceptFuture<'a>;
175
176 /// Rejects a control request.
177 ///
178 /// Sets a STALL condition on the pipe to indicate an error.
179 fn reject<'a>(&'a mut self) -> Self::RejectFuture<'a>;
180}
181
182pub trait EndpointIn: Endpoint {
183 type WriteFuture<'a>: Future<Output = Result<(), EndpointError>> + 'a
184 where
185 Self: 'a;
186
187 /// Writes a single packet of data to the endpoint.
188 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a>;
189}
190
191#[derive(Copy, Clone, Eq, PartialEq, Debug)]
192#[cfg_attr(feature = "defmt", derive(defmt::Format))]
193/// Event returned by [`Bus::poll`].
194pub enum Event {
195 /// The USB reset condition has been detected.
196 Reset,
197
198 /// A USB suspend request has been detected or, in the case of self-powered devices, the device
199 /// has been disconnected from the USB bus.
200 Suspend,
201
202 /// A USB resume request has been detected after being suspended or, in the case of self-powered
203 /// devices, the device has been connected to the USB bus.
204 Resume,
205
206 /// The USB power has been detected.
207 PowerDetected,
208
209 /// The USB power has been removed. Not supported by all devices.
210 PowerRemoved,
211}
212
213#[derive(Copy, Clone, Eq, PartialEq, Debug)]
214#[cfg_attr(feature = "defmt", derive(defmt::Format))]
215pub struct EndpointAllocError;
216
217#[derive(Copy, Clone, Eq, PartialEq, Debug)]
218#[cfg_attr(feature = "defmt", derive(defmt::Format))]
219/// Operation is unsupported by the driver.
220pub struct Unsupported;
221
222#[derive(Copy, Clone, Eq, PartialEq, Debug)]
223#[cfg_attr(feature = "defmt", derive(defmt::Format))]
224/// Errors returned by [`EndpointIn::write`] and [`EndpointOut::read`]
225pub enum EndpointError {
226 /// Either the packet to be written is too long to fit in the transmission
227 /// buffer or the received packet is too long to fit in `buf`.
228 BufferOverflow,
229
230 /// The endpoint is disabled.
231 Disabled,
232}
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 @@
4// This mod MUST go first, so that the others see its macros. 4// This mod MUST go first, so that the others see its macros.
5pub(crate) mod fmt; 5pub(crate) mod fmt;
6 6
7pub use embassy_usb_driver as driver;
8
7mod builder; 9mod builder;
8pub mod control; 10pub mod control;
9pub mod descriptor; 11pub mod descriptor;
10mod descriptor_reader; 12mod descriptor_reader;
11pub mod driver;
12pub mod types; 13pub mod types;
13 14
14use embassy_futures::select::{select, Either}; 15use embassy_futures::select::{select, Either};
15use heapless::Vec; 16use heapless::Vec;
16 17
17pub use self::builder::{Builder, Config}; 18pub use crate::builder::{Builder, Config};
18use self::control::*; 19use crate::control::*;
19use self::descriptor::*; 20use crate::descriptor::*;
20use self::driver::{Bus, Driver, Event};
21use self::types::*;
22use crate::descriptor_reader::foreach_endpoint; 21use crate::descriptor_reader::foreach_endpoint;
23use crate::driver::ControlPipe; 22use crate::driver::{Bus, ControlPipe, Direction, Driver, EndpointAddress, Event};
23use crate::types::*;
24 24
25/// The global state of the USB device. 25/// The global state of the USB device.
26/// 26///
@@ -250,8 +250,8 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
250 trace!("control request: {:?}", req); 250 trace!("control request: {:?}", req);
251 251
252 match req.direction { 252 match req.direction {
253 UsbDirection::In => self.handle_control_in(req).await, 253 Direction::In => self.handle_control_in(req).await,
254 UsbDirection::Out => self.handle_control_out(req).await, 254 Direction::Out => self.handle_control_out(req).await,
255 } 255 }
256 256
257 if self.inner.set_address_pending { 257 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 @@
1/// Direction of USB traffic. Note that in the USB standard the direction is always indicated from
2/// the perspective of the host, which is backward for devices, but the standard directions are used
3/// for consistency.
4///
5/// The values of the enum also match the direction bit used in endpoint addresses and control
6/// request types.
7#[repr(u8)]
8#[derive(Copy, Clone, Eq, PartialEq, Debug)]
9#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10pub enum UsbDirection {
11 /// Host to device (OUT)
12 Out = 0x00,
13 /// Device to host (IN)
14 In = 0x80,
15}
16
17impl From<u8> for UsbDirection {
18 fn from(value: u8) -> Self {
19 unsafe { core::mem::transmute(value & 0x80) }
20 }
21}
22
23/// USB endpoint transfer type. The values of this enum can be directly cast into `u8` to get the
24/// transfer bmAttributes transfer type bits.
25#[repr(u8)]
26#[derive(Copy, Clone, Eq, PartialEq, Debug)]
27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28pub enum EndpointType {
29 /// Control endpoint. Used for device management. Only the host can initiate requests. Usually
30 /// used only endpoint 0.
31 Control = 0b00,
32 /// Isochronous endpoint. Used for time-critical unreliable data. Not implemented yet.
33 Isochronous = 0b01,
34 /// Bulk endpoint. Used for large amounts of best-effort reliable data.
35 Bulk = 0b10,
36 /// Interrupt endpoint. Used for small amounts of time-critical reliable data.
37 Interrupt = 0b11,
38}
39
40/// Type-safe endpoint address.
41#[derive(Debug, Clone, Copy, Eq, PartialEq)]
42#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43pub struct EndpointAddress(u8);
44
45impl From<u8> for EndpointAddress {
46 #[inline]
47 fn from(addr: u8) -> EndpointAddress {
48 EndpointAddress(addr)
49 }
50}
51
52impl From<EndpointAddress> for u8 {
53 #[inline]
54 fn from(addr: EndpointAddress) -> u8 {
55 addr.0
56 }
57}
58
59impl EndpointAddress {
60 const INBITS: u8 = UsbDirection::In as u8;
61
62 /// Constructs a new EndpointAddress with the given index and direction.
63 #[inline]
64 pub fn from_parts(index: usize, dir: UsbDirection) -> Self {
65 EndpointAddress(index as u8 | dir as u8)
66 }
67
68 /// Gets the direction part of the address.
69 #[inline]
70 pub fn direction(&self) -> UsbDirection {
71 if (self.0 & Self::INBITS) != 0 {
72 UsbDirection::In
73 } else {
74 UsbDirection::Out
75 }
76 }
77
78 /// Returns true if the direction is IN, otherwise false.
79 #[inline]
80 pub fn is_in(&self) -> bool {
81 (self.0 & Self::INBITS) != 0
82 }
83
84 /// Returns true if the direction is OUT, otherwise false.
85 #[inline]
86 pub fn is_out(&self) -> bool {
87 (self.0 & Self::INBITS) == 0
88 }
89
90 /// Gets the index part of the endpoint address.
91 #[inline]
92 pub fn index(&self) -> usize {
93 (self.0 & !Self::INBITS) as usize
94 }
95}
96
97#[derive(Copy, Clone, Eq, PartialEq, Debug)]
98#[cfg_attr(feature = "defmt", derive(defmt::Format))]
99pub struct EndpointInfo {
100 pub addr: EndpointAddress,
101 pub ep_type: EndpointType,
102 pub max_packet_size: u16,
103 pub interval: u8,
104}
105
106/// A handle for a USB interface that contains its number. 1/// A handle for a USB interface that contains its number.
107#[derive(Copy, Clone, Eq, PartialEq)] 2#[derive(Copy, Clone, Eq, PartialEq)]
108#[cfg_attr(feature = "defmt", derive(defmt::Format))] 3#[cfg_attr(feature = "defmt", derive(defmt::Format))]