From 1e180614b3608e1cb0f81753b2172af253d58a52 Mon Sep 17 00:00:00 2001 From: Shankari Anand Date: Thu, 14 Aug 2025 16:16:15 +0530 Subject: rust: driver-core: Update ARef and AlwaysRefCounted imports from sync::aref Update call sites in the driver-core files and its related samples to import `ARef` and `AlwaysRefCounted` from `sync::aref` instead of `types`. This aligns with the ongoing effort to move `ARef` and `AlwaysRefCounted` to sync. Suggested-by: Benno Lossin Link: https://github.com/Rust-for-Linux/linux/issues/1173 Signed-off-by: Shankari Anand Link: https://lore.kernel.org/r/20250814104615.355106-1-shankari.ak0208@gmail.com Signed-off-by: Danilo Krummrich --- samples/rust/rust_driver_pci.rs | 2 +- samples/rust/rust_driver_platform.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'samples/rust') diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index 606946ff4d7f..0798019014cd 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -4,7 +4,7 @@ //! //! To make this driver probe, QEMU must be run with `-device pci-testdev`. -use kernel::{bindings, c_str, device::Core, devres::Devres, pci, prelude::*, types::ARef}; +use kernel::{bindings, c_str, device::Core, devres::Devres, pci, prelude::*, sync::aref::ARef}; struct Regs; diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs index 69ed55b7b0fa..6473baf4f120 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -72,7 +72,7 @@ use kernel::{ of, platform, prelude::*, str::CString, - types::ARef, + sync::aref::ARef, }; struct SampleDriver { -- cgit v1.2.3 From 1b8ac37677d307cd0fc10f6bf9bceae2c282bdb4 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Fri, 29 Aug 2025 15:36:31 -0700 Subject: rust: pci: use pci::Vendor instead of bindings::PCI_VENDOR_ID_* Change Device::vendor_id() to return a Vendor type, and change DeviceId::from_id() to accept a Vendor type. Use the new pci::Vendor in the various Rust for Linux callers who were previously using bindings::PCI_VENDOR_ID_*. Doing so also allows removing "use kernel::bindings" entirely from most of the affected files here. Also, mark vendor_id() as inline. Cc: Danilo Krummrich Cc: Elle Rhumsaa Reviewed-by: Alexandre Courbot Signed-off-by: John Hubbard Link: https://lore.kernel.org/r/20250829223632.144030-6-jhubbard@nvidia.com [ Replace "as a validated vendor" with "as [`Vendor`]". - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/pci.rs | 35 ++++++++++++++++++++++++++--------- rust/kernel/pci/id.rs | 1 - samples/rust/rust_dma.rs | 6 +----- samples/rust/rust_driver_auxiliary.rs | 12 +++++------- samples/rust/rust_driver_pci.rs | 9 +++++---- 5 files changed, 37 insertions(+), 26 deletions(-) (limited to 'samples/rust') diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 5d95081346e6..391baf95929a 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -133,10 +133,10 @@ impl DeviceId { /// Equivalent to C's `PCI_DEVICE` macro. /// - /// Create a new `pci::DeviceId` from a vendor and device ID number. - pub const fn from_id(vendor: u32, device: u32) -> Self { + /// Create a new `pci::DeviceId` from a vendor and device ID. + pub const fn from_id(vendor: Vendor, device: u32) -> Self { Self(bindings::pci_device_id { - vendor, + vendor: vendor.as_raw() as u32, device, subvendor: DeviceId::PCI_ANY_ID, subdevice: DeviceId::PCI_ANY_ID, @@ -234,7 +234,7 @@ macro_rules! pci_device_table { /// ::IdInfo, /// [ /// ( -/// pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, bindings::PCI_ANY_ID as u32), +/// pci::DeviceId::from_id(pci::Vendor::REDHAT, bindings::PCI_ANY_ID as u32), /// (), /// ) /// ] @@ -415,12 +415,29 @@ impl Device { } impl Device { - /// Returns the PCI vendor ID. + /// Returns the PCI vendor ID as [`Vendor`]. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{device::Core, pci::{self, Vendor}, prelude::*}; + /// fn log_device_info(pdev: &pci::Device) -> Result { + /// // Get an instance of `Vendor`. + /// let vendor = pdev.vendor_id(); + /// dev_info!( + /// pdev.as_ref(), + /// "Device: Vendor={}, Device=0x{:x}\n", + /// vendor, + /// pdev.device_id() + /// ); + /// Ok(()) + /// } + /// ``` #[inline] - pub fn vendor_id(&self) -> u16 { - // SAFETY: By its type invariant `self.as_raw` is always a valid pointer to a - // `struct pci_dev`. - unsafe { (*self.as_raw()).vendor } + pub fn vendor_id(&self) -> Vendor { + // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`. + let vendor_id = unsafe { (*self.as_raw()).vendor }; + Vendor::from_raw(vendor_id) } /// Returns the PCI device ID. diff --git a/rust/kernel/pci/id.rs b/rust/kernel/pci/id.rs index f56a024f80aa..8ee1dc5c3057 100644 --- a/rust/kernel/pci/id.rs +++ b/rust/kernel/pci/id.rs @@ -136,7 +136,6 @@ macro_rules! define_all_pci_vendors { /// Once constructed, a `Vendor` contains a valid PCI Vendor ID. impl Vendor { /// Create a Vendor from a raw 16-bit vendor ID. - #[expect(dead_code)] #[inline] pub(super) fn from_raw(vendor_id: u16) -> Self { Self(vendor_id) diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs index c5e7cce68654..f3385c4a7e5b 100644 --- a/samples/rust/rust_dma.rs +++ b/samples/rust/rust_dma.rs @@ -5,7 +5,6 @@ //! To make this driver probe, QEMU must be run with `-device pci-testdev`. use kernel::{ - bindings, device::Core, dma::{CoherentAllocation, Device, DmaMask}, pci, @@ -45,10 +44,7 @@ kernel::pci_device_table!( PCI_TABLE, MODULE_PCI_TABLE, ::IdInfo, - [( - pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5), - () - )] + [(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())] ); impl pci::Driver for DmaSampleDriver { diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs index f2a820683fc3..55ece336ee45 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -5,7 +5,7 @@ //! To make this driver probe, QEMU must be run with `-device pci-testdev`. use kernel::{ - auxiliary, bindings, c_str, device::Core, driver, error::Error, pci, prelude::*, InPlaceModule, + auxiliary, c_str, device::Core, driver, error::Error, pci, prelude::*, InPlaceModule, }; use pin_init::PinInit; @@ -50,10 +50,7 @@ kernel::pci_device_table!( PCI_TABLE, MODULE_PCI_TABLE, ::IdInfo, - [( - pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5), - () - )] + [(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())] ); impl pci::Driver for ParentDriver { @@ -81,11 +78,12 @@ impl ParentDriver { let parent = adev.parent().ok_or(EINVAL)?; let pdev: &pci::Device = parent.try_into()?; + let vendor = pdev.vendor_id(); dev_info!( adev.as_ref(), - "Connect auxiliary {} with parent: VendorID={:#x}, DeviceID={:#x}\n", + "Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n", adev.id(), - pdev.vendor_id(), + vendor, pdev.device_id() ); diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index 0798019014cd..97baec8df9bc 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -4,7 +4,7 @@ //! //! To make this driver probe, QEMU must be run with `-device pci-testdev`. -use kernel::{bindings, c_str, device::Core, devres::Devres, pci, prelude::*, sync::aref::ARef}; +use kernel::{c_str, device::Core, devres::Devres, pci, prelude::*, sync::aref::ARef}; struct Regs; @@ -38,7 +38,7 @@ kernel::pci_device_table!( MODULE_PCI_TABLE, ::IdInfo, [( - pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5), + pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), TestIndex::NO_EVENTFD )] ); @@ -66,10 +66,11 @@ impl pci::Driver for SampleDriver { const ID_TABLE: pci::IdTable = &PCI_TABLE; fn probe(pdev: &pci::Device, info: &Self::IdInfo) -> Result>> { + let vendor = pdev.vendor_id(); dev_dbg!( pdev.as_ref(), - "Probe Rust PCI driver sample (PCI ID: 0x{:x}, 0x{:x}).\n", - pdev.vendor_id(), + "Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n", + vendor, pdev.device_id() ); -- cgit v1.2.3 From 6f227d21377c8b86bcacb266ee1f72bc937f4598 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Thu, 4 Sep 2025 21:13:56 +0000 Subject: samples: rust: Add debugfs sample driver Adds a new sample driver that demonstrates the debugfs APIs. The driver creates a directory in debugfs and populates it with a few files: - A read-only file that displays a fwnode property. - A read-write file that exposes an atomic counter. - A read-write file that exposes a custom struct. This sample serves as a basic example of how to use the `debugfs::Dir` and `debugfs::File` APIs to create and manage debugfs entries. Signed-off-by: Matthew Maurer Tested-by: Dirk Behme Acked-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250904-debugfs-rust-v11-5-7d12a165685a@google.com [ Change ACPI ID "LNUXDEBF" to "LNUXBEEF". - Danilo ] Signed-off-by: Danilo Krummrich --- MAINTAINERS | 1 + samples/rust/Kconfig | 11 ++++ samples/rust/Makefile | 1 + samples/rust/rust_debugfs.rs | 151 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+) create mode 100644 samples/rust/rust_debugfs.rs (limited to 'samples/rust') diff --git a/MAINTAINERS b/MAINTAINERS index 4dc5d124bb14..4c471251a304 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7496,6 +7496,7 @@ F: rust/kernel/devres.rs F: rust/kernel/driver.rs F: rust/kernel/faux.rs F: rust/kernel/platform.rs +F: samples/rust/rust_debugfs.rs F: samples/rust/rust_driver_platform.rs F: samples/rust/rust_driver_faux.rs diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index 7f7371a004ee..01101db41ae3 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -62,6 +62,17 @@ config SAMPLE_RUST_DMA If unsure, say N. +config SAMPLE_RUST_DEBUGFS + tristate "DebugFS Test Module" + depends on DEBUG_FS + help + This option builds the Rust DebugFS Test module sample. + + To compile this as a module, choose M here: + the module will be called rust_debugfs. + + If unsure, say N. + config SAMPLE_RUST_DRIVER_PCI tristate "PCI Driver" depends on PCI diff --git a/samples/rust/Makefile b/samples/rust/Makefile index bd2faad63b4f..61276222a99f 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -4,6 +4,7 @@ ccflags-y += -I$(src) # needed for trace events obj-$(CONFIG_SAMPLE_RUST_MINIMAL) += rust_minimal.o obj-$(CONFIG_SAMPLE_RUST_MISC_DEVICE) += rust_misc_device.o obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o +obj-$(CONFIG_SAMPLE_RUST_DEBUGFS) += rust_debugfs.o obj-$(CONFIG_SAMPLE_RUST_DMA) += rust_dma.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) += rust_driver_pci.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) += rust_driver_platform.o diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs new file mode 100644 index 000000000000..82b61a15a34b --- /dev/null +++ b/samples/rust/rust_debugfs.rs @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +//! Sample DebugFS exporting platform driver +//! +//! To successfully probe this driver with ACPI, use an ssdt that looks like +//! +//! ```dsl +//! DefinitionBlock ("", "SSDT", 2, "TEST", "VIRTACPI", 0x00000001) +//! { +//! Scope (\_SB) +//! { +//! Device (T432) +//! { +//! Name (_HID, "LNUXBEEF") // ACPI hardware ID to match +//! Name (_UID, 1) +//! Name (_STA, 0x0F) // Device present, enabled +//! Name (_DSD, Package () { // Sample attribute +//! ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +//! Package() { +//! Package(2) {"compatible", "sample-debugfs"} +//! } +//! }) +//! Name (_CRS, ResourceTemplate () +//! { +//! Memory32Fixed (ReadWrite, 0xFED00000, 0x1000) +//! }) +//! } +//! } +//! } +//! ``` + +use core::str::FromStr; +use core::sync::atomic::AtomicUsize; +use core::sync::atomic::Ordering; +use kernel::c_str; +use kernel::debugfs::{Dir, File}; +use kernel::new_mutex; +use kernel::prelude::*; +use kernel::sync::Mutex; + +use kernel::{acpi, device::Core, of, platform, str::CString, types::ARef}; + +kernel::module_platform_driver! { + type: RustDebugFs, + name: "rust_debugfs", + authors: ["Matthew Maurer"], + description: "Rust DebugFS usage sample", + license: "GPL", +} + +#[pin_data] +struct RustDebugFs { + pdev: ARef, + // As we only hold these for drop effect (to remove the directory/files) we have a leading + // underscore to indicate to the compiler that we don't expect to use this field directly. + _debugfs: Dir, + #[pin] + _compatible: File, + #[pin] + counter: File, + #[pin] + inner: File>, +} + +#[derive(Debug)] +struct Inner { + x: u32, + y: u32, +} + +impl FromStr for Inner { + type Err = Error; + fn from_str(s: &str) -> Result { + let mut parts = s.split_whitespace(); + let x = parts + .next() + .ok_or(EINVAL)? + .parse::() + .map_err(|_| EINVAL)?; + let y = parts + .next() + .ok_or(EINVAL)? + .parse::() + .map_err(|_| EINVAL)?; + if parts.next().is_some() { + return Err(EINVAL); + } + Ok(Inner { x, y }) + } +} + +kernel::acpi_device_table!( + ACPI_TABLE, + MODULE_ACPI_TABLE, + ::IdInfo, + [(acpi::DeviceId::new(c_str!("LNUXBEEF")), ())] +); + +impl platform::Driver for RustDebugFs { + type IdInfo = (); + const OF_ID_TABLE: Option> = None; + const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); + + fn probe( + pdev: &platform::Device, + _info: Option<&Self::IdInfo>, + ) -> Result>> { + let result = KBox::try_pin_init(RustDebugFs::new(pdev), GFP_KERNEL)?; + // We can still mutate fields through the files which are atomic or mutexed: + result.counter.store(91, Ordering::Relaxed); + { + let mut guard = result.inner.lock(); + guard.x = guard.y; + guard.y = 42; + } + Ok(result) + } +} + +impl RustDebugFs { + fn build_counter(dir: &Dir) -> impl PinInit> + '_ { + dir.read_write_file(c_str!("counter"), AtomicUsize::new(0)) + } + + fn build_inner(dir: &Dir) -> impl PinInit>> + '_ { + dir.read_write_file(c_str!("pair"), new_mutex!(Inner { x: 3, y: 10 })) + } + + fn new(pdev: &platform::Device) -> impl PinInit + '_ { + let debugfs = Dir::new(c_str!("sample_debugfs")); + let dev = pdev.as_ref(); + + try_pin_init! { + Self { + _compatible <- debugfs.read_only_file( + c_str!("compatible"), + dev.fwnode() + .ok_or(ENOENT)? + .property_read::(c_str!("compatible")) + .required_by(dev)?, + ), + counter <- Self::build_counter(&debugfs), + inner <- Self::build_inner(&debugfs), + _debugfs: debugfs, + pdev: pdev.into(), + } + } + } +} -- cgit v1.2.3 From d4a5d397c7fb1ca967e0da202cac196e7324f4ea Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Thu, 4 Sep 2025 21:13:58 +0000 Subject: samples: rust: Add scoped debugfs sample driver Adds a new sample driver `rust_scoped_debugfs` that demonstrates the use of the scoped debugfs APIs. The driver creates a `control` directory with two write-only files, `create` and `remove`. Writing a name and a series of numbers to `create` will create a new subdirectory under a `dynamic` directory. This new subdirectory will contain files that expose the numbers as atomic values. Writing a name to `remove` will remove the corresponding subdirectory from the `dynamic` directory. This sample serves as an example of how to use the `debugfs::Scope` and `debugfs::ScopedDir` APIs to create and manage debugfs entries that are tied to the lifetime of a data structure. Signed-off-by: Matthew Maurer Tested-by: Dirk Behme Acked-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250904-debugfs-rust-v11-7-7d12a165685a@google.com [ Rename "scoped_debugfs" -> "debugfs_scoped", fix up Result<(), Error> -> Result. - Danilo ] Signed-off-by: Danilo Krummrich --- MAINTAINERS | 1 + samples/rust/Kconfig | 11 +++ samples/rust/Makefile | 1 + samples/rust/rust_debugfs_scoped.rs | 134 ++++++++++++++++++++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 samples/rust/rust_debugfs_scoped.rs (limited to 'samples/rust') diff --git a/MAINTAINERS b/MAINTAINERS index 4c471251a304..c01599d1727c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7497,6 +7497,7 @@ F: rust/kernel/driver.rs F: rust/kernel/faux.rs F: rust/kernel/platform.rs F: samples/rust/rust_debugfs.rs +F: samples/rust/rust_debugfs_scoped.rs F: samples/rust/rust_driver_platform.rs F: samples/rust/rust_driver_faux.rs diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index 01101db41ae3..66360cdf048f 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -73,6 +73,17 @@ config SAMPLE_RUST_DEBUGFS If unsure, say N. +config SAMPLE_RUST_DEBUGFS_SCOPED + tristate "Scoped DebugFS Test Module" + depends on DEBUG_FS + help + This option builds the Rust Scoped DebugFS Test module sample. + + To compile this as a module, choose M here: + the module will be called rust_debugfs_scoped. + + If unsure, say N. + config SAMPLE_RUST_DRIVER_PCI tristate "PCI Driver" depends on PCI diff --git a/samples/rust/Makefile b/samples/rust/Makefile index 61276222a99f..69ca01497b58 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_SAMPLE_RUST_MINIMAL) += rust_minimal.o obj-$(CONFIG_SAMPLE_RUST_MISC_DEVICE) += rust_misc_device.o obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o obj-$(CONFIG_SAMPLE_RUST_DEBUGFS) += rust_debugfs.o +obj-$(CONFIG_SAMPLE_RUST_DEBUGFS_SCOPED) += rust_debugfs_scoped.o obj-$(CONFIG_SAMPLE_RUST_DMA) += rust_dma.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) += rust_driver_pci.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) += rust_driver_platform.o diff --git a/samples/rust/rust_debugfs_scoped.rs b/samples/rust/rust_debugfs_scoped.rs new file mode 100644 index 000000000000..b0c4e76b123e --- /dev/null +++ b/samples/rust/rust_debugfs_scoped.rs @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +//! Sample DebugFS exporting platform driver that demonstrates the use of +//! `Scope::dir` to create a variety of files without the need to separately +//! track them all. + +use core::sync::atomic::AtomicUsize; +use kernel::debugfs::{Dir, Scope}; +use kernel::prelude::*; +use kernel::sync::Mutex; +use kernel::{c_str, new_mutex, str::CString}; + +module! { + type: RustScopedDebugFs, + name: "rust_debugfs_scoped", + authors: ["Matthew Maurer"], + description: "Rust Scoped DebugFS usage sample", + license: "GPL", +} + +fn remove_file_write( + mod_data: &ModuleData, + reader: &mut kernel::uaccess::UserSliceReader, +) -> Result { + let mut buf = [0u8; 128]; + if reader.len() >= buf.len() { + return Err(EINVAL); + } + let n = reader.len(); + reader.read_slice(&mut buf[..n])?; + + let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?.trim(); + let nul_idx = s.len(); + buf[nul_idx] = 0; + let to_remove = CStr::from_bytes_with_nul(&buf[..nul_idx + 1]).map_err(|_| EINVAL)?; + mod_data + .devices + .lock() + .retain(|device| device.name.as_bytes() != to_remove.as_bytes()); + Ok(()) +} + +fn create_file_write( + mod_data: &ModuleData, + reader: &mut kernel::uaccess::UserSliceReader, +) -> Result { + let mut buf = [0u8; 128]; + if reader.len() > buf.len() { + return Err(EINVAL); + } + let n = reader.len(); + reader.read_slice(&mut buf[..n])?; + + let mut nums = KVec::new(); + + let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?.trim(); + let mut items = s.split_whitespace(); + let name_str = items.next().ok_or(EINVAL)?; + let name = CString::try_from_fmt(fmt!("{name_str}"))?; + let file_name = CString::try_from_fmt(fmt!("{name_str}"))?; + for sub in items { + nums.push( + AtomicUsize::new(sub.parse().map_err(|_| EINVAL)?), + GFP_KERNEL, + )?; + } + + let scope = KBox::pin_init( + mod_data + .device_dir + .scope(DeviceData { name, nums }, &file_name, |dev_data, dir| { + for (idx, val) in dev_data.nums.iter().enumerate() { + let Ok(name) = CString::try_from_fmt(fmt!("{idx}")) else { + return; + }; + dir.read_write_file(&name, val); + } + }), + GFP_KERNEL, + )?; + (*mod_data.devices.lock()).push(scope, GFP_KERNEL)?; + + Ok(()) +} + +struct RustScopedDebugFs { + _data: Pin>>, +} + +#[pin_data] +struct ModuleData { + device_dir: Dir, + #[pin] + devices: Mutex>>>>, +} + +impl ModuleData { + fn init(device_dir: Dir) -> impl PinInit { + pin_init! { + Self { + device_dir: device_dir, + devices <- new_mutex!(KVec::new()) + } + } + } +} + +struct DeviceData { + name: CString, + nums: KVec, +} + +fn init_control(base_dir: &Dir, dyn_dirs: Dir) -> impl PinInit> + '_ { + base_dir.scope( + ModuleData::init(dyn_dirs), + c_str!("control"), + |data, dir| { + dir.write_only_callback_file(c_str!("create"), data, &create_file_write); + dir.write_only_callback_file(c_str!("remove"), data, &remove_file_write); + }, + ) +} + +impl kernel::Module for RustScopedDebugFs { + fn init(_module: &'static kernel::ThisModule) -> Result { + let base_dir = Dir::new(c_str!("rust_scoped_debugfs")); + let dyn_dirs = base_dir.subdir(c_str!("dynamic")); + Ok(Self { + _data: KBox::pin_init(init_control(&base_dir, dyn_dirs), GFP_KERNEL)?, + }) + } +} -- cgit v1.2.3