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
next prev parent 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®