aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb-driver/src
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-usb-driver/src')
-rw-r--r--embassy-usb-driver/src/lib.rs337
1 files changed, 337 insertions, 0 deletions
diff --git a/embassy-usb-driver/src/lib.rs b/embassy-usb-driver/src/lib.rs
new file mode 100644
index 000000000..051190a48
--- /dev/null
+++ b/embassy-usb-driver/src/lib.rs
@@ -0,0 +1,337 @@
1#![no_std]
2
3use core::future::Future;
4
5/// Direction of USB traffic. Note that in the USB standard the direction is always indicated from
6/// the perspective of the host, which is backward for devices, but the standard directions are used
7/// for consistency.
8///
9/// The values of the enum also match the direction bit used in endpoint addresses and control
10/// request types.
11#[repr(u8)]
12#[derive(Copy, Clone, Eq, PartialEq, Debug)]
13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
14pub enum Direction {
15 /// Host to device (OUT)
16 Out = 0x00,
17 /// Device to host (IN)
18 In = 0x80,
19}
20
21impl From<u8> for Direction {
22 fn from(value: u8) -> Self {
23 unsafe { core::mem::transmute(value & 0x80) }
24 }
25}
26
27/// USB endpoint transfer type. The values of this enum can be directly cast into `u8` to get the
28/// transfer bmAttributes transfer type bits.
29#[repr(u8)]
30#[derive(Copy, Clone, Eq, PartialEq, Debug)]
31#[cfg_attr(feature = "defmt", derive(defmt::Format))]
32pub enum EndpointType {
33 /// Control endpoint. Used for device management. Only the host can initiate requests. Usually
34 /// used only endpoint 0.
35 Control = 0b00,
36 /// Isochronous endpoint. Used for time-critical unreliable data. Not implemented yet.
37 Isochronous = 0b01,
38 /// Bulk endpoint. Used for large amounts of best-effort reliable data.
39 Bulk = 0b10,
40 /// Interrupt endpoint. Used for small amounts of time-critical reliable data.
41 Interrupt = 0b11,
42}
43
44/// Type-safe endpoint address.
45#[derive(Debug, Clone, Copy, Eq, PartialEq)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub struct EndpointAddress(u8);
48
49impl From<u8> for EndpointAddress {
50 #[inline]
51 fn from(addr: u8) -> EndpointAddress {
52 EndpointAddress(addr)
53 }
54}
55
56impl From<EndpointAddress> for u8 {
57 #[inline]
58 fn from(addr: EndpointAddress) -> u8 {
59 addr.0
60 }
61}
62
63impl EndpointAddress {
64 const INBITS: u8 = Direction::In as u8;
65
66 /// Constructs a new EndpointAddress with the given index and direction.
67 #[inline]
68 pub fn from_parts(index: usize, dir: Direction) -> Self {
69 EndpointAddress(index as u8 | dir as u8)
70 }
71
72 /// Gets the direction part of the address.
73 #[inline]
74 pub fn direction(&self) -> Direction {
75 if (self.0 & Self::INBITS) != 0 {
76 Direction::In
77 } else {
78 Direction::Out
79 }
80 }
81
82 /// Returns true if the direction is IN, otherwise false.
83 #[inline]
84 pub fn is_in(&self) -> bool {
85 (self.0 & Self::INBITS) != 0
86 }
87
88 /// Returns true if the direction is OUT, otherwise false.
89 #[inline]
90 pub fn is_out(&self) -> bool {
91 (self.0 & Self::INBITS) == 0
92 }
93
94 /// Gets the index part of the endpoint address.
95 #[inline]
96 pub fn index(&self) -> usize {
97 (self.0 & !Self::INBITS) as usize
98 }
99}
100
101#[derive(Copy, Clone, Eq, PartialEq, Debug)]
102#[cfg_attr(feature = "defmt", derive(defmt::Format))]
103pub struct EndpointInfo {
104 pub addr: EndpointAddress,
105 pub ep_type: EndpointType,
106 pub max_packet_size: u16,
107 pub interval: u8,
108}
109
110/// Driver for a specific USB peripheral. Implement this to add support for a new hardware
111/// platform.
112pub trait Driver<'a> {
113 type EndpointOut: EndpointOut + 'a;
114 type EndpointIn: EndpointIn + 'a;
115 type ControlPipe: ControlPipe + 'a;
116 type Bus: Bus + 'a;
117
118 /// Allocates an endpoint and specified endpoint parameters. This method is called by the device
119 /// and class implementations to allocate endpoints, and can only be called before
120 /// [`start`](Self::start) is called.
121 ///
122 /// # Arguments
123 ///
124 /// * `ep_addr` - A static endpoint address to allocate. If Some, the implementation should
125 /// attempt to return an endpoint with the specified address. If None, the implementation
126 /// should return the next available one.
127 /// * `max_packet_size` - Maximum packet size in bytes.
128 /// * `interval` - Polling interval parameter for interrupt endpoints.
129 fn alloc_endpoint_out(
130 &mut self,
131 ep_type: EndpointType,
132 max_packet_size: u16,
133 interval: u8,
134 ) -> Result<Self::EndpointOut, EndpointAllocError>;
135
136 fn alloc_endpoint_in(
137 &mut self,
138 ep_type: EndpointType,
139 max_packet_size: u16,
140 interval: u8,
141 ) -> Result<Self::EndpointIn, EndpointAllocError>;
142
143 /// Start operation of the USB device.
144 ///
145 /// This returns the `Bus` and `ControlPipe` instances that are used to operate
146 /// the USB device. Additionally, this makes all the previously allocated endpoints
147 /// start operating.
148 ///
149 /// This consumes the `Driver` instance, so it's no longer possible to allocate more
150 /// endpoints.
151 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe);
152
153 /// Indicates that `set_device_address` must be called before accepting the corresponding
154 /// control transfer, not after.
155 ///
156 /// The default value for this constant is `false`, which corresponds to the USB 2.0 spec, 9.4.6
157 const QUIRK_SET_ADDRESS_BEFORE_STATUS: bool = false;
158}
159
160pub trait Bus {
161 type EnableFuture<'a>: Future<Output = ()> + 'a
162 where
163 Self: 'a;
164 type DisableFuture<'a>: Future<Output = ()> + 'a
165 where
166 Self: 'a;
167 type PollFuture<'a>: Future<Output = Event> + 'a
168 where
169 Self: 'a;
170 type RemoteWakeupFuture<'a>: Future<Output = Result<(), Unsupported>> + 'a
171 where
172 Self: 'a;
173
174 /// Enables the USB peripheral. Soon after enabling the device will be reset, so
175 /// there is no need to perform a USB reset in this method.
176 fn enable(&mut self) -> Self::EnableFuture<'_>;
177
178 /// Disables and powers down the USB peripheral.
179 fn disable(&mut self) -> Self::DisableFuture<'_>;
180
181 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a>;
182
183 /// Sets the device USB address to `addr`.
184 fn set_address(&mut self, addr: u8);
185
186 /// Enables or disables an endpoint.
187 fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool);
188
189 /// Sets or clears the STALL condition for an endpoint. If the endpoint is an OUT endpoint, it
190 /// should be prepared to receive data again. Only used during control transfers.
191 fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool);
192
193 /// Gets whether the STALL condition is set for an endpoint. Only used during control transfers.
194 fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool;
195
196 /// Simulates a disconnect from the USB bus, causing the host to reset and re-enumerate the
197 /// device.
198 ///
199 /// The default implementation just returns `Unsupported`.
200 ///
201 /// # Errors
202 ///
203 /// * [`Unsupported`](crate::driver::Unsupported) - This UsbBus implementation doesn't support
204 /// simulating a disconnect or it has not been enabled at creation time.
205 fn force_reset(&mut self) -> Result<(), Unsupported> {
206 Err(Unsupported)
207 }
208
209 /// Initiates a remote wakeup of the host by the device.
210 ///
211 /// # Errors
212 ///
213 /// * [`Unsupported`](crate::driver::Unsupported) - This UsbBus implementation doesn't support
214 /// remote wakeup or it has not been enabled at creation time.
215 fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_>;
216}
217
218pub trait Endpoint {
219 type WaitEnabledFuture<'a>: Future<Output = ()> + 'a
220 where
221 Self: 'a;
222
223 /// Get the endpoint address
224 fn info(&self) -> &EndpointInfo;
225
226 /// Waits for the endpoint to be enabled.
227 fn wait_enabled(&mut self) -> Self::WaitEnabledFuture<'_>;
228}
229
230pub trait EndpointOut: Endpoint {
231 type ReadFuture<'a>: Future<Output = Result<usize, EndpointError>> + 'a
232 where
233 Self: 'a;
234
235 /// Reads a single packet of data from the endpoint, and returns the actual length of
236 /// the packet.
237 ///
238 /// This should also clear any NAK flags and prepare the endpoint to receive the next packet.
239 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a>;
240}
241
242pub trait ControlPipe {
243 type SetupFuture<'a>: Future<Output = [u8; 8]> + 'a
244 where
245 Self: 'a;
246 type DataOutFuture<'a>: Future<Output = Result<usize, EndpointError>> + 'a
247 where
248 Self: 'a;
249 type DataInFuture<'a>: Future<Output = Result<(), EndpointError>> + 'a
250 where
251 Self: 'a;
252 type AcceptFuture<'a>: Future<Output = ()> + 'a
253 where
254 Self: 'a;
255 type RejectFuture<'a>: Future<Output = ()> + 'a
256 where
257 Self: 'a;
258
259 /// Maximum packet size for the control pipe
260 fn max_packet_size(&self) -> usize;
261
262 /// Reads a single setup packet from the endpoint.
263 fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a>;
264
265 /// Reads a DATA OUT packet into `buf` in response to a control write request.
266 ///
267 /// Must be called after `setup()` for requests with `direction` of `Out`
268 /// and `length` greater than zero.
269 fn data_out<'a>(&'a mut self, buf: &'a mut [u8], first: bool, last: bool) -> Self::DataOutFuture<'a>;
270
271 /// Sends a DATA IN packet with `data` in response to a control read request.
272 ///
273 /// If `last_packet` is true, the STATUS packet will be ACKed following the transfer of `data`.
274 fn data_in<'a>(&'a mut self, data: &'a [u8], first: bool, last: bool) -> Self::DataInFuture<'a>;
275
276 /// Accepts a control request.
277 ///
278 /// Causes the STATUS packet for the current request to be ACKed.
279 fn accept<'a>(&'a mut self) -> Self::AcceptFuture<'a>;
280
281 /// Rejects a control request.
282 ///
283 /// Sets a STALL condition on the pipe to indicate an error.
284 fn reject<'a>(&'a mut self) -> Self::RejectFuture<'a>;
285}
286
287pub trait EndpointIn: Endpoint {
288 type WriteFuture<'a>: Future<Output = Result<(), EndpointError>> + 'a
289 where
290 Self: 'a;
291
292 /// Writes a single packet of data to the endpoint.
293 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a>;
294}
295
296#[derive(Copy, Clone, Eq, PartialEq, Debug)]
297#[cfg_attr(feature = "defmt", derive(defmt::Format))]
298/// Event returned by [`Bus::poll`].
299pub enum Event {
300 /// The USB reset condition has been detected.
301 Reset,
302
303 /// A USB suspend request has been detected or, in the case of self-powered devices, the device
304 /// has been disconnected from the USB bus.
305 Suspend,
306
307 /// A USB resume request has been detected after being suspended or, in the case of self-powered
308 /// devices, the device has been connected to the USB bus.
309 Resume,
310
311 /// The USB power has been detected.
312 PowerDetected,
313
314 /// The USB power has been removed. Not supported by all devices.
315 PowerRemoved,
316}
317
318#[derive(Copy, Clone, Eq, PartialEq, Debug)]
319#[cfg_attr(feature = "defmt", derive(defmt::Format))]
320pub struct EndpointAllocError;
321
322#[derive(Copy, Clone, Eq, PartialEq, Debug)]
323#[cfg_attr(feature = "defmt", derive(defmt::Format))]
324/// Operation is unsupported by the driver.
325pub struct Unsupported;
326
327#[derive(Copy, Clone, Eq, PartialEq, Debug)]
328#[cfg_attr(feature = "defmt", derive(defmt::Format))]
329/// Errors returned by [`EndpointIn::write`] and [`EndpointOut::read`]
330pub enum EndpointError {
331 /// Either the packet to be written is too long to fit in the transmission
332 /// buffer or the received packet is too long to fit in `buf`.
333 BufferOverflow,
334
335 /// The endpoint is disabled.
336 Disabled,
337}