From: Jonathan Cameron <jic23@kernel.org>
To: Muchamad Coirul Anwar <muchamadcoirulanwar@gmail.com>
Cc: lars@metafoo.de, linux-iio@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-i2c@vger.kernel.org,
rust-for-linux@vger.kernel.org, andi.shyti@kernel.org,
wsa+renesas@sang-engineering.com, ojeda@kernel.org,
dakr@kernel.org, igor.korotin@linux.dev, branstj@gmail.com,
brucer42@gmail.com
Subject: Re: [RFC PATCH v5 2/3] rust: add minimal IIO subsystem abstractions
Date: Mon, 24 Aug 2026 01:07:26 +0100 [thread overview]
Message-ID: <20260824010726.2849f3d8@jic23-huawei> (raw)
In-Reply-To: <20260822062725.60519-3-muchamadcoirulanwar@gmail.com>
On Sat, 22 Aug 2026 14:26:57 +0800
Muchamad Coirul Anwar <muchamadcoirulanwar@gmail.com> wrote:
> Add safe Rust wrappers for the Linux IIO (Industrial I/O) subsystem:
>
> - IioChanInfo enum wrapping iio_chan_info_enum, with TryFrom<u32> for
> type-safe dispatch in read_raw. The compiler enforces match
> exhaustiveness, replacing the previous raw isize approach.
> - IioVal enum with NonZeroI32 for division-by-zero prevention on
> IIO_VAL_FRACTIONAL.
> - IioDriver trait with read_raw callback (requires Send + Sync).
> - Device<T, State> with typestate (Unregistered -> Registered) to
> prevent double-registration at compile time.
> - PinnedDrop for guaranteed cleanup sequence:
> iio_device_unregister -> drop_in_place(T) -> iio_device_free
> iio_device_unregister() calls cdev_device_del() which drains the
> kernfs workqueue before returning. All in-flight read_raw callbacks
> (which go through kernfs sysfs reads) complete before drop_in_place
> proceeds. This covers the sysfs read path used by this driver.
> - Compile-time const VTABLE (iio_info).
> - C-to-Rust FFI trampoline for read_raw dispatch.
>
> The abstraction uses iio_device_alloc (not devm_*) so that the Rust
> Drop implementation has full control over the cleanup sequence.
> Module ownership is enforced via __iio_device_register(indio_dev, module).
>
> Signed-off-by: Muchamad Coirul Anwar <muchamadcoirulanwar@gmail.com>
Hi Muchamad
This looks fine to me subject to a few little things - see inline.
However I didn't take the time to decode every line of rust today so there were bits
I simply didn't understand yet. So for this to be able to move forward I'm going
to need reviews from rust experts!
Jonathan
> diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
> index a56ba6309594..5dc917d92151 100644
> --- a/rust/kernel/error.rs
> +++ b/rust/kernel/error.rs
> @@ -86,6 +86,7 @@ macro_rules! declare_err {
> declare_err!(EIOCBQUEUED, "iocb queued, will get completion event.");
> declare_err!(ERECALLCONFLICT, "Conflict with recalled state.");
> declare_err!(ENOGRACE, "NFS file lock reclaim refused.");
> + declare_err!(ENODATA, "No data available.");
Do we have something says there must be a user in the same patch?
A really generic thing like this in C would definitely be a patch on its
own so that folk who care about maintaining a given file can easily see
it without reviewing the rest of the series.
So unless you can't do otherwise, break this out as a precursor patch.
> }
>
> /// Generic integer kernel error.
> diff --git a/rust/kernel/iio.rs b/rust/kernel/iio.rs
> new file mode 100644
> index 000000000000..f1638160fed1
> --- /dev/null
> +++ b/rust/kernel/iio.rs
...
> +
> +build_iio_enum! {
> + /// Raw unprocessed value from the channel (`IIO_CHAN_INFO_RAW`).
> + ///
> + /// For sensors, this is typically the ADC reading or register value
> + /// before any scaling or offset correction.
> + Raw = iio_chan_info_enum_IIO_CHAN_INFO_RAW,
I guess there may be a rust convention for this but from a human trying to
read the code point of view this need a blank line here and in similar places
where you have docs / thing documented repeated back to back.
> + /// Scale factor to convert raw values to SI units (`IIO_CHAN_INFO_SCALE`).
> + ///
> + /// The processed value is `raw * scale`. The unit depends on the channel
> + /// type (e.g. V for voltage, m/s² for acceleration, rad for angle).
> + Scale = iio_chan_info_enum_IIO_CHAN_INFO_SCALE,
> +}
> +
> +/// C-compatible trampoline for the `iio_info.read_raw` callback.
> +///
> +/// # Safety
> +///
> +/// This function is only called by the IIO core via the `read_raw` function
> +/// pointer in `iio_info`. The IIO core guarantees:
> +/// - `indio_dev` is a valid `iio_dev` allocated by `iio_device_alloc`.
> +/// - `chan` points to a valid channel spec from the device's channel array.
> +/// - `val` is a valid non-null pointer to a writable `int`.
> +/// - `val2` is a valid non-null pointer to a writable `int`. The IIO core
> +/// always passes stack-allocated storage for both, regardless of whether
> +/// the driver uses `val2` (e.g. `IIO_VAL_INT` only writes `val`; `val2`
That val2 is always a valid pointer smells a bit like the c interface leaking
into the rust. I'm not necessarily against that being a constraint we take
on but I'm not sure how we document that. Probably add something to the C docs.
Any C driver relying on this today is probably buggy for other reasons.
> +/// is provided but left unread by the caller for that return type).
> +unsafe extern "C" fn read_raw_callback<T: IioDriver>(
> + indio_dev: *mut iio_dev,
> + chan: *const iio_chan_spec,
> + val: *mut c_int,
> + val2: *mut c_int,
> + info: isize,
> +) -> c_int {
> + // SAFETY: `indio_dev` is valid and was allocated with space for `T` in its
> + // private data area. The `priv_` field was initialized in `Device::build_device()`.
> + let priv_ptr = unsafe { (*indio_dev).priv_ as *mut T };
> + // SAFETY: `priv_ptr` points to a valid, initialized instance of `T` that
> + // lives as long as the `iio_dev` allocation.
> + let driver = unsafe { &*priv_ptr };
> +
> + let info_enum = match IioChanInfo::try_from(info as u32) {
> + Ok(valid) => valid,
> + Err(e) => return e.to_errno(),
> + };
> +
> + match driver.read_raw(chan, info_enum) {
> + Ok(IioVal::Int(v)) => {
> + // SAFETY: `val` is valid per the function's Safety contract above.
> + // `val2` is not written; `IIO_VAL_INT` signals to the IIO core
> + // that only `val` carries meaningful data.
> + unsafe {
> + *val = v;
> + }
> + IIO_VAL_INT
> + }
> + Ok(IioVal::Fractional(v, v2)) => {
> + // SAFETY: both `val` and `val2` are valid per the Safety contract.
> + unsafe {
> + *val = v;
> + *val2 = v2.get();
Why get in some places and not others? May well be a gap in my really limited
rust knowledge.
> + }
> + IIO_VAL_FRACTIONAL
> + }
> + Ok(IioVal::IntPlusMicro(v, v2)) => {
> + // SAFETY: both `val` and `val2` are valid per the Safety contract.
> + unsafe {
> + *val = v;
> + *val2 = v2;
> + }
> + IIO_VAL_INT_PLUS_MICRO
> + }
> + Ok(IioVal::IntPlusNano(v, v2)) => {
> + // SAFETY: both `val` and `val2` are valid per the Safety contract.
> + unsafe {
> + *val = v;
> + *val2 = v2;
> + }
> + IIO_VAL_INT_PLUS_NANO
> + }
> + Err(e) => e.to_errno(),
> + }
> +}
next prev parent reply other threads:[~2026-08-24 0:07 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-22 6:26 [RFC PATCH v5 0/3] iio: position: add Rust driver for ams AS5600 Muchamad Coirul Anwar
2026-08-22 6:26 ` [RFC PATCH v5 1/3] i2c: rust: implement SMBus access via IoBackend and FallibleIoCapable Muchamad Coirul Anwar
2026-08-23 23:41 ` Jonathan Cameron
2026-08-22 6:26 ` [RFC PATCH v5 2/3] rust: add minimal IIO subsystem abstractions Muchamad Coirul Anwar
2026-08-24 0:07 ` Jonathan Cameron [this message]
2026-08-22 6:26 ` [RFC PATCH v5 3/3] iio: position: add Rust driver for ams AS5600 Muchamad Coirul Anwar
2026-08-24 0:17 ` Jonathan Cameron
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=20260824010726.2849f3d8@jic23-huawei \
--to=jic23@kernel.org \
--cc=andi.shyti@kernel.org \
--cc=branstj@gmail.com \
--cc=brucer42@gmail.com \
--cc=dakr@kernel.org \
--cc=igor.korotin@linux.dev \
--cc=lars@metafoo.de \
--cc=linux-i2c@vger.kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=muchamadcoirulanwar@gmail.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=wsa+renesas@sang-engineering.com \
/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