[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.