usb_device/bus.rs
1use crate::endpoint::{
2 Endpoint, EndpointAddress, EndpointDirection, EndpointType, IsochronousSynchronizationType,
3 IsochronousUsageType,
4};
5use crate::{Result, UsbDirection, UsbError};
6use core::cell::RefCell;
7use core::mem;
8use core::ptr;
9use portable_atomic::{AtomicPtr, Ordering};
10
11/// A trait for device-specific USB peripherals. Implement this to add support for a new hardware
12/// platform.
13///
14/// The UsbBus is shared by reference between the global [`UsbDevice`](crate::device::UsbDevice) as
15/// well as [`UsbClass`](crate::class::UsbClass)es, and therefore any required mutability must be
16/// implemented using interior mutability. Most operations that may mutate the bus object itself
17/// take place before [`enable`](UsbBus::enable) is called. After the bus is enabled, in practice
18/// most access won't mutate the object itself but only endpoint-specific registers and buffers, the
19/// access to which is mostly arbitrated by endpoint handles.
20pub trait UsbBus: Sync + Sized {
21 /// Allocates an endpoint and specified endpoint parameters. This method is called by the device
22 /// and class implementations to allocate endpoints, and can only be called before
23 /// [`enable`](UsbBus::enable) is called.
24 ///
25 /// # Arguments
26 ///
27 /// * `ep_dir` - The endpoint direction.
28 /// * `ep_addr` - A static endpoint address to allocate. If Some, the implementation should
29 /// attempt to return an endpoint with the specified address. If None, the implementation
30 /// should return the next available one.
31 /// * `max_packet_size` - Maximum packet size in bytes.
32 /// * `interval` - Polling interval parameter for interrupt endpoints.
33 ///
34 /// # Errors
35 ///
36 /// * [`EndpointOverflow`](crate::UsbError::EndpointOverflow) - Available total number of
37 /// endpoints, endpoints of the specified type, or endpoind packet memory has been exhausted.
38 /// This is generally caused when a user tries to add too many classes to a composite device.
39 /// * [`InvalidEndpoint`](crate::UsbError::InvalidEndpoint) - A specific `ep_addr` was specified
40 /// but the endpoint in question has already been allocated.
41 fn alloc_ep(
42 &mut self,
43 ep_dir: UsbDirection,
44 ep_addr: Option<EndpointAddress>,
45 ep_type: EndpointType,
46 max_packet_size: u16,
47 interval: u8,
48 ) -> Result<EndpointAddress>;
49
50 /// Enables and initializes the USB peripheral. Soon after enabling the device will be reset, so
51 /// there is no need to perform a USB reset in this method.
52 fn enable(&mut self);
53
54 /// Called when the host resets the device. This will be soon called after
55 /// [`poll`](crate::device::UsbDevice::poll) returns [`PollResult::Reset`]. This method should
56 /// reset the state of all endpoints and peripheral flags back to a state suitable for
57 /// enumeration, as well as ensure that all endpoints previously allocated with alloc_ep are
58 /// initialized as specified.
59 fn reset(&self);
60
61 /// Sets the device USB address to `addr`.
62 fn set_device_address(&self, addr: u8);
63
64 /// Writes a single packet of data to the specified endpoint and returns number of bytes
65 /// actually written.
66 ///
67 /// The only reason for a short write is if the caller passes a slice larger than the amount of
68 /// memory allocated earlier, and this is generally an error in the class implementation.
69 ///
70 /// # Errors
71 ///
72 /// * [`InvalidEndpoint`](crate::UsbError::InvalidEndpoint) - The `ep_addr` does not point to a
73 /// valid endpoint that was previously allocated with [`UsbBus::alloc_ep`].
74 /// * [`WouldBlock`](crate::UsbError::WouldBlock) - A previously written packet is still pending
75 /// to be sent.
76 /// * [`BufferOverflow`](crate::UsbError::BufferOverflow) - The packet is too long to fit in the
77 /// transmission buffer. This is generally an error in the class implementation, because the
78 /// class shouldn't provide more data than the `max_packet_size` it specified when allocating
79 /// the endpoint.
80 ///
81 /// Implementations may also return other errors if applicable.
82 fn write(&self, ep_addr: EndpointAddress, buf: &[u8]) -> Result<usize>;
83
84 /// Reads a single packet of data from the specified endpoint and returns the actual length of
85 /// the packet.
86 ///
87 /// This should also clear any NAK flags and prepare the endpoint to receive the next packet.
88 ///
89 /// # Errors
90 ///
91 /// * [`InvalidEndpoint`](crate::UsbError::InvalidEndpoint) - The `ep_addr` does not point to a
92 /// valid endpoint that was previously allocated with [`UsbBus::alloc_ep`].
93 /// * [`WouldBlock`](crate::UsbError::WouldBlock) - There is no packet to be read. Note that
94 /// this is different from a received zero-length packet, which is valid in USB. A zero-length
95 /// packet will return `Ok(0)`.
96 /// * [`BufferOverflow`](crate::UsbError::BufferOverflow) - The received packet is too long to
97 /// fit in `buf`. This is generally an error in the class implementation, because the class
98 /// should use a buffer that is large enough for the `max_packet_size` it specified when
99 /// allocating the endpoint.
100 ///
101 /// Implementations may also return other errors if applicable.
102 fn read(&self, ep_addr: EndpointAddress, buf: &mut [u8]) -> Result<usize>;
103
104 /// Sets or clears the STALL condition for an endpoint. If the endpoint is an OUT endpoint, it
105 /// should be prepared to receive data again.
106 fn set_stalled(&self, ep_addr: EndpointAddress, stalled: bool);
107
108 /// Gets whether the STALL condition is set for an endpoint.
109 fn is_stalled(&self, ep_addr: EndpointAddress) -> bool;
110
111 /// Causes the USB peripheral to enter USB suspend mode, lowering power consumption and
112 /// preparing to detect a USB wakeup event. This will be called after
113 /// [`poll`](crate::device::UsbDevice::poll) returns [`PollResult::Suspend`]. The device will
114 /// continue be polled, and it shall return a value other than `Suspend` from `poll` when it no
115 /// longer detects the suspend condition.
116 fn suspend(&self);
117
118 /// Resumes from suspend mode. This may only be called after the peripheral has been previously
119 /// suspended.
120 fn resume(&self);
121
122 /// Gets information about events and incoming data. Usually called in a loop or from an
123 /// interrupt handler. See the [`PollResult`] struct for more information.
124 fn poll(&self) -> PollResult;
125
126 /// Simulates a disconnect from the USB bus, causing the host to reset and re-enumerate the
127 /// device.
128 ///
129 /// The default implementation just returns `Unsupported`.
130 ///
131 /// # Errors
132 ///
133 /// * [`Unsupported`](crate::UsbError::Unsupported) - This UsbBus implementation doesn't support
134 /// simulating a disconnect or it has not been enabled at creation time.
135 fn force_reset(&self) -> Result<()> {
136 Err(UsbError::Unsupported)
137 }
138
139 /// Indicates that `set_device_address` must be called before accepting the corresponding
140 /// control transfer, not after.
141 ///
142 /// The default value for this constant is `false`, which corresponds to the USB 2.0 spec, 9.4.6
143 const QUIRK_SET_ADDRESS_BEFORE_STATUS: bool = false;
144}
145
146struct AllocatorState {
147 next_interface_number: u8,
148 next_string_index: u8,
149}
150
151/// Helper type used for UsbBus resource allocation and initialization.
152pub struct UsbBusAllocator<B: UsbBus> {
153 bus: RefCell<B>,
154 bus_ptr: AtomicPtr<B>,
155 state: RefCell<AllocatorState>,
156}
157
158impl<B: UsbBus> UsbBusAllocator<B> {
159 /// Creates a new [`UsbBusAllocator`] that wraps the provided [`UsbBus`]. Usually only called by
160 /// USB driver implementations.
161 pub fn new(bus: B) -> UsbBusAllocator<B> {
162 UsbBusAllocator {
163 bus: RefCell::new(bus),
164 bus_ptr: AtomicPtr::new(ptr::null_mut()),
165 state: RefCell::new(AllocatorState {
166 next_interface_number: 0,
167 next_string_index: 4,
168 }),
169 }
170 }
171
172 pub(crate) fn freeze(&self) -> &B {
173 // Prevent further allocation by borrowing the allocation state permanently.
174 mem::forget(self.state.borrow_mut());
175
176 // Enable the USB bus
177 self.bus.borrow_mut().enable();
178
179 // An AtomicPtr is used for the reference from Endpoints to UsbBus, in order to ensure that
180 // Endpoints stay Sync (if the Endpoints had a reference to a RefCell, they would not be
181 // Sync) Set the pointer used by the Endpoints to access the UsbBus to point to the UsbBus
182 // in the RefCell.
183 let mut bus_ref = self.bus.borrow_mut();
184 let bus_ptr_v = &mut *bus_ref as *mut B;
185 self.bus_ptr.store(bus_ptr_v, Ordering::SeqCst);
186
187 // And then leave the RefCell borrowed permanently so that it cannot be borrowed mutably
188 // anymore.
189 mem::forget(bus_ref);
190
191 // Return the reference to the UsbBus, for use by UsbDevice.
192 unsafe { &*bus_ptr_v }
193 }
194
195 /// Allocates a new interface number.
196 pub fn interface(&self) -> InterfaceNumber {
197 let mut state = self.state.borrow_mut();
198 let number = state.next_interface_number;
199 state.next_interface_number += 1;
200
201 InterfaceNumber(number)
202 }
203
204 /// Allocates a new string index.
205 pub fn string(&self) -> StringIndex {
206 let mut state = self.state.borrow_mut();
207 let index = state.next_string_index;
208 state.next_string_index += 1;
209
210 StringIndex(index)
211 }
212
213 /// Allocates an endpoint with the specified direction and address.
214 ///
215 /// This directly delegates to [`UsbBus::alloc_ep`], so see that method for details. In most
216 /// cases classes should call the endpoint type specific methods instead.
217 pub fn alloc<D: EndpointDirection>(
218 &self,
219 ep_addr: Option<EndpointAddress>,
220 ep_type: EndpointType,
221 max_packet_size: u16,
222 interval: u8,
223 ) -> Result<Endpoint<'_, B, D>> {
224 self.bus
225 .borrow_mut()
226 .alloc_ep(D::DIRECTION, ep_addr, ep_type, max_packet_size, interval)
227 .map(|a| Endpoint::new(&self.bus_ptr, a, ep_type, max_packet_size, interval))
228 }
229
230 /// Allocates a control endpoint.
231 ///
232 /// This crate implements the control state machine only for endpoint 0. If classes want to
233 /// support control requests in other endpoints, the state machine must be implemented manually.
234 /// This should rarely be needed by classes.
235 ///
236 /// # Arguments
237 ///
238 /// * `max_packet_size` - Maximum packet size in bytes. Must be one of 8, 16, 32 or 64.
239 ///
240 /// # Panics
241 ///
242 /// Panics if endpoint allocation fails, because running out of endpoints or memory is not
243 /// feasibly recoverable.
244 #[inline]
245 pub fn control<D: EndpointDirection>(&self, max_packet_size: u16) -> Endpoint<'_, B, D> {
246 self.alloc(None, EndpointType::Control, max_packet_size, 0)
247 .expect("alloc_ep failed")
248 }
249
250 /// Allocates an isochronous endpoint.
251 ///
252 /// # Arguments
253 ///
254 /// * `synchronization` - Type of synchronization used by the endpoint
255 /// * `usage` - Whether the endpoint is data, explicit feedback, or data+implicit feedback
256 /// * `payload_size` - Payload size in bytes.
257 /// * `interval` - Interval for polling, expressed in frames/microframes.
258 ///
259 /// See USB 2.0 section 9.6.6.
260 ///
261 /// # Panics
262 ///
263 /// Panics if endpoint allocation fails, because running out of endpoints or memory is not
264 /// feasibly recoverable.
265 #[inline]
266 pub fn isochronous<D: EndpointDirection>(
267 &self,
268 synchronization: IsochronousSynchronizationType,
269 usage: IsochronousUsageType,
270 payload_size: u16,
271 interval: u8,
272 ) -> Endpoint<'_, B, D> {
273 self.alloc(
274 None,
275 EndpointType::Isochronous {
276 synchronization,
277 usage,
278 },
279 payload_size,
280 interval,
281 )
282 .expect("alloc_ep failed")
283 }
284
285 /// Allocates a bulk endpoint.
286 ///
287 /// # Arguments
288 ///
289 /// * `max_packet_size` - Maximum packet size in bytes. Must be one of 8, 16, 32 or 64.
290 ///
291 /// # Panics
292 ///
293 /// Panics if endpoint allocation fails, because running out of endpoints or memory is not
294 /// feasibly recoverable.
295 #[inline]
296 pub fn bulk<D: EndpointDirection>(&self, max_packet_size: u16) -> Endpoint<'_, B, D> {
297 self.alloc(None, EndpointType::Bulk, max_packet_size, 0)
298 .expect("alloc_ep failed")
299 }
300
301 /// Allocates an interrupt endpoint.
302 ///
303 /// * `max_packet_size` - Maximum packet size in bytes. Cannot exceed 64 bytes.
304 /// * `interval` - Polling interval.
305 ///
306 /// # Panics
307 ///
308 /// Panics if endpoint allocation fails, because running out of endpoints or memory is not
309 /// feasibly recoverable.
310 #[inline]
311 pub fn interrupt<D: EndpointDirection>(
312 &self,
313 max_packet_size: u16,
314 interval: u8,
315 ) -> Endpoint<'_, B, D> {
316 self.alloc(None, EndpointType::Interrupt, max_packet_size, interval)
317 .expect("alloc_ep failed")
318 }
319}
320
321/// A handle for a USB interface that contains its number.
322#[derive(Copy, Clone, Eq, PartialEq)]
323#[cfg_attr(feature = "defmt", derive(defmt::Format))]
324pub struct InterfaceNumber(pub(crate) u8);
325
326impl From<InterfaceNumber> for u8 {
327 fn from(n: InterfaceNumber) -> u8 {
328 n.0
329 }
330}
331
332/// A handle for a USB string descriptor that contains its index.
333#[derive(Copy, Clone, Eq, PartialEq)]
334#[cfg_attr(feature = "defmt", derive(defmt::Format))]
335pub struct StringIndex(u8);
336
337impl StringIndex {
338 pub(crate) fn new(index: u8) -> StringIndex {
339 StringIndex(index)
340 }
341}
342
343impl From<StringIndex> for u8 {
344 fn from(i: StringIndex) -> u8 {
345 i.0
346 }
347}
348
349/// Event and incoming packet information returned by [`UsbBus::poll`].
350pub enum PollResult {
351 /// No events or packets to report.
352 None,
353
354 /// The USB reset condition has been detected.
355 Reset,
356
357 /// USB packets have been received or sent. Each data field is a bit-field where the least
358 /// significant bit represents endpoint 0 etc., and a set bit signifies the event has occurred
359 /// for the corresponding endpoint.
360 Data {
361 /// An OUT packet has been received. This event should continue to be reported until the
362 /// packet is read.
363 ep_out: u16,
364
365 /// An IN packet has finished transmitting. This event should only be reported once for each
366 /// completed transfer.
367 ep_in_complete: u16,
368
369 /// A SETUP packet has been received. This event should continue to be reported until the
370 /// packet is read. The corresponding bit in `ep_out` may also be set but is ignored.
371 ep_setup: u16,
372 },
373
374 /// A USB suspend request has been detected or, in the case of self-powered devices, the device
375 /// has been disconnected from the USB bus.
376 Suspend,
377
378 /// A USB resume request has been detected after being suspended or, in the case of self-powered
379 /// devices, the device has been connected to the USB bus.
380 Resume,
381}