linux-usb.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] rust: usb: add initial USB abstractions
@ 2025-08-25 18:18 Daniel Almeida
  2025-08-25 18:18 ` [PATCH 1/2] rust: usb: add basic " Daniel Almeida
                   ` (2 more replies)
  0 siblings, 3 replies; 18+ messages in thread
From: Daniel Almeida @ 2025-08-25 18:18 UTC (permalink / raw)
  To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman
  Cc: linux-kernel, rust-for-linux, linux-usb, Daniel Almeida

This adds initial support for USB Rust drivers, not only because I see a
widespread use of module_usb_driver() in media (which is a subsystem I
aim to support) but also because I want to learn about USB in general
and this is a nice opportunity to start doing so.

I tried to keep things as consistent with pci.rs and platform.rs as
possible and tested it by manually binding a device (i.e.: my Logitech
mouse) to the sample driver via:

/sys/bus/usb/drivers/rust_driver_usb/new_id

This initial patch is therefore comprised of the same patterns that are
known to work for pci and platform already.

Physically disconnecting the device also worked, i.e.: nothing bad
showed up in dmesg.

Note that I did not touch MAINTAINERS at all. The objective is to
kickstart the discussion of what to do there here in v1.

---
Daniel Almeida (2):
      rust: usb: add basic USB abstractions
      samples: rust: add a USB driver sample

 rust/bindings/bindings_helper.h |   1 +
 rust/helpers/helpers.c          |   1 +
 rust/helpers/usb.c              |   8 +
 rust/kernel/lib.rs              |   2 +
 rust/kernel/usb.rs              | 457 ++++++++++++++++++++++++++++++++++++++++
 samples/rust/Kconfig            |  11 +
 samples/rust/Makefile           |   1 +
 samples/rust/rust_driver_usb.rs |  47 +++++
 8 files changed, 528 insertions(+)
---
base-commit: 44d454fcffa8b08d6d66df132121c1d387fa85db
change-id: 20250825-b4-usb-dd0fe44fd78b

Best regards,
-- 
Daniel Almeida <daniel.almeida@collabora.com>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 1/2] rust: usb: add basic USB abstractions
  2025-08-25 18:18 [PATCH 0/2] rust: usb: add initial USB abstractions Daniel Almeida
@ 2025-08-25 18:18 ` Daniel Almeida
  2025-08-25 20:49   ` Benno Lossin
  2025-08-25 18:18 ` [PATCH 2/2] samples: rust: add a USB driver sample Daniel Almeida
  2025-08-25 20:32 ` [PATCH 0/2] rust: usb: add initial USB abstractions Greg Kroah-Hartman
  2 siblings, 1 reply; 18+ messages in thread
From: Daniel Almeida @ 2025-08-25 18:18 UTC (permalink / raw)
  To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman
  Cc: linux-kernel, rust-for-linux, linux-usb, Daniel Almeida

Add basic USB abstractions, consisting of usb::{Device, Interface,
Driver, Adapter, DeviceId} and the module_usb_driver macro. This is the
first step in being able to write USB device drivers, which paves the
way for USB media drivers - for example - among others.

This initial support will then be used by a subsequent sample driver,
which constitutes the only user of the USB abstractions so far.

Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
 rust/bindings/bindings_helper.h |   1 +
 rust/helpers/helpers.c          |   1 +
 rust/helpers/usb.c              |   8 +
 rust/kernel/lib.rs              |   2 +
 rust/kernel/usb.rs              | 457 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 469 insertions(+)

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 69a975da829f0c35760f71a1b32b8fcb12c8a8dc..645afe578668097ae04455d9eefb102d1f1ce4af 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -73,6 +73,7 @@
 #include <linux/security.h>
 #include <linux/slab.h>
 #include <linux/tracepoint.h>
+#include <linux/usb.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <linux/xarray.h>
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 44b2005d50140d34a44ae37d01c2ddbae6aeaa32..da1ee0d3705739e789c7ad21b957bbdb7ca23521 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -48,6 +48,7 @@
 #include "task.c"
 #include "time.c"
 #include "uaccess.c"
+#include "usb.c"
 #include "vmalloc.c"
 #include "wait.c"
 #include "workqueue.c"
diff --git a/rust/helpers/usb.c b/rust/helpers/usb.c
new file mode 100644
index 0000000000000000000000000000000000000000..fb2aad0cbf4d26ac7fb1a3f176ee7a1d30800f92
--- /dev/null
+++ b/rust/helpers/usb.c
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/usb.h>
+
+struct usb_device *rust_helper_interface_to_usbdev(struct usb_interface *intf)
+{
+	return interface_to_usbdev(intf);
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index f8db761c5c95fc66e4c55f539b17fca613161ada..b15277a02028aa1d27480d0630f9f599cacd6e4d 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -127,6 +127,8 @@
 pub mod tracepoint;
 pub mod transmute;
 pub mod types;
+#[cfg(CONFIG_USB)]
+pub mod usb;
 pub mod uaccess;
 pub mod workqueue;
 pub mod xarray;
diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8899e7520b58d4e4b08927d54c8912650b78da33
--- /dev/null
+++ b/rust/kernel/usb.rs
@@ -0,0 +1,457 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (C) 2025 Collabora Ltd.
+
+//! Abstractions for the USB bus.
+//!
+//! C header: [`include/linux/usb.h`](srctree/include/linux/usb.h)
+
+use crate::{
+    bindings, device,
+    device_id::{RawDeviceId, RawDeviceIdIndex},
+    driver,
+    error::{from_result, to_result, Result},
+    prelude::*,
+    str::CStr,
+    types::{AlwaysRefCounted, Opaque},
+    ThisModule,
+};
+use core::{marker::PhantomData, mem::MaybeUninit, ptr::NonNull};
+
+/// An adapter for the registration of USB drivers.
+pub struct Adapter<T: Driver>(T);
+
+// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if
+// a preceding call to `register` has been successful.
+unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
+    type RegType = bindings::usb_driver;
+
+    unsafe fn register(
+        udrv: &Opaque<Self::RegType>,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: It's safe to set the fields of `struct usb_driver` on initialization.
+        unsafe {
+            (*udrv.get()).name = name.as_char_ptr();
+            (*udrv.get()).probe = Some(Self::probe_callback);
+            (*udrv.get()).disconnect = Some(Self::disconnect_callback);
+            (*udrv.get()).id_table = T::ID_TABLE.as_ptr();
+        }
+
+        // SAFETY: `udrv` is guaranteed to be a valid `RegType`.
+        to_result(unsafe {
+            bindings::usb_register_driver(udrv.get(), module.0, name.as_char_ptr())
+        })
+    }
+
+    unsafe fn unregister(udrv: &Opaque<Self::RegType>) {
+        // SAFETY: `udrv` is guaranteed to be a valid `RegType`.
+        unsafe { bindings::usb_deregister(udrv.get()) };
+    }
+}
+
+impl<T: Driver + 'static> Adapter<T> {
+    extern "C" fn probe_callback(
+        intf: *mut bindings::usb_interface,
+        id: *const bindings::usb_device_id,
+    ) -> kernel::ffi::c_int {
+        // SAFETY: The USB core only ever calls the probe callback with a valid pointer to a
+        // `struct usb_interface` and `struct usb_device_id`.
+        //
+        // INVARIANT: `intf` is valid for the duration of `probe_callback()`.
+        let intf = unsafe { &*intf.cast::<Interface<device::CoreInternal>>() };
+
+        from_result(|| {
+            // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct usb_device_id` and
+            // does not add additional invariants, so it's safe to transmute.
+            let id = unsafe { &*id.cast::<DeviceId>() };
+
+            let info = T::ID_TABLE.info(id.index());
+            let data = T::probe(intf, id, info)?;
+
+            let dev: &device::Device<device::CoreInternal> = intf.as_ref();
+            dev.set_drvdata(data);
+            Ok(0)
+        })
+    }
+
+    extern "C" fn disconnect_callback(intf: *mut bindings::usb_interface) {
+        // SAFETY: The USB core only ever calls the disconnect callback with a valid pointer to a
+        // `struct usb_interface`.
+        //
+        // INVARIANT: `intf` is valid for the duration of `disconnect_callback()`.
+        let intf = unsafe { &*intf.cast::<Interface<device::CoreInternal>>() };
+
+        let dev: &device::Device<device::CoreInternal> = intf.as_ref();
+
+        // SAFETY: `disconnect_callback` is only ever called after a successful call to
+        // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called
+        // and stored a `Pin<KBox<T>>`.
+        let data = unsafe { dev.drvdata_obtain::<Pin<KBox<T>>>() };
+
+        T::disconnect(intf, data.as_ref());
+    }
+}
+
+/// Abstraction for the USB device ID structure, i.e. [`struct usb_device_id`].
+///
+/// [`struct usb_device_id`]: https://docs.kernel.org/driver-api/basics.html#c.usb_device_id
+#[repr(transparent)]
+#[derive(Clone, Copy)]
+pub struct DeviceId(bindings::usb_device_id);
+
+impl DeviceId {
+    /// Equivalent to C's `USB_DEVICE` macro.
+    pub const fn from_id(vendor: u16, product: u16) -> Self {
+        Self(bindings::usb_device_id {
+            match_flags: bindings::USB_DEVICE_ID_MATCH_DEVICE as u16,
+            idVendor: vendor,
+            idProduct: product,
+            // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
+            ..unsafe { MaybeUninit::zeroed().assume_init() }
+        })
+    }
+
+    /// Equivalent to C's `USB_DEVICE_VER` macro.
+    pub const fn from_device_ver(vendor: u16, product: u16, bcd_lo: u16, bcd_hi: u16) -> Self {
+        Self(bindings::usb_device_id {
+            match_flags: bindings::USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION as u16,
+            idVendor: vendor,
+            idProduct: product,
+            bcdDevice_lo: bcd_lo,
+            bcdDevice_hi: bcd_hi,
+            // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
+            ..unsafe { MaybeUninit::zeroed().assume_init() }
+        })
+    }
+
+    /// Equivalent to C's `USB_DEVICE_INFO` macro.
+    pub const fn from_device_info(class: u8, subclass: u8, protocol: u8) -> Self {
+        Self(bindings::usb_device_id {
+            match_flags: bindings::USB_DEVICE_ID_MATCH_DEV_INFO as u16,
+            bDeviceClass: class,
+            bDeviceSubClass: subclass,
+            bDeviceProtocol: protocol,
+            // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
+            ..unsafe { MaybeUninit::zeroed().assume_init() }
+        })
+    }
+
+    /// Equivalent to C's `USB_INTERFACE_INFO` macro.
+    pub const fn from_interface_info(class: u8, subclass: u8, protocol: u8) -> Self {
+        Self(bindings::usb_device_id {
+            match_flags: bindings::USB_DEVICE_ID_MATCH_INT_INFO as u16,
+            bInterfaceClass: class,
+            bInterfaceSubClass: subclass,
+            bInterfaceProtocol: protocol,
+            // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
+            ..unsafe { MaybeUninit::zeroed().assume_init() }
+        })
+    }
+
+    /// Equivalent to C's `USB_DEVICE_INTERFACE_CLASS` macro.
+    pub const fn from_device_interface_class(vendor: u16, product: u16, class: u8) -> Self {
+        Self(bindings::usb_device_id {
+            match_flags: (bindings::USB_DEVICE_ID_MATCH_DEVICE
+                | bindings::USB_DEVICE_ID_MATCH_INT_CLASS) as u16,
+            idVendor: vendor,
+            idProduct: product,
+            bInterfaceClass: class,
+            // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
+            ..unsafe { MaybeUninit::zeroed().assume_init() }
+        })
+    }
+
+    /// Equivalent to C's `USB_DEVICE_INTERFACE_PROTOCOL` macro.
+    pub const fn from_device_interface_protocol(vendor: u16, product: u16, protocol: u8) -> Self {
+        Self(bindings::usb_device_id {
+            match_flags: (bindings::USB_DEVICE_ID_MATCH_DEVICE
+                | bindings::USB_DEVICE_ID_MATCH_INT_PROTOCOL) as u16,
+            idVendor: vendor,
+            idProduct: product,
+            bInterfaceProtocol: protocol,
+            // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
+            ..unsafe { MaybeUninit::zeroed().assume_init() }
+        })
+    }
+
+    /// Equivalent to C's `USB_DEVICE_INTERFACE_NUMBER` macro.
+    pub const fn from_device_interface_number(vendor: u16, product: u16, number: u8) -> Self {
+        Self(bindings::usb_device_id {
+            match_flags: (bindings::USB_DEVICE_ID_MATCH_DEVICE
+                | bindings::USB_DEVICE_ID_MATCH_INT_NUMBER) as u16,
+            idVendor: vendor,
+            idProduct: product,
+            bInterfaceNumber: number,
+            // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
+            ..unsafe { MaybeUninit::zeroed().assume_init() }
+        })
+    }
+
+    /// Equivalent to C's `USB_DEVICE_AND_INTERFACE_INFO` macro.
+    pub const fn from_device_and_interface_info(
+        vendor: u16,
+        product: u16,
+        class: u8,
+        subclass: u8,
+        protocol: u8,
+    ) -> Self {
+        Self(bindings::usb_device_id {
+            match_flags: (bindings::USB_DEVICE_ID_MATCH_INT_INFO
+                | bindings::USB_DEVICE_ID_MATCH_DEVICE) as u16,
+            idVendor: vendor,
+            idProduct: product,
+            bInterfaceClass: class,
+            bInterfaceSubClass: subclass,
+            bInterfaceProtocol: protocol,
+            // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
+            ..unsafe { MaybeUninit::zeroed().assume_init() }
+        })
+    }
+}
+
+// SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `usb_device_id` and does not add
+// additional invariants, so it's safe to transmute to `RawType`.
+unsafe impl RawDeviceId for DeviceId {
+    type RawType = bindings::usb_device_id;
+}
+
+// SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_info` field.
+unsafe impl RawDeviceIdIndex for DeviceId {
+    const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::usb_device_id, driver_info);
+
+    fn index(&self) -> usize {
+        self.0.driver_info
+    }
+}
+
+/// [`IdTable`](kernel::device_id::IdTable) type for USB.
+pub type IdTable<T> = &'static dyn kernel::device_id::IdTable<DeviceId, T>;
+
+/// Create a USB `IdTable` with its alias for modpost.
+#[macro_export]
+macro_rules! usb_device_table {
+    ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
+        const $table_name: $crate::device_id::IdArray<
+            $crate::usb::DeviceId,
+            $id_info_type,
+            { $table_data.len() },
+        > = $crate::device_id::IdArray::new($table_data);
+
+        $crate::module_device_table!("usb", $module_table_name, $table_name);
+    };
+}
+
+/// The USB driver trait.
+///
+/// # Examples
+///
+///```
+/// # use kernel::{bindings, device::Core, usb};
+/// use kernel::prelude::*;
+///
+/// struct MyDriver;
+///
+/// kernel::usb_device_table!(
+///     USB_TABLE,
+///     MODULE_USB_TABLE,
+///     <MyDriver as usb::Driver>::IdInfo,
+///     [
+///         (usb::DeviceId::from_id(0x1234, 0x5678), ()),
+///         (usb::DeviceId::from_id(0xabcd, 0xef01), ()),
+///     ]
+/// );
+///
+/// impl usb::Driver for MyDriver {
+///     type IdInfo = ();
+///     const ID_TABLE: usb::IdTable<Self::IdInfo> = &USB_TABLE;
+///
+///     fn probe(
+///         _interface: &usb::Interface<Core>,
+///         _id: &usb::DeviceId,
+///         _info: &Self::IdInfo,
+///     ) -> Result<Pin<KBox<Self>>> {
+///         Err(ENODEV)
+///     }
+///
+///     fn disconnect(_interface: &usb::Interface<Core>, _data: Pin<&Self>) {}
+/// }
+///```
+pub trait Driver {
+    /// The type holding information about each one of the device ids supported by the driver.
+    type IdInfo: 'static;
+
+    /// The table of device ids supported by the driver.
+    const ID_TABLE: IdTable<Self::IdInfo>;
+
+    /// USB driver probe.
+    ///
+    /// Called when a new USB interface is bound to this driver.
+    /// Implementers should attempt to initialize the interface here.
+    fn probe(
+        interface: &Interface<device::Core>,
+        id: &DeviceId,
+        id_info: &Self::IdInfo,
+    ) -> Result<Pin<KBox<Self>>>;
+
+    /// USB driver disconnect.
+    ///
+    /// Called when the USB interface is about to be unbound from this driver.
+    fn disconnect(interface: &Interface<device::Core>, data: Pin<&Self>);
+}
+
+/// A USB interface.
+///
+/// This structure represents the Rust abstraction for a C [`struct usb_interface`].
+/// The implementation abstracts the usage of a C [`struct usb_interface`] passed
+/// in from the C side.
+///
+/// # Invariants
+///
+/// An [`Interface`] instance represents a valid [`struct usb_interface`] created
+/// by the C portion of the kernel.
+///
+/// [`struct usb_interface`]: https://www.kernel.org/doc/html/latest/driver-api/usb/usb.html#c.usb_interface
+#[repr(transparent)]
+pub struct Interface<Ctx: device::DeviceContext = device::Normal>(
+    Opaque<bindings::usb_interface>,
+    PhantomData<Ctx>,
+);
+
+impl<Ctx: device::DeviceContext> Interface<Ctx> {
+    fn as_raw(&self) -> *mut bindings::usb_interface {
+        self.0.get()
+    }
+}
+
+// SAFETY: `Interface` is a transparent wrapper of a type that doesn't depend on
+// `Interface`'s generic argument.
+kernel::impl_device_context_deref!(unsafe { Interface });
+kernel::impl_device_context_into_aref!(Interface);
+
+impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Interface<Ctx> {
+    fn as_ref(&self) -> &device::Device<Ctx> {
+        // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
+        // `struct usb_interface`.
+        let dev = unsafe { &raw mut ((*self.as_raw()).dev) };
+
+        // SAFETY: `dev` points to a valid `struct device`.
+        unsafe { device::Device::from_raw(dev) }
+    }
+}
+
+impl<Ctx: device::DeviceContext> AsRef<Device<Ctx>> for Interface<Ctx> {
+    fn as_ref(&self) -> &Device<Ctx> {
+        // SAFETY: `self.as_raw()` is valid by the type invariants. For a valid interface,
+        // the helper should always return a valid USB device pointer.
+        let usb_dev = unsafe { bindings::interface_to_usbdev(self.as_raw()) };
+
+        // SAFETY: The helper returns a valid interface pointer that shares the
+        // same `DeviceContext`.
+        unsafe { &*(usb_dev.cast()) }
+    }
+}
+
+// SAFETY: Instances of `Interface` are always reference-counted.
+unsafe impl AlwaysRefCounted for Interface {
+    fn inc_ref(&self) {
+        // SAFETY: The invariants of `Interface` guarantee that `self.as_raw()`
+        // returns a valid `struct usb_interface` pointer, for which we will
+        // acquire a new refcount.
+        unsafe { bindings::usb_get_intf(self.as_raw()) };
+    }
+
+    unsafe fn dec_ref(obj: NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is non-zero.
+        unsafe { bindings::usb_put_intf(obj.cast().as_ptr()) }
+    }
+}
+
+// SAFETY: A `Interface` is always reference-counted and can be released from any thread.
+unsafe impl Send for Interface {}
+
+// SAFETY: It is safe to send a &Interface to another thread because we do not
+// allow any mutation through a shared reference.
+unsafe impl Sync for Interface {}
+
+/// A USB device.
+///
+/// This structure represents the Rust abstraction for a C [`struct usb_device`].
+/// The implementation abstracts the usage of a C [`struct usb_device`] passed in
+/// from the C side.
+///
+/// # Invariants
+///
+/// A [`Device`] instance represents a valid [`struct usb_device`] created by the C portion of the
+/// kernel.
+///
+/// [`struct usb_device`]: https://www.kernel.org/doc/html/latest/driver-api/usb/usb.html#c.usb_device
+#[repr(transparent)]
+pub struct Device<Ctx: device::DeviceContext = device::Normal>(
+    Opaque<bindings::usb_device>,
+    PhantomData<Ctx>,
+);
+
+impl<Ctx: device::DeviceContext> Device<Ctx> {
+    fn as_raw(&self) -> *mut bindings::usb_device {
+        self.0.get()
+    }
+}
+
+// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
+// argument.
+kernel::impl_device_context_deref!(unsafe { Device });
+kernel::impl_device_context_into_aref!(Device);
+
+// SAFETY: Instances of `Device` are always reference-counted.
+unsafe impl AlwaysRefCounted for Device {
+    fn inc_ref(&self) {
+        // SAFETY: The invariants of `Device` guarantee that `self.as_raw()`
+        // returns a valid `struct usb_device` pointer, for which we will
+        // acquire a new refcount.
+        unsafe { bindings::usb_get_dev(self.as_raw()) };
+    }
+
+    unsafe fn dec_ref(obj: NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is non-zero.
+        unsafe { bindings::usb_put_dev(obj.cast().as_ptr()) }
+    }
+}
+
+impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
+    fn as_ref(&self) -> &device::Device<Ctx> {
+        // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
+        // `struct usb_device`.
+        let dev = unsafe { &raw mut ((*self.as_raw()).dev) };
+
+        // SAFETY: `dev` points to a valid `struct device`.
+        unsafe { device::Device::from_raw(dev) }
+    }
+}
+
+// SAFETY: A `Device` is always reference-counted and can be released from any thread.
+unsafe impl Send for Device {}
+
+// SAFETY: It is safe to send a &Device to another thread because we do not
+// allow any mutation through a shared reference.
+unsafe impl Sync for Device {}
+
+/// Declares a kernel module that exposes a single USB driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// module_usb_driver! {
+///     type: MyDriver,
+///     name: "Module name",
+///     author: ["Author name"],
+///     description: "Description",
+///     license: "GPL v2",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_usb_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::usb::Adapter<T>, { $($f)* });
+    }
+}

-- 
2.50.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 2/2] samples: rust: add a USB driver sample
  2025-08-25 18:18 [PATCH 0/2] rust: usb: add initial USB abstractions Daniel Almeida
  2025-08-25 18:18 ` [PATCH 1/2] rust: usb: add basic " Daniel Almeida
@ 2025-08-25 18:18 ` Daniel Almeida
  2025-09-06 11:14   ` Greg Kroah-Hartman
  2025-08-25 20:32 ` [PATCH 0/2] rust: usb: add initial USB abstractions Greg Kroah-Hartman
  2 siblings, 1 reply; 18+ messages in thread
From: Daniel Almeida @ 2025-08-25 18:18 UTC (permalink / raw)
  To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman
  Cc: linux-kernel, rust-for-linux, linux-usb, Daniel Almeida

In light of the newly-added Rust abstractions for USB devices and
drivers, add a sample USB rust driver that serves both to showcase what
is currently supported, as well as be the only user of the USB
abstractions for now.

Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
 samples/rust/Kconfig            | 11 ++++++++++
 samples/rust/Makefile           |  1 +
 samples/rust/rust_driver_usb.rs | 47 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 59 insertions(+)

diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
index 7f7371a004ee0a8f67dca99c836596709a70c4fa..fb222f93014c921b27a8a9a4293e90a2532faa82 100644
--- a/samples/rust/Kconfig
+++ b/samples/rust/Kconfig
@@ -83,6 +83,17 @@ config SAMPLE_RUST_DRIVER_PLATFORM
 
 	  If unsure, say N.
 
+config SAMPLE_RUST_DRIVER_USB
+	tristate "USB Driver"
+	depends on USB
+	help
+	  This option builds the Rust USB driver sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_driver_usb.
+
+	  If unsure, say N.
+
 config SAMPLE_RUST_DRIVER_FAUX
 	tristate "Faux Driver"
 	help
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
index bd2faad63b4f3befe7d1ed5139fe25c7a8b6d7f6..4e7df8a5cd277d101920c4b89a3ac6648b372b28 100644
--- a/samples/rust/Makefile
+++ b/samples/rust/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_SAMPLE_RUST_PRINT)			+= rust_print.o
 obj-$(CONFIG_SAMPLE_RUST_DMA)			+= rust_dma.o
 obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI)		+= rust_driver_pci.o
 obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM)	+= rust_driver_platform.o
+obj-$(CONFIG_SAMPLE_RUST_DRIVER_USB)		+= rust_driver_usb.o
 obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX)		+= rust_driver_faux.o
 obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY)	+= rust_driver_auxiliary.o
 obj-$(CONFIG_SAMPLE_RUST_CONFIGFS)		+= rust_configfs.o
diff --git a/samples/rust/rust_driver_usb.rs b/samples/rust/rust_driver_usb.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5c396f421de7f972985e57af48e8a9da0c558973
--- /dev/null
+++ b/samples/rust/rust_driver_usb.rs
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (C) 2025 Collabora Ltd.
+
+//! Rust USB driver sample.
+
+use kernel::{device, device::Core, prelude::*, sync::aref::ARef, usb};
+
+struct SampleDriver {
+    _intf: ARef<usb::Interface>,
+}
+
+kernel::usb_device_table!(
+    USB_TABLE,
+    MODULE_USB_TABLE,
+    <SampleDriver as usb::Driver>::IdInfo,
+    [(usb::DeviceId::from_id(0x1234, 0x5678), ()),]
+);
+
+impl usb::Driver for SampleDriver {
+    type IdInfo = ();
+    const ID_TABLE: usb::IdTable<Self::IdInfo> = &USB_TABLE;
+
+    fn probe(
+        intf: &usb::Interface<Core>,
+        _id: &usb::DeviceId,
+        _info: &Self::IdInfo,
+    ) -> Result<Pin<KBox<Self>>> {
+        let dev: &device::Device<Core> = intf.as_ref();
+        dev_info!(dev, "Rust USB driver sample probed\n");
+
+        let drvdata = KBox::new(Self { _intf: intf.into() }, GFP_KERNEL)?;
+        Ok(drvdata.into())
+    }
+
+    fn disconnect(intf: &usb::Interface<Core>, _data: Pin<&Self>) {
+        let dev: &device::Device<Core> = intf.as_ref();
+        dev_info!(dev, "Rust USB driver sample disconnected\n");
+    }
+}
+
+kernel::module_usb_driver! {
+    type: SampleDriver,
+    name: "rust_driver_usb",
+    authors: ["Daniel Almeida"],
+    description: "Rust USB driver sample",
+    license: "GPL v2",
+}

-- 
2.50.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH 0/2] rust: usb: add initial USB abstractions
  2025-08-25 18:18 [PATCH 0/2] rust: usb: add initial USB abstractions Daniel Almeida
  2025-08-25 18:18 ` [PATCH 1/2] rust: usb: add basic " Daniel Almeida
  2025-08-25 18:18 ` [PATCH 2/2] samples: rust: add a USB driver sample Daniel Almeida
@ 2025-08-25 20:32 ` Greg Kroah-Hartman
  2 siblings, 0 replies; 18+ messages in thread
From: Greg Kroah-Hartman @ 2025-08-25 20:32 UTC (permalink / raw)
  To: Daniel Almeida
  Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, linux-kernel, rust-for-linux,
	linux-usb

On Mon, Aug 25, 2025 at 03:18:04PM -0300, Daniel Almeida wrote:
> This adds initial support for USB Rust drivers, not only because I see a
> widespread use of module_usb_driver() in media (which is a subsystem I
> aim to support) but also because I want to learn about USB in general
> and this is a nice opportunity to start doing so.

Oh wow, I wasn't expecting this, nice!

I'm at a conference all this week so I can't review this just yet, give
me a week please.  But I am happy to see this happen, thanks for doing
it.

greg k-h

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/2] rust: usb: add basic USB abstractions
  2025-08-25 18:18 ` [PATCH 1/2] rust: usb: add basic " Daniel Almeida
@ 2025-08-25 20:49   ` Benno Lossin
  2025-08-25 21:03     ` Daniel Almeida
  0 siblings, 1 reply; 18+ messages in thread
From: Benno Lossin @ 2025-08-25 20:49 UTC (permalink / raw)
  To: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Greg Kroah-Hartman
  Cc: linux-kernel, rust-for-linux, linux-usb

On Mon Aug 25, 2025 at 8:18 PM CEST, Daniel Almeida wrote:
> +impl DeviceId {
> +    /// Equivalent to C's `USB_DEVICE` macro.
> +    pub const fn from_id(vendor: u16, product: u16) -> Self {
> +        Self(bindings::usb_device_id {
> +            match_flags: bindings::USB_DEVICE_ID_MATCH_DEVICE as u16,
> +            idVendor: vendor,
> +            idProduct: product,
> +            // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
> +            ..unsafe { MaybeUninit::zeroed().assume_init() }

You can avoid this usage of `unsafe` with this patch series:

    https://lore.kernel.org/all/20250814093046.2071971-1-lossin@kernel.org

I'd like to avoid introducing any new one of these.

---
Cheers,
Benno

> +        })
> +    }

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/2] rust: usb: add basic USB abstractions
  2025-08-25 20:49   ` Benno Lossin
@ 2025-08-25 21:03     ` Daniel Almeida
  0 siblings, 0 replies; 18+ messages in thread
From: Daniel Almeida @ 2025-08-25 21:03 UTC (permalink / raw)
  To: Benno Lossin
  Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Greg Kroah-Hartman, linux-kernel,
	rust-for-linux, linux-usb

Hi Benno,

> On 25 Aug 2025, at 17:49, Benno Lossin <lossin@kernel.org> wrote:
> 
> On Mon Aug 25, 2025 at 8:18 PM CEST, Daniel Almeida wrote:
>> +impl DeviceId {
>> +    /// Equivalent to C's `USB_DEVICE` macro.
>> +    pub const fn from_id(vendor: u16, product: u16) -> Self {
>> +        Self(bindings::usb_device_id {
>> +            match_flags: bindings::USB_DEVICE_ID_MATCH_DEVICE as u16,
>> +            idVendor: vendor,
>> +            idProduct: product,
>> +            // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`.
>> +            ..unsafe { MaybeUninit::zeroed().assume_init() }
> 
> You can avoid this usage of `unsafe` with this patch series:
> 
>    https://lore.kernel.org/all/20250814093046.2071971-1-lossin@kernel.org
> 
> I'd like to avoid introducing any new one of these.
> 
> ---
> Cheers,
> Benno
> 
>> +        })
>> +    }
> 

Ah, nice, you spoke about this in the last RFL call, I remember it now.

Ok, I will address this in the next version.

— Daniel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] samples: rust: add a USB driver sample
  2025-08-25 18:18 ` [PATCH 2/2] samples: rust: add a USB driver sample Daniel Almeida
@ 2025-09-06 11:14   ` Greg Kroah-Hartman
  2025-09-06 12:04     ` Daniel Almeida
  0 siblings, 1 reply; 18+ messages in thread
From: Greg Kroah-Hartman @ 2025-09-06 11:14 UTC (permalink / raw)
  To: Daniel Almeida
  Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, linux-kernel, rust-for-linux,
	linux-usb

On Mon, Aug 25, 2025 at 03:18:06PM -0300, Daniel Almeida wrote:
> In light of the newly-added Rust abstractions for USB devices and
> drivers, add a sample USB rust driver that serves both to showcase what
> is currently supported, as well as be the only user of the USB
> abstractions for now.
> 
> Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
> ---
>  samples/rust/Kconfig            | 11 ++++++++++
>  samples/rust/Makefile           |  1 +
>  samples/rust/rust_driver_usb.rs | 47 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 59 insertions(+)
> 
> diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
> index 7f7371a004ee0a8f67dca99c836596709a70c4fa..fb222f93014c921b27a8a9a4293e90a2532faa82 100644
> --- a/samples/rust/Kconfig
> +++ b/samples/rust/Kconfig
> @@ -83,6 +83,17 @@ config SAMPLE_RUST_DRIVER_PLATFORM
>  
>  	  If unsure, say N.
>  
> +config SAMPLE_RUST_DRIVER_USB
> +	tristate "USB Driver"
> +	depends on USB
> +	help
> +	  This option builds the Rust USB driver sample.
> +
> +	  To compile this as a module, choose M here:
> +	  the module will be called rust_driver_usb.
> +
> +	  If unsure, say N.
> +
>  config SAMPLE_RUST_DRIVER_FAUX
>  	tristate "Faux Driver"
>  	help
> diff --git a/samples/rust/Makefile b/samples/rust/Makefile
> index bd2faad63b4f3befe7d1ed5139fe25c7a8b6d7f6..4e7df8a5cd277d101920c4b89a3ac6648b372b28 100644
> --- a/samples/rust/Makefile
> +++ b/samples/rust/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_SAMPLE_RUST_PRINT)			+= rust_print.o
>  obj-$(CONFIG_SAMPLE_RUST_DMA)			+= rust_dma.o
>  obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI)		+= rust_driver_pci.o
>  obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM)	+= rust_driver_platform.o
> +obj-$(CONFIG_SAMPLE_RUST_DRIVER_USB)		+= rust_driver_usb.o
>  obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX)		+= rust_driver_faux.o
>  obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY)	+= rust_driver_auxiliary.o
>  obj-$(CONFIG_SAMPLE_RUST_CONFIGFS)		+= rust_configfs.o
> diff --git a/samples/rust/rust_driver_usb.rs b/samples/rust/rust_driver_usb.rs
> new file mode 100644
> index 0000000000000000000000000000000000000000..5c396f421de7f972985e57af48e8a9da0c558973
> --- /dev/null
> +++ b/samples/rust/rust_driver_usb.rs
> @@ -0,0 +1,47 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// SPDX-FileCopyrightText: Copyright (C) 2025 Collabora Ltd.
> +
> +//! Rust USB driver sample.
> +
> +use kernel::{device, device::Core, prelude::*, sync::aref::ARef, usb};
> +
> +struct SampleDriver {
> +    _intf: ARef<usb::Interface>,
> +}
> +
> +kernel::usb_device_table!(
> +    USB_TABLE,
> +    MODULE_USB_TABLE,
> +    <SampleDriver as usb::Driver>::IdInfo,
> +    [(usb::DeviceId::from_id(0x1234, 0x5678), ()),]
> +);
> +
> +impl usb::Driver for SampleDriver {
> +    type IdInfo = ();
> +    const ID_TABLE: usb::IdTable<Self::IdInfo> = &USB_TABLE;
> +
> +    fn probe(
> +        intf: &usb::Interface<Core>,
> +        _id: &usb::DeviceId,
> +        _info: &Self::IdInfo,
> +    ) -> Result<Pin<KBox<Self>>> {
> +        let dev: &device::Device<Core> = intf.as_ref();
> +        dev_info!(dev, "Rust USB driver sample probed\n");
> +
> +        let drvdata = KBox::new(Self { _intf: intf.into() }, GFP_KERNEL)?;
> +        Ok(drvdata.into())
> +    }
> +
> +    fn disconnect(intf: &usb::Interface<Core>, _data: Pin<&Self>) {
> +        let dev: &device::Device<Core> = intf.as_ref();
> +        dev_info!(dev, "Rust USB driver sample disconnected\n");
> +    }
> +}
> +
> +kernel::module_usb_driver! {
> +    type: SampleDriver,
> +    name: "rust_driver_usb",
> +    authors: ["Daniel Almeida"],
> +    description: "Rust USB driver sample",
> +    license: "GPL v2",
> +}

Sorry for the delay.

But these bindings really are only for a usb interface probe/disconnect
sequence, right?  no real data flow at all?

I recommend looking at the usb-skeleton.c driver, and implementing that
as your sample driver for rust.  That will ensure that you actually have
the correct apis implemented and the reference count logic working
properly.  You have urb anchors and callbacks and other stuff as well to
ensure that you get right.  That driver pretty much should handle
everything that you need to do to write a usb driver for any type of
"real" device.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] samples: rust: add a USB driver sample
  2025-09-06 11:14   ` Greg Kroah-Hartman
@ 2025-09-06 12:04     ` Daniel Almeida
  2025-09-06 12:10       ` Greg Kroah-Hartman
  0 siblings, 1 reply; 18+ messages in thread
From: Daniel Almeida @ 2025-09-06 12:04 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, linux-kernel, rust-for-linux,
	linux-usb

Hi Greg,

[…]

> 
> Sorry for the delay.
> 
> But these bindings really are only for a usb interface probe/disconnect
> sequence, right?  no real data flow at all?
> 
> I recommend looking at the usb-skeleton.c driver, and implementing that
> as your sample driver for rust.  That will ensure that you actually have
> the correct apis implemented and the reference count logic working
> properly.  You have urb anchors and callbacks and other stuff as well to
> ensure that you get right.  That driver pretty much should handle
> everything that you need to do to write a usb driver for any type of
> "real" device.
> 
> thanks,
> 
> greg k-h


I thought that an iterative approach would work here, i.e.: merge this, then
URBs, then more stuff, etc.

In any case that’s OK. I will work on the other stuff you listed here.

— Daniel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] samples: rust: add a USB driver sample
  2025-09-06 12:04     ` Daniel Almeida
@ 2025-09-06 12:10       ` Greg Kroah-Hartman
  2025-09-06 12:41         ` Daniel Almeida
  0 siblings, 1 reply; 18+ messages in thread
From: Greg Kroah-Hartman @ 2025-09-06 12:10 UTC (permalink / raw)
  To: Daniel Almeida
  Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, linux-kernel, rust-for-linux,
	linux-usb

On Sat, Sep 06, 2025 at 09:04:04AM -0300, Daniel Almeida wrote:
> Hi Greg,
> 
> […]
> 
> > 
> > Sorry for the delay.
> > 
> > But these bindings really are only for a usb interface probe/disconnect
> > sequence, right?  no real data flow at all?
> > 
> > I recommend looking at the usb-skeleton.c driver, and implementing that
> > as your sample driver for rust.  That will ensure that you actually have
> > the correct apis implemented and the reference count logic working
> > properly.  You have urb anchors and callbacks and other stuff as well to
> > ensure that you get right.  That driver pretty much should handle
> > everything that you need to do to write a usb driver for any type of
> > "real" device.
> > 
> > thanks,
> > 
> > greg k-h
> 
> 
> I thought that an iterative approach would work here, i.e.: merge this, then
> URBs, then more stuff, etc.

Ah, that makes sense, I didn't realize you want that here.  What USB
device do you want to write a rust driver for?  Are you going to need
bindings to the usb major number, or is it going to talk to some other
subsystem instead?

Right now, these bindings don't really do anything USB specific at all
except allow a driver to bind to a device.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] samples: rust: add a USB driver sample
  2025-09-06 12:10       ` Greg Kroah-Hartman
@ 2025-09-06 12:41         ` Daniel Almeida
  2025-09-06 13:07           ` Greg Kroah-Hartman
  2025-09-06 13:22           ` Danilo Krummrich
  0 siblings, 2 replies; 18+ messages in thread
From: Daniel Almeida @ 2025-09-06 12:41 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, linux-kernel, rust-for-linux,
	linux-usb



>> 
>> I thought that an iterative approach would work here, i.e.: merge this, then
>> URBs, then more stuff, etc.
> 
> Ah, that makes sense, I didn't realize you want that here.  What USB
> device do you want to write a rust driver for?  Are you going to need
> bindings to the usb major number, or is it going to talk to some other
> subsystem instead?
> 
> Right now, these bindings don't really do anything USB specific at all
> except allow a driver to bind to a device.
> 
> thanks,
> 
> greg k-h

To be honest, I'm trying to pave the way for others.

I often hear people saying that they would look into Rust drivers if only they
did not have to write all the surrounding infrastructure themselves. On the
other hand, there is no infrastructure because there are no drivers. It's a
chicken and egg problem that I am trying to solve.

It's also a cool opportunity to learn about USB, but I don't have any plans
for a driver at the moment other than a instructional sample driver in Rust.

Give me a few more weeks and I'll come up with the code for the other things
you've pointed out.

By the way, I wonder how testing would work. I tested this by plugging in my
mouse and fiddling around with /sys/bus/usb/drivers/rust_driver_usb/new_id. I
am not sure how this is going to work once I start looking into data transfer
and etc. Perhaps there's a simple device out there that I should target? Or
maybe there's a way to "fake" a USB device that would work with the sample
driver for demonstration purposes.

-- Daniel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] samples: rust: add a USB driver sample
  2025-09-06 12:41         ` Daniel Almeida
@ 2025-09-06 13:07           ` Greg Kroah-Hartman
  2025-09-06 14:49             ` Alan Stern
  2025-09-06 14:56             ` Daniel Almeida
  2025-09-06 13:22           ` Danilo Krummrich
  1 sibling, 2 replies; 18+ messages in thread
From: Greg Kroah-Hartman @ 2025-09-06 13:07 UTC (permalink / raw)
  To: Daniel Almeida
  Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, linux-kernel, rust-for-linux,
	linux-usb

On Sat, Sep 06, 2025 at 09:41:16AM -0300, Daniel Almeida wrote:
> 
> 
> >> 
> >> I thought that an iterative approach would work here, i.e.: merge this, then
> >> URBs, then more stuff, etc.
> > 
> > Ah, that makes sense, I didn't realize you want that here.  What USB
> > device do you want to write a rust driver for?  Are you going to need
> > bindings to the usb major number, or is it going to talk to some other
> > subsystem instead?
> > 
> > Right now, these bindings don't really do anything USB specific at all
> > except allow a driver to bind to a device.
> > 
> > thanks,
> > 
> > greg k-h
> 
> To be honest, I'm trying to pave the way for others.
> 
> I often hear people saying that they would look into Rust drivers if only they
> did not have to write all the surrounding infrastructure themselves. On the
> other hand, there is no infrastructure because there are no drivers. It's a
> chicken and egg problem that I am trying to solve.

Sure, but a framework like this (probe/disconnect), really isn't USB,
it's just driver core stuff :)

> It's also a cool opportunity to learn about USB, but I don't have any plans
> for a driver at the moment other than a instructional sample driver in Rust.

Then let's not add bindings without a real user please.  We don't want
to maintain them for no good reason.

> Give me a few more weeks and I'll come up with the code for the other things
> you've pointed out.
> 
> By the way, I wonder how testing would work. I tested this by plugging in my
> mouse and fiddling around with /sys/bus/usb/drivers/rust_driver_usb/new_id. I
> am not sure how this is going to work once I start looking into data transfer
> and etc. Perhaps there's a simple device out there that I should target? Or
> maybe there's a way to "fake" a USB device that would work with the sample
> driver for demonstration purposes.

You can use the usb-gadget subsystem and dummy-hcd to create a loop-back
for a virtual USB device.  That's how syzbot does USB driver fuzz
testing, there should be some documentation on that somewhere in the
tree.

thanks

greg k-h

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] samples: rust: add a USB driver sample
  2025-09-06 12:41         ` Daniel Almeida
  2025-09-06 13:07           ` Greg Kroah-Hartman
@ 2025-09-06 13:22           ` Danilo Krummrich
  2025-09-06 14:50             ` Daniel Almeida
  1 sibling, 1 reply; 18+ messages in thread
From: Danilo Krummrich @ 2025-09-06 13:22 UTC (permalink / raw)
  To: Daniel Almeida
  Cc: Greg Kroah-Hartman, Miguel Ojeda, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, linux-kernel, rust-for-linux, linux-usb

On Sat Sep 6, 2025 at 2:41 PM CEST, Daniel Almeida wrote:
>>> 
>>> I thought that an iterative approach would work here, i.e.: merge this, then
>>> URBs, then more stuff, etc.
>> 
>> Ah, that makes sense, I didn't realize you want that here.  What USB
>> device do you want to write a rust driver for?  Are you going to need
>> bindings to the usb major number, or is it going to talk to some other
>> subsystem instead?
>> 
>> Right now, these bindings don't really do anything USB specific at all
>> except allow a driver to bind to a device.
>> 
>> thanks,
>> 
>> greg k-h
>
> To be honest, I'm trying to pave the way for others.
>
> I often hear people saying that they would look into Rust drivers if only they
> did not have to write all the surrounding infrastructure themselves. On the
> other hand, there is no infrastructure because there are no drivers.

I think saying that there is no infrastructure for writing Rust drivers is not
accurate:

We already have lots of infrastructure in place, such as device / driver core
infrastructure, PCI, platform (with OF and ACPI), faux and auxilirary bus
infrastructure, I/O, workqueues, timekeeping, cpufreq, firmware, DMA and a lot
more.

Not to forget the absolute core primitives, such as kernel allocators, xarray,
locking infrastructure or very recently maple tree and LKMM atomics.

Besides that we also have a lot of infrastructure that we do not have in C
because it's simply not possible or applicable.

However, it is in fact true that there is no USB infrastructure yet.

> It's a chicken and egg problem that I am trying to solve.

This is exactly why we develop Nova in-tree, such that we have a justification
for adding all this infrastructure.

Lot's of the stuff I listed above originates from that and I think the Nova
project has proven that we can break this chicken and egg problem. I think
one proof for that is that Tyr follows the approach.

However, I agree that it still remains that someone (i.e. some driver) has to
take the burden of doing the "heavy lifting" for a particular subsystem.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] samples: rust: add a USB driver sample
  2025-09-06 13:07           ` Greg Kroah-Hartman
@ 2025-09-06 14:49             ` Alan Stern
  2025-09-06 14:56             ` Daniel Almeida
  1 sibling, 0 replies; 18+ messages in thread
From: Alan Stern @ 2025-09-06 14:49 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Daniel Almeida, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, linux-kernel, rust-for-linux,
	linux-usb

On Sat, Sep 06, 2025 at 03:07:16PM +0200, Greg Kroah-Hartman wrote:
> On Sat, Sep 06, 2025 at 09:41:16AM -0300, Daniel Almeida wrote:
> > By the way, I wonder how testing would work. I tested this by plugging in my
> > mouse and fiddling around with /sys/bus/usb/drivers/rust_driver_usb/new_id. I
> > am not sure how this is going to work once I start looking into data transfer
> > and etc. Perhaps there's a simple device out there that I should target? Or
> > maybe there's a way to "fake" a USB device that would work with the sample
> > driver for demonstration purposes.
> 
> You can use the usb-gadget subsystem and dummy-hcd to create a loop-back
> for a virtual USB device.  That's how syzbot does USB driver fuzz
> testing, there should be some documentation on that somewhere in the
> tree.

Gadget zero is a good one to use for testing.  That's what it's meant 
for.  If you need any help setting it up, just ask.

Alan Stern

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] samples: rust: add a USB driver sample
  2025-09-06 13:22           ` Danilo Krummrich
@ 2025-09-06 14:50             ` Daniel Almeida
  2025-09-06 15:22               ` Danilo Krummrich
  0 siblings, 1 reply; 18+ messages in thread
From: Daniel Almeida @ 2025-09-06 14:50 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: Greg Kroah-Hartman, Miguel Ojeda, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, linux-kernel, rust-for-linux, linux-usb

Hi Danilo,

> On 6 Sep 2025, at 10:22, Danilo Krummrich <dakr@kernel.org> wrote:
> 
> On Sat Sep 6, 2025 at 2:41 PM CEST, Daniel Almeida wrote:
>>>> 
>>>> I thought that an iterative approach would work here, i.e.: merge this, then
>>>> URBs, then more stuff, etc.
>>> 
>>> Ah, that makes sense, I didn't realize you want that here.  What USB
>>> device do you want to write a rust driver for?  Are you going to need
>>> bindings to the usb major number, or is it going to talk to some other
>>> subsystem instead?
>>> 
>>> Right now, these bindings don't really do anything USB specific at all
>>> except allow a driver to bind to a device.
>>> 
>>> thanks,
>>> 
>>> greg k-h
>> 
>> To be honest, I'm trying to pave the way for others.
>> 
>> I often hear people saying that they would look into Rust drivers if only they
>> did not have to write all the surrounding infrastructure themselves. On the
>> other hand, there is no infrastructure because there are no drivers.
> 
> I think saying that there is no infrastructure for writing Rust drivers is not
> accurate:
> 
> We already have lots of infrastructure in place, such as device / driver core
> infrastructure, PCI, platform (with OF and ACPI), faux and auxilirary bus
> infrastructure, I/O, workqueues, timekeeping, cpufreq, firmware, DMA and a lot
> more.
> 
> Not to forget the absolute core primitives, such as kernel allocators, xarray,
> locking infrastructure or very recently maple tree and LKMM atomics.
> 
> Besides that we also have a lot of infrastructure that we do not have in C
> because it's simply not possible or applicable.
> 
> However, it is in fact true that there is no USB infrastructure yet.

Ah yes, of course there’s plenty of things but this is specifically about
USB. I worked on a few of those so I'm not denying them, I guess I should have
written this more clearly :)

I’ve also been told the same about media drivers. For example, someone
trying to write a USB media driver stares at work needed to just _start_ doing
what they had initially planned and simply gives up. It creates a scenario
where people continuously wait on each other to do the "heavy work", i.e.: to
come up with the common code/abstractions.

So far I see a pattern where sample drivers count as users. This has been the
case, for example, for rust_dma.rs. I was under the impression that the same
would apply here. Although I do realize that there were plans for dma code
other than rust_dma.rs, of course.

> 
>> It's a chicken and egg problem that I am trying to solve.
> 
> This is exactly why we develop Nova in-tree, such that we have a justification
> for adding all this infrastructure.
> 
> Lot's of the stuff I listed above originates from that and I think the Nova
> project has proven that we can break this chicken and egg problem. I think
> one proof for that is that Tyr follows the approach.
> 
> However, I agree that it still remains that someone (i.e. some driver) has to
> take the burden of doing the "heavy lifting" for a particular subsystem.

As for Nova and Tyr, these are projects with a lot of big companies involved.

They were able to break this chicken and egg situation in part due to that,
because companies were willing to allocate engineers for both the drivers _and_
the required infrastructure. Unless the same can be said for USB, media or any
other subsystems, I don't see it happening. Also, even if there is a company
interested, smaller ones are not willing to work on the infrastructure either,
only on the actual end results (i.e.: drivers).

That's just my humble opinion, of course.



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] samples: rust: add a USB driver sample
  2025-09-06 13:07           ` Greg Kroah-Hartman
  2025-09-06 14:49             ` Alan Stern
@ 2025-09-06 14:56             ` Daniel Almeida
  1 sibling, 0 replies; 18+ messages in thread
From: Daniel Almeida @ 2025-09-06 14:56 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, linux-kernel, rust-for-linux,
	linux-usb



> On 6 Sep 2025, at 10:07, Greg Kroah-Hartman <gregkh@linuxfoundation.org> wrote:
> 
> On Sat, Sep 06, 2025 at 09:41:16AM -0300, Daniel Almeida wrote:
>> 
>> 
>>>> 
>>>> I thought that an iterative approach would work here, i.e.: merge this, then
>>>> URBs, then more stuff, etc.
>>> 
>>> Ah, that makes sense, I didn't realize you want that here.  What USB
>>> device do you want to write a rust driver for?  Are you going to need
>>> bindings to the usb major number, or is it going to talk to some other
>>> subsystem instead?
>>> 
>>> Right now, these bindings don't really do anything USB specific at all
>>> except allow a driver to bind to a device.
>>> 
>>> thanks,
>>> 
>>> greg k-h
>> 
>> To be honest, I'm trying to pave the way for others.
>> 
>> I often hear people saying that they would look into Rust drivers if only they
>> did not have to write all the surrounding infrastructure themselves. On the
>> other hand, there is no infrastructure because there are no drivers. It's a
>> chicken and egg problem that I am trying to solve.
> 
> Sure, but a framework like this (probe/disconnect), really isn't USB,
> it's just driver core stuff :)
> 
>> It's also a cool opportunity to learn about USB, but I don't have any plans
>> for a driver at the moment other than a instructional sample driver in Rust.
> 
> Then let's not add bindings without a real user please.  We don't want
> to maintain them for no good reason.
> 

That’s OK Greg, I totally see your point here. I guess we can shelve this
work for the time being then.

To everybody else: if anyone is willing to write USB drivers, let me know. I
will work with you to get the abstractions in place so that we have both the
abstractions and a real user.

-- Daniel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] samples: rust: add a USB driver sample
  2025-09-06 14:50             ` Daniel Almeida
@ 2025-09-06 15:22               ` Danilo Krummrich
  2025-09-06 15:46                 ` Daniel Almeida
  0 siblings, 1 reply; 18+ messages in thread
From: Danilo Krummrich @ 2025-09-06 15:22 UTC (permalink / raw)
  To: Daniel Almeida
  Cc: Greg Kroah-Hartman, Miguel Ojeda, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Michal Wilczynski, Igor Korotin,
	linux-kernel, rust-for-linux, linux-usb

On Sat Sep 6, 2025 at 4:50 PM CEST, Daniel Almeida wrote:
> So far I see a pattern where sample drivers count as users. This has been the
> case, for example, for rust_dma.rs. I was under the impression that the same
> would apply here. Although I do realize that there were plans for dma code
> other than rust_dma.rs, of course.

This isn't the case, we have those sample drivers to make it easy to review the
the code and illustrate in an isolated context how it works. But, there has
always been a "real" user behind that. In the case of the DMA work it was Nova.

> As for Nova and Tyr, these are projects with a lot of big companies involved.
>
> They were able to break this chicken and egg situation in part due to that,
> because companies were willing to allocate engineers for both the drivers _and_
> the required infrastructure. Unless the same can be said for USB, media or any
> other subsystems, I don't see it happening.

Well, this is true for Nova and Tyr, but I disagree that this is the reason we
were able to break the chicken and egg problem.

For instance, the initial lift around the driver core, PCI, I/O, etc.
infrastructure was done by me, a single person. This could have been happening
in the context of a very simple and small driver as well, rather than a big GPU
driver with lots of companies and people involved.

Igor (Cc) is doing the initial lift for I2C and Michal (Cc) for PWM for
instance.

So, I see those things happen and I don't think that such initial lifting
necessarily needs big companies with dozens of engineers being involved.

If we know people who want to write drivers for a subsystem that doesn't yet
have Rust infrastructure (such as USB), let's encourage them to get started /
involved anyways and let's help them as they go.

But also please don't get me wrong, I understand and very much appreciate you
want to get the ball rolling, but let's not discourage people by making it
sounds as if it would be impossible for individuals.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] samples: rust: add a USB driver sample
  2025-09-06 15:22               ` Danilo Krummrich
@ 2025-09-06 15:46                 ` Daniel Almeida
  2025-09-06 15:48                   ` Danilo Krummrich
  0 siblings, 1 reply; 18+ messages in thread
From: Daniel Almeida @ 2025-09-06 15:46 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: Greg Kroah-Hartman, Miguel Ojeda, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Michal Wilczynski, Igor Korotin,
	linux-kernel, rust-for-linux, linux-usb



> On 6 Sep 2025, at 12:22, Danilo Krummrich <dakr@kernel.org> wrote:
> 
> On Sat Sep 6, 2025 at 4:50 PM CEST, Daniel Almeida wrote:
>> So far I see a pattern where sample drivers count as users. This has been the
>> case, for example, for rust_dma.rs. I was under the impression that the same
>> would apply here. Although I do realize that there were plans for dma code
>> other than rust_dma.rs, of course.
> 
> This isn't the case, we have those sample drivers to make it easy to review the
> the code and illustrate in an isolated context how it works. But, there has
> always been a "real" user behind that. In the case of the DMA work it was Nova.

I see, thanks for clarifying!

> 
>> As for Nova and Tyr, these are projects with a lot of big companies involved.
>> 
>> They were able to break this chicken and egg situation in part due to that,
>> because companies were willing to allocate engineers for both the drivers _and_
>> the required infrastructure. Unless the same can be said for USB, media or any
>> other subsystems, I don't see it happening.
> 
> Well, this is true for Nova and Tyr, but I disagree that this is the reason we
> were able to break the chicken and egg problem.
> 
> For instance, the initial lift around the driver core, PCI, I/O, etc.
> infrastructure was done by me, a single person. This could have been happening
> in the context of a very simple and small driver as well, rather than a big GPU
> driver with lots of companies and people involved.
> 
> Igor (Cc) is doing the initial lift for I2C and Michal (Cc) for PWM for
> instance.
> 
> So, I see those things happen and I don't think that such initial lifting
> necessarily needs big companies with dozens of engineers being involved.

It’s not about the number of people, or the work being out of reach for a
single person, but more of someone asking themselves why it should be them to
do it when there’s no big project like Nova or Tyr to justify it and employ
them to do it all, vs employ them only for the actual drivers but not for the
abstractions. Or if they’re working on their free time, it becomes even
harder to justify spending energy on the abstractions if all they want is
to write a driver.

But if anyone got the impression that it is impossible to do it, my bad. It
isn’t.

> 
> If we know people who want to write drivers for a subsystem that doesn't yet
> have Rust infrastructure (such as USB), let's encourage them to get started /
> involved anyways and let's help them as they go.
> 
> But also please don't get me wrong, I understand and very much appreciate you
> want to get the ball rolling, but let's not discourage people by making it
> sounds as if it would be impossible for individuals.
> 

Yeah, point taken :)

As I said to Greg above, I’m here to help if anyone wants to write a USB
driver. Those interested are free to reach out to me and we will work together
to merge the required abstractions with a real user in mind. Hopefully this
encourages others to join in this work :)


— Daniel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] samples: rust: add a USB driver sample
  2025-09-06 15:46                 ` Daniel Almeida
@ 2025-09-06 15:48                   ` Danilo Krummrich
  0 siblings, 0 replies; 18+ messages in thread
From: Danilo Krummrich @ 2025-09-06 15:48 UTC (permalink / raw)
  To: Daniel Almeida
  Cc: Greg Kroah-Hartman, Miguel Ojeda, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Michal Wilczynski, Igor Korotin,
	linux-kernel, rust-for-linux, linux-usb

On Sat Sep 6, 2025 at 5:46 PM CEST, Daniel Almeida wrote:
> As I said to Greg above, I’m here to help if anyone wants to write a USB
> driver. Those interested are free to reach out to me and we will work together
> to merge the required abstractions with a real user in mind. Hopefully this
> encourages others to join in this work :)

Yes, that'd be great! :)

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2025-09-06 15:48 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-25 18:18 [PATCH 0/2] rust: usb: add initial USB abstractions Daniel Almeida
2025-08-25 18:18 ` [PATCH 1/2] rust: usb: add basic " Daniel Almeida
2025-08-25 20:49   ` Benno Lossin
2025-08-25 21:03     ` Daniel Almeida
2025-08-25 18:18 ` [PATCH 2/2] samples: rust: add a USB driver sample Daniel Almeida
2025-09-06 11:14   ` Greg Kroah-Hartman
2025-09-06 12:04     ` Daniel Almeida
2025-09-06 12:10       ` Greg Kroah-Hartman
2025-09-06 12:41         ` Daniel Almeida
2025-09-06 13:07           ` Greg Kroah-Hartman
2025-09-06 14:49             ` Alan Stern
2025-09-06 14:56             ` Daniel Almeida
2025-09-06 13:22           ` Danilo Krummrich
2025-09-06 14:50             ` Daniel Almeida
2025-09-06 15:22               ` Danilo Krummrich
2025-09-06 15:46                 ` Daniel Almeida
2025-09-06 15:48                   ` Danilo Krummrich
2025-08-25 20:32 ` [PATCH 0/2] rust: usb: add initial USB abstractions Greg Kroah-Hartman

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).