diff --git a/drivers/usb/xhcid/src/main.rs b/drivers/usb/xhcid/src/main.rs index 1e2693ddbd..7af2088260 100644 --- a/drivers/usb/xhcid/src/main.rs +++ b/drivers/usb/xhcid/src/main.rs @@ -47,7 +47,7 @@ use crate::xhci::{InterruptMethod, Xhci, XhciAdapter}; // mean anything. pub mod driver_interface; -mod usb; +pub(crate) mod usb; mod xhci; use usb_core::scheme_path; diff --git a/drivers/usb/xhcid/src/xhci/mod.rs b/drivers/usb/xhcid/src/xhci/mod.rs index 61df7452c0..0648a93b9f 100644 --- a/drivers/usb/xhcid/src/xhci/mod.rs +++ b/drivers/usb/xhcid/src/xhci/mod.rs @@ -1538,6 +1538,42 @@ impl Xhci { self.supported_protocol_speeds(port) .find(|speed| speed.psiv() == psiv) } + + pub(crate) fn trait_control_transfer( + &self, + port_id: PortId, + setup: &::usb_core::SetupPacket, + data: &mut [u8], + ) -> Result { + use crate::xhci::trb::TransferKind; + let is_in = setup.request_type & 0x80 != 0; + let setup_pkt = crate::usb::Setup { + kind: setup.request_type, + request: setup.request, + value: setup.value, + index: setup.index, + length: setup.length, + }; + let tk = if data.is_empty() { + TransferKind::NoData + } else if is_in { + TransferKind::In + } else { + TransferKind::Out + }; + let data_ptr = data.as_ptr() as usize; + let data_len = data.len(); + let _event = futures::executor::block_on( + self.execute_control_transfer_once(port_id, setup_pkt, tk, |trb, cycle| { + if tk == TransferKind::NoData { + return crate::xhci::scheme::ControlFlow::Break; + } + trb.data(data_ptr, data_len as u16, !is_in, cycle); + crate::xhci::scheme::ControlFlow::Break + }), + )?; + Ok(data_len) + } } pub fn start_irq_reactor(hci: &Arc>, irq_file: Option) { let hci_clone = Arc::clone(&hci); diff --git a/drivers/usb/xhcid/src/xhci/scheme.rs b/drivers/usb/xhcid/src/xhci/scheme.rs index 4ffbd1b417..28c350cde3 100644 --- a/drivers/usb/xhcid/src/xhci/scheme.rs +++ b/drivers/usb/xhcid/src/xhci/scheme.rs @@ -82,7 +82,7 @@ lazy_static! { Regex::new(r"^$").expect("Failed to create the regex for the top-level scheme"); } -pub enum ControlFlow { +pub(crate) enum ControlFlow { Continue, Break, } @@ -714,7 +714,7 @@ impl Xhci { } } - async fn execute_control_transfer_once( + pub(crate) async fn execute_control_transfer_once( &self, port_num: PortId, setup: usb::Setup, diff --git a/drivers/usb/xhcid/src/xhci/trait_adapter.rs b/drivers/usb/xhcid/src/xhci/trait_adapter.rs index 69b1682b46..926d73107a 100644 --- a/drivers/usb/xhcid/src/xhci/trait_adapter.rs +++ b/drivers/usb/xhcid/src/xhci/trait_adapter.rs @@ -59,15 +59,14 @@ impl UsbHostController for XhciAdapter { fn control_transfer( &mut self, - _device_address: u8, - _setup: &SetupPacket, - _data: &mut [u8], + device_address: u8, + setup: &SetupPacket, + data: &mut [u8], ) -> Result { - // xhci handles device enumeration internally via attach_device(). - // Class drivers communicate through the scheme IPC, not through - // this trait method. Real implementation deferred to the usb-core - // unified enumeration loop follow-up. - Err(UsbError::Unsupported) + let port_id = self.addr_map.get(&device_address).copied() + .ok_or(UsbError::NoDevice)?; + self.hci.trait_control_transfer(port_id, setup, data) + .map_err(|_| UsbError::IoError) } fn bulk_transfer(