From 81066162c240f45fbed96ca868d69c91a40bfb0e Mon Sep 17 00:00:00 2001 From: Jingkui Wang Date: Fri, 2 Nov 2018 00:09:31 -0700 Subject: [PATCH] usb_util: Add descriptors add config descriptors, endpoint descriptors, interface descriptors. BUG=chromium:831850 TEST=cargo test CQ-DEPEND=CL:1135783 Change-Id: If74c407f198725bdc6a3096b03d6fe02dcd29ec8 Reviewed-on: https://chromium-review.googlesource.com/1299716 Commit-Ready: Jingkui Wang Tested-by: Jingkui Wang Reviewed-by: Jingkui Wang --- usb_util/src/config_descriptor.rs | 36 +++++++++++++++++- usb_util/src/endpoint_descriptor.rs | 56 ++++++++++++++++++++++++++++ usb_util/src/interface_descriptor.rs | 39 +++++++++++++++++++ usb_util/src/lib.rs | 2 + 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 usb_util/src/endpoint_descriptor.rs create mode 100644 usb_util/src/interface_descriptor.rs diff --git a/usb_util/src/config_descriptor.rs b/usb_util/src/config_descriptor.rs index 37bd7d6f9d..debfcb315a 100644 --- a/usb_util/src/config_descriptor.rs +++ b/usb_util/src/config_descriptor.rs @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +use super::interface_descriptor::InterfaceDescriptor; use bindings; use bindings::libusb_config_descriptor; +use std::ops::Deref; /// ConfigDescriptor wraps libusb_config_descriptor. -/// TODO(jkwang) Add utility functions to make ConfigDescriptor actually useful. pub struct ConfigDescriptor { descriptor: *mut libusb_config_descriptor, } @@ -29,4 +30,37 @@ impl ConfigDescriptor { assert!(!descriptor.is_null()); ConfigDescriptor { descriptor } } + + /// Get interface by number and alt setting. + pub fn get_interface_descriptor( + &self, + interface_num: u8, + alt_setting: i32, + ) -> Option { + let config_descriptor = self.deref(); + if interface_num >= config_descriptor.bNumInterfaces { + return None; + } + // Safe because interface num is checked. + let interface = unsafe { &*(config_descriptor.interface.offset(interface_num as isize)) }; + + if alt_setting >= interface.num_altsetting { + return None; + } + // Safe because setting num is checked. + unsafe { + Some(InterfaceDescriptor::new( + &*(interface.altsetting.offset(alt_setting as isize)), + )) + } + } +} + +impl Deref for ConfigDescriptor { + type Target = libusb_config_descriptor; + + fn deref(&self) -> &libusb_config_descriptor { + // Safe because 'self.descriptor' is valid. + unsafe { &*(self.descriptor) } + } } diff --git a/usb_util/src/endpoint_descriptor.rs b/usb_util/src/endpoint_descriptor.rs new file mode 100644 index 0000000000..e8d328a49a --- /dev/null +++ b/usb_util/src/endpoint_descriptor.rs @@ -0,0 +1,56 @@ +// Copyright 2018 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 super::types::{EndpointDirection, EndpointType}; +use bindings::libusb_endpoint_descriptor; +use std::ops::Deref; + +/// ConfigDescriptor wraps libusb_interface_descriptor. +pub struct EndpointDescriptor<'a>(&'a libusb_endpoint_descriptor); + +const ENDPOINT_DESCRIPTOR_DIRECTION_MASK: u8 = 1 << 7; +const ENDPOINT_DESCRIPTOR_NUMBER_MASK: u8 = 0xf; +const ENDPOINT_DESCRIPTOR_ATTRIBUTES_TYPE_MASK: u8 = 0x3; + +impl<'a> EndpointDescriptor<'a> { + // Create new endpoint descriptor. + pub fn new(descriptor: &libusb_endpoint_descriptor) -> EndpointDescriptor { + EndpointDescriptor(descriptor) + } + + // Get direction of this endpoint. + pub fn get_direction(&self) -> EndpointDirection { + let direction = self.0.bEndpointAddress & ENDPOINT_DESCRIPTOR_DIRECTION_MASK; + if direction > 0 { + EndpointDirection::DeviceToHost + } else { + EndpointDirection::HostToDevice + } + } + + // Get endpoint number. + pub fn get_endpoint_number(&self) -> u8 { + self.0.bEndpointAddress & ENDPOINT_DESCRIPTOR_NUMBER_MASK + } + + // Get endpoint type. + pub fn get_endpoint_type(&self) -> Option { + let ep_type = self.0.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, + } + } +} + +impl<'a> Deref for EndpointDescriptor<'a> { + type Target = libusb_endpoint_descriptor; + + fn deref(&self) -> &libusb_endpoint_descriptor { + self.0 + } +} diff --git a/usb_util/src/interface_descriptor.rs b/usb_util/src/interface_descriptor.rs new file mode 100644 index 0000000000..08b270497e --- /dev/null +++ b/usb_util/src/interface_descriptor.rs @@ -0,0 +1,39 @@ +// Copyright 2018 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 super::endpoint_descriptor::EndpointDescriptor; +use bindings::libusb_interface_descriptor; +use std::ops::Deref; + +/// ConfigDescriptor wraps libusb_interface_descriptor. +pub struct InterfaceDescriptor<'a>(&'a libusb_interface_descriptor); + +impl<'a> InterfaceDescriptor<'a> { + /// Create a new Interface descriptor. + pub fn new(descriptor: &'a libusb_interface_descriptor) -> InterfaceDescriptor<'a> { + InterfaceDescriptor(descriptor) + } + + /// Get endpoint descriptor at index. + pub fn endpoint_descriptor(&self, ep_idx: u8) -> Option { + if ep_idx >= self.0.bNumEndpoints { + return None; + } + + // Safe because idx is checked. + unsafe { + Some(EndpointDescriptor::new( + &*(self.0.endpoint.offset(ep_idx as isize)), + )) + } + } +} + +impl<'a> Deref for InterfaceDescriptor<'a> { + type Target = libusb_interface_descriptor; + + fn deref(&self) -> &libusb_interface_descriptor { + self.0 + } +} diff --git a/usb_util/src/lib.rs b/usb_util/src/lib.rs index 0860d71ab5..a0170f3b89 100644 --- a/usb_util/src/lib.rs +++ b/usb_util/src/lib.rs @@ -14,6 +14,8 @@ extern crate data_model; pub mod error; pub mod config_descriptor; pub mod device_handle; +pub mod endpoint_descriptor; +pub mod interface_descriptor; pub mod libusb_context; pub mod libusb_device; pub mod types;