diff options
| -rw-r--r-- | embassy-nrf/src/usb.rs | 153 | ||||
| -rw-r--r-- | embassy-usb/src/driver.rs | 23 | ||||
| -rw-r--r-- | embassy-usb/src/lib.rs | 115 |
3 files changed, 161 insertions, 130 deletions
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs index 1057d880c..570d1c95b 100644 --- a/embassy-nrf/src/usb.rs +++ b/embassy-nrf/src/usb.rs | |||
| @@ -186,7 +186,6 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { | |||
| 186 | Ok(ControlPipe { | 186 | Ok(ControlPipe { |
| 187 | _phantom: PhantomData, | 187 | _phantom: PhantomData, |
| 188 | max_packet_size, | 188 | max_packet_size, |
| 189 | request: None, | ||
| 190 | }) | 189 | }) |
| 191 | } | 190 | } |
| 192 | 191 | ||
| @@ -502,72 +501,19 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 502 | pub struct ControlPipe<'d, T: Instance> { | 501 | pub struct ControlPipe<'d, T: Instance> { |
| 503 | _phantom: PhantomData<&'d mut T>, | 502 | _phantom: PhantomData<&'d mut T>, |
| 504 | max_packet_size: u16, | 503 | max_packet_size: u16, |
| 505 | request: Option<Request>, | ||
| 506 | } | ||
| 507 | |||
| 508 | impl<'d, T: Instance> ControlPipe<'d, T> { | ||
| 509 | async fn read(&mut self, buf: &mut [u8]) -> Result<usize, ReadError> { | ||
| 510 | let regs = T::regs(); | ||
| 511 | |||
| 512 | // Wait until ready | ||
| 513 | regs.intenset.write(|w| w.ep0datadone().set()); | ||
| 514 | poll_fn(|cx| { | ||
| 515 | EP_OUT_WAKERS[0].register(cx.waker()); | ||
| 516 | let regs = T::regs(); | ||
| 517 | if regs | ||
| 518 | .events_ep0datadone | ||
| 519 | .read() | ||
| 520 | .events_ep0datadone() | ||
| 521 | .bit_is_set() | ||
| 522 | { | ||
| 523 | Poll::Ready(()) | ||
| 524 | } else { | ||
| 525 | Poll::Pending | ||
| 526 | } | ||
| 527 | }) | ||
| 528 | .await; | ||
| 529 | |||
| 530 | unsafe { read_dma::<T>(0, buf) } | ||
| 531 | } | ||
| 532 | |||
| 533 | async fn write(&mut self, buf: &[u8], last_chunk: bool) { | ||
| 534 | let regs = T::regs(); | ||
| 535 | regs.events_ep0datadone.reset(); | ||
| 536 | unsafe { write_dma::<T>(0, buf) } | ||
| 537 | |||
| 538 | regs.shorts | ||
| 539 | .modify(|_, w| w.ep0datadone_ep0status().bit(last_chunk)); | ||
| 540 | |||
| 541 | regs.intenset.write(|w| w.ep0datadone().set()); | ||
| 542 | let res = with_timeout( | ||
| 543 | Duration::from_millis(10), | ||
| 544 | poll_fn(|cx| { | ||
| 545 | EP_IN_WAKERS[0].register(cx.waker()); | ||
| 546 | let regs = T::regs(); | ||
| 547 | if regs.events_ep0datadone.read().bits() != 0 { | ||
| 548 | Poll::Ready(()) | ||
| 549 | } else { | ||
| 550 | Poll::Pending | ||
| 551 | } | ||
| 552 | }), | ||
| 553 | ) | ||
| 554 | .await; | ||
| 555 | |||
| 556 | if res.is_err() { | ||
| 557 | error!("ControlPipe::write timed out."); | ||
| 558 | } | ||
| 559 | } | ||
| 560 | } | 504 | } |
| 561 | 505 | ||
| 562 | impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | 506 | impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { |
| 563 | type SetupFuture<'a> = impl Future<Output = Request> + 'a where Self: 'a; | 507 | type SetupFuture<'a> = impl Future<Output = Request> + 'a where Self: 'a; |
| 564 | type DataOutFuture<'a> = impl Future<Output = Result<usize, ReadError>> + 'a where Self: 'a; | 508 | type DataOutFuture<'a> = impl Future<Output = Result<usize, ReadError>> + 'a where Self: 'a; |
| 565 | type AcceptInFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; | 509 | type DataInFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; |
| 510 | |||
| 511 | fn max_packet_size(&self) -> usize { | ||
| 512 | usize::from(self.max_packet_size) | ||
| 513 | } | ||
| 566 | 514 | ||
| 567 | fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a> { | 515 | fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a> { |
| 568 | async move { | 516 | async move { |
| 569 | assert!(self.request.is_none()); | ||
| 570 | |||
| 571 | let regs = T::regs(); | 517 | let regs = T::regs(); |
| 572 | 518 | ||
| 573 | // Wait for SETUP packet | 519 | // Wait for SETUP packet |
| @@ -605,29 +551,65 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 605 | .write(|w| w.tasks_ep0rcvout().set_bit()); | 551 | .write(|w| w.tasks_ep0rcvout().set_bit()); |
| 606 | } | 552 | } |
| 607 | 553 | ||
| 608 | self.request = Some(req); | ||
| 609 | req | 554 | req |
| 610 | } | 555 | } |
| 611 | } | 556 | } |
| 612 | 557 | ||
| 613 | fn data_out<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::DataOutFuture<'a> { | 558 | fn data_out<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::DataOutFuture<'a> { |
| 614 | async move { | 559 | async move { |
| 615 | let req = unwrap!(self.request); | 560 | let regs = T::regs(); |
| 616 | assert!(req.direction == UsbDirection::Out); | 561 | |
| 617 | assert!(req.length > 0); | 562 | // Wait until ready |
| 618 | 563 | regs.intenset.write(|w| w.ep0datadone().set()); | |
| 619 | let req_length = usize::from(req.length); | 564 | poll_fn(|cx| { |
| 620 | let max_packet_size = usize::from(self.max_packet_size); | 565 | EP_OUT_WAKERS[0].register(cx.waker()); |
| 621 | let mut total = 0; | 566 | let regs = T::regs(); |
| 622 | for chunk in buf.chunks_mut(max_packet_size) { | 567 | if regs |
| 623 | let size = self.read(chunk).await?; | 568 | .events_ep0datadone |
| 624 | total += size; | 569 | .read() |
| 625 | if size < max_packet_size || total == req_length { | 570 | .events_ep0datadone() |
| 626 | break; | 571 | .bit_is_set() |
| 572 | { | ||
| 573 | Poll::Ready(()) | ||
| 574 | } else { | ||
| 575 | Poll::Pending | ||
| 627 | } | 576 | } |
| 577 | }) | ||
| 578 | .await; | ||
| 579 | |||
| 580 | unsafe { read_dma::<T>(0, buf) } | ||
| 581 | } | ||
| 582 | } | ||
| 583 | |||
| 584 | fn data_in<'a>(&'a mut self, buf: &'a [u8], last_packet: bool) -> Self::DataInFuture<'a> { | ||
| 585 | async move { | ||
| 586 | let regs = T::regs(); | ||
| 587 | regs.events_ep0datadone.reset(); | ||
| 588 | unsafe { | ||
| 589 | write_dma::<T>(0, buf); | ||
| 628 | } | 590 | } |
| 629 | 591 | ||
| 630 | Ok(total) | 592 | regs.shorts |
| 593 | .modify(|_, w| w.ep0datadone_ep0status().bit(last_packet)); | ||
| 594 | |||
| 595 | regs.intenset.write(|w| w.ep0datadone().set()); | ||
| 596 | let res = with_timeout( | ||
| 597 | Duration::from_millis(10), | ||
| 598 | poll_fn(|cx| { | ||
| 599 | EP_IN_WAKERS[0].register(cx.waker()); | ||
| 600 | let regs = T::regs(); | ||
| 601 | if regs.events_ep0datadone.read().bits() != 0 { | ||
| 602 | Poll::Ready(()) | ||
| 603 | } else { | ||
| 604 | Poll::Pending | ||
| 605 | } | ||
| 606 | }), | ||
| 607 | ) | ||
| 608 | .await; | ||
| 609 | |||
| 610 | if res.is_err() { | ||
| 611 | error!("ControlPipe::data_in timed out."); | ||
| 612 | } | ||
| 631 | } | 613 | } |
| 632 | } | 614 | } |
| 633 | 615 | ||
| @@ -636,37 +618,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | |||
| 636 | let regs = T::regs(); | 618 | let regs = T::regs(); |
| 637 | regs.tasks_ep0status | 619 | regs.tasks_ep0status |
| 638 | .write(|w| w.tasks_ep0status().bit(true)); | 620 | .write(|w| w.tasks_ep0status().bit(true)); |
| 639 | self.request = None; | ||
| 640 | } | ||
| 641 | |||
| 642 | fn accept_in<'a>(&'a mut self, buf: &'a [u8]) -> Self::AcceptInFuture<'a> { | ||
| 643 | async move { | ||
| 644 | #[cfg(feature = "defmt")] | ||
| 645 | debug!("control in accept {:x}", buf); | ||
| 646 | #[cfg(not(feature = "defmt"))] | ||
| 647 | debug!("control in accept {:x?}", buf); | ||
| 648 | let req = unwrap!(self.request); | ||
| 649 | assert!(req.direction == UsbDirection::In); | ||
| 650 | |||
| 651 | let req_len = usize::from(req.length); | ||
| 652 | let len = buf.len().min(req_len); | ||
| 653 | let need_zlp = len != req_len && (len % usize::from(self.max_packet_size)) == 0; | ||
| 654 | let mut chunks = buf[0..len] | ||
| 655 | .chunks(usize::from(self.max_packet_size)) | ||
| 656 | .chain(need_zlp.then(|| -> &[u8] { &[] })); | ||
| 657 | while let Some(chunk) = chunks.next() { | ||
| 658 | self.write(chunk, chunks.size_hint().0 == 0).await; | ||
| 659 | } | ||
| 660 | |||
| 661 | self.request = None; | ||
| 662 | } | ||
| 663 | } | 621 | } |
| 664 | 622 | ||
| 665 | fn reject(&mut self) { | 623 | fn reject(&mut self) { |
| 666 | debug!("control reject"); | 624 | debug!("control reject"); |
| 667 | let regs = T::regs(); | 625 | let regs = T::regs(); |
| 668 | regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(true)); | 626 | regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(true)); |
| 669 | self.request = None; | ||
| 670 | } | 627 | } |
| 671 | } | 628 | } |
| 672 | 629 | ||
diff --git a/embassy-usb/src/driver.rs b/embassy-usb/src/driver.rs index 1c6ba1f52..82b59bd1e 100644 --- a/embassy-usb/src/driver.rs +++ b/embassy-usb/src/driver.rs | |||
| @@ -137,30 +137,35 @@ pub trait ControlPipe { | |||
| 137 | type DataOutFuture<'a>: Future<Output = Result<usize, ReadError>> + 'a | 137 | type DataOutFuture<'a>: Future<Output = Result<usize, ReadError>> + 'a |
| 138 | where | 138 | where |
| 139 | Self: 'a; | 139 | Self: 'a; |
| 140 | type AcceptInFuture<'a>: Future<Output = ()> + 'a | 140 | type DataInFuture<'a>: Future<Output = ()> + 'a |
| 141 | where | 141 | where |
| 142 | Self: 'a; | 142 | Self: 'a; |
| 143 | 143 | ||
| 144 | /// Maximum packet size for the control pipe | ||
| 145 | fn max_packet_size(&self) -> usize; | ||
| 146 | |||
| 144 | /// Reads a single setup packet from the endpoint. | 147 | /// Reads a single setup packet from the endpoint. |
| 145 | fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a>; | 148 | fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a>; |
| 146 | 149 | ||
| 147 | /// Reads the data packet of a control write sequence. | 150 | /// Reads a DATA OUT packet into `buf` in response to a control write request. |
| 148 | /// | 151 | /// |
| 149 | /// Must be called after `setup()` for requests with `direction` of `Out` | 152 | /// Must be called after `setup()` for requests with `direction` of `Out` |
| 150 | /// and `length` greater than zero. | 153 | /// and `length` greater than zero. |
| 151 | /// | ||
| 152 | /// `buf.len()` must be greater than or equal to the request's `length`. | ||
| 153 | fn data_out<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::DataOutFuture<'a>; | 154 | fn data_out<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::DataOutFuture<'a>; |
| 154 | 155 | ||
| 155 | /// Accepts a control request. | 156 | /// Sends a DATA IN packet with `data` in response to a control read request. |
| 156 | fn accept(&mut self); | 157 | /// |
| 158 | /// If `last_packet` is true, the STATUS packet will be ACKed following the transfer of `data`. | ||
| 159 | fn data_in<'a>(&'a mut self, data: &'a [u8], last_packet: bool) -> Self::DataInFuture<'a>; | ||
| 157 | 160 | ||
| 158 | /// Accepts a control read request with `data`. | 161 | /// Accepts a control request. |
| 159 | /// | 162 | /// |
| 160 | /// `data.len()` must be less than or equal to the request's `length`. | 163 | /// Causes the STATUS packet for the current request to be ACKed. |
| 161 | fn accept_in<'a>(&'a mut self, data: &'a [u8]) -> Self::AcceptInFuture<'a>; | 164 | fn accept(&mut self); |
| 162 | 165 | ||
| 163 | /// Rejects a control request. | 166 | /// Rejects a control request. |
| 167 | /// | ||
| 168 | /// Sets a STALL condition on the pipe to indicate an error. | ||
| 164 | fn reject(&mut self); | 169 | fn reject(&mut self); |
| 165 | } | 170 | } |
| 166 | 171 | ||
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index 32b67a766..77a9c33be 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs | |||
| @@ -55,7 +55,7 @@ pub const MAX_INTERFACE_COUNT: usize = 4; | |||
| 55 | 55 | ||
| 56 | pub struct UsbDevice<'d, D: Driver<'d>> { | 56 | pub struct UsbDevice<'d, D: Driver<'d>> { |
| 57 | bus: D::Bus, | 57 | bus: D::Bus, |
| 58 | control: D::ControlPipe, | 58 | control: ControlPipe<D::ControlPipe>, |
| 59 | 59 | ||
| 60 | config: Config<'d>, | 60 | config: Config<'d>, |
| 61 | device_descriptor: &'d [u8], | 61 | device_descriptor: &'d [u8], |
| @@ -92,7 +92,10 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 92 | Self { | 92 | Self { |
| 93 | bus: driver, | 93 | bus: driver, |
| 94 | config, | 94 | config, |
| 95 | control, | 95 | control: ControlPipe { |
| 96 | control, | ||
| 97 | request: None, | ||
| 98 | }, | ||
| 96 | device_descriptor, | 99 | device_descriptor, |
| 97 | config_descriptor, | 100 | config_descriptor, |
| 98 | bos_descriptor, | 101 | bos_descriptor, |
| @@ -140,32 +143,19 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 140 | } | 143 | } |
| 141 | } | 144 | } |
| 142 | 145 | ||
| 143 | async fn control_in_accept_writer( | ||
| 144 | &mut self, | ||
| 145 | req: Request, | ||
| 146 | f: impl FnOnce(&mut DescriptorWriter), | ||
| 147 | ) { | ||
| 148 | let mut buf = [0; 256]; | ||
| 149 | let mut w = DescriptorWriter::new(&mut buf); | ||
| 150 | f(&mut w); | ||
| 151 | let pos = w.position().min(usize::from(req.length)); | ||
| 152 | self.control.accept_in(&buf[..pos]).await; | ||
| 153 | } | ||
| 154 | |||
| 155 | async fn handle_control_out(&mut self, req: Request) { | 146 | async fn handle_control_out(&mut self, req: Request) { |
| 156 | const CONFIGURATION_NONE_U16: u16 = CONFIGURATION_NONE as u16; | 147 | const CONFIGURATION_NONE_U16: u16 = CONFIGURATION_NONE as u16; |
| 157 | const CONFIGURATION_VALUE_U16: u16 = CONFIGURATION_VALUE as u16; | 148 | const CONFIGURATION_VALUE_U16: u16 = CONFIGURATION_VALUE as u16; |
| 158 | 149 | ||
| 159 | // If the request has a data state, we must read it. | 150 | // If the request has a data state, we must read it. |
| 160 | let data = if req.length > 0 { | 151 | let data = if req.length > 0 { |
| 161 | let size = match self.control.data_out(self.control_buf).await { | 152 | match self.control.data_out(self.control_buf).await { |
| 162 | Ok(size) => size, | 153 | Ok(data) => data, |
| 163 | Err(_) => { | 154 | Err(_) => { |
| 164 | warn!("usb: failed to read CONTROL OUT data stage."); | 155 | warn!("usb: failed to read CONTROL OUT data stage."); |
| 165 | return; | 156 | return; |
| 166 | } | 157 | } |
| 167 | }; | 158 | } |
| 168 | &self.control_buf[0..size] | ||
| 169 | } else { | 159 | } else { |
| 170 | &[] | 160 | &[] |
| 171 | }; | 161 | }; |
| @@ -315,10 +305,11 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 315 | descriptor_type::CONFIGURATION => self.control.accept_in(self.config_descriptor).await, | 305 | descriptor_type::CONFIGURATION => self.control.accept_in(self.config_descriptor).await, |
| 316 | descriptor_type::STRING => { | 306 | descriptor_type::STRING => { |
| 317 | if index == 0 { | 307 | if index == 0 { |
| 318 | self.control_in_accept_writer(req, |w| { | 308 | self.control |
| 319 | w.write(descriptor_type::STRING, &lang_id::ENGLISH_US.to_le_bytes()) | 309 | .accept_in_writer(req, |w| { |
| 320 | }) | 310 | w.write(descriptor_type::STRING, &lang_id::ENGLISH_US.to_le_bytes()); |
| 321 | .await | 311 | }) |
| 312 | .await | ||
| 322 | } else { | 313 | } else { |
| 323 | let s = match index { | 314 | let s = match index { |
| 324 | 1 => self.config.manufacturer, | 315 | 1 => self.config.manufacturer, |
| @@ -333,7 +324,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 333 | }; | 324 | }; |
| 334 | 325 | ||
| 335 | if let Some(s) = s { | 326 | if let Some(s) = s { |
| 336 | self.control_in_accept_writer(req, |w| w.string(s)).await; | 327 | self.control.accept_in_writer(req, |w| w.string(s)).await; |
| 337 | } else { | 328 | } else { |
| 338 | self.control.reject() | 329 | self.control.reject() |
| 339 | } | 330 | } |
| @@ -343,3 +334,81 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 343 | } | 334 | } |
| 344 | } | 335 | } |
| 345 | } | 336 | } |
| 337 | |||
| 338 | struct ControlPipe<C: driver::ControlPipe> { | ||
| 339 | control: C, | ||
| 340 | request: Option<Request>, | ||
| 341 | } | ||
| 342 | |||
| 343 | impl<C: driver::ControlPipe> ControlPipe<C> { | ||
| 344 | async fn setup(&mut self) -> Request { | ||
| 345 | assert!(self.request.is_none()); | ||
| 346 | let req = self.control.setup().await; | ||
| 347 | self.request = Some(req); | ||
| 348 | req | ||
| 349 | } | ||
| 350 | |||
| 351 | async fn data_out<'a>(&mut self, buf: &'a mut [u8]) -> Result<&'a [u8], ReadError> { | ||
| 352 | let req = self.request.unwrap(); | ||
| 353 | assert_eq!(req.direction, UsbDirection::Out); | ||
| 354 | assert!(req.length > 0); | ||
| 355 | let req_length = usize::from(req.length); | ||
| 356 | |||
| 357 | let max_packet_size = self.control.max_packet_size(); | ||
| 358 | let mut total = 0; | ||
| 359 | |||
| 360 | for chunk in buf.chunks_mut(max_packet_size) { | ||
| 361 | let size = self.control.data_out(chunk).await?; | ||
| 362 | total += size; | ||
| 363 | if size < max_packet_size || total == req_length { | ||
| 364 | break; | ||
| 365 | } | ||
| 366 | } | ||
| 367 | |||
| 368 | Ok(&buf[0..total]) | ||
| 369 | } | ||
| 370 | |||
| 371 | async fn accept_in(&mut self, buf: &[u8]) -> () { | ||
| 372 | #[cfg(feature = "defmt")] | ||
| 373 | debug!("control in accept {:x}", buf); | ||
| 374 | #[cfg(not(feature = "defmt"))] | ||
| 375 | debug!("control in accept {:x?}", buf); | ||
| 376 | let req = unwrap!(self.request); | ||
| 377 | assert!(req.direction == UsbDirection::In); | ||
| 378 | |||
| 379 | let req_len = usize::from(req.length); | ||
| 380 | let len = buf.len().min(req_len); | ||
| 381 | let max_packet_size = self.control.max_packet_size(); | ||
| 382 | let need_zlp = len != req_len && (len % usize::from(max_packet_size)) == 0; | ||
| 383 | |||
| 384 | let mut chunks = buf[0..len] | ||
| 385 | .chunks(max_packet_size) | ||
| 386 | .chain(need_zlp.then(|| -> &[u8] { &[] })); | ||
| 387 | |||
| 388 | while let Some(chunk) = chunks.next() { | ||
| 389 | self.control.data_in(chunk, chunks.size_hint().0 == 0).await; | ||
| 390 | } | ||
| 391 | |||
| 392 | self.request = None; | ||
| 393 | } | ||
| 394 | |||
| 395 | async fn accept_in_writer(&mut self, req: Request, f: impl FnOnce(&mut DescriptorWriter)) { | ||
| 396 | let mut buf = [0; 256]; | ||
| 397 | let mut w = DescriptorWriter::new(&mut buf); | ||
| 398 | f(&mut w); | ||
| 399 | let pos = w.position().min(usize::from(req.length)); | ||
| 400 | self.accept_in(&buf[..pos]).await; | ||
| 401 | } | ||
| 402 | |||
| 403 | fn accept(&mut self) { | ||
| 404 | assert!(self.request.is_some()); | ||
| 405 | self.control.accept(); | ||
| 406 | self.request = None; | ||
| 407 | } | ||
| 408 | |||
| 409 | fn reject(&mut self) { | ||
| 410 | assert!(self.request.is_some()); | ||
| 411 | self.control.reject(); | ||
| 412 | self.request = None; | ||
| 413 | } | ||
| 414 | } | ||
