@@ -10,11 +10,13 @@ use crate::{
1010 alloc:: flags:: * ,
1111 bindings, drm,
1212 drm:: driver:: { AllocImpl , AllocOps } ,
13+ dma_buf,
1314 error:: { to_result, Result } ,
1415 prelude:: * ,
1516 sync:: aref:: { ARef , AlwaysRefCounted } ,
1617 types:: Opaque ,
1718} ;
19+ use core:: marker:: PhantomData ;
1820use core:: { ops:: Deref , ptr:: NonNull } ;
1921
2022/// A macro for implementing [`AlwaysRefCounted`] for any GEM object type.
@@ -62,6 +64,7 @@ pub(crate) use impl_aref_for_gem_obj;
6264pub type DriverFile < T > = drm:: File < <<T as DriverObject >:: Driver as drm:: Driver >:: File > ;
6365
6466/// GEM object functions, which must be implemented by drivers.
67+ #[ vtable]
6568pub trait DriverObject : Sync + Send + Sized {
6669 /// Parent `Driver` for this object.
6770 type Driver : drm:: Driver ;
@@ -83,6 +86,11 @@ pub trait DriverObject: Sync + Send + Sized {
8386
8487 /// Close a handle to an existing object, associated with a File.
8588 fn close ( _obj : & <Self :: Driver as drm:: Driver >:: Object , _file : & DriverFile < Self > ) { }
89+
90+ /// Optional handle for exporting a gem object.
91+ fn export ( _obj : & <Self :: Driver as drm:: Driver >:: Object , _flags : u32 ) -> Result < DmaBuf < <Self :: Driver as drm:: Driver >:: Object > > {
92+ unimplemented ! ( )
93+ }
8694}
8795
8896/// Trait that represents a GEM object subtype
@@ -132,6 +140,21 @@ extern "C" fn close_callback<T: DriverObject>(
132140 T :: close ( obj, file) ;
133141}
134142
143+ extern "C" fn export_callback < T : DriverObject > (
144+ raw_obj : * mut bindings:: drm_gem_object ,
145+ flags : i32 ,
146+ ) -> * mut bindings:: dma_buf {
147+ // SAFETY: `export_callback` is specified in the AllocOps structure for `Object<T>`, ensuring
148+ // that `raw_obj` is contained within a `Object<T>`.
149+ let obj = unsafe { <<T :: Driver as drm:: Driver >:: Object as IntoGEMObject >:: from_raw ( raw_obj) } ;
150+
151+ match T :: export ( obj, flags as _ ) {
152+ // DRM takes a hold of the reference
153+ Ok ( buf) => buf. into_raw ( ) ,
154+ Err ( e) => e. to_ptr ( ) ,
155+ }
156+ }
157+
135158impl < T : DriverObject > IntoGEMObject for Object < T > {
136159 fn as_raw ( & self ) -> * mut bindings:: drm_gem_object {
137160 self . obj . get ( )
@@ -238,7 +261,11 @@ impl<T: DriverObject> Object<T> {
238261 open : Some ( open_callback :: < T > ) ,
239262 close : Some ( close_callback :: < T > ) ,
240263 print_info : None ,
241- export : None ,
264+ export : if T :: HAS_EXPORT {
265+ Some ( export_callback :: < T > )
266+ } else {
267+ None
268+ } ,
242269 pin : None ,
243270 unpin : None ,
244271 get_sg_table : None ,
@@ -335,6 +362,49 @@ impl<T: DriverObject> AllocImpl for Object<T> {
335362 } ;
336363}
337364
365+ /// A [`dma_buf::DmaBuf`] which has been exported from a GEM object.
366+ ///
367+ /// The [`dma_buf::DmaBuf`] will be released when this type is dropped.
368+ ///
369+ /// # Invariants
370+ ///
371+ /// - `self.0` points to a valid initialized [`dma_buf::DmaBuf`] for the lifetime of this object.
372+ /// - The GEM object from which this [`dma_buf::DmaBuf`] was exported from is guaranteed to be of
373+ /// type `T`.
374+ pub struct DmaBuf < T : IntoGEMObject > ( NonNull < dma_buf:: DmaBuf > , PhantomData < T > ) ;
375+
376+ impl < T : IntoGEMObject > Deref for DmaBuf < T > {
377+ type Target = dma_buf:: DmaBuf ;
378+
379+ #[ inline]
380+ fn deref ( & self ) -> & Self :: Target {
381+ // SAFETY: This pointer is guaranteed to be valid by our type invariants.
382+ unsafe { self . 0 . as_ref ( ) }
383+ }
384+ }
385+
386+ impl < T : IntoGEMObject > Drop for DmaBuf < T > {
387+ #[ inline]
388+ fn drop ( & mut self ) {
389+ // SAFETY:
390+ // - `dma_buf::DmaBuf` is guaranteed to have an identical layout to `struct dma_buf`
391+ // by its type invariants.
392+ // - We hold the last reference to this `DmaBuf`, making it safe to destroy.
393+ unsafe { bindings:: drm_gem_dmabuf_release ( self . 0 . cast ( ) . as_ptr ( ) ) }
394+ }
395+ }
396+
397+ impl < T : IntoGEMObject > DmaBuf < T > {
398+ /// Leak the reference for this [`DmaBuf`] and return a raw pointer to it.
399+ #[ inline]
400+ pub ( crate ) fn into_raw ( self ) -> * mut bindings:: dma_buf {
401+ let dma_ptr = self . as_raw ( ) ;
402+
403+ core:: mem:: forget ( self ) ;
404+ dma_ptr
405+ }
406+ }
407+
338408pub ( super ) const fn create_fops ( ) -> bindings:: file_operations {
339409 // SAFETY: As by the type invariant, it is safe to initialize `bindings::file_operations`
340410 // zeroed.
0 commit comments