rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Igor Korotin <igor.korotin.linux@gmail.com>
To: Daniel Almeida <daniel.almeida@collabora.com>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
	"Alex Gaynor" <alex.gaynor@gmail.com>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"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>,
	rust-for-linux@vger.kernel.org
Subject: Re: [PATCH v3 1/3] rust: i2c: add basic I2C device and driver abstractions
Date: Mon, 4 Aug 2025 15:16:57 +0100	[thread overview]
Message-ID: <ff90c4d7-733a-4d76-a939-b460d66389bc@gmail.com> (raw)
In-Reply-To: <F8F4578D-9095-48D4-BC21-67177F2DDD6F@collabora.com>

Hello Daniel

Thank you for the review.

On 8/1/25 18:14, Daniel Almeida wrote:
>> +
>> +        Self(i2c)
>> +    }
>> +}
>> +
>> +// SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `i2c_device_id` and does not add
>> +// additional invariants, so it's safe to transmute to `RawType`.
>> +unsafe impl RawDeviceId for DeviceId {
>> +    type RawType = bindings::i2c_device_id;
>> +}
>> +
>> +// SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field.
>> +unsafe impl RawDeviceIdIndex for DeviceId {
>> +    const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::i2c_device_id, driver_data);
>> +
>> +    fn index(&self) -> usize {
>> +        self.0.driver_data as _
>> +    }
>> +}
>> +
>> +/// IdTable type for I2C
>> +pub type IdTable<T> = &'static dyn kernel::device_id::IdTable<DeviceId, T>;
>> +
>> +/// Create a I2C `IdTable` with its alias for modpost.
>> +#[macro_export]
>> +macro_rules! i2c_device_table {
>> +    ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
>> +        const $table_name: $crate::device_id::IdArray<
>> +            $crate::i2c::DeviceId,
>> +            $id_info_type,
>> +            { $table_data.len() },
>> +        > = $crate::device_id::IdArray::new($table_data);
>> +
>> +        $crate::module_device_table!("i2c", $module_table_name, $table_name);
>> +    };
>> +}
>> +
>> +/// An adapter for the registration of I2C drivers.
>> +pub struct Adapter<T: Driver>(T);
>> +
>> +// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if
>> +// a preceding call to `register` has been successful.
>> +unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
>> +    type RegType = bindings::i2c_driver;
>> +
>> +    unsafe fn register(
>> +        pdrv: &Opaque<Self::RegType>,
>> +        name: &'static CStr,
>> +        module: &'static ThisModule,
>> +    ) -> Result {
>> +        let i2c_table = match T::I2C_ID_TABLE {
>> +            Some(table) => table.as_ptr(),
>> +            None => core::ptr::null(),
>> +        };
>> +
>> +        let of_table = match T::OF_ID_TABLE {
>> +            Some(table) => table.as_ptr(),
>> +            None => core::ptr::null(),
>> +        };
>> +
>> +        let acpi_table = match T::ACPI_ID_TABLE {
>> +            Some(table) => table.as_ptr(),
>> +            None => core::ptr::null(),
>> +        };
> 
> I wonder what happens if these are all None?
> 

C code in the i2c_register_driver function doesn't require id_table, OF
table, or ACPI table to be non-NULL. Technically, there's no issue
registering such an I2C driver. Though there's the following code in
i2c_device_probe:

    /*
     * An I2C ID table is not mandatory, if and only if, a suitable OF
     * or ACPI ID table is supplied for the probing device.
     */
    if (!driver->id_table &&
        !acpi_driver_match_device(dev, dev->driver) &&
        !i2c_of_match_device(dev->driver->of_match_table, client)) {
        status = -ENODEV;
        goto put_sync_adapter;
    }

Based on that, maybe it makes sense to add some kind of
compile-time/build-time assertion to make sure the developer defines at
least one of those tables. If so, I'm happy to think about how to
implement something like that.

>> +
>> +        // SAFETY: It's safe to set the fields of `struct i2c_client` on initialization.
>> +        unsafe {
>> +            (*pdrv.get()).driver.name = name.as_char_ptr();
>> +            (*pdrv.get()).probe = Some(Self::probe_callback);
>> +            (*pdrv.get()).remove = Some(Self::remove_callback);
>> +            (*pdrv.get()).shutdown = Some(Self::shutdown_callback);
>> +            (*pdrv.get()).id_table = i2c_table;
>> +            (*pdrv.get()).driver.of_match_table = of_table;
>> +            (*pdrv.get()).driver.acpi_match_table = acpi_table;
>> +        }
>> +
>> +        // SAFETY: `pdrv` is guaranteed to be a valid `RegType`.
>> +        to_result(unsafe { bindings::i2c_register_driver(module.0, pdrv.get()) })
>> +    }
>> +
>> +    unsafe fn unregister(pdrv: &Opaque<Self::RegType>) {
>> +        // SAFETY: `pdrv` is guaranteed to be a valid `RegType`.
>> +        unsafe { bindings::i2c_del_driver(pdrv.get()) }
>> +    }
>> +}
>> +
>> +impl<T: Driver + 'static> Adapter<T> {
>> +    extern "C" fn probe_callback(pdev: *mut bindings::i2c_client) -> kernel::ffi::c_int {
> 
> Nit: throughout the file: I think that pdev comes either from pci or platform
> devices? Maybe a different variable name should be used?
> 

To be honest, I always thought pdev/pdrv/etc just meant "pointer to
device"/"pointer to driver" and not necessarily PCI/platform. If it
actually implies platform/PCI, then yeah, I agree — better to use
something like idev/idrv, as Danilo also pointed out.

>> +        // - `dev` is guaranteed to be valid while it's alive, and so is `pdev.as_ref().as_raw()`.
>> +        let raw_id = unsafe { bindings::i2c_match_id(table.as_ptr(), dev.as_raw()) };
> 
> Wait, where’s `pdev.as_ref().as_raw()` here?
> 
Yeah, good catch. There was a significant rework between v2 and v3, and
I didn’t clean up all the comments properly. My bad.

Noted all the other comments too — I’ll fix those in the next drop.

Best Regards
Igor


  parent reply	other threads:[~2025-08-04 14:19 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-01 15:37 [PATCH v3 0/3] rust: i2c: Add basic I2C driver abstractions Igor Korotin
2025-08-01 15:40 ` [PATCH v3 1/3] rust: i2c: add basic I2C device and " Igor Korotin
2025-08-01 17:14   ` Daniel Almeida
2025-08-02  0:22     ` Danilo Krummrich
2025-08-04 14:16     ` Igor Korotin [this message]
2025-08-02  0:00   ` Danilo Krummrich
2025-08-02  9:07     ` Wolfram Sang
2025-08-02 10:51       ` Danilo Krummrich
2025-08-02 12:14         ` Wolfram Sang
2025-08-02 12:41           ` Danilo Krummrich
2025-08-04 14:58     ` Igor Korotin
2025-08-04 15:17       ` Danilo Krummrich
2025-08-04 15:24         ` Miguel Ojeda
2025-08-04 15:40         ` Igor Korotin
2025-08-04 16:11           ` Wolfram Sang
2025-08-04 17:15             ` Danilo Krummrich
2025-08-04 22:01               ` Wolfram Sang
2025-08-05  8:37                 ` Igor Korotin
2025-08-05  9:28                   ` Wolfram Sang
2025-08-05 12:40                 ` Daniel Almeida
2025-08-04 17:26             ` Igor Korotin
2025-08-04 17:46               ` Miguel Ojeda
2025-08-04 21:57               ` Wolfram Sang
2025-08-15 15:40     ` Igor Korotin
2025-08-15 16:03       ` Danilo Krummrich
2025-08-15 17:04         ` Greg KH
2025-08-15 17:16           ` Danilo Krummrich
2025-08-01 15:44 ` [PATCH v3 2/3] rust: i2c: add manual I2C device creation abstractions Igor Korotin
2025-08-01 17:59   ` Daniel Almeida
2025-08-02  0:26     ` Danilo Krummrich
2025-08-04 14:38     ` Igor Korotin
2025-08-02  0:12   ` Danilo Krummrich
2025-08-01 15:45 ` [PATCH v3 3/3] samples: rust: add Rust I2C sample driver Igor Korotin
2025-08-01 18:09   ` Daniel Almeida
2025-08-04 14:43     ` Igor Korotin
2025-08-04 14:58       ` Daniel Almeida
2025-08-02  0:18   ` Danilo Krummrich
2025-08-07  8:42   ` kernel test robot
2025-08-04 15:07 ` [PATCH v3 0/3] rust: i2c: Add basic I2C driver abstractions Daniel Almeida

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=ff90c4d7-733a-4d76-a939-b460d66389bc@gmail.com \
    --to=igor.korotin.linux@gmail.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=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=gary@garyguo.net \
    --cc=lossin@kernel.org \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tmgross@umich.edu \
    /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).