Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: i2c: add manual I2C device creation abstractions

In addition to the basic I2C device support, add rust abstractions
upon `i2c_new_client_device`/`i2c_unregister_device` C functions.

Implement the core abstractions needed for manual creation/deletion
of I2C devices, including:

* `i2c::Registration` — a NonNull pointer created by the function
`i2c_new_client_device`

* `i2c::I2cAdapter` — a ref counted wrapper around `struct i2c_adapter`

* `i2c::I2cBoardInfo` — a safe wrapper around `struct i2c_board_info`

Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Igor Korotin <igor.korotin.linux@gmail.com>
Link: https://patch.msgid.link/20251116162154.171493-1-igor.korotin.linux@gmail.com
[ Remove unnecessary safety comment. - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>

authored by

Igor Korotin and committed by
Danilo Krummrich
f3cc26a4 57c5bd9a

+152 -1
+152 -1
rust/kernel/i2c.rs
··· 11 11 RawDeviceId, 12 12 RawDeviceIdIndex, // 13 13 }, 14 + devres::Devres, 14 15 driver, 15 16 error::*, 16 17 of, ··· 24 23 25 24 use core::{ 26 25 marker::PhantomData, 27 - ptr::NonNull, // 26 + ptr::{ 27 + from_ref, 28 + NonNull, // 29 + }, // 28 30 }; 31 + 32 + use kernel::types::ARef; 29 33 30 34 /// An I2C device id table. 31 35 #[repr(transparent)] ··· 360 354 } 361 355 } 362 356 357 + /// The i2c adapter representation. 358 + /// 359 + /// This structure represents the Rust abstraction for a C `struct i2c_adapter`. The 360 + /// implementation abstracts the usage of an existing C `struct i2c_adapter` that 361 + /// gets passed from the C side 362 + /// 363 + /// # Invariants 364 + /// 365 + /// A [`I2cAdapter`] instance represents a valid `struct i2c_adapter` created by the C portion of 366 + /// the kernel. 367 + #[repr(transparent)] 368 + pub struct I2cAdapter<Ctx: device::DeviceContext = device::Normal>( 369 + Opaque<bindings::i2c_adapter>, 370 + PhantomData<Ctx>, 371 + ); 372 + 373 + impl<Ctx: device::DeviceContext> I2cAdapter<Ctx> { 374 + fn as_raw(&self) -> *mut bindings::i2c_adapter { 375 + self.0.get() 376 + } 377 + } 378 + 379 + impl I2cAdapter { 380 + /// Returns the I2C Adapter index. 381 + #[inline] 382 + pub fn index(&self) -> i32 { 383 + // SAFETY: `self.as_raw` is a valid pointer to a `struct i2c_adapter`. 384 + unsafe { (*self.as_raw()).nr } 385 + } 386 + 387 + /// Gets pointer to an `i2c_adapter` by index. 388 + pub fn get(index: i32) -> Result<ARef<Self>> { 389 + // SAFETY: `index` must refer to a valid I2C adapter; the kernel 390 + // guarantees that `i2c_get_adapter(index)` returns either a valid 391 + // pointer or NULL. `NonNull::new` guarantees the correct check. 392 + let adapter = NonNull::new(unsafe { bindings::i2c_get_adapter(index) }).ok_or(ENODEV)?; 393 + 394 + // SAFETY: `adapter` is non-null and points to a live `i2c_adapter`. 395 + // `I2cAdapter` is #[repr(transparent)], so this cast is valid. 396 + Ok(unsafe { (&*adapter.as_ptr().cast::<I2cAdapter<device::Normal>>()).into() }) 397 + } 398 + } 399 + 400 + // SAFETY: `I2cAdapter` is a transparent wrapper of a type that doesn't depend on 401 + // `I2cAdapter`'s generic argument. 402 + kernel::impl_device_context_deref!(unsafe { I2cAdapter }); 403 + kernel::impl_device_context_into_aref!(I2cAdapter); 404 + 405 + // SAFETY: Instances of `I2cAdapter` are always reference-counted. 406 + unsafe impl crate::types::AlwaysRefCounted for I2cAdapter { 407 + fn inc_ref(&self) { 408 + // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. 409 + unsafe { bindings::i2c_get_adapter(self.index()) }; 410 + } 411 + 412 + unsafe fn dec_ref(obj: NonNull<Self>) { 413 + // SAFETY: The safety requirements guarantee that the refcount is non-zero. 414 + unsafe { bindings::i2c_put_adapter(obj.as_ref().as_raw()) } 415 + } 416 + } 417 + 418 + /// The i2c board info representation 419 + /// 420 + /// This structure represents the Rust abstraction for a C `struct i2c_board_info` structure, 421 + /// which is used for manual I2C client creation. 422 + #[repr(transparent)] 423 + pub struct I2cBoardInfo(bindings::i2c_board_info); 424 + 425 + impl I2cBoardInfo { 426 + const I2C_TYPE_SIZE: usize = 20; 427 + /// Create a new [`I2cBoardInfo`] for a kernel driver. 428 + #[inline(always)] 429 + pub const fn new(type_: &'static CStr, addr: u16) -> Self { 430 + build_assert!( 431 + type_.len_with_nul() <= Self::I2C_TYPE_SIZE, 432 + "Type exceeds 20 bytes" 433 + ); 434 + let src = type_.as_bytes_with_nul(); 435 + let mut i2c_board_info: bindings::i2c_board_info = pin_init::zeroed(); 436 + let mut i: usize = 0; 437 + while i < src.len() { 438 + i2c_board_info.type_[i] = src[i]; 439 + i += 1; 440 + } 441 + 442 + i2c_board_info.addr = addr; 443 + Self(i2c_board_info) 444 + } 445 + 446 + fn as_raw(&self) -> *const bindings::i2c_board_info { 447 + from_ref(&self.0) 448 + } 449 + } 450 + 363 451 /// The i2c client representation. 364 452 /// 365 453 /// This structure represents the Rust abstraction for a C `struct i2c_client`. The ··· 532 432 // SAFETY: `I2cClient` can be shared among threads because all methods of `I2cClient` 533 433 // (i.e. `I2cClient<Normal>) are thread safe. 534 434 unsafe impl Sync for I2cClient {} 435 + 436 + /// The registration of an i2c client device. 437 + /// 438 + /// This type represents the registration of a [`struct i2c_client`]. When an instance of this 439 + /// type is dropped, its respective i2c client device will be unregistered from the system. 440 + /// 441 + /// # Invariants 442 + /// 443 + /// `self.0` always holds a valid pointer to an initialized and registered 444 + /// [`struct i2c_client`]. 445 + #[repr(transparent)] 446 + pub struct Registration(NonNull<bindings::i2c_client>); 447 + 448 + impl Registration { 449 + /// The C `i2c_new_client_device` function wrapper for manual I2C client creation. 450 + pub fn new<'a>( 451 + i2c_adapter: &I2cAdapter, 452 + i2c_board_info: &I2cBoardInfo, 453 + parent_dev: &'a device::Device<device::Bound>, 454 + ) -> impl PinInit<Devres<Self>, Error> + 'a { 455 + Devres::new(parent_dev, Self::try_new(i2c_adapter, i2c_board_info)) 456 + } 457 + 458 + fn try_new(i2c_adapter: &I2cAdapter, i2c_board_info: &I2cBoardInfo) -> Result<Self> { 459 + // SAFETY: the kernel guarantees that `i2c_new_client_device()` returns either a valid 460 + // pointer or NULL. `from_err_ptr` separates errors. Following `NonNull::new` 461 + // checks for NULL. 462 + let raw_dev = from_err_ptr(unsafe { 463 + bindings::i2c_new_client_device(i2c_adapter.as_raw(), i2c_board_info.as_raw()) 464 + })?; 465 + 466 + let dev_ptr = NonNull::new(raw_dev).ok_or(ENODEV)?; 467 + 468 + Ok(Self(dev_ptr)) 469 + } 470 + } 471 + 472 + impl Drop for Registration { 473 + fn drop(&mut self) { 474 + // SAFETY: `Drop` is only called for a valid `Registration`, which by invariant 475 + // always contains a non-null pointer to an `i2c_client`. 476 + unsafe { bindings::i2c_unregister_device(self.0.as_ptr()) } 477 + } 478 + } 479 + 480 + // SAFETY: A `Registration` of a `struct i2c_client` can be released from any thread. 481 + unsafe impl Send for Registration {} 482 + 483 + // SAFETY: `Registration` offers no interior mutability (no mutation through &self 484 + // and no mutable access is exposed) 485 + unsafe impl Sync for Registration {}