From e05f0677637b2816c5aef852b3e52b135b51ae7e Mon Sep 17 00:00:00 2001
From: Fabien Parent <fabien.parent@linaro.org>
Date: Wed, 3 May 2023 01:01:08 +0200
Subject: [PATCH] samples: rust: add debugfs samples

Add some basic debugfs sample module to show how to use the debugfs API.
The sample module is showing:
 * How to create a directory
 * How to define and register a debugfs file by implementing
   file::Operations
 * How to use the attribute macro to expose simple numerical debugfs
   values. This is the equivalent of the C macro
   DEFINE_DEBUGFS_ATTRIBUTE{,_SIGNED}

Signed-off-by: Fabien Parent <fabien.parent@linaro.org>
---
 samples/rust/Kconfig         |  10 +++
 samples/rust/Makefile        |   1 +
 samples/rust/rust_debugfs.rs | 114 +++++++++++++++++++++++++++++++++++
 3 files changed, 125 insertions(+)
 create mode 100644 samples/rust/rust_debugfs.rs

diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
index b0f74a81c8f9ad..fc26dafc6fa386 100644
--- a/samples/rust/Kconfig
+++ b/samples/rust/Kconfig
@@ -10,6 +10,16 @@ menuconfig SAMPLES_RUST
 
 if SAMPLES_RUST
 
+config SAMPLE_RUST_DEBUGFS
+	tristate "Debugfs"
+	help
+	  This option builds the Rust debugfs module sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_debugfs.
+
+	  If unsure, say N.
+
 config SAMPLE_RUST_MINIMAL
 	tristate "Minimal"
 	help
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
index 03086dabbea44f..f80ff73028b40c 100644
--- a/samples/rust/Makefile
+++ b/samples/rust/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
+obj-$(CONFIG_SAMPLE_RUST_DEBUGFS)		+= rust_debugfs.o
 obj-$(CONFIG_SAMPLE_RUST_MINIMAL)		+= rust_minimal.o
 obj-$(CONFIG_SAMPLE_RUST_PRINT)			+= rust_print.o
 
diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs
new file mode 100644
index 00000000000000..063cfd21ea324c
--- /dev/null
+++ b/samples/rust/rust_debugfs.rs
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust debugfs device sample
+
+#![allow(missing_docs)]
+
+use kernel::{
+    c_str, debugfs, file,
+    file::File,
+    io_buffer::IoBufferWriter,
+    prelude::*,
+    sync::{Arc, SpinLock},
+    types::Mode,
+};
+
+struct SampleFile;
+
+#[vtable]
+impl file::Operations for SampleFile {
+    fn open(_data: &(), _file: &File) -> Result {
+        Ok(())
+    }
+
+    fn read(
+        _data: (),
+        _file: &File,
+        writer: &mut impl IoBufferWriter,
+        offset: u64,
+    ) -> Result<usize> {
+        let data = b"Sample debugfs file implementing file::Operations\n";
+        let offset = offset as usize;
+
+        if offset > data.len() {
+            return Ok(0);
+        }
+
+        let len = core::cmp::min(writer.len(), data.len() - offset);
+        writer.write_slice(&data[offset..(offset + len)])?;
+        Ok(len)
+    }
+}
+
+#[pin_data]
+struct IncAttribute {
+    #[pin]
+    data: SpinLock<i64>,
+}
+
+impl debugfs::attr::Attribute<i64> for IncAttribute {
+    fn get(&self) -> Result<i64> {
+        let mut guard = self.data.lock();
+        let ret = *guard;
+        *guard = ret + 1;
+        Ok(ret)
+    }
+
+    fn set(&self, val: i64) -> Result {
+        let mut guard = self.data.lock();
+        *guard = val;
+        Ok(())
+    }
+}
+
+debugfs::attribute_signed!(IncAttribute, "%#d\n");
+
+struct RustDebugfs {
+    _sample_file: debugfs::PinnedRegistration,
+    _inc_attribute: debugfs::PinnedRegistration<Arc<IncAttribute>>,
+    _symlink: debugfs::Registration<()>,
+}
+impl kernel::Module for RustDebugfs {
+    fn init(_module: &'static ThisModule) -> Result<Self> {
+        let dir = Arc::try_new(debugfs::Registration::register_dir(
+            c_str!("rust_samples"),
+            None,
+        )?)?;
+
+        let sample_file = debugfs::Registration::register_file::<SampleFile>(
+            c_str!("sample"),
+            Mode::from_int(0444),
+            (),
+            Some(dir.clone()),
+        )?;
+
+        let symlink = debugfs::Registration::register_symlink(
+            c_str!("sample_symlink"),
+            Some(dir.clone()),
+            c_str!("sample"),
+        )?;
+
+        let attribute = Arc::pin_init(pin_init!(IncAttribute {
+            data <- kernel::new_spinlock!(0x42),
+        }))?;
+        let inc_attribute = attribute.register(
+            c_str!("inc_attribute"),
+            Mode::from_int(0666),
+            Some(dir.clone()),
+        )?;
+
+        Ok(Self {
+            _sample_file: sample_file,
+            _inc_attribute: inc_attribute,
+            _symlink: symlink,
+        })
+    }
+}
+
+module! {
+    type: RustDebugfs,
+    name: "rust_debugfs",
+    author: "Fabien Parent <fabien.parent@linaro.org>",
+    description: "Rust debugfs sample",
+    license: "GPL",
+}