1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 3 //! DRM driver core. 4 //! 5 //! C header: [`include/drm/drm_drv.h`](srctree/include/drm/drm_drv.h) 6 7 use crate::{ 8 bindings, 9 device, 10 devres, 11 drm, 12 error::{ 13 to_result, 14 Result, // 15 }, 16 prelude::*, 17 sync::aref::ARef, // 18 }; 19 use macros::vtable; 20 21 /// Driver use the GEM memory manager. This should be set for all modern drivers. 22 pub(crate) const FEAT_GEM: u32 = bindings::drm_driver_feature_DRIVER_GEM; 23 24 /// Information data for a DRM Driver. 25 pub struct DriverInfo { 26 /// Driver major version. 27 pub major: i32, 28 /// Driver minor version. 29 pub minor: i32, 30 /// Driver patchlevel version. 31 pub patchlevel: i32, 32 /// Driver name. 33 pub name: &'static CStr, 34 /// Driver description. 35 pub desc: &'static CStr, 36 } 37 38 /// Internal memory management operation set, normally created by memory managers (e.g. GEM). 39 pub struct AllocOps { 40 pub(crate) gem_create_object: Option< 41 unsafe extern "C" fn( 42 dev: *mut bindings::drm_device, 43 size: usize, 44 ) -> *mut bindings::drm_gem_object, 45 >, 46 pub(crate) prime_handle_to_fd: Option< 47 unsafe extern "C" fn( 48 dev: *mut bindings::drm_device, 49 file_priv: *mut bindings::drm_file, 50 handle: u32, 51 flags: u32, 52 prime_fd: *mut core::ffi::c_int, 53 ) -> core::ffi::c_int, 54 >, 55 pub(crate) prime_fd_to_handle: Option< 56 unsafe extern "C" fn( 57 dev: *mut bindings::drm_device, 58 file_priv: *mut bindings::drm_file, 59 prime_fd: core::ffi::c_int, 60 handle: *mut u32, 61 ) -> core::ffi::c_int, 62 >, 63 pub(crate) gem_prime_import: Option< 64 unsafe extern "C" fn( 65 dev: *mut bindings::drm_device, 66 dma_buf: *mut bindings::dma_buf, 67 ) -> *mut bindings::drm_gem_object, 68 >, 69 pub(crate) gem_prime_import_sg_table: Option< 70 unsafe extern "C" fn( 71 dev: *mut bindings::drm_device, 72 attach: *mut bindings::dma_buf_attachment, 73 sgt: *mut bindings::sg_table, 74 ) -> *mut bindings::drm_gem_object, 75 >, 76 pub(crate) dumb_create: Option< 77 unsafe extern "C" fn( 78 file_priv: *mut bindings::drm_file, 79 dev: *mut bindings::drm_device, 80 args: *mut bindings::drm_mode_create_dumb, 81 ) -> core::ffi::c_int, 82 >, 83 pub(crate) dumb_map_offset: Option< 84 unsafe extern "C" fn( 85 file_priv: *mut bindings::drm_file, 86 dev: *mut bindings::drm_device, 87 handle: u32, 88 offset: *mut u64, 89 ) -> core::ffi::c_int, 90 >, 91 } 92 93 /// Trait for memory manager implementations. Implemented internally. 94 pub trait AllocImpl: super::private::Sealed + drm::gem::IntoGEMObject { 95 /// The [`Driver`] implementation for this [`AllocImpl`]. 96 type Driver: drm::Driver; 97 98 /// The C callback operations for this memory manager. 99 const ALLOC_OPS: AllocOps; 100 } 101 102 /// The DRM `Driver` trait. 103 /// 104 /// This trait must be implemented by drivers in order to create a `struct drm_device` and `struct 105 /// drm_driver` to be registered in the DRM subsystem. 106 #[vtable] 107 pub trait Driver { 108 /// Context data associated with the DRM driver 109 type Data: Sync + Send; 110 111 /// The type used to manage memory for this driver. 112 type Object: AllocImpl; 113 114 /// The type used to represent a DRM File (client) 115 type File: drm::file::DriverFile; 116 117 /// Driver metadata 118 const INFO: DriverInfo; 119 120 /// IOCTL list. See `kernel::drm::ioctl::declare_drm_ioctls!{}`. 121 const IOCTLS: &'static [drm::ioctl::DrmIoctlDescriptor]; 122 } 123 124 /// The registration type of a `drm::Device`. 125 /// 126 /// Once the `Registration` structure is dropped, the device is unregistered. 127 pub struct Registration<T: Driver>(ARef<drm::Device<T>>); 128 129 impl<T: Driver> Registration<T> { 130 fn new(drm: &drm::Device<T>, flags: usize) -> Result<Self> { 131 // SAFETY: `drm.as_raw()` is valid by the invariants of `drm::Device`. 132 to_result(unsafe { bindings::drm_dev_register(drm.as_raw(), flags) })?; 133 134 Ok(Self(drm.into())) 135 } 136 137 /// Registers a new [`Device`](drm::Device) with userspace. 138 /// 139 /// Ownership of the [`Registration`] object is passed to [`devres::register`]. 140 pub fn new_foreign_owned( 141 drm: &drm::Device<T>, 142 dev: &device::Device<device::Bound>, 143 flags: usize, 144 ) -> Result 145 where 146 T: 'static, 147 { 148 if drm.as_ref().as_raw() != dev.as_raw() { 149 return Err(EINVAL); 150 } 151 152 let reg = Registration::<T>::new(drm, flags)?; 153 154 devres::register(dev, reg, GFP_KERNEL) 155 } 156 157 /// Returns a reference to the `Device` instance for this registration. 158 pub fn device(&self) -> &drm::Device<T> { 159 &self.0 160 } 161 } 162 163 // SAFETY: `Registration` doesn't offer any methods or access to fields when shared between 164 // threads, hence it's safe to share it. 165 unsafe impl<T: Driver> Sync for Registration<T> {} 166 167 // SAFETY: Registration with and unregistration from the DRM subsystem can happen from any thread. 168 unsafe impl<T: Driver> Send for Registration<T> {} 169 170 impl<T: Driver> Drop for Registration<T> { 171 fn drop(&mut self) { 172 // SAFETY: Safe by the invariant of `ARef<drm::Device<T>>`. The existence of this 173 // `Registration` also guarantees the this `drm::Device` is actually registered. 174 unsafe { bindings::drm_dev_unregister(self.0.as_raw()) }; 175 } 176 } 177