1use crate::{
8 bindings,
9 drm::{
10 self,
11 device::{
12 DeviceContext,
13 Registered, },
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, Ctx = Registered> =
85 <<T as DriverObject>::Driver as drm::Driver>::Object<Ctx>;
86
87pub trait DriverObject: Sync + Send + Sized {
89 type Driver: drm::Driver;
91
92 type Args;
94
95 fn new<Ctx: DeviceContext>(
97 dev: &drm::Device<Self::Driver, Ctx>,
98 size: usize,
99 args: Self::Args,
100 ) -> impl PinInit<Self, Error>;
101
102 fn open(_obj: &DriverAllocImpl<Self>, _file: &DriverFile<Self>) -> Result {
104 Ok(())
105 }
106
107 fn close(_obj: &DriverAllocImpl<Self>, _file: &DriverFile<Self>) {}
109}
110
111pub trait IntoGEMObject: Sized + super::private::Sealed + AlwaysRefCounted {
113 fn as_raw(&self) -> *mut bindings::drm_gem_object;
116
117 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<Registered> = 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>,
201 D: drm::Driver<Object<Registered> = 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 = Registered> {
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 new(
285 dev: &drm::Device<T::Driver, Ctx>,
286 size: usize,
287 args: T::Args,
288 ) -> Result<ARef<Self>> {
289 let obj: Pin<KBox<Self>> = KBox::pin_init(
290 try_pin_init!(Self {
291 obj: Opaque::new(bindings::drm_gem_object::default()),
292 data <- T::new(dev, size, args),
293 _ctx: PhantomData,
294 }),
295 GFP_KERNEL,
296 )?;
297
298 unsafe { (*obj.as_raw()).funcs = &Self::OBJECT_FUNCS };
300
301 if let Err(err) =
304 to_result(unsafe {
306 bindings::drm_gem_object_init(dev.as_raw(), obj.obj.get(), size)
307 })
308 {
309 unsafe { bindings::drm_gem_private_object_fini(obj.obj.get()) };
312 return Err(err);
313 }
314
315 let ptr = KBox::into_raw(unsafe { Pin::into_inner_unchecked(obj) });
317
318 let ptr = unsafe { NonNull::new_unchecked(ptr) };
320
321 Ok(unsafe { ARef::from_raw(ptr) })
323 }
324
325 pub fn dev(&self) -> &drm::Device<T::Driver, Ctx> {
327 unsafe { drm::Device::from_raw((*self.as_raw()).dev) }
336 }
337
338 fn as_raw(&self) -> *mut bindings::drm_gem_object {
339 self.obj.get()
340 }
341
342 extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) {
343 let ptr: *mut Opaque<bindings::drm_gem_object> = obj.cast();
344
345 let this = unsafe { crate::container_of!(ptr, Self, obj) };
347
348 unsafe { bindings::drm_gem_object_release(obj) };
351
352 let _ = unsafe { KBox::from_raw(this) };
356 }
357}
358
359impl_aref_for_gem_obj! {
360 impl<T, C> for Object<T, C>
361 where
362 T: DriverObject,
363 C: DeviceContext
364}
365
366impl<T: DriverObject, Ctx: DeviceContext> super::private::Sealed for Object<T, Ctx> {}
367
368impl<T: DriverObject, Ctx: DeviceContext> Deref for Object<T, Ctx> {
369 type Target = T;
370
371 fn deref(&self) -> &Self::Target {
372 &self.data
373 }
374}
375
376impl<T: DriverObject, Ctx: DeviceContext> AllocImpl for Object<T, Ctx> {
377 type Driver = T::Driver;
378
379 const ALLOC_OPS: AllocOps = AllocOps {
380 gem_create_object: None,
381 prime_handle_to_fd: None,
382 prime_fd_to_handle: None,
383 gem_prime_import: None,
384 gem_prime_import_sg_table: None,
385 dumb_create: None,
386 dumb_map_offset: None,
387 };
388}
389
390pub(super) const fn create_fops() -> bindings::file_operations {
391 let mut fops: bindings::file_operations = pin_init::zeroed();
392
393 fops.owner = core::ptr::null_mut();
394 fops.open = Some(bindings::drm_open);
395 fops.release = Some(bindings::drm_release);
396 fops.unlocked_ioctl = Some(bindings::drm_ioctl);
397 #[cfg(CONFIG_COMPAT)]
398 {
399 fops.compat_ioctl = Some(bindings::drm_compat_ioctl);
400 }
401 fops.poll = Some(bindings::drm_poll);
402 fops.read = Some(bindings::drm_read);
403 fops.llseek = Some(bindings::noop_llseek);
404 fops.mmap = Some(bindings::drm_gem_mmap);
405 fops.fop_flags = bindings::FOP_UNSIGNED_OFFSET;
406
407 fops
408}