summary refs log tree commit diff
path: root/usb_util/src/types.rs
diff options
context:
space:
mode:
authorDaniel Verkamp <dverkamp@chromium.org>2019-07-09 17:21:54 -0700
committerCommit Bot <commit-bot@chromium.org>2019-10-17 00:20:24 +0000
commit6494117e1766337f5d688b98bfc3df999932c3ac (patch)
tree0c8b6fd24a615ae146bb0a2d6f4d8ce332f5cc42 /usb_util/src/types.rs
parentbed8b0017d2cb283c20dc50241adb4f5b2668489 (diff)
downloadcrosvm-6494117e1766337f5d688b98bfc3df999932c3ac.tar
crosvm-6494117e1766337f5d688b98bfc3df999932c3ac.tar.gz
crosvm-6494117e1766337f5d688b98bfc3df999932c3ac.tar.bz2
crosvm-6494117e1766337f5d688b98bfc3df999932c3ac.tar.lz
crosvm-6494117e1766337f5d688b98bfc3df999932c3ac.tar.xz
crosvm-6494117e1766337f5d688b98bfc3df999932c3ac.tar.zst
crosvm-6494117e1766337f5d688b98bfc3df999932c3ac.zip
usb: replace libusb with Rust usb_util library
Drop the dependency on libusb and reimplement the host USB backend using
usb_sys to wrap the Linux usbdevfs ioctls.

This allows sandboxing to work without any dependency on libusb patches,
and it gives us the flexibility to modify and update the USB backend
without depending on an external third-party library.

BUG=chromium:987833
TEST=`adb logcat` on nami with Nexus 5 attached
TEST=deploy app to phone with Android Studio
TEST=Run EdgeTPU USB accelerator demo (including DFU mode transition)

Cq-Depend: chromium:1773695
Change-Id: I4321c2b6142caac15f48f197795a37d59d268831
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1783601
Reviewed-by: Zach Reizner <zachr@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Diffstat (limited to 'usb_util/src/types.rs')
-rw-r--r--usb_util/src/types.rs259
1 files changed, 232 insertions, 27 deletions
diff --git a/usb_util/src/types.rs b/usb_util/src/types.rs
index f40dd6c..d669dcd 100644
--- a/usb_util/src/types.rs
+++ b/usb_util/src/types.rs
@@ -7,35 +7,159 @@ use data_model::DataInit;
 
 use std::mem::size_of;
 
-use crate::bindings;
-
-/// Speed of usb device. See usb spec for more details.
-#[derive(Debug)]
-pub enum Speed {
-    /// The OS doesn't report or know the device speed.
-    Unknown,
-    /// The device is operating at low speed (1.5MBit/s).
-    Low,
-    /// The device is operating at full speed (12MBit/s).
-    Full,
-    /// The device is operating at high speed (480MBit/s).
-    High,
-    /// The device is operating at super speed (5000MBit/s).
-    Super,
-}
-
-impl From<bindings::libusb_speed> for Speed {
-    fn from(speed: bindings::libusb_speed) -> Speed {
-        match speed {
-            bindings::LIBUSB_SPEED_LOW => Speed::Low,
-            bindings::LIBUSB_SPEED_FULL => Speed::Full,
-            bindings::LIBUSB_SPEED_HIGH => Speed::High,
-            bindings::LIBUSB_SPEED_SUPER => Speed::Super,
-            _ => Speed::Unknown,
-        }
+/// Standard USB descriptor types.
+pub enum DescriptorType {
+    Device = 0x01,
+    Configuration = 0x02,
+    Interface = 0x04,
+    Endpoint = 0x05,
+}
+
+/// Trait describing USB descriptors.
+pub trait Descriptor {
+    /// Get the expected bDescriptorType value for this type of descriptor.
+    fn descriptor_type() -> DescriptorType;
+}
+
+/// Standard USB descriptor header common to all descriptor types.
+#[allow(non_snake_case)]
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C, packed)]
+pub struct DescriptorHeader {
+    pub bLength: u8,
+    pub bDescriptorType: u8,
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for DescriptorHeader {}
+
+fn _assert_descriptor_header() {
+    const_assert!(size_of::<DescriptorHeader>() == 2);
+}
+
+/// Standard USB device descriptor as defined in USB 2.0 chapter 9,
+/// not including the standard header.
+#[allow(non_snake_case)]
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C, packed)]
+pub struct DeviceDescriptor {
+    pub bcdUSB: u16,
+    pub bDeviceClass: u8,
+    pub bDeviceSubClass: u8,
+    pub bDeviceProtocol: u8,
+    pub bMaxPacketSize0: u8,
+    pub idVendor: u16,
+    pub idProduct: u16,
+    pub bcdDevice: u16,
+    pub iManufacturer: u8,
+    pub iProduct: u8,
+    pub iSerialNumber: u8,
+    pub bNumConfigurations: u8,
+}
+
+impl Descriptor for DeviceDescriptor {
+    fn descriptor_type() -> DescriptorType {
+        DescriptorType::Device
+    }
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for DeviceDescriptor {}
+
+fn _assert_device_descriptor() {
+    const_assert!(size_of::<DeviceDescriptor>() == 18 - 2);
+}
+
+/// Standard USB configuration descriptor as defined in USB 2.0 chapter 9,
+/// not including the standard header.
+#[allow(non_snake_case)]
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C, packed)]
+pub struct ConfigDescriptor {
+    pub wTotalLength: u16,
+    pub bNumInterfaces: u8,
+    pub bConfigurationValue: u8,
+    pub iConfiguration: u8,
+    pub bmAttributes: u8,
+    pub bMaxPower: u8,
+}
+
+impl Descriptor for ConfigDescriptor {
+    fn descriptor_type() -> DescriptorType {
+        DescriptorType::Configuration
+    }
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for ConfigDescriptor {}
+
+fn _assert_config_descriptor() {
+    const_assert!(size_of::<ConfigDescriptor>() == 9 - 2);
+}
+
+impl ConfigDescriptor {
+    pub fn num_interfaces(&self) -> u8 {
+        self.bNumInterfaces
+    }
+}
+
+/// Standard USB interface descriptor as defined in USB 2.0 chapter 9,
+/// not including the standard header.
+#[allow(non_snake_case)]
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C, packed)]
+pub struct InterfaceDescriptor {
+    pub bInterfaceNumber: u8,
+    pub bAlternateSetting: u8,
+    pub bNumEndpoints: u8,
+    pub bInterfaceClass: u8,
+    pub bInterfaceSubClass: u8,
+    pub bInterfaceProtocol: u8,
+    pub iInterface: u8,
+}
+
+impl Descriptor for InterfaceDescriptor {
+    fn descriptor_type() -> DescriptorType {
+        DescriptorType::Interface
+    }
+}
+
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for InterfaceDescriptor {}
+
+fn _assert_interface_descriptor() {
+    const_assert!(size_of::<InterfaceDescriptor>() == 9 - 2);
+}
+
+/// Standard USB endpoint descriptor as defined in USB 2.0 chapter 9,
+/// not including the standard header.
+#[allow(non_snake_case)]
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C, packed)]
+pub struct EndpointDescriptor {
+    pub bEndpointAddress: u8,
+    pub bmAttributes: u8,
+    pub wMaxPacketSize: u16,
+    pub bInterval: u8,
+}
+
+impl Descriptor for EndpointDescriptor {
+    fn descriptor_type() -> DescriptorType {
+        DescriptorType::Endpoint
     }
 }
 
+// Safe because it only has data and has no implicit padding.
+unsafe impl DataInit for EndpointDescriptor {}
+
+fn _assert_endpoint_descriptor() {
+    const_assert!(size_of::<EndpointDescriptor>() == 7 - 2);
+}
+
+const ENDPOINT_DESCRIPTOR_DIRECTION_MASK: u8 = 1 << 7;
+const ENDPOINT_DESCRIPTOR_NUMBER_MASK: u8 = 0xf;
+const ENDPOINT_DESCRIPTOR_ATTRIBUTES_TYPE_MASK: u8 = 0x3;
+
 /// Endpoint types.
 #[derive(PartialEq)]
 pub enum EndpointType {
@@ -54,6 +178,35 @@ pub enum EndpointDirection {
 /// Endpoint direction offset.
 pub const ENDPOINT_DIRECTION_OFFSET: u8 = 7;
 
+impl EndpointDescriptor {
+    // Get direction of this endpoint.
+    pub fn get_direction(&self) -> EndpointDirection {
+        let direction = self.bEndpointAddress & ENDPOINT_DESCRIPTOR_DIRECTION_MASK;
+        if direction != 0 {
+            EndpointDirection::DeviceToHost
+        } else {
+            EndpointDirection::HostToDevice
+        }
+    }
+
+    // Get endpoint number.
+    pub fn get_endpoint_number(&self) -> u8 {
+        self.bEndpointAddress & ENDPOINT_DESCRIPTOR_NUMBER_MASK
+    }
+
+    // Get endpoint type.
+    pub fn get_endpoint_type(&self) -> Option<EndpointType> {
+        let ep_type = self.bmAttributes & ENDPOINT_DESCRIPTOR_ATTRIBUTES_TYPE_MASK;
+        match ep_type {
+            0 => Some(EndpointType::Control),
+            1 => Some(EndpointType::Isochronous),
+            2 => Some(EndpointType::Bulk),
+            3 => Some(EndpointType::Interrupt),
+            _ => None,
+        }
+    }
+}
+
 /// Offset of data phase transfer direction.
 pub const DATA_PHASE_DIRECTION_OFFSET: u8 = 7;
 /// Bit mask of data phase transfer direction.
@@ -118,7 +271,7 @@ pub struct UsbRequestSetup {
     pub length: u16,      // wLength
 }
 
-fn _assert() {
+fn _assert_usb_request_setup() {
     const_assert!(size_of::<UsbRequestSetup>() == 8);
 }
 
@@ -194,3 +347,55 @@ impl UsbRequestSetup {
         }
     }
 }
+
+/// Construct a bmRequestType value for a control request.
+pub fn control_request_type(
+    type_: ControlRequestType,
+    dir: ControlRequestDataPhaseTransferDirection,
+    recipient: ControlRequestRecipient,
+) -> u8 {
+    ((type_ as u8) << CONTROL_REQUEST_TYPE_OFFSET)
+        | ((dir as u8) << DATA_PHASE_DIRECTION_OFFSET)
+        | (recipient as u8)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn control_request_types() {
+        assert_eq!(
+            control_request_type(
+                ControlRequestType::Standard,
+                ControlRequestDataPhaseTransferDirection::HostToDevice,
+                ControlRequestRecipient::Device
+            ),
+            0b0_00_00000
+        );
+        assert_eq!(
+            control_request_type(
+                ControlRequestType::Standard,
+                ControlRequestDataPhaseTransferDirection::DeviceToHost,
+                ControlRequestRecipient::Device
+            ),
+            0b1_00_00000
+        );
+        assert_eq!(
+            control_request_type(
+                ControlRequestType::Standard,
+                ControlRequestDataPhaseTransferDirection::HostToDevice,
+                ControlRequestRecipient::Interface
+            ),
+            0b0_00_00001
+        );
+        assert_eq!(
+            control_request_type(
+                ControlRequestType::Class,
+                ControlRequestDataPhaseTransferDirection::HostToDevice,
+                ControlRequestRecipient::Device
+            ),
+            0b0_01_00000
+        );
+    }
+}