rust: faux: add Device type with AsBusDevice support

Add a faux::Device type that wraps struct faux_device and implements
AsBusDevice, enabling faux devices to be used as parent devices for
subsystems that require a bus device, such as DRM.

Update Registration to return &faux::Device<Bound> via AsRef.

Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Tested-by: Deborah Brouwer <deborah.brouwer@collabora.com>
Link: https://patch.msgid.link/20260628145406.2107056-4-dakr@kernel.org
[ Drop redundant 'struct device' invariant; implied by valid
  struct faux_device. - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
This commit is contained in:
Danilo Krummrich
2026-06-28 16:53:23 +02:00
parent fd0f827c53
commit 893f39dada
3 changed files with 68 additions and 15 deletions

View File

@@ -692,10 +692,12 @@ impl drm::Driver for KunitDriver {
fn create_drm_dev() -> Result<(faux::Registration, UnregisteredDevice<KunitDriver>)> {
// Create a faux DRM device so we can test gem object creation.
let data = try_pin_init!(KunitData {});
let dev = faux::Registration::new(c"Kunit", None)?;
let drm = UnregisteredDevice::new(dev.as_ref(), data)?;
let reg = faux::Registration::new(c"Kunit", None)?;
let fdev = reg.as_ref();
let dev = fdev.as_ref();
let drm = UnregisteredDevice::new(dev, data)?;
Ok((dev, drm))
Ok((reg, drm))
}
#[test]
@@ -755,7 +757,8 @@ fn vmap_io() -> Result {
#[test]
fn fail_sg_table_on_wrong_dev() -> Result {
let (_dev, drm) = create_drm_dev()?;
let wrong_dev = faux::Registration::new(c"EvilKunit", None)?;
let reg = faux::Registration::new(c"EvilKunit", None)?;
let wrong_dev = reg.as_ref();
let obj = Object::<KunitObject, _>::new(&drm, PAGE_SIZE, ObjectConfig::default(), ())?;

View File

@@ -9,15 +9,63 @@
use crate::{
bindings,
device,
prelude::*, //
prelude::*,
types::Opaque, //
};
use core::ptr::{
addr_of_mut,
null,
null_mut,
NonNull, //
use core::{
marker::PhantomData,
ptr::{
null,
null_mut,
NonNull, //
},
};
/// A faux device.
///
/// A faux device is a virtual device backed by the faux bus, primarily used for scenarios where a
/// real hardware device is not available or for testing.
///
/// # Invariants
///
/// The underlying `struct faux_device` is valid.
#[repr(transparent)]
pub struct Device<Ctx: device::DeviceContext = device::Normal>(
Opaque<bindings::faux_device>,
PhantomData<Ctx>,
);
impl<Ctx: device::DeviceContext> Device<Ctx> {
#[inline]
fn as_raw(&self) -> *mut bindings::faux_device {
self.0.get()
}
/// # Safety
///
/// `ptr` must be a valid pointer to a `struct faux_device`.
#[inline]
unsafe fn from_raw<'a>(ptr: *mut bindings::faux_device) -> &'a Self {
// SAFETY: `Device` is a transparent wrapper of `Opaque<bindings::faux_device>`.
unsafe { &*ptr.cast() }
}
}
impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
#[inline]
fn as_ref(&self) -> &device::Device<Ctx> {
// SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
// `struct faux_device`. `dev` points to a valid `struct device`.
unsafe { device::Device::from_raw(&raw mut (*self.as_raw()).dev) }
}
}
// SAFETY: `faux::Device` is a transparent wrapper of `struct faux_device`.
// The offset is guaranteed to point to a valid device field inside `faux::Device`.
unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx> {
const OFFSET: usize = core::mem::offset_of!(bindings::faux_device, dev);
}
/// The registration of a faux device.
///
/// This type represents the registration of a [`struct faux_device`]. When an instance of this type
@@ -60,10 +108,11 @@ fn as_raw(&self) -> *mut bindings::faux_device {
}
}
impl AsRef<device::Device<device::Bound>> for Registration {
fn as_ref(&self) -> &device::Device<device::Bound> {
impl AsRef<Device<device::Bound>> for Registration {
#[inline]
fn as_ref(&self) -> &Device<device::Bound> {
// SAFETY:
// - The underlying `device` in `faux_device` is guaranteed by the C API to be a valid
// - The underlying `struct faux_device` is guaranteed by the C API to be a valid
// initialized `device`.
// - `faux_match()` always returns 1, and probe runs synchronously
// (PROBE_FORCE_SYNCHRONOUS).
@@ -71,7 +120,7 @@ fn as_ref(&self) -> &device::Device<device::Bound> {
// sysfs.
// - `mem::forget(Registration)` is not a problem; if the `Registration` is leaked, the faux
// device stays bound forever.
unsafe { device::Device::from_raw(addr_of_mut!((*self.as_raw()).dev)) }
unsafe { Device::from_raw(self.as_raw()) }
}
}

View File

@@ -25,8 +25,9 @@ fn init(_module: &'static ThisModule) -> Result<Self> {
pr_info!("Initialising Rust Faux Device Sample\n");
let reg = faux::Registration::new(c"rust-faux-sample-device", None)?;
let fdev = reg.as_ref();
dev_info!(reg, "Hello from faux device!\n");
dev_info!(fdev, "Hello from faux device!\n");
Ok(Self { _reg: reg })
}