diff --git a/rust/kernel/drm/kms/plane.rs b/rust/kernel/drm/kms/plane.rs index d3d8b9f6d5c8d4f08a9e541580cee8a1a422b880..9eea0f4fe0c42690503fd556a890d3c6bf316811 100644 --- a/rust/kernel/drm/kms/plane.rs +++ b/rust/kernel/drm/kms/plane.rs @@ -22,6 +22,7 @@ use core::{ ptr::{self, null, null_mut, NonNull}, marker::*, ops::*, + iter, }; use macros::pin_data; use super::{ @@ -150,6 +151,10 @@ pub struct DriverPlaneOps { /// An enumerator describing a type of [`Plane`]. /// /// This is mainly just relevant for DRM legacy drivers. +/// +/// # Invariants +/// +/// This type is identical to `drm_plane_type`. pub enum PlaneType { /// Overlay planes represent all non-primary, non-cursor planes. Some drivers refer to these /// types of planes as "sprites" internally. @@ -210,11 +215,11 @@ impl<T: DriverPlane> Plane<T> { /// [`Plane`] objects. /// /// [`KmsDriver::create_objects`]: kernel::drm::kms::KmsDriver::create_objects - pub fn new<'a, 'b: 'a, const FMT_COUNT: usize, const MOD_COUNT: usize>( + pub fn new<'a, 'b: 'a>( dev: &'a UnregisteredKmsDevice<'a, T::Driver>, possible_crtcs: u32, - formats: &'static FormatList<FMT_COUNT>, - format_modifiers: Option<&'static ModifierList<MOD_COUNT>>, + formats: &[u32], + format_modifiers: Option<&[u64]>, type_: PlaneType, name: Option<&CStr>, args: T::Args, @@ -231,7 +236,31 @@ impl<T: DriverPlane> Plane<T> { GFP_KERNEL )?; - // SAFETY: FFI call with no special requirements + // TODO: Move this over to using collect() someday + // Create a modifiers array with the sentinel for passing to DRM + let format_modifiers_raw; + if let Some(modifiers) = format_modifiers { + let mut raw = KVec::with_capacity(modifiers.len() + 1, GFP_KERNEL)?; + for modifier in modifiers { + raw.push(*modifier, GFP_KERNEL)?; + } + raw.push(bindings::DRM_FORMAT_MOD_INVALID, GFP_KERNEL)?; + + format_modifiers_raw = Some(raw); + } else { + format_modifiers_raw = None; + } + + // SAFETY: + // - We just allocated `this`, and we won't move it since it's pinned + // - We just allocated the `format_modifiers_raw` vec and added the sentinel DRM expects + // above + // - `drm_universal_plane_init` will memcpy() the following parameters into its own storage, + // so it's safe for them to become inaccessible after this call returns: + // - `formats` + // - `format_modifiers_raw` + // - `name` + // - `type_` is equivalent to `drm_plane_type` via its type invariants. to_result(unsafe { bindings::drm_universal_plane_init( dev.as_raw(), @@ -239,8 +268,8 @@ impl<T: DriverPlane> Plane<T> { possible_crtcs, &T::OPS.funcs, formats.as_ptr(), - formats.raw_len() as _, - format_modifiers.map_or(null(), |f| f.as_ptr()), + formats.len() as _, + format_modifiers_raw.map_or(null(), |f| f.as_ptr()), type_ as _, name.map_or(null(), |n| n.as_char_ptr()) )