From: Daniel Almeida <daniel.almeida@collabora.com>
To: wedsonaf@gmail.com, ojeda@kernel.org, mchehab@kernel.org,
hverkuil@xs4all.nl
Cc: Daniel Almeida <daniel.almeida@collabora.com>,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-media@vger.kernel.org, kernel@collabora.com
Subject: [PATCH 2/6] rust: media: add initial videodev2.h abstractions
Date: Thu, 6 Apr 2023 18:56:11 -0300 [thread overview]
Message-ID: <20230406215615.122099-3-daniel.almeida@collabora.com> (raw)
In-Reply-To: <20230406215615.122099-1-daniel.almeida@collabora.com>
Add initial videodev2.h abstractions.
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/bindings/bindings_helper.h | 1 +
rust/kernel/media/v4l2/capabilities.rs | 80 +++++++++++
rust/kernel/media/v4l2/enums.rs | 135 +++++++++++++++++++
rust/kernel/media/v4l2/format.rs | 178 +++++++++++++++++++++++++
rust/kernel/media/v4l2/framesize.rs | 176 ++++++++++++++++++++++++
rust/kernel/media/v4l2/inputs.rs | 104 +++++++++++++++
rust/kernel/media/v4l2/mmap.rs | 81 +++++++++++
rust/kernel/media/v4l2/mod.rs | 7 +
8 files changed, 762 insertions(+)
create mode 100644 rust/kernel/media/v4l2/capabilities.rs
create mode 100644 rust/kernel/media/v4l2/enums.rs
create mode 100644 rust/kernel/media/v4l2/format.rs
create mode 100644 rust/kernel/media/v4l2/framesize.rs
create mode 100644 rust/kernel/media/v4l2/inputs.rs
create mode 100644 rust/kernel/media/v4l2/mmap.rs
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 048bae2197ac..3b3d6fcf110f 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -35,6 +35,7 @@
#include <linux/sysctl.h>
#include <linux/uaccess.h>
#include <linux/uio.h>
+#include <linux/videodev2.h>
/* `bindgen` gets confused at certain things. */
const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;
diff --git a/rust/kernel/media/v4l2/capabilities.rs b/rust/kernel/media/v4l2/capabilities.rs
new file mode 100644
index 000000000000..4abc5728f12d
--- /dev/null
+++ b/rust/kernel/media/v4l2/capabilities.rs
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! V4L2 Capabilities
+//!
+//! Part of the following C header: [`include/linux/videodev2.h`](../../../../include/linux/videodev2.h)
+
+/// Capabilities as defined by `V4L2_CAP_*`.
+#[allow(missing_docs)]
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub enum Capabilities {
+ VideoCapture = bindings::V4L2_CAP_VIDEO_CAPTURE as isize,
+ VideoOutput = bindings::V4L2_CAP_VIDEO_OUTPUT as isize,
+ VideoOverlay = bindings::V4L2_CAP_VIDEO_OVERLAY as isize,
+ VbiCapture = bindings::V4L2_CAP_VBI_CAPTURE as isize,
+ VbiOutput = bindings::V4L2_CAP_VBI_OUTPUT as isize,
+ SlicedVbiCapture = bindings::V4L2_CAP_SLICED_VBI_CAPTURE as isize,
+ SlicedVbiOutput = bindings::V4L2_CAP_SLICED_VBI_OUTPUT as isize,
+ RdsCapture = bindings::V4L2_CAP_RDS_CAPTURE as isize,
+ VideoOutputOverlay = bindings::V4L2_CAP_VIDEO_OUTPUT_OVERLAY as isize,
+ HwFrequencySeek = bindings::V4L2_CAP_HW_FREQ_SEEK as isize,
+ RdsOutput = bindings::V4L2_CAP_RDS_OUTPUT as isize,
+ VideoCaptureMplane = bindings::V4L2_CAP_VIDEO_CAPTURE_MPLANE as isize,
+ VideoOutputMplane = bindings::V4L2_CAP_VIDEO_OUTPUT_MPLANE as isize,
+ M2mMplane = bindings::V4L2_CAP_VIDEO_M2M_MPLANE as isize,
+ M2m = bindings::V4L2_CAP_VIDEO_M2M as isize,
+ Tuner = bindings::V4L2_CAP_TUNER as isize,
+ Audio = bindings::V4L2_CAP_AUDIO as isize,
+ Radio = bindings::V4L2_CAP_RADIO as isize,
+ Modulator = bindings::V4L2_CAP_MODULATOR as isize,
+ SdrCapture = bindings::V4L2_CAP_SDR_CAPTURE as isize,
+ ExtPixFormat = bindings::V4L2_CAP_EXT_PIX_FORMAT as isize,
+ SdrOutput = bindings::V4L2_CAP_SDR_OUTPUT as isize,
+ MetaCapture = bindings::V4L2_CAP_META_CAPTURE as isize,
+ ReadWrite = bindings::V4L2_CAP_READWRITE as isize,
+ Streaming = bindings::V4L2_CAP_STREAMING as isize,
+ MetaOutput = bindings::V4L2_CAP_META_OUTPUT as isize,
+ Touch = bindings::V4L2_CAP_TOUCH as isize,
+ IoMc = bindings::V4L2_CAP_IO_MC as isize,
+}
+
+/// A wrapper over a pointer to `struct v4l2_capability`.
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub struct CapabilitiesRef(*mut bindings::v4l2_capability);
+
+impl CapabilitiesRef {
+ /// # Safety
+ /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+ /// returned [`CapabilitiesRef`] instance.
+ pub unsafe fn from_ptr(ptr: *mut bindings::v4l2_capability) -> Self {
+ Self(ptr)
+ }
+
+ // For internal convenience only.
+ fn as_mut(&mut self) -> &mut bindings::v4l2_capability {
+ // SAFETY: ptr is safe during the lifetime of [`CapabilitiesRef`] as per
+ // the safety requirement in `from_ptr()`
+ unsafe { self.0.as_mut().unwrap() }
+ }
+
+ /// Sets the `driver` field.
+ pub fn set_driver(&mut self, driver: &[u8]) {
+ let this = self.as_mut();
+ let len = core::cmp::min(driver.len(), this.driver.len());
+ this.driver[0..len].copy_from_slice(&driver[0..len]);
+ }
+
+ /// Sets the `card` field.
+ pub fn set_card(&mut self, card: &[u8]) {
+ let this = self.as_mut();
+ let len = core::cmp::min(card.len(), this.card.len());
+ this.card[0..len].copy_from_slice(&card[0..len]);
+ }
+
+ /// Sets the `bus_info` field.
+ pub fn set_bus_info(&mut self, bus_info: &[u8]) {
+ let this = self.as_mut();
+ let len = core::cmp::min(bus_info.len(), this.bus_info.len());
+ this.bus_info[0..len].copy_from_slice(&bus_info[0..len]);
+ }
+}
diff --git a/rust/kernel/media/v4l2/enums.rs b/rust/kernel/media/v4l2/enums.rs
new file mode 100644
index 000000000000..41397693c208
--- /dev/null
+++ b/rust/kernel/media/v4l2/enums.rs
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! V4L2 Enums
+//!
+//! Part of the following C header: [`include/linux/videodev2.h`](../../../../include/linux/videodev2.h)
+
+use crate::prelude::EINVAL;
+
+/// Buffer types as defined by `V4L2_BUF_TYPE_*`
+#[allow(missing_docs)]
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub enum BufType {
+ VideoCapture = bindings::v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_CAPTURE as isize,
+ VideoOutput = bindings::v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT as isize,
+ VideoOverlay = bindings::v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OVERLAY as isize,
+ VbiCapture = bindings::v4l2_buf_type_V4L2_BUF_TYPE_VBI_CAPTURE as isize,
+ VbiOutput = bindings::v4l2_buf_type_V4L2_BUF_TYPE_VBI_OUTPUT as isize,
+ SlicedVbiCapture = bindings::v4l2_buf_type_V4L2_BUF_TYPE_SLICED_VBI_CAPTURE as isize,
+ SlicedVbiOutput = bindings::v4l2_buf_type_V4L2_BUF_TYPE_SLICED_VBI_OUTPUT as isize,
+ VideoOutputOverlay = bindings::v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY as isize,
+ VideoCaptureMplane = bindings::v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE as isize,
+ VideoOutputMplane = bindings::v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE as isize,
+ SdrCapture = bindings::v4l2_buf_type_V4L2_BUF_TYPE_SDR_CAPTURE as isize,
+ SdrOutput = bindings::v4l2_buf_type_V4L2_BUF_TYPE_SDR_OUTPUT as isize,
+ MetaCapture = bindings::v4l2_buf_type_V4L2_BUF_TYPE_META_CAPTURE as isize,
+ MetaOutput = bindings::v4l2_buf_type_V4L2_BUF_TYPE_META_OUTPUT as isize,
+}
+
+impl TryFrom<u32> for BufType {
+ type Error = crate::error::Error;
+
+ fn try_from(value: u32) -> Result<Self, Self::Error> {
+ match value {
+ bindings::v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_CAPTURE => Ok(Self::VideoCapture),
+ bindings::v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT => Ok(Self::VideoOutput),
+ bindings::v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OVERLAY => Ok(Self::VideoOverlay),
+ bindings::v4l2_buf_type_V4L2_BUF_TYPE_VBI_CAPTURE => Ok(Self::VbiCapture),
+ bindings::v4l2_buf_type_V4L2_BUF_TYPE_VBI_OUTPUT => Ok(Self::VbiOutput),
+ bindings::v4l2_buf_type_V4L2_BUF_TYPE_SLICED_VBI_CAPTURE => Ok(Self::SlicedVbiCapture),
+ bindings::v4l2_buf_type_V4L2_BUF_TYPE_SLICED_VBI_OUTPUT => Ok(Self::SlicedVbiOutput),
+ bindings::v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY => {
+ Ok(Self::VideoOutputOverlay)
+ }
+ bindings::v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE => {
+ Ok(Self::VideoCaptureMplane)
+ }
+ bindings::v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE => {
+ Ok(Self::VideoOutputMplane)
+ }
+ bindings::v4l2_buf_type_V4L2_BUF_TYPE_SDR_CAPTURE => Ok(Self::SdrCapture),
+ bindings::v4l2_buf_type_V4L2_BUF_TYPE_SDR_OUTPUT => Ok(Self::SdrOutput),
+ bindings::v4l2_buf_type_V4L2_BUF_TYPE_META_CAPTURE => Ok(Self::MetaCapture),
+ bindings::v4l2_buf_type_V4L2_BUF_TYPE_META_OUTPUT => Ok(Self::MetaOutput),
+ _ => Err(EINVAL),
+ }
+ }
+}
+
+/// Fields as defined by `V4L2_FIELD_*`
+#[allow(missing_docs)]
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub enum Field {
+ Any = bindings::v4l2_field_V4L2_FIELD_ANY as isize,
+ None = bindings::v4l2_field_V4L2_FIELD_NONE as isize,
+ Top = bindings::v4l2_field_V4L2_FIELD_TOP as isize,
+ Bottom = bindings::v4l2_field_V4L2_FIELD_BOTTOM as isize,
+ Interlaced = bindings::v4l2_field_V4L2_FIELD_INTERLACED as isize,
+ SeqTb = bindings::v4l2_field_V4L2_FIELD_SEQ_TB as isize,
+ SeqBt = bindings::v4l2_field_V4L2_FIELD_SEQ_BT as isize,
+ Alternate = bindings::v4l2_field_V4L2_FIELD_ALTERNATE as isize,
+ InterlacedTb = bindings::v4l2_field_V4L2_FIELD_INTERLACED_TB as isize,
+ InterlacedBt = bindings::v4l2_field_V4L2_FIELD_INTERLACED_BT as isize,
+}
+
+impl TryFrom<u32> for Field {
+ type Error = crate::error::Error;
+
+ fn try_from(value: u32) -> Result<Self, Self::Error> {
+ match value {
+ bindings::v4l2_field_V4L2_FIELD_ANY => Ok(Self::Any),
+ bindings::v4l2_field_V4L2_FIELD_NONE => Ok(Self::None),
+ bindings::v4l2_field_V4L2_FIELD_TOP => Ok(Self::Top),
+ bindings::v4l2_field_V4L2_FIELD_BOTTOM => Ok(Self::Bottom),
+ bindings::v4l2_field_V4L2_FIELD_INTERLACED => Ok(Self::Interlaced),
+ bindings::v4l2_field_V4L2_FIELD_SEQ_TB => Ok(Self::SeqTb),
+ bindings::v4l2_field_V4L2_FIELD_SEQ_BT => Ok(Self::SeqBt),
+ bindings::v4l2_field_V4L2_FIELD_ALTERNATE => Ok(Self::Alternate),
+ bindings::v4l2_field_V4L2_FIELD_INTERLACED_TB => Ok(Self::InterlacedTb),
+ bindings::v4l2_field_V4L2_FIELD_INTERLACED_BT => Ok(Self::InterlacedBt),
+ _ => Err(EINVAL),
+ }
+ }
+}
+
+/// Colorspaces as defined by `V4L2_COLORSPACE_*`
+#[allow(missing_docs)]
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub enum Colorspace {
+ Default = bindings::v4l2_colorspace_V4L2_COLORSPACE_DEFAULT as isize,
+ Smpte170m = bindings::v4l2_colorspace_V4L2_COLORSPACE_SMPTE170M as isize,
+ Smpte240m = bindings::v4l2_colorspace_V4L2_COLORSPACE_SMPTE240M as isize,
+ Rec709 = bindings::v4l2_colorspace_V4L2_COLORSPACE_REC709 as isize,
+ Bt878 = bindings::v4l2_colorspace_V4L2_COLORSPACE_BT878 as isize,
+ SystemM470 = bindings::v4l2_colorspace_V4L2_COLORSPACE_470_SYSTEM_M as isize,
+ SystemBg470 = bindings::v4l2_colorspace_V4L2_COLORSPACE_470_SYSTEM_BG as isize,
+ Jpeg = bindings::v4l2_colorspace_V4L2_COLORSPACE_JPEG as isize,
+ Srgb = bindings::v4l2_colorspace_V4L2_COLORSPACE_SRGB as isize,
+ Oprgb = bindings::v4l2_colorspace_V4L2_COLORSPACE_OPRGB as isize,
+ Bt2020 = bindings::v4l2_colorspace_V4L2_COLORSPACE_BT2020 as isize,
+ Raw = bindings::v4l2_colorspace_V4L2_COLORSPACE_RAW as isize,
+ DciP3 = bindings::v4l2_colorspace_V4L2_COLORSPACE_DCI_P3 as isize,
+}
+
+impl TryFrom<u32> for Colorspace {
+ type Error = crate::error::Error;
+
+ fn try_from(value: u32) -> Result<Self, Self::Error> {
+ match value {
+ bindings::v4l2_colorspace_V4L2_COLORSPACE_DEFAULT => Ok(Self::Default),
+ bindings::v4l2_colorspace_V4L2_COLORSPACE_SMPTE170M => Ok(Self::Smpte170m),
+ bindings::v4l2_colorspace_V4L2_COLORSPACE_SMPTE240M => Ok(Self::Smpte240m),
+ bindings::v4l2_colorspace_V4L2_COLORSPACE_REC709 => Ok(Self::Rec709),
+ bindings::v4l2_colorspace_V4L2_COLORSPACE_BT878 => Ok(Self::Bt878),
+ bindings::v4l2_colorspace_V4L2_COLORSPACE_470_SYSTEM_M => Ok(Self::SystemM470),
+ bindings::v4l2_colorspace_V4L2_COLORSPACE_470_SYSTEM_BG => Ok(Self::SystemBg470),
+ bindings::v4l2_colorspace_V4L2_COLORSPACE_JPEG => Ok(Self::Jpeg),
+ bindings::v4l2_colorspace_V4L2_COLORSPACE_SRGB => Ok(Self::Srgb),
+ bindings::v4l2_colorspace_V4L2_COLORSPACE_OPRGB => Ok(Self::Oprgb),
+ bindings::v4l2_colorspace_V4L2_COLORSPACE_BT2020 => Ok(Self::Bt2020),
+ bindings::v4l2_colorspace_V4L2_COLORSPACE_RAW => Ok(Self::Raw),
+ bindings::v4l2_colorspace_V4L2_COLORSPACE_DCI_P3 => Ok(Self::DciP3),
+ _ => Err(EINVAL),
+ }
+ }
+}
diff --git a/rust/kernel/media/v4l2/format.rs b/rust/kernel/media/v4l2/format.rs
new file mode 100644
index 000000000000..83bdd61b5c09
--- /dev/null
+++ b/rust/kernel/media/v4l2/format.rs
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! V4L2 Format Enumerations
+//!
+//! Part of the following C header: [`include/linux/videodev2.h`](../../../../include/linux/videodev2.h)
+
+use crate::media::v4l2::enums;
+use crate::prelude::*;
+
+/// A wrapper over a pointer to `struct v4l2_fmtdesc`.
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub struct FormatDescRef(*mut bindings::v4l2_fmtdesc);
+
+impl FormatDescRef {
+ /// # Safety
+ /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+ /// returned [`FormatDescRef`] instance.
+ pub unsafe fn from_ptr(ptr: *mut bindings::v4l2_fmtdesc) -> Self {
+ Self(ptr)
+ }
+
+ fn as_mut(&mut self) -> &mut bindings::v4l2_fmtdesc {
+ // SAFETY: ptr is safe during the lifetime of [`FormatDescRef`] as per
+ // the safety requirement in `from_ptr()`
+ unsafe { self.0.as_mut().unwrap() }
+ }
+
+ fn as_ref(&self) -> &bindings::v4l2_fmtdesc {
+ // SAFETY: ptr is safe during the lifetime of [`FormatDescRef`] as per
+ // the safety requirement in `from_ptr()`
+ unsafe { self.0.as_mut().unwrap() }
+ }
+
+ /// Sets the `pixelformat` field.
+ pub fn set_pixel_format(&mut self, pixel_format: u32) {
+ let fmt = self.as_mut();
+ fmt.pixelformat = pixel_format;
+ }
+
+ /// Returns the `index` field.
+ pub fn index(&self) -> u32 {
+ self.as_ref().index
+ }
+
+ /// Returns the `type_` field.
+ pub fn type_(&self) -> u32 {
+ self.as_ref().type_
+ }
+}
+
+/// A wrapper over a pointer to `struct v4l2_format`.
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub struct FormatRef(*mut bindings::v4l2_format);
+
+impl FormatRef {
+ /// # Safety
+ /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+ /// returned [`FormatRef`] instance.
+ pub unsafe fn from_ptr(ptr: *mut bindings::v4l2_format) -> Self {
+ Self(ptr)
+ }
+
+ // For internal convenience only.
+ fn as_mut(&mut self) -> &mut bindings::v4l2_format {
+ // SAFETY: ptr is safe during the lifetime of [`FormatDescRef`] as per
+ // the safety requirement in `from_ptr()`
+ unsafe { self.0.as_mut().unwrap() }
+ }
+
+ fn as_ref(&self) -> &bindings::v4l2_format {
+ // SAFETY: ptr is safe during the lifetime of [`FormatDescRef`] as per
+ // the safety requirement in `from_ptr()`
+ unsafe { self.0.as_mut().unwrap() }
+ }
+
+ /// Returns the `type_` field.
+ pub fn type_(&self) -> u32 {
+ self.as_ref().type_
+ }
+
+ /// Get the field `field` for the `pix` union member.
+ pub fn pix_field(&self) -> Result<enums::Field> {
+ let fmt = self.as_ref();
+ let pix = &unsafe { fmt.fmt.pix };
+ enums::Field::try_from(pix.field)
+ }
+
+ /// Get the field `width` for the `pix` union member.
+ pub fn pix_width(&self) -> u32 {
+ let fmt = self.as_ref();
+ let pix = &unsafe { fmt.fmt.pix };
+ pix.width
+ }
+
+ /// Get the field `height` for the `pix` union member.
+ pub fn pix_height(&self) -> u32 {
+ let fmt = self.as_ref();
+ let pix = &unsafe { fmt.fmt.pix };
+ pix.height
+ }
+
+ /// Get the field `pixelformat` for the `pix` union member.
+ pub fn pix_pixelformat(&self) -> u32 {
+ let fmt = self.as_ref();
+ let pix = &unsafe { fmt.fmt.pix };
+ pix.pixelformat
+ }
+
+ /// Get the field `bytesperline` for the `pix` union member.
+ pub fn pix_bytesperline(&self) -> u32 {
+ let fmt = self.as_ref();
+ let pix = &unsafe { fmt.fmt.pix };
+ pix.bytesperline
+ }
+
+ /// Get the field `sizeimage` for the `pix` union member.
+ pub fn pix_sizeimage(&self) -> u32 {
+ let fmt = self.as_ref();
+ let pix = &unsafe { fmt.fmt.pix };
+ pix.sizeimage
+ }
+
+ /// Get the field `colorspace` for the `pix` union member.
+ pub fn pix_colorspace(&self) -> Result<enums::Colorspace> {
+ let fmt = self.as_ref();
+ let pix = &unsafe { fmt.fmt.pix };
+ enums::Colorspace::try_from(pix.colorspace)
+ }
+
+ /// Set the field `field` for the `pix` union member.
+ pub fn set_pix_field(&mut self, field: enums::Field) {
+ let fmt = self.as_mut();
+ let pix = &mut unsafe { fmt.fmt.pix };
+ pix.field = field as u32;
+ }
+
+ /// Set the field `width` for the `pix` union member.
+ pub fn set_pix_width(&mut self, width: u32) {
+ let fmt = self.as_mut();
+ let pix = &mut unsafe { fmt.fmt.pix };
+ pix.width = width;
+ }
+
+ /// Set the field `height` for the `pix` union member.
+ pub fn set_pix_height(&mut self, height: u32) {
+ let fmt = self.as_mut();
+ let pix = &mut unsafe { fmt.fmt.pix };
+ pix.height = height;
+ }
+
+ /// Set the field `pixelformat` for the `pix` union member.
+ pub fn set_pix_pixel_format(&mut self, pixel_format: u32) {
+ let fmt = self.as_mut();
+ let pix = &mut unsafe { fmt.fmt.pix };
+ pix.pixelformat = pixel_format;
+ }
+
+ /// Set the field `bytesperline` for the `pix` union member.
+ pub fn set_pix_bytesperline(&mut self, bytesperline: u32) {
+ let fmt = self.as_mut();
+ let pix = &mut unsafe { fmt.fmt.pix };
+ pix.bytesperline = bytesperline;
+ }
+
+ /// Set the field `sizeimage` for the `pix` union member.
+ pub fn set_pix_sizeimage(&mut self, sizeimage: u32) {
+ let fmt = self.as_mut();
+ let pix = &mut unsafe { fmt.fmt.pix };
+ pix.sizeimage = sizeimage;
+ }
+
+ /// Set the field `sizeimage` for the `pix` union member.
+ pub fn set_pix_colorspace(&mut self, colorspace: enums::Colorspace) {
+ let fmt = self.as_mut();
+ let pix = &mut unsafe { fmt.fmt.pix };
+ pix.colorspace = colorspace as u32;
+ }
+}
diff --git a/rust/kernel/media/v4l2/framesize.rs b/rust/kernel/media/v4l2/framesize.rs
new file mode 100644
index 000000000000..2d015a7444be
--- /dev/null
+++ b/rust/kernel/media/v4l2/framesize.rs
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! V4L2 Frame size enumerations
+//!
+//! Part of the following C header: [`include/linux/videodev2.h`](../../../../include/linux/videodev2.h)
+
+/// Frame size types as defined in `V4L2_FRMSIZE_TYPE`
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+#[allow(missing_docs)]
+pub enum FrameSizeType {
+ Discrete = bindings::v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_DISCRETE as isize,
+ Continuous = bindings::v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_CONTINUOUS as isize,
+ Stepwise = bindings::v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_STEPWISE as isize,
+}
+
+impl TryFrom<u32> for FrameSizeType {
+ type Error = crate::error::Error;
+
+ fn try_from(value: u32) -> Result<Self, Self::Error> {
+ match value {
+ bindings::v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_DISCRETE => Ok(Self::Discrete),
+ bindings::v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_CONTINUOUS => Ok(Self::Continuous),
+ bindings::v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_STEPWISE => Ok(Self::Stepwise),
+ _ => Err(crate::prelude::EINVAL),
+ }
+ }
+}
+
+/// A wrapper over a pointer to `struct v4l2_frmsizeenum`.
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub struct FrameSizeRef(*mut bindings::v4l2_frmsizeenum);
+
+impl FrameSizeRef {
+ /// # Safety
+ /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+ /// returned [`FrameSizeRef`] instance.
+ pub unsafe fn from_ptr(ptr: *mut bindings::v4l2_frmsizeenum) -> Self {
+ Self(ptr)
+ }
+
+ fn as_ref(&self) -> &bindings::v4l2_frmsizeenum {
+ // SAFETY: ptr is safe during the lifetime of [`FrameSizeRef`] as per
+ // the safety requirement in `from_ptr()`
+ unsafe { self.0.as_ref().unwrap() }
+ }
+
+ fn as_mut(&mut self) -> &mut bindings::v4l2_frmsizeenum {
+ // SAFETY: ptr is safe during the lifetime of [`FrameSizeRef`] as per
+ // the safety requirement in `from_ptr()`
+ unsafe { self.0.as_mut().unwrap() }
+ }
+
+ /// Sets the `index` member.
+ pub fn set_index(&mut self, index: u32) {
+ let this = self.as_mut();
+ this.index = index;
+ }
+
+ /// Sets the `pixel_format` member.
+ pub fn set_pixel_format(&mut self, pixel_format: u32) {
+ let this = self.as_mut();
+ this.pixel_format = pixel_format;
+ }
+
+ /// Sets the `type_` member.
+ pub fn set_type(&mut self, type_: FrameSizeType) {
+ let this = self.as_mut();
+ this.type_ = type_ as _;
+ }
+
+ /// Sets the `width` member from the `discrete` union member.
+ pub fn set_discrete_width(&mut self, width: u32) {
+ let this = self.as_mut();
+ this.__bindgen_anon_1.discrete.width = width;
+ }
+
+ /// Sets the `height` member from the `discrete` union member.
+ pub fn set_discrete_height(&mut self, height: u32) {
+ let this = self.as_mut();
+ this.__bindgen_anon_1.discrete.height = height;
+ }
+
+ /// Sets the `min_width` member from the `step_wise` union member.
+ pub fn set_stepwise_min_width(&mut self, min_width: u32) {
+ let this = self.as_mut();
+ this.__bindgen_anon_1.stepwise.min_width = min_width;
+ }
+
+ /// Sets the `max_width` member from the `step_wise` union member.
+ pub fn set_stepwise_max_width(&mut self, max_width: u32) {
+ let this = self.as_mut();
+ this.__bindgen_anon_1.stepwise.max_width = max_width;
+ }
+
+ /// Sets the `step_width` member from the `step_wise` union member.
+ pub fn set_stepwise_step_width(&mut self, step_width: u32) {
+ let this = self.as_mut();
+ this.__bindgen_anon_1.stepwise.step_width = step_width;
+ }
+
+ /// Sets the `min_height` member from the `step_wise` union member.
+ pub fn set_stepwise_min_height(&mut self, min_height: u32) {
+ let this = self.as_mut();
+ this.__bindgen_anon_1.stepwise.min_height = min_height;
+ }
+
+ /// Sets the `max_height` member from the `step_wise` union member.
+ pub fn set_stepwise_max_height(&mut self, max_height: u32) {
+ let this = self.as_mut();
+ this.__bindgen_anon_1.stepwise.max_height = max_height;
+ }
+
+ /// Sets the `step_height` member from the `step_wise` union member.
+ pub fn set_stepwise_step_height(&mut self, step_height: u32) {
+ let this = self.as_mut();
+ this.__bindgen_anon_1.stepwise.step_height = step_height;
+ }
+
+ /// Returns the `index` member.
+ pub fn index(&self) -> u32 {
+ self.as_ref().index
+ }
+
+ /// Returns the `pixel_format` member.
+ pub fn pixel_format(&self) -> u32 {
+ self.as_ref().pixel_format
+ }
+
+ /// Returns the `width` member from the `discrete` union member.
+ pub fn discrete_width(&self) -> u32 {
+ let this = self.as_ref();
+ unsafe { this.__bindgen_anon_1.discrete.width }
+ }
+
+ /// Returns the `height` member from the `discrete` union member.
+ pub fn discrete_height(&self) -> u32 {
+ let this = self.as_ref();
+ unsafe { this.__bindgen_anon_1.discrete.height }
+ }
+
+ /// Returns the `min_width` member from the `step_wise` union member.
+ pub fn stepwise_min_width(&self) -> u32 {
+ let this = self.as_ref();
+ unsafe { this.__bindgen_anon_1.stepwise.min_width }
+ }
+
+ /// Returns the `max_width` member from the `step_wise` union member.
+ pub fn stepwise_max_width(&self) -> u32 {
+ let this = self.as_ref();
+ unsafe { this.__bindgen_anon_1.stepwise.max_width }
+ }
+
+ /// Returns the `step_width` member from the `step_wise` union member.
+ pub fn stepwise_step_width(&self) -> u32 {
+ let this = self.as_ref();
+ unsafe { this.__bindgen_anon_1.stepwise.step_width }
+ }
+
+ /// Returns the `min_height` member from the `step_wise` union member.
+ pub fn stepwise_min_height(&self) -> u32 {
+ let this = self.as_ref();
+ unsafe { this.__bindgen_anon_1.stepwise.min_height }
+ }
+
+ /// Returns the `max_height` member from the `step_wise` union member.
+ pub fn stepwise_max_height(&self) -> u32 {
+ let this = self.as_ref();
+ unsafe { this.__bindgen_anon_1.stepwise.max_height }
+ }
+
+ /// Returns the `step_height` member from the `step_wise` union member.
+ pub fn stepwise_step_height(&self) -> u32 {
+ let this = self.as_ref();
+ unsafe { this.__bindgen_anon_1.stepwise.step_height }
+ }
+}
diff --git a/rust/kernel/media/v4l2/inputs.rs b/rust/kernel/media/v4l2/inputs.rs
new file mode 100644
index 000000000000..8361971e2983
--- /dev/null
+++ b/rust/kernel/media/v4l2/inputs.rs
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! V4L2 Video Inputs
+//!
+//! Part of the following C header: [`include/linux/videodev2.h`](../../../../include/linux/videodev2.h)
+
+use crate::prelude::*;
+use crate::str::CStr;
+
+/// A wrapper over a pointer to `struct v4l2_input`.
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub struct InputRef(*mut bindings::v4l2_input);
+
+impl InputRef {
+ /// # Safety
+ /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+ /// returned [`InputRef`] instance.
+ pub unsafe fn from_ptr(ptr: *mut bindings::v4l2_input) -> Self {
+ Self(ptr)
+ }
+
+ fn as_mut(&mut self) -> &mut bindings::v4l2_input {
+ // SAFETY: ptr is safe during the lifetime of [`InputRef`] as per
+ // the safety requirement in `from_ptr()`
+ unsafe { self.0.as_mut().unwrap() }
+ }
+
+ fn as_ref(&self) -> &bindings::v4l2_input {
+ // SAFETY: ptr is safe during the lifetime of [`InputRef`] as per
+ // the safety requirement in `from_ptr()`
+ unsafe { self.0.as_ref().unwrap() }
+ }
+
+ /// Returns the `index` member.
+ pub fn index(&self) -> u32 {
+ let this = self.as_ref();
+ this.index
+ }
+
+ /// Returns the `name` member.
+ pub fn name(&self) -> core::result::Result<&CStr, crate::str::CStrConvertError> {
+ let this = self.as_ref();
+ CStr::from_bytes_with_nul(&this.name)
+ }
+
+ /// Returns the `type_` member.
+ pub fn type_(&self) -> Result<Type> {
+ let this = self.as_ref();
+ Type::try_from(this.type_)
+ }
+
+ /// Returns the `status` member.
+ pub fn status(&self) -> u32 {
+ let this = self.as_ref();
+ this.status
+ }
+
+ /// Sets the `name` member.
+ pub fn set_name(&mut self, name: &CStr) {
+ let this = self.as_mut();
+ let len = core::cmp::min(name.len(), this.name.len());
+ this.name[0..len].copy_from_slice(&name[0..len]);
+ }
+
+ /// Sets the `type_` member.
+ pub fn set_type(&mut self, type_: Type) {
+ let this = self.as_mut();
+ this.type_ = type_ as u32;
+ }
+
+ /// Sets the `std` member.
+ pub fn set_std(&mut self, std: u64) {
+ let this = self.as_mut();
+ this.std = std;
+ }
+
+ /// Sets the `status` member.
+ pub fn set_status(&mut self, status: u32) {
+ let this = self.as_mut();
+ this.status = status;
+ }
+}
+
+/// Input types as defined by `V4L2_INPUT_TYPE_*`
+#[allow(missing_docs)]
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub enum Type {
+ Tuner = bindings::V4L2_INPUT_TYPE_TUNER as isize,
+ Camera = bindings::V4L2_INPUT_TYPE_CAMERA as isize,
+ Touch = bindings::V4L2_INPUT_TYPE_TOUCH as isize,
+}
+
+impl TryFrom<u32> for Type {
+ type Error = crate::error::Error;
+
+ fn try_from(value: u32) -> Result<Self> {
+ match value {
+ bindings::V4L2_INPUT_TYPE_TUNER => Ok(Self::Tuner),
+ bindings::V4L2_INPUT_TYPE_CAMERA => Ok(Self::Camera),
+ bindings::V4L2_INPUT_TYPE_TOUCH => Ok(Self::Touch),
+ _ => Err(EINVAL),
+ }
+ }
+}
diff --git a/rust/kernel/media/v4l2/mmap.rs b/rust/kernel/media/v4l2/mmap.rs
new file mode 100644
index 000000000000..2d9ce2ceb148
--- /dev/null
+++ b/rust/kernel/media/v4l2/mmap.rs
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! V4L2 Memory-mapping buffers
+//!
+//! Part of the following C header: [`include/linux/videodev2.h`](../../../../include/linux/videodev2.h)
+
+/// Buffer flags as defined by `V4L2_BUF_FLAG_*`.
+#[allow(missing_docs)]
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub enum BufferFlag {
+ Mapped = bindings::V4L2_BUF_FLAG_MAPPED as isize,
+ Queued = bindings::V4L2_BUF_FLAG_QUEUED as isize,
+ Done = bindings::V4L2_BUF_FLAG_DONE as isize,
+ Keyframe = bindings::V4L2_BUF_FLAG_KEYFRAME as isize,
+ Pframe = bindings::V4L2_BUF_FLAG_PFRAME as isize,
+ Bframe = bindings::V4L2_BUF_FLAG_BFRAME as isize,
+ Error = bindings::V4L2_BUF_FLAG_ERROR as isize,
+ InRequest = bindings::V4L2_BUF_FLAG_IN_REQUEST as isize,
+ Timecode = bindings::V4L2_BUF_FLAG_TIMECODE as isize,
+ HoldCaptureBuf = bindings::V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF as isize,
+ Prepared = bindings::V4L2_BUF_FLAG_PREPARED as isize,
+ NoCacheInvalidate = bindings::V4L2_BUF_FLAG_NO_CACHE_INVALIDATE as isize,
+ NoCacheClean = bindings::V4L2_BUF_FLAG_NO_CACHE_CLEAN as isize,
+ TimestampMonotonic = bindings::V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC as isize,
+ TimestampCopy = bindings::V4L2_BUF_FLAG_TIMESTAMP_COPY as isize,
+ TstampSrcSoe = bindings::V4L2_BUF_FLAG_TSTAMP_SRC_SOE as isize,
+ Last = bindings::V4L2_BUF_FLAG_LAST as isize,
+ RequestFd = bindings::V4L2_BUF_FLAG_REQUEST_FD as isize,
+}
+
+/// A wrapper over a pointer to `struct v4l2_exportbuffer`.
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub struct ExportBufferRef(*mut bindings::v4l2_exportbuffer);
+
+impl ExportBufferRef {
+ /// # Safety
+ /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+ /// returned [`ExportBufferRef`] instance.
+ pub unsafe fn from_ptr(ptr: *mut bindings::v4l2_exportbuffer) -> Self {
+ Self(ptr)
+ }
+}
+
+/// A wrapper over a pointer to `struct v4l2_requestbuffers`.
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub struct RequestBuffersRef(*mut bindings::v4l2_requestbuffers);
+
+impl RequestBuffersRef {
+ /// # Safety
+ /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+ /// returned [`RequestBuffersRef`] instance.
+ pub unsafe fn from_ptr(ptr: *mut bindings::v4l2_requestbuffers) -> Self {
+ Self(ptr)
+ }
+}
+
+/// A wrapper over a pointer to `struct v4l2_create_buffers`.
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub struct CreateBuffersRef(*mut bindings::v4l2_create_buffers);
+
+impl CreateBuffersRef {
+ /// # Safety
+ /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+ /// returned [`CreateBuffersRef`] instance.
+ pub unsafe fn from_ptr(ptr: *mut bindings::v4l2_create_buffers) -> Self {
+ Self(ptr)
+ }
+}
+
+/// A wrapper over a pointer to `struct v4l2_buffer`.
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub struct BufferRef(*mut bindings::v4l2_buffer);
+
+impl BufferRef {
+ /// # Safety
+ /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
+ /// returned [`BufferRef`] instance.
+ pub unsafe fn from_ptr(ptr: *mut bindings::v4l2_buffer) -> Self {
+ Self(ptr)
+ }
+}
diff --git a/rust/kernel/media/v4l2/mod.rs b/rust/kernel/media/v4l2/mod.rs
index 068dd9b4863d..77864640f19e 100644
--- a/rust/kernel/media/v4l2/mod.rs
+++ b/rust/kernel/media/v4l2/mod.rs
@@ -1,3 +1,10 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
//! Abstractions for include/media/v4l2-*.h
+
+pub mod capabilities;
+pub mod enums;
+pub mod format;
+pub mod framesize;
+pub mod inputs;
+pub mod mmap;
--
2.40.0
next prev parent reply other threads:[~2023-04-06 21:58 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-04-06 21:56 [PATCH 0/6] Initial Rust V4L2 support Daniel Almeida
2023-04-06 21:56 ` [PATCH 1/6] rust: media: add the media module Daniel Almeida
2023-04-06 21:56 ` Daniel Almeida [this message]
2023-04-06 21:56 ` [PATCH 3/6] rust: sync: introduce FfiMutex Daniel Almeida
2023-04-06 21:56 ` [PATCH 4/6] rust: media: videobuf2: add a videobuf2 abstraction Daniel Almeida
2023-04-06 21:56 ` [PATCH 5/6] rust: media: add {video|v4l2}_device_register support Daniel Almeida
2023-04-06 21:56 ` [PATCH 6/6] rust: media: add v4l2 rust sample Daniel Almeida
2023-04-08 19:06 ` [PATCH 0/6] Initial Rust V4L2 support Daniel Almeida
2023-04-08 19:43 ` Hans Petter Selasky
2023-04-09 14:10 ` Daniel Almeida
2023-04-10 18:59 ` Hans Petter Selasky
2023-04-10 23:41 ` Miguel Ojeda
2023-04-11 9:52 ` Hans Petter Selasky
2023-04-11 12:36 ` Miguel Ojeda
2023-04-11 13:15 ` Hans Petter Selasky
2023-04-11 14:19 ` Miguel Ojeda
2023-04-11 15:33 ` Hans Petter Selasky
2023-04-11 19:22 ` Miguel Ojeda
2023-04-12 10:00 ` Hans Petter Selasky
2023-04-12 10:13 ` Greg KH
2023-04-12 10:23 ` Hans Petter Selasky
2023-04-10 23:40 ` Miguel Ojeda
2023-04-26 14:31 ` Enrico Weigelt, metux IT consult
2023-04-10 22:46 ` Deborah Brouwer
2023-04-11 14:22 ` Miguel Ojeda
2023-04-12 2:58 ` Theodore Ts'o
2023-04-12 12:21 ` Miguel Ojeda
2023-04-12 12:38 ` Morten Linderud
2023-04-12 18:44 ` Nicolas Dufresne
[not found] ` <aae753d6-6874-4f91-e7ba-bd6c77f07b62@metux.net>
2023-04-26 15:33 ` Miguel Ojeda
2023-04-11 7:51 ` Hans Verkuil
2023-04-11 12:02 ` Miguel Ojeda
2023-04-11 12:49 ` Willy Tarreau
2023-04-11 14:01 ` Daniel Almeida
2023-04-11 14:13 ` Miguel Ojeda
2023-04-11 16:52 ` Willy Tarreau
2023-04-11 19:27 ` Miguel Ojeda
2023-04-11 20:26 ` Willy Tarreau
2023-04-11 22:14 ` Miguel Ojeda
[not found] ` <0da49a77-14d8-cb9d-e36d-985699746b6b@metux.net>
2023-04-26 16:05 ` Miguel Ojeda
2023-04-26 0:32 ` Laurent Pinchart
[not found] ` <57ec90ad-8535-fa7d-d6de-d5c1d06f37d3@metux.net>
2023-04-26 13:29 ` Laurent Pinchart
2023-04-26 16:18 ` Miguel Ojeda
2023-04-26 16:35 ` Laurent Pinchart
2023-04-26 17:14 ` Daniel Almeida
2023-04-26 17:25 ` Laurent Pinchart
2023-05-01 20:10 ` Nicolas Dufresne
2023-05-01 20:17 ` Asahi Lina
2023-05-01 20:19 ` Nicolas Dufresne
2023-05-02 19:13 ` Miguel Ojeda
2023-05-03 11:00 ` Daniel Almeida
2023-04-26 19:58 ` Sakari Ailus
2023-07-05 6:40 ` Hans Verkuil
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230406215615.122099-3-daniel.almeida@collabora.com \
--to=daniel.almeida@collabora.com \
--cc=hverkuil@xs4all.nl \
--cc=kernel@collabora.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=wedsonaf@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox