|
4 | 4 | //! |
5 | 5 | //! C header: [`include/linux/drm/drm_device.h`](../../../../include/linux/drm/drm_device.h) |
6 | 6 |
|
7 | | -use crate::{bindings, device, drm, types::ForeignOwnable}; |
| 7 | +use crate::{ |
| 8 | + bindings, device, drm, |
| 9 | + types::{ARef, AlwaysRefCounted, ForeignOwnable}, |
| 10 | +}; |
| 11 | +use core::cell::UnsafeCell; |
8 | 12 | use core::marker::PhantomData; |
| 13 | +use core::ptr::NonNull; |
9 | 14 |
|
10 | | -/// Represents a reference to a DRM device. The device is reference-counted and is guaranteed to |
11 | | -/// not be dropped while this object is alive. |
| 15 | +/// A typed DRM device with a specific driver. The device is always reference-counted. |
| 16 | +#[repr(transparent)] |
12 | 17 | pub struct Device<T: drm::drv::Driver> { |
13 | | - // Type invariant: ptr must be a valid and initialized drm_device, |
14 | | - // and this value must either own a reference to it or the caller |
15 | | - // must ensure that it is never dropped if the reference is borrowed. |
16 | | - pub(super) ptr: *mut bindings::drm_device, |
| 18 | + pub(super) drm: UnsafeCell<bindings::drm_device>, |
17 | 19 | _p: PhantomData<T>, |
18 | 20 | } |
19 | 21 |
|
20 | 22 | impl<T: drm::drv::Driver> Device<T> { |
21 | | - // Not intended to be called externally, except via declare_drm_ioctls!() |
22 | | - #[doc(hidden)] |
23 | | - pub unsafe fn from_raw(raw: *mut bindings::drm_device) -> Device<T> { |
24 | | - Device { |
25 | | - ptr: raw, |
26 | | - _p: PhantomData, |
27 | | - } |
28 | | - } |
29 | | - |
30 | | - #[allow(dead_code)] |
31 | | - pub(crate) fn raw(&self) -> *const bindings::drm_device { |
32 | | - self.ptr |
| 23 | + #[allow(dead_code, clippy::mut_from_ref)] |
| 24 | + pub(crate) unsafe fn raw_mut(&self) -> &mut bindings::drm_device { |
| 25 | + unsafe { &mut *self.drm.get() } |
33 | 26 | } |
34 | 27 |
|
35 | | - pub(crate) fn raw_mut(&mut self) -> *mut bindings::drm_device { |
36 | | - self.ptr |
| 28 | + // Not intended to be called externally, except via declare_drm_ioctls!() |
| 29 | + #[doc(hidden)] |
| 30 | + pub unsafe fn borrow<'a>(raw: *const bindings::drm_device) -> &'a Self { |
| 31 | + unsafe { &*(raw as *const Self) } |
37 | 32 | } |
38 | 33 |
|
39 | 34 | /// Returns a borrowed reference to the user data associated with this Device. |
40 | 35 | pub fn data(&self) -> <T::Data as ForeignOwnable>::Borrowed<'_> { |
41 | | - unsafe { T::Data::borrow((*self.ptr).dev_private) } |
| 36 | + // SAFETY: dev_private is guaranteed to be initialized for all |
| 37 | + // Device objects exposed to users. |
| 38 | + unsafe { T::Data::borrow((*self.drm.get()).dev_private) } |
42 | 39 | } |
43 | 40 | } |
44 | 41 |
|
45 | | -impl<T: drm::drv::Driver> Drop for Device<T> { |
46 | | - fn drop(&mut self) { |
47 | | - // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to |
48 | | - // relinquish it now. |
49 | | - unsafe { bindings::drm_dev_put(self.ptr) }; |
| 42 | +// SAFETY: DRM device objects are always reference counted and the get/put functions |
| 43 | +// satisfy the requirements. |
| 44 | +unsafe impl<T: drm::drv::Driver> AlwaysRefCounted for Device<T> { |
| 45 | + fn inc_ref(&self) { |
| 46 | + unsafe { bindings::drm_dev_get(&self.drm as *const _ as *mut _) }; |
50 | 47 | } |
51 | | -} |
52 | 48 |
|
53 | | -impl<T: drm::drv::Driver> Clone for Device<T> { |
54 | | - fn clone(&self) -> Self { |
55 | | - // SAFETY: We get a new reference and then create a new owning object from the raw pointer |
56 | | - unsafe { |
57 | | - bindings::drm_dev_get(self.ptr); |
58 | | - Device::from_raw(self.ptr) |
59 | | - } |
| 49 | + unsafe fn dec_ref(obj: NonNull<Self>) { |
| 50 | + // SAFETY: The Device<T> type has the same layout as drm_device, |
| 51 | + // so we can just cast. |
| 52 | + unsafe { bindings::drm_dev_put(obj.as_ptr() as *mut _) }; |
60 | 53 | } |
61 | 54 | } |
62 | 55 |
|
63 | 56 | // SAFETY: `Device` only holds a pointer to a C device, which is safe to be used from any thread. |
64 | | -unsafe impl<T: drm::drv::Driver> Send for Device<T> {} |
| 57 | +unsafe impl<T: drm::drv::Driver> Send for ARef<Device<T>> {} |
65 | 58 |
|
66 | 59 | // SAFETY: `Device` only holds a pointer to a C device, references to which are safe to be used |
67 | 60 | // from any thread. |
68 | | -unsafe impl<T: drm::drv::Driver> Sync for Device<T> {} |
| 61 | +unsafe impl<T: drm::drv::Driver> Sync for ARef<Device<T>> {} |
69 | 62 |
|
70 | 63 | // Make drm::Device work for dev_info!() and friends |
71 | 64 | unsafe impl<T: drm::drv::Driver> device::RawDevice for Device<T> { |
72 | 65 | fn raw_device(&self) -> *mut bindings::device { |
73 | | - // SAFETY: ptr must be valid per the type invariant |
74 | | - unsafe { (*self.ptr).dev } |
| 66 | + // SAFETY: dev is initialized by C for all Device objects |
| 67 | + unsafe { (*self.drm.get()).dev } |
75 | 68 | } |
76 | 69 | } |
0 commit comments