From: Daniel Almeida <daniel.almeida@collabora.com>
To: "Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Alexandre Courbot" <acourbot@nvidia.com>
Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
kernel@collabora.com, linux-media@vger.kernel.org,
Daniel Almeida <daniel.almeida@collabora.com>
Subject: [PATCH 6/7] rust: v4l2: add basic ioctl support
Date: Mon, 18 Aug 2025 02:49:52 -0300 [thread overview]
Message-ID: <20250818-v4l2-v1-6-6887e772aac2@collabora.com> (raw)
In-Reply-To: <20250818-v4l2-v1-0-6887e772aac2@collabora.com>
Most of the v4l2 API is implemented through ioctl(), so adding support
for them is essential in order to be able to write v4l2 drivers.
Hook up ioctl support by filling up an instance of v4l2_ioctl_ops. For
now, we only support the most basic v4l2 ioctl: VIDIOC_QUERYCAPS. This
is used by userspace to retrieve information about the device, and is
considered enough to implement a simple v4l2 sample Rust driver.
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
rust/kernel/media/v4l2/file.rs | 1 -
rust/kernel/media/v4l2/ioctl.rs | 92 +++++++++++++++++++++++++++++++++++++++++
rust/kernel/media/v4l2/mod.rs | 3 ++
rust/kernel/media/v4l2/video.rs | 13 +++++-
4 files changed, 107 insertions(+), 2 deletions(-)
diff --git a/rust/kernel/media/v4l2/file.rs b/rust/kernel/media/v4l2/file.rs
index 37b34f8e6f251fafde5f7e6b4bd654519d8247a5..8817051268323866f41fd56a0c7e8fa4b7537858 100644
--- a/rust/kernel/media/v4l2/file.rs
+++ b/rust/kernel/media/v4l2/file.rs
@@ -50,7 +50,6 @@ impl<T: DriverFile> File<T> {
///
/// - `ptr` must be a valid pointer to a `struct v4l2_file`.
/// - `ptr` must be valid for 'a.
- #[expect(dead_code)]
pub(super) unsafe fn from_raw<'a>(ptr: *mut bindings::v4l2_fh) -> &'a File<T> {
// SAFETY: `ptr` is a valid pointer to a `struct v4l2_file` as per the
// safety requirements of this function.
diff --git a/rust/kernel/media/v4l2/ioctl.rs b/rust/kernel/media/v4l2/ioctl.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e8d20d4cb70f5722c0109ea5bad36041355fc7a1
--- /dev/null
+++ b/rust/kernel/media/v4l2/ioctl.rs
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-copyrightText: Copyright (C) 2025 Collabora Ltd.
+
+//! V4L2 device node ioctl support.
+//!
+//! Most of the V4L2 API is implemented through the ioctl system call. This
+//! module provides support for ioctl operations on V4L2 device nodes.
+
+use core::{marker::PhantomData, mem::MaybeUninit};
+
+use crate::{
+ media::v4l2::{
+ self,
+ video::{self, Driver},
+ },
+ prelude::*,
+};
+
+/// The vtable for the ioctls of a registered Rust [`video::Device`].
+///
+/// # Invariants
+///
+/// - All the callbacks in [`IoctlVtable`] are called after the underlying
+/// [`video::Device`] has been registered.
+pub(super) struct IoctlVtable<T: Driver>(PhantomData<T>);
+
+impl<T: Driver> IoctlVtable<T> {
+ /// # Safety
+ ///
+ /// This should only be called from the ioctl callbacks and the returned
+ /// reference should not outlive the callback itself.
+ unsafe fn data<'a>(file: *mut bindings::file) -> &'a <T as Driver>::Data
+ where
+ T: 'a,
+ {
+ // SAFETY: This was set during the video device registration process.
+ let vdev = unsafe { bindings::video_devdata(file) };
+
+ // SAFETY: `video_device` is a valid pointer to a `struct video_device`
+ // returned by `bindings::video_devdata` and it is valid while the
+ // reference is alive.
+ unsafe { video::Device::<T>::from_raw(vdev) }
+ }
+
+ /// # Safety
+ ///
+ /// This should only be used as the `videoc_querycap` callback.
+ unsafe extern "C" fn vidioc_querycap_callback(
+ file: *mut bindings::file,
+ _fh: *mut c_void,
+ cap: *mut bindings::v4l2_capability,
+ ) -> core::ffi::c_int {
+ // SAFETY: this is being called from an ioctl callback and the returned
+ // reference does not outlive it.
+ let data = unsafe { Self::data(file) };
+
+ // SAFETY: the fact that this is being called from an ioctl callback means that:
+ //
+ // - the video device has been registered.
+ // - `open()` has been called (as you cannot call ioctl() on a file that
+ // has not been previously opened).
+ // - as a result from the statement above, a valid `v4l2_fh` was
+ // installed in `bindings::file::private_data`, which we then convert
+ // into `File<T>` here.
+ // - `ptr` is valid for 'a, i.e.: for the scope of this function.
+ let file = unsafe { v4l2::file::File::<T::File>::from_raw((*file).private_data.cast()) };
+
+ // SAFETY: the safety requirements ensure that `cap` is a valid pointer
+ // to a `struct v4l2_capability`, which fulfills the requirements of the
+ // `Capabilities::from_raw`.
+ let cap = unsafe { v4l2::caps::Capabilities::from_raw(cap) };
+
+ match T::querycap(file, data, cap) {
+ Ok(()) => 0,
+ Err(err) => err.to_errno(),
+ }
+ }
+
+ const VTABLE: bindings::v4l2_ioctl_ops = bindings::v4l2_ioctl_ops {
+ vidioc_querycap: if T::HAS_QUERYCAP {
+ Some(Self::vidioc_querycap_callback)
+ } else {
+ None
+ },
+ // SAFETY: All zeros is a valid value for `bindings::v4l2_ioctl_ops`.
+ ..unsafe { MaybeUninit::zeroed().assume_init() }
+ };
+
+ pub(super) const fn build() -> &'static bindings::v4l2_ioctl_ops {
+ &Self::VTABLE
+ }
+}
diff --git a/rust/kernel/media/v4l2/mod.rs b/rust/kernel/media/v4l2/mod.rs
index 1d8241f8a2230954371965bb91b20e726f144dce..4caa9fdc1ff3ed2bd6145cc653b49a84873ecac2 100644
--- a/rust/kernel/media/v4l2/mod.rs
+++ b/rust/kernel/media/v4l2/mod.rs
@@ -15,3 +15,6 @@
pub mod caps;
/// Support for Video for Linux 2 (V4L2) file handles.
pub mod file;
+
+/// Support for Video for Linux 2 (V4L2) ioctls.
+pub mod ioctl;
diff --git a/rust/kernel/media/v4l2/video.rs b/rust/kernel/media/v4l2/video.rs
index c0ac99a8234d2f7a8effd4701b9f7440236540c8..2390a93a39925dbff3f809bc65adfac1d881309c 100644
--- a/rust/kernel/media/v4l2/video.rs
+++ b/rust/kernel/media/v4l2/video.rs
@@ -19,7 +19,7 @@
use crate::{
alloc,
- error::to_result,
+ error::{to_result, VTABLE_DEFAULT_ERROR},
media::v4l2::{self, caps::DeviceCaps, file::DriverFile, video},
prelude::*,
types::{ARef, AlwaysRefCounted, Opaque},
@@ -143,6 +143,7 @@ unsafe impl<T: Driver> Sync for Device<T> {}
/// The interface that must be implemented by structs that would otherwise embed
/// a C [`struct video_device`](srctree/include/media/v4l2-dev.h).
+#[vtable]
pub trait Driver: v4l2::device::Driver {
/// The type of the driver's private data.
type Data;
@@ -161,6 +162,15 @@ pub trait Driver: v4l2::device::Driver {
/// The capabilities offered by this device node.
const CAPS: DeviceCaps;
+
+ /// Driver implementation for the `querycap` ioctl.
+ fn querycap(
+ _file: &v4l2::file::File<<Self as Driver>::File>,
+ _data: &<Self as Driver>::Data,
+ _cap: &mut v4l2::caps::Capabilities,
+ ) -> Result {
+ build_error!(VTABLE_DEFAULT_ERROR)
+ }
}
struct DeviceOptions<'a, T: Driver> {
@@ -184,6 +194,7 @@ fn into_raw(self) -> bindings::video_device {
release: Some(Device::<T>::release_callback),
fops: super::file::FileVtable::<T::File>::build(),
device_caps: T::CAPS.as_raw(),
+ ioctl_ops: super::ioctl::IoctlVtable::<T>::build(),
// SAFETY: All zeros is valid for the rest of the fields in this C
// type.
..unsafe { MaybeUninit::zeroed().assume_init() }
--
2.50.1
next prev parent reply other threads:[~2025-08-18 5:52 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-18 5:49 [PATCH 0/7] rust: add initial v4l2 support Daniel Almeida
2025-08-18 5:49 ` [PATCH 1/7] rust: media: add the media module Daniel Almeida
2025-08-18 8:56 ` Miguel Ojeda
2025-08-18 10:28 ` Janne Grunau
2025-08-18 5:49 ` [PATCH 2/7] rust: v4l2: add support for v4l2_device Daniel Almeida
2025-08-18 9:14 ` Danilo Krummrich
2025-08-18 5:49 ` [PATCH 3/7] rust: v4l2: add support for video device nodes Daniel Almeida
2025-08-18 9:26 ` Danilo Krummrich
2025-08-18 5:49 ` [PATCH 4/7] rust: v4l2: add support for v4l2 file handles Daniel Almeida
2025-08-18 5:49 ` [PATCH 5/7] rust: v4l2: add device capabilities Daniel Almeida
2025-08-20 4:14 ` Elle Rhumsaa
2025-08-18 5:49 ` Daniel Almeida [this message]
2025-08-20 4:22 ` [PATCH 6/7] rust: v4l2: add basic ioctl support Elle Rhumsaa
2025-08-18 5:49 ` [PATCH 7/7] rust: samples: add the v4l2 sample driver Daniel Almeida
2025-08-20 4:24 ` Elle Rhumsaa
2025-08-20 12:39 ` Danilo Krummrich
2025-08-18 8:45 ` [PATCH 0/7] rust: add initial v4l2 support Miguel Ojeda
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=20250818-v4l2-v1-6-6887e772aac2@collabora.com \
--to=daniel.almeida@collabora.com \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=gary@garyguo.net \
--cc=kernel@collabora.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
/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;
as well as URLs for NNTP newsgroup(s).