Merge pull request #701 from alexmoon/async-usb-stack

Async-ify Driver::enable and UsbDeviceBuilder::build
This commit is contained in:
Dario Nieuwenhuis 2022-04-07 19:55:00 +02:00 committed by GitHub
commit d2494486d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 59 additions and 45 deletions

View File

@ -140,6 +140,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
type EndpointIn = Endpoint<'d, T, In>; type EndpointIn = Endpoint<'d, T, In>;
type ControlPipe = ControlPipe<'d, T>; type ControlPipe = ControlPipe<'d, T>;
type Bus = Bus<'d, T>; type Bus = Bus<'d, T>;
type EnableFuture = impl Future<Output = Self::Bus> + 'd;
fn alloc_endpoint_in( fn alloc_endpoint_in(
&mut self, &mut self,
@ -191,35 +192,46 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
}) })
} }
fn enable(self) -> Self::Bus { fn enable(self) -> Self::EnableFuture {
let regs = T::regs(); async move {
let regs = T::regs();
errata::pre_enable(); errata::pre_enable();
regs.enable.write(|w| w.enable().enabled()); regs.enable.write(|w| w.enable().enabled());
// Wait until the peripheral is ready. // Wait until the peripheral is ready.
while !regs.eventcause.read().ready().is_ready() {} regs.intenset.write(|w| w.usbevent().set_bit());
regs.eventcause.write(|w| w.ready().set_bit()); // Write 1 to clear. poll_fn(|cx| {
BUS_WAKER.register(cx.waker());
if regs.eventcause.read().ready().is_ready() {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
regs.eventcause.write(|w| w.ready().set_bit()); // Write 1 to clear.
errata::post_enable(); errata::post_enable();
unsafe { NVIC::unmask(pac::Interrupt::USBD) }; unsafe { NVIC::unmask(pac::Interrupt::USBD) };
regs.intenset.write(|w| { regs.intenset.write(|w| {
w.usbreset().set_bit(); w.usbreset().set_bit();
w.usbevent().set_bit(); w.usbevent().set_bit();
w.epdata().set_bit(); w.epdata().set_bit();
w w
}); });
// Enable the USB pullup, allowing enumeration. // Enable the USB pullup, allowing enumeration.
regs.usbpullup.write(|w| w.connect().enabled()); regs.usbpullup.write(|w| w.connect().enabled());
trace!("enabled"); trace!("enabled");
Bus { Bus {
phantom: PhantomData, phantom: PhantomData,
alloc_in: self.alloc_in, alloc_in: self.alloc_in,
alloc_out: self.alloc_out, alloc_out: self.alloc_out,
}
} }
} }
} }
@ -650,14 +662,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
poll_fn(|cx| { poll_fn(|cx| {
EP0_WAKER.register(cx.waker()); EP0_WAKER.register(cx.waker());
let regs = T::regs(); let regs = T::regs();
if regs.events_usbreset.read().bits() != 0 { if regs.events_ep0datadone.read().bits() != 0 {
Poll::Ready(Ok(()))
} else if regs.events_usbreset.read().bits() != 0 {
trace!("aborted control data_out: usb reset"); trace!("aborted control data_out: usb reset");
Poll::Ready(Err(ReadError::Disabled)) Poll::Ready(Err(ReadError::Disabled))
} else if regs.events_ep0setup.read().bits() != 0 { } else if regs.events_ep0setup.read().bits() != 0 {
trace!("aborted control data_out: received another SETUP"); trace!("aborted control data_out: received another SETUP");
Poll::Ready(Err(ReadError::Disabled)) Poll::Ready(Err(ReadError::Disabled))
} else if regs.events_ep0datadone.read().bits() != 0 {
Poll::Ready(Ok(()))
} else { } else {
Poll::Pending Poll::Pending
} }
@ -689,14 +701,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
cx.waker().wake_by_ref(); cx.waker().wake_by_ref();
EP0_WAKER.register(cx.waker()); EP0_WAKER.register(cx.waker());
let regs = T::regs(); let regs = T::regs();
if regs.events_usbreset.read().bits() != 0 { if regs.events_ep0datadone.read().bits() != 0 {
Poll::Ready(Ok(()))
} else if regs.events_usbreset.read().bits() != 0 {
trace!("aborted control data_in: usb reset"); trace!("aborted control data_in: usb reset");
Poll::Ready(Err(WriteError::Disabled)) Poll::Ready(Err(WriteError::Disabled))
} else if regs.events_ep0setup.read().bits() != 0 { } else if regs.events_ep0setup.read().bits() != 0 {
trace!("aborted control data_in: received another SETUP"); trace!("aborted control data_in: received another SETUP");
Poll::Ready(Err(WriteError::Disabled)) Poll::Ready(Err(WriteError::Disabled))
} else if regs.events_ep0datadone.read().bits() != 0 {
Poll::Ready(Ok(()))
} else { } else {
Poll::Pending Poll::Pending
} }

View File

@ -122,7 +122,7 @@ pub struct UsbDeviceBuilder<'d, D: Driver<'d>> {
interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>, interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>,
control_buf: &'d mut [u8], control_buf: &'d mut [u8],
bus: D, driver: D,
next_interface_number: u8, next_interface_number: u8,
next_string_index: u8, next_string_index: u8,
@ -139,7 +139,7 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
/// large enough for the length of the largest control request (in or out) /// large enough for the length of the largest control request (in or out)
/// anticipated by any class added to the device. /// anticipated by any class added to the device.
pub fn new( pub fn new(
bus: D, driver: D,
config: Config<'d>, config: Config<'d>,
device_descriptor_buf: &'d mut [u8], device_descriptor_buf: &'d mut [u8],
config_descriptor_buf: &'d mut [u8], config_descriptor_buf: &'d mut [u8],
@ -173,7 +173,7 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
bos_descriptor.bos(); bos_descriptor.bos();
UsbDeviceBuilder { UsbDeviceBuilder {
bus, driver,
config, config,
interfaces: Vec::new(), interfaces: Vec::new(),
control_buf, control_buf,
@ -187,12 +187,12 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
} }
/// Creates the [`UsbDevice`] instance with the configuration in this builder. /// Creates the [`UsbDevice`] instance with the configuration in this builder.
pub fn build(mut self) -> UsbDevice<'d, D> { pub async fn build(mut self) -> UsbDevice<'d, D> {
self.config_descriptor.end_configuration(); self.config_descriptor.end_configuration();
self.bos_descriptor.end_bos(); self.bos_descriptor.end_bos();
UsbDevice::build( UsbDevice::build(
self.bus, self.driver,
self.config, self.config,
self.device_descriptor.into_buf(), self.device_descriptor.into_buf(),
self.config_descriptor.into_buf(), self.config_descriptor.into_buf(),
@ -200,6 +200,7 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
self.interfaces, self.interfaces,
self.control_buf, self.control_buf,
) )
.await
} }
/// Allocates a new interface number. /// Allocates a new interface number.
@ -251,7 +252,7 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
max_packet_size: u16, max_packet_size: u16,
interval: u8, interval: u8,
) -> Result<D::EndpointIn, EndpointAllocError> { ) -> Result<D::EndpointIn, EndpointAllocError> {
self.bus self.driver
.alloc_endpoint_in(ep_addr, ep_type, max_packet_size, interval) .alloc_endpoint_in(ep_addr, ep_type, max_packet_size, interval)
} }
@ -266,7 +267,7 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
max_packet_size: u16, max_packet_size: u16,
interval: u8, interval: u8,
) -> Result<D::EndpointOut, EndpointAllocError> { ) -> Result<D::EndpointOut, EndpointAllocError> {
self.bus self.driver
.alloc_endpoint_out(ep_addr, ep_type, max_packet_size, interval) .alloc_endpoint_out(ep_addr, ep_type, max_packet_size, interval)
} }
@ -306,7 +307,7 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
/// feasibly recoverable. /// feasibly recoverable.
#[inline] #[inline]
pub fn alloc_control_pipe(&mut self, max_packet_size: u16) -> D::ControlPipe { pub fn alloc_control_pipe(&mut self, max_packet_size: u16) -> D::ControlPipe {
self.bus self.driver
.alloc_control_pipe(max_packet_size) .alloc_control_pipe(max_packet_size)
.expect("alloc_control_pipe failed") .expect("alloc_control_pipe failed")
} }

View File

@ -11,6 +11,7 @@ pub trait Driver<'a> {
type EndpointIn: EndpointIn + 'a; type EndpointIn: EndpointIn + 'a;
type ControlPipe: ControlPipe + 'a; type ControlPipe: ControlPipe + 'a;
type Bus: Bus + 'a; type Bus: Bus + 'a;
type EnableFuture: Future<Output = Self::Bus> + 'a;
/// Allocates an endpoint and specified endpoint parameters. This method is called by the device /// 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 /// and class implementations to allocate endpoints, and can only be called before
@ -46,7 +47,7 @@ pub trait Driver<'a> {
/// Enables and initializes the USB peripheral. Soon after enabling the device will be reset, so /// 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. /// there is no need to perform a USB reset in this method.
fn enable(self) -> Self::Bus; fn enable(self) -> Self::EnableFuture;
/// Indicates that `set_device_address` must be called before accepting the corresponding /// Indicates that `set_device_address` must be called before accepting the corresponding
/// control transfer, not after. /// control transfer, not after.

View File

@ -72,7 +72,7 @@ pub struct UsbDevice<'d, D: Driver<'d>> {
} }
impl<'d, D: Driver<'d>> UsbDevice<'d, D> { impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
pub(crate) fn build( pub(crate) async fn build(
mut driver: D, mut driver: D,
config: Config<'d>, config: Config<'d>,
device_descriptor: &'d [u8], device_descriptor: &'d [u8],
@ -80,17 +80,17 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
bos_descriptor: &'d [u8], bos_descriptor: &'d [u8],
interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>, interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>,
control_buf: &'d mut [u8], control_buf: &'d mut [u8],
) -> Self { ) -> UsbDevice<'d, D> {
let control = driver let control = driver
.alloc_control_pipe(config.max_packet_size_0 as u16) .alloc_control_pipe(config.max_packet_size_0 as u16)
.expect("failed to alloc control endpoint"); .expect("failed to alloc control endpoint");
// Enable the USB bus. // Enable the USB bus.
// This prevent further allocation by consuming the driver. // This prevent further allocation by consuming the driver.
let driver = driver.enable(); let bus = driver.enable().await;
Self { Self {
bus: driver, bus,
config, config,
control: ControlPipe::new(control), control: ControlPipe::new(control),
device_descriptor, device_descriptor,

View File

@ -76,7 +76,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
); );
// Build the builder. // Build the builder.
let mut usb = builder.build(); let mut usb = builder.build().await;
// Run the USB device. // Run the USB device.
let usb_fut = usb.run(); let usb_fut = usb.run();

View File

@ -74,7 +74,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
); );
// Build the builder. // Build the builder.
let mut usb = builder.build(); let mut usb = builder.build().await;
// Run the USB device. // Run the USB device.
let usb_fut = usb.run(); let usb_fut = usb.run();

View File

@ -60,7 +60,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
// Build the builder. // Build the builder.
let mut usb = builder.build(); let mut usb = builder.build().await;
// Run the USB device. // Run the USB device.
let usb_fut = usb.run(); let usb_fut = usb.run();

View File

@ -85,7 +85,7 @@ async fn main(spawner: Spawner, p: Peripherals) {
let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64); let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64);
// Build the builder. // Build the builder.
let usb = builder.build(); let usb = builder.build().await;
unwrap!(spawner.spawn(usb_task(usb))); unwrap!(spawner.spawn(usb_task(usb)));
unwrap!(spawner.spawn(echo_task(class))); unwrap!(spawner.spawn(echo_task(class)));