1use crate::{
8 alloc::flags::*,
9 bindings, drm,
10 drm::driver::{AllocImpl, AllocOps},
11 error::{to_result, Result},
12 prelude::*,
13 sync::aref::{ARef, AlwaysRefCounted},
14 types::Opaque,
15};
16use core::{ops::Deref, ptr::NonNull};
17
18pub type DriverFile<T> = drm::File<<<T as DriverObject>::Driver as drm::Driver>::File>;
24
25pub trait DriverObject: Sync + Send + Sized {
27 type Driver: drm::Driver;
29
30 fn new(dev: &drm::Device<Self::Driver>, size: usize) -> impl PinInit<Self, Error>;
32
33 fn open(_obj: &<Self::Driver as drm::Driver>::Object, _file: &DriverFile<Self>) -> Result {
35 Ok(())
36 }
37
38 fn close(_obj: &<Self::Driver as drm::Driver>::Object, _file: &DriverFile<Self>) {}
40}
41
42pub trait IntoGEMObject: Sized + super::private::Sealed + AlwaysRefCounted {
44 fn as_raw(&self) -> *mut bindings::drm_gem_object;
47
48 unsafe fn from_raw<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self;
56}
57
58unsafe impl<T: IntoGEMObject> AlwaysRefCounted for T {
60 fn inc_ref(&self) {
61 unsafe { bindings::drm_gem_object_get(self.as_raw()) };
63 }
64
65 unsafe fn dec_ref(obj: NonNull<Self>) {
66 let obj = unsafe { obj.as_ref() }.as_raw();
70
71 unsafe { bindings::drm_gem_object_put(obj) };
75 }
76}
77
78extern "C" fn open_callback<T: DriverObject>(
79 raw_obj: *mut bindings::drm_gem_object,
80 raw_file: *mut bindings::drm_file,
81) -> core::ffi::c_int {
82 let file = unsafe { DriverFile::<T>::from_raw(raw_file) };
84
85 let obj = unsafe { <<T::Driver as drm::Driver>::Object as IntoGEMObject>::from_raw(raw_obj) };
88
89 match T::open(obj, file) {
90 Err(e) => e.to_errno(),
91 Ok(()) => 0,
92 }
93}
94
95extern "C" fn close_callback<T: DriverObject>(
96 raw_obj: *mut bindings::drm_gem_object,
97 raw_file: *mut bindings::drm_file,
98) {
99 let file = unsafe { DriverFile::<T>::from_raw(raw_file) };
101
102 let obj = unsafe { <<T::Driver as drm::Driver>::Object as IntoGEMObject>::from_raw(raw_obj) };
105
106 T::close(obj, file);
107}
108
109impl<T: DriverObject> IntoGEMObject for Object<T> {
110 fn as_raw(&self) -> *mut bindings::drm_gem_object {
111 self.obj.get()
112 }
113
114 unsafe fn from_raw<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self {
115 unsafe { &*crate::container_of!(Opaque::cast_from(self_ptr), Object<T>, obj) }
118 }
119}
120
121pub trait BaseObject: IntoGEMObject {
123 fn size(&self) -> usize {
125 unsafe { (*self.as_raw()).size }
127 }
128
129 fn create_handle<D, F>(&self, file: &drm::File<F>) -> Result<u32>
132 where
133 Self: AllocImpl<Driver = D>,
134 D: drm::Driver<Object = Self, File = F>,
135 F: drm::file::DriverFile<Driver = D>,
136 {
137 let mut handle: u32 = 0;
138 to_result(unsafe {
140 bindings::drm_gem_handle_create(file.as_raw().cast(), self.as_raw(), &mut handle)
141 })?;
142 Ok(handle)
143 }
144
145 fn lookup_handle<D, F>(file: &drm::File<F>, handle: u32) -> Result<ARef<Self>>
147 where
148 Self: AllocImpl<Driver = D>,
149 D: drm::Driver<Object = Self, File = F>,
150 F: drm::file::DriverFile<Driver = D>,
151 {
152 let ptr = unsafe { bindings::drm_gem_object_lookup(file.as_raw().cast(), handle) };
154 if ptr.is_null() {
155 return Err(ENOENT);
156 }
157
158 let obj = unsafe { Self::from_raw(ptr) };
165
166 Ok(unsafe { ARef::from_raw(obj.into()) })
171 }
172
173 fn create_mmap_offset(&self) -> Result<u64> {
175 to_result(unsafe { bindings::drm_gem_create_mmap_offset(self.as_raw()) })?;
177
178 Ok(unsafe { bindings::drm_vma_node_offset_addr(&raw mut (*self.as_raw()).vma_node) })
180 }
181}
182
183impl<T: IntoGEMObject> BaseObject for T {}
184
185#[repr(C)]
192#[pin_data]
193pub struct Object<T: DriverObject + Send + Sync> {
194 obj: Opaque<bindings::drm_gem_object>,
195 dev: NonNull<drm::Device<T::Driver>>,
196 #[pin]
197 data: T,
198}
199
200impl<T: DriverObject> Object<T> {
201 const OBJECT_FUNCS: bindings::drm_gem_object_funcs = bindings::drm_gem_object_funcs {
202 free: Some(Self::free_callback),
203 open: Some(open_callback::<T>),
204 close: Some(close_callback::<T>),
205 print_info: None,
206 export: None,
207 pin: None,
208 unpin: None,
209 get_sg_table: None,
210 vmap: None,
211 vunmap: None,
212 mmap: None,
213 status: None,
214 vm_ops: core::ptr::null_mut(),
215 evict: None,
216 rss: None,
217 };
218
219 pub fn new(dev: &drm::Device<T::Driver>, size: usize) -> Result<ARef<Self>> {
221 let obj: Pin<KBox<Self>> = KBox::pin_init(
222 try_pin_init!(Self {
223 obj: Opaque::new(bindings::drm_gem_object::default()),
224 data <- T::new(dev, size),
225 dev: dev.into(),
228 }),
229 GFP_KERNEL,
230 )?;
231
232 unsafe { (*obj.as_raw()).funcs = &Self::OBJECT_FUNCS };
234
235 to_result(unsafe { bindings::drm_gem_object_init(dev.as_raw(), obj.obj.get(), size) })?;
237
238 let ptr = KBox::into_raw(unsafe { Pin::into_inner_unchecked(obj) });
240
241 let ptr = unsafe { NonNull::new_unchecked(ptr) };
243
244 Ok(unsafe { ARef::from_raw(ptr) })
246 }
247
248 pub fn dev(&self) -> &drm::Device<T::Driver> {
250 unsafe { self.dev.as_ref() }
253 }
254
255 fn as_raw(&self) -> *mut bindings::drm_gem_object {
256 self.obj.get()
257 }
258
259 extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) {
260 let ptr: *mut Opaque<bindings::drm_gem_object> = obj.cast();
261
262 let this = unsafe { crate::container_of!(ptr, Self, obj) };
264
265 unsafe { bindings::drm_gem_object_release(obj) };
268
269 let _ = unsafe { KBox::from_raw(this) };
273 }
274}
275
276impl<T: DriverObject> super::private::Sealed for Object<T> {}
277
278impl<T: DriverObject> Deref for Object<T> {
279 type Target = T;
280
281 fn deref(&self) -> &Self::Target {
282 &self.data
283 }
284}
285
286impl<T: DriverObject> AllocImpl for Object<T> {
287 type Driver = T::Driver;
288
289 const ALLOC_OPS: AllocOps = AllocOps {
290 gem_create_object: None,
291 prime_handle_to_fd: None,
292 prime_fd_to_handle: None,
293 gem_prime_import: None,
294 gem_prime_import_sg_table: None,
295 dumb_create: None,
296 dumb_map_offset: None,
297 };
298}
299
300pub(super) const fn create_fops() -> bindings::file_operations {
301 let mut fops: bindings::file_operations = unsafe { core::mem::zeroed() };
304
305 fops.owner = core::ptr::null_mut();
306 fops.open = Some(bindings::drm_open);
307 fops.release = Some(bindings::drm_release);
308 fops.unlocked_ioctl = Some(bindings::drm_ioctl);
309 #[cfg(CONFIG_COMPAT)]
310 {
311 fops.compat_ioctl = Some(bindings::drm_compat_ioctl);
312 }
313 fops.poll = Some(bindings::drm_poll);
314 fops.read = Some(bindings::drm_read);
315 fops.llseek = Some(bindings::noop_llseek);
316 fops.mmap = Some(bindings::drm_gem_mmap);
317 fops.fop_flags = bindings::FOP_UNSIGNED_OFFSET;
318
319 fops
320}