From f7f2890f4e1ab3a65bc5e4963e706d3328771a5d Mon Sep 17 00:00:00 2001 From: vasilito Date: Tue, 7 Jul 2026 00:58:03 +0300 Subject: [PATCH] =?UTF-8?q?ehcid:=20P0-B1=20=E2=80=94=20xhcid-compat=20sch?= =?UTF-8?q?eme=20paths=20+=20auto-spawn=20class=20drivers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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). --- .../recipes/drivers/ehcid/source/src/main.rs | 53 ++++++++++++++++--- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/local/recipes/drivers/ehcid/source/src/main.rs b/local/recipes/drivers/ehcid/source/src/main.rs index 7a4cc4f0db..d5d004847b 100644 --- a/local/recipes/drivers/ehcid/source/src/main.rs +++ b/local/recipes/drivers/ehcid/source/src/main.rs @@ -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 { 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, } };