use crate::{
bindings, device, devres, drm,
error::{to_result, Result},
prelude::*,
sync::aref::ARef,
};
use macros::vtable;
pub(crate) const FEAT_GEM: u32 = bindings::drm_driver_feature_DRIVER_GEM;
pub struct DriverInfo {
pub major: i32,
pub minor: i32,
pub patchlevel: i32,
pub name: &'static CStr,
pub desc: &'static CStr,
}
pub struct AllocOps {
pub(crate) gem_create_object: Option<
unsafe extern "C" fn(
dev: *mut bindings::drm_device,
size: usize,
) -> *mut bindings::drm_gem_object,
>,
pub(crate) prime_handle_to_fd: Option<
unsafe extern "C" fn(
dev: *mut bindings::drm_device,
file_priv: *mut bindings::drm_file,
handle: u32,
flags: u32,
prime_fd: *mut core::ffi::c_int,
) -> core::ffi::c_int,
>,
pub(crate) prime_fd_to_handle: Option<
unsafe extern "C" fn(
dev: *mut bindings::drm_device,
file_priv: *mut bindings::drm_file,
prime_fd: core::ffi::c_int,
handle: *mut u32,
) -> core::ffi::c_int,
>,
pub(crate) gem_prime_import: Option<
unsafe extern "C" fn(
dev: *mut bindings::drm_device,
dma_buf: *mut bindings::dma_buf,
) -> *mut bindings::drm_gem_object,
>,
pub(crate) gem_prime_import_sg_table: Option<
unsafe extern "C" fn(
dev: *mut bindings::drm_device,
attach: *mut bindings::dma_buf_attachment,
sgt: *mut bindings::sg_table,
) -> *mut bindings::drm_gem_object,
>,
pub(crate) dumb_create: Option<
unsafe extern "C" fn(
file_priv: *mut bindings::drm_file,
dev: *mut bindings::drm_device,
args: *mut bindings::drm_mode_create_dumb,
) -> core::ffi::c_int,
>,
pub(crate) dumb_map_offset: Option<
unsafe extern "C" fn(
file_priv: *mut bindings::drm_file,
dev: *mut bindings::drm_device,
handle: u32,
offset: *mut u64,
) -> core::ffi::c_int,
>,
}
pub trait AllocImpl: super::private::Sealed + drm::gem::IntoGEMObject {
type Driver: drm::Driver;
const ALLOC_OPS: AllocOps;
}
#[vtable]
pub trait Driver {
type Data: Sync + Send;
type Object: AllocImpl;
type File: drm::file::DriverFile;
const INFO: DriverInfo;
const IOCTLS: &'static [drm::ioctl::DrmIoctlDescriptor];
}
pub struct Registration<T: Driver>(ARef<drm::Device<T>>);
impl<T: Driver> Registration<T> {
fn new(drm: &drm::Device<T>, flags: usize) -> Result<Self> {
to_result(unsafe { bindings::drm_dev_register(drm.as_raw(), flags) })?;
Ok(Self(drm.into()))
}
pub fn new_foreign_owned(
drm: &drm::Device<T>,
dev: &device::Device<device::Bound>,
flags: usize,
) -> Result
where
T: 'static,
{
if drm.as_ref().as_raw() != dev.as_raw() {
return Err(EINVAL);
}
let reg = Registration::<T>::new(drm, flags)?;
devres::register(dev, reg, GFP_KERNEL)
}
pub fn device(&self) -> &drm::Device<T> {
&self.0
}
}
unsafe impl<T: Driver> Sync for Registration<T> {}
unsafe impl<T: Driver> Send for Registration<T> {}
impl<T: Driver> Drop for Registration<T> {
fn drop(&mut self) {
unsafe { bindings::drm_dev_unregister(self.0.as_raw()) };
}
}