ehcid: P0-B1 — xhcid-compat scheme paths + auto-spawn class drivers
Add xhcid-compatible path aliases to the EHCI scheme handler so that
class daemons (usbhubd, usbhidd, usbscsid) can successfully open an
XhciClientHandle on scheme "usb".
resolve_root_path / resolve_port_child:
"descriptors" → aliases "descriptor"
"request" → aliases "control"
"attach" → new write-only stub (logs port attach)
"endpoints" → new stub (resolves to PortDir so openat succeeds;
child reads/writes return empty, enough for
class daemon polling to work)
Directory listing updated with the new entries.
After device enumeration (setup_port_device), call
usb_core::spawn::spawn_class_driver_for_port to auto-spawn the
matching class daemon. HID (0x03), Mass Storage (0x08), and Hub
(0x09) are mapped to their respective binaries.
This is P0-B1 from USB-IMPLEMENTATION-PLAN.md v2. Real endpoint
transfer through the Endpoints stub is follow-up work (P0-B1-compat).
This commit is contained in:
@@ -113,6 +113,10 @@ enum HandleKind {
|
||||
Descriptor { port: usize },
|
||||
Control { port: usize },
|
||||
Config { port: usize },
|
||||
/// xhcid-compat: signals a class driver attached to this port (write-only stub)
|
||||
Attach { port: usize },
|
||||
/// xhcid-compat: endpoint transfer handle (stub — always returns Ok(0))
|
||||
Endpoints { port: usize },
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -562,6 +566,24 @@ impl EhciController {
|
||||
|
||||
self.ports[port].device = Some(device);
|
||||
self.ports[port].last_error = None;
|
||||
|
||||
// P0-B1: auto-spawn class drivers (usbhubd, usbhidd, usbscsid)
|
||||
// for devices enumerated on this port. The class daemons will open
|
||||
// an XhciClientHandle on scheme "usb", which our compat aliases
|
||||
// (descriptors, request, attach, endpoints) now serve.
|
||||
if let Some(ref dev) = self.ports[port].device {
|
||||
if !dev.device_descriptor.is_empty() {
|
||||
usb_core::spawn::spawn_class_driver_for_port(
|
||||
dev.device_class,
|
||||
dev.device_subclass,
|
||||
dev.device_protocol,
|
||||
"usb",
|
||||
&format!("{}", port + 1),
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1126,9 +1148,15 @@ impl EhciScheme {
|
||||
match (parts.next(), parts.next()) {
|
||||
(None, None) => Ok(HandleKind::PortDir { port }),
|
||||
(Some("status"), None) => Ok(HandleKind::Status { port }),
|
||||
(Some("descriptor"), None) => Ok(HandleKind::Descriptor { port }),
|
||||
(Some("control"), None) => Ok(HandleKind::Control { port }),
|
||||
(Some("descriptor"), None) | (Some("descriptors"), None) => {
|
||||
Ok(HandleKind::Descriptor { port })
|
||||
}
|
||||
(Some("control"), None) | (Some("request"), None) => {
|
||||
Ok(HandleKind::Control { port })
|
||||
}
|
||||
(Some("config"), None) => Ok(HandleKind::Config { port }),
|
||||
(Some("attach"), None) => Ok(HandleKind::Attach { port }),
|
||||
(Some("endpoints"), Some(_)) => Ok(HandleKind::Endpoints { port }),
|
||||
_ => Err(SysError::new(ENOENT)),
|
||||
}
|
||||
}
|
||||
@@ -1136,9 +1164,11 @@ impl EhciScheme {
|
||||
fn resolve_port_child(&self, port: usize, path: &str) -> SysResult<HandleKind> {
|
||||
match path {
|
||||
"status" => Ok(HandleKind::Status { port }),
|
||||
"descriptor" => Ok(HandleKind::Descriptor { port }),
|
||||
"control" => Ok(HandleKind::Control { port }),
|
||||
"descriptor" | "descriptors" => Ok(HandleKind::Descriptor { port }),
|
||||
"control" | "request" => Ok(HandleKind::Control { port }),
|
||||
"config" => Ok(HandleKind::Config { port }),
|
||||
"attach" => Ok(HandleKind::Attach { port }),
|
||||
"endpoints" => Ok(HandleKind::PortDir { port }), // open as O_DIRECTORY, then openat into child
|
||||
_ => Err(SysError::new(ENOENT)),
|
||||
}
|
||||
}
|
||||
@@ -1257,11 +1287,12 @@ impl EhciScheme {
|
||||
|
||||
let handle = self.handle(id)?;
|
||||
match &handle.kind {
|
||||
HandleKind::PortDir { .. } => Ok(b"status\ndescriptor\ncontrol\nconfig\n".to_vec()),
|
||||
HandleKind::PortDir { .. } => Ok(b"status\ndescriptor\ndescriptors\ncontrol\nrequest\nconfig\nattach\nendpoints\n".to_vec()),
|
||||
HandleKind::Status { port } => self.status_bytes(*port),
|
||||
HandleKind::Descriptor { port } => self.descriptor_bytes(*port),
|
||||
HandleKind::Control { .. } => Ok(handle.response.clone()),
|
||||
HandleKind::Config { port } => self.config_bytes(*port),
|
||||
HandleKind::Attach { .. } | HandleKind::Endpoints { .. } => Ok(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1279,6 +1310,8 @@ impl EhciScheme {
|
||||
}
|
||||
HandleKind::Control { port } => format!("{SCHEME_NAME}:/port{}/control", port + 1),
|
||||
HandleKind::Config { port } => format!("{SCHEME_NAME}:/port{}/config", port + 1),
|
||||
HandleKind::Attach { port } => format!("{SCHEME_NAME}:/port{}/attach", port + 1),
|
||||
HandleKind::Endpoints { port } => format!("{SCHEME_NAME}:/port{}/endpoints", port + 1),
|
||||
};
|
||||
Ok(path)
|
||||
}
|
||||
@@ -1362,6 +1395,11 @@ impl SchemeSync for EhciScheme {
|
||||
}
|
||||
Ok(buf.len())
|
||||
}
|
||||
HandleKind::Attach { port } => {
|
||||
log::info!("ehcid: class driver attached to port {}", port + 1);
|
||||
Ok(buf.len())
|
||||
}
|
||||
HandleKind::Endpoints { .. } => Ok(buf.len()),
|
||||
_ => Err(SysError::new(EROFS)),
|
||||
}
|
||||
}
|
||||
@@ -1378,7 +1416,10 @@ impl SchemeSync for EhciScheme {
|
||||
match self.handle(id)?.kind {
|
||||
HandleKind::PortDir { .. } => MODE_DIR | 0o755,
|
||||
HandleKind::Status { .. } | HandleKind::Descriptor { .. } => MODE_FILE | 0o444,
|
||||
HandleKind::Control { .. } | HandleKind::Config { .. } => MODE_FILE | 0o644,
|
||||
HandleKind::Control { .. }
|
||||
| HandleKind::Config { .. }
|
||||
| HandleKind::Attach { .. }
|
||||
| HandleKind::Endpoints { .. } => MODE_FILE | 0o644,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user