Skip to content

Commit

Permalink
rust: use #[vtable] for kernel::gpio::Chip
Browse files Browse the repository at this point in the history
Signed-off-by: Gary Guo <[email protected]>
  • Loading branch information
nbdd0121 committed Jul 3, 2022
1 parent 5d98b5a commit 5292e21
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 64 deletions.
9 changes: 1 addition & 8 deletions drivers/gpio/gpio_pl061_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,10 @@ type DeviceData = device::Data<PL061Registrations, PL061Resources, PL061Data>;

struct PL061Device;

#[vtable]
impl gpio::Chip for PL061Device {
type Data = Ref<DeviceData>;

kernel::declare_gpio_chip_operations!(
get_direction,
direction_input,
direction_output,
get,
set
);

fn get_direction(data: RefBorrow<'_, DeviceData>, offset: u32) -> Result<gpio::LineDirection> {
let pl061 = data.resources().ok_or(ENXIO)?;
Ok(if pl061.base.readb(GPIODIR) & bit(offset) != 0 {
Expand Down
64 changes: 8 additions & 56 deletions rust/kernel/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//!
//! C header: [`include/linux/gpio/driver.h`](../../../../include/linux/gpio/driver.h)
use crate::prelude::*;
use crate::{
bindings, device, error::code::*, error::from_kernel_result, sync::LockClassKey,
types::PointerWrapper, Error, Result,
Expand All @@ -27,16 +28,13 @@ pub enum LineDirection {
}

/// A gpio chip.
#[vtable]
pub trait Chip {
/// Context data associated with the gpio chip.
///
/// It determines the type of the context data passed to each of the methods of the trait.
type Data: PointerWrapper + Sync + Send;

/// The methods to use to populate [`struct gpio_chip`]. This is typically populated with
/// [`declare_gpio_chip_operations`].
const TO_USE: ToUse;

/// Returns the direction of the given gpio line.
fn get_direction(
_data: <Self::Data as PointerWrapper>::Borrowed<'_>,
Expand Down Expand Up @@ -73,52 +71,6 @@ pub trait Chip {
fn set(_data: <Self::Data as PointerWrapper>::Borrowed<'_>, _offset: u32, _value: bool) {}
}

/// Represents which fields of [`struct gpio_chip`] should be populated with pointers.
///
/// This is typically populated with the [`declare_gpio_chip_operations`] macro.
pub struct ToUse {
/// The `get_direction` field of [`struct gpio_chip`].
pub get_direction: bool,

/// The `direction_input` field of [`struct gpio_chip`].
pub direction_input: bool,

/// The `direction_output` field of [`struct gpio_chip`].
pub direction_output: bool,

/// The `get` field of [`struct gpio_chip`].
pub get: bool,

/// The `set` field of [`struct gpio_chip`].
pub set: bool,
}

/// A constant version where all values are set to `false`, that is, all supported fields will be
/// set to null pointers.
pub const USE_NONE: ToUse = ToUse {
get_direction: false,
direction_input: false,
direction_output: false,
get: false,
set: false,
};

/// Defines the [`Chip::TO_USE`] field based on a list of fields to be populated.
#[macro_export]
macro_rules! declare_gpio_chip_operations {
() => {
const TO_USE: $crate::gpio::ToUse = $crate::gpio::USE_NONE;
};
($($i:ident),+) => {
#[allow(clippy::needless_update)]
const TO_USE: $crate::gpio::ToUse =
$crate::gpio::ToUse {
$($i: true),+ ,
..$crate::gpio::USE_NONE
};
};
}

/// A registration of a gpio chip.
///
/// # Examples
Expand All @@ -130,9 +82,9 @@ macro_rules! declare_gpio_chip_operations {
/// use kernel::{device::RawDevice, gpio::{self, Registration}};
///
/// struct MyGpioChip;
/// #[vtable]
/// impl gpio::Chip for MyGpioChip {
/// type Data = ();
/// kernel::declare_gpio_chip_operations!();
/// }
///
/// fn example(parent: &dyn RawDevice) -> Result<Pin<Box<Registration<MyGpioChip>>>> {
Expand Down Expand Up @@ -186,19 +138,19 @@ impl<T: Chip> Registration<T> {
// Set up the callbacks.
gc.request = Some(bindings::gpiochip_generic_request);
gc.free = Some(bindings::gpiochip_generic_free);
if T::TO_USE.get_direction {
if T::HAS_GET_DIRECTION {
gc.get_direction = Some(get_direction_callback::<T>);
}
if T::TO_USE.direction_input {
if T::HAS_DIRECTION_INPUT {
gc.direction_input = Some(direction_input_callback::<T>);
}
if T::TO_USE.direction_output {
if T::HAS_DIRECTION_OUTPUT {
gc.direction_output = Some(direction_output_callback::<T>);
}
if T::TO_USE.get {
if T::HAS_GET {
gc.get = Some(get_callback::<T>);
}
if T::TO_USE.set {
if T::HAS_SET {
gc.set = Some(set_callback::<T>);
}

Expand Down

0 comments on commit 5292e21

Please sign in to comment.