1use crate::{
8 bindings,
9 drm::{
10 self,
11 device::{
12 DeviceContext,
13 Normal, },
15 driver::{
16 AllocImpl,
17 AllocOps, },
19 },
20 error::to_result,
21 prelude::*,
22 sync::aref::{
23 ARef,
24 AlwaysRefCounted, },
26 types::Opaque,
27};
28use core::{
29 marker::PhantomData,
30 ops::Deref,
31 ptr::NonNull, };
33
34#[cfg(CONFIG_RUST_DRM_GEM_SHMEM_HELPER)]
35pub mod shmem;
36
37#[macro_export]
41macro_rules! impl_aref_for_gem_obj {
42 (
43 impl $( <$( $tparam_id:ident ),+> )? for $type:ty
44 $(
45 where
46 $( $bind_param:path : $bind_trait:path ),+
47 )?
48 ) => {
49 unsafe impl $( <$( $tparam_id ),+> )? $crate::sync::aref::AlwaysRefCounted for $type
51 where
52 Self: IntoGEMObject,
53 $( $( $bind_param : $bind_trait ),+ )?
54 {
55 fn inc_ref(&self) {
56 unsafe { bindings::drm_gem_object_get(self.as_raw()) };
59 }
60
61 unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
62 let obj = unsafe { obj.as_ref() }.as_raw();
64
65 unsafe { bindings::drm_gem_object_put(obj) };
67 }
68 }
69 };
70}
71#[cfg_attr(not(CONFIG_RUST_DRM_GEM_SHMEM_HELPER), allow(unused))]
72pub(crate) use impl_aref_for_gem_obj;
73
74pub type DriverFile<T> = drm::File<<<T as DriverObject>::Driver as drm::Driver>::File>;
80
81pub type DriverAllocImpl<T> = <<T as DriverObject>::Driver as drm::Driver>::Object;
85
86pub trait DriverObject: Sync + Send + Sized + 'static {
88 type Driver: drm::Driver;
90
91 type Args;
93
94 fn new(
96 dev: &drm::Device<Self::Driver>,
97 size: usize,
98 args: Self::Args,
99 ) -> impl PinInit<Self, Error>;
100
101 fn open(_obj: &DriverAllocImpl<Self>, _file: &DriverFile<Self>) -> Result {
103 Ok(())
104 }
105
106 fn close(_obj: &DriverAllocImpl<Self>, _file: &DriverFile<Self>) {}
108}
109
110pub trait IntoGEMObject: Sized + super::private::Sealed {
112 fn as_raw(&self) -> *mut bindings::drm_gem_object;
115
116 unsafe fn from_raw<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self;
125}
126
127extern "C" fn open_callback<T: DriverObject>(
128 raw_obj: *mut bindings::drm_gem_object,
129 raw_file: *mut bindings::drm_file,
130) -> core::ffi::c_int {
131 let file = unsafe { DriverFile::<T>::from_raw(raw_file) };
133
134 let obj: &DriverAllocImpl<T> = unsafe { IntoGEMObject::from_raw(raw_obj) };
140
141 match T::open(obj, file) {
142 Err(e) => e.to_errno(),
143 Ok(()) => 0,
144 }
145}
146
147extern "C" fn close_callback<T: DriverObject>(
148 raw_obj: *mut bindings::drm_gem_object,
149 raw_file: *mut bindings::drm_file,
150) {
151 let file = unsafe { DriverFile::<T>::from_raw(raw_file) };
153
154 let obj: &DriverAllocImpl<T> = unsafe { IntoGEMObject::from_raw(raw_obj) };
157
158 T::close(obj, file);
159}
160
161impl<T: DriverObject, Ctx: DeviceContext> IntoGEMObject for Object<T, Ctx> {
162 fn as_raw(&self) -> *mut bindings::drm_gem_object {
163 self.obj.get()
164 }
165
166 unsafe fn from_raw<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self {
167 unsafe { &*crate::container_of!(Opaque::cast_from(self_ptr), Object<T, Ctx>, obj) }
170 }
171}
172
173pub trait BaseObject: IntoGEMObject {
175 fn size(&self) -> usize {
177 unsafe { (*self.as_raw()).size }
179 }
180
181 fn create_handle<D, F>(&self, file: &drm::File<F>) -> Result<u32>
184 where
185 Self: AllocImpl<Driver = D>,
186 D: drm::Driver<Object = Self, File = F>,
187 F: drm::file::DriverFile<Driver = D>,
188 {
189 let mut handle: u32 = 0;
190 to_result(unsafe {
192 bindings::drm_gem_handle_create(file.as_raw().cast(), self.as_raw(), &mut handle)
193 })?;
194 Ok(handle)
195 }
196
197 fn lookup_handle<D, F>(file: &drm::File<F>, handle: u32) -> Result<ARef<Self>>
199 where
200 Self: AllocImpl<Driver = D> + AlwaysRefCounted,
201 D: drm::Driver<Object = Self, File = F>,
202 F: drm::file::DriverFile<Driver = D>,
203 {
204 let ptr = unsafe { bindings::drm_gem_object_lookup(file.as_raw().cast(), handle) };
206 if ptr.is_null() {
207 return Err(ENOENT);
208 }
209
210 let obj = unsafe { Self::from_raw(ptr) };
217
218 Ok(unsafe { ARef::from_raw(obj.into()) })
223 }
224
225 fn create_mmap_offset(&self) -> Result<u64> {
227 to_result(unsafe { bindings::drm_gem_create_mmap_offset(self.as_raw()) })?;
229
230 Ok(unsafe { bindings::drm_vma_node_offset_addr(&raw mut (*self.as_raw()).vma_node) })
232 }
233}
234
235impl<T: IntoGEMObject> BaseObject for T {}
236
237#[cfg_attr(not(CONFIG_RUST_DRM_GEM_SHMEM_HELPER), expect(unused))]
239pub(crate) trait BaseObjectPrivate: IntoGEMObject {
240 fn raw_dma_resv(&self) -> *mut bindings::dma_resv {
242 unsafe { (*self.as_raw()).resv }
244 }
245}
246
247impl<T: IntoGEMObject> BaseObjectPrivate for T {}
248
249#[repr(C)]
256#[pin_data]
257pub struct Object<T: DriverObject + Send + Sync, Ctx: DeviceContext = Normal> {
258 obj: Opaque<bindings::drm_gem_object>,
259 #[pin]
260 data: T,
261 _ctx: PhantomData<Ctx>,
262}
263
264impl<T: DriverObject, Ctx: DeviceContext> Object<T, Ctx> {
265 const OBJECT_FUNCS: bindings::drm_gem_object_funcs = bindings::drm_gem_object_funcs {
266 free: Some(Self::free_callback),
267 open: Some(open_callback::<T>),
268 close: Some(close_callback::<T>),
269 print_info: None,
270 export: None,
271 pin: None,
272 unpin: None,
273 get_sg_table: None,
274 vmap: None,
275 vunmap: None,
276 mmap: None,
277 status: None,
278 vm_ops: core::ptr::null_mut(),
279 evict: None,
280 rss: None,
281 };
282
283 pub fn dev(&self) -> &drm::Device<T::Driver, Ctx> {
285 unsafe { drm::Device::from_raw((*self.as_raw()).dev) }
294 }
295
296 fn as_raw(&self) -> *mut bindings::drm_gem_object {
297 self.obj.get()
298 }
299
300 extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) {
301 let ptr: *mut Opaque<bindings::drm_gem_object> = obj.cast();
302
303 let this = unsafe { crate::container_of!(ptr, Self, obj) };
305
306 unsafe { bindings::drm_gem_object_release(obj) };
309
310 let _ = unsafe { KBox::from_raw(this) };
314 }
315}
316
317impl<T: DriverObject> Object<T> {
318 pub fn new(dev: &drm::Device<T::Driver>, size: usize, args: T::Args) -> Result<ARef<Self>> {
320 let obj: Pin<KBox<Self>> = KBox::pin_init(
321 try_pin_init!(Self {
322 obj: Opaque::new(bindings::drm_gem_object::default()),
323 data <- T::new(dev, size, args),
324 _ctx: PhantomData,
325 }),
326 GFP_KERNEL,
327 )?;
328
329 unsafe { (*obj.as_raw()).funcs = &Self::OBJECT_FUNCS };
331
332 if let Err(err) =
335 to_result(unsafe {
337 bindings::drm_gem_object_init(dev.as_raw(), obj.obj.get(), size)
338 })
339 {
340 unsafe { bindings::drm_gem_private_object_fini(obj.obj.get()) };
343 return Err(err);
344 }
345
346 let ptr = KBox::into_raw(unsafe { Pin::into_inner_unchecked(obj) });
348
349 let ptr = unsafe { NonNull::new_unchecked(ptr) };
351
352 Ok(unsafe { ARef::from_raw(ptr) })
354 }
355}
356
357impl_aref_for_gem_obj! {
358 impl<T> for Object<T>
359 where
360 T: DriverObject
361}
362
363impl<T: DriverObject, Ctx: DeviceContext> super::private::Sealed for Object<T, Ctx> {}
364
365impl<T: DriverObject, Ctx: DeviceContext> Deref for Object<T, Ctx> {
366 type Target = T;
367
368 fn deref(&self) -> &Self::Target {
369 &self.data
370 }
371}
372
373impl<T: DriverObject, Ctx: DeviceContext> AllocImpl for Object<T, Ctx> {
374 type Driver = T::Driver;
375
376 const ALLOC_OPS: AllocOps = AllocOps {
377 gem_create_object: None,
378 prime_handle_to_fd: None,
379 prime_fd_to_handle: None,
380 gem_prime_import: None,
381 gem_prime_import_sg_table: None,
382 dumb_create: None,
383 dumb_map_offset: None,
384 };
385}
386
387pub(super) const fn create_fops() -> bindings::file_operations {
388 let mut fops: bindings::file_operations = pin_init::zeroed();
389
390 fops.owner = core::ptr::null_mut();
391 fops.open = Some(bindings::drm_open);
392 fops.release = Some(bindings::drm_release);
393 fops.unlocked_ioctl = Some(bindings::drm_ioctl);
394 #[cfg(CONFIG_COMPAT)]
395 {
396 fops.compat_ioctl = Some(bindings::drm_compat_ioctl);
397 }
398 fops.poll = Some(bindings::drm_poll);
399 fops.read = Some(bindings::drm_read);
400 fops.llseek = Some(bindings::noop_llseek);
401 fops.mmap = Some(bindings::drm_gem_mmap);
402 fops.fop_flags = bindings::FOP_UNSIGNED_OFFSET;
403
404 fops
405}