diff --git a/usb-host/src/backend/kmod/transfer.rs b/usb-host/src/backend/kmod/transfer.rs index 2730255..7efe34d 100644 --- a/usb-host/src/backend/kmod/transfer.rs +++ b/usb-host/src/backend/kmod/transfer.rs @@ -3,6 +3,7 @@ use core::ptr::NonNull; use alloc::vec::Vec; use dma_api::DmaDirection; use usb_if::endpoint::TransferRequest; +use usb_if::err::TransferError; use usb_if::transfer::Direction; use crate::{ @@ -18,7 +19,7 @@ impl Transfer { kind: TransferKind, direction: Direction, buff: Option<(NonNull, usize)>, - ) -> Self { + ) -> Result { let dma_direction = match direction { Direction::In => DmaDirection::FromDevice, Direction::Out => DmaDirection::ToDevice, @@ -27,22 +28,25 @@ impl Transfer { let slice = unsafe { core::slice::from_raw_parts_mut(ptr.as_ptr(), len) }; Some( dma.map_single_array(slice, ALIGN, dma_direction) - .expect("DMA mapping failed"), + .map_err(|err| TransferError::Other(anyhow!("DMA mapping failed: {err}")))?, ) } else { None }; - Self { + Ok(Self { kind, direction, mapping, transfer_len: 0, iso_packet_actual_lengths: Vec::new(), - } + }) } - pub(crate) fn from_request(dma: &Kernel, request: TransferRequest) -> Self { + pub(crate) fn from_request( + dma: &Kernel, + request: TransferRequest, + ) -> Result { let (kind, direction, buffer) = request.into(); let buff = buffer.map(|buffer| (buffer.ptr, buffer.len)); Self::new(dma, kind, direction, buff) diff --git a/usb-host/src/backend/kmod/xhci/endpoint.rs b/usb-host/src/backend/kmod/xhci/endpoint.rs index 9e8d129..43a97c1 100644 --- a/usb-host/src/backend/kmod/xhci/endpoint.rs +++ b/usb-host/src/backend/kmod/xhci/endpoint.rs @@ -276,13 +276,28 @@ impl Endpoint { } Ok(()) } + + fn required_trbs_for_request(request: &TransferRequest) -> usize { + match request { + TransferRequest::Control { buffer, .. } => { + if buffer.is_some_and(|buffer| buffer.len > 0) { + 3 + } else { + 2 + } + } + TransferRequest::Bulk { .. } | TransferRequest::Interrupt { .. } => 1, + TransferRequest::Isochronous { packets, .. } => packets.len().max(1), + } + } } impl EndpointOp for Endpoint { fn submit_request(&mut self, request: TransferRequest) -> Result { - let transfer = Transfer::from_request(&self.kernel, request); - let required_trbs = Self::required_trbs(&transfer); + let required_trbs = Self::required_trbs_for_request(&request); self.ensure_ring_capacity(required_trbs)?; + let transfer = Transfer::from_request(&self.kernel, request)?; + debug_assert_eq!(required_trbs, Self::required_trbs(&transfer)); let mut data_bus_addr = 0; if transfer.buffer_len() > 0 {