rust_debugfs.rs 4.6 KB

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