blob: d669dcdf76f0cd52dc0b9b35eb5dcda7a07d9cd4 [file] [log] [blame]
// 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 assertions::const_assert;
use data_model::DataInit;
use std::mem::size_of;
/// 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 {
Control,
Isochronous,
Bulk,
Interrupt,
}
/// Endpoint Directions.
#[derive(PartialEq, Clone, Copy)]
pub enum EndpointDirection {
HostToDevice = 0,
DeviceToHost = 1,
}
/// 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.
pub const DATA_PHASE_DIRECTION: u8 = 1u8 << DATA_PHASE_DIRECTION_OFFSET;
// Types of data phase transfer directions.
#[derive(Copy, Clone, PartialEq)]
pub enum ControlRequestDataPhaseTransferDirection {
HostToDevice = 0,
DeviceToHost = 1,
}
/// Offset of control request type.
pub const CONTROL_REQUEST_TYPE_OFFSET: u8 = 5;
/// Bit mask of control request type.
pub const CONTROL_REQUEST_TYPE: u8 = 0b11 << CONTROL_REQUEST_TYPE_OFFSET;
/// Request types.
#[derive(PartialEq)]
pub enum ControlRequestType {
Standard = 0,
Class = 1,
Vendor = 2,
Reserved = 3,
}
/// Recipient type bits.
pub const REQUEST_RECIPIENT_TYPE: u8 = 0b1111;
/// Recipient type of control request.
#[derive(PartialEq)]
pub enum ControlRequestRecipient {
Device = 0,
Interface = 1,
Endpoint = 2,
Other = 3,
Reserved,
}
/// Standard request defined in usb spec.
#[derive(PartialEq)]
pub enum StandardControlRequest {
GetStatus = 0x00,
ClearFeature = 0x01,
SetFeature = 0x03,
SetAddress = 0x05,
GetDescriptor = 0x06,
SetDescriptor = 0x07,
GetConfiguration = 0x08,
SetConfiguration = 0x09,
GetInterface = 0x0a,
SetInterface = 0x11,
SynchFrame = 0x12,
}
/// RequestSetup is first part of control transfer buffer.
#[repr(C, packed)]
#[derive(Copy, Clone, Debug)]
pub struct UsbRequestSetup {
// USB Device Request. USB spec. rev. 2.0 9.3
pub request_type: u8, // bmRequestType
pub request: u8, // bRequest
pub value: u16, // wValue
pub index: u16, // wIndex
pub length: u16, // wLength
}
fn _assert_usb_request_setup() {
const_assert!(size_of::<UsbRequestSetup>() == 8);
}
unsafe impl DataInit for UsbRequestSetup {}
impl UsbRequestSetup {
pub fn new(
request_type: u8,
request: u8,
value: u16,
index: u16,
length: u16,
) -> UsbRequestSetup {
UsbRequestSetup {
request_type,
request,
value,
index,
length,
}
}
/// Get type of request.
pub fn get_type(&self) -> ControlRequestType {
let ty = (self.request_type & CONTROL_REQUEST_TYPE) >> CONTROL_REQUEST_TYPE_OFFSET;
match ty {
0 => ControlRequestType::Standard,
1 => ControlRequestType::Class,
2 => ControlRequestType::Vendor,
_ => ControlRequestType::Reserved,
}
}
/// Get request direction.
pub fn get_direction(&self) -> ControlRequestDataPhaseTransferDirection {
let dir = (self.request_type & DATA_PHASE_DIRECTION) >> DATA_PHASE_DIRECTION_OFFSET;
match dir {
0 => ControlRequestDataPhaseTransferDirection::HostToDevice,
_ => ControlRequestDataPhaseTransferDirection::DeviceToHost,
}
}
/// Get recipient of this control transfer.
pub fn get_recipient(&self) -> ControlRequestRecipient {
let recipient = self.request_type & REQUEST_RECIPIENT_TYPE;
match recipient {
0 => ControlRequestRecipient::Device,
1 => ControlRequestRecipient::Interface,
2 => ControlRequestRecipient::Endpoint,
3 => ControlRequestRecipient::Other,
_ => ControlRequestRecipient::Reserved,
}
}
/// Return the type of standard control request.
pub fn get_standard_request(&self) -> Option<StandardControlRequest> {
if self.get_type() != ControlRequestType::Standard {
return None;
}
match self.request {
0x00 => Some(StandardControlRequest::GetStatus),
0x01 => Some(StandardControlRequest::ClearFeature),
0x03 => Some(StandardControlRequest::SetFeature),
0x05 => Some(StandardControlRequest::SetAddress),
0x06 => Some(StandardControlRequest::GetDescriptor),
0x07 => Some(StandardControlRequest::SetDescriptor),
0x08 => Some(StandardControlRequest::GetConfiguration),
0x09 => Some(StandardControlRequest::SetConfiguration),
0x0a => Some(StandardControlRequest::GetInterface),
0x11 => Some(StandardControlRequest::SetInterface),
0x12 => Some(StandardControlRequest::SynchFrame),
_ => None,
}
}
}
/// 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
);
}
}