From: "Danilo Krummrich" <dakr@kernel.org>
To: "Markus Probst" <markus.probst@posteo.de>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
	"Alex Gaynor" <alex.gaynor@gmail.com>,
	"Lee Jones" <lee@kernel.org>, "Pavel Machek" <pavel@kernel.org>,
	"Lorenzo Stoakes" <lorenzo.stoakes@oracle.com>,
	"Vlastimil Babka" <vbabka@suse.cz>,
	"Liam R. Howlett" <Liam.Howlett@oracle.com>,
	"Uladzislau Rezki" <urezki@gmail.com>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Gary Guo" <gary@garyguo.net>, <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <lossin@kernel.org>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	<rust-for-linux@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<linux-leds@vger.kernel.org>
Subject: Re: [PATCH 2/2] rust: leds: add basic led classdev abstractions
Date: Fri, 10 Oct 2025 20:36:28 +0200	[thread overview]
Message-ID: <DDEUYJ3RLBO0.3BI35RYL7OUU6@kernel.org> (raw)
In-Reply-To: <20251009170739.235221-3-markus.probst@posteo.de>
On Thu Oct 9, 2025 at 7:07 PM CEST, Markus Probst wrote:
> +/// The led class device representation.
> +///
> +/// This structure represents the Rust abstraction for a C `struct led_classdev`.
> +#[pin_data(PinnedDrop)]
> +pub struct Device {
> +    handler: KBox<dyn HandlerImpl>,
The corresponding callbacks already exist in struct led_classdev, please use
them instead.
> +    #[pin]
> +    classdev: Opaque<bindings::led_classdev>,
> +}
<snip>
> +// SAFETY: A `led::Device` can be unregistered from any thread.
> +unsafe impl Send for Device {}
> +
> +// SAFETY: `led::Device` can be shared among threads because all methods of `led::Device`
> +// are thread safe.
> +unsafe impl Sync for Device {}
> +
> +impl Device {
> +    /// Registers a new led classdev.
> +    ///
> +    /// The [`Device`] will be unregistered and drop.
> +    pub fn new<'a, T: Handler + 'static>(
> +        parent: Option<&'a device::Device>,
This should not be an Option, all LED devices should have a parent (bus) device.
Also, it should be a &Device<Bound>, i.e. a device that is guaranteed to be
bound to a driver.
> +        init_data: InitData<'a>,
> +        handler: T,
> +    ) -> impl PinInit<Self, Error> + use<'a, T> {
This will not compile for all supported compiler versions. For now it just has
to be:
	impl PinInit<Self, Error> + 'a
Besides that, this should return impl PinInit<Devres<Self>, Error> + 'a instead.
This will allow you to let callbacks, such as blink_set(), to provide the parent
device as &Device<Bound>.
Please see also the PWM abstractions for reference [1]. There's one difference between
LED and PWM though. Unlike PWM (and most other class device implementations) LED
combines initialization and registration of the device, hence PWM is slightly
different in its implementation details, but semantically it's the same.
[1] https://lore.kernel.org/all/20250930-rust-next-pwm-working-fan-for-sending-v15-3-5661c3090877@samsung.com/
> +        try_pin_init!(Self {
> +            handler <- {
> +                let handler: KBox<dyn HandlerImpl> = KBox::<T>::new(handler, GFP_KERNEL)?;
> +                Ok::<_, Error>(handler)
> +            },
> +            classdev <- Opaque::try_ffi_init(|ptr: *mut bindings::led_classdev| {
> +                // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write.
> +                unsafe { ptr.write(bindings::led_classdev {
This looks very odd at a first glance, but it is indeed correct. It would be
good to add a comment that the parts of struct led_classdev that need to be
initialized in place (e.g. the struct mutex and struct list_head) are
initialized by led_classdev_register_ext() (which is not exactly straight
forward).
> +                    max_brightness: T::MAX_BRIGHTNESS,
> +                    brightness_set: T::BLOCKING.then_some(
> +                        brightness_set as unsafe extern "C" fn(*mut bindings::led_classdev, u32)
> +                    ),
> +                    brightness_set_blocking: (!T::BLOCKING).then_some(
> +                        brightness_set_blocking
> +                            as unsafe extern "C" fn(*mut bindings::led_classdev,u32) -> i32
> +                    ),
> +                    blink_set: T::BLINK.then_some(
> +                        blink_set
> +                            as unsafe extern "C" fn(*mut bindings::led_classdev, *mut usize,
> +                                                    *mut usize) -> i32
> +                    ),
> +                    .. bindings::led_classdev::default()
> +                }) };
> +
> +                let mut init_data = bindings::led_init_data {
> +                    fwnode: init_data.fwnode.map_or(core::ptr::null_mut(), FwNode::as_raw),
> +                    default_label: init_data.default_label
> +                                            .map_or(core::ptr::null(), CStr::as_char_ptr),
> +                    devicename: init_data.devicename.map_or(core::ptr::null(), CStr::as_char_ptr),
> +                    devname_mandatory: init_data.devname_mandatory,
> +                };
> +
> +                let parent = parent
> +                    .map_or(core::ptr::null_mut(), device::Device::as_raw);
> +
> +                // SAFETY:
> +                // - `parent` is guaranteed to be a pointer to a valid `device`
> +                //    or a null pointer.
> +                // - `ptr` is guaranteed to be a pointer to an initialized `led_classdev`.
> +                to_result(unsafe {
> +                    bindings::led_classdev_register_ext(parent, ptr, &mut init_data)
> +                })
> +            }),
> +        })
> +    }
> +}
next prev parent reply	other threads:[~2025-10-10 18:36 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-09 17:07 [PATCH 0/2] rust: leds: add led classdev abstractions Markus Probst
2025-10-09 17:07 ` [PATCH 1/2] rust: add basic Pin<Vec<T, A>> abstractions Markus Probst
2025-10-09 17:45   ` Onur Özkan
2025-10-09 17:07 ` [PATCH 2/2] rust: leds: add basic led classdev abstractions Markus Probst
2025-10-09 17:49   ` Onur Özkan
2025-10-10 18:36   ` Danilo Krummrich [this message]
2025-10-09 17:46 ` [PATCH 0/2] rust: leds: add " Onur Özkan
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=DDEUYJ3RLBO0.3BI35RYL7OUU6@kernel.org \
    --to=dakr@kernel.org \
    --cc=Liam.Howlett@oracle.com \
    --cc=a.hindborg@kernel.org \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=gary@garyguo.net \
    --cc=lee@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-leds@vger.kernel.org \
    --cc=lorenzo.stoakes@oracle.com \
    --cc=lossin@kernel.org \
    --cc=markus.probst@posteo.de \
    --cc=ojeda@kernel.org \
    --cc=pavel@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tmgross@umich.edu \
    --cc=urezki@gmail.com \
    --cc=vbabka@suse.cz \
    /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;
as well as URLs for NNTP newsgroup(s).