use crate::{
acpi,
container_of,
device,
device_id::{
RawDeviceId,
RawDeviceIdIndex, },
devres::Devres,
driver,
error::*,
of,
prelude::*,
sync::aref::{
ARef,
AlwaysRefCounted, },
types::Opaque, };
use core::{
marker::PhantomData,
mem::offset_of,
ptr::{
from_ref,
NonNull, }, };
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct DeviceId(bindings::i2c_device_id);
impl DeviceId {
const I2C_NAME_SIZE: usize = 20;
#[inline(always)]
pub const fn new(id: &'static CStr) -> Self {
let src = id.to_bytes_with_nul();
build_assert!(src.len() <= Self::I2C_NAME_SIZE, "ID exceeds 20 bytes");
let mut i2c: bindings::i2c_device_id = pin_init::zeroed();
let mut i = 0;
while i < src.len() {
i2c.name[i] = src[i];
i += 1;
}
Self(i2c)
}
}
unsafe impl RawDeviceId for DeviceId {
type RawType = bindings::i2c_device_id;
}
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
}
}
pub type IdTable<T> = &'static dyn kernel::device_id::IdTable<DeviceId, T>;
#[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);
};
}
pub struct Adapter<T: Driver>(T);
unsafe impl<T: Driver + 'static> driver::DriverLayout for Adapter<T> {
type DriverType = bindings::i2c_driver;
type DriverData = T;
const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver);
}
unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
unsafe fn register(
idrv: &Opaque<Self::DriverType>,
name: &'static CStr,
module: &'static ThisModule,
) -> Result {
build_assert!(
T::ACPI_ID_TABLE.is_some() || T::OF_ID_TABLE.is_some() || T::I2C_ID_TABLE.is_some(),
"At least one of ACPI/OF/Legacy tables must be present when registering an i2c driver"
);
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(),
};
unsafe {
(*idrv.get()).driver.name = name.as_char_ptr();
(*idrv.get()).probe = Some(Self::probe_callback);
(*idrv.get()).remove = Some(Self::remove_callback);
(*idrv.get()).shutdown = Some(Self::shutdown_callback);
(*idrv.get()).id_table = i2c_table;
(*idrv.get()).driver.of_match_table = of_table;
(*idrv.get()).driver.acpi_match_table = acpi_table;
}
to_result(unsafe { bindings::i2c_register_driver(module.0, idrv.get()) })
}
unsafe fn unregister(idrv: &Opaque<Self::DriverType>) {
unsafe { bindings::i2c_del_driver(idrv.get()) }
}
}
impl<T: Driver + 'static> Adapter<T> {
extern "C" fn probe_callback(idev: *mut bindings::i2c_client) -> kernel::ffi::c_int {
let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal>>() };
let info =
Self::i2c_id_info(idev).or_else(|| <Self as driver::Adapter>::id_info(idev.as_ref()));
from_result(|| {
let data = T::probe(idev, info);
idev.as_ref().set_drvdata(data)?;
Ok(0)
})
}
extern "C" fn remove_callback(idev: *mut bindings::i2c_client) {
let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal>>() };
let data = unsafe { idev.as_ref().drvdata_borrow::<T>() };
T::unbind(idev, data);
}
extern "C" fn shutdown_callback(idev: *mut bindings::i2c_client) {
let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal>>() };
let data = unsafe { idev.as_ref().drvdata_borrow::<T>() };
T::shutdown(idev, data);
}
fn i2c_id_table() -> Option<IdTable<<Self as driver::Adapter>::IdInfo>> {
T::I2C_ID_TABLE
}
fn i2c_id_info(dev: &I2cClient) -> Option<&'static <Self as driver::Adapter>::IdInfo> {
let table = Self::i2c_id_table()?;
let raw_id = unsafe { bindings::i2c_match_id(table.as_ptr(), dev.as_raw()) };
if raw_id.is_null() {
return None;
}
let id = unsafe { &*raw_id.cast::<DeviceId>() };
Some(table.info(<DeviceId as RawDeviceIdIndex>::index(id)))
}
}
impl<T: Driver + 'static> driver::Adapter for Adapter<T> {
type IdInfo = T::IdInfo;
fn of_id_table() -> Option<of::IdTable<Self::IdInfo>> {
T::OF_ID_TABLE
}
fn acpi_id_table() -> Option<acpi::IdTable<Self::IdInfo>> {
T::ACPI_ID_TABLE
}
}
#[macro_export]
macro_rules! module_i2c_driver {
($($f:tt)*) => {
$crate::module_driver!(<T>, $crate::i2c::Adapter<T>, { $($f)* });
};
}
pub trait Driver: Send {
type IdInfo: 'static;
const I2C_ID_TABLE: Option<IdTable<Self::IdInfo>> = None;
const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = None;
fn probe(
dev: &I2cClient<device::Core>,
id_info: Option<&Self::IdInfo>,
) -> impl PinInit<Self, Error>;
fn shutdown(dev: &I2cClient<device::Core>, this: Pin<&Self>) {
let _ = (dev, this);
}
fn unbind(dev: &I2cClient<device::Core>, this: Pin<&Self>) {
let _ = (dev, this);
}
}
#[repr(transparent)]
pub struct I2cAdapter<Ctx: device::DeviceContext = device::Normal>(
Opaque<bindings::i2c_adapter>,
PhantomData<Ctx>,
);
impl<Ctx: device::DeviceContext> I2cAdapter<Ctx> {
fn as_raw(&self) -> *mut bindings::i2c_adapter {
self.0.get()
}
}
impl I2cAdapter {
#[inline]
pub fn index(&self) -> i32 {
unsafe { (*self.as_raw()).nr }
}
pub fn get(index: i32) -> Result<ARef<Self>> {
let adapter = NonNull::new(unsafe { bindings::i2c_get_adapter(index) }).ok_or(ENODEV)?;
Ok(unsafe { (&*adapter.as_ptr().cast::<I2cAdapter<device::Normal>>()).into() })
}
}
kernel::impl_device_context_deref!(unsafe { I2cAdapter });
kernel::impl_device_context_into_aref!(I2cAdapter);
unsafe impl AlwaysRefCounted for I2cAdapter {
fn inc_ref(&self) {
unsafe { bindings::i2c_get_adapter(self.index()) };
}
unsafe fn dec_ref(obj: NonNull<Self>) {
unsafe { bindings::i2c_put_adapter(obj.as_ref().as_raw()) }
}
}
#[repr(transparent)]
pub struct I2cBoardInfo(bindings::i2c_board_info);
impl I2cBoardInfo {
const I2C_TYPE_SIZE: usize = 20;
#[inline(always)]
pub const fn new(type_: &'static CStr, addr: u16) -> Self {
let src = type_.to_bytes_with_nul();
build_assert!(src.len() <= Self::I2C_TYPE_SIZE, "Type exceeds 20 bytes");
let mut i2c_board_info: bindings::i2c_board_info = pin_init::zeroed();
let mut i: usize = 0;
while i < src.len() {
i2c_board_info.type_[i] = src[i];
i += 1;
}
i2c_board_info.addr = addr;
Self(i2c_board_info)
}
fn as_raw(&self) -> *const bindings::i2c_board_info {
from_ref(&self.0)
}
}
#[repr(transparent)]
pub struct I2cClient<Ctx: device::DeviceContext = device::Normal>(
Opaque<bindings::i2c_client>,
PhantomData<Ctx>,
);
impl<Ctx: device::DeviceContext> I2cClient<Ctx> {
fn as_raw(&self) -> *mut bindings::i2c_client {
self.0.get()
}
}
unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for I2cClient<Ctx> {
const OFFSET: usize = offset_of!(bindings::i2c_client, dev);
}
kernel::impl_device_context_deref!(unsafe { I2cClient });
kernel::impl_device_context_into_aref!(I2cClient);
unsafe impl AlwaysRefCounted for I2cClient {
fn inc_ref(&self) {
unsafe { bindings::get_device(self.as_ref().as_raw()) };
}
unsafe fn dec_ref(obj: NonNull<Self>) {
unsafe { bindings::put_device(&raw mut (*obj.as_ref().as_raw()).dev) }
}
}
impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for I2cClient<Ctx> {
fn as_ref(&self) -> &device::Device<Ctx> {
let raw = self.as_raw();
let dev = unsafe { &raw mut (*raw).dev };
unsafe { device::Device::from_raw(dev) }
}
}
impl<Ctx: device::DeviceContext> TryFrom<&device::Device<Ctx>> for &I2cClient<Ctx> {
type Error = kernel::error::Error;
fn try_from(dev: &device::Device<Ctx>) -> Result<Self, Self::Error> {
if unsafe { bindings::i2c_verify_client(dev.as_raw()).is_null() } {
return Err(EINVAL);
}
let idev = unsafe { container_of!(dev.as_raw(), bindings::i2c_client, dev) };
Ok(unsafe { &*idev.cast() })
}
}
unsafe impl Send for I2cClient {}
unsafe impl Sync for I2cClient {}
#[repr(transparent)]
pub struct Registration(NonNull<bindings::i2c_client>);
impl Registration {
pub fn new<'a>(
i2c_adapter: &I2cAdapter,
i2c_board_info: &I2cBoardInfo,
parent_dev: &'a device::Device<device::Bound>,
) -> impl PinInit<Devres<Self>, Error> + 'a {
Devres::new(parent_dev, Self::try_new(i2c_adapter, i2c_board_info))
}
fn try_new(i2c_adapter: &I2cAdapter, i2c_board_info: &I2cBoardInfo) -> Result<Self> {
let raw_dev = from_err_ptr(unsafe {
bindings::i2c_new_client_device(i2c_adapter.as_raw(), i2c_board_info.as_raw())
})?;
let dev_ptr = NonNull::new(raw_dev).ok_or(ENODEV)?;
Ok(Self(dev_ptr))
}
}
impl Drop for Registration {
fn drop(&mut self) {
unsafe { bindings::i2c_unregister_device(self.0.as_ptr()) }
}
}
unsafe impl Send for Registration {}
unsafe impl Sync for Registration {}