All of lore.kernel.org
 help / color / mirror / Atom feed
From: clicedvly768 <harepro29@gmail.com>
To: ojeda@kernel.org, dmitry.torokhov@gmail.com
Cc: rust-for-linux@vger.kernel.org, linux-input@vger.kernel.org,
	clicedvly768 <harepro29@gmail.com>
Subject: [PATCH 1/3] rust: input: add input device abstractions
Date: Sat,  7 Nov 2026 00:17:12 +0500	[thread overview]
Message-ID: <20261106191714.334055-2-harepro29@gmail.com> (raw)
In-Reply-To: <20261106191714.334055-1-harepro29@gmail.com>

Add safe Rust abstractions for Linux input devices (struct input_dev).

This provides:
- `AllocatedDevice`: a newly allocated, unregistered input device handle
  that allows configuring capabilities (keys, absolute axes limits)
  before registration.
- `RegisteredDevice`: a registered input device handle providing safe
  methods to report keys, absolute coordinates, and synchronization
  events. Automatically calls `input_unregister_device` on drop (RAII).
- Constants for bus types (`bus::*`) and event types (`event_type::*`).
- C helper wrappers for inline static functions in <linux/input.h>.

Signed-off-by: clicedvly768 <harepro29@gmail.com>
---
 rust/bindings/bindings_helper.h |   1 +
 rust/helpers/helpers.c          |   1 +
 rust/helpers/input.c            |  18 ++++
 rust/kernel/input.rs            | 174 ++++++++++++++++++++++++++++++++
 rust/kernel/lib.rs              |   1 +
 5 files changed, 195 insertions(+)
 create mode 100644 rust/helpers/input.c
 create mode 100644 rust/kernel/input.rs

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 3791af0aadc7..301c75cfeb61 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -171,3 +171,4 @@ const unsigned long RUST_CONST_HELPER_GPU_BUDDY_TRIM_DISABLE = GPU_BUDDY_TRIM_DI
 #include "../../drivers/android/binder/rust_binder.h"
 #include "../../drivers/android/binder/rust_binder_events.h"
 #endif
+#include <linux/input.h>
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index d62c7be1ca7b..0bc33a7b4351 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -109,3 +109,4 @@
 #include "wait.c"
 #include "workqueue.c"
 #include "xarray.c"
+#include "input.c"
diff --git a/rust/helpers/input.c b/rust/helpers/input.c
new file mode 100644
index 000000000000..531733d32f9c
--- /dev/null
+++ b/rust/helpers/input.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/input.h>
+
+__rust_helper void rust_helper_input_report_key(struct input_dev *dev, unsigned int code, int value)
+{
+	input_report_key(dev, code, value);
+}
+
+__rust_helper void rust_helper_input_report_abs(struct input_dev *dev, unsigned int code, int value)
+{
+	input_report_abs(dev, code, value);
+}
+
+__rust_helper void rust_helper_input_sync(struct input_dev *dev)
+{
+	input_sync(dev);
+}
diff --git a/rust/kernel/input.rs b/rust/kernel/input.rs
new file mode 100644
index 000000000000..dc617fdbdcfd
--- /dev/null
+++ b/rust/kernel/input.rs
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Input subsystem abstractions for safe Rust drivers.
+//!
+//! Provides a safe Rust object-oriented interface around Linux `struct input_dev`,
+//! ensuring safe allocation, capability configuration, registration, and RAII cleanup.
+
+use crate::{bindings, error::Result, prelude::*, str::CStr};
+use core::ptr::NonNull;
+
+/// Bus types for input devices.
+pub mod bus {
+    use super::*;
+
+    /// PCI bus.
+    pub const PCI: u16 = bindings::BUS_PCI as u16;
+    /// USB bus.
+    pub const USB: u16 = bindings::BUS_USB as u16;
+    /// RS232 serial bus.
+    pub const RS232: u16 = bindings::BUS_RS232 as u16;
+    /// I8042 PS/2 bus.
+    pub const I8042: u16 = bindings::BUS_I8042 as u16;
+}
+
+/// Linux input event types.
+pub mod event_type {
+    use super::*;
+
+    /// Synchronisation event.
+    pub const SYN: u32 = bindings::EV_SYN;
+    /// Key or button event.
+    pub const KEY: u32 = bindings::EV_KEY;
+    /// Relative movement event.
+    pub const REL: u32 = bindings::EV_REL;
+    /// Absolute movement event.
+    pub const ABS: u32 = bindings::EV_ABS;
+}
+
+/// An allocated input device that hasn't been registered yet.
+pub struct AllocatedDevice {
+    ptr: NonNull<bindings::input_dev>,
+}
+
+impl AllocatedDevice {
+    /// Allocates a new input device.
+    pub fn new() -> Result<Self> {
+        // SAFETY: `input_allocate_device` returns either a valid pointer or NULL.
+        let ptr = unsafe { bindings::input_allocate_device() };
+        let ptr = NonNull::new(ptr).ok_or(crate::error::code::ENOMEM)?;
+
+        Ok(Self { ptr })
+    }
+
+    /// Sets the human-readable device name.
+    pub fn set_name(&mut self, name: &'static CStr) {
+        // SAFETY: `self.ptr` is valid and `name` has static lifetime.
+        unsafe {
+            (*self.ptr.as_ptr()).name = name.as_char_ptr().cast();
+        }
+    }
+
+    /// Sets the physical location string.
+    pub fn set_phys(&mut self, phys: *const u8) {
+        // SAFETY: `self.ptr` is valid.
+        unsafe {
+            (*self.ptr.as_ptr()).phys = phys.cast();
+        }
+    }
+
+    /// Sets device identifier (bus type, vendor, product, version).
+    pub fn set_id(&mut self, bustype: u16, vendor: u16, product: u16, version: u16) {
+        // SAFETY: `self.ptr` is valid.
+        unsafe {
+            let dev = self.ptr.as_ptr();
+            (*dev).id.bustype = bustype;
+            (*dev).id.vendor = vendor;
+            (*dev).id.product = product;
+            (*dev).id.version = version;
+        }
+    }
+
+    /// Enables support for a capability (e.g. key or axis).
+    pub fn set_capability(&mut self, type_: u32, code: u32) {
+        // SAFETY: `self.ptr` is valid and type/code are valid capability values.
+        unsafe {
+            bindings::input_set_capability(self.ptr.as_ptr(), type_, code);
+        }
+    }
+
+    /// Sets parameter limits for an absolute axis.
+    pub fn set_abs_params(&mut self, axis: u32, min: i32, max: i32, fuzz: i32, flat: i32) {
+        // SAFETY: `self.ptr` is valid.
+        unsafe {
+            bindings::input_set_abs_params(self.ptr.as_ptr(), axis, min, max, fuzz, flat);
+        }
+    }
+
+    /// Registers the input device with the kernel subsystem.
+    ///
+    /// Consumes the `AllocatedDevice` and returns a registered RAII handle [`RegisteredDevice`].
+    pub fn register(self) -> Result<RegisteredDevice> {
+        let dev_ptr = self.ptr.as_ptr();
+        core::mem::forget(self);
+
+        // SAFETY: `dev_ptr` was allocated by `input_allocate_device()`.
+        let ret = unsafe { bindings::input_register_device(dev_ptr) };
+        if ret != 0 {
+            // SAFETY: Clean up on failure.
+            unsafe {
+                bindings::input_free_device(dev_ptr);
+            }
+            return Err(crate::error::Error::from_errno(ret));
+        }
+
+        // SAFETY: `dev_ptr` is known valid and non-null from `AllocatedDevice`.
+        let ptr = unsafe { NonNull::new_unchecked(dev_ptr) };
+        Ok(RegisteredDevice { ptr })
+    }
+}
+
+impl Drop for AllocatedDevice {
+    fn drop(&mut self) {
+        // SAFETY: Device was allocated but not registered; free it cleanly.
+        unsafe {
+            bindings::input_free_device(self.ptr.as_ptr());
+        }
+    }
+}
+
+/// A registered input device capable of reporting events.
+pub struct RegisteredDevice {
+    ptr: NonNull<bindings::input_dev>,
+}
+
+impl RegisteredDevice {
+    /// Reports a binary key/button press or release event.
+    pub fn report_key(&self, code: u32, value: bool) {
+        // SAFETY: `self.ptr` points to a valid registered `struct input_dev`.
+        unsafe {
+            bindings::input_report_key(self.ptr.as_ptr(), code, if value { 1 } else { 0 });
+        }
+    }
+
+    /// Reports an absolute axis coordinate.
+    pub fn report_abs(&self, axis: u32, value: i32) {
+        // SAFETY: `self.ptr` points to a valid registered `struct input_dev`.
+        unsafe {
+            bindings::input_report_abs(self.ptr.as_ptr(), axis, value);
+        }
+    }
+
+    /// Synchronizes input events (signals completion of an event packet).
+    pub fn sync(&self) {
+        // SAFETY: `self.ptr` points to a valid registered `struct input_dev`.
+        unsafe {
+            bindings::input_sync(self.ptr.as_ptr());
+        }
+    }
+}
+
+impl Drop for RegisteredDevice {
+    fn drop(&mut self) {
+        // SAFETY: `self.ptr` is a valid registered device.
+        // `input_unregister_device` automatically unregisters and frees it.
+        unsafe {
+            bindings::input_unregister_device(self.ptr.as_ptr());
+        }
+    }
+}
+
+// SAFETY: `RegisteredDevice` can be safely sent across threads (the input core is thread-safe).
+unsafe impl Send for RegisteredDevice {}
+// SAFETY: `RegisteredDevice` can be safely shared across threads.
+unsafe impl Sync for RegisteredDevice {}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 1ab41129d557..35cbde5f6a97 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -314,3 +314,4 @@ pub fn file_from_location<'a>(loc: &'a core::panic::Location<'a>) -> &'a core::f
         c"<Location::file_as_c_str() not supported>"
     }
 }
+pub mod input;
-- 
2.56.0


  reply	other threads:[~2026-11-06 19:17 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-06 19:17 [PATCH 0/3] rust: input: add input/serio abstractions and port Gravis Stinger driver clicedvly768
2026-11-06 19:17 ` clicedvly768 [this message]
2026-11-06 19:29   ` [PATCH 1/3] rust: input: add input device abstractions sashiko-bot
2026-11-06 19:17 ` [PATCH 2/3] rust: serio: add serio bus abstractions clicedvly768
2026-11-06 19:35   ` sashiko-bot
2026-11-06 19:17 ` [PATCH 3/3] input: joystick: stinger: port Gravis Stinger driver to safe Rust clicedvly768
2026-11-06 19:42   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261106191714.334055-2-harepro29@gmail.com \
    --to=harepro29@gmail.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=linux-input@vger.kernel.org \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.