usb: split driver trait to separate crate.

This commit is contained in:
Dario Nieuwenhuis 2022-09-26 12:29:27 +02:00
parent a9efbf18c6
commit 7f7c14b7bc
12 changed files with 189 additions and 165 deletions

View file

@ -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 {

View file

@ -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]

View file

@ -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]

View file

@ -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 }

View file

@ -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.

View file

@ -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 }

View file

@ -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))]

View file

@ -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.

View file

@ -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)]

View file

@ -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))]

View file

@ -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 {

View file

@ -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))]