Skip to content

Commit 6f227d2

Browse files
maurerDanilo Krummrich
authored andcommitted
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 <mmaurer@google.com> Tested-by: Dirk Behme <dirk.behme@de.bosch.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> 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 <dakr@kernel.org>
1 parent 40ecc49 commit 6f227d2

4 files changed

Lines changed: 164 additions & 0 deletions

File tree

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7496,6 +7496,7 @@ F: rust/kernel/devres.rs
74967496
F: rust/kernel/driver.rs
74977497
F: rust/kernel/faux.rs
74987498
F: rust/kernel/platform.rs
7499+
F: samples/rust/rust_debugfs.rs
74997500
F: samples/rust/rust_driver_platform.rs
75007501
F: samples/rust/rust_driver_faux.rs
75017502

samples/rust/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,17 @@ config SAMPLE_RUST_DMA
6262

6363
If unsure, say N.
6464

65+
config SAMPLE_RUST_DEBUGFS
66+
tristate "DebugFS Test Module"
67+
depends on DEBUG_FS
68+
help
69+
This option builds the Rust DebugFS Test module sample.
70+
71+
To compile this as a module, choose M here:
72+
the module will be called rust_debugfs.
73+
74+
If unsure, say N.
75+
6576
config SAMPLE_RUST_DRIVER_PCI
6677
tristate "PCI Driver"
6778
depends on PCI

samples/rust/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ ccflags-y += -I$(src) # needed for trace events
44
obj-$(CONFIG_SAMPLE_RUST_MINIMAL) += rust_minimal.o
55
obj-$(CONFIG_SAMPLE_RUST_MISC_DEVICE) += rust_misc_device.o
66
obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o
7+
obj-$(CONFIG_SAMPLE_RUST_DEBUGFS) += rust_debugfs.o
78
obj-$(CONFIG_SAMPLE_RUST_DMA) += rust_dma.o
89
obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) += rust_driver_pci.o
910
obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) += rust_driver_platform.o

samples/rust/rust_debugfs.rs

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
// Copyright (C) 2025 Google LLC.
4+
5+
//! Sample DebugFS exporting platform driver
6+
//!
7+
//! To successfully probe this driver with ACPI, use an ssdt that looks like
8+
//!
9+
//! ```dsl
10+
//! DefinitionBlock ("", "SSDT", 2, "TEST", "VIRTACPI", 0x00000001)
11+
//! {
12+
//! Scope (\_SB)
13+
//! {
14+
//! Device (T432)
15+
//! {
16+
//! Name (_HID, "LNUXBEEF") // ACPI hardware ID to match
17+
//! Name (_UID, 1)
18+
//! Name (_STA, 0x0F) // Device present, enabled
19+
//! Name (_DSD, Package () { // Sample attribute
20+
//! ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
21+
//! Package() {
22+
//! Package(2) {"compatible", "sample-debugfs"}
23+
//! }
24+
//! })
25+
//! Name (_CRS, ResourceTemplate ()
26+
//! {
27+
//! Memory32Fixed (ReadWrite, 0xFED00000, 0x1000)
28+
//! })
29+
//! }
30+
//! }
31+
//! }
32+
//! ```
33+
34+
use core::str::FromStr;
35+
use core::sync::atomic::AtomicUsize;
36+
use core::sync::atomic::Ordering;
37+
use kernel::c_str;
38+
use kernel::debugfs::{Dir, File};
39+
use kernel::new_mutex;
40+
use kernel::prelude::*;
41+
use kernel::sync::Mutex;
42+
43+
use kernel::{acpi, device::Core, of, platform, str::CString, types::ARef};
44+
45+
kernel::module_platform_driver! {
46+
type: RustDebugFs,
47+
name: "rust_debugfs",
48+
authors: ["Matthew Maurer"],
49+
description: "Rust DebugFS usage sample",
50+
license: "GPL",
51+
}
52+
53+
#[pin_data]
54+
struct RustDebugFs {
55+
pdev: ARef<platform::Device>,
56+
// As we only hold these for drop effect (to remove the directory/files) we have a leading
57+
// underscore to indicate to the compiler that we don't expect to use this field directly.
58+
_debugfs: Dir,
59+
#[pin]
60+
_compatible: File<CString>,
61+
#[pin]
62+
counter: File<AtomicUsize>,
63+
#[pin]
64+
inner: File<Mutex<Inner>>,
65+
}
66+
67+
#[derive(Debug)]
68+
struct Inner {
69+
x: u32,
70+
y: u32,
71+
}
72+
73+
impl FromStr for Inner {
74+
type Err = Error;
75+
fn from_str(s: &str) -> Result<Self> {
76+
let mut parts = s.split_whitespace();
77+
let x = parts
78+
.next()
79+
.ok_or(EINVAL)?
80+
.parse::<u32>()
81+
.map_err(|_| EINVAL)?;
82+
let y = parts
83+
.next()
84+
.ok_or(EINVAL)?
85+
.parse::<u32>()
86+
.map_err(|_| EINVAL)?;
87+
if parts.next().is_some() {
88+
return Err(EINVAL);
89+
}
90+
Ok(Inner { x, y })
91+
}
92+
}
93+
94+
kernel::acpi_device_table!(
95+
ACPI_TABLE,
96+
MODULE_ACPI_TABLE,
97+
<RustDebugFs as platform::Driver>::IdInfo,
98+
[(acpi::DeviceId::new(c_str!("LNUXBEEF")), ())]
99+
);
100+
101+
impl platform::Driver for RustDebugFs {
102+
type IdInfo = ();
103+
const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
104+
const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE);
105+
106+
fn probe(
107+
pdev: &platform::Device<Core>,
108+
_info: Option<&Self::IdInfo>,
109+
) -> Result<Pin<KBox<Self>>> {
110+
let result = KBox::try_pin_init(RustDebugFs::new(pdev), GFP_KERNEL)?;
111+
// We can still mutate fields through the files which are atomic or mutexed:
112+
result.counter.store(91, Ordering::Relaxed);
113+
{
114+
let mut guard = result.inner.lock();
115+
guard.x = guard.y;
116+
guard.y = 42;
117+
}
118+
Ok(result)
119+
}
120+
}
121+
122+
impl RustDebugFs {
123+
fn build_counter(dir: &Dir) -> impl PinInit<File<AtomicUsize>> + '_ {
124+
dir.read_write_file(c_str!("counter"), AtomicUsize::new(0))
125+
}
126+
127+
fn build_inner(dir: &Dir) -> impl PinInit<File<Mutex<Inner>>> + '_ {
128+
dir.read_write_file(c_str!("pair"), new_mutex!(Inner { x: 3, y: 10 }))
129+
}
130+
131+
fn new(pdev: &platform::Device<Core>) -> impl PinInit<Self, Error> + '_ {
132+
let debugfs = Dir::new(c_str!("sample_debugfs"));
133+
let dev = pdev.as_ref();
134+
135+
try_pin_init! {
136+
Self {
137+
_compatible <- debugfs.read_only_file(
138+
c_str!("compatible"),
139+
dev.fwnode()
140+
.ok_or(ENOENT)?
141+
.property_read::<CString>(c_str!("compatible"))
142+
.required_by(dev)?,
143+
),
144+
counter <- Self::build_counter(&debugfs),
145+
inner <- Self::build_inner(&debugfs),
146+
_debugfs: debugfs,
147+
pdev: pdev.into(),
148+
}
149+
}
150+
}
151+
}

0 commit comments

Comments
 (0)