diff --git a/local/recipes/drivers/redox-driver-core/src/bus.rs b/local/recipes/drivers/redox-driver-core/src/bus.rs deleted file mode 100644 index 1ef64c80fb..0000000000 --- a/local/recipes/drivers/redox-driver-core/src/bus.rs +++ /dev/null @@ -1,37 +0,0 @@ -use alloc::vec::Vec; - -use crate::device::DeviceInfo; -#[cfg(feature = "hotplug")] -use crate::hotplug::HotplugSubscription; - -/// A hardware bus that can enumerate devices. -pub trait Bus: Send + Sync { - /// Returns a human-readable bus name such as `"pci"`, `"usb"`, or `"acpi"`. - fn name(&self) -> &str; - - /// Enumerates all devices currently visible on this bus. - /// - /// Implementations must be safe to call repeatedly so that the manager can perform - /// re-scans after topology changes or deferred-probe retries. - fn enumerate_devices(&self) -> Result, BusError>; - - /// Subscribes to bus hotplug notifications. - /// - /// The returned subscription is intentionally opaque so concrete bus implementations can - /// map it to a file descriptor, channel, or other event source. - #[cfg(feature = "hotplug")] - fn subscribe_hotplug(&self) -> Result; -} - -/// Errors produced by a [`Bus`] implementation. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum BusError { - /// The bus has not finished initializing and cannot currently enumerate devices. - NotReady, - /// A transport or I/O failure occurred while talking to the bus. - IoError, - /// The requested capability is not supported by this bus implementation. - Unsupported, - /// An implementation-specific static error message. - Other(&'static str), -} diff --git a/local/recipes/drivers/redox-driver-core/src/device.rs b/local/recipes/drivers/redox-driver-core/src/device.rs deleted file mode 100644 index 76f33a3fdf..0000000000 --- a/local/recipes/drivers/redox-driver-core/src/device.rs +++ /dev/null @@ -1,58 +0,0 @@ -use alloc::collections::BTreeMap; -use alloc::string::String; - -/// Unique identifier for a device on a specific bus. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct DeviceId { - /// The bus namespace for this device, such as `"pci"` or `"usb"`. - pub bus: String, - /// The bus-local path for the device, such as `"0000:00:02.0"` or `"1-2"`. - pub path: String, -} - -/// Information about a discovered device, used for driver matching and probing. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct DeviceInfo { - /// Stable device identifier within the manager. - pub id: DeviceId, - /// Optional vendor identifier reported by the bus or firmware. - pub vendor: Option, - /// Optional device identifier reported by the bus or firmware. - pub device: Option, - /// Optional base class code. - pub class: Option, - /// Optional subclass code. - pub subclass: Option, - /// Optional programming-interface code. - pub prog_if: Option, - /// Optional hardware revision code. - pub revision: Option, - /// Optional subsystem vendor identifier. - pub subsystem_vendor: Option, - /// Optional subsystem device identifier. - pub subsystem_device: Option, - /// Raw bus-specific device handle for detailed access. - pub raw_path: String, - /// Optional human-readable description provided by firmware or the bus layer. - pub description: Option, -} - -/// Generic interface for an owned device handle. -pub trait Device: Send + Sync { - /// Returns the stable identifier for this device. - fn id(&self) -> &DeviceId; - - /// Returns the immutable descriptor used for matching and lifecycle actions. - fn info(&self) -> &DeviceInfo; -} - -/// A device that has been successfully matched and bound to a driver. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct BoundDevice { - /// Static information captured at discovery time. - pub info: DeviceInfo, - /// The name of the driver that currently owns the device. - pub driver_name: String, - /// Key-value parameters associated with the active binding. - pub parameters: BTreeMap, -} diff --git a/local/recipes/drivers/redox-driver-core/src/driver.rs b/local/recipes/drivers/redox-driver-core/src/driver.rs deleted file mode 100644 index a64268cee7..0000000000 --- a/local/recipes/drivers/redox-driver-core/src/driver.rs +++ /dev/null @@ -1,110 +0,0 @@ -use alloc::string::String; - -use crate::device::DeviceInfo; -use crate::params::DriverParams; -use crate::r#match::DriverMatch; - -/// Result of a driver probe attempt. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum ProbeResult { - /// The driver successfully bound to the device. - Bound, - /// The device is not supported by this driver and other drivers may still try. - NotSupported, - /// A dependency is not yet available, so the manager should retry the probe later. - Deferred { - /// Human-readable reason for the deferral. - reason: String, - }, - /// The device cannot be driven successfully by this driver. - Fatal { - /// Human-readable explanation of the failure. - reason: String, - }, -} - -/// Errors returned by driver lifecycle operations after a device has been matched. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum DriverError { - /// The operation requires a resource that is not ready yet. - NotReady, - /// The driver encountered an I/O failure while managing the device. - IoError, - /// The requested lifecycle operation is not supported by this driver. - Unsupported, - /// An implementation-specific static error message. - Other(&'static str), -} - -/// A device driver that can bind to and manage devices. -pub trait Driver: Send + Sync { - /// Returns the unique driver name, such as `"nvmed"` or `"e1000d"`. - fn name(&self) -> &str; - - /// Returns a human-readable description of the driver. - fn description(&self) -> &str; - - /// Returns the probe priority for this driver. - /// - /// Higher numbers are probed first. Storage drivers typically use higher priorities than - /// networking or peripheral drivers so boot-critical hardware claims happen early. - fn priority(&self) -> i32 { - 0 - } - - /// Returns the driver's static match table. - fn match_table(&self) -> &[DriverMatch]; - - /// Probes a candidate device and decides whether the driver should take ownership. - fn probe(&self, info: &DeviceInfo) -> ProbeResult; - - /// Detaches the driver from a previously bound device. - fn remove(&self, info: &DeviceInfo) -> Result<(), DriverError>; - - /// Suspends a bound device. - fn suspend(&self, info: &DeviceInfo) -> Result<(), DriverError> { - let _ = info; - Ok(()) - } - - /// Resumes a previously suspended device. - fn resume(&self, info: &DeviceInfo) -> Result<(), DriverError> { - let _ = info; - Ok(()) - } - - /// Returns the driver's parameter definitions and current values. - fn params(&self) -> DriverParams { - DriverParams::default() - } -} - -#[cfg(test)] -mod tests { - use alloc::string::String; - - use super::ProbeResult; - - #[test] - fn probe_result_variants_preserve_payloads() { - let bound = ProbeResult::Bound; - let not_supported = ProbeResult::NotSupported; - let deferred = ProbeResult::Deferred { - reason: String::from("waiting for scheme"), - }; - let fatal = ProbeResult::Fatal { - reason: String::from("device is wedged"), - }; - - assert!(matches!(bound, ProbeResult::Bound)); - assert!(matches!(not_supported, ProbeResult::NotSupported)); - assert!(matches!( - deferred, - ProbeResult::Deferred { reason } if reason == "waiting for scheme" - )); - assert!(matches!( - fatal, - ProbeResult::Fatal { reason } if reason == "device is wedged" - )); - } -} diff --git a/local/recipes/drivers/redox-driver-core/src/hotplug.rs b/local/recipes/drivers/redox-driver-core/src/hotplug.rs deleted file mode 100644 index 19cccb003d..0000000000 --- a/local/recipes/drivers/redox-driver-core/src/hotplug.rs +++ /dev/null @@ -1,47 +0,0 @@ -use alloc::string::String; - -use hashbrown::HashMap; - -use crate::device::DeviceId; -#[cfg(feature = "hotplug")] -use crate::device::DeviceInfo; - -/// A normalized action associated with a userspace device event. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum UeventAction { - /// A device or logical function was added. - Add, - /// A device or logical function was removed. - Remove, - /// A device changed state or metadata. - Change, - /// A driver or subsystem bound to the device. - Bind, - /// A driver or subsystem detached from the device. - Unbind, -} - -/// Bus-agnostic metadata describing a userspace device event. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Uevent { - /// Event action, normalized across bus implementations. - pub action: UeventAction, - /// Stable device identifier associated with the event. - pub device: DeviceId, - /// Bus-specific key-value metadata that accompanied the event. - pub properties: HashMap, -} - -/// Opaque subscription handle for receiving hotplug notifications. -#[cfg(feature = "hotplug")] -pub type HotplugSubscription = usize; - -/// High-level hotplug event delivered by a bus implementation. -#[cfg(feature = "hotplug")] -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum HotplugEvent { - /// A device appeared on the bus and is ready for probing. - DeviceAdded(DeviceInfo), - /// A device disappeared from the bus. - DeviceRemoved(DeviceId), -} diff --git a/local/recipes/drivers/redox-driver-core/src/lib.rs b/local/recipes/drivers/redox-driver-core/src/lib.rs deleted file mode 100644 index c3210e40e0..0000000000 --- a/local/recipes/drivers/redox-driver-core/src/lib.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] -#![doc = "Core device-model traits and orchestration primitives for Red Bear OS drivers."] - -#[cfg(not(any(feature = "std", feature = "alloc", test)))] -compile_error!("redox-driver-core requires either the `std` or `alloc` feature"); - -extern crate alloc; - -/// Bus abstractions and related error types. -pub mod bus; -/// Device descriptors and bound-device state. -pub mod device; -/// Driver traits and probe outcomes. -pub mod driver; -/// Hotplug and uevent metadata types. -pub mod hotplug; -/// Device-manager orchestration. -pub mod manager; -/// Match-table primitives. -pub mod r#match; -/// Driver parameter definitions and runtime values. -pub mod params; - -pub use bus::{Bus, BusError}; -pub use device::{BoundDevice, Device, DeviceId, DeviceInfo}; -pub use driver::{Driver, DriverError, ProbeResult}; -pub use hotplug::{Uevent, UeventAction}; -#[cfg(feature = "hotplug")] -pub use hotplug::{HotplugEvent, HotplugSubscription}; -pub use manager::{DeviceManager, ManagerConfig, ProbeEvent}; -pub use params::{DriverParams, ParamDef, ParamValue}; -pub use r#match::{DriverMatch, MatchPriority, MatchTable}; diff --git a/local/recipes/drivers/redox-driver-core/src/manager.rs b/local/recipes/drivers/redox-driver-core/src/manager.rs deleted file mode 100644 index 5f1182cad7..0000000000 --- a/local/recipes/drivers/redox-driver-core/src/manager.rs +++ /dev/null @@ -1,433 +0,0 @@ -use alloc::boxed::Box; -use alloc::collections::BTreeMap; -use alloc::string::{String, ToString}; -use alloc::vec::Vec; - -use crate::bus::{Bus, BusError}; -use crate::device::{BoundDevice, DeviceId, DeviceInfo}; -use crate::driver::{Driver, ProbeResult}; - -/// Event emitted by the device manager during discovery or deferred-probe processing. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum ProbeEvent { - /// A bus finished enumeration and reported the number of discovered devices. - BusEnumerated { - /// Bus name returned by the [`Bus`] implementation. - bus: String, - /// Number of devices returned by the bus. - device_count: usize, - }, - /// A bus failed to enumerate devices. - BusEnumerationFailed { - /// Bus name returned by the [`Bus`] implementation. - bus: String, - /// Error returned by the bus. - error: BusError, - }, - /// The manager skipped probing because the device is already bound. - AlreadyBound { - /// Identifier of the device that was skipped. - device: DeviceId, - /// Driver that already owns the device. - driver_name: String, - }, - /// A driver completed a probe attempt for a device. - ProbeCompleted { - /// Identifier of the probed device. - device: DeviceId, - /// Driver that performed the probe. - driver_name: String, - /// Result returned by the driver's probe method. - result: ProbeResult, - }, - /// No registered driver had a matching table entry for the device. - NoDriverFound { - /// Identifier of the unmatched device. - device: DeviceId, - }, - /// A deferred probe referenced a driver that is no longer registered. - MissingDriver { - /// Identifier of the affected device. - device: DeviceId, - /// Driver name that could not be found. - driver_name: String, - }, -} - -/// Configuration for the central [`DeviceManager`]. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ManagerConfig { - /// Maximum number of probes the manager should allow concurrently. - /// - /// The current implementation probes synchronously and stores this as policy metadata for - /// future async or threaded executors. - pub max_concurrent_probes: usize, - /// Interval, in milliseconds, between deferred-probe retries. - pub deferred_retry_ms: u64, - /// Whether the manager should prefer asynchronous probing when an executor is available. - pub async_probe: bool, -} - -/// Central device manager that orchestrates device discovery and driver binding. -pub struct DeviceManager { - buses: Vec>, - drivers: Vec>, - bound_devices: BTreeMap, - deferred_queue: Vec<(DeviceInfo, String)>, - config: ManagerConfig, -} - -impl DeviceManager { - /// Creates a new device manager with the provided policy configuration. - pub fn new(config: ManagerConfig) -> Self { - Self { - buses: Vec::new(), - drivers: Vec::new(), - bound_devices: BTreeMap::new(), - deferred_queue: Vec::new(), - config, - } - } - - /// Registers a bus that will be included in future enumeration cycles. - pub fn register_bus(&mut self, bus: Box) { - self.buses.push(bus); - } - - /// Registers a driver and reorders drivers so higher-priority probes run first. - pub fn register_driver(&mut self, driver: Box) { - self.drivers.push(driver); - self.drivers - .sort_by(|left, right| right.priority().cmp(&left.priority())); - } - - /// Runs a full enumeration cycle across all registered buses. - pub fn enumerate(&mut self) -> Vec { - let _probe_budget = self.config.max_concurrent_probes.max(1); - let _async_probe = self.config.async_probe; - - let mut events = Vec::new(); - - for bus_index in 0..self.buses.len() { - let (bus_name, enumeration) = { - let bus = &self.buses[bus_index]; - (bus.name().to_string(), bus.enumerate_devices()) - }; - - match enumeration { - Ok(devices) => { - events.push(ProbeEvent::BusEnumerated { - bus: bus_name, - device_count: devices.len(), - }); - - for info in devices { - if let Some(bound) = self.bound_devices.get(&info.id) { - events.push(ProbeEvent::AlreadyBound { - device: info.id.clone(), - driver_name: bound.driver_name.clone(), - }); - continue; - } - - self.probe_device(info, &mut events); - } - } - Err(error) => events.push(ProbeEvent::BusEnumerationFailed { - bus: bus_name, - error, - }), - } - } - - events - } - - /// Retries all deferred probe attempts in registration order. - pub fn retry_deferred(&mut self) -> Vec { - let _retry_interval_ms = self.config.deferred_retry_ms; - - let mut events = Vec::new(); - let deferred = core::mem::take(&mut self.deferred_queue); - - for (info, driver_name) in deferred { - if let Some(bound) = self.bound_devices.get(&info.id) { - events.push(ProbeEvent::AlreadyBound { - device: info.id.clone(), - driver_name: bound.driver_name.clone(), - }); - continue; - } - - let Some(driver_index) = self - .drivers - .iter() - .position(|driver| driver.name() == driver_name) - else { - events.push(ProbeEvent::MissingDriver { - device: info.id.clone(), - driver_name, - }); - continue; - }; - - let (probe_driver_name, result) = { - let driver = &self.drivers[driver_index]; - (driver.name().to_string(), driver.probe(&info)) - }; - - match &result { - ProbeResult::Bound => { - self.bound_devices.insert( - info.id.clone(), - BoundDevice { - info: info.clone(), - driver_name: probe_driver_name.clone(), - parameters: BTreeMap::new(), - }, - ); - } - ProbeResult::Deferred { .. } => { - self.enqueue_deferred(info.clone(), probe_driver_name.clone()); - } - ProbeResult::NotSupported | ProbeResult::Fatal { .. } => {} - } - - events.push(ProbeEvent::ProbeCompleted { - device: info.id.clone(), - driver_name: probe_driver_name, - result, - }); - } - - events - } - - fn probe_device(&mut self, info: DeviceInfo, events: &mut Vec) { - let mut matched = false; - - for driver_index in 0..self.drivers.len() { - let is_match = { - let driver = &self.drivers[driver_index]; - driver - .match_table() - .iter() - .any(|driver_match| driver_match.matches(&info)) - }; - - if !is_match { - continue; - } - - matched = true; - let (driver_name, result) = { - let driver = &self.drivers[driver_index]; - (driver.name().to_string(), driver.probe(&info)) - }; - - match &result { - ProbeResult::Bound => { - self.bound_devices.insert( - info.id.clone(), - BoundDevice { - info: info.clone(), - driver_name: driver_name.clone(), - parameters: BTreeMap::new(), - }, - ); - - events.push(ProbeEvent::ProbeCompleted { - device: info.id.clone(), - driver_name, - result, - }); - return; - } - ProbeResult::Deferred { .. } => { - self.enqueue_deferred(info.clone(), driver_name.clone()); - events.push(ProbeEvent::ProbeCompleted { - device: info.id.clone(), - driver_name, - result, - }); - return; - } - ProbeResult::Fatal { .. } => { - events.push(ProbeEvent::ProbeCompleted { - device: info.id.clone(), - driver_name, - result, - }); - return; - } - ProbeResult::NotSupported => { - events.push(ProbeEvent::ProbeCompleted { - device: info.id.clone(), - driver_name, - result, - }); - } - } - } - - if !matched { - events.push(ProbeEvent::NoDriverFound { device: info.id }); - } - } - - fn enqueue_deferred(&mut self, info: DeviceInfo, driver_name: String) { - let already_queued = self.deferred_queue.iter().any(|(queued_info, queued_driver)| { - queued_info.id == info.id && queued_driver == &driver_name - }); - - if !already_queued { - self.deferred_queue.push((info, driver_name)); - } - } -} - -#[cfg(test)] -mod tests { - use alloc::boxed::Box; - use alloc::string::String; - use alloc::vec; - use alloc::vec::Vec; - - use super::{DeviceManager, ManagerConfig}; - use crate::bus::{Bus, BusError}; - use crate::device::{DeviceId, DeviceInfo}; - use crate::driver::{Driver, DriverError, ProbeResult}; - use crate::r#match::DriverMatch; - - struct MockBus { - name: &'static str, - devices: Vec, - } - - impl Bus for MockBus { - fn name(&self) -> &str { - self.name - } - - fn enumerate_devices(&self) -> Result, BusError> { - Ok(self.devices.clone()) - } - } - - struct MockDriver { - name: &'static str, - description: &'static str, - priority: i32, - matches: Vec, - } - - impl Driver for MockDriver { - 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.as_slice() - } - - fn probe(&self, _info: &DeviceInfo) -> ProbeResult { - ProbeResult::NotSupported - } - - fn remove(&self, _info: &DeviceInfo) -> Result<(), DriverError> { - Ok(()) - } - } - - fn config() -> ManagerConfig { - ManagerConfig { - max_concurrent_probes: 4, - deferred_retry_ms: 250, - async_probe: false, - } - } - - #[test] - fn register_bus_and_driver_store_entries() { - let mut manager = DeviceManager::new(config()); - - manager.register_bus(Box::new(MockBus { - name: "pci", - devices: Vec::new(), - })); - manager.register_driver(Box::new(MockDriver { - name: "low", - description: "low-priority driver", - priority: 10, - matches: vec![DriverMatch { - vendor: Some(0x1234), - device: None, - class: None, - subclass: None, - prog_if: None, - subsystem_vendor: None, - subsystem_device: None, - }], - })); - manager.register_driver(Box::new(MockDriver { - name: "high", - description: "high-priority driver", - priority: 100, - matches: vec![DriverMatch { - vendor: Some(0x1234), - device: Some(0x5678), - class: None, - subclass: None, - prog_if: None, - subsystem_vendor: None, - subsystem_device: None, - }], - })); - - assert_eq!(manager.buses.len(), 1); - assert_eq!(manager.drivers.len(), 2); - assert_eq!(manager.drivers[0].name(), "high"); - assert_eq!(manager.drivers[1].name(), "low"); - } - - #[test] - fn enumerate_reports_registered_bus() { - let mut manager = DeviceManager::new(config()); - - manager.register_bus(Box::new(MockBus { - name: "pci", - devices: vec![DeviceInfo { - id: DeviceId { - bus: String::from("pci"), - path: String::from("0000:00:1f.2"), - }, - vendor: Some(0x8086), - device: Some(0x2922), - class: Some(0x01), - subclass: Some(0x06), - prog_if: Some(0x01), - revision: Some(0x02), - subsystem_vendor: None, - subsystem_device: None, - raw_path: String::from("/scheme/pci/00.1f.2"), - description: Some(String::from("AHCI controller")), - }], - })); - - let events = manager.enumerate(); - - assert!(events.iter().any(|event| matches!( - event, - super::ProbeEvent::BusEnumerated { bus, device_count } - if bus == "pci" && *device_count == 1 - ))); - } -} diff --git a/local/recipes/drivers/redox-driver-core/src/match.rs b/local/recipes/drivers/redox-driver-core/src/match.rs deleted file mode 100644 index 8e795d1272..0000000000 --- a/local/recipes/drivers/redox-driver-core/src/match.rs +++ /dev/null @@ -1,146 +0,0 @@ -use alloc::vec::Vec; - -use crate::device::DeviceInfo; - -/// Priority type used to order driver probes. -pub type MatchPriority = i32; - -/// A single entry in a driver's match table. -#[derive(Clone, Debug, PartialEq, Eq, Default)] -pub struct DriverMatch { - /// Optional vendor identifier match. - pub vendor: Option, - /// Optional device identifier match. - pub device: Option, - /// Optional class-code match. - pub class: Option, - /// Optional subclass-code match. - pub subclass: Option, - /// Optional programming-interface match. - pub prog_if: Option, - /// Optional subsystem vendor match. - pub subsystem_vendor: Option, - /// Optional subsystem device match. - pub subsystem_device: Option, -} - -impl DriverMatch { - /// Checks whether this match entry matches the provided device information. - pub fn matches(&self, info: &DeviceInfo) -> bool { - self.vendor.map_or(true, |v| info.vendor == Some(v)) - && self.device.map_or(true, |d| info.device == Some(d)) - && self.class.map_or(true, |c| info.class == Some(c)) - && self.subclass.map_or(true, |s| info.subclass == Some(s)) - && self.prog_if.map_or(true, |p| info.prog_if == Some(p)) - && self - .subsystem_vendor - .map_or(true, |v| info.subsystem_vendor == Some(v)) - && self - .subsystem_device - .map_or(true, |d| info.subsystem_device == Some(d)) - } -} - -/// Collection wrapper for a driver's match entries. -#[derive(Clone, Debug, PartialEq, Eq, Default)] -pub struct MatchTable { - entries: Vec, -} - -impl MatchTable { - /// Creates a new match table from the provided entries. - pub fn new(entries: Vec) -> Self { - Self { entries } - } - - /// Returns the underlying immutable slice of match entries. - pub fn entries(&self) -> &[DriverMatch] { - self.entries.as_slice() - } - - /// Returns `true` if any entry in the table matches the provided device. - pub fn matches(&self, info: &DeviceInfo) -> bool { - self.entries.iter().any(|entry| entry.matches(info)) - } -} - -impl From> for MatchTable { - fn from(entries: Vec) -> Self { - Self::new(entries) - } -} - -#[cfg(test)] -mod tests { - use alloc::string::String; - - use super::DriverMatch; - use crate::device::{DeviceId, DeviceInfo}; - - fn sample_device() -> DeviceInfo { - DeviceInfo { - id: DeviceId { - bus: String::from("pci"), - path: String::from("0000:00:02.0"), - }, - vendor: Some(0x8086), - device: Some(0x1234), - class: Some(0x03), - subclass: Some(0x00), - prog_if: Some(0x00), - revision: Some(0x01), - subsystem_vendor: Some(0x8086), - subsystem_device: Some(0xabcd), - raw_path: String::from("/scheme/pci/00.02.0"), - description: Some(String::from("Display controller")), - } - } - - #[test] - fn driver_match_accepts_exact_match() { - let info = sample_device(); - let driver_match = DriverMatch { - vendor: Some(0x8086), - device: Some(0x1234), - class: Some(0x03), - subclass: Some(0x00), - prog_if: Some(0x00), - subsystem_vendor: Some(0x8086), - subsystem_device: Some(0xabcd), - }; - - assert!(driver_match.matches(&info)); - } - - #[test] - fn driver_match_supports_wildcards() { - let info = sample_device(); - let driver_match = DriverMatch { - vendor: Some(0x8086), - device: None, - class: Some(0x03), - subclass: None, - prog_if: None, - subsystem_vendor: None, - subsystem_device: None, - }; - - assert!(driver_match.matches(&info)); - } - - #[test] - fn driver_match_rejects_mismatch() { - let info = sample_device(); - let driver_match = DriverMatch { - vendor: Some(0x10ec), - device: None, - class: None, - subclass: None, - prog_if: None, - subsystem_vendor: None, - subsystem_device: None, - }; - - assert!(!driver_match.matches(&info)); - } -} diff --git a/local/recipes/drivers/redox-driver-core/src/params.rs b/local/recipes/drivers/redox-driver-core/src/params.rs deleted file mode 100644 index 65257732e5..0000000000 --- a/local/recipes/drivers/redox-driver-core/src/params.rs +++ /dev/null @@ -1,166 +0,0 @@ -use alloc::collections::BTreeMap; -use alloc::string::String; -use alloc::vec::Vec; -use alloc::format; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum ParamValue { - Bool(bool), - Int(i64), - Uint(u64), - String(String), - Enum(String, Vec), -} - -impl ParamValue { - pub fn type_name(&self) -> &str { - match self { - ParamValue::Bool(_) => "bool", - ParamValue::Int(_) => "int", - ParamValue::Uint(_) => "uint", - ParamValue::String(_) => "string", - ParamValue::Enum(_, _) => "enum", - } - } - - pub fn to_display_string(&self) -> String { - match self { - ParamValue::Bool(v) => format!("{}", v), - ParamValue::Int(v) => format!("{}", v), - ParamValue::Uint(v) => format!("{}", v), - ParamValue::String(v) => v.clone(), - ParamValue::Enum(v, _) => v.clone(), - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ParamDef { - pub name: String, - pub description: String, - pub default: ParamValue, - pub writable: bool, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct DriverParams { - pub params: BTreeMap, - pub values: BTreeMap, -} - -impl DriverParams { - pub fn new() -> Self { - DriverParams { - params: BTreeMap::new(), - values: BTreeMap::new(), - } - } - - pub fn define(&mut self, name: &str, description: &str, default: ParamValue, writable: bool) { - self.params.insert( - String::from(name), - ParamDef { - name: String::from(name), - description: String::from(description), - default: default.clone(), - writable, - }, - ); - self.values.insert(String::from(name), default); - } - - pub fn get(&self, name: &str) -> Option<&ParamValue> { - self.values.get(name) - } - - pub fn set(&mut self, name: &str, value: ParamValue) -> Result<(), &'static str> { - match self.params.get(name) { - Some(def) if !def.writable => Err("parameter is read-only"), - Some(def) => { - if core::mem::discriminant(&def.default) == core::mem::discriminant(&value) { - self.values.insert(String::from(name), value); - Ok(()) - } else { - Err("parameter type mismatch") - } - } - None => Err("unknown parameter"), - } - } - - pub fn list(&self) -> Vec<&ParamDef> { - self.params.values().collect() - } - - pub fn parse_bool(s: &str) -> Option { - match s.to_lowercase().as_str() { - "true" | "1" | "yes" | "on" => Some(true), - "false" | "0" | "no" | "off" => Some(false), - _ => None, - } - } - - pub fn parse_int(s: &str) -> Option { - s.parse().ok() - } - - pub fn parse_uint(s: &str) -> Option { - s.parse().ok() - } -} - -impl Default for DriverParams { - fn default() -> Self { - Self::new() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn define_and_get_parameter() { - let mut p = DriverParams::new(); - p.define("debug", "Enable debug logging", ParamValue::Bool(false), true); - assert_eq!(p.get("debug"), Some(&ParamValue::Bool(false))); - } - - #[test] - fn set_writable_parameter() { - let mut p = DriverParams::new(); - p.define("debug", "Enable debug logging", ParamValue::Bool(false), true); - assert!(p.set("debug", ParamValue::Bool(true)).is_ok()); - assert_eq!(p.get("debug"), Some(&ParamValue::Bool(true))); - } - - #[test] - fn set_readonly_parameter_fails() { - let mut p = DriverParams::new(); - p.define("vendor_id", "Vendor ID", ParamValue::Uint(0), false); - assert!(p.set("vendor_id", ParamValue::Uint(1)).is_err()); - } - - #[test] - fn set_unknown_parameter_fails() { - let mut p = DriverParams::new(); - assert!(p.set("nonexistent", ParamValue::Bool(true)).is_err()); - } - - #[test] - fn param_value_display_strings() { - assert_eq!(ParamValue::Bool(true).to_display_string(), "true"); - assert_eq!(ParamValue::Int(-42).to_display_string(), "-42"); - assert_eq!(ParamValue::Uint(42).to_display_string(), "42"); - assert_eq!(ParamValue::String(String::from("hello")).to_display_string(), "hello"); - } - - #[test] - fn parse_bool_variants() { - assert_eq!(DriverParams::parse_bool("true"), Some(true)); - assert_eq!(DriverParams::parse_bool("1"), Some(true)); - assert_eq!(DriverParams::parse_bool("yes"), Some(true)); - assert_eq!(DriverParams::parse_bool("false"), Some(false)); - assert_eq!(DriverParams::parse_bool("0"), Some(false)); - } -}