mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Kohei Ito <koheiito.dev@gmail.com>
To: Alexandre Courbot <acourbot@nvidia.com>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
	"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <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>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"Daniel Almeida" <daniel.almeida@collabora.com>,
	"Tamir Duberstein" <tamird@kernel.org>,
	"Onur Özkan" <work@onurozkan.dev>,
	linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
	linux-gpio@vger.kernel.org
Subject: Re: [PATCH 2/3] rust: gpio: Add basic consumer abstractions
Date: Sun, 4 Oct 2026 01:45:30 +0900	[thread overview]
Message-ID: <6ac1312c.ee551989.ce4ed.e56f@mx.google.com> (raw)
In-Reply-To: <DLE2CBE8FJ9B.23HDU37C95ROK@nvidia.com>

Hi Alexandre,

thank you for your review.

> > Due to a bindgen issue that may generate the wrong type for enum types,
> > `gpio/consumer.h` is included at the top of `bindings_helper.h` as a
> > temporary workaround. Once the issue is resolved, it can be moved back
> > to its proper alphabetical position.
> 
> Can you describe what the issue is, and share any relevant link?

`bindgen` can generate the wrong type for the `enum`s when their
forward declarations appear before the actual definitions. The details
are described in [1].

I haven't confirmed that `gpiod_flags` is actually affected. I placed
the include at the top as a precaution, but if it isn't needed I'll drop
the workaround.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8cbc95f983bcec7e042266766ffe0d68980e4290

> > +/// The GPIO descriptor flags to configure its direction and output value.
> > +///
> > +/// Rust abstraction for the C [`enum gpiod_flags`].
> > +///
> > +/// They can be combined with the operators `|`, and `&`.
> 
> The C comment for `gpiod_flags` says "these values cannot be OR'd" so I
> guess this comment isn't true. Besides, there is no `BitOr` impl for
> `GpiodFlags` in the patch so it actually cannot be done.

Good catch! I'll correct it.

> > +    // Always inline to optimize out error path of `build_assert`.
> > +    #[inline(always)]
> > +    const fn new(value: bindings::gpiod_flags) -> Self {
> > +        build_assert!(value as u64 <= bindings::gpiod_flags::MAX as u64);
> 
> Better to not use `build_assert` here as it inserts build-time
> landmines.
> 
> Since you are only using this to build the constants above, you can just
> do `Self(bindings::gpiod_flags_*)` on them. Adding an extra assert for
> an bounded enum type doesn't add any extra protection.

Sure. I'll remove it.


> > +/// A reference-counted gpio descriptor.
> 
> Not really - the GPIO device is reference-counted, but descriptors are
> not. Calling `gpiod_get` a second time returns `EBUSY`.

Sure. I'll correct it.

> > +/// ```
> > +/// use crate::{
> 
> These doctests won't compile as they are supposed to use `kernel::`, not
> `crate::`.
> 
> Please make sure to include the doctests when building
> (`CONFIG_RUST_KERNEL_DOCTESTS` build option), and to also build the
> `rustdoc` target as per the checklist [1].
> 
> [1] https://rust-for-linux.com/contributing#submit-checklist-addendum

Sure. I'll fix it and make sure to run the doctests and build rustdoc.

> > +// SAFETY: It is safe to call `gpiod_put` on another thread than where `gpiod_get` was called.
> > +unsafe impl Send for GpioDesc {}
> 
> We should probably also implement `Sync` so GPIOs can be used in
> interrupt context.

I agree we want `Sync` so that GPIOs can be used from interrupt context.
However, the direction setters are not safe to call concurrently on the
same descriptor: gpiolib changes the hardware direction and then updates
`GPIOD_FLAG_IS_OUT`, so the two can become inconsistent.

I think we can add `Sync` if the direction setters take `&mut self` (or
use the typestate approach). I'll look into this together with the
typestate design.

> > +
> > +impl GpioDesc {
> > +    /// Gets [`GpioDesc`] corresponding to a [`Device`] and a connection id.
> > +    ///
> > +    /// Equivalent to the kernel's [`gpiod_get`] API.
> > +    ///
> > +    /// [`gpiod_get`]: https://docs.kernel.org/driver-api/gpio/index.html#c.gpiod_get
> > +    pub fn get(dev: &Device, name: Option<&CStr>, flags: GpiodFlags) -> Result<Self> {
> 
> `dev` here is only used as a lookup key, and the GPIO descriptor can
> outlive the device being unbound (the GPIO can actually even be obtained
> while the device is unbound!). This is because `dev` is not the provider
> of the GPIO, but as the API name implies its consumer - i.e. the device
> on which the GPIO is expected to have an effect.
> 
> This is what the GPIO API expects, but it looks a bit counterintuitive
> when compared to most other Rust subsystems, where an obtained resource
> is typically tied to the device given as parameter being bound. I think
> it's worth mentioning in the comment.

Sure. I'll add a note explaining how `dev` is used.

> > +    /// Get the direction.
> > +    ///
> > +    /// Equivalent to the kernel's [`gpiod_get_direction`] API.
> > +    ///
> > +    /// [`gpiod_get_direction`]:
> > +    /// https://docs.kernel.org/driver-api/gpio/index.html#c.gpiod_get_direction
> > +    #[inline]
> > +    pub fn get_direction(&self) -> Result<LineDirection> {
> > +        // SAFETY: By the type invariants, self.as_raw() is a valid argument for
> > +        // [`gpiod_get_direction`].
> > +        let ret = unsafe { bindings::gpiod_get_direction(self.as_raw()) };
> > +        if ret < 0 {
> > +            Err(Error::from_errno(ret))
> > +        } else {
> > +            LineDirection::try_from(ret)
> > +        }
> > +    }
> 
> IIUC the direction of a GPIO at a given point in the code is always
> statically known, and only a subset of the API really make sense for a
> given direction (e.g. `gpiod_set_raw_value_commit` returns `EPERM` if
> the direction is not output). So this is a prime candidate for using the
> typestate pattern to store the direction in the type.
> 
> I.e. you would have `GpioDesc<Input>`, `GpioDesc<Output>`, and changing
> the direction would consume the descriptor and return the new one with
> the requested direction.
> 
> The regulator Rust API makes use of this pattern, you can check it out
> for an example if needed.

I haven't fully grasped the idea yet. I'll check the regulator Rust API
implementation and explore a typestate implementation for GPIO consumer
APIs.

> > +    /// Test whether the GPIO is active-low or not.
> > +    ///
> > +    /// Equivalent to the kernel's [`gpiod_is_active_low`] API.
> > +    ///
> > +    /// [`gpiod_is_active_low`]:
> > +    /// https://docs.kernel.org/driver-api/gpio/index.html#c.gpiod_is_active_low
> > +    #[inline]
> > +    pub fn is_active_low(&self) -> Result<bool> {
> > +        // SAFETY: By the type invariants, self.as_raw() is a valid argument for
> > +        // [`gpiod_is_active_low`].
> > +        match unsafe { bindings::gpiod_is_active_low(self.as_raw()) } {
> > +            0 => Ok(false),
> > +            1 => Ok(true),
> > +            err => Err(Error::from_errno(err)),
> > +        }
> 
> In C this function cannot fail for a valid descriptor, so the Rust one
> shouldn't either. Anything != 0 can be considered `true`.

Sure. I'll correct it for `GpioDesc`. Should we return Result<bool> for
OptionalGpioDesc? As I understand, NULL GPIO descriptors can't return
the right state.

> > +    /// Report whether gpio value access may sleep or not.
> > +    ///
> > +    /// Equivalent to the kernel's [`gpiod_cansleep`] API.
> > +    ///
> > +    /// [`gpiod_cansleep`]:
> > +    /// https://docs.kernel.org/driver-api/gpio/index.html#c.gpiod_cansleep
> > +    #[inline]
> > +    pub fn cansleep(&self) -> Result<bool> {
> > +        // SAFETY: By the type invariants, self.as_raw() is a valid argument for
> > +        // [`gpiod_cansleep`].
> > +        match unsafe { bindings::gpiod_cansleep(self.as_raw()) } {
> > +            0 => Ok(false),
> > +            1 => Ok(true),
> > +            err => Err(Error::from_errno(err)),
> > +        }
> > +    }
> 
> Same here.

Sure. I'll fix it in the same way.

> Also, as a general guideline, it is good to have a concrete user for new
> Rust abstractions. Do you have a project that will make use of this?

No, I don't have a specific project that will use this. My motivation
is that Rust drivers currently have no way to use GPIO lines, so I
expect that providing a basic set of consumer APIs would make it easier
for such drivers to appear.

That said, I understand the concern about adding APIs without actual
users. If you think it should wait until there is a concrete user,
please let me know.

Best regards,
Kohei Ito

  reply	other threads:[~2026-10-03 16:45 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-06  8:45 [PATCH 0/3] rust: Add basic GPIO " Kohei Ito
2026-09-06  8:45 ` [PATCH 1/3] rust: gpio: add GPIO module with common definitions Kohei Ito
2026-09-06  9:56   ` Miguel Ojeda
2026-09-06 13:09     ` Gary Guo
2026-09-06 15:53       ` Kohei Ito
2026-09-16 13:29   ` Linus Walleij
2026-10-03 16:50     ` Kohei Ito
2026-09-06  8:45 ` [PATCH 2/3] rust: gpio: Add basic consumer abstractions Kohei Ito
2026-09-10  7:38   ` Bartosz Golaszewski
2026-09-13  8:58   ` Alexandre Courbot
2026-10-03 16:45     ` Kohei Ito [this message]
2026-09-06  8:45 ` [PATCH 3/3] sample: rust: Add GPIO consumer sample driver Kohei Ito
2026-09-10  7:37   ` Bartosz Golaszewski
2026-09-13  8:46     ` Kohei Ito
2026-09-14  1:41       ` Alexandre Courbot
2026-09-14  8:36         ` Bartosz Golaszewski
2026-09-21 13:12           ` Kohei Ito
2026-09-21 14:38             ` Bartosz Golaszewski
2026-09-22 13:32               ` Alexandre Courbot
2026-10-03 16:58                 ` Kohei Ito

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=6ac1312c.ee551989.ce4ed.e56f@mx.google.com \
    --to=koheiito.dev@gmail.com \
    --cc=a.hindborg@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=aliceryhl@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun@kernel.org \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=gary@garyguo.net \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=ojeda@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

all inboxes | Powered by JetHome®