Puts in the machinery to handle power detected/removed
This commit is contained in:
parent
c46e9b6cfc
commit
4a8f117f25
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
|
use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use cortex_m::peripheral::NVIC;
|
use cortex_m::peripheral::NVIC;
|
||||||
@ -25,6 +25,7 @@ static EP0_WAKER: AtomicWaker = NEW_AW;
|
|||||||
static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
|
static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
|
||||||
static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
|
static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
|
||||||
static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
|
static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
|
||||||
|
static POWER_AVAILABLE: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
pub struct Driver<'d, T: Instance> {
|
pub struct Driver<'d, T: Instance> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
@ -39,6 +40,11 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
irq.unpend();
|
irq.unpend();
|
||||||
irq.enable();
|
irq.enable();
|
||||||
|
|
||||||
|
// Initialize the bus so that it signals that power is available.
|
||||||
|
// Not required when using with_power_management as we then rely on the irq.
|
||||||
|
POWER_AVAILABLE.store(true, Ordering::Relaxed);
|
||||||
|
BUS_WAKER.wake();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
alloc_in: Allocator::new(),
|
alloc_in: Allocator::new(),
|
||||||
@ -46,6 +52,25 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Establish a new device that then uses the POWER peripheral to
|
||||||
|
/// detect USB power detected/removed events are handled.
|
||||||
|
#[cfg(not(feature = "_nrf5340-app"))]
|
||||||
|
pub fn with_power_management(
|
||||||
|
_usb: impl Unborrow<Target = T> + 'd,
|
||||||
|
irq: impl Unborrow<Target = T::Interrupt> + 'd,
|
||||||
|
power_irq: impl Interrupt,
|
||||||
|
) -> Self {
|
||||||
|
let regs = unsafe { &*pac::POWER::ptr() };
|
||||||
|
|
||||||
|
power_irq.set_handler(Self::on_power_interrupt);
|
||||||
|
power_irq.unpend();
|
||||||
|
power_irq.enable();
|
||||||
|
|
||||||
|
regs.intenset.write(|w| w.usbdetected().set().usbremoved().set());
|
||||||
|
|
||||||
|
Self::new(_usb, irq)
|
||||||
|
}
|
||||||
|
|
||||||
fn on_interrupt(_: *mut ()) {
|
fn on_interrupt(_: *mut ()) {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
@ -76,7 +101,6 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
// doesn't cause an infinite irq loop.
|
// doesn't cause an infinite irq loop.
|
||||||
if regs.events_usbevent.read().bits() != 0 {
|
if regs.events_usbevent.read().bits() != 0 {
|
||||||
regs.events_usbevent.reset();
|
regs.events_usbevent.reset();
|
||||||
//regs.intenclr.write(|w| w.usbevent().clear());
|
|
||||||
BUS_WAKER.wake();
|
BUS_WAKER.wake();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +120,31 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "_nrf5340-app"))]
|
||||||
|
fn on_power_interrupt(_: *mut ()) {
|
||||||
|
let regs = unsafe { &*pac::POWER::ptr() };
|
||||||
|
|
||||||
|
let mut power_changed = false;
|
||||||
|
let mut power_available = false;
|
||||||
|
|
||||||
|
if regs.events_usbdetected.read().bits() != 0 {
|
||||||
|
regs.events_usbdetected.reset();
|
||||||
|
power_changed = true;
|
||||||
|
power_available = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if regs.events_usbremoved.read().bits() != 0 {
|
||||||
|
regs.events_usbremoved.reset();
|
||||||
|
power_changed = true;
|
||||||
|
power_available = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if power_changed {
|
||||||
|
POWER_AVAILABLE.store(power_available, Ordering::Relaxed);
|
||||||
|
BUS_WAKER.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
||||||
@ -138,7 +187,10 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
|||||||
|
|
||||||
fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
|
fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
|
||||||
(
|
(
|
||||||
Bus { phantom: PhantomData },
|
Bus {
|
||||||
|
phantom: PhantomData,
|
||||||
|
power_available: false,
|
||||||
|
},
|
||||||
ControlPipe {
|
ControlPipe {
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
max_packet_size: control_max_packet_size,
|
max_packet_size: control_max_packet_size,
|
||||||
@ -149,6 +201,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
|||||||
|
|
||||||
pub struct Bus<'d, T: Instance> {
|
pub struct Bus<'d, T: Instance> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
|
power_available: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||||
@ -246,6 +299,17 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
trace!("USB event: ready");
|
trace!("USB event: ready");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if POWER_AVAILABLE.load(Ordering::Relaxed) != self.power_available {
|
||||||
|
self.power_available = !self.power_available;
|
||||||
|
if self.power_available {
|
||||||
|
trace!("Power event: available");
|
||||||
|
return Poll::Ready(Event::PowerDetected);
|
||||||
|
} else {
|
||||||
|
trace!("Power event: removed");
|
||||||
|
return Poll::Ready(Event::PowerRemoved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -161,6 +161,9 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
|
dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the bus so that it signals that power is available
|
||||||
|
BUS_WAKER.wake();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
alloc: [EndpointData {
|
alloc: [EndpointData {
|
||||||
@ -406,6 +409,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
|||||||
Bus {
|
Bus {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
ep_types,
|
ep_types,
|
||||||
|
inited: false,
|
||||||
},
|
},
|
||||||
ControlPipe {
|
ControlPipe {
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
@ -420,6 +424,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
|||||||
pub struct Bus<'d, T: Instance> {
|
pub struct Bus<'d, T: Instance> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
ep_types: [EpType; EP_COUNT - 1],
|
ep_types: [EpType; EP_COUNT - 1],
|
||||||
|
inited: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||||
@ -428,6 +433,8 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> {
|
fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> {
|
||||||
poll_fn(move |cx| unsafe {
|
poll_fn(move |cx| unsafe {
|
||||||
BUS_WAKER.register(cx.waker());
|
BUS_WAKER.register(cx.waker());
|
||||||
|
|
||||||
|
if self.inited {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
let flags = IRQ_FLAGS.load(Ordering::Acquire);
|
let flags = IRQ_FLAGS.load(Ordering::Acquire);
|
||||||
@ -475,6 +482,10 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
|
} else {
|
||||||
|
self.inited = true;
|
||||||
|
return Poll::Ready(Event::PowerDetected);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,6 +202,12 @@ pub enum Event {
|
|||||||
/// A USB resume request has been detected after being suspended or, in the case of self-powered
|
/// 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.
|
/// devices, the device has been connected to the USB bus.
|
||||||
Resume,
|
Resume,
|
||||||
|
|
||||||
|
/// The USB power has been detected.
|
||||||
|
PowerDetected,
|
||||||
|
|
||||||
|
/// The USB power has been removed. Not supported by all devices.
|
||||||
|
PowerRemoved,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
|
@ -11,7 +11,6 @@ pub mod descriptor;
|
|||||||
mod descriptor_reader;
|
mod descriptor_reader;
|
||||||
pub mod driver;
|
pub mod driver;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod util;
|
|
||||||
|
|
||||||
use embassy::util::{select, Either};
|
use embassy::util::{select, Either};
|
||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
@ -115,6 +114,7 @@ struct Inner<'d, D: Driver<'d>> {
|
|||||||
|
|
||||||
device_state: UsbDeviceState,
|
device_state: UsbDeviceState,
|
||||||
suspended: bool,
|
suspended: bool,
|
||||||
|
power_available: bool,
|
||||||
remote_wakeup_enabled: bool,
|
remote_wakeup_enabled: bool,
|
||||||
self_powered: bool,
|
self_powered: bool,
|
||||||
|
|
||||||
@ -157,6 +157,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
|||||||
|
|
||||||
device_state: UsbDeviceState::Disabled,
|
device_state: UsbDeviceState::Disabled,
|
||||||
suspended: false,
|
suspended: false,
|
||||||
|
power_available: false,
|
||||||
remote_wakeup_enabled: false,
|
remote_wakeup_enabled: false,
|
||||||
self_powered: false,
|
self_powered: false,
|
||||||
address: 0,
|
address: 0,
|
||||||
@ -186,6 +187,11 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
|||||||
/// before calling any other `UsbDevice` methods to fully reset the
|
/// before calling any other `UsbDevice` methods to fully reset the
|
||||||
/// peripheral.
|
/// peripheral.
|
||||||
pub async fn run_until_suspend(&mut self) -> () {
|
pub async fn run_until_suspend(&mut self) -> () {
|
||||||
|
while !self.inner.power_available {
|
||||||
|
let evt = self.inner.bus.poll().await;
|
||||||
|
self.inner.handle_bus_event(evt);
|
||||||
|
}
|
||||||
|
|
||||||
if self.inner.device_state == UsbDeviceState::Disabled {
|
if self.inner.device_state == UsbDeviceState::Disabled {
|
||||||
self.inner.bus.enable().await;
|
self.inner.bus.enable().await;
|
||||||
self.inner.device_state = UsbDeviceState::Default;
|
self.inner.device_state = UsbDeviceState::Default;
|
||||||
@ -195,7 +201,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while !self.inner.suspended {
|
while !self.inner.suspended && self.inner.power_available {
|
||||||
let control_fut = self.control.setup();
|
let control_fut = self.control.setup();
|
||||||
let bus_fut = self.inner.bus.poll();
|
let bus_fut = self.inner.bus.poll();
|
||||||
match select(bus_fut, control_fut).await {
|
match select(bus_fut, control_fut).await {
|
||||||
@ -223,7 +229,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
|
|||||||
///
|
///
|
||||||
/// This future is cancel-safe.
|
/// This future is cancel-safe.
|
||||||
pub async fn wait_resume(&mut self) {
|
pub async fn wait_resume(&mut self) {
|
||||||
while self.inner.suspended {
|
while self.inner.suspended || !self.inner.power_available {
|
||||||
let evt = self.inner.bus.poll().await;
|
let evt = self.inner.bus.poll().await;
|
||||||
self.inner.handle_bus_event(evt);
|
self.inner.handle_bus_event(evt);
|
||||||
}
|
}
|
||||||
@ -377,6 +383,14 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
|
|||||||
h.suspended(true);
|
h.suspended(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Event::PowerDetected => {
|
||||||
|
trace!("usb: power detected");
|
||||||
|
self.power_available = true;
|
||||||
|
}
|
||||||
|
Event::PowerRemoved => {
|
||||||
|
trace!("usb: power removed");
|
||||||
|
self.power_available = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
use embassy::channel::signal::Signal;
|
|
||||||
use embassy::util::{select, Either};
|
|
||||||
|
|
||||||
use crate::driver::Driver;
|
|
||||||
use crate::UsbDevice;
|
|
||||||
|
|
||||||
/// Am enabled usb device is a device that further receives external notifications
|
|
||||||
/// regarding whether it is enabled or not. A common example of where this is
|
|
||||||
/// required is when receiving notifications from the POWER peripheral that
|
|
||||||
/// USB has been connected to or removed. The device here wraps an existing
|
|
||||||
/// USB device, keeping it publically available so that device-oriented operations
|
|
||||||
/// may still be performed. A signal is also provided that enables/disables the
|
|
||||||
/// USB device, taking care of suspension and resumption. In the case of the POWER
|
|
||||||
/// peripheral, this signal can be used from within a POWER_CLOCK interrupt
|
|
||||||
/// handler. Alternatively, for softdevice usage where the POWER peripheral is not
|
|
||||||
/// available, similar USB power events can be leveraged.
|
|
||||||
pub struct EnabledUsbDevice<'d, D: Driver<'d>> {
|
|
||||||
pub underlying: UsbDevice<'d, D>,
|
|
||||||
enable_usb_signal: &'d Signal<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, D: Driver<'d>> EnabledUsbDevice<'d, D> {
|
|
||||||
/// Wrap an existing UsbDevice and take a signal that will be used
|
|
||||||
/// to enable/disable it, perhaps from an external POWER_CLOCK
|
|
||||||
/// interrupt, or the equivalent when dealing with softdevices.
|
|
||||||
pub fn new(underlying: UsbDevice<'d, D>, enable_usb_signal: &'d Signal<bool>) -> Self {
|
|
||||||
Self {
|
|
||||||
underlying,
|
|
||||||
enable_usb_signal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs the underlying `UsbDevice` taking care of reacting to USB becoming
|
|
||||||
/// enabled/disabled.
|
|
||||||
///
|
|
||||||
/// This future may leave the bus in an invalid state if it is dropped.
|
|
||||||
/// After dropping the future, [`UsbDevice::disable()`] should be called
|
|
||||||
/// before calling any other `UsbDevice` methods to fully reset the
|
|
||||||
/// peripheral.
|
|
||||||
pub async fn run(&mut self) -> ! {
|
|
||||||
while !self.enable_usb_signal.wait().await {}
|
|
||||||
loop {
|
|
||||||
match select(
|
|
||||||
self.underlying.run_until_suspend(),
|
|
||||||
self.enable_usb_signal.wait(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Either::First(_) => {}
|
|
||||||
Either::Second(enable) => {
|
|
||||||
if !enable {
|
|
||||||
self.underlying.disable().await;
|
|
||||||
while !self.enable_usb_signal.wait().await {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match select(self.underlying.wait_resume(), self.enable_usb_signal.wait()).await {
|
|
||||||
Either::First(_) => {}
|
|
||||||
Either::Second(enable) => {
|
|
||||||
if !enable {
|
|
||||||
self.underlying.disable().await;
|
|
||||||
while !self.enable_usb_signal.wait().await {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,47 +6,18 @@
|
|||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
use defmt::{info, panic};
|
use defmt::{info, panic};
|
||||||
use embassy::channel::signal::Signal;
|
|
||||||
use embassy::executor::Spawner;
|
use embassy::executor::Spawner;
|
||||||
use embassy::interrupt::InterruptExt;
|
|
||||||
use embassy_nrf::usb::{Driver, Instance};
|
use embassy_nrf::usb::{Driver, Instance};
|
||||||
use embassy_nrf::{interrupt, interrupt, pac, pac, Peripherals};
|
use embassy_nrf::{interrupt, pac, Peripherals};
|
||||||
use embassy_usb::driver::EndpointError;
|
use embassy_usb::driver::EndpointError;
|
||||||
use embassy_usb::util::EnabledUsbDevice;
|
|
||||||
use embassy_usb::{Builder, Config};
|
use embassy_usb::{Builder, Config};
|
||||||
use embassy_usb_serial::{CdcAcmClass, State};
|
use embassy_usb_serial::{CdcAcmClass, State};
|
||||||
use futures::future::join;
|
use futures::future::join;
|
||||||
use {defmt_rtt as _, panic_probe as _}; // global logger
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
static ENABLE_USB: Signal<bool> = Signal::new();
|
|
||||||
|
|
||||||
fn on_power_interrupt(_: *mut ()) {
|
|
||||||
let regs = unsafe { &*pac::POWER::ptr() };
|
|
||||||
|
|
||||||
if regs.events_usbdetected.read().bits() != 0 {
|
|
||||||
regs.events_usbdetected.reset();
|
|
||||||
info!("Vbus detected, enabling USB...");
|
|
||||||
ENABLE_USB.signal(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if regs.events_usbremoved.read().bits() != 0 {
|
|
||||||
regs.events_usbremoved.reset();
|
|
||||||
info!("Vbus removed, disabling USB...");
|
|
||||||
ENABLE_USB.signal(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[embassy::main]
|
#[embassy::main]
|
||||||
async fn main(_spawner: Spawner, p: Peripherals) {
|
async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
let clock: pac::CLOCK = unsafe { mem::transmute(()) };
|
let clock: pac::CLOCK = unsafe { mem::transmute(()) };
|
||||||
let power: pac::POWER = unsafe { mem::transmute(()) };
|
|
||||||
|
|
||||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
|
||||||
power_irq.set_handler(on_power_interrupt);
|
|
||||||
power_irq.unpend();
|
|
||||||
power_irq.enable();
|
|
||||||
|
|
||||||
power.intenset.write(|w| w.usbdetected().set().usbremoved().set());
|
|
||||||
|
|
||||||
info!("Enabling ext hfosc...");
|
info!("Enabling ext hfosc...");
|
||||||
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
||||||
@ -54,7 +25,8 @@ async fn main(_spawner: Spawner, p: Peripherals) {
|
|||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBD);
|
let irq = interrupt::take!(USBD);
|
||||||
let driver = Driver::new(p.USBD, irq);
|
let power_irq = interrupt::take!(POWER_CLOCK);
|
||||||
|
let driver = Driver::with_power_management(p.USBD, irq, power_irq);
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
@ -94,7 +66,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 = EnabledUsbDevice::new(builder.build(), &ENABLE_USB);
|
let mut usb = builder.build();
|
||||||
|
|
||||||
// Run the USB device.
|
// Run the USB device.
|
||||||
let usb_fut = usb.run();
|
let usb_fut = usb.run();
|
||||||
|
Loading…
Reference in New Issue
Block a user