rust/kernel/driver.rs

Source file repositories/reference/linux-study-clean/rust/kernel/driver.rs

File Facts

System
Linux kernel
Corpus path
rust/kernel/driver.rs
Extension
.rs
Size
17443 bytes
Lines
442
Domain
Rust Kernel Layer
Bucket
Rust API Membrane
Inferred role
Rust Kernel Layer: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Rust-side wrappers and abstractions around kernel C APIs, ownership contracts, allocation, synchronization, and module integration.

Dependency Surface

Detected Declarations

Annotated Snippet

/// This trait describes the layout of a specific driver structure, such as `struct pci_driver` or
/// `struct platform_driver`.
///
/// # Safety
///
/// Implementors must guarantee that:
/// - `DriverType` is `repr(C)`,
/// - `DriverData` is the type of the driver's device private data.
/// - `DriverType` embeds a valid `struct device_driver` at byte offset `DEVICE_DRIVER_OFFSET`.
pub unsafe trait DriverLayout {
    /// The specific driver type embedding a `struct device_driver`.
    type DriverType: Default;

    /// The type of the driver's bus device private data.
    type DriverData<'bound>;

    /// Byte offset of the embedded `struct device_driver` within `DriverType`.
    ///
    /// This must correspond exactly to the location of the embedded `struct device_driver` field.
    const DEVICE_DRIVER_OFFSET: usize;
}

/// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform,
/// Amba, etc.) to provide the corresponding subsystem specific implementation to register /
/// unregister a driver of the particular type (`DriverType`).
///
/// For instance, the PCI subsystem would set `DriverType` to `bindings::pci_driver` and call
/// `bindings::__pci_register_driver` from `RegistrationOps::register` and
/// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`.
///
/// # Safety
///
/// A call to [`RegistrationOps::unregister`] for a given instance of `DriverType` is only valid if
/// a preceding call to [`RegistrationOps::register`] has been successful.
pub unsafe trait RegistrationOps: DriverLayout {
    /// Registers a driver.
    ///
    /// # Safety
    ///
    /// On success, `reg` must remain pinned and valid until the matching call to
    /// [`RegistrationOps::unregister`].
    unsafe fn register(
        reg: &Opaque<Self::DriverType>,
        name: &'static CStr,
        module: &'static ThisModule,
    ) -> Result;

    /// Unregisters a driver previously registered with [`RegistrationOps::register`].
    ///
    /// # Safety
    ///
    /// Must only be called after a preceding successful call to [`RegistrationOps::register`] for
    /// the same `reg`.
    unsafe fn unregister(reg: &Opaque<Self::DriverType>);
}

/// A [`Registration`] is a generic type that represents the registration of some driver type (e.g.
/// `bindings::pci_driver`). Therefore a [`Registration`] must be initialized with a type that
/// implements the [`RegistrationOps`] trait, such that the generic `T::register` and
/// `T::unregister` calls result in the subsystem specific registration calls.
///
///Once the `Registration` structure is dropped, the driver is unregistered.
#[pin_data(PinnedDrop)]
pub struct Registration<T: RegistrationOps> {
    #[pin]
    reg: Opaque<T::DriverType>,
}

// SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to
// share references to it with multiple threads as nothing can be done.
unsafe impl<T: RegistrationOps> Sync for Registration<T> {}

// SAFETY: Both registration and unregistration are implemented in C and safe to be performed from
// any thread, so `Registration` is `Send`.
unsafe impl<T: RegistrationOps> Send for Registration<T> {}

impl<T: RegistrationOps> Registration<T> {
    extern "C" fn post_unbind_callback(dev: *mut bindings::device) {
        // SAFETY: The driver core only ever calls the post unbind callback with a valid pointer to
        // a `struct device`.
        //
        // INVARIANT: `dev` is valid for the duration of the `post_unbind_callback()`.
        let dev = unsafe { &*dev.cast::<device::Device<device::CoreInternal<'_>>>() };

        // `remove()` has been completed at this point; devres resources are still valid and will
        // be released after the driver's bus device private data is dropped.
        //
        // SAFETY: By the safety requirements of the `Driver` trait, `T::DriverData` is the
        // driver's bus device private data type.
        drop(unsafe { dev.drvdata_obtain::<T::DriverData<'_>>() });

Annotation

Implementation Notes