diff --git a/drivers/hwd/src/backend/acpi.rs b/drivers/hwd/src/backend/acpi.rs --- a/drivers/hwd/src/backend/acpi.rs +++ b/drivers/hwd/src/backend/acpi.rs @@ -1,27 +1,36 @@ use amlserde::{AmlSerde, AmlSerdeValue}; -use std::{error::Error, fs, process::Command}; +use std::{error::Error, fs}; use super::Backend; pub struct AcpiBackend { - rxsdt: Vec, + _rxsdt: Vec, } impl Backend for AcpiBackend { fn new() -> Result> { let rxsdt = fs::read("/scheme/kernel.acpi/rxsdt")?; - // Spawn acpid - //TODO: pass rxsdt data to acpid? - #[allow(deprecated, reason = "we can't yet move this to init")] - daemon::Daemon::spawn(Command::new("acpid")); - - Ok(Self { rxsdt }) + Ok(Self { _rxsdt: rxsdt }) } fn probe(&mut self) -> Result<(), Box> { + let mut boot_critical_input_candidates = 0usize; + let mut thc_candidates = 0usize; + let mut non_hid_i2c_candidates = 0usize; + // Read symbols from acpi scheme - let entries = fs::read_dir("/scheme/acpi/symbols")?; + let entries = match fs::read_dir("/scheme/acpi/symbols") { + Ok(entries) => entries, + Err(err) + if err.kind() == std::io::ErrorKind::WouldBlock + || err.raw_os_error() == Some(11) => + { + log::debug!("hwd: ACPI symbols are not ready yet"); + return Ok(()); + } + Err(err) => return Err(Box::new(err)), + }; // TODO: Reimplement with getdents? let symbols_fd = libredox::Fd::open( "/scheme/acpi/symbols", @@ -100,12 +109,103 @@ "PNP0C0F" => "PCI interrupt link", "PNP0C50" => "I2C HID", "PNP0F13" => "PS/2 port for PS/2-style mouse", + "80860F41" | "808622C1" => "DesignWare I2C controller", + "AMDI0010" | "AMDI0019" | "AMDI0510" => "AMD laptop I2C controller", + "INT33C2" | "INT33C3" | "INT3432" | "INT3433" | "INTC10EF" => { + "Intel LPSS/SerialIO I2C controller" + } + "INT34C5" | "INTC1055" => "Intel GPIO controller", + "INTC1050" | "INTC1051" | "INTC1080" | "INTC1081" | "INTC1082" => { + "Intel THC companion (QuickI2C/QuickSPI path)" + } + _ if is_elan_touchpad_id(&id) => "ELAN touchpad (I2C/SMBus path)", + _ if is_cypress_touchpad_id(&id) => "Cypress/Trackpad (non-HID I2C path)", + _ if is_synaptics_rmi_id(&id) => "Synaptics RMI touchpad (I2C/SMBus path)", _ => "?", }; log::debug!("{}: {} ({})", name, id, what); + if is_boot_critical_i2c_surface(&id) { + boot_critical_input_candidates += 1; + log::info!("{}: {} is boot-critical for laptop input path", name, id); + } + if is_thc_companion(&id) { + thc_candidates += 1; + log::warn!( + "{}: {} indicates Intel THC path; DMA/report fast-path is not complete yet", + name, + id + ); + } + if is_non_hid_i2c_input_id(&id) { + non_hid_i2c_candidates += 1; + } } } } + + if boot_critical_input_candidates == 0 { + log::warn!( + "hwd: no ACPI boot-critical I2C input candidates found; built-in laptop input may require additional controller/device support" + ); + } else { + log::info!( + "hwd: ACPI input candidates: total={} thc={} non_hid_i2c={}", + boot_critical_input_candidates, + thc_candidates, + non_hid_i2c_candidates + ); + } + Ok(()) } } + +fn is_boot_critical_i2c_surface(id: &str) -> bool { + matches!( + id, + "PNP0C50" + | "ACPI0C50" + | "80860F41" + | "808622C1" + | "AMDI0010" + | "AMDI0019" + | "AMDI0510" + | "INT33C2" + | "INT33C3" + | "INT3432" + | "INT3433" + | "INTC10EF" + | "INT34C5" + | "INTC1055" + | "INTC1050" + | "INTC1051" + | "INTC1080" + | "INTC1081" + | "INTC1082" + ) || is_elan_touchpad_id(id) + || is_cypress_touchpad_id(id) + || is_synaptics_rmi_id(id) +} + +fn is_thc_companion(id: &str) -> bool { + matches!( + id, + "INTC1050" | "INTC1051" | "INTC1080" | "INTC1081" | "INTC1082" + ) +} + +fn is_elan_touchpad_id(id: &str) -> bool { + id.starts_with("ELAN") +} + +fn is_cypress_touchpad_id(id: &str) -> bool { + id.starts_with("CYAP") +} + +fn is_synaptics_rmi_id(id: &str) -> bool { + id.starts_with("SYNA") +} + +fn is_non_hid_i2c_input_id(id: &str) -> bool { + is_elan_touchpad_id(id) || is_cypress_touchpad_id(id) || is_synaptics_rmi_id(id) +} diff --git a/drivers/pcid-spawner/src/main.rs b/drivers/pcid-spawner/src/main.rs --- a/drivers/pcid-spawner/src/main.rs +++ b/drivers/pcid-spawner/src/main.rs @@ -1,11 +1,40 @@ +use std::env; use std::fs; use std::process::Command; +use std::thread; use anyhow::{anyhow, Context, Result}; use pcid_interface::config::Config; use pcid_interface::PciFunctionHandle; +fn strict_usb_boot() -> bool { + matches!( + env::var("REDBEAR_STRICT_USB_BOOT") + .ok() + .as_deref() + .map(str::to_ascii_lowercase) + .as_deref(), + Some("1" | "true" | "yes" | "on") + ) +} + +fn should_detach_in_initfs(initfs: bool, class: u8, subclass: u8, strict_usb_boot: bool) -> bool { + if !initfs { + return false; + } + + if class == 0x01 { + return false; + } + + if strict_usb_boot && class == 0x0C && subclass == 0x03 { + return false; + } + + true +} + fn main() -> Result<()> { let mut args = pico_args::Arguments::from_env(); let initfs = args.contains("--initfs"); @@ -30,6 +59,7 @@ } let config: Config = toml::from_str(&config_data)?; + let strict_usb_boot = strict_usb_boot(); for entry in fs::read_dir("/scheme/pci")? { let entry = entry.context("failed to get entry")?; @@ -87,14 +117,70 @@ log::info!("pcid-spawner: spawn {:?}", command); + let device_addr = handle.config().func.addr; + handle.enable_device(); let channel_fd = handle.into_inner_fd(); command.env("PCID_CLIENT_CHANNEL", channel_fd.to_string()); #[allow(deprecated, reason = "we can't yet move this to init")] - daemon::Daemon::spawn(command); - syscall::close(channel_fd as usize).unwrap(); + if should_detach_in_initfs( + initfs, + full_device_id.class, + full_device_id.subclass, + strict_usb_boot, + ) { + log::warn!( + "pcid-spawner: detached initfs spawn for {} to avoid blocking early boot", + device_addr + ); + + let device_addr = device_addr.to_string(); + thread::spawn(move || { + #[allow(deprecated, reason = "we can't yet move this to init")] + if let Err(err) = daemon::Daemon::spawn(command) { + log::error!( + "pcid-spawner: spawn/readiness failed for {}: {}", + device_addr, + err + ); + log::error!( + "pcid-spawner: {} remains enabled without a confirmed ready driver", + device_addr + ); + } + if let Err(err) = syscall::close(channel_fd as usize) { + log::error!( + "pcid-spawner: failed to close channel fd {} for {}: {}", + channel_fd, + device_addr, + err + ); + } + }); + } else { + #[allow(deprecated, reason = "we can't yet move this to init")] + if let Err(err) = daemon::Daemon::spawn(command) { + log::error!( + "pcid-spawner: spawn/readiness failed for {}: {}", + device_addr, + err + ); + log::error!( + "pcid-spawner: {} remains enabled without a confirmed ready driver", + device_addr + ); + } + if let Err(err) = syscall::close(channel_fd as usize) { + log::error!( + "pcid-spawner: failed to close channel fd {} for {}: {}", + channel_fd, + device_addr, + err + ); + } + } } Ok(()) diff --git a/drivers/pcid/src/main.rs b/drivers/pcid/src/main.rs --- a/drivers/pcid/src/main.rs +++ b/drivers/pcid/src/main.rs @@ -12,6 +12,7 @@ }; use redox_scheme::scheme::register_sync_scheme; use scheme_utils::Blocking; +use syscall::{sendfd, SendFdFlags}; use crate::cfg_access::Pcie; use pcid_interface::{FullDeviceId, LegacyInterruptLine, PciBar, PciFunction, PciRom}; @@ -262,14 +263,13 @@ let access_fd = socket .create_this_scheme_fd(0, access_id, syscall::O_RDWR, 0) .expect("failed to issue this resource"); - let access_bytes = access_fd.to_ne_bytes(); - let _ = register_pci - .call_wo( - &access_bytes, - syscall::CallFlags::WRITE | syscall::CallFlags::FD, - &[], - ) - .expect("failed to send pci_fd to acpid"); + sendfd( + register_pci.raw(), + access_fd as usize, + SendFdFlags::empty().bits(), + 0, + ) + .expect("failed to send pci_fd to acpid"); } Err(err) => { if err.errno() == libredox::errno::ENODEV {