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