diff options
| author | alexmoon <[email protected]> | 2022-04-02 16:35:03 -0400 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-04-06 05:38:11 +0200 |
| commit | 2ce435dc341c0238392df5dab5db9b80db167117 (patch) | |
| tree | 19e64218922a67601540261749af81d2d1d0aac4 /embassy-nrf/src | |
| parent | 99f95a33c30b08359fcd72123fea01f4de0903ec (diff) | |
Add basic device state handling for endpoints.
Diffstat (limited to 'embassy-nrf/src')
| -rw-r--r-- | embassy-nrf/src/usb.rs | 180 |
1 files changed, 129 insertions, 51 deletions
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs index 124316a29..c16e1be00 100644 --- a/embassy-nrf/src/usb.rs +++ b/embassy-nrf/src/usb.rs | |||
| @@ -17,6 +17,7 @@ use futures::future::poll_fn; | |||
| 17 | use futures::Future; | 17 | use futures::Future; |
| 18 | 18 | ||
| 19 | pub use embassy_usb; | 19 | pub use embassy_usb; |
| 20 | use pac::usbd::RegisterBlock; | ||
| 20 | 21 | ||
| 21 | use crate::interrupt::Interrupt; | 22 | use crate::interrupt::Interrupt; |
| 22 | use crate::pac; | 23 | use crate::pac; |
| @@ -92,11 +93,11 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 92 | regs.epdatastatus.write(|w| unsafe { w.bits(r) }); | 93 | regs.epdatastatus.write(|w| unsafe { w.bits(r) }); |
| 93 | READY_ENDPOINTS.fetch_or(r, Ordering::AcqRel); | 94 | READY_ENDPOINTS.fetch_or(r, Ordering::AcqRel); |
| 94 | for i in 1..=7 { | 95 | for i in 1..=7 { |
| 95 | if r & (1 << i) != 0 { | 96 | if r & In::mask(i) != 0 { |
| 96 | EP_IN_WAKERS[i - 1].wake(); | 97 | In::waker(i).wake(); |
| 97 | } | 98 | } |
| 98 | if r & (1 << (i + 16)) != 0 { | 99 | if r & Out::mask(i) != 0 { |
| 99 | EP_OUT_WAKERS[i - 1].wake(); | 100 | Out::waker(i).wake(); |
| 100 | } | 101 | } |
| 101 | } | 102 | } |
| 102 | } | 103 | } |
| @@ -272,32 +273,48 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 272 | 273 | ||
| 273 | #[inline] | 274 | #[inline] |
| 274 | fn reset(&mut self) { | 275 | fn reset(&mut self) { |
| 275 | let regs = T::regs(); | 276 | self.set_configured(false); |
| 277 | } | ||
| 276 | 278 | ||
| 277 | // TODO: Initialize ISO buffers | 279 | #[inline] |
| 280 | fn set_configured(&mut self, configured: bool) { | ||
| 281 | let regs = T::regs(); | ||
| 278 | 282 | ||
| 279 | // XXX this is not spec compliant; the endpoints should only be enabled after the device | ||
| 280 | // has been put in the Configured state. However, usb-device provides no hook to do that | ||
| 281 | unsafe { | 283 | unsafe { |
| 282 | regs.epinen.write(|w| w.bits(self.alloc_in.used.into())); | 284 | if configured { |
| 283 | regs.epouten.write(|w| w.bits(self.alloc_out.used.into())); | 285 | // TODO: Initialize ISO buffers |
| 284 | } | ||
| 285 | 286 | ||
| 286 | for i in 1..8 { | 287 | regs.epinen.write(|w| w.bits(self.alloc_in.used.into())); |
| 287 | let out_enabled = self.alloc_out.used & (1 << i) != 0; | 288 | regs.epouten.write(|w| w.bits(self.alloc_out.used.into())); |
| 289 | |||
| 290 | for i in 1..8 { | ||
| 291 | let out_enabled = self.alloc_out.used & (1 << i) != 0; | ||
| 292 | |||
| 293 | // when first enabled, bulk/interrupt OUT endpoints will *not* receive data (the | ||
| 294 | // peripheral will NAK all incoming packets) until we write a zero to the SIZE | ||
| 295 | // register (see figure 203 of the 52840 manual). To avoid that we write a 0 to the | ||
| 296 | // SIZE register | ||
| 297 | if out_enabled { | ||
| 298 | regs.size.epout[i].reset(); | ||
| 299 | } | ||
| 300 | } | ||
| 288 | 301 | ||
| 289 | // when first enabled, bulk/interrupt OUT endpoints will *not* receive data (the | 302 | // IN endpoints (low bits) default to ready. |
| 290 | // peripheral will NAK all incoming packets) until we write a zero to the SIZE | 303 | // OUT endpoints (high bits) default to NOT ready, they become ready when data comes in. |
| 291 | // register (see figure 203 of the 52840 manual). To avoid that we write a 0 to the | 304 | READY_ENDPOINTS.store(0x0000FFFF, Ordering::Release); |
| 292 | // SIZE register | 305 | } else { |
| 293 | if out_enabled { | 306 | // Disable all endpoints except EP0 |
| 294 | regs.size.epout[i].reset(); | 307 | regs.epinen.write(|w| w.bits(0x01)); |
| 308 | regs.epouten.write(|w| w.bits(0x01)); | ||
| 309 | |||
| 310 | READY_ENDPOINTS.store(In::mask(0), Ordering::Release); | ||
| 295 | } | 311 | } |
| 296 | } | 312 | } |
| 297 | 313 | ||
| 298 | // IN endpoints (low bits) default to ready. | 314 | for i in 1..=7 { |
| 299 | // OUT endpoints (high bits) default to NOT ready, they become ready when data comes in. | 315 | In::waker(i).wake(); |
| 300 | READY_ENDPOINTS.store(0x0000FFFF, Ordering::Release); | 316 | Out::waker(i).wake(); |
| 317 | } | ||
| 301 | } | 318 | } |
| 302 | 319 | ||
| 303 | #[inline] | 320 | #[inline] |
| @@ -332,6 +349,46 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 332 | pub enum Out {} | 349 | pub enum Out {} |
| 333 | pub enum In {} | 350 | pub enum In {} |
| 334 | 351 | ||
| 352 | trait EndpointDir { | ||
| 353 | fn waker(i: usize) -> &'static AtomicWaker; | ||
| 354 | fn mask(i: usize) -> u32; | ||
| 355 | fn is_enabled(regs: &RegisterBlock, i: usize) -> bool; | ||
| 356 | } | ||
| 357 | |||
| 358 | impl EndpointDir for In { | ||
| 359 | #[inline] | ||
| 360 | fn waker(i: usize) -> &'static AtomicWaker { | ||
| 361 | &EP_IN_WAKERS[i - 1] | ||
| 362 | } | ||
| 363 | |||
| 364 | #[inline] | ||
| 365 | fn mask(i: usize) -> u32 { | ||
| 366 | 1 << i | ||
| 367 | } | ||
| 368 | |||
| 369 | #[inline] | ||
| 370 | fn is_enabled(regs: &RegisterBlock, i: usize) -> bool { | ||
| 371 | (regs.epinen.read().bits() & (1 << i)) != 0 | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 375 | impl EndpointDir for Out { | ||
| 376 | #[inline] | ||
| 377 | fn waker(i: usize) -> &'static AtomicWaker { | ||
| 378 | &EP_OUT_WAKERS[i - 1] | ||
| 379 | } | ||
| 380 | |||
| 381 | #[inline] | ||
| 382 | fn mask(i: usize) -> u32 { | ||
| 383 | 1 << (i + 16) | ||
| 384 | } | ||
| 385 | |||
| 386 | #[inline] | ||
| 387 | fn is_enabled(regs: &RegisterBlock, i: usize) -> bool { | ||
| 388 | (regs.epouten.read().bits() & (1 << i)) != 0 | ||
| 389 | } | ||
| 390 | } | ||
| 391 | |||
| 335 | pub struct Endpoint<'d, T: Instance, Dir> { | 392 | pub struct Endpoint<'d, T: Instance, Dir> { |
| 336 | _phantom: PhantomData<(&'d mut T, Dir)>, | 393 | _phantom: PhantomData<(&'d mut T, Dir)>, |
| 337 | info: EndpointInfo, | 394 | info: EndpointInfo, |
| @@ -346,7 +403,7 @@ impl<'d, T: Instance, Dir> Endpoint<'d, T, Dir> { | |||
| 346 | } | 403 | } |
| 347 | } | 404 | } |
| 348 | 405 | ||
| 349 | impl<'d, T: Instance, Dir> driver::Endpoint for Endpoint<'d, T, Dir> { | 406 | impl<'d, T: Instance, Dir: EndpointDir> driver::Endpoint for Endpoint<'d, T, Dir> { |
| 350 | fn info(&self) -> &EndpointInfo { | 407 | fn info(&self) -> &EndpointInfo { |
| 351 | &self.info | 408 | &self.info |
| 352 | } | 409 | } |
| @@ -358,6 +415,49 @@ impl<'d, T: Instance, Dir> driver::Endpoint for Endpoint<'d, T, Dir> { | |||
| 358 | fn is_stalled(&self) -> bool { | 415 | fn is_stalled(&self) -> bool { |
| 359 | Driver::<T>::is_stalled(self.info.addr) | 416 | Driver::<T>::is_stalled(self.info.addr) |
| 360 | } | 417 | } |
| 418 | |||
| 419 | type WaitEnabledFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; | ||
| 420 | |||
| 421 | fn wait_enabled(&mut self) -> Self::WaitEnabledFuture<'_> { | ||
| 422 | let i = self.info.addr.index(); | ||
| 423 | assert!(i != 0); | ||
| 424 | |||
| 425 | poll_fn(move |cx| { | ||
| 426 | Dir::waker(i).register(cx.waker()); | ||
| 427 | if Dir::is_enabled(T::regs(), i) { | ||
| 428 | Poll::Ready(()) | ||
| 429 | } else { | ||
| 430 | Poll::Pending | ||
| 431 | } | ||
| 432 | }) | ||
| 433 | } | ||
| 434 | } | ||
| 435 | |||
| 436 | impl<'d, T: Instance, Dir> Endpoint<'d, T, Dir> { | ||
| 437 | async fn wait_data_ready(&mut self) -> Result<(), ()> | ||
| 438 | where | ||
| 439 | Dir: EndpointDir, | ||
| 440 | { | ||
| 441 | let i = self.info.addr.index(); | ||
| 442 | assert!(i != 0); | ||
| 443 | poll_fn(|cx| { | ||
| 444 | Dir::waker(i).register(cx.waker()); | ||
| 445 | let r = READY_ENDPOINTS.load(Ordering::Acquire); | ||
| 446 | if !Dir::is_enabled(T::regs(), i) { | ||
| 447 | Poll::Ready(Err(())) | ||
| 448 | } else if r & Dir::mask(i) != 0 { | ||
| 449 | Poll::Ready(Ok(())) | ||
| 450 | } else { | ||
| 451 | Poll::Pending | ||
| 452 | } | ||
| 453 | }) | ||
| 454 | .await?; | ||
| 455 | |||
| 456 | // Mark as not ready | ||
| 457 | READY_ENDPOINTS.fetch_and(!Dir::mask(i), Ordering::AcqRel); | ||
| 458 | |||
| 459 | Ok(()) | ||
| 460 | } | ||
| 361 | } | 461 | } |
| 362 | 462 | ||
| 363 | unsafe fn read_dma<T: Instance>(i: usize, buf: &mut [u8]) -> Result<usize, ReadError> { | 463 | unsafe fn read_dma<T: Instance>(i: usize, buf: &mut [u8]) -> Result<usize, ReadError> { |
| @@ -449,20 +549,9 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 449 | let i = self.info.addr.index(); | 549 | let i = self.info.addr.index(); |
| 450 | assert!(i != 0); | 550 | assert!(i != 0); |
| 451 | 551 | ||
| 452 | // Wait until ready | 552 | self.wait_data_ready() |
| 453 | poll_fn(|cx| { | 553 | .await |
| 454 | EP_OUT_WAKERS[i - 1].register(cx.waker()); | 554 | .map_err(|_| ReadError::Disabled)?; |
| 455 | let r = READY_ENDPOINTS.load(Ordering::Acquire); | ||
| 456 | if r & (1 << (i + 16)) != 0 { | ||
| 457 | Poll::Ready(()) | ||
| 458 | } else { | ||
| 459 | Poll::Pending | ||
| 460 | } | ||
| 461 | }) | ||
| 462 | .await; | ||
| 463 | |||
| 464 | // Mark as not ready | ||
| 465 | READY_ENDPOINTS.fetch_and(!(1 << (i + 16)), Ordering::AcqRel); | ||
| 466 | 555 | ||
| 467 | unsafe { read_dma::<T>(i, buf) } | 556 | unsafe { read_dma::<T>(i, buf) } |
| 468 | } | 557 | } |
| @@ -477,20 +566,9 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 477 | let i = self.info.addr.index(); | 566 | let i = self.info.addr.index(); |
| 478 | assert!(i != 0); | 567 | assert!(i != 0); |
| 479 | 568 | ||
| 480 | // Wait until ready. | 569 | self.wait_data_ready() |
| 481 | poll_fn(|cx| { | 570 | .await |
| 482 | EP_IN_WAKERS[i - 1].register(cx.waker()); | 571 | .map_err(|_| WriteError::Disabled)?; |
| 483 | let r = READY_ENDPOINTS.load(Ordering::Acquire); | ||
| 484 | if r & (1 << i) != 0 { | ||
| 485 | Poll::Ready(()) | ||
| 486 | } else { | ||
| 487 | Poll::Pending | ||
| 488 | } | ||
| 489 | }) | ||
| 490 | .await; | ||
| 491 | |||
| 492 | // Mark as not ready | ||
| 493 | READY_ENDPOINTS.fetch_and(!(1 << i), Ordering::AcqRel); | ||
| 494 | 572 | ||
| 495 | unsafe { write_dma::<T>(i, buf) } | 573 | unsafe { write_dma::<T>(i, buf) } |
| 496 | 574 | ||
