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 ) -> impl PinInit<Self, Error> { 110 RustDebugFs::new(pdev).pin_chain(|this| { 111 this.counter.store(91, Ordering::Relaxed); 112 { 113 let mut guard = this.inner.lock(); 114 guard.x = guard.y; 115 guard.y = 42; 116 } 117 118 Ok(()) 119 }) 120 } 121 } 122 123 impl RustDebugFs { 124 fn build_counter(dir: &Dir) -> impl PinInit<File<AtomicUsize>> + '_ { 125 dir.read_write_file(c_str!("counter"), AtomicUsize::new(0)) 126 } 127 128 fn build_inner(dir: &Dir) -> impl PinInit<File<Mutex<Inner>>> + '_ { 129 dir.read_write_file(c_str!("pair"), new_mutex!(Inner { x: 3, y: 10 })) 130 } 131 132 fn new(pdev: &platform::Device<Core>) -> impl PinInit<Self, Error> + '_ { 133 let debugfs = Dir::new(c_str!("sample_debugfs")); 134 let dev = pdev.as_ref(); 135 136 try_pin_init! { 137 Self { 138 _compatible <- debugfs.read_only_file( 139 c_str!("compatible"), 140 dev.fwnode() 141 .ok_or(ENOENT)? 142 .property_read::<CString>(c_str!("compatible")) 143 .required_by(dev)?, 144 ), 145 counter <- Self::build_counter(&debugfs), 146 inner <- Self::build_inner(&debugfs), 147 _debugfs: debugfs, 148 pdev: pdev.into(), 149 } 150 } 151 } 152 } 153