1e7e2296bSDaniel Almeida // SPDX-License-Identifier: GPL-2.0 2e7e2296bSDaniel Almeida // SPDX-FileCopyrightText: Copyright (C) 2025 Collabora Ltd. 3e7e2296bSDaniel Almeida 4e7e2296bSDaniel Almeida //! Abstractions for the USB bus. 5e7e2296bSDaniel Almeida //! 6e7e2296bSDaniel Almeida //! C header: [`include/linux/usb.h`](srctree/include/linux/usb.h) 7e7e2296bSDaniel Almeida 8e7e2296bSDaniel Almeida use crate::{ 9e7e2296bSDaniel Almeida bindings, device, 10e7e2296bSDaniel Almeida device_id::{RawDeviceId, RawDeviceIdIndex}, 11e7e2296bSDaniel Almeida driver, 12e7e2296bSDaniel Almeida error::{from_result, to_result, Result}, 13e7e2296bSDaniel Almeida prelude::*, 14e7e2296bSDaniel Almeida str::CStr, 15e7e2296bSDaniel Almeida types::{AlwaysRefCounted, Opaque}, 16e7e2296bSDaniel Almeida ThisModule, 17e7e2296bSDaniel Almeida }; 18e7e2296bSDaniel Almeida use core::{marker::PhantomData, mem::MaybeUninit, ptr::NonNull}; 19e7e2296bSDaniel Almeida 20e7e2296bSDaniel Almeida /// An adapter for the registration of USB drivers. 21e7e2296bSDaniel Almeida pub struct Adapter<T: Driver>(T); 22e7e2296bSDaniel Almeida 23e7e2296bSDaniel Almeida // SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if 24e7e2296bSDaniel Almeida // a preceding call to `register` has been successful. 25e7e2296bSDaniel Almeida unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { 26e7e2296bSDaniel Almeida type RegType = bindings::usb_driver; 27e7e2296bSDaniel Almeida 28e7e2296bSDaniel Almeida unsafe fn register( 29e7e2296bSDaniel Almeida udrv: &Opaque<Self::RegType>, 30e7e2296bSDaniel Almeida name: &'static CStr, 31e7e2296bSDaniel Almeida module: &'static ThisModule, 32e7e2296bSDaniel Almeida ) -> Result { 33e7e2296bSDaniel Almeida // SAFETY: It's safe to set the fields of `struct usb_driver` on initialization. 34e7e2296bSDaniel Almeida unsafe { 35e7e2296bSDaniel Almeida (*udrv.get()).name = name.as_char_ptr(); 36e7e2296bSDaniel Almeida (*udrv.get()).probe = Some(Self::probe_callback); 37e7e2296bSDaniel Almeida (*udrv.get()).disconnect = Some(Self::disconnect_callback); 38e7e2296bSDaniel Almeida (*udrv.get()).id_table = T::ID_TABLE.as_ptr(); 39e7e2296bSDaniel Almeida } 40e7e2296bSDaniel Almeida 41e7e2296bSDaniel Almeida // SAFETY: `udrv` is guaranteed to be a valid `RegType`. 42e7e2296bSDaniel Almeida to_result(unsafe { 43e7e2296bSDaniel Almeida bindings::usb_register_driver(udrv.get(), module.0, name.as_char_ptr()) 44e7e2296bSDaniel Almeida }) 45e7e2296bSDaniel Almeida } 46e7e2296bSDaniel Almeida 47e7e2296bSDaniel Almeida unsafe fn unregister(udrv: &Opaque<Self::RegType>) { 48e7e2296bSDaniel Almeida // SAFETY: `udrv` is guaranteed to be a valid `RegType`. 49e7e2296bSDaniel Almeida unsafe { bindings::usb_deregister(udrv.get()) }; 50e7e2296bSDaniel Almeida } 51e7e2296bSDaniel Almeida } 52e7e2296bSDaniel Almeida 53e7e2296bSDaniel Almeida impl<T: Driver + 'static> Adapter<T> { 54e7e2296bSDaniel Almeida extern "C" fn probe_callback( 55e7e2296bSDaniel Almeida intf: *mut bindings::usb_interface, 56e7e2296bSDaniel Almeida id: *const bindings::usb_device_id, 57e7e2296bSDaniel Almeida ) -> kernel::ffi::c_int { 58e7e2296bSDaniel Almeida // SAFETY: The USB core only ever calls the probe callback with a valid pointer to a 59e7e2296bSDaniel Almeida // `struct usb_interface` and `struct usb_device_id`. 60e7e2296bSDaniel Almeida // 61e7e2296bSDaniel Almeida // INVARIANT: `intf` is valid for the duration of `probe_callback()`. 62e7e2296bSDaniel Almeida let intf = unsafe { &*intf.cast::<Interface<device::CoreInternal>>() }; 63e7e2296bSDaniel Almeida 64e7e2296bSDaniel Almeida from_result(|| { 65e7e2296bSDaniel Almeida // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct usb_device_id` and 66e7e2296bSDaniel Almeida // does not add additional invariants, so it's safe to transmute. 67e7e2296bSDaniel Almeida let id = unsafe { &*id.cast::<DeviceId>() }; 68e7e2296bSDaniel Almeida 69e7e2296bSDaniel Almeida let info = T::ID_TABLE.info(id.index()); 70e7e2296bSDaniel Almeida let data = T::probe(intf, id, info)?; 71e7e2296bSDaniel Almeida 72e7e2296bSDaniel Almeida let dev: &device::Device<device::CoreInternal> = intf.as_ref(); 73e7e2296bSDaniel Almeida dev.set_drvdata(data); 74e7e2296bSDaniel Almeida Ok(0) 75e7e2296bSDaniel Almeida }) 76e7e2296bSDaniel Almeida } 77e7e2296bSDaniel Almeida 78e7e2296bSDaniel Almeida extern "C" fn disconnect_callback(intf: *mut bindings::usb_interface) { 79e7e2296bSDaniel Almeida // SAFETY: The USB core only ever calls the disconnect callback with a valid pointer to a 80e7e2296bSDaniel Almeida // `struct usb_interface`. 81e7e2296bSDaniel Almeida // 82e7e2296bSDaniel Almeida // INVARIANT: `intf` is valid for the duration of `disconnect_callback()`. 83e7e2296bSDaniel Almeida let intf = unsafe { &*intf.cast::<Interface<device::CoreInternal>>() }; 84e7e2296bSDaniel Almeida 85e7e2296bSDaniel Almeida let dev: &device::Device<device::CoreInternal> = intf.as_ref(); 86e7e2296bSDaniel Almeida 87e7e2296bSDaniel Almeida // SAFETY: `disconnect_callback` is only ever called after a successful call to 88e7e2296bSDaniel Almeida // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called 89e7e2296bSDaniel Almeida // and stored a `Pin<KBox<T>>`. 90e7e2296bSDaniel Almeida let data = unsafe { dev.drvdata_obtain::<Pin<KBox<T>>>() }; 91e7e2296bSDaniel Almeida 92e7e2296bSDaniel Almeida T::disconnect(intf, data.as_ref()); 93e7e2296bSDaniel Almeida } 94e7e2296bSDaniel Almeida } 95e7e2296bSDaniel Almeida 96e7e2296bSDaniel Almeida /// Abstraction for the USB device ID structure, i.e. [`struct usb_device_id`]. 97e7e2296bSDaniel Almeida /// 98e7e2296bSDaniel Almeida /// [`struct usb_device_id`]: https://docs.kernel.org/driver-api/basics.html#c.usb_device_id 99e7e2296bSDaniel Almeida #[repr(transparent)] 100e7e2296bSDaniel Almeida #[derive(Clone, Copy)] 101e7e2296bSDaniel Almeida pub struct DeviceId(bindings::usb_device_id); 102e7e2296bSDaniel Almeida 103e7e2296bSDaniel Almeida impl DeviceId { 104e7e2296bSDaniel Almeida /// Equivalent to C's `USB_DEVICE` macro. 105e7e2296bSDaniel Almeida pub const fn from_id(vendor: u16, product: u16) -> Self { 106e7e2296bSDaniel Almeida Self(bindings::usb_device_id { 107e7e2296bSDaniel Almeida match_flags: bindings::USB_DEVICE_ID_MATCH_DEVICE as u16, 108e7e2296bSDaniel Almeida idVendor: vendor, 109e7e2296bSDaniel Almeida idProduct: product, 110e7e2296bSDaniel Almeida // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. 111e7e2296bSDaniel Almeida ..unsafe { MaybeUninit::zeroed().assume_init() } 112e7e2296bSDaniel Almeida }) 113e7e2296bSDaniel Almeida } 114e7e2296bSDaniel Almeida 115e7e2296bSDaniel Almeida /// Equivalent to C's `USB_DEVICE_VER` macro. 116e7e2296bSDaniel Almeida pub const fn from_device_ver(vendor: u16, product: u16, bcd_lo: u16, bcd_hi: u16) -> Self { 117e7e2296bSDaniel Almeida Self(bindings::usb_device_id { 118e7e2296bSDaniel Almeida match_flags: bindings::USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION as u16, 119e7e2296bSDaniel Almeida idVendor: vendor, 120e7e2296bSDaniel Almeida idProduct: product, 121e7e2296bSDaniel Almeida bcdDevice_lo: bcd_lo, 122e7e2296bSDaniel Almeida bcdDevice_hi: bcd_hi, 123e7e2296bSDaniel Almeida // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. 124e7e2296bSDaniel Almeida ..unsafe { MaybeUninit::zeroed().assume_init() } 125e7e2296bSDaniel Almeida }) 126e7e2296bSDaniel Almeida } 127e7e2296bSDaniel Almeida 128e7e2296bSDaniel Almeida /// Equivalent to C's `USB_DEVICE_INFO` macro. 129e7e2296bSDaniel Almeida pub const fn from_device_info(class: u8, subclass: u8, protocol: u8) -> Self { 130e7e2296bSDaniel Almeida Self(bindings::usb_device_id { 131e7e2296bSDaniel Almeida match_flags: bindings::USB_DEVICE_ID_MATCH_DEV_INFO as u16, 132e7e2296bSDaniel Almeida bDeviceClass: class, 133e7e2296bSDaniel Almeida bDeviceSubClass: subclass, 134e7e2296bSDaniel Almeida bDeviceProtocol: protocol, 135e7e2296bSDaniel Almeida // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. 136e7e2296bSDaniel Almeida ..unsafe { MaybeUninit::zeroed().assume_init() } 137e7e2296bSDaniel Almeida }) 138e7e2296bSDaniel Almeida } 139e7e2296bSDaniel Almeida 140e7e2296bSDaniel Almeida /// Equivalent to C's `USB_INTERFACE_INFO` macro. 141e7e2296bSDaniel Almeida pub const fn from_interface_info(class: u8, subclass: u8, protocol: u8) -> Self { 142e7e2296bSDaniel Almeida Self(bindings::usb_device_id { 143e7e2296bSDaniel Almeida match_flags: bindings::USB_DEVICE_ID_MATCH_INT_INFO as u16, 144e7e2296bSDaniel Almeida bInterfaceClass: class, 145e7e2296bSDaniel Almeida bInterfaceSubClass: subclass, 146e7e2296bSDaniel Almeida bInterfaceProtocol: protocol, 147e7e2296bSDaniel Almeida // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. 148e7e2296bSDaniel Almeida ..unsafe { MaybeUninit::zeroed().assume_init() } 149e7e2296bSDaniel Almeida }) 150e7e2296bSDaniel Almeida } 151e7e2296bSDaniel Almeida 152e7e2296bSDaniel Almeida /// Equivalent to C's `USB_DEVICE_INTERFACE_CLASS` macro. 153e7e2296bSDaniel Almeida pub const fn from_device_interface_class(vendor: u16, product: u16, class: u8) -> Self { 154e7e2296bSDaniel Almeida Self(bindings::usb_device_id { 155e7e2296bSDaniel Almeida match_flags: (bindings::USB_DEVICE_ID_MATCH_DEVICE 156e7e2296bSDaniel Almeida | bindings::USB_DEVICE_ID_MATCH_INT_CLASS) as u16, 157e7e2296bSDaniel Almeida idVendor: vendor, 158e7e2296bSDaniel Almeida idProduct: product, 159e7e2296bSDaniel Almeida bInterfaceClass: class, 160e7e2296bSDaniel Almeida // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. 161e7e2296bSDaniel Almeida ..unsafe { MaybeUninit::zeroed().assume_init() } 162e7e2296bSDaniel Almeida }) 163e7e2296bSDaniel Almeida } 164e7e2296bSDaniel Almeida 165e7e2296bSDaniel Almeida /// Equivalent to C's `USB_DEVICE_INTERFACE_PROTOCOL` macro. 166e7e2296bSDaniel Almeida pub const fn from_device_interface_protocol(vendor: u16, product: u16, protocol: u8) -> Self { 167e7e2296bSDaniel Almeida Self(bindings::usb_device_id { 168e7e2296bSDaniel Almeida match_flags: (bindings::USB_DEVICE_ID_MATCH_DEVICE 169e7e2296bSDaniel Almeida | bindings::USB_DEVICE_ID_MATCH_INT_PROTOCOL) as u16, 170e7e2296bSDaniel Almeida idVendor: vendor, 171e7e2296bSDaniel Almeida idProduct: product, 172e7e2296bSDaniel Almeida bInterfaceProtocol: protocol, 173e7e2296bSDaniel Almeida // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. 174e7e2296bSDaniel Almeida ..unsafe { MaybeUninit::zeroed().assume_init() } 175e7e2296bSDaniel Almeida }) 176e7e2296bSDaniel Almeida } 177e7e2296bSDaniel Almeida 178e7e2296bSDaniel Almeida /// Equivalent to C's `USB_DEVICE_INTERFACE_NUMBER` macro. 179e7e2296bSDaniel Almeida pub const fn from_device_interface_number(vendor: u16, product: u16, number: u8) -> Self { 180e7e2296bSDaniel Almeida Self(bindings::usb_device_id { 181e7e2296bSDaniel Almeida match_flags: (bindings::USB_DEVICE_ID_MATCH_DEVICE 182e7e2296bSDaniel Almeida | bindings::USB_DEVICE_ID_MATCH_INT_NUMBER) as u16, 183e7e2296bSDaniel Almeida idVendor: vendor, 184e7e2296bSDaniel Almeida idProduct: product, 185e7e2296bSDaniel Almeida bInterfaceNumber: number, 186e7e2296bSDaniel Almeida // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. 187e7e2296bSDaniel Almeida ..unsafe { MaybeUninit::zeroed().assume_init() } 188e7e2296bSDaniel Almeida }) 189e7e2296bSDaniel Almeida } 190e7e2296bSDaniel Almeida 191e7e2296bSDaniel Almeida /// Equivalent to C's `USB_DEVICE_AND_INTERFACE_INFO` macro. 192e7e2296bSDaniel Almeida pub const fn from_device_and_interface_info( 193e7e2296bSDaniel Almeida vendor: u16, 194e7e2296bSDaniel Almeida product: u16, 195e7e2296bSDaniel Almeida class: u8, 196e7e2296bSDaniel Almeida subclass: u8, 197e7e2296bSDaniel Almeida protocol: u8, 198e7e2296bSDaniel Almeida ) -> Self { 199e7e2296bSDaniel Almeida Self(bindings::usb_device_id { 200e7e2296bSDaniel Almeida match_flags: (bindings::USB_DEVICE_ID_MATCH_INT_INFO 201e7e2296bSDaniel Almeida | bindings::USB_DEVICE_ID_MATCH_DEVICE) as u16, 202e7e2296bSDaniel Almeida idVendor: vendor, 203e7e2296bSDaniel Almeida idProduct: product, 204e7e2296bSDaniel Almeida bInterfaceClass: class, 205e7e2296bSDaniel Almeida bInterfaceSubClass: subclass, 206e7e2296bSDaniel Almeida bInterfaceProtocol: protocol, 207e7e2296bSDaniel Almeida // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. 208e7e2296bSDaniel Almeida ..unsafe { MaybeUninit::zeroed().assume_init() } 209e7e2296bSDaniel Almeida }) 210e7e2296bSDaniel Almeida } 211e7e2296bSDaniel Almeida } 212e7e2296bSDaniel Almeida 213e7e2296bSDaniel Almeida // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `usb_device_id` and does not add 214e7e2296bSDaniel Almeida // additional invariants, so it's safe to transmute to `RawType`. 215e7e2296bSDaniel Almeida unsafe impl RawDeviceId for DeviceId { 216e7e2296bSDaniel Almeida type RawType = bindings::usb_device_id; 217e7e2296bSDaniel Almeida } 218e7e2296bSDaniel Almeida 219e7e2296bSDaniel Almeida // SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_info` field. 220e7e2296bSDaniel Almeida unsafe impl RawDeviceIdIndex for DeviceId { 221e7e2296bSDaniel Almeida const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::usb_device_id, driver_info); 222e7e2296bSDaniel Almeida 223e7e2296bSDaniel Almeida fn index(&self) -> usize { 224e7e2296bSDaniel Almeida self.0.driver_info 225e7e2296bSDaniel Almeida } 226e7e2296bSDaniel Almeida } 227e7e2296bSDaniel Almeida 228e7e2296bSDaniel Almeida /// [`IdTable`](kernel::device_id::IdTable) type for USB. 229e7e2296bSDaniel Almeida pub type IdTable<T> = &'static dyn kernel::device_id::IdTable<DeviceId, T>; 230e7e2296bSDaniel Almeida 231e7e2296bSDaniel Almeida /// Create a USB `IdTable` with its alias for modpost. 232e7e2296bSDaniel Almeida #[macro_export] 233e7e2296bSDaniel Almeida macro_rules! usb_device_table { 234e7e2296bSDaniel Almeida ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => { 235e7e2296bSDaniel Almeida const $table_name: $crate::device_id::IdArray< 236e7e2296bSDaniel Almeida $crate::usb::DeviceId, 237e7e2296bSDaniel Almeida $id_info_type, 238e7e2296bSDaniel Almeida { $table_data.len() }, 239e7e2296bSDaniel Almeida > = $crate::device_id::IdArray::new($table_data); 240e7e2296bSDaniel Almeida 241e7e2296bSDaniel Almeida $crate::module_device_table!("usb", $module_table_name, $table_name); 242e7e2296bSDaniel Almeida }; 243e7e2296bSDaniel Almeida } 244e7e2296bSDaniel Almeida 245e7e2296bSDaniel Almeida /// The USB driver trait. 246e7e2296bSDaniel Almeida /// 247e7e2296bSDaniel Almeida /// # Examples 248e7e2296bSDaniel Almeida /// 249e7e2296bSDaniel Almeida ///``` 250e7e2296bSDaniel Almeida /// # use kernel::{bindings, device::Core, usb}; 251e7e2296bSDaniel Almeida /// use kernel::prelude::*; 252e7e2296bSDaniel Almeida /// 253e7e2296bSDaniel Almeida /// struct MyDriver; 254e7e2296bSDaniel Almeida /// 255e7e2296bSDaniel Almeida /// kernel::usb_device_table!( 256e7e2296bSDaniel Almeida /// USB_TABLE, 257e7e2296bSDaniel Almeida /// MODULE_USB_TABLE, 258e7e2296bSDaniel Almeida /// <MyDriver as usb::Driver>::IdInfo, 259e7e2296bSDaniel Almeida /// [ 260e7e2296bSDaniel Almeida /// (usb::DeviceId::from_id(0x1234, 0x5678), ()), 261e7e2296bSDaniel Almeida /// (usb::DeviceId::from_id(0xabcd, 0xef01), ()), 262e7e2296bSDaniel Almeida /// ] 263e7e2296bSDaniel Almeida /// ); 264e7e2296bSDaniel Almeida /// 265e7e2296bSDaniel Almeida /// impl usb::Driver for MyDriver { 266e7e2296bSDaniel Almeida /// type IdInfo = (); 267e7e2296bSDaniel Almeida /// const ID_TABLE: usb::IdTable<Self::IdInfo> = &USB_TABLE; 268e7e2296bSDaniel Almeida /// 269e7e2296bSDaniel Almeida /// fn probe( 270e7e2296bSDaniel Almeida /// _interface: &usb::Interface<Core>, 271e7e2296bSDaniel Almeida /// _id: &usb::DeviceId, 272e7e2296bSDaniel Almeida /// _info: &Self::IdInfo, 273e7e2296bSDaniel Almeida /// ) -> Result<Pin<KBox<Self>>> { 274e7e2296bSDaniel Almeida /// Err(ENODEV) 275e7e2296bSDaniel Almeida /// } 276e7e2296bSDaniel Almeida /// 277e7e2296bSDaniel Almeida /// fn disconnect(_interface: &usb::Interface<Core>, _data: Pin<&Self>) {} 278e7e2296bSDaniel Almeida /// } 279e7e2296bSDaniel Almeida ///``` 280e7e2296bSDaniel Almeida pub trait Driver { 281e7e2296bSDaniel Almeida /// The type holding information about each one of the device ids supported by the driver. 282e7e2296bSDaniel Almeida type IdInfo: 'static; 283e7e2296bSDaniel Almeida 284e7e2296bSDaniel Almeida /// The table of device ids supported by the driver. 285e7e2296bSDaniel Almeida const ID_TABLE: IdTable<Self::IdInfo>; 286e7e2296bSDaniel Almeida 287e7e2296bSDaniel Almeida /// USB driver probe. 288e7e2296bSDaniel Almeida /// 289e7e2296bSDaniel Almeida /// Called when a new USB interface is bound to this driver. 290e7e2296bSDaniel Almeida /// Implementers should attempt to initialize the interface here. 291e7e2296bSDaniel Almeida fn probe( 292e7e2296bSDaniel Almeida interface: &Interface<device::Core>, 293e7e2296bSDaniel Almeida id: &DeviceId, 294e7e2296bSDaniel Almeida id_info: &Self::IdInfo, 295e7e2296bSDaniel Almeida ) -> Result<Pin<KBox<Self>>>; 296e7e2296bSDaniel Almeida 297e7e2296bSDaniel Almeida /// USB driver disconnect. 298e7e2296bSDaniel Almeida /// 299e7e2296bSDaniel Almeida /// Called when the USB interface is about to be unbound from this driver. 300e7e2296bSDaniel Almeida fn disconnect(interface: &Interface<device::Core>, data: Pin<&Self>); 301e7e2296bSDaniel Almeida } 302e7e2296bSDaniel Almeida 303e7e2296bSDaniel Almeida /// A USB interface. 304e7e2296bSDaniel Almeida /// 305e7e2296bSDaniel Almeida /// This structure represents the Rust abstraction for a C [`struct usb_interface`]. 306e7e2296bSDaniel Almeida /// The implementation abstracts the usage of a C [`struct usb_interface`] passed 307e7e2296bSDaniel Almeida /// in from the C side. 308e7e2296bSDaniel Almeida /// 309e7e2296bSDaniel Almeida /// # Invariants 310e7e2296bSDaniel Almeida /// 311e7e2296bSDaniel Almeida /// An [`Interface`] instance represents a valid [`struct usb_interface`] created 312e7e2296bSDaniel Almeida /// by the C portion of the kernel. 313e7e2296bSDaniel Almeida /// 314e7e2296bSDaniel Almeida /// [`struct usb_interface`]: https://www.kernel.org/doc/html/latest/driver-api/usb/usb.html#c.usb_interface 315e7e2296bSDaniel Almeida #[repr(transparent)] 316e7e2296bSDaniel Almeida pub struct Interface<Ctx: device::DeviceContext = device::Normal>( 317e7e2296bSDaniel Almeida Opaque<bindings::usb_interface>, 318e7e2296bSDaniel Almeida PhantomData<Ctx>, 319e7e2296bSDaniel Almeida ); 320e7e2296bSDaniel Almeida 321e7e2296bSDaniel Almeida impl<Ctx: device::DeviceContext> Interface<Ctx> { 322e7e2296bSDaniel Almeida fn as_raw(&self) -> *mut bindings::usb_interface { 323e7e2296bSDaniel Almeida self.0.get() 324e7e2296bSDaniel Almeida } 325e7e2296bSDaniel Almeida } 326e7e2296bSDaniel Almeida 327e7e2296bSDaniel Almeida // SAFETY: `Interface` is a transparent wrapper of a type that doesn't depend on 328e7e2296bSDaniel Almeida // `Interface`'s generic argument. 329e7e2296bSDaniel Almeida kernel::impl_device_context_deref!(unsafe { Interface }); 330e7e2296bSDaniel Almeida kernel::impl_device_context_into_aref!(Interface); 331e7e2296bSDaniel Almeida 332e7e2296bSDaniel Almeida impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Interface<Ctx> { 333e7e2296bSDaniel Almeida fn as_ref(&self) -> &device::Device<Ctx> { 334e7e2296bSDaniel Almeida // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid 335e7e2296bSDaniel Almeida // `struct usb_interface`. 336e7e2296bSDaniel Almeida let dev = unsafe { &raw mut ((*self.as_raw()).dev) }; 337e7e2296bSDaniel Almeida 338e7e2296bSDaniel Almeida // SAFETY: `dev` points to a valid `struct device`. 339e7e2296bSDaniel Almeida unsafe { device::Device::from_raw(dev) } 340e7e2296bSDaniel Almeida } 341e7e2296bSDaniel Almeida } 342e7e2296bSDaniel Almeida 343f12140f2SDanilo Krummrich impl<Ctx: device::DeviceContext> AsRef<Device> for Interface<Ctx> { 344f12140f2SDanilo Krummrich fn as_ref(&self) -> &Device { 345f12140f2SDanilo Krummrich // SAFETY: `self.as_raw()` is valid by the type invariants. 346e7e2296bSDaniel Almeida let usb_dev = unsafe { bindings::interface_to_usbdev(self.as_raw()) }; 347e7e2296bSDaniel Almeida 348f12140f2SDanilo Krummrich // SAFETY: For a valid `struct usb_interface` pointer, the above call to 349f12140f2SDanilo Krummrich // `interface_to_usbdev()` guarantees to return a valid pointer to a `struct usb_device`. 350e7e2296bSDaniel Almeida unsafe { &*(usb_dev.cast()) } 351e7e2296bSDaniel Almeida } 352e7e2296bSDaniel Almeida } 353e7e2296bSDaniel Almeida 354e7e2296bSDaniel Almeida // SAFETY: Instances of `Interface` are always reference-counted. 355e7e2296bSDaniel Almeida unsafe impl AlwaysRefCounted for Interface { 356e7e2296bSDaniel Almeida fn inc_ref(&self) { 357e7e2296bSDaniel Almeida // SAFETY: The invariants of `Interface` guarantee that `self.as_raw()` 358e7e2296bSDaniel Almeida // returns a valid `struct usb_interface` pointer, for which we will 359e7e2296bSDaniel Almeida // acquire a new refcount. 360e7e2296bSDaniel Almeida unsafe { bindings::usb_get_intf(self.as_raw()) }; 361e7e2296bSDaniel Almeida } 362e7e2296bSDaniel Almeida 363e7e2296bSDaniel Almeida unsafe fn dec_ref(obj: NonNull<Self>) { 364e7e2296bSDaniel Almeida // SAFETY: The safety requirements guarantee that the refcount is non-zero. 365e7e2296bSDaniel Almeida unsafe { bindings::usb_put_intf(obj.cast().as_ptr()) } 366e7e2296bSDaniel Almeida } 367e7e2296bSDaniel Almeida } 368e7e2296bSDaniel Almeida 369e7e2296bSDaniel Almeida // SAFETY: A `Interface` is always reference-counted and can be released from any thread. 370e7e2296bSDaniel Almeida unsafe impl Send for Interface {} 371e7e2296bSDaniel Almeida 372e7e2296bSDaniel Almeida // SAFETY: It is safe to send a &Interface to another thread because we do not 373e7e2296bSDaniel Almeida // allow any mutation through a shared reference. 374e7e2296bSDaniel Almeida unsafe impl Sync for Interface {} 375e7e2296bSDaniel Almeida 376e7e2296bSDaniel Almeida /// A USB device. 377e7e2296bSDaniel Almeida /// 378e7e2296bSDaniel Almeida /// This structure represents the Rust abstraction for a C [`struct usb_device`]. 379e7e2296bSDaniel Almeida /// The implementation abstracts the usage of a C [`struct usb_device`] passed in 380e7e2296bSDaniel Almeida /// from the C side. 381e7e2296bSDaniel Almeida /// 382e7e2296bSDaniel Almeida /// # Invariants 383e7e2296bSDaniel Almeida /// 384e7e2296bSDaniel Almeida /// A [`Device`] instance represents a valid [`struct usb_device`] created by the C portion of the 385e7e2296bSDaniel Almeida /// kernel. 386e7e2296bSDaniel Almeida /// 387e7e2296bSDaniel Almeida /// [`struct usb_device`]: https://www.kernel.org/doc/html/latest/driver-api/usb/usb.html#c.usb_device 388e7e2296bSDaniel Almeida #[repr(transparent)] 389*22d693e4SDanilo Krummrich struct Device<Ctx: device::DeviceContext = device::Normal>( 390e7e2296bSDaniel Almeida Opaque<bindings::usb_device>, 391e7e2296bSDaniel Almeida PhantomData<Ctx>, 392e7e2296bSDaniel Almeida ); 393e7e2296bSDaniel Almeida 394e7e2296bSDaniel Almeida impl<Ctx: device::DeviceContext> Device<Ctx> { 395e7e2296bSDaniel Almeida fn as_raw(&self) -> *mut bindings::usb_device { 396e7e2296bSDaniel Almeida self.0.get() 397e7e2296bSDaniel Almeida } 398e7e2296bSDaniel Almeida } 399e7e2296bSDaniel Almeida 400e7e2296bSDaniel Almeida // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic 401e7e2296bSDaniel Almeida // argument. 402e7e2296bSDaniel Almeida kernel::impl_device_context_deref!(unsafe { Device }); 403e7e2296bSDaniel Almeida kernel::impl_device_context_into_aref!(Device); 404e7e2296bSDaniel Almeida 405e7e2296bSDaniel Almeida // SAFETY: Instances of `Device` are always reference-counted. 406e7e2296bSDaniel Almeida unsafe impl AlwaysRefCounted for Device { 407e7e2296bSDaniel Almeida fn inc_ref(&self) { 408e7e2296bSDaniel Almeida // SAFETY: The invariants of `Device` guarantee that `self.as_raw()` 409e7e2296bSDaniel Almeida // returns a valid `struct usb_device` pointer, for which we will 410e7e2296bSDaniel Almeida // acquire a new refcount. 411e7e2296bSDaniel Almeida unsafe { bindings::usb_get_dev(self.as_raw()) }; 412e7e2296bSDaniel Almeida } 413e7e2296bSDaniel Almeida 414e7e2296bSDaniel Almeida unsafe fn dec_ref(obj: NonNull<Self>) { 415e7e2296bSDaniel Almeida // SAFETY: The safety requirements guarantee that the refcount is non-zero. 416e7e2296bSDaniel Almeida unsafe { bindings::usb_put_dev(obj.cast().as_ptr()) } 417e7e2296bSDaniel Almeida } 418e7e2296bSDaniel Almeida } 419e7e2296bSDaniel Almeida 420e7e2296bSDaniel Almeida impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> { 421e7e2296bSDaniel Almeida fn as_ref(&self) -> &device::Device<Ctx> { 422e7e2296bSDaniel Almeida // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid 423e7e2296bSDaniel Almeida // `struct usb_device`. 424e7e2296bSDaniel Almeida let dev = unsafe { &raw mut ((*self.as_raw()).dev) }; 425e7e2296bSDaniel Almeida 426e7e2296bSDaniel Almeida // SAFETY: `dev` points to a valid `struct device`. 427e7e2296bSDaniel Almeida unsafe { device::Device::from_raw(dev) } 428e7e2296bSDaniel Almeida } 429e7e2296bSDaniel Almeida } 430e7e2296bSDaniel Almeida 431e7e2296bSDaniel Almeida // SAFETY: A `Device` is always reference-counted and can be released from any thread. 432e7e2296bSDaniel Almeida unsafe impl Send for Device {} 433e7e2296bSDaniel Almeida 434e7e2296bSDaniel Almeida // SAFETY: It is safe to send a &Device to another thread because we do not 435e7e2296bSDaniel Almeida // allow any mutation through a shared reference. 436e7e2296bSDaniel Almeida unsafe impl Sync for Device {} 437e7e2296bSDaniel Almeida 438e7e2296bSDaniel Almeida /// Declares a kernel module that exposes a single USB driver. 439e7e2296bSDaniel Almeida /// 440e7e2296bSDaniel Almeida /// # Examples 441e7e2296bSDaniel Almeida /// 442e7e2296bSDaniel Almeida /// ```ignore 443e7e2296bSDaniel Almeida /// module_usb_driver! { 444e7e2296bSDaniel Almeida /// type: MyDriver, 445e7e2296bSDaniel Almeida /// name: "Module name", 446e7e2296bSDaniel Almeida /// author: ["Author name"], 447e7e2296bSDaniel Almeida /// description: "Description", 448e7e2296bSDaniel Almeida /// license: "GPL v2", 449e7e2296bSDaniel Almeida /// } 450e7e2296bSDaniel Almeida /// ``` 451e7e2296bSDaniel Almeida #[macro_export] 452e7e2296bSDaniel Almeida macro_rules! module_usb_driver { 453e7e2296bSDaniel Almeida ($($f:tt)*) => { 454e7e2296bSDaniel Almeida $crate::module_driver!(<T>, $crate::usb::Adapter<T>, { $($f)* }); 455e7e2296bSDaniel Almeida } 456e7e2296bSDaniel Almeida } 457