From: Elle Rhumsaa <elle@weathered-steel.dev>
To: Daniel Almeida <daniel.almeida@collabora.com>
Cc: "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>,
linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
kernel@collabora.com, linux-media@vger.kernel.org
Subject: Re: [PATCH 6/7] rust: v4l2: add basic ioctl support
Date: Wed, 20 Aug 2025 04:22:31 +0000 [thread overview]
Message-ID: <aKVNh8HRe5ADbiSZ@archiso> (raw)
In-Reply-To: <20250818-v4l2-v1-6-6887e772aac2@collabora.com>
On Mon, Aug 18, 2025 at 02:49:52AM -0300, Daniel Almeida wrote:
> 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
Reviewed-by: Elle Rhumsaa <elle@weathered-steel.dev>
next prev parent reply other threads:[~2025-08-20 4:22 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 ` [PATCH 6/7] rust: v4l2: add basic ioctl support Daniel Almeida
2025-08-20 4:22 ` Elle Rhumsaa [this message]
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=aKVNh8HRe5ADbiSZ@archiso \
--to=elle@weathered-steel.dev \
--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=daniel.almeida@collabora.com \
--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).