All of lore.kernel.org
 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 consumer abstractions 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 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.