diff options
| author | alexmoon <[email protected]> | 2022-03-29 20:26:30 -0400 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-04-06 05:38:11 +0200 |
| commit | 77e0aca03b89ebc5f1e93b6c64b6c91ca10cedd1 (patch) | |
| tree | b0b5982f3daddafa7bc36362adcddeae11b07023 /embassy-usb/src/lib.rs | |
| parent | 1672fdc666188454a56b9369150e54420dc67078 (diff) | |
Move data chunking from the driver to the lib
Diffstat (limited to 'embassy-usb/src/lib.rs')
| -rw-r--r-- | embassy-usb/src/lib.rs | 115 |
1 files changed, 92 insertions, 23 deletions
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 | } | ||
