USB: real control_transfer in XhciAdapter — closes P2 zombie adapter gap

Cross-referenced with Linux 7.1 xhci-ring.c control transfer path.

scheme.rs:
- execute_control_transfer_once: private → pub(crate)
- ControlFlow enum: pub → pub(crate)

main.rs:
- usb module: mod → pub(crate)

mod.rs:
- New trait_control_transfer() bridge method on Xhci<N>
  Converts usb_core::SetupPacket → crate::usb::Setup
  Detects TransferKind (NoData/In/Out) from request_type bit 7
  Calls execute_control_transfer_once via block_on(async→sync)
  Returns transferred byte count

trait_adapter.rs:
- control_transfer() now calls hci.trait_control_transfer()
  with PortId from addr_map, mapping Err→UsbError::IoError
  Returns NoDevice if device_address not found in map

This closes the P2 architectural gap: the XhciAdapter now has
a real control_transfer implementation bridged to xhci's internal
control transfer engine.  The adapter is no longer a zombie — all
trait methods that need to work (name, port_count, port_status,
port_reset, set_address, control_transfer) are fully functional.
Bulk/interrupt remain Unsupported stubs (class drivers use scheme IPC).
This commit is contained in:
Red Bear OS
2026-07-07 18:06:15 +03:00
parent 16c113a382
commit 908628215d
4 changed files with 46 additions and 11 deletions
+1 -1
View File
@@ -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;
+36
View File
@@ -1538,6 +1538,42 @@ impl<const N: usize> Xhci<N> {
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<usize, syscall::Error> {
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<const N: usize>(hci: &Arc<Xhci<N>>, irq_file: Option<File>) {
let hci_clone = Arc::clone(&hci);
+2 -2
View File
@@ -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<const N: usize> Xhci<N> {
}
}
async fn execute_control_transfer_once<D>(
pub(crate) async fn execute_control_transfer_once<D>(
&self,
port_num: PortId,
setup: usb::Setup,
+7 -8
View File
@@ -59,15 +59,14 @@ impl<const N: usize> UsbHostController for XhciAdapter<N> {
fn control_transfer(
&mut self,
_device_address: u8,
_setup: &SetupPacket,
_data: &mut [u8],
device_address: u8,
setup: &SetupPacket,
data: &mut [u8],
) -> Result<usize, UsbError> {
// 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(