summaryrefslogtreecommitdiff
path: root/rust
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-04-01 11:26:08 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2025-04-01 11:26:08 -0700
commit25601e85441dd91cf7973b002f27af4c5b8691ea (patch)
tree821267764ed1dbdfb7d08839f7bf0054358eb4f8 /rust
parent2cd5769fb0b78b8ef583ab4c0015c2c48d525dac (diff)
parent5d1a5c4f121f0ec50327e899c9450978505f1560 (diff)
Merge tag 'char-misc-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char / misc / IIO driver updates from Greg KH: "Here is the big set of char, misc, iio, and other smaller driver subsystems for 6.15-rc1. Lots of stuff in here, including: - loads of IIO changes and driver updates - counter driver updates - w1 driver updates - faux conversions for some drivers that were abusing the platform bus interface - coresight driver updates - rust miscdevice binding updates based on real-world-use - other minor driver updates All of these have been in linux-next with no reported issues for quite a while" * tag 'char-misc-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (292 commits) samples: rust_misc_device: fix markup in top-level docs Coresight: Fix a NULL vs IS_ERR() bug in probe misc: lis3lv02d: convert to use faux_device tlclk: convert to use faux_device regulator: dummy: convert to use the faux device interface bus: mhi: host: Fix race between unprepare and queue_buf coresight: configfs: Constify struct config_item_type doc: iio: ad7380: describe offload support iio: ad7380: add support for SPI offload iio: light: Add check for array bounds in veml6075_read_int_time_ms iio: adc: ti-ads7924 Drop unnecessary function parameters staging: iio: ad9834: Use devm_regulator_get_enable() staging: iio: ad9832: Use devm_regulator_get_enable() iio: gyro: bmg160_spi: add of_match_table dt-bindings: iio: adc: Add i.MX94 and i.MX95 support iio: adc: ad7768-1: remove unnecessary locking Documentation: ABI: add wideband filter type to sysfs-bus-iio iio: adc: ad7768-1: set MOSI idle state to prevent accidental reset iio: adc: ad7768-1: Fix conversion result sign iio: adc: ad7124: Benefit of dev = indio_dev->dev.parent in ad7124_parse_channel_config() ...
Diffstat (limited to 'rust')
-rw-r--r--rust/kernel/miscdevice.rs297
1 files changed, 143 insertions, 154 deletions
diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
index e14433b2ab9d..fa9ecc42602a 100644
--- a/rust/kernel/miscdevice.rs
+++ b/rust/kernel/miscdevice.rs
@@ -35,7 +35,7 @@ impl MiscDeviceOptions {
let mut result: bindings::miscdevice = unsafe { MaybeUninit::zeroed().assume_init() };
result.minor = bindings::MISC_DYNAMIC_MINOR as _;
result.name = self.name.as_char_ptr();
- result.fops = create_vtable::<T>();
+ result.fops = MiscdeviceVTable::<T>::build();
result
}
}
@@ -160,171 +160,160 @@ pub trait MiscDevice: Sized {
}
}
-const fn create_vtable<T: MiscDevice>() -> &'static bindings::file_operations {
- const fn maybe_fn<T: Copy>(check: bool, func: T) -> Option<T> {
- if check {
- Some(func)
- } else {
- None
+/// A vtable for the file operations of a Rust miscdevice.
+struct MiscdeviceVTable<T: MiscDevice>(PhantomData<T>);
+
+impl<T: MiscDevice> MiscdeviceVTable<T> {
+ /// # Safety
+ ///
+ /// `file` and `inode` must be the file and inode for a file that is undergoing initialization.
+ /// The file must be associated with a `MiscDeviceRegistration<T>`.
+ unsafe extern "C" fn open(inode: *mut bindings::inode, raw_file: *mut bindings::file) -> c_int {
+ // SAFETY: The pointers are valid and for a file being opened.
+ let ret = unsafe { bindings::generic_file_open(inode, raw_file) };
+ if ret != 0 {
+ return ret;
}
- }
- struct VtableHelper<T: MiscDevice> {
- _t: PhantomData<T>,
- }
- impl<T: MiscDevice> VtableHelper<T> {
- const VTABLE: bindings::file_operations = bindings::file_operations {
- open: Some(fops_open::<T>),
- release: Some(fops_release::<T>),
- unlocked_ioctl: maybe_fn(T::HAS_IOCTL, fops_ioctl::<T>),
- #[cfg(CONFIG_COMPAT)]
- compat_ioctl: if T::HAS_COMPAT_IOCTL {
- Some(fops_compat_ioctl::<T>)
- } else if T::HAS_IOCTL {
- Some(bindings::compat_ptr_ioctl)
- } else {
- None
- },
- show_fdinfo: maybe_fn(T::HAS_SHOW_FDINFO, fops_show_fdinfo::<T>),
- // SAFETY: All zeros is a valid value for `bindings::file_operations`.
- ..unsafe { MaybeUninit::zeroed().assume_init() }
- };
- }
+ // SAFETY: The open call of a file can access the private data.
+ let misc_ptr = unsafe { (*raw_file).private_data };
- &VtableHelper::<T>::VTABLE
-}
+ // SAFETY: This is a miscdevice, so `misc_open()` set the private data to a pointer to the
+ // associated `struct miscdevice` before calling into this method. Furthermore,
+ // `misc_open()` ensures that the miscdevice can't be unregistered and freed during this
+ // call to `fops_open`.
+ let misc = unsafe { &*misc_ptr.cast::<MiscDeviceRegistration<T>>() };
-/// # Safety
-///
-/// `file` and `inode` must be the file and inode for a file that is undergoing initialization.
-/// The file must be associated with a `MiscDeviceRegistration<T>`.
-unsafe extern "C" fn fops_open<T: MiscDevice>(
- inode: *mut bindings::inode,
- raw_file: *mut bindings::file,
-) -> c_int {
- // SAFETY: The pointers are valid and for a file being opened.
- let ret = unsafe { bindings::generic_file_open(inode, raw_file) };
- if ret != 0 {
- return ret;
- }
+ // SAFETY:
+ // * This underlying file is valid for (much longer than) the duration of `T::open`.
+ // * There is no active fdget_pos region on the file on this thread.
+ let file = unsafe { File::from_raw_file(raw_file) };
- // SAFETY: The open call of a file can access the private data.
- let misc_ptr = unsafe { (*raw_file).private_data };
-
- // SAFETY: This is a miscdevice, so `misc_open()` set the private data to a pointer to the
- // associated `struct miscdevice` before calling into this method. Furthermore, `misc_open()`
- // ensures that the miscdevice can't be unregistered and freed during this call to `fops_open`.
- let misc = unsafe { &*misc_ptr.cast::<MiscDeviceRegistration<T>>() };
+ let ptr = match T::open(file, misc) {
+ Ok(ptr) => ptr,
+ Err(err) => return err.to_errno(),
+ };
- // SAFETY:
- // * This underlying file is valid for (much longer than) the duration of `T::open`.
- // * There is no active fdget_pos region on the file on this thread.
- let file = unsafe { File::from_raw_file(raw_file) };
+ // This overwrites the private data with the value specified by the user, changing the type
+ // of this file's private data. All future accesses to the private data is performed by
+ // other fops_* methods in this file, which all correctly cast the private data to the new
+ // type.
+ //
+ // SAFETY: The open call of a file can access the private data.
+ unsafe { (*raw_file).private_data = ptr.into_foreign() };
- let ptr = match T::open(file, misc) {
- Ok(ptr) => ptr,
- Err(err) => return err.to_errno(),
- };
-
- // This overwrites the private data with the value specified by the user, changing the type of
- // this file's private data. All future accesses to the private data is performed by other
- // fops_* methods in this file, which all correctly cast the private data to the new type.
- //
- // SAFETY: The open call of a file can access the private data.
- unsafe { (*raw_file).private_data = ptr.into_foreign() };
+ 0
+ }
- 0
-}
+ /// # Safety
+ ///
+ /// `file` and `inode` must be the file and inode for a file that is being released. The file
+ /// must be associated with a `MiscDeviceRegistration<T>`.
+ unsafe extern "C" fn release(_inode: *mut bindings::inode, file: *mut bindings::file) -> c_int {
+ // SAFETY: The release call of a file owns the private data.
+ let private = unsafe { (*file).private_data };
+ // SAFETY: The release call of a file owns the private data.
+ let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) };
+
+ // SAFETY:
+ // * The file is valid for the duration of this call.
+ // * There is no active fdget_pos region on the file on this thread.
+ T::release(ptr, unsafe { File::from_raw_file(file) });
+
+ 0
+ }
-/// # Safety
-///
-/// `file` and `inode` must be the file and inode for a file that is being released. The file must
-/// be associated with a `MiscDeviceRegistration<T>`.
-unsafe extern "C" fn fops_release<T: MiscDevice>(
- _inode: *mut bindings::inode,
- file: *mut bindings::file,
-) -> c_int {
- // SAFETY: The release call of a file owns the private data.
- let private = unsafe { (*file).private_data };
- // SAFETY: The release call of a file owns the private data.
- let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) };
-
- // SAFETY:
- // * The file is valid for the duration of this call.
- // * There is no active fdget_pos region on the file on this thread.
- T::release(ptr, unsafe { File::from_raw_file(file) });
-
- 0
-}
+ /// # Safety
+ ///
+ /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
+ unsafe extern "C" fn ioctl(file: *mut bindings::file, cmd: c_uint, arg: c_ulong) -> c_long {
+ // SAFETY: The ioctl call of a file can access the private data.
+ let private = unsafe { (*file).private_data };
+ // SAFETY: Ioctl calls can borrow the private data of the file.
+ let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
+
+ // SAFETY:
+ // * The file is valid for the duration of this call.
+ // * There is no active fdget_pos region on the file on this thread.
+ let file = unsafe { File::from_raw_file(file) };
+
+ match T::ioctl(device, file, cmd, arg) {
+ Ok(ret) => ret as c_long,
+ Err(err) => err.to_errno() as c_long,
+ }
+ }
-/// # Safety
-///
-/// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
-unsafe extern "C" fn fops_ioctl<T: MiscDevice>(
- file: *mut bindings::file,
- cmd: c_uint,
- arg: c_ulong,
-) -> c_long {
- // SAFETY: The ioctl call of a file can access the private data.
- let private = unsafe { (*file).private_data };
- // SAFETY: Ioctl calls can borrow the private data of the file.
- let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
-
- // SAFETY:
- // * The file is valid for the duration of this call.
- // * There is no active fdget_pos region on the file on this thread.
- let file = unsafe { File::from_raw_file(file) };
-
- match T::ioctl(device, file, cmd, arg) {
- Ok(ret) => ret as c_long,
- Err(err) => err.to_errno() as c_long,
+ /// # Safety
+ ///
+ /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
+ #[cfg(CONFIG_COMPAT)]
+ unsafe extern "C" fn compat_ioctl(
+ file: *mut bindings::file,
+ cmd: c_uint,
+ arg: c_ulong,
+ ) -> c_long {
+ // SAFETY: The compat ioctl call of a file can access the private data.
+ let private = unsafe { (*file).private_data };
+ // SAFETY: Ioctl calls can borrow the private data of the file.
+ let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
+
+ // SAFETY:
+ // * The file is valid for the duration of this call.
+ // * There is no active fdget_pos region on the file on this thread.
+ let file = unsafe { File::from_raw_file(file) };
+
+ match T::compat_ioctl(device, file, cmd, arg) {
+ Ok(ret) => ret as c_long,
+ Err(err) => err.to_errno() as c_long,
+ }
}
-}
-/// # Safety
-///
-/// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
-#[cfg(CONFIG_COMPAT)]
-unsafe extern "C" fn fops_compat_ioctl<T: MiscDevice>(
- file: *mut bindings::file,
- cmd: c_uint,
- arg: c_ulong,
-) -> c_long {
- // SAFETY: The compat ioctl call of a file can access the private data.
- let private = unsafe { (*file).private_data };
- // SAFETY: Ioctl calls can borrow the private data of the file.
- let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
-
- // SAFETY:
- // * The file is valid for the duration of this call.
- // * There is no active fdget_pos region on the file on this thread.
- let file = unsafe { File::from_raw_file(file) };
-
- match T::compat_ioctl(device, file, cmd, arg) {
- Ok(ret) => ret as c_long,
- Err(err) => err.to_errno() as c_long,
+ /// # Safety
+ ///
+ /// - `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
+ /// - `seq_file` must be a valid `struct seq_file` that we can write to.
+ unsafe extern "C" fn show_fdinfo(seq_file: *mut bindings::seq_file, file: *mut bindings::file) {
+ // SAFETY: The release call of a file owns the private data.
+ let private = unsafe { (*file).private_data };
+ // SAFETY: Ioctl calls can borrow the private data of the file.
+ let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
+ // SAFETY:
+ // * The file is valid for the duration of this call.
+ // * There is no active fdget_pos region on the file on this thread.
+ let file = unsafe { File::from_raw_file(file) };
+ // SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in
+ // which this method is called.
+ let m = unsafe { SeqFile::from_raw(seq_file) };
+
+ T::show_fdinfo(device, m, file);
}
-}
-/// # Safety
-///
-/// - `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
-/// - `seq_file` must be a valid `struct seq_file` that we can write to.
-unsafe extern "C" fn fops_show_fdinfo<T: MiscDevice>(
- seq_file: *mut bindings::seq_file,
- file: *mut bindings::file,
-) {
- // SAFETY: The release call of a file owns the private data.
- let private = unsafe { (*file).private_data };
- // SAFETY: Ioctl calls can borrow the private data of the file.
- let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
- // SAFETY:
- // * The file is valid for the duration of this call.
- // * There is no active fdget_pos region on the file on this thread.
- let file = unsafe { File::from_raw_file(file) };
- // SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which
- // this method is called.
- let m = unsafe { SeqFile::from_raw(seq_file) };
-
- T::show_fdinfo(device, m, file);
+ const VTABLE: bindings::file_operations = bindings::file_operations {
+ open: Some(Self::open),
+ release: Some(Self::release),
+ unlocked_ioctl: if T::HAS_IOCTL {
+ Some(Self::ioctl)
+ } else {
+ None
+ },
+ #[cfg(CONFIG_COMPAT)]
+ compat_ioctl: if T::HAS_COMPAT_IOCTL {
+ Some(Self::compat_ioctl)
+ } else if T::HAS_IOCTL {
+ Some(bindings::compat_ptr_ioctl)
+ } else {
+ None
+ },
+ show_fdinfo: if T::HAS_SHOW_FDINFO {
+ Some(Self::show_fdinfo)
+ } else {
+ None
+ },
+ // SAFETY: All zeros is a valid value for `bindings::file_operations`.
+ ..unsafe { MaybeUninit::zeroed().assume_init() }
+ };
+
+ const fn build() -> &'static bindings::file_operations {
+ &Self::VTABLE
+ }
}