[PATCH v3 17/23] rust: drm: add an owned display mode constructor
Mike Lothian <[email protected]>
| Newsgroups | org.kernel.vger.rust-for-linux,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Add a safe constructor for standalone display modes used by drivers and tests. Accept the essential timing fields and reject invalid active, sync, and total ordering before exposing the owned mode. Assisted-by: Claude:claude-opus-5 Signed-off-by: Mike Lothian <[email protected]> --- rust/kernel/drm/kms/modes.rs | 62 +++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/rust/kernel/drm/kms/modes.rs b/rust/kernel/drm/kms/modes.rs index cc3c486eecf1..b48a02edfc13 100644 --- a/rust/kernel/drm/kms/modes.rs +++ b/rust/kernel/drm/kms/modes.rs @@ -6,7 +6,33 @@ use bindings; -use crate::types::Opaque; +use crate::{ + error::{code::EINVAL, Result}, + types::Opaque, +}; + +/// The essential timing fields of a display mode. +#[derive(Clone, Copy)] +pub struct ModeTimings { + /// Pixel clock in kHz. + pub clock_khz: i32, + /// Horizontal active pixels. + pub hdisplay: u16, + /// Start of the horizontal sync pulse. + pub hsync_start: u16, + /// End of the horizontal sync pulse. + pub hsync_end: u16, + /// Total horizontal pixels including blanking. + pub htotal: u16, + /// Vertical active lines. + pub vdisplay: u16, + /// Start of the vertical sync pulse. + pub vsync_start: u16, + /// End of the vertical sync pulse. + pub vsync_end: u16, + /// Total vertical lines including blanking. + pub vtotal: u16, +} /// DRM kernel-internal display mode structure. /// @@ -30,6 +56,40 @@ unsafe impl Send for DisplayMode {} unsafe impl Sync for DisplayMode {} impl DisplayMode { + /// Creates a standalone display mode from validated timings. + /// + /// This is useful when a driver needs an owned mode for validation or tests rather than a + /// reference to a mode owned by the DRM core. + pub fn from_timings(t: ModeTimings) -> Result<Self> { + if t.clock_khz <= 0 + || t.hdisplay == 0 + || t.hdisplay > t.hsync_start + || t.hsync_start > t.hsync_end + || t.hsync_end > t.htotal + || t.vdisplay == 0 + || t.vdisplay > t.vsync_start + || t.vsync_start > t.vsync_end + || t.vsync_end > t.vtotal + { + return Err(EINVAL); + } + + let mut mode = bindings::drm_display_mode::default(); + mode.clock = t.clock_khz; + mode.hdisplay = t.hdisplay; + mode.hsync_start = t.hsync_start; + mode.hsync_end = t.hsync_end; + mode.htotal = t.htotal; + mode.vdisplay = t.vdisplay; + mode.vsync_start = t.vsync_start; + mode.vsync_end = t.vsync_end; + mode.vtotal = t.vtotal; + + Ok(Self { + inner: Opaque::new(mode), + }) + } + /// Convert a raw pointer to a `struct drm_display_mode` into an immutable [`DisplayMode`] ref. /// /// # SAFETY