use crate::{
bindings,
device,
device_id::{
RawDeviceId,
RawDeviceIdIndex, },
driver,
error::{
from_result,
to_result, },
prelude::*,
sync::aref::AlwaysRefCounted,
types::Opaque,
ThisModule, };
use core::{
marker::PhantomData,
mem::{
offset_of,
MaybeUninit, },
ptr::NonNull,
};
pub struct Adapter<T: Driver>(T);
unsafe impl<T: Driver + 'static> driver::DriverLayout for Adapter<T> {
type DriverType = bindings::usb_driver;
type DriverData = T;
const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver);
}
unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
unsafe fn register(
udrv: &Opaque<Self::DriverType>,
name: &'static CStr,
module: &'static ThisModule,
) -> Result {
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();
}
to_result(unsafe {
bindings::usb_register_driver(udrv.get(), module.0, name.as_char_ptr())
})
}
unsafe fn unregister(udrv: &Opaque<Self::DriverType>) {
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 {
let intf = unsafe { &*intf.cast::<Interface<device::CoreInternal>>() };
from_result(|| {
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) {
let intf = unsafe { &*intf.cast::<Interface<device::CoreInternal>>() };
let dev: &device::Device<device::CoreInternal> = intf.as_ref();
let data = unsafe { dev.drvdata_borrow::<T>() };
T::disconnect(intf, data);
}
}
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct DeviceId(bindings::usb_device_id);
impl DeviceId {
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,
..unsafe { MaybeUninit::zeroed().assume_init() }
})
}
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,
..unsafe { MaybeUninit::zeroed().assume_init() }
})
}
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,
..unsafe { MaybeUninit::zeroed().assume_init() }
})
}
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,
..unsafe { MaybeUninit::zeroed().assume_init() }
})
}
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,
..unsafe { MaybeUninit::zeroed().assume_init() }
})
}
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,
..unsafe { MaybeUninit::zeroed().assume_init() }
})
}
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,
..unsafe { MaybeUninit::zeroed().assume_init() }
})
}
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,
..unsafe { MaybeUninit::zeroed().assume_init() }
})
}
}
unsafe impl RawDeviceId for DeviceId {
type RawType = bindings::usb_device_id;
}
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
}
}
pub type IdTable<T> = &'static dyn kernel::device_id::IdTable<DeviceId, T>;
#[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);
};
}
pub trait Driver {
type IdInfo: 'static;
const ID_TABLE: IdTable<Self::IdInfo>;
fn probe(
interface: &Interface<device::Core>,
id: &DeviceId,
id_info: &Self::IdInfo,
) -> impl PinInit<Self, Error>;
fn disconnect(interface: &Interface<device::Core>, data: Pin<&Self>);
}
#[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()
}
}
unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Interface<Ctx> {
const OFFSET: usize = offset_of!(bindings::usb_interface, dev);
}
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> {
let dev = unsafe { &raw mut ((*self.as_raw()).dev) };
unsafe { device::Device::from_raw(dev) }
}
}
impl<Ctx: device::DeviceContext> AsRef<Device> for Interface<Ctx> {
fn as_ref(&self) -> &Device {
let usb_dev = unsafe { bindings::interface_to_usbdev(self.as_raw()) };
unsafe { &*(usb_dev.cast()) }
}
}
unsafe impl AlwaysRefCounted for Interface {
fn inc_ref(&self) {
unsafe { bindings::usb_get_intf(self.as_raw()) };
}
unsafe fn dec_ref(obj: NonNull<Self>) {
unsafe { bindings::usb_put_intf(obj.cast().as_ptr()) }
}
}
unsafe impl Send for Interface {}
unsafe impl Sync for Interface {}
#[repr(transparent)]
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()
}
}
kernel::impl_device_context_deref!(unsafe { Device });
kernel::impl_device_context_into_aref!(Device);
unsafe impl AlwaysRefCounted for Device {
fn inc_ref(&self) {
unsafe { bindings::usb_get_dev(self.as_raw()) };
}
unsafe fn dec_ref(obj: NonNull<Self>) {
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> {
let dev = unsafe { &raw mut ((*self.as_raw()).dev) };
unsafe { device::Device::from_raw(dev) }
}
}
unsafe impl Send for Device {}
unsafe impl Sync for Device {}
#[macro_export]
macro_rules! module_usb_driver {
($($f:tt)*) => {
$crate::module_driver!(<T>, $crate::usb::Adapter<T>, { $($f)* });
}
}