recipes: remove remaining stale duplicate manifests + driver-manager stale src/

Completes the stale-tree cleanup: redox-driver-core/Cargo.toml (left
target-less after the src/ removal, breaking cargo workspace search),
driver-manager/Cargo.toml and driver-manager/src/*.rs (Jul-10 duplicate
sources whose exec.rs predates the live tree's P0-3 removal). Live
trees are */source/.
This commit is contained in:
2026-07-23 22:12:37 +09:00
parent f9e153f0fc
commit 2e9c746745
6 changed files with 0 additions and 642 deletions
@@ -1,14 +0,0 @@
[package]
name = "redox-driver-core"
version = "0.1.0"
edition = "2024"
description = "Core device-model traits and orchestration for Red Bear drivers"
[features]
default = ["std"]
alloc = []
std = ["alloc"]
hotplug = []
[dependencies]
hashbrown = { version = "0.15", default-features = false, features = ["default-hasher"] }
@@ -1,18 +0,0 @@
[package]
name = "driver-manager"
version = "0.1.0"
edition = "2024"
description = "Device driver manager with deferred and async probing"
[[bin]]
name = "driver-manager"
path = "src/main.rs"
[dependencies]
redox-driver-core = { path = "../../drivers/redox-driver-core" }
redox-driver-pci = { path = "../../drivers/redox-driver-pci" }
pcid_interface = { path = "../../../../local/sources/base/drivers/pcid", package = "pcid" }
redox_syscall = { path = "../../../../local/sources/syscall" }
log = "0.4"
toml = "0.8"
serde = { version = "1", features = ["derive"] }
@@ -1,334 +0,0 @@
use std::collections::HashMap;
use std::fs::{self, File, OpenOptions};
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
use std::path::Path;
use std::process::Command;
use std::string::String;
use std::sync::Mutex;
use std::vec::Vec;
use pcid_interface::PciFunctionHandle;
use redox_driver_core::device::DeviceInfo;
use redox_driver_core::driver::{Driver, DriverError, ProbeResult};
use redox_driver_core::params::{DriverParams, ParamValue};
use redox_driver_core::r#match::DriverMatch;
use serde::Deserialize;
#[derive(Debug)]
struct SpawnedDriver {
pid: u32,
bind_handle: File,
}
#[derive(Debug)]
pub struct DriverConfig {
pub name: String,
pub description: String,
pub priority: i32,
pub command: Vec<String>,
pub matches: Vec<DriverMatch>,
spawned: Mutex<HashMap<String, SpawnedDriver>>,
}
impl Clone for DriverConfig {
fn clone(&self) -> Self {
DriverConfig {
name: self.name.clone(),
description: self.description.clone(),
priority: self.priority,
command: self.command.clone(),
matches: self.matches.clone(),
spawned: Mutex::new(HashMap::new()),
}
}
}
#[derive(Deserialize)]
struct RawDriverMatch {
vendor: Option<u16>,
device: Option<u16>,
class: Option<u8>,
subclass: Option<u8>,
prog_if: Option<u8>,
subsystem_vendor: Option<u16>,
subsystem_device: Option<u16>,
}
impl From<RawDriverMatch> for DriverMatch {
fn from(r: RawDriverMatch) -> Self {
DriverMatch {
vendor: r.vendor,
device: r.device,
class: r.class,
subclass: r.subclass,
prog_if: r.prog_if,
subsystem_vendor: r.subsystem_vendor,
subsystem_device: r.subsystem_device,
}
}
}
impl DriverConfig {
pub fn load_all(dir: &str) -> Result<Vec<DriverConfig>, String> {
let entries = fs::read_dir(dir).map_err(|e| format!("read_dir failed: {}", e))?;
let mut configs = Vec::new();
for entry in entries {
let entry = entry.map_err(|e| format!("entry error: {}", e))?;
let path = entry.path();
if !path.is_file() {
continue;
}
let data = fs::read_to_string(&path)
.map_err(|e| format!("read {} failed: {}", path.display(), e))?;
let parsed: RawDriverToml = toml::from_str(&data)
.map_err(|e| format!("parse {} failed: {}", path.display(), e))?;
for driver in parsed.driver {
let matches: Vec<DriverMatch> = driver.r#match.into_iter().map(DriverMatch::from).collect();
configs.push(DriverConfig {
name: driver.name,
description: driver.description,
priority: driver.priority,
command: driver.command,
matches,
spawned: Mutex::new(HashMap::new()),
});
}
}
configs.sort_by(|a, b| b.priority.cmp(&a.priority));
Ok(configs)
}
}
fn pci_device_path(info: &DeviceInfo) -> String {
if info.raw_path.starts_with("/scheme/pci/") {
info.raw_path.clone()
} else {
format!("/scheme/pci/{}", info.id.path)
}
}
fn claim_pci_device(info: &DeviceInfo) -> Result<(String, File), ProbeResult> {
let device_path = pci_device_path(info);
let bind_path = format!("{}/bind", device_path);
match OpenOptions::new().read(true).write(true).open(&bind_path) {
Ok(bind_handle) => Ok((device_path, bind_handle)),
Err(err) => match err.raw_os_error() {
Some(code) if code == syscall::EALREADY as i32 || code == 114 => {
log::debug!("device {} already claimed via {}", info.id.path, bind_path);
Err(ProbeResult::NotSupported)
}
_ => Err(ProbeResult::Deferred {
reason: format!("bind {} failed: {}", bind_path, err),
}),
},
}
}
fn open_pcid_channel(device_path: &str) -> Result<OwnedFd, ProbeResult> {
let mut handle = match PciFunctionHandle::connect_by_path(Path::new(device_path)) {
Ok(handle) => handle,
Err(err) => {
return Err(ProbeResult::Deferred {
reason: format!("open channel for {} failed: {}", device_path, err),
});
}
};
handle.enable_device();
let channel_fd = handle.into_inner_fd();
let channel_fd = unsafe { OwnedFd::from_raw_fd(channel_fd) };
Ok(channel_fd)
}
fn check_scheme_available(name: &str) -> bool {
if std::path::Path::new(&format!("/scheme/{}", name)).exists() {
return true;
}
false
}
impl Driver for DriverConfig {
fn name(&self) -> &str {
&self.name
}
fn description(&self) -> &str {
&self.description
}
fn priority(&self) -> i32 {
self.priority
}
fn match_table(&self) -> &[DriverMatch] {
&self.matches
}
fn probe(&self, info: &DeviceInfo) -> ProbeResult {
let device_key = info.id.path.clone();
{
let spawned = self.spawned.lock().unwrap();
if spawned.contains_key(&device_key) {
log::debug!("driver {} already bound to {}", self.name, device_key);
return ProbeResult::Bound;
}
}
if self.command.is_empty() {
return ProbeResult::Fatal {
reason: String::from("empty command"),
};
}
let actual_path = if self.command[0].starts_with('/') {
self.command[0].clone()
} else {
format!("/usr/lib/drivers/{}", self.command[0])
};
if !std::path::Path::new(&actual_path).exists() {
return ProbeResult::Deferred {
reason: format!("driver binary not found: {}", actual_path),
};
}
let deps = guess_dependencies(&self.name);
for dep in &deps {
if !check_scheme_available(dep) {
return ProbeResult::Deferred {
reason: format!("dependency scheme not ready: {}", dep),
};
}
}
log::info!("probing {} with driver {}", device_key, self.name);
let (device_path, bind_handle) = match claim_pci_device(info) {
Ok(claimed) => claimed,
Err(result) => return result,
};
let channel_fd = match open_pcid_channel(&device_path) {
Ok(channel_fd) => channel_fd,
Err(result) => return result,
};
let mut cmd = Command::new(&actual_path);
for arg in &self.command[1..] {
cmd.arg(arg);
}
cmd.env("PCID_CLIENT_CHANNEL", channel_fd.as_raw_fd().to_string());
cmd.env("PCID_DEVICE_PATH", &device_path);
match cmd.spawn() {
Ok(child) => {
let pid = child.id();
log::info!(
"driver {} spawned (pid {}) for device {}",
self.name, pid, device_key
);
let mut spawned = self.spawned.lock().unwrap();
spawned.insert(device_key, SpawnedDriver { pid, bind_handle });
ProbeResult::Bound
}
Err(e) => ProbeResult::Fatal {
reason: format!("spawn failed: {}", e),
},
}
}
fn remove(&self, info: &DeviceInfo) -> Result<(), DriverError> {
let device_key = info.id.path.clone();
let binding = {
let mut spawned = self.spawned.lock().unwrap();
spawned.remove(&device_key)
};
match binding {
Some(binding) => {
let bind_fd = binding.bind_handle.as_raw_fd();
log::info!(
"unbound: device {} from driver {} (pid {}, bind fd {})",
device_key,
self.name,
binding.pid,
bind_fd
);
Ok(())
}
_ => {
log::warn!("driver {} not bound to device {}", self.name, device_key);
Err(DriverError::Other("not bound"))
}
}
}
fn params(&self) -> DriverParams {
let mut p = DriverParams::new();
p.define("enabled", "Whether this driver is active", ParamValue::Bool(true), true);
p.define(
"priority",
"Probe priority (higher = earlier)",
ParamValue::Int(self.priority as i64),
false,
);
p
}
}
fn guess_dependencies(driver_name: &str) -> Vec<String> {
match driver_name {
"xhcid" | "usbhubd" | "usbctl" | "usbhidd" | "usbscsid" => {
vec![String::from("pci")]
}
"nvmed" | "ahcid" | "ided" | "virtio-blkd" => {
vec![String::from("pci")]
}
"e1000d" | "rtl8168d" | "rtl8139d" | "ixgbed" | "virtio-netd" => {
vec![String::from("pci")]
}
"vesad" | "virtio-gpud" | "redox-drm" => {
vec![String::from("pci")]
}
"ihdad" | "ac97d" | "sb16d" => {
vec![String::from("pci")]
}
"ps2d" => vec![String::from("serio")],
"i2c-hidd" => vec![String::from("i2c")],
"dw-acpi-i2cd" | "amd-mp2-i2cd" | "intel-lpss-i2cd" => {
vec![String::from("acpi"), String::from("i2c")]
}
_ => vec![String::from("pci")],
}
}
#[derive(Deserialize)]
struct RawDriverToml {
driver: Vec<RawDriverEntry>,
}
#[derive(Deserialize)]
struct RawDriverEntry {
name: String,
#[serde(default)]
description: String,
#[serde(default)]
priority: i32,
#[serde(default)]
command: Vec<String>,
#[serde(rename = "match")]
r#match: Vec<RawDriverMatch>,
}
@@ -1,18 +0,0 @@
use std::process::Command;
#[allow(dead_code)]
pub fn spawn_driver(command: &[String]) -> Result<std::process::Child, std::io::Error> {
if command.is_empty() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"empty command",
));
}
let mut cmd = Command::new(&command[0]);
for arg in &command[1..] {
cmd.arg(arg);
}
cmd.spawn()
}
@@ -1,74 +0,0 @@
use std::thread;
use std::time::Duration;
use std::sync::{Arc, Mutex};
use redox_driver_core::manager::DeviceManager;
use redox_driver_core::manager::ProbeEvent;
use redox_driver_core::driver::ProbeResult;
pub fn run_hotplug_loop(
manager: Arc<Mutex<DeviceManager>>,
poll_interval_ms: u64,
) {
log::info!("hotplug: starting event loop ({} ms poll)", poll_interval_ms);
loop {
thread::sleep(Duration::from_millis(poll_interval_ms));
let events = {
let mut mgr = manager.lock().unwrap();
mgr.enumerate()
};
for event in &events {
match event {
ProbeEvent::ProbeCompleted { device, driver_name, result } => {
match result {
ProbeResult::Bound => {
log::info!("hotplug: bound {} -> {}", device.path, driver_name);
}
ProbeResult::Deferred { reason } => {
log::info!(
"hotplug: deferred {} -> {} ({})",
device.path,
driver_name,
reason
);
}
ProbeResult::Fatal { reason } => {
log::error!(
"hotplug: fatal {} -> {} ({})",
device.path,
driver_name,
reason
);
}
_ => {}
}
}
ProbeEvent::NoDriverFound { device } => {
log::debug!("hotplug: no driver for new device {}", device.path);
}
_ => {}
}
}
let retry_events = {
let mut mgr = manager.lock().unwrap();
mgr.retry_deferred()
};
let mut resolved = 0usize;
for event in &retry_events {
if let ProbeEvent::ProbeCompleted { result, .. } = event {
if *result == ProbeResult::Bound {
resolved += 1;
}
}
}
if resolved > 0 {
log::info!("hotplug: resolved {} deferred probes", resolved);
}
}
}
@@ -1,184 +0,0 @@
mod config;
mod exec;
mod hotplug;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};
use std::{process, env};
use redox_driver_core::manager::{DeviceManager, ManagerConfig, ProbeEvent};
use redox_driver_core::driver::ProbeResult;
use redox_driver_pci::PciBus;
use config::DriverConfig;
struct StderrLogger;
impl log::Log for StderrLogger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
metadata.level() <= log::Level::Info
}
fn log(&self, record: &log::Record) {
if self.enabled(record.metadata()) {
eprintln!("[{}] driver-manager: {}", record.level(), record.args());
}
}
fn flush(&self) {}
}
fn run_enumeration(
manager: &Arc<Mutex<DeviceManager>>,
) -> (usize, usize) {
let events = {
let mut mgr = manager.lock().unwrap();
mgr.enumerate()
};
let mut bound = 0usize;
let mut deferred = 0usize;
let mut durations: Vec<u128> = Vec::new();
for event in &events {
match event {
ProbeEvent::ProbeCompleted { device, driver_name, result } => {
let start = Instant::now();
match result {
ProbeResult::Bound => {
let duration = start.elapsed();
durations.push(duration.as_millis());
log::info!("probed: {} -> {} ({}ms)", device.path, driver_name, duration.as_millis());
log::info!("bound: {} -> {}", device.path, driver_name);
bound += 1;
}
ProbeResult::Deferred { reason } => {
let duration = start.elapsed();
log::info!("probed: {} -> {} ({}ms)", device.path, driver_name, duration.as_millis());
log::info!("deferred: {} -> {} ({})", device.path, driver_name, reason);
deferred += 1;
}
ProbeResult::Fatal { reason } => {
let duration = start.elapsed();
log::info!("probed: {} -> {} ({}ms)", device.path, driver_name, duration.as_millis());
log::error!("fatal: {} -> {} ({})", device.path, driver_name, reason);
}
_ => {}
}
}
ProbeEvent::BusEnumerated { bus, device_count } => {
log::info!("bus {} enumerated {} device(s)", bus, device_count);
}
_ => {}
}
}
if !durations.is_empty() {
let sum: u128 = durations.iter().sum();
let avg = sum / durations.len() as u128;
let max = *durations.iter().max().unwrap_or(&0);
log::info!("probe summary: {} drivers, avg {}ms, max {}ms", durations.len(), avg, max);
}
(bound, deferred)
}
fn main() {
log::set_logger(&StderrLogger).ok();
log::set_max_level(log::LevelFilter::Info);
let args: Vec<String> = env::args().collect();
let initfs = args.iter().any(|a| a == "--initfs");
let hotplug_mode = args.iter().any(|a| a == "--hotplug");
let config_dir = if initfs {
"/scheme/initfs/lib/drivers.d"
} else {
"/lib/drivers.d"
};
let driver_configs = match DriverConfig::load_all(config_dir) {
Ok(c) => c,
Err(e) => {
log::error!("failed to load driver configs: {}", e);
process::exit(1);
}
};
if driver_configs.is_empty() {
log::warn!("no driver configs found in {}", config_dir);
process::exit(0);
}
log::info!("loaded {} driver config(s)", driver_configs.len());
let manager_config = ManagerConfig {
max_concurrent_probes: 4,
deferred_retry_ms: 500,
async_probe: true,
};
let manager = Arc::new(Mutex::new(DeviceManager::new(manager_config.clone())));
{
let mut mgr = manager.lock().unwrap();
mgr.register_bus(Box::new(PciBus::new()));
for dc in &driver_configs {
mgr.register_driver(Box::new(dc.clone()));
}
}
let mgr_clone = Arc::clone(&manager);
if manager_config.async_probe {
let handle = thread::spawn(move || {
let (bound, deferred) = run_enumeration(&mgr_clone);
log::info!("async enum: {} bound, {} deferred", bound, deferred);
});
let _ = handle.join();
} else {
let (bound, deferred) = run_enumeration(&manager);
log::info!("enum complete: {} bound, {} deferred", bound, deferred);
}
if hotplug_mode {
log::info!("entering hotplug event loop");
hotplug::run_hotplug_loop(manager.clone(), 2000);
return;
}
let max_retries = 30u32;
for retry in 1..=max_retries {
thread::sleep(Duration::from_millis(500));
let retry_events = {
let mut mgr = manager.lock().unwrap();
mgr.retry_deferred()
};
let mut remaining = 0;
let mut newly_bound = 0;
for event in &retry_events {
if let ProbeEvent::ProbeCompleted { result, .. } = event {
match result {
ProbeResult::Bound => newly_bound += 1,
ProbeResult::Deferred { .. } => remaining += 1,
_ => {}
}
}
}
if remaining == 0 {
log::info!("all deferred resolved after {} retries", retry);
return;
}
if newly_bound > 0 {
log::info!("retry #{}: {} new, {} remaining", retry, newly_bound, remaining);
}
}
log::warn!("deferred probe retry limit reached");
process::exit(0);
}