aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhuntc <[email protected]>2022-06-16 16:08:58 +1000
committerhuntc <[email protected]>2022-07-07 10:08:57 +1000
commit4a8f117f2520df9d1919cbbac3d2840ea1539e04 (patch)
tree37312b498d3bce9e05a906a88e290063e4d610ca
parentc46e9b6cfc1375f5e5e2bade8eb2174cc47c4a28 (diff)
Puts in the machinery to handle power detected/removed
-rw-r--r--embassy-nrf/src/usb.rs70
-rw-r--r--embassy-stm32/src/usb/usb.rs83
-rw-r--r--embassy-usb/src/driver.rs6
-rw-r--r--embassy-usb/src/lib.rs20
-rw-r--r--embassy-usb/src/util.rs68
-rw-r--r--examples/nrf/src/bin/usb_serial.rs38
6 files changed, 142 insertions, 143 deletions
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs
index 6c872581d..88af74fc0 100644
--- a/embassy-nrf/src/usb.rs
+++ b/embassy-nrf/src/usb.rs
@@ -2,7 +2,7 @@
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::mem::MaybeUninit; 4use core::mem::MaybeUninit;
5use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 5use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering};
6use core::task::Poll; 6use core::task::Poll;
7 7
8use cortex_m::peripheral::NVIC; 8use cortex_m::peripheral::NVIC;
@@ -25,6 +25,7 @@ static EP0_WAKER: AtomicWaker = NEW_AW;
25static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; 25static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
26static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; 26static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
27static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0); 27static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
28static POWER_AVAILABLE: AtomicBool = AtomicBool::new(false);
28 29
29pub struct Driver<'d, T: Instance> { 30pub struct Driver<'d, T: Instance> {
30 phantom: PhantomData<&'d mut T>, 31 phantom: PhantomData<&'d mut T>,
@@ -39,6 +40,11 @@ impl<'d, T: Instance> Driver<'d, T> {
39 irq.unpend(); 40 irq.unpend();
40 irq.enable(); 41 irq.enable();
41 42
43 // Initialize the bus so that it signals that power is available.
44 // Not required when using with_power_management as we then rely on the irq.
45 POWER_AVAILABLE.store(true, Ordering::Relaxed);
46 BUS_WAKER.wake();
47
42 Self { 48 Self {
43 phantom: PhantomData, 49 phantom: PhantomData,
44 alloc_in: Allocator::new(), 50 alloc_in: Allocator::new(),
@@ -46,6 +52,25 @@ impl<'d, T: Instance> Driver<'d, T> {
46 } 52 }
47 } 53 }
48 54
55 /// Establish a new device that then uses the POWER peripheral to
56 /// detect USB power detected/removed events are handled.
57 #[cfg(not(feature = "_nrf5340-app"))]
58 pub fn with_power_management(
59 _usb: impl Unborrow<Target = T> + 'd,
60 irq: impl Unborrow<Target = T::Interrupt> + 'd,
61 power_irq: impl Interrupt,
62 ) -> Self {
63 let regs = unsafe { &*pac::POWER::ptr() };
64
65 power_irq.set_handler(Self::on_power_interrupt);
66 power_irq.unpend();
67 power_irq.enable();
68
69 regs.intenset.write(|w| w.usbdetected().set().usbremoved().set());
70
71 Self::new(_usb, irq)
72 }
73
49 fn on_interrupt(_: *mut ()) { 74 fn on_interrupt(_: *mut ()) {
50 let regs = T::regs(); 75 let regs = T::regs();
51 76
@@ -76,7 +101,6 @@ impl<'d, T: Instance> Driver<'d, T> {
76 // doesn't cause an infinite irq loop. 101 // doesn't cause an infinite irq loop.
77 if regs.events_usbevent.read().bits() != 0 { 102 if regs.events_usbevent.read().bits() != 0 {
78 regs.events_usbevent.reset(); 103 regs.events_usbevent.reset();
79 //regs.intenclr.write(|w| w.usbevent().clear());
80 BUS_WAKER.wake(); 104 BUS_WAKER.wake();
81 } 105 }
82 106
@@ -96,6 +120,31 @@ impl<'d, T: Instance> Driver<'d, T> {
96 } 120 }
97 } 121 }
98 } 122 }
123
124 #[cfg(not(feature = "_nrf5340-app"))]
125 fn on_power_interrupt(_: *mut ()) {
126 let regs = unsafe { &*pac::POWER::ptr() };
127
128 let mut power_changed = false;
129 let mut power_available = false;
130
131 if regs.events_usbdetected.read().bits() != 0 {
132 regs.events_usbdetected.reset();
133 power_changed = true;
134 power_available = true;
135 }
136
137 if regs.events_usbremoved.read().bits() != 0 {
138 regs.events_usbremoved.reset();
139 power_changed = true;
140 power_available = false;
141 }
142
143 if power_changed {
144 POWER_AVAILABLE.store(power_available, Ordering::Relaxed);
145 BUS_WAKER.wake();
146 }
147 }
99} 148}
100 149
101impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { 150impl<'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> {
138 187
139 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { 188 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
140 ( 189 (
141 Bus { phantom: PhantomData }, 190 Bus {
191 phantom: PhantomData,
192 power_available: false,
193 },
142 ControlPipe { 194 ControlPipe {
143 _phantom: PhantomData, 195 _phantom: PhantomData,
144 max_packet_size: control_max_packet_size, 196 max_packet_size: control_max_packet_size,
@@ -149,6 +201,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
149 201
150pub struct Bus<'d, T: Instance> { 202pub struct Bus<'d, T: Instance> {
151 phantom: PhantomData<&'d mut T>, 203 phantom: PhantomData<&'d mut T>,
204 power_available: bool,
152} 205}
153 206
154impl<'d, T: Instance> driver::Bus for Bus<'d, T> { 207impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
@@ -246,6 +299,17 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
246 trace!("USB event: ready"); 299 trace!("USB event: ready");
247 } 300 }
248 301
302 if POWER_AVAILABLE.load(Ordering::Relaxed) != self.power_available {
303 self.power_available = !self.power_available;
304 if self.power_available {
305 trace!("Power event: available");
306 return Poll::Ready(Event::PowerDetected);
307 } else {
308 trace!("Power event: removed");
309 return Poll::Ready(Event::PowerRemoved);
310 }
311 }
312
249 Poll::Pending 313 Poll::Pending
250 }) 314 })
251 } 315 }
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index cadbb423c..4633ff00c 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -161,6 +161,9 @@ impl<'d, T: Instance> Driver<'d, T> {
161 dm.set_as_af(dm.af_num(), AFType::OutputPushPull); 161 dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
162 } 162 }
163 163
164 // Initialize the bus so that it signals that power is available
165 BUS_WAKER.wake();
166
164 Self { 167 Self {
165 phantom: PhantomData, 168 phantom: PhantomData,
166 alloc: [EndpointData { 169 alloc: [EndpointData {
@@ -406,6 +409,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
406 Bus { 409 Bus {
407 phantom: PhantomData, 410 phantom: PhantomData,
408 ep_types, 411 ep_types,
412 inited: false,
409 }, 413 },
410 ControlPipe { 414 ControlPipe {
411 _phantom: PhantomData, 415 _phantom: PhantomData,
@@ -420,6 +424,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
420pub struct Bus<'d, T: Instance> { 424pub struct Bus<'d, T: Instance> {
421 phantom: PhantomData<&'d mut T>, 425 phantom: PhantomData<&'d mut T>,
422 ep_types: [EpType; EP_COUNT - 1], 426 ep_types: [EpType; EP_COUNT - 1],
427 inited: bool,
423} 428}
424 429
425impl<'d, T: Instance> driver::Bus for Bus<'d, T> { 430impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
@@ -428,53 +433,59 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
428 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> { 433 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> {
429 poll_fn(move |cx| unsafe { 434 poll_fn(move |cx| unsafe {
430 BUS_WAKER.register(cx.waker()); 435 BUS_WAKER.register(cx.waker());
431 let regs = T::regs();
432 436
433 let flags = IRQ_FLAGS.load(Ordering::Acquire); 437 if self.inited {
438 let regs = T::regs();
434 439
435 if flags & IRQ_FLAG_RESUME != 0 { 440 let flags = IRQ_FLAGS.load(Ordering::Acquire);
436 IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESUME, Ordering::AcqRel);
437 return Poll::Ready(Event::Resume);
438 }
439 441
440 if flags & IRQ_FLAG_RESET != 0 { 442 if flags & IRQ_FLAG_RESUME != 0 {
441 IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESET, Ordering::AcqRel); 443 IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESUME, Ordering::AcqRel);
444 return Poll::Ready(Event::Resume);
445 }
442 446
443 trace!("RESET REGS WRITINGINGING"); 447 if flags & IRQ_FLAG_RESET != 0 {
444 regs.daddr().write(|w| { 448 IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESET, Ordering::AcqRel);
445 w.set_ef(true);
446 w.set_add(0);
447 });
448 449
449 regs.epr(0).write(|w| { 450 trace!("RESET REGS WRITINGINGING");
450 w.set_ep_type(EpType::CONTROL); 451 regs.daddr().write(|w| {
451 w.set_stat_rx(Stat::NAK); 452 w.set_ef(true);
452 w.set_stat_tx(Stat::NAK); 453 w.set_add(0);
453 }); 454 });
454 455
455 for i in 1..EP_COUNT { 456 regs.epr(0).write(|w| {
456 regs.epr(i).write(|w| { 457 w.set_ep_type(EpType::CONTROL);
457 w.set_ea(i as _); 458 w.set_stat_rx(Stat::NAK);
458 w.set_ep_type(self.ep_types[i - 1]); 459 w.set_stat_tx(Stat::NAK);
459 }) 460 });
460 } 461
462 for i in 1..EP_COUNT {
463 regs.epr(i).write(|w| {
464 w.set_ea(i as _);
465 w.set_ep_type(self.ep_types[i - 1]);
466 })
467 }
461 468
462 for w in &EP_IN_WAKERS { 469 for w in &EP_IN_WAKERS {
463 w.wake() 470 w.wake()
464 } 471 }
465 for w in &EP_OUT_WAKERS { 472 for w in &EP_OUT_WAKERS {
466 w.wake() 473 w.wake()
474 }
475
476 return Poll::Ready(Event::Reset);
467 } 477 }
468 478
469 return Poll::Ready(Event::Reset); 479 if flags & IRQ_FLAG_SUSPEND != 0 {
470 } 480 IRQ_FLAGS.fetch_and(!IRQ_FLAG_SUSPEND, Ordering::AcqRel);
481 return Poll::Ready(Event::Suspend);
482 }
471 483
472 if flags & IRQ_FLAG_SUSPEND != 0 { 484 Poll::Pending
473 IRQ_FLAGS.fetch_and(!IRQ_FLAG_SUSPEND, Ordering::AcqRel); 485 } else {
474 return Poll::Ready(Event::Suspend); 486 self.inited = true;
487 return Poll::Ready(Event::PowerDetected);
475 } 488 }
476
477 Poll::Pending
478 }) 489 })
479 } 490 }
480 491
diff --git a/embassy-usb/src/driver.rs b/embassy-usb/src/driver.rs
index bfe44d627..2a84ff9e7 100644
--- a/embassy-usb/src/driver.rs
+++ b/embassy-usb/src/driver.rs
@@ -202,6 +202,12 @@ pub enum Event {
202 /// A USB resume request has been detected after being suspended or, in the case of self-powered 202 /// A USB resume request has been detected after being suspended or, in the case of self-powered
203 /// devices, the device has been connected to the USB bus. 203 /// devices, the device has been connected to the USB bus.
204 Resume, 204 Resume,
205
206 /// The USB power has been detected.
207 PowerDetected,
208
209 /// The USB power has been removed. Not supported by all devices.
210 PowerRemoved,
205} 211}
206 212
207#[derive(Copy, Clone, Eq, PartialEq, Debug)] 213#[derive(Copy, Clone, Eq, PartialEq, Debug)]
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index eba46b892..af102e589 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -11,7 +11,6 @@ pub mod descriptor;
11mod descriptor_reader; 11mod descriptor_reader;
12pub mod driver; 12pub mod driver;
13pub mod types; 13pub mod types;
14pub mod util;
15 14
16use embassy::util::{select, Either}; 15use embassy::util::{select, Either};
17use heapless::Vec; 16use heapless::Vec;
@@ -115,6 +114,7 @@ struct Inner<'d, D: Driver<'d>> {
115 114
116 device_state: UsbDeviceState, 115 device_state: UsbDeviceState,
117 suspended: bool, 116 suspended: bool,
117 power_available: bool,
118 remote_wakeup_enabled: bool, 118 remote_wakeup_enabled: bool,
119 self_powered: bool, 119 self_powered: bool,
120 120
@@ -157,6 +157,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
157 157
158 device_state: UsbDeviceState::Disabled, 158 device_state: UsbDeviceState::Disabled,
159 suspended: false, 159 suspended: false,
160 power_available: false,
160 remote_wakeup_enabled: false, 161 remote_wakeup_enabled: false,
161 self_powered: false, 162 self_powered: false,
162 address: 0, 163 address: 0,
@@ -186,6 +187,11 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
186 /// before calling any other `UsbDevice` methods to fully reset the 187 /// before calling any other `UsbDevice` methods to fully reset the
187 /// peripheral. 188 /// peripheral.
188 pub async fn run_until_suspend(&mut self) -> () { 189 pub async fn run_until_suspend(&mut self) -> () {
190 while !self.inner.power_available {
191 let evt = self.inner.bus.poll().await;
192 self.inner.handle_bus_event(evt);
193 }
194
189 if self.inner.device_state == UsbDeviceState::Disabled { 195 if self.inner.device_state == UsbDeviceState::Disabled {
190 self.inner.bus.enable().await; 196 self.inner.bus.enable().await;
191 self.inner.device_state = UsbDeviceState::Default; 197 self.inner.device_state = UsbDeviceState::Default;
@@ -195,7 +201,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
195 } 201 }
196 } 202 }
197 203
198 while !self.inner.suspended { 204 while !self.inner.suspended && self.inner.power_available {
199 let control_fut = self.control.setup(); 205 let control_fut = self.control.setup();
200 let bus_fut = self.inner.bus.poll(); 206 let bus_fut = self.inner.bus.poll();
201 match select(bus_fut, control_fut).await { 207 match select(bus_fut, control_fut).await {
@@ -223,7 +229,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
223 /// 229 ///
224 /// This future is cancel-safe. 230 /// This future is cancel-safe.
225 pub async fn wait_resume(&mut self) { 231 pub async fn wait_resume(&mut self) {
226 while self.inner.suspended { 232 while self.inner.suspended || !self.inner.power_available {
227 let evt = self.inner.bus.poll().await; 233 let evt = self.inner.bus.poll().await;
228 self.inner.handle_bus_event(evt); 234 self.inner.handle_bus_event(evt);
229 } 235 }
@@ -377,6 +383,14 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
377 h.suspended(true); 383 h.suspended(true);
378 } 384 }
379 } 385 }
386 Event::PowerDetected => {
387 trace!("usb: power detected");
388 self.power_available = true;
389 }
390 Event::PowerRemoved => {
391 trace!("usb: power removed");
392 self.power_available = false;
393 }
380 } 394 }
381 } 395 }
382 396
diff --git a/embassy-usb/src/util.rs b/embassy-usb/src/util.rs
deleted file mode 100644
index ac56691b8..000000000
--- a/embassy-usb/src/util.rs
+++ /dev/null
@@ -1,68 +0,0 @@
1use embassy::channel::signal::Signal;
2use embassy::util::{select, Either};
3
4use crate::driver::Driver;
5use crate::UsbDevice;
6
7/// Am enabled usb device is a device that further receives external notifications
8/// regarding whether it is enabled or not. A common example of where this is
9/// required is when receiving notifications from the POWER peripheral that
10/// USB has been connected to or removed. The device here wraps an existing
11/// USB device, keeping it publically available so that device-oriented operations
12/// may still be performed. A signal is also provided that enables/disables the
13/// USB device, taking care of suspension and resumption. In the case of the POWER
14/// peripheral, this signal can be used from within a POWER_CLOCK interrupt
15/// handler. Alternatively, for softdevice usage where the POWER peripheral is not
16/// available, similar USB power events can be leveraged.
17pub struct EnabledUsbDevice<'d, D: Driver<'d>> {
18 pub underlying: UsbDevice<'d, D>,
19 enable_usb_signal: &'d Signal<bool>,
20}
21
22impl<'d, D: Driver<'d>> EnabledUsbDevice<'d, D> {
23 /// Wrap an existing UsbDevice and take a signal that will be used
24 /// to enable/disable it, perhaps from an external POWER_CLOCK
25 /// interrupt, or the equivalent when dealing with softdevices.
26 pub fn new(underlying: UsbDevice<'d, D>, enable_usb_signal: &'d Signal<bool>) -> Self {
27 Self {
28 underlying,
29 enable_usb_signal,
30 }
31 }
32
33 /// Runs the underlying `UsbDevice` taking care of reacting to USB becoming
34 /// enabled/disabled.
35 ///
36 /// This future may leave the bus in an invalid state if it is dropped.
37 /// After dropping the future, [`UsbDevice::disable()`] should be called
38 /// before calling any other `UsbDevice` methods to fully reset the
39 /// peripheral.
40 pub async fn run(&mut self) -> ! {
41 while !self.enable_usb_signal.wait().await {}
42 loop {
43 match select(
44 self.underlying.run_until_suspend(),
45 self.enable_usb_signal.wait(),
46 )
47 .await
48 {
49 Either::First(_) => {}
50 Either::Second(enable) => {
51 if !enable {
52 self.underlying.disable().await;
53 while !self.enable_usb_signal.wait().await {}
54 }
55 }
56 }
57 match select(self.underlying.wait_resume(), self.enable_usb_signal.wait()).await {
58 Either::First(_) => {}
59 Either::Second(enable) => {
60 if !enable {
61 self.underlying.disable().await;
62 while !self.enable_usb_signal.wait().await {}
63 }
64 }
65 }
66 }
67 }
68}
diff --git a/examples/nrf/src/bin/usb_serial.rs b/examples/nrf/src/bin/usb_serial.rs
index 377ae8c3a..7c1d8cbb8 100644
--- a/examples/nrf/src/bin/usb_serial.rs
+++ b/examples/nrf/src/bin/usb_serial.rs
@@ -6,47 +6,18 @@
6use core::mem; 6use core::mem;
7 7
8use defmt::{info, panic}; 8use defmt::{info, panic};
9use embassy::channel::signal::Signal;
10use embassy::executor::Spawner; 9use embassy::executor::Spawner;
11use embassy::interrupt::InterruptExt;
12use embassy_nrf::usb::{Driver, Instance}; 10use embassy_nrf::usb::{Driver, Instance};
13use embassy_nrf::{interrupt, interrupt, pac, pac, Peripherals}; 11use embassy_nrf::{interrupt, pac, Peripherals};
14use embassy_usb::driver::EndpointError; 12use embassy_usb::driver::EndpointError;
15use embassy_usb::util::EnabledUsbDevice;
16use embassy_usb::{Builder, Config}; 13use embassy_usb::{Builder, Config};
17use embassy_usb_serial::{CdcAcmClass, State}; 14use embassy_usb_serial::{CdcAcmClass, State};
18use futures::future::join; 15use futures::future::join;
19use {defmt_rtt as _, panic_probe as _}; // global logger 16use {defmt_rtt as _, panic_probe as _};
20
21static ENABLE_USB: Signal<bool> = Signal::new();
22
23fn on_power_interrupt(_: *mut ()) {
24 let regs = unsafe { &*pac::POWER::ptr() };
25
26 if regs.events_usbdetected.read().bits() != 0 {
27 regs.events_usbdetected.reset();
28 info!("Vbus detected, enabling USB...");
29 ENABLE_USB.signal(true);
30 }
31
32 if regs.events_usbremoved.read().bits() != 0 {
33 regs.events_usbremoved.reset();
34 info!("Vbus removed, disabling USB...");
35 ENABLE_USB.signal(false);
36 }
37}
38 17
39#[embassy::main] 18#[embassy::main]
40async fn main(_spawner: Spawner, p: Peripherals) { 19async fn main(_spawner: Spawner, p: Peripherals) {
41 let clock: pac::CLOCK = unsafe { mem::transmute(()) }; 20 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
42 let power: pac::POWER = unsafe { mem::transmute(()) };
43
44 let power_irq = interrupt::take!(POWER_CLOCK);
45 power_irq.set_handler(on_power_interrupt);
46 power_irq.unpend();
47 power_irq.enable();
48
49 power.intenset.write(|w| w.usbdetected().set().usbremoved().set());
50 21
51 info!("Enabling ext hfosc..."); 22 info!("Enabling ext hfosc...");
52 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 23 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
@@ -54,7 +25,8 @@ async fn main(_spawner: Spawner, p: Peripherals) {
54 25
55 // Create the driver, from the HAL. 26 // Create the driver, from the HAL.
56 let irq = interrupt::take!(USBD); 27 let irq = interrupt::take!(USBD);
57 let driver = Driver::new(p.USBD, irq); 28 let power_irq = interrupt::take!(POWER_CLOCK);
29 let driver = Driver::with_power_management(p.USBD, irq, power_irq);
58 30
59 // Create embassy-usb Config 31 // Create embassy-usb Config
60 let mut config = Config::new(0xc0de, 0xcafe); 32 let mut config = Config::new(0xc0de, 0xcafe);
@@ -94,7 +66,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
94 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); 66 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
95 67
96 // Build the builder. 68 // Build the builder.
97 let mut usb = EnabledUsbDevice::new(builder.build(), &ENABLE_USB); 69 let mut usb = builder.build();
98 70
99 // Run the USB device. 71 // Run the USB device.
100 let usb_fut = usb.run(); 72 let usb_fut = usb.run();