|
| 1 | +// SPDX-License-Identifier: GPL-2.0 OR MIT |
| 2 | +#![allow(non_snake_case)] |
| 3 | + |
| 4 | +//! DRM IOCTL definitions. |
| 5 | +//! |
| 6 | +//! C header: [`include/linux/drm/drm_ioctl.h`](../../../../include/linux/drm/drm_ioctl.h) |
| 7 | +
|
| 8 | +use crate::ioctl; |
| 9 | + |
| 10 | +const BASE: u32 = bindings::DRM_IOCTL_BASE as u32; |
| 11 | + |
| 12 | +/// Construct a DRM ioctl number with no argument. |
| 13 | +#[inline(always)] |
| 14 | +pub const fn IO(nr: u32) -> u32 { |
| 15 | + ioctl::_IO(BASE, nr) |
| 16 | +} |
| 17 | + |
| 18 | +/// Construct a DRM ioctl number with a read-only argument. |
| 19 | +#[inline(always)] |
| 20 | +pub const fn IOR<T>(nr: u32) -> u32 { |
| 21 | + ioctl::_IOR::<T>(BASE, nr) |
| 22 | +} |
| 23 | + |
| 24 | +/// Construct a DRM ioctl number with a write-only argument. |
| 25 | +#[inline(always)] |
| 26 | +pub const fn IOW<T>(nr: u32) -> u32 { |
| 27 | + ioctl::_IOW::<T>(BASE, nr) |
| 28 | +} |
| 29 | + |
| 30 | +/// Construct a DRM ioctl number with a read-write argument. |
| 31 | +#[inline(always)] |
| 32 | +pub const fn IOWR<T>(nr: u32) -> u32 { |
| 33 | + ioctl::_IOWR::<T>(BASE, nr) |
| 34 | +} |
| 35 | + |
| 36 | +/// Descriptor type for DRM ioctls. Use the `declare_drm_ioctls!{}` macro to construct them. |
| 37 | +pub type DrmIoctlDescriptor = bindings::drm_ioctl_desc; |
| 38 | + |
| 39 | +/// This is for ioctl which are used for rendering, and require that the file descriptor is either |
| 40 | +/// for a render node, or if it’s a legacy/primary node, then it must be authenticated. |
| 41 | +pub const AUTH: u32 = bindings::drm_ioctl_flags_DRM_AUTH; |
| 42 | + |
| 43 | +/// This must be set for any ioctl which can change the modeset or display state. Userspace must |
| 44 | +/// call the ioctl through a primary node, while it is the active master. |
| 45 | +/// |
| 46 | +/// Note that read-only modeset ioctl can also be called by unauthenticated clients, or when a |
| 47 | +/// master is not the currently active one. |
| 48 | +pub const MASTER: u32 = bindings::drm_ioctl_flags_DRM_MASTER; |
| 49 | + |
| 50 | +/// Anything that could potentially wreak a master file descriptor needs to have this flag set. |
| 51 | +/// |
| 52 | +/// Current that’s only for the SETMASTER and DROPMASTER ioctl, which e.g. logind can call to force |
| 53 | +/// a non-behaving master (display compositor) into compliance. |
| 54 | +/// |
| 55 | +/// This is equivalent to callers with the SYSADMIN capability. |
| 56 | +pub const ROOT_ONLY: u32 = bindings::drm_ioctl_flags_DRM_ROOT_ONLY; |
| 57 | + |
| 58 | +/// Whether drm_ioctl_desc.func should be called with the DRM BKL held or not. Enforced as the |
| 59 | +/// default for all modern drivers, hence there should never be a need to set this flag. |
| 60 | +/// |
| 61 | +/// Do not use anywhere else than for the VBLANK_WAIT IOCTL, which is the only legacy IOCTL which |
| 62 | +/// needs this. |
| 63 | +pub const UNLOCKED: u32 = bindings::drm_ioctl_flags_DRM_UNLOCKED; |
| 64 | + |
| 65 | +/// This is used for all ioctl needed for rendering only, for drivers which support render nodes. |
| 66 | +/// This should be all new render drivers, and hence it should be always set for any ioctl with |
| 67 | +/// `AUTH` set. Note though that read-only query ioctl might have this set, but have not set |
| 68 | +/// DRM_AUTH because they do not require authentication. |
| 69 | +pub const RENDER_ALLOW: u32 = bindings::drm_ioctl_flags_DRM_RENDER_ALLOW; |
| 70 | + |
| 71 | +/// Internal structures used by the [`declare_drm_ioctls!{}`] macro. Do not use directly. |
| 72 | +#[doc(hidden)] |
| 73 | +pub mod internal { |
| 74 | + pub use bindings::drm_device; |
| 75 | + pub use bindings::drm_file; |
| 76 | + pub use bindings::drm_ioctl_desc; |
| 77 | +} |
| 78 | + |
| 79 | +/// Declare the DRM ioctls for a driver. |
| 80 | +/// |
| 81 | +/// Each entry in the list should have the form: |
| 82 | +/// |
| 83 | +/// `(ioctl_number, argument_type, flags, user_callback),` |
| 84 | +/// |
| 85 | +/// `argument_type` is the type name within the `bindings` crate. |
| 86 | +/// `user_callback` should have the following prototype: |
| 87 | +/// |
| 88 | +/// ``` |
| 89 | +/// fn foo(device: &kernel::drm::device::Device<Self>, |
| 90 | +/// data: &mut bindings::argument_type, |
| 91 | +/// file: &kernel::drm::file::File<Self::File>, |
| 92 | +/// ) |
| 93 | +/// ``` |
| 94 | +/// where `Self` is the drm::drv::Driver implementation these ioctls are being declared within. |
| 95 | +/// |
| 96 | +/// # Examples |
| 97 | +/// |
| 98 | +/// ``` |
| 99 | +/// kernel::declare_drm_ioctls! { |
| 100 | +/// (FOO_GET_PARAM, drm_foo_get_param, ioctl::RENDER_ALLOW, my_get_param_handler), |
| 101 | +/// } |
| 102 | +/// ``` |
| 103 | +/// |
| 104 | +#[macro_export] |
| 105 | +macro_rules! declare_drm_ioctls { |
| 106 | + ( $(($cmd:ident, $struct:ident, $flags:expr, $func:expr)),* $(,)? ) => { |
| 107 | + const IOCTLS: &'static [$crate::drm::ioctl::DrmIoctlDescriptor] = { |
| 108 | + use $crate::uapi::*; |
| 109 | + const _:() = { |
| 110 | + let i: u32 = $crate::uapi::DRM_COMMAND_BASE; |
| 111 | + // Assert that all the IOCTLs are in the right order and there are no gaps, |
| 112 | + // and that the sizeof of the specified type is correct. |
| 113 | + $( |
| 114 | + let cmd: u32 = $crate::macros::concat_idents!(DRM_IOCTL_, $cmd); |
| 115 | + ::core::assert!(i == $crate::ioctl::_IOC_NR(cmd)); |
| 116 | + ::core::assert!(core::mem::size_of::<$crate::uapi::$struct>() == $crate::ioctl::_IOC_SIZE(cmd)); |
| 117 | + let i: u32 = i + 1; |
| 118 | + )* |
| 119 | + }; |
| 120 | + |
| 121 | + let ioctls = &[$( |
| 122 | + $crate::drm::ioctl::internal::drm_ioctl_desc { |
| 123 | + cmd: $crate::macros::concat_idents!(DRM_IOCTL_, $cmd) as u32, |
| 124 | + func: { |
| 125 | + #[allow(non_snake_case)] |
| 126 | + unsafe extern "C" fn $cmd( |
| 127 | + raw_dev: *mut $crate::drm::ioctl::internal::drm_device, |
| 128 | + raw_data: *mut ::core::ffi::c_void, |
| 129 | + raw_file_priv: *mut $crate::drm::ioctl::internal::drm_file, |
| 130 | + ) -> core::ffi::c_int { |
| 131 | + // SAFETY: We never drop this, and the DRM core ensures the device lives |
| 132 | + // while callbacks are being called. |
| 133 | + // |
| 134 | + // FIXME: Currently there is nothing enforcing that the types of the |
| 135 | + // dev/file match the current driver these ioctls are being declared |
| 136 | + // for, and it's not clear how to enforce this within the type system. |
| 137 | + let dev = ::core::mem::ManuallyDrop::new(unsafe { |
| 138 | + $crate::drm::device::Device::from_raw(raw_dev) |
| 139 | + }); |
| 140 | + // SAFETY: This is just the ioctl argument, which hopefully has the right type |
| 141 | + // (we've done our best checking the size). |
| 142 | + let data = unsafe { &mut *(raw_data as *mut $crate::uapi::$struct) }; |
| 143 | + // SAFETY: This is just the DRM file structure |
| 144 | + let file = unsafe { $crate::drm::file::File::from_raw(raw_file_priv) }; |
| 145 | + |
| 146 | + match $func(&*dev, data, &file) { |
| 147 | + Err(e) => e.to_errno(), |
| 148 | + Ok(i) => i.try_into().unwrap_or(ERANGE.to_errno()), |
| 149 | + } |
| 150 | + } |
| 151 | + Some($cmd) |
| 152 | + }, |
| 153 | + flags: $flags, |
| 154 | + name: $crate::c_str!(::core::stringify!($cmd)).as_char_ptr(), |
| 155 | + } |
| 156 | + ),*]; |
| 157 | + ioctls |
| 158 | + }; |
| 159 | + }; |
| 160 | +} |
0 commit comments