diff options
| author | korbin <[email protected]> | 2025-07-13 22:44:48 -0600 |
|---|---|---|
| committer | korbin <[email protected]> | 2025-07-13 22:44:48 -0600 |
| commit | 93e2fdf51267f112adf0c14ccb7b46eb51edd48c (patch) | |
| tree | 44468210395e05189dee35f54e142aee7d2fcc51 | |
| parent | b666a88ab175043d711c97b67b5b4d3bf409f102 (diff) | |
consolidate endpoint validation logic in stm32
| -rw-r--r-- | embassy-stm32/src/usb/usb.rs | 78 |
1 files changed, 32 insertions, 46 deletions
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 05c28aceb..92c1601cc 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs | |||
| @@ -359,6 +359,34 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 359 | addr | 359 | addr |
| 360 | } | 360 | } |
| 361 | 361 | ||
| 362 | fn is_endpoint_available<D: Dir>(&self, index: usize, ep_type: EndpointType) -> bool { | ||
| 363 | if index == 0 && ep_type != EndpointType::Control { | ||
| 364 | return false; // EP0 is reserved for control | ||
| 365 | } | ||
| 366 | |||
| 367 | let ep = match self.alloc.get(index) { | ||
| 368 | Some(ep) => ep, | ||
| 369 | None => return false, | ||
| 370 | }; | ||
| 371 | |||
| 372 | let used = ep.used_out || ep.used_in; | ||
| 373 | |||
| 374 | if used && ep.ep_type == EndpointType::Isochronous { | ||
| 375 | // Isochronous endpoints are always double-buffered. | ||
| 376 | // Their corresponding endpoint/channel registers are forced to be unidirectional. | ||
| 377 | // Do not reuse this index. | ||
| 378 | // FIXME: Bulk endpoints can be double buffered, but are not in the current implementation. | ||
| 379 | return false; | ||
| 380 | } | ||
| 381 | |||
| 382 | let used_dir = match D::dir() { | ||
| 383 | Direction::Out => ep.used_out, | ||
| 384 | Direction::In => ep.used_in, | ||
| 385 | }; | ||
| 386 | |||
| 387 | !used || (ep.ep_type == ep_type && !used_dir) | ||
| 388 | } | ||
| 389 | |||
| 362 | fn alloc_endpoint<D: Dir>( | 390 | fn alloc_endpoint<D: Dir>( |
| 363 | &mut self, | 391 | &mut self, |
| 364 | ep_type: EndpointType, | 392 | ep_type: EndpointType, |
| @@ -376,57 +404,15 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 376 | 404 | ||
| 377 | let index = if let Some(addr) = ep_addr { | 405 | let index = if let Some(addr) = ep_addr { |
| 378 | // Use the specified endpoint address | 406 | // Use the specified endpoint address |
| 379 | let requested_index = addr.index(); | 407 | self.is_endpoint_available::<D>(addr.index(), ep_type) |
| 380 | if requested_index >= EP_COUNT { | 408 | .then_some(addr.index()) |
| 381 | return Err(EndpointAllocError); | ||
| 382 | } | ||
| 383 | if requested_index == 0 && ep_type != EndpointType::Control { | ||
| 384 | return Err(EndpointAllocError); // EP0 is reserved for control | ||
| 385 | } | ||
| 386 | |||
| 387 | let ep = &self.alloc[requested_index]; | ||
| 388 | let used = ep.used_out || ep.used_in; | ||
| 389 | if used && (ep.ep_type == EndpointType::Isochronous) { | ||
| 390 | // Isochronous endpoints are always double-buffered. | ||
| 391 | // Their corresponding endpoint/channel registers are forced to be unidirectional. | ||
| 392 | // Do not reuse this index. | ||
| 393 | return Err(EndpointAllocError); | ||
| 394 | } | ||
| 395 | |||
| 396 | let used_dir = match D::dir() { | ||
| 397 | Direction::Out => ep.used_out, | ||
| 398 | Direction::In => ep.used_in, | ||
| 399 | }; | ||
| 400 | if used && (ep.ep_type != ep_type || used_dir) { | ||
| 401 | return Err(EndpointAllocError); | ||
| 402 | } | ||
| 403 | |||
| 404 | Some((requested_index, &mut self.alloc[requested_index])) | ||
| 405 | } else { | 409 | } else { |
| 406 | // Find any available endpoint | 410 | // Find any available endpoint |
| 407 | self.alloc.iter_mut().enumerate().find(|(i, ep)| { | 411 | (0..self.alloc.len()).find(|&i| self.is_endpoint_available::<D>(i, ep_type)) |
| 408 | if *i == 0 && ep_type != EndpointType::Control { | ||
| 409 | return false; // reserved for control pipe | ||
| 410 | } | ||
| 411 | let used = ep.used_out || ep.used_in; | ||
| 412 | if used && (ep.ep_type == EndpointType::Isochronous) { | ||
| 413 | // Isochronous endpoints are always double-buffered. | ||
| 414 | // Their corresponding endpoint/channel registers are forced to be unidirectional. | ||
| 415 | // Do not reuse this index. | ||
| 416 | // FIXME: Bulk endpoints can be double buffered, but are not in the current implementation. | ||
| 417 | return false; | ||
| 418 | } | ||
| 419 | |||
| 420 | let used_dir = match D::dir() { | ||
| 421 | Direction::Out => ep.used_out, | ||
| 422 | Direction::In => ep.used_in, | ||
| 423 | }; | ||
| 424 | !used || (ep.ep_type == ep_type && !used_dir) | ||
| 425 | }) | ||
| 426 | }; | 412 | }; |
| 427 | 413 | ||
| 428 | let (index, ep) = match index { | 414 | let (index, ep) = match index { |
| 429 | Some(x) => x, | 415 | Some(i) => (i, &mut self.alloc[i]), |
| 430 | None => return Err(EndpointAllocError), | 416 | None => return Err(EndpointAllocError), |
| 431 | }; | 417 | }; |
| 432 | 418 | ||
