From: Alice Ryhl <aliceryhl@google.com>
To: Markus Probst <markus.probst@posteo.de>
Cc: "Lee Jones" <lee@kernel.org>, "Pavel Machek" <pavel@kernel.org>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Dave Ertman" <david.m.ertman@intel.com>,
"Leon Romanovsky" <leon@kernel.org>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Rafael J. Wysocki" <rafael@kernel.org>,
"Bjorn Helgaas" <bhelgaas@google.com>,
"Krzysztof Wilczyński" <kwilczynski@kernel.org>,
"Boqun Feng" <boqun@kernel.org>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"Tamir Duberstein" <tamird@kernel.org>,
"Alexandre Courbot" <acourbot@nvidia.com>,
"Onur Özkan" <work@onurozkan.dev>,
"Ira Weiny" <iweiny@kernel.org>,
rust-for-linux@vger.kernel.org, linux-leds@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
Subject: Re: [PATCH v21 1/3] rust: leds: add basic led classdev abstractions
Date: Thu, 2 Jul 2026 10:47:12 +0000 [thread overview]
Message-ID: <akZBsBrMlxd4qbBl@google.com> (raw)
In-Reply-To: <20260629-rust_leds-v21-1-4f0f19579db5@posteo.de>
On Mon, Jun 29, 2026 at 01:10:28PM +0000, Markus Probst wrote:
> Implement the core abstractions needed for led class devices, including:
>
> * `led::LedOps` - the trait for handling leds, including
> `brightness_set`, `brightness_get` and `blink_set`
>
> * `led::DeviceBuilder` - the builder for the led class device
>
> * `led::Device` - a safe wrapper around `led_classdev`
>
> Signed-off-by: Markus Probst <markus.probst@posteo.de>
> ---
> MAINTAINERS | 8 ++
> rust/kernel/led.rs | 288 ++++++++++++++++++++++++++++++++++++++++++++++
> rust/kernel/led/normal.rs | 230 ++++++++++++++++++++++++++++++++++++
> rust/kernel/lib.rs | 1 +
> 4 files changed, 527 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 15011f5752a9..ceb2285366ff 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -14662,6 +14662,14 @@ F: drivers/leds/
> F: include/dt-bindings/leds/
> F: include/linux/leds.h
>
> +LED SUBSYSTEM [RUST]
> +M: Markus Probst <markus.probst@posteo.de>
> +L: linux-leds@vger.kernel.org
> +L: rust-for-linux@vger.kernel.org
> +S: Maintained
> +F: rust/kernel/led.rs
> +F: rust/kernel/led/
> +
> LEGO MINDSTORMS EV3
> R: David Lechner <david@lechnology.com>
> S: Maintained
> diff --git a/rust/kernel/led.rs b/rust/kernel/led.rs
> new file mode 100644
> index 000000000000..c92d99d68497
> --- /dev/null
> +++ b/rust/kernel/led.rs
> @@ -0,0 +1,288 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Abstractions for the leds driver model.
> +//!
> +//! C header: [`include/linux/leds.h`](srctree/include/linux/leds.h)
> +
> +use core::{
> + marker::PhantomData,
> + mem::transmute,
> + ptr::NonNull, //
> +};
> +
> +use crate::{
> + container_of,
> + device::{
> + self,
> + property::FwNode,
> + AsBusDevice,
> + Bound, //
> + },
> + error::{
> + from_result,
> + to_result,
> + VTABLE_DEFAULT_ERROR, //
> + },
> + macros::vtable,
> + prelude::*,
> + str::CStrExt,
CStrExt is in the prelude. Please check for unnecessary imports.
> diff --git a/rust/kernel/led/normal.rs b/rust/kernel/led/normal.rs
> new file mode 100644
> index 000000000000..2769f690bb24
> --- /dev/null
> +++ b/rust/kernel/led/normal.rs
> @@ -0,0 +1,230 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Led mode for the `struct led_classdev`.
> +//!
> +//! C header: [`include/linux/leds.h`](srctree/include/linux/leds.h)
> +
> +use super::*;
> +
> +/// 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> {
> + #[pin]
> + ops: T,
> + #[pin]
> + classdev: Opaque<bindings::led_classdev>,
> + _p: PhantomData<&'bound ()>,
> +}
> +
> +impl<'a, S: DeviceBuilderState> DeviceBuilder<'a, S> {
> + /// Registers a new [`Device`].
> + pub fn build<'bound: 'a, T: LedOps + 'bound>(
> + self,
> + parent: &'bound T::Bus,
> + ops: impl PinInit<T, Error> + 'a,
> + ) -> impl PinInit<Device<'bound, T>, Error> + 'a {
I think it would be useful to separate out the two lifetimes more
clearly. You have two sets of lifetimes:
* 'bound which is the duration in which the bus device is bound.
* 'a which is the duration in which the `name`/`devicename` fields are
valid.
And these have different constraints because 'bound is much larger than
'a. The 'bound lifetime is longer than the entire Device struct, but the
'a lifetime only needs to last for the duration of the initialization
because (I assume) the strings are copied by `led_classdev_register_ext`
So under that logic, I would rename 'a to 'name or something like that
to indicate what it's the lifetime of.
Note that if I'm wrong about the lifetime of the name strings, then this
code should be changed accordingly. It looks like you're actually
stashing the pointers in the led_classdev, and if that outlives this
initializer, then the current lifetimes are wrong, and Device must also
be annotated with 'name to indicate this additional lifetime.
> + const_assert!(T::MAX_BRIGHTNESS <= i32::MAX.unsigned_abs() || !T::HAS_BRIGHTNESS_GET);
> +
> + try_pin_init!(Device {
> + ops <- ops,
> + classdev <- Opaque::try_ffi_init(|ptr: *mut bindings::led_classdev| {
> + // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write.
> + // `led_classdev` gets fully initialized in-place by
> + // `led_classdev_register_ext` including `mutex` and `list_head`.
> + unsafe {
> + ptr.write(bindings::led_classdev {
> + brightness_set: (!T::BLOCKING)
> + .then_some(Adapter::<T>::brightness_set_callback),
> + brightness_set_blocking: T::BLOCKING
> + .then_some(Adapter::<T>::brightness_set_blocking_callback),
> + brightness_get: T::HAS_BRIGHTNESS_GET
> + .then_some(Adapter::<T>::brightness_get_callback),
> + blink_set: T::HAS_BLINK_SET.then_some(Adapter::<T>::blink_set_callback),
> + max_brightness: T::MAX_BRIGHTNESS,
> + brightness: self.initial_brightness,
> + color: self.color as u32,
> + name: self.name.map_or(core::ptr::null(), CStrExt::as_char_ptr),
> + ..bindings::led_classdev::default()
> + })
> + };
> +
> + let mut init_data = bindings::led_init_data {
> + fwnode: self
> + .fwnode
> + .as_ref()
> + .map_or(core::ptr::null_mut(), |fwnode| fwnode.as_raw()),
> + default_label: core::ptr::null(),
> + devicename: self
> + .devicename
> + .map_or(core::ptr::null(), CStrExt::as_char_ptr),
> + devname_mandatory: self.devname_mandatory,
> + };
> +
> + // SAFETY:
> + // - `parent.as_ref().as_raw()` is guaranteed to be a pointer to a valid
> + // `device`.
> + // - `ptr` is guaranteed to be a pointer to an initialized `led_classdev`.
> + to_result(unsafe {
> + bindings::led_classdev_register_ext(
> + parent.as_ref().as_raw(),
> + ptr,
> + if self.name.is_none() {
> + &raw mut init_data
> + } else {
> + core::ptr::null_mut()
> + },
> + )
> + })?;
> +
> + core::mem::forget(self.fwnode); // keep the reference count incremented
> +
> + Ok::<_, Error>(())
> + }),
> + _p: PhantomData,
> + })
> + }
> +}
Alice
next prev parent reply other threads:[~2026-07-02 10:47 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-29 13:10 [PATCH v21 0/3] rust: leds: add led classdev abstractions Markus Probst
2026-06-29 13:10 ` [PATCH v21 1/3] rust: leds: add basic " Markus Probst
2026-07-02 10:47 ` Alice Ryhl [this message]
2026-07-02 11:00 ` Markus Probst
2026-07-02 11:22 ` Alice Ryhl
2026-07-02 11:09 ` Gary Guo
2026-06-29 13:10 ` [PATCH v21 2/3] rust: leds: add Mode trait Markus Probst
2026-06-29 13:10 ` [PATCH v21 3/3] rust: leds: add multicolor classdev abstractions Markus Probst
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=akZBsBrMlxd4qbBl@google.com \
--to=aliceryhl@google.com \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=alex.gaynor@gmail.com \
--cc=bhelgaas@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=david.m.ertman@intel.com \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=iweiny@kernel.org \
--cc=kwilczynski@kernel.org \
--cc=lee@kernel.org \
--cc=leon@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-leds@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=markus.probst@posteo.de \
--cc=ojeda@kernel.org \
--cc=pavel@kernel.org \
--cc=rafael@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tamird@kernel.org \
--cc=tmgross@umich.edu \
--cc=work@onurozkan.dev \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox