[PATCH RESEND v23 2/3] rust: leds: add Mode trait
Markus Probst via B4 Relay <[email protected]> Wed, 05 Aug 2026 21:34:11 +0200
| Newsgroups | org.kernel.vger.linux-leds,org.kernel.feeds.b4-sent,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci,org.kernel.vger.rust-for-linux |
|---|---|
| Message-ID | <[email protected]> |
From: Markus Probst <[email protected]> Add the `led::Mode` trait to allow for other types of led class devices in `led::LedOps`. Signed-off-by: Markus Probst <[email protected]> --- rust/kernel/led.rs | 27 +++++++++++++++++++++++---- rust/kernel/led/normal.rs | 22 +++++++++++++++------- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/rust/kernel/led.rs b/rust/kernel/led.rs index 596975e103b8..5d7e6d08ad2a 100644 --- a/rust/kernel/led.rs +++ b/rust/kernel/led.rs @@ -32,7 +32,10 @@ mod normal; -pub use normal::Device; +pub use normal::{ + Device, + Normal, // +}; /// The name of the led is determined by the driver. pub enum Named {} @@ -161,6 +164,7 @@ pub fn name(self, name: &'init CStr) -> Self { /// #[vtable] /// impl led::LedOps for MyLedOps { /// type Bus = platform::Device<device::Bound>; +/// type Mode = led::Normal; /// const BLOCKING: bool = false; /// const MAX_BRIGHTNESS: u32 = 255; /// @@ -182,6 +186,11 @@ pub trait LedOps: Send + Sync + Sized { #[allow(private_bounds)] type Bus: AsBusDevice<Bound>; + /// The led mode to use. + /// + /// See [`Mode`]. + type Mode: Mode; + /// If set true, [`LedOps::brightness_set`] and [`LedOps::blink_set`] must perform the /// operation immediately. If set false, they must not sleep. const BLOCKING: bool; @@ -194,7 +203,7 @@ pub trait LedOps: Send + Sync + Sized { fn brightness_set<'bound>( &self, dev: &'bound Self::Bus, - classdev: &Device<'bound, Self>, + classdev: &<Self::Mode as Mode>::Device<'bound, Self>, brightness: u32, ) -> Result<()>; @@ -202,7 +211,7 @@ fn brightness_set<'bound>( fn brightness_get<'bound>( &self, dev: &'bound Self::Bus, - classdev: &Device<'bound, Self>, + classdev: &<Self::Mode as Mode>::Device<'bound, Self>, ) -> Result<u32> { let _ = (dev, classdev); build_error!(VTABLE_DEFAULT_ERROR) @@ -219,7 +228,7 @@ fn brightness_get<'bound>( fn blink_set<'bound>( &self, dev: &'bound Self::Bus, - classdev: &Device<'bound, Self>, + classdev: &<Self::Mode as Mode>::Device<'bound, Self>, delay_on: &mut usize, delay_off: &mut usize, ) -> Result<()> { @@ -283,6 +292,16 @@ fn try_from(value: u32) -> core::result::Result<Self, Self::Error> { } } +/// The led mode. +/// +/// Each led mode has its own led class device type with different capabilities. +/// +/// See [`Normal`]. +pub trait Mode: private::Sealed { + /// The class device for the led mode. + type Device<'bound, T: LedOps<Mode = Self> + 'bound>; +} + mod private { pub trait Sealed {} } diff --git a/rust/kernel/led/normal.rs b/rust/kernel/led/normal.rs index 816db7c57689..25190486a62d 100644 --- a/rust/kernel/led/normal.rs +++ b/rust/kernel/led/normal.rs @@ -6,11 +6,19 @@ use super::*; +/// The led mode for the `struct led_classdev`. Leds with this mode can only have a fixed color. +pub enum Normal {} + +impl Mode for Normal { + type Device<'bound, T: LedOps<Mode = Self> + 'bound> = Device<'bound, T>; +} +impl private::Sealed for Normal {} + /// The led class device representation. /// /// This structure represents the Rust abstraction for a led class device. #[pin_data(PinnedDrop)] -pub struct Device<'bound, T: LedOps + 'bound> { +pub struct Device<'bound, T: LedOps<Mode = Normal> + 'bound> { #[pin] ops: T, #[pin] @@ -20,7 +28,7 @@ pub struct Device<'bound, T: LedOps + 'bound> { impl<'init, S: DeviceBuilderState> DeviceBuilder<'init, S> { /// Registers a new [`Device`]. - pub fn build<'bound: 'init, T: LedOps + 'bound>( + pub fn build<'bound: 'init, T: LedOps<Mode = Normal> + 'bound>( self, parent: &'bound T::Bus, ops: impl PinInit<T, Error> + 'init, @@ -87,7 +95,7 @@ pub fn build<'bound: 'init, T: LedOps + 'bound>( } } -impl<'bound, T: LedOps + 'bound> Device<'bound, T> { +impl<'bound, T: LedOps<Mode = Normal> + 'bound> Device<'bound, T> { /// # Safety /// `led_cdev` must be a valid pointer to a `led_classdev` embedded within a /// `led::Device`. @@ -107,17 +115,17 @@ fn parent(&self) -> &'bound device::Device<Bound> { } // SAFETY: A `led::Device` can be unregistered from any thread. -unsafe impl<'bound, T: LedOps + 'bound + Send> Send for Device<'bound, T> {} +unsafe impl<'bound, T: LedOps<Mode = Normal> + 'bound + Send> Send for Device<'bound, T> {} // SAFETY: `led::Device` can be shared among threads because all methods of `led::Device` // are thread safe. -unsafe impl<'bound, T: LedOps + 'bound + Sync> Sync for Device<'bound, T> {} +unsafe impl<'bound, T: LedOps<Mode = Normal> + 'bound + Sync> Sync for Device<'bound, T> {} struct Adapter<T: LedOps> { _p: PhantomData<T>, } -impl<T: LedOps> Adapter<T> { +impl<T: LedOps<Mode = Normal>> Adapter<T> { /// # Safety /// `led_cdev` must be a valid pointer to a `led_classdev` embedded within a /// `led::Device`. @@ -210,7 +218,7 @@ impl<T: LedOps> Adapter<T> { } #[pinned_drop] -impl<'bound, T: LedOps + 'bound> PinnedDrop for Device<'bound, T> { +impl<'bound, T: LedOps<Mode = Normal> + 'bound> PinnedDrop for Device<'bound, T> { fn drop(self: Pin<&mut Self>) { let raw = self.classdev.get(); // SAFETY: The existence of `self` guarantees that `self.classdev.get()` is a pointer to a -- 2.54.0