summaryrefslogtreecommitdiffstats
path: root/rust/kernel/faux.rs
blob: 8a50fcd4c9bbba1f894a09080446ca3173571b03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// SPDX-License-Identifier: GPL-2.0-only

//! Abstractions for the faux bus.
//!
//! This module provides bindings for working with faux devices in kernel modules.
//!
//! C header: [`include/linux/device/faux.h`]

use crate::{bindings, device, error::code::*, prelude::*};
use core::ptr::{addr_of_mut, null, null_mut, NonNull};

/// The registration of a faux device.
///
/// This type represents the registration of a [`struct faux_device`]. When an instance of this type
/// is dropped, its respective faux device will be unregistered from the system.
///
/// # Invariants
///
/// `self.0` always holds a valid pointer to an initialized and registered [`struct faux_device`].
///
/// [`struct faux_device`]: srctree/include/linux/device/faux.h
pub struct Registration(NonNull<bindings::faux_device>);

impl Registration {
    /// Create and register a new faux device with the given name.
    #[inline]
    pub fn new(name: &CStr, parent: Option<&device::Device>) -> Result<Self> {
        // SAFETY:
        // - `name` is copied by this function into its own storage
        // - `faux_ops` is safe to leave NULL according to the C API
        // - `parent` can be either NULL or a pointer to a `struct device`, and `faux_device_create`
        //   will take a reference to `parent` using `device_add` - ensuring that it remains valid
        //   for the lifetime of the faux device.
        let dev = unsafe {
            bindings::faux_device_create(
                name.as_char_ptr(),
                parent.map_or(null_mut(), |p| p.as_raw()),
                null(),
            )
        };

        // The above function will return either a valid device, or NULL on failure
        // INVARIANT: The device will remain registered until faux_device_destroy() is called, which
        // happens in our Drop implementation.
        Ok(Self(NonNull::new(dev).ok_or(ENODEV)?))
    }

    fn as_raw(&self) -> *mut bindings::faux_device {
        self.0.as_ptr()
    }
}

impl AsRef<device::Device> for Registration {
    fn as_ref(&self) -> &device::Device {
        // SAFETY: The underlying `device` in `faux_device` is guaranteed by the C API to be
        // a valid initialized `device`.
        unsafe { device::Device::as_ref(addr_of_mut!((*self.as_raw()).dev)) }
    }
}

impl Drop for Registration {
    #[inline]
    fn drop(&mut self) {
        // SAFETY: `self.0` is a valid registered faux_device via our type invariants.
        unsafe { bindings::faux_device_destroy(self.as_raw()) }
    }
}

// SAFETY: The faux device API is thread-safe as guaranteed by the device core, as long as
// faux_device_destroy() is guaranteed to only be called once - which is guaranteed by our type not
// having Copy/Clone.
unsafe impl Send for Registration {}

// SAFETY: The faux device API is thread-safe as guaranteed by the device core, as long as
// faux_device_destroy() is guaranteed to only be called once - which is guaranteed by our type not
// having Copy/Clone.
unsafe impl Sync for Registration {}