rdrive/
lib.rs

1#![no_std]
2#![feature(box_as_ptr)]
3
4extern crate alloc;
5
6use core::ptr::NonNull;
7pub use fdt_parser::Phandle;
8
9use log::warn;
10use register::{DriverRegister, DriverRegisterData, ProbeLevel};
11use spin::Mutex;
12
13mod descriptor;
14pub mod driver;
15pub mod error;
16mod id;
17mod lock;
18mod manager;
19mod osal;
20
21pub mod probe;
22pub mod register;
23
24pub use descriptor::*;
25pub use driver::PlatformDevice;
26pub use lock::*;
27pub use manager::*;
28pub use osal::*;
29pub use probe::ProbeError;
30pub use rdif_base::{DriverGeneric, KError, irq::IrqId};
31pub use rdrive_macros::*;
32
33use crate::{
34    driver::Class,
35    error::DriverError,
36    probe::{EnumSystem, OnProbeError},
37};
38
39static MANAGER: Mutex<Option<Manager>> = Mutex::new(None);
40
41#[derive(Debug, Clone)]
42pub enum Platform {
43    Fdt { addr: NonNull<u8> },
44}
45
46unsafe impl Send for Platform {}
47
48pub fn init(platform: Platform) -> Result<(), DriverError> {
49    let mut g = MANAGER.lock();
50    if g.is_none() {
51        g.replace(Manager::new(platform)?);
52    }
53    Ok(())
54}
55
56pub(crate) fn edit<F, T>(f: F) -> T
57where
58    F: FnOnce(&mut Manager) -> T,
59{
60    let mut g = MANAGER.lock();
61    f(g.as_mut().expect("manager not init"))
62}
63
64pub(crate) fn read<F, T>(f: F) -> T
65where
66    F: FnOnce(&Manager) -> T,
67{
68    let g = MANAGER.lock();
69    f(g.as_ref().expect("manager not init"))
70}
71
72pub fn register_add(register: DriverRegister) {
73    edit(|manager| manager.registers.add(register));
74}
75
76pub fn register_append(registers: &[DriverRegister]) {
77    edit(|manager| manager.registers.append(registers))
78}
79
80pub fn probe_pre_kernel() -> Result<(), ProbeError> {
81    let unregistered = edit(|manager| manager.unregistered())?;
82
83    let ls = unregistered
84        .iter()
85        .filter(|one| matches!(one.register.level, ProbeLevel::PreKernel));
86
87    probe_with(ls, true)?;
88
89    Ok(())
90}
91
92fn probe_with<'a>(
93    registers: impl Iterator<Item = &'a DriverRegisterData>,
94    stop_if_fail: bool,
95) -> Result<(), ProbeError> {
96    for one in registers {
97        match probe_one(one) {
98            Ok(_) => {} // Successfully probed, move to the next
99            Err(e) => {
100                if stop_if_fail {
101                    return Err(e);
102                } else {
103                    warn!("Probe failed for [{}]: {}", one.register.name, e);
104                }
105            }
106        }
107    }
108
109    Ok(())
110}
111
112fn probe_one(one: &DriverRegisterData) -> Result<(), ProbeError> {
113    let to_probe = edit(|manager| manager.to_unprobed(one))?;
114    for to_probe in to_probe {
115        match to_probe() {
116            Ok(_) => {
117                edit(|manager| manager.registers.set_probed(one.id));
118                return Ok(());
119            }
120            Err(OnProbeError::NotMatch) => {
121                continue; // Not a match, skip to the next probe
122            }
123            Err(e) => {
124                return Err(e.into());
125            }
126        }
127    }
128    Ok(())
129}
130
131pub fn probe_all(stop_if_fail: bool) -> Result<(), ProbeError> {
132    let unregistered = edit(|manager| manager.unregistered())?;
133    probe_with(unregistered.iter(), stop_if_fail)
134}
135
136pub fn get_list<T: Class>() -> Vec<Device<T>> {
137    read(|manager| manager.dev_container.devices())
138}
139
140pub fn get<T: Class>(id: DeviceId) -> Result<Device<T>, GetDeviceError> {
141    read(|manager| manager.dev_container.get_typed(id))
142}
143
144pub fn get_one<T: Class>() -> Option<Device<T>> {
145    read(|manager| manager.dev_container.get_one())
146}
147
148pub fn fdt_phandle_to_device_id(phandle: Phandle) -> Option<DeviceId> {
149    read(|manager| {
150        let EnumSystem::Fdt(system) = &manager.enum_system;
151        system.phandle_to_device_id(phandle)
152    })
153}
154
155/// Macro for generating a driver module.
156///
157/// This macro automatically generates a driver registration module that creates a static
158/// `DriverRegister` struct containing driver metadata (such as name, probe level, priority,
159/// and probe types). The generated static variable is placed in the special linker section
160/// `.driver.register` to be automatically discovered and registered by the driver manager
161/// at runtime.
162///
163/// # Parameters
164/// - `$i:ident`: Field identifier (e.g., `name`, `level`, `priority`, `probe_kinds`)
165/// - `$t:expr`: Expression for the corresponding field value
166///
167/// # Generated Code
168///
169/// The macro generates a module containing a static `DriverRegister` that:
170/// - Uses `#[link_section = ".driver.register"]` attribute to place it in a special linker section
171/// - Uses `#[no_mangle]` and `#[used]` to prevent compiler optimization
172/// - Contains all driver registration information
173///
174/// # Example
175///
176/// ```rust
177/// use rdrive::{
178///     module_driver,
179///     driver::*,
180///     register::FdtInfo,
181///     probe::OnProbeError,
182///     PlatformDevice,
183/// };
184///
185/// struct UartDriver {}
186///
187/// impl DriverGeneric for UartDriver {
188///     fn open(&mut self) -> Result<(), rdrive::KError> { todo!() }
189///     fn close(&mut self) -> Result<(), rdrive::KError> { todo!() }
190/// }
191///
192/// impl rdrive::driver::serial::Interface for UartDriver {
193///     fn handle_irq(&mut self) { todo!() }
194///     fn take_tx(&mut self) -> Option<Box<(dyn rdrive::driver::serial::io::Write + 'static)>> { todo!() }
195///     fn take_rx(&mut self) -> Option<Box<(dyn rdrive::driver::serial::io::Read + 'static)>> { todo!() }
196/// }
197///
198/// // Define probe function
199/// fn probe_uart(fdt: FdtInfo<'_>, dev: PlatformDevice) -> Result<(), OnProbeError> {
200///     // Implement specific device probing logic
201///     dev.register_serial(UartDriver{});
202///     Ok(())
203/// }
204///
205/// // Use macro to generate driver registration module
206/// module_driver! {
207///     name: "UART Driver",
208///     level: ProbeLevel::PostKernel,
209///     priority: ProbePriority::DEFAULT,
210///     probe_kinds: &[ProbeKind::Fdt {
211///         compatibles: &["ns16550a", "arm,pl011"],
212///         // Use `probe_uart` above; this usage is because doctests cannot find the parent module.
213///         on_probe: |fdt, dev|{
214///             Ok(())
215///         },
216///     }],
217/// }
218/// ```
219///
220/// # Notes
221///
222/// - This macro can only be used once per driver module
223/// - The generated module name is automatically derived from the driver name
224/// - All fields must be properly set, especially the `probe_kinds` array
225/// - Probe functions must implement the correct signature and error handling
226#[macro_export]
227macro_rules! module_driver {
228    (
229        $($i:ident : $t:expr),+,
230    ) => {
231        /// Auto-generated driver registration module.
232        #[allow(unused)]
233        $crate::__mod_maker!{
234            pub mod some {
235                use super::*;
236                use $crate::register::*;
237
238                /// Static instance of driver registration information.
239                ///
240                /// This static variable is placed in the `.driver.register` linker section
241                /// so that the driver manager can automatically discover and load it during
242                /// system startup.
243                #[unsafe(link_section = ".driver.register")]
244                #[unsafe(no_mangle)]
245                #[link(used)]
246                pub static DRIVER: DriverRegister = DriverRegister {
247                    $($i : $t),+
248                };
249            }
250        }
251    };
252}