projects/linux·blob master · refs

179 lines · 4.7 KiB

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
34use core::str::FromStr;
35use kernel::{
36 acpi,
37 debugfs::{
38 Dir,
39 File, //
40 },
41 device::Core,
42 new_mutex,
43 of,
44 platform,
45 prelude::*,
46 sizes::*,
47 str::CString,
48 sync::{
49 aref::ARef,
50 atomic::{
51 Atomic,
52 Relaxed, //
53 },
54 Mutex,
55 }, //
56};
57
58kernel::module_platform_driver! {
59 type: RustDebugFs,
60 name: "rust_debugfs",
61 authors: ["Matthew Maurer"],
62 description: "Rust DebugFS usage sample",
63 license: "GPL",
64}
65
66#[pin_data]
67struct RustDebugFs {
68 pdev: ARef<platform::Device>,
69 // As we only hold these for drop effect (to remove the directory/files) we have a leading
70 // underscore to indicate to the compiler that we don't expect to use this field directly.
71 _debugfs: Dir,
72 #[pin]
73 _compatible: File<CString>,
74 #[pin]
75 counter: File<Atomic<usize>>,
76 #[pin]
77 inner: File<Mutex<Inner>>,
78 #[pin]
79 array_blob: File<Mutex<[u8; 4]>>,
80 #[pin]
81 vector_blob: File<Mutex<KVec<u8>>>,
82}
83
84#[derive(Debug)]
85struct Inner {
86 x: u32,
87 y: u32,
88}
89
90impl FromStr for Inner {
91 type Err = Error;
92 fn from_str(s: &str) -> Result<Self> {
93 let mut parts = s.split_whitespace();
94 let x = parts
95 .next()
96 .ok_or(EINVAL)?
97 .parse::<u32>()
98 .map_err(|_| EINVAL)?;
99 let y = parts
100 .next()
101 .ok_or(EINVAL)?
102 .parse::<u32>()
103 .map_err(|_| EINVAL)?;
104 if parts.next().is_some() {
105 return Err(EINVAL);
106 }
107 Ok(Inner { x, y })
108 }
109}
110
111kernel::acpi_device_table!(
112 ACPI_TABLE,
113 <RustDebugFs as platform::Driver>::IdInfo,
114 [(acpi::DeviceId::new(c"LNUXBEEF"), ())]
115);
116
117impl platform::Driver for RustDebugFs {
118 type IdInfo = ();
119 type Data<'bound> = Self;
120 const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
121 const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE);
122
123 fn probe<'bound>(
124 pdev: &'bound platform::Device<Core<'_>>,
125 _info: Option<&'bound Self::IdInfo>,
126 ) -> impl PinInit<Self, Error> + 'bound {
127 RustDebugFs::new(pdev).pin_chain(|this| {
128 this.counter.store(91, Relaxed);
129 {
130 let mut guard = this.inner.lock();
131 guard.x = guard.y;
132 guard.y = 42;
133 }
134
135 Ok(())
136 })
137 }
138}
139
140impl RustDebugFs {
141 fn build_counter(dir: &Dir) -> impl PinInit<File<Atomic<usize>>> + '_ {
142 dir.read_write_file(c"counter", Atomic::<usize>::new(0))
143 }
144
145 fn build_inner(dir: &Dir) -> impl PinInit<File<Mutex<Inner>>> + '_ {
146 dir.read_write_file(c"pair", new_mutex!(Inner { x: 3, y: 10 }))
147 }
148
149 fn new<'a, 'b>(
150 pdev: &'a platform::Device<Core<'b>>,
151 ) -> impl PinInit<Self, Error> + use<'a, 'b> {
152 let debugfs = Dir::new(c"sample_debugfs");
153 let dev = pdev.as_ref();
154
155 try_pin_init! {
156 Self {
157 _compatible <- debugfs.read_only_file(
158 c"compatible",
159 dev.fwnode()
160 .ok_or(ENOENT)?
161 .property_read::<CString>(c"compatible")
162 .required_by(dev)?,
163 ),
164 counter <- Self::build_counter(&debugfs),
165 inner <- Self::build_inner(&debugfs),
166 array_blob <- debugfs.read_write_binary_file(
167 c"array_blob",
168 new_mutex!([0x62, 0x6c, 0x6f, 0x62]),
169 ),
170 vector_blob <- debugfs.read_write_binary_file(
171 c"vector_blob",
172 new_mutex!(kernel::kvec!(0x42; SZ_4K)?),
173 ),
174 _debugfs: debugfs,
175 pdev: pdev.into(),
176 }
177 }
178 }
179}