summary refs log tree commit diff
path: root/usb_util/src/descriptor.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/descriptor.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/descriptor.rs')
-rw-r--r--usb_util/src/descriptor.rs499
1 files changed, 499 insertions, 0 deletions
diff --git a/usb_util/src/descriptor.rs b/usb_util/src/descriptor.rs
new file mode 100644
index 0000000..cf711d1
--- /dev/null
+++ b/usb_util/src/descriptor.rs
@@ -0,0 +1,499 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::types::{self, Descriptor, DescriptorHeader, EndpointDescriptor};
+use crate::{Error, Result};
+use data_model::DataInit;
+use std::collections::BTreeMap;
+use std::io::{self, Read};
+use std::mem::size_of;
+use std::ops::Deref;
+use sys_util::warn;
+
+#[derive(Clone)]
+pub struct DeviceDescriptorTree {
+    inner: types::DeviceDescriptor,
+    // Map of bConfigurationValue to ConfigDescriptor
+    config_descriptors: BTreeMap<u8, ConfigDescriptorTree>,
+}
+
+#[derive(Clone)]
+pub struct ConfigDescriptorTree {
+    inner: types::ConfigDescriptor,
+    // Map of (bInterfaceNumber, bAlternateSetting) to InterfaceDescriptor
+    interface_descriptors: BTreeMap<(u8, u8), InterfaceDescriptorTree>,
+}
+
+#[derive(Clone)]
+pub struct InterfaceDescriptorTree {
+    inner: types::InterfaceDescriptor,
+    // Map of bEndpointAddress to EndpointDescriptor
+    endpoint_descriptors: BTreeMap<u8, EndpointDescriptor>,
+}
+
+impl DeviceDescriptorTree {
+    pub fn get_config_descriptor(&self, config_value: u8) -> Option<&ConfigDescriptorTree> {
+        self.config_descriptors.get(&config_value)
+    }
+}
+
+impl Deref for DeviceDescriptorTree {
+    type Target = types::DeviceDescriptor;
+
+    fn deref(&self) -> &types::DeviceDescriptor {
+        &self.inner
+    }
+}
+
+impl ConfigDescriptorTree {
+    /// Get interface by number and alt setting.
+    pub fn get_interface_descriptor(
+        &self,
+        interface_num: u8,
+        alt_setting: u8,
+    ) -> Option<&InterfaceDescriptorTree> {
+        self.interface_descriptors
+            .get(&(interface_num, alt_setting))
+    }
+}
+
+impl Deref for ConfigDescriptorTree {
+    type Target = types::ConfigDescriptor;
+
+    fn deref(&self) -> &types::ConfigDescriptor {
+        &self.inner
+    }
+}
+
+impl InterfaceDescriptorTree {
+    pub fn get_endpoint_descriptor(&self, ep_idx: u8) -> Option<&EndpointDescriptor> {
+        self.endpoint_descriptors.get(&ep_idx)
+    }
+}
+
+impl Deref for InterfaceDescriptorTree {
+    type Target = types::InterfaceDescriptor;
+
+    fn deref(&self) -> &types::InterfaceDescriptor {
+        &self.inner
+    }
+}
+
+/// Given a `reader` for a full set of descriptors as provided by the Linux kernel
+/// usbdevfs `descriptors` file, parse the descriptors into a tree data structure.
+pub fn parse_usbfs_descriptors<R: Read>(mut reader: R) -> Result<DeviceDescriptorTree> {
+    // Given a structure of length `struct_length`, of which `bytes_consumed` have
+    // already been read, skip the remainder of the struct. If `bytes_consumed` is
+    // more than `struct_length`, no additional bytes are skipped.
+    fn skip<R: Read>(reader: R, bytes_consumed: usize, struct_length: u8) -> io::Result<u64> {
+        let bytes_to_skip = u64::from(struct_length).saturating_sub(bytes_consumed as u64);
+        io::copy(&mut reader.take(bytes_to_skip), &mut io::sink())
+    }
+
+    // Find the next descriptor of type T and return it.
+    // Any other descriptors encountered while searching for the expected type are skipped.
+    fn next_descriptor<R: Read, T: Descriptor + DataInit>(mut reader: R) -> Result<T> {
+        let desc_type = T::descriptor_type() as u8;
+        loop {
+            let hdr = DescriptorHeader::from_reader(&mut reader).map_err(Error::DescriptorRead)?;
+            if hdr.bDescriptorType == desc_type {
+                if usize::from(hdr.bLength) < size_of::<DescriptorHeader>() + size_of::<T>() {
+                    return Err(Error::DescriptorParse);
+                }
+
+                let desc = T::from_reader(&mut reader).map_err(Error::DescriptorRead)?;
+
+                // Skip any extra data beyond the standard descriptor length.
+                skip(
+                    &mut reader,
+                    size_of::<DescriptorHeader>() + size_of::<T>(),
+                    hdr.bLength,
+                )
+                .map_err(Error::DescriptorRead)?;
+                return Ok(desc);
+            }
+
+            // Skip this entire descriptor, since it's not the right type.
+            skip(&mut reader, size_of::<DescriptorHeader>(), hdr.bLength)
+                .map_err(Error::DescriptorRead)?;
+        }
+    }
+
+    let raw_device_descriptor: types::DeviceDescriptor = next_descriptor(&mut reader)?;
+    let mut device_descriptor = DeviceDescriptorTree {
+        inner: raw_device_descriptor,
+        config_descriptors: BTreeMap::new(),
+    };
+
+    for cfg_idx in 0..device_descriptor.bNumConfigurations {
+        if let Ok(raw_config_descriptor) =
+            next_descriptor::<_, types::ConfigDescriptor>(&mut reader)
+        {
+            let mut config_descriptor = ConfigDescriptorTree {
+                inner: raw_config_descriptor,
+                interface_descriptors: BTreeMap::new(),
+            };
+
+            for intf_idx in 0..config_descriptor.bNumInterfaces {
+                if let Ok(raw_interface_descriptor) =
+                    next_descriptor::<_, types::InterfaceDescriptor>(&mut reader)
+                {
+                    let mut interface_descriptor = InterfaceDescriptorTree {
+                        inner: raw_interface_descriptor,
+                        endpoint_descriptors: BTreeMap::new(),
+                    };
+
+                    for ep_idx in 0..interface_descriptor.bNumEndpoints {
+                        if let Ok(endpoint_descriptor) =
+                            next_descriptor::<_, EndpointDescriptor>(&mut reader)
+                        {
+                            interface_descriptor
+                                .endpoint_descriptors
+                                .insert(ep_idx, endpoint_descriptor);
+                        } else {
+                            warn!("Could not read endpoint descriptor {}", ep_idx);
+                            break;
+                        }
+                    }
+
+                    config_descriptor.interface_descriptors.insert(
+                        (
+                            interface_descriptor.bInterfaceNumber,
+                            interface_descriptor.bAlternateSetting,
+                        ),
+                        interface_descriptor,
+                    );
+                } else {
+                    warn!("Could not read interface descriptor {}", intf_idx);
+                    break;
+                }
+            }
+
+            device_descriptor
+                .config_descriptors
+                .insert(config_descriptor.bConfigurationValue, config_descriptor);
+        } else {
+            warn!("Could not read config descriptor {}", cfg_idx);
+            break;
+        }
+    }
+
+    Ok(device_descriptor)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    #[test]
+    fn parse_descriptors_mass_storage() {
+        let data: &[u8] = &[
+            0x12, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x81, 0x07, 0x80, 0x55, 0x10, 0x00,
+            0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x2C, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09,
+            0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, 0x00, 0x07, 0x05, 0x81, 0x02, 0x00, 0x04,
+            0x00, 0x06, 0x30, 0x0F, 0x00, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x00, 0x04, 0x00,
+            0x06, 0x30, 0x0F, 0x00, 0x00, 0x00,
+        ];
+
+        let d = parse_usbfs_descriptors(data).expect("parse_usbfs_descriptors failed");
+
+        // The seemingly-redundant u16::from() calls avoid borrows of packed fields.
+
+        assert_eq!(u16::from(d.bcdUSB), 0x03_00);
+        assert_eq!(d.bDeviceClass, 0x00);
+        assert_eq!(d.bDeviceSubClass, 0x00);
+        assert_eq!(d.bDeviceProtocol, 0x00);
+        assert_eq!(d.bMaxPacketSize0, 9);
+        assert_eq!(u16::from(d.idVendor), 0x0781);
+        assert_eq!(u16::from(d.idProduct), 0x5580);
+        assert_eq!(u16::from(d.bcdDevice), 0x00_10);
+        assert_eq!(d.iManufacturer, 1);
+        assert_eq!(d.iProduct, 2);
+        assert_eq!(d.iSerialNumber, 3);
+        assert_eq!(d.bNumConfigurations, 1);
+
+        let c = d
+            .get_config_descriptor(1)
+            .expect("could not get config descriptor 1");
+        assert_eq!(u16::from(c.wTotalLength), 44);
+        assert_eq!(c.bNumInterfaces, 1);
+        assert_eq!(c.bConfigurationValue, 1);
+        assert_eq!(c.iConfiguration, 0);
+        assert_eq!(c.bmAttributes, 0x80);
+        assert_eq!(c.bMaxPower, 50);
+
+        let i = c
+            .get_interface_descriptor(0, 0)
+            .expect("could not get interface descriptor 0 alt setting 0");
+        assert_eq!(i.bInterfaceNumber, 0);
+        assert_eq!(i.bAlternateSetting, 0);
+        assert_eq!(i.bNumEndpoints, 2);
+        assert_eq!(i.bInterfaceClass, 0x08);
+        assert_eq!(i.bInterfaceSubClass, 0x06);
+        assert_eq!(i.bInterfaceProtocol, 0x50);
+        assert_eq!(i.iInterface, 0);
+
+        let e = i
+            .get_endpoint_descriptor(0)
+            .expect("could not get endpoint 0 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x81);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0400);
+        assert_eq!(e.bInterval, 0);
+
+        let e = i
+            .get_endpoint_descriptor(1)
+            .expect("could not get endpoint 1 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x02);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0400);
+        assert_eq!(e.bInterval, 0);
+    }
+
+    #[test]
+    fn parse_descriptors_servo() {
+        let data: &[u8] = &[
+            0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0xd1, 0x18, 0x1b, 0x50, 0x00, 0x01,
+            0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x7c, 0x00, 0x06, 0x01, 0x04, 0xc0, 0xfa, 0x09,
+            0x04, 0x00, 0x00, 0x02, 0xff, 0x50, 0x01, 0x06, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00,
+            0x0a, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x02, 0x00, 0x02, 0xff,
+            0x52, 0x01, 0x05, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x0a, 0x07, 0x05, 0x03, 0x02,
+            0x40, 0x00, 0x00, 0x09, 0x04, 0x03, 0x00, 0x02, 0xff, 0x50, 0x01, 0x07, 0x07, 0x05,
+            0x84, 0x02, 0x10, 0x00, 0x0a, 0x07, 0x05, 0x04, 0x02, 0x10, 0x00, 0x00, 0x09, 0x04,
+            0x04, 0x00, 0x02, 0xff, 0x50, 0x01, 0x08, 0x07, 0x05, 0x85, 0x02, 0x10, 0x00, 0x0a,
+            0x07, 0x05, 0x05, 0x02, 0x10, 0x00, 0x00, 0x09, 0x04, 0x05, 0x00, 0x02, 0xff, 0x53,
+            0xff, 0x09, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x0a, 0x07, 0x05, 0x06, 0x02, 0x40,
+            0x00, 0x00,
+        ];
+
+        // Note: configuration 1 has bNumInterfaces == 6, but it actually only contains 5
+        // interface descriptors. This causes us to try to read beyond EOF, which should be
+        // silently ignored by parse_usbfs_descriptors so that we can use the rest of the
+        // descriptors.
+        let d = parse_usbfs_descriptors(data).expect("parse_usbfs_descriptors failed");
+
+        // The seemingly-redundant u16::from() calls avoid borrows of packed fields.
+
+        assert_eq!(u16::from(d.bcdUSB), 0x02_00);
+        assert_eq!(d.bDeviceClass, 0x00);
+        assert_eq!(d.bDeviceSubClass, 0x00);
+        assert_eq!(d.bDeviceProtocol, 0x00);
+        assert_eq!(d.bMaxPacketSize0, 64);
+        assert_eq!(u16::from(d.idVendor), 0x18d1);
+        assert_eq!(u16::from(d.idProduct), 0x501b);
+        assert_eq!(u16::from(d.bcdDevice), 0x01_00);
+        assert_eq!(d.iManufacturer, 1);
+        assert_eq!(d.iProduct, 2);
+        assert_eq!(d.iSerialNumber, 3);
+        assert_eq!(d.bNumConfigurations, 1);
+
+        let c = d
+            .get_config_descriptor(1)
+            .expect("could not get config descriptor 1");
+        assert_eq!(u16::from(c.wTotalLength), 124);
+        assert_eq!(c.bNumInterfaces, 6);
+        assert_eq!(c.bConfigurationValue, 1);
+        assert_eq!(c.iConfiguration, 4);
+        assert_eq!(c.bmAttributes, 0xc0);
+        assert_eq!(c.bMaxPower, 250);
+
+        let i = c
+            .get_interface_descriptor(0, 0)
+            .expect("could not get interface descriptor 0 alt setting 0");
+        assert_eq!(i.bInterfaceNumber, 0);
+        assert_eq!(i.bAlternateSetting, 0);
+        assert_eq!(i.bNumEndpoints, 2);
+        assert_eq!(i.bInterfaceClass, 0xff);
+        assert_eq!(i.bInterfaceSubClass, 0x50);
+        assert_eq!(i.bInterfaceProtocol, 0x01);
+        assert_eq!(i.iInterface, 6);
+
+        let e = i
+            .get_endpoint_descriptor(0)
+            .expect("could not get endpoint 0 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x81);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0040);
+        assert_eq!(e.bInterval, 10);
+
+        let e = i
+            .get_endpoint_descriptor(1)
+            .expect("could not get endpoint 1 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x01);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0040);
+        assert_eq!(e.bInterval, 0);
+
+        let i = c
+            .get_interface_descriptor(2, 0)
+            .expect("could not get interface descriptor 2 alt setting 0");
+        assert_eq!(i.bInterfaceNumber, 2);
+        assert_eq!(i.bAlternateSetting, 0);
+        assert_eq!(i.bNumEndpoints, 2);
+        assert_eq!(i.bInterfaceClass, 0xff);
+        assert_eq!(i.bInterfaceSubClass, 0x52);
+        assert_eq!(i.bInterfaceProtocol, 0x01);
+        assert_eq!(i.iInterface, 5);
+
+        let e = i
+            .get_endpoint_descriptor(0)
+            .expect("could not get endpoint 0 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x83);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0040);
+        assert_eq!(e.bInterval, 10);
+
+        let e = i
+            .get_endpoint_descriptor(1)
+            .expect("could not get endpoint 1 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x03);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0040);
+        assert_eq!(e.bInterval, 0);
+
+        let i = c
+            .get_interface_descriptor(3, 0)
+            .expect("could not get interface descriptor 3 alt setting 0");
+        assert_eq!(i.bInterfaceNumber, 3);
+        assert_eq!(i.bAlternateSetting, 0);
+        assert_eq!(i.bNumEndpoints, 2);
+        assert_eq!(i.bInterfaceClass, 0xff);
+        assert_eq!(i.bInterfaceSubClass, 0x50);
+        assert_eq!(i.bInterfaceProtocol, 0x01);
+        assert_eq!(i.iInterface, 7);
+
+        let e = i
+            .get_endpoint_descriptor(0)
+            .expect("could not get endpoint 0 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x84);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0010);
+        assert_eq!(e.bInterval, 10);
+
+        let e = i
+            .get_endpoint_descriptor(1)
+            .expect("could not get endpoint 1 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x04);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0010);
+        assert_eq!(e.bInterval, 0);
+
+        let i = c
+            .get_interface_descriptor(4, 0)
+            .expect("could not get interface descriptor 4 alt setting 0");
+        assert_eq!(i.bInterfaceNumber, 4);
+        assert_eq!(i.bAlternateSetting, 0);
+        assert_eq!(i.bNumEndpoints, 2);
+        assert_eq!(i.bInterfaceClass, 0xff);
+        assert_eq!(i.bInterfaceSubClass, 0x50);
+        assert_eq!(i.bInterfaceProtocol, 0x01);
+        assert_eq!(i.iInterface, 8);
+
+        let e = i
+            .get_endpoint_descriptor(0)
+            .expect("could not get endpoint 0 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x85);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0010);
+        assert_eq!(e.bInterval, 10);
+
+        let e = i
+            .get_endpoint_descriptor(1)
+            .expect("could not get endpoint 1 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x05);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0010);
+        assert_eq!(e.bInterval, 0);
+
+        let i = c
+            .get_interface_descriptor(5, 0)
+            .expect("could not get interface descriptor 5 alt setting 0");
+        assert_eq!(i.bInterfaceNumber, 5);
+        assert_eq!(i.bAlternateSetting, 0);
+        assert_eq!(i.bNumEndpoints, 2);
+        assert_eq!(i.bInterfaceClass, 0xff);
+        assert_eq!(i.bInterfaceSubClass, 0x53);
+        assert_eq!(i.bInterfaceProtocol, 0xff);
+        assert_eq!(i.iInterface, 9);
+
+        let e = i
+            .get_endpoint_descriptor(0)
+            .expect("could not get endpoint 0 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x86);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0040);
+        assert_eq!(e.bInterval, 10);
+
+        let e = i
+            .get_endpoint_descriptor(1)
+            .expect("could not get endpoint 1 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x06);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0040);
+        assert_eq!(e.bInterval, 0);
+    }
+
+    #[test]
+    fn parse_descriptors_adb() {
+        let data: &[u8] = &[
+            0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0xd1, 0x18, 0xe7, 0x4e, 0x10, 0x03,
+            0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0xfa, 0x09,
+            0x04, 0x00, 0x00, 0x02, 0xff, 0x42, 0x01, 0x05, 0x07, 0x05, 0x01, 0x02, 0x00, 0x02,
+            0x00, 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00,
+        ];
+
+        let d = parse_usbfs_descriptors(data).expect("parse_usbfs_descriptors failed");
+
+        // The seemingly-redundant u16::from() calls avoid borrows of packed fields.
+
+        assert_eq!(u16::from(d.bcdUSB), 0x02_00);
+        assert_eq!(d.bDeviceClass, 0x00);
+        assert_eq!(d.bDeviceSubClass, 0x00);
+        assert_eq!(d.bDeviceProtocol, 0x00);
+        assert_eq!(d.bMaxPacketSize0, 64);
+        assert_eq!(u16::from(d.idVendor), 0x18d1);
+        assert_eq!(u16::from(d.idProduct), 0x4ee7);
+        assert_eq!(u16::from(d.bcdDevice), 0x03_10);
+        assert_eq!(d.iManufacturer, 1);
+        assert_eq!(d.iProduct, 2);
+        assert_eq!(d.iSerialNumber, 3);
+        assert_eq!(d.bNumConfigurations, 1);
+
+        let c = d
+            .get_config_descriptor(1)
+            .expect("could not get config descriptor 1");
+        assert_eq!(u16::from(c.wTotalLength), 32);
+        assert_eq!(c.bNumInterfaces, 1);
+        assert_eq!(c.bConfigurationValue, 1);
+        assert_eq!(c.iConfiguration, 0);
+        assert_eq!(c.bmAttributes, 0x80);
+        assert_eq!(c.bMaxPower, 250);
+
+        let i = c
+            .get_interface_descriptor(0, 0)
+            .expect("could not get interface descriptor 0 alt setting 0");
+        assert_eq!(i.bInterfaceNumber, 0);
+        assert_eq!(i.bAlternateSetting, 0);
+        assert_eq!(i.bNumEndpoints, 2);
+        assert_eq!(i.bInterfaceClass, 0xff);
+        assert_eq!(i.bInterfaceSubClass, 0x42);
+        assert_eq!(i.bInterfaceProtocol, 0x01);
+        assert_eq!(i.iInterface, 5);
+
+        let e = i
+            .get_endpoint_descriptor(0)
+            .expect("could not get endpoint 0 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x01);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x200);
+        assert_eq!(e.bInterval, 0);
+
+        let e = i
+            .get_endpoint_descriptor(1)
+            .expect("could not get endpoint 1 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x81);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0200);
+        assert_eq!(e.bInterval, 0);
+    }
+}