Skip to content

Commit

Permalink
Merge pull request raspberrypi#322 from nbdd0121/macros
Browse files Browse the repository at this point in the history
Implement a `#[vtable]` macro
  • Loading branch information
wedsonaf authored Jul 5, 2022
2 parents b3e8654 + d2b8246 commit ec966c7
Show file tree
Hide file tree
Showing 15 changed files with 187 additions and 237 deletions.
3 changes: 1 addition & 2 deletions drivers/android/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -805,12 +805,11 @@ impl IoctlHandler for Process {
}
}

#[vtable]
impl file::Operations for Process {
type Data = Ref<Self>;
type OpenData = Ref<Context>;

kernel::declare_file_operations!(ioctl, compat_ioctl, mmap, poll);

fn open(ctx: &Ref<Context>, file: &File) -> Result<Self::Data> {
Self::new(ctx.clone(), file.cred().into())
}
Expand Down
3 changes: 1 addition & 2 deletions drivers/char/hw_random/bcm2835_rng_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ module_platform_driver! {

struct RngDevice;

#[vtable]
impl file::Operations for RngDevice {
kernel::declare_file_operations!(read);

fn open(_open_data: &(), _file: &File) -> Result {
Ok(())
}
Expand Down
12 changes: 2 additions & 10 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 Expand Up @@ -129,11 +122,10 @@ impl gpio::ChipWithIrqChip for PL061Device {
}
}

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

kernel::declare_irq_chip_operations!(set_type, set_wake);

fn set_type(
data: RefBorrow<'_, DeviceData>,
irq_data: &mut LockedIrqData,
Expand Down
88 changes: 12 additions & 76 deletions rust/kernel/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::{
};
use core::convert::{TryFrom, TryInto};
use core::{cell::UnsafeCell, marker, mem, ptr};
use macros::vtable;

/// Wraps the kernel's `struct file`.
///
Expand Down Expand Up @@ -468,24 +469,24 @@ impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> {
const VTABLE: bindings::file_operations = bindings::file_operations {
open: Some(Self::open_callback),
release: Some(Self::release_callback),
read: if T::TO_USE.read {
read: if T::HAS_READ {
Some(Self::read_callback)
} else {
None
},
write: if T::TO_USE.write {
write: if T::HAS_WRITE {
Some(Self::write_callback)
} else {
None
},
llseek: if T::TO_USE.seek {
llseek: if T::HAS_SEEK {
Some(Self::llseek_callback)
} else {
None
},

check_flags: None,
compat_ioctl: if T::TO_USE.compat_ioctl {
compat_ioctl: if T::HAS_COMPAT_IOCTL {
Some(Self::compat_ioctl_callback)
} else {
None
Expand All @@ -496,7 +497,7 @@ impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> {
fasync: None,
flock: None,
flush: None,
fsync: if T::TO_USE.fsync {
fsync: if T::HAS_FSYNC {
Some(Self::fsync_callback)
} else {
None
Expand All @@ -506,19 +507,19 @@ impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> {
iterate_shared: None,
iopoll: None,
lock: None,
mmap: if T::TO_USE.mmap {
mmap: if T::HAS_MMAP {
Some(Self::mmap_callback)
} else {
None
},
mmap_supported_flags: 0,
owner: ptr::null_mut(),
poll: if T::TO_USE.poll {
poll: if T::HAS_POLL {
Some(Self::poll_callback)
} else {
None
},
read_iter: if T::TO_USE.read_iter {
read_iter: if T::HAS_READ {
Some(Self::read_iter_callback)
} else {
None
Expand All @@ -529,13 +530,13 @@ impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> {
show_fdinfo: None,
splice_read: None,
splice_write: None,
unlocked_ioctl: if T::TO_USE.ioctl {
unlocked_ioctl: if T::HAS_IOCTL {
Some(Self::unlocked_ioctl_callback)
} else {
None
},
uring_cmd: None,
write_iter: if T::TO_USE.write_iter {
write_iter: if T::HAS_WRITE {
Some(Self::write_iter_callback)
} else {
None
Expand All @@ -552,69 +553,6 @@ impl<A: OpenAdapter<T::OpenData>, T: Operations> OperationsVtable<A, T> {
}
}

/// Represents which fields of [`struct file_operations`] should be populated with pointers.
pub struct ToUse {
/// The `read` field of [`struct file_operations`].
pub read: bool,

/// The `read_iter` field of [`struct file_operations`].
pub read_iter: bool,

/// The `write` field of [`struct file_operations`].
pub write: bool,

/// The `write_iter` field of [`struct file_operations`].
pub write_iter: bool,

/// The `llseek` field of [`struct file_operations`].
pub seek: bool,

/// The `unlocked_ioctl` field of [`struct file_operations`].
pub ioctl: bool,

/// The `compat_ioctl` field of [`struct file_operations`].
pub compat_ioctl: bool,

/// The `fsync` field of [`struct file_operations`].
pub fsync: bool,

/// The `mmap` field of [`struct file_operations`].
pub mmap: bool,

/// The `poll` field of [`struct file_operations`].
pub poll: bool,
}

/// A constant version where all values are to set to `false`, that is, all supported fields will
/// be set to null pointers.
pub const USE_NONE: ToUse = ToUse {
read: false,
read_iter: false,
write: false,
write_iter: false,
seek: false,
ioctl: false,
compat_ioctl: false,
fsync: false,
mmap: false,
poll: false,
};

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

/// Allows the handling of ioctls defined with the `_IO`, `_IOR`, `_IOW`, and `_IOWR` macros.
///
/// For each macro, there is a handler function that takes the appropriate types as arguments.
Expand Down Expand Up @@ -742,10 +680,8 @@ pub trait OpenAdapter<T: Sync> {
/// File descriptors may be used from multiple threads/processes concurrently, so your type must be
/// [`Sync`]. It must also be [`Send`] because [`Operations::release`] will be called from the
/// thread that decrements that associated file's refcount to zero.
#[vtable]
pub trait Operations {
/// The methods to use to populate [`struct file_operations`].
const TO_USE: ToUse;

/// The type of the context data returned by [`Operations::open`] and made available to
/// other methods.
type Data: PointerWrapper + Send + Sync = ();
Expand Down
69 changes: 12 additions & 57 deletions rust/kernel/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use core::{
marker::{PhantomData, PhantomPinned},
pin::Pin,
};
use macros::vtable;

#[cfg(CONFIG_GPIOLIB_IRQCHIP)]
pub use irqchip::{ChipWithIrqChip, RegistrationWithIrqChip};
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 Expand Up @@ -475,9 +427,12 @@ mod irqchip {
/// data is passed as context.
struct IrqChipAdapter<T: irq::Chip>(PhantomData<T>);

#[vtable]
impl<T: irq::Chip> irq::Chip for IrqChipAdapter<T> {
type Data = *mut bindings::gpio_chip;
const TO_USE: irq::ToUse = T::TO_USE;

const HAS_SET_TYPE: bool = T::HAS_SET_TYPE;
const HAS_SET_WAKE: bool = T::HAS_SET_WAKE;

fn ack(gc: *mut bindings::gpio_chip, irq_data: &irq::IrqData) {
// SAFETY: `IrqChipAdapter` is a private struct, only used when the data stored in the
Expand Down
Loading

0 comments on commit ec966c7

Please sign in to comment.