Hi Lyude, > On 30 Sep 2024, at 20:09, Lyude Paul <ly...@redhat.com> wrote: > > This is the same thing as OpaqueConnector and OpaqueConnectorState, but for > CRTCs now. > > Signed-off-by: Lyude Paul <ly...@redhat.com> > > --- > > TODO: > * Add upcast functions > > Signed-off-by: Lyude Paul <ly...@redhat.com> > --- > rust/kernel/drm/kms/crtc.rs | 131 ++++++++++++++++++++++++++++++++++++ > 1 file changed, 131 insertions(+) > > diff --git a/rust/kernel/drm/kms/crtc.rs b/rust/kernel/drm/kms/crtc.rs > index d84db49948380..1a3c9c448afcc 100644 > --- a/rust/kernel/drm/kms/crtc.rs > +++ b/rust/kernel/drm/kms/crtc.rs > @@ -234,6 +234,41 @@ pub fn new<'a, 'b: 'a, P, C>( > // SAFETY: We don't move anything > Ok(unsafe { &*Box::into_raw(Pin::into_inner_unchecked(this)) }) > } > + > + /// Attempt to convert an [`OpaqueCrtc`] into a fully qualified [`Crtc`]. > + /// > + /// This checks if the given [`OpaqueCrtc`] uses the same [`DriverCrtc`] > implementation, and > + /// returns the [`OpaqueCrtc`] as a [`Crtc`] object if so. > + pub fn try_from_opaque<'a, D>(opaque: &'a OpaqueCrtc<D>) -> Option<&'a > Self> > + where > + D: KmsDriver, > + T: DriverCrtc<Driver = D> > + { > + // SAFETY: The vtables for a `Crtc` are initialized throughout the > lifetime of the object > + let funcs = unsafe { (*opaque.crtc.get()).funcs }; > + > + // SAFETY: We only perform this transmutation if the opaque CRTC > shares our vtable pointers, > + // so the underlying `Crtc` must share our data layout. > + ptr::eq(funcs, &T::OPS.funcs).then(|| unsafe { > mem::transmute(opaque) }) > + } > + > + /// Convert a [`OpaqueCrtc`] into its fully qualified [`Crtc`]. > + /// > + /// This is an infallible version of [`Self::try_from_opaque`]. This > function is mainly useful > + /// for drivers where only a single [`DriverCrtc`] implementation exists.
I am confused. If a driver has a single `DriverCrtc`, why would it care for `OpaqueCrtc`? > + /// > + /// # Panics > + /// > + /// This function will panic if the underlying CRTC in the provided > [`OpaqueCrtc`] does not > + /// belong to the same [`DriverCrtc`] implementation. > + pub fn from_opaque<'a, D>(opaque: &'a OpaqueCrtc<D>) -> &'a Self > + where > + D: KmsDriver, > + T: DriverCrtc<Driver = D> > + { > + Self::try_from_opaque(opaque) > + .expect("Passed OpaqueCrtc does not share this DriverCrtc > implementation") > + } > } > > /// A trait implemented by any type that acts as a [`struct drm_crtc`] > interface. > @@ -267,6 +302,66 @@ unsafe fn from_raw<'a>(ptr: *mut bindings::drm_crtc) -> > &'a Self { > } > } > > +/// A [`struct drm_crtc`] without a known [`DriverCrtc`] implementation. > +/// > +/// This is mainly for situations where our bindings can't infer the > [`DriverCrtc`] implementation > +/// for a [`struct drm_crtc`] automatically. It is identical to [`Crtc`], > except that it does not > +/// provide access to the driver's private data. > +/// > +/// It may be upcasted to a full [`Crtc`] using [`Crtc::from_opaque`] or > +/// [`Crtc::try_from_opaque`]. > +/// > +/// # Invariants > +/// > +/// - `crtc` is initialized for as long as this object is made available to > users. > +/// - The data layout of this structure is equivalent to [`struct drm_crtc`]. nit: Maybe worth clarifying that it’s equivalent to `bindings::drm_crtc`, not directly to C’s `struct drm_crtc`. Although it should also be equivalent to that in practice. > +/// > +/// [`struct drm_crtc`]: srctree/include/drm/drm_crtc.h > +#[repr(transparent)] > +pub struct OpaqueCrtc<T: KmsDriver> { > + crtc: Opaque<bindings::drm_crtc>, > + _p: PhantomData<T> > +} > + > +impl<T: KmsDriver> Sealed for OpaqueCrtc<T> {} > + > +impl<T: KmsDriver> AsRawCrtc for OpaqueCrtc<T> { > + type State = OpaqueCrtcState<T>; > + > + fn as_raw(&self) -> *mut bindings::drm_crtc { > + self.crtc.get() > + } > + > + unsafe fn from_raw<'a>(ptr: *mut bindings::drm_crtc) -> &'a Self { > + // SAFETY: Our data layout starts with `bindings::drm_crtc` > + unsafe { &*ptr.cast() } > + } > +} > + > +impl<T: KmsDriver> ModeObject for OpaqueCrtc<T> { > + type Driver = T; > + > + fn drm_dev(&self) -> &Device<Self::Driver> { > + // SAFETY: The parent device for a DRM connector will never outlive > the connector, and this > + // pointer is invariant through the lifetime of the connector > + unsafe { Device::borrow((*self.as_raw()).dev) } > + } > + > + fn raw_mode_obj(&self) -> *mut bindings::drm_mode_object { > + // SAFETY: We don't expose DRM connectors to users before `base` is > initialized > + unsafe { addr_of_mut!((*self.as_raw()).base) } > + } > +} > + > +// SAFETY: CRTCs are non-refcounted modesetting objects > +unsafe impl<T: KmsDriver> StaticModeObject for OpaqueCrtc<T> {} > + > +// SAFETY: Our CRTC interface is guaranteed to be thread-safe > +unsafe impl<T: KmsDriver> Send for OpaqueCrtc<T> {} > + > +// SAFETY: Our CRTC interface is guaranteed to be thread-safe > +unsafe impl<T: KmsDriver> Sync for OpaqueCrtc<T> {} > + > unsafe impl Zeroable for bindings::drm_crtc_state { } > > impl<T: DriverCrtcState> Sealed for CrtcState<T> {} > @@ -400,6 +495,42 @@ unsafe fn from_raw<'a>(ptr: *const > bindings::drm_crtc_state) -> &'a Self { > } > } > > +/// A [`struct drm_crtc_state`] without a known [`DriverCrtcState`] > implementation. > +/// > +/// This is mainly for situations where our bindings can't infer the > [`DriverCrtcState`] > +/// implementation for a [`struct drm_crtc_state`] automatically. It is > identical to [`Crtc`], > +/// except that it does not provide access to the driver's private data. > +/// > +/// TODO: Add upcast functions > +/// > +/// # Invariants > +/// > +/// - `state` is initialized for as long as this object is exposed to users. > +/// - The data layout of this type is identical to [`struct drm_crtc_state`]. > +/// > +/// [`struct drm_crtc_state`]: srctree/include/drm/drm_crtc.h > +#[repr(transparent)] > +pub struct OpaqueCrtcState<T: KmsDriver> { > + state: Opaque<bindings::drm_crtc_state>, > + _p: PhantomData<T> > +} > + > +impl<T: KmsDriver> AsRawCrtcState for OpaqueCrtcState<T> { > + type Crtc = OpaqueCrtc<T>; > +} > + > +impl<T: KmsDriver> private::AsRawCrtcState for OpaqueCrtcState<T> { > + fn as_raw(&self) -> *mut bindings::drm_crtc_state { > + self.state.get() > + } > +} > + > +impl<T: KmsDriver> FromRawCrtcState for OpaqueCrtcState<T> { > + unsafe fn from_raw<'a>(ptr: *const bindings::drm_crtc_state) -> &'a Self > { > + // SAFETY: Our data layout is identical to `bindings::drm_crtc_state` > + unsafe { &*(ptr.cast()) } > + } > +} > unsafe extern "C" fn crtc_destroy_callback<T: DriverCrtc>( > crtc: *mut bindings::drm_crtc > ) { > -- > 2.46.1 > > — Daniel