diff --git a/drivers/char/hw_random/bcm2835_rng_rust.rs b/drivers/char/hw_random/bcm2835_rng_rust.rs index ef7e0f6a29fde1..ea07f48221b5b5 100644 --- a/drivers/char/hw_random/bcm2835_rng_rust.rs +++ b/drivers/char/hw_random/bcm2835_rng_rust.rs @@ -13,6 +13,7 @@ use kernel::{ of::ConstOfMatchTable, platdev::PlatformDriver, prelude::*, + sync::Ref, {c_str, platdev}, }; @@ -24,24 +25,39 @@ module! { license: b"GPL v2", } -struct RngDevice; +struct RngDevice { + zero: u32, +} + +impl RngDevice { + fn new() -> Self { + Self { zero: 0 } + } +} -impl FileOpener<()> for RngDevice { - fn open(_state: &()) -> Result { - Ok(Box::try_new(RngDevice)?) +impl FileOpener> for RngDevice { + fn open(state: &Ref) -> Result { + Ok(state.clone()) } } impl FileOperations for RngDevice { + type Wrapper = Ref; + kernel::declare_file_operations!(read); - fn read(_: &Self, _: &File, data: &mut T, offset: u64) -> Result { + fn read( + this: &Ref, + _: &File, + data: &mut T, + offset: u64, + ) -> Result { // Succeed if the caller doesn't provide a buffer or if not at the start. if data.is_empty() || offset != 0 { return Ok(0); } - data.write(&0_u32)?; + data.write(&this.zero)?; Ok(4) } } @@ -49,12 +65,13 @@ impl FileOperations for RngDevice { struct RngDriver; impl PlatformDriver for RngDriver { - type DrvData = Pin>>; + type DrvData = Pin>>>; fn probe(device_id: i32) -> Result { pr_info!("probing discovered hwrng with id {}\n", device_id); + let device = Ref::try_new(RngDevice::new())?; let drv_data = - miscdev::Registration::new_pinned::(c_str!("rust_hwrng"), None, ())?; + miscdev::Registration::new_pinned::(c_str!("rust_hwrng"), None, device)?; Ok(drv_data) } @@ -62,6 +79,14 @@ impl PlatformDriver for RngDriver { pr_info!("removing hwrng with id {}\n", device_id); Ok(()) } + + fn shutdown(device_id: i32, drv_data: &miscdev::Registration>) { + pr_info!( + "shutting down hwrng with id {}, zero {}\n", + device_id, + drv_data.context.zero + ); + } } struct RngModule { diff --git a/rust/kernel/platdev.rs b/rust/kernel/platdev.rs index 5f306b61321e36..1623d8bc5442b5 100644 --- a/rust/kernel/platdev.rs +++ b/rust/kernel/platdev.rs @@ -15,7 +15,7 @@ use crate::{ types::PointerWrapper, }; use alloc::boxed::Box; -use core::{marker::PhantomPinned, pin::Pin}; +use core::{marker::PhantomPinned, ops::Deref, pin::Pin}; /// A registration of a platform device. #[derive(Default)] @@ -70,14 +70,33 @@ extern "C" fn remove_callback( // - we allocated this pointer using `P::DrvData::into_pointer`, // so it is safe to turn back into a `P::DrvData`. // - the allocation happened in `probe`, no-one freed the memory, - // `remove` is the canonical kernel location to free driver data. so OK - // to convert the pointer back to a Rust structure here. + // `remove` is the canonical kernel location to free driver data, + // no borrows are outstanding as the driver model guarantees that + // `remove` is called only while no other `bindings::platform_driver` + // callbacks are in progress, + // so OK to convert the pointer back to a Rust structure here. let drv_data = unsafe { P::DrvData::from_pointer(ptr) }; P::remove(device_id, drv_data)?; Ok(0) } } +extern "C" fn shutdown_callback(pdev: *mut bindings::platform_device) { + // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer. + let device_id = unsafe { (*pdev).id }; + // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer. + let ptr = unsafe { rust_helper_platform_get_drvdata(pdev) }; + // SAFETY: + // - `ptr` was returned by a previous call to `P::DrvData::into_pointer`; + // - the structure which `ptr` points at, is guaranteed to exist: it's + // deallocated in `remove`, which is guaranteed by the driver model to + // execute after all other `bindings::platform_driver` callbacks have + // returned; + // so `ptr` is safe to borrow here. + let drv_data = unsafe { P::DrvData::borrow(ptr) }; + P::shutdown(device_id, &drv_data); +} + impl Registration { fn register( self: Pin<&mut Self>, @@ -97,6 +116,7 @@ impl Registration { } this.pdrv.probe = Some(probe_callback::

); this.pdrv.remove = Some(remove_callback::

); + this.pdrv.shutdown = Some(shutdown_callback::

); // SAFETY: // - `this.pdrv` lives at least until the call to `platform_driver_unregister()` returns. // - `name` pointer has static lifetime. @@ -163,4 +183,13 @@ pub trait PlatformDriver { /// Called when a platform device is removed. /// Implementers should prepare the device for complete removal here. fn remove(device_id: i32, drv_data: Self::DrvData) -> Result; + + /// Platform driver shutdown. + /// + /// Called at shut-down time to quiesce the device. + fn shutdown( + _device_id: i32, + _drv_data: &<::Borrowed as Deref>::Target, + ) { + } }