File Index
Files and directories
Sign in
FILE

rust_debugfs.rs

File preview with syntax highlighting.

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