diff options
author | Jingkui Wang <jkwang@google.com> | 2018-07-18 13:26:44 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-12-25 17:55:08 -0800 |
commit | 526672672ef801d726686c0241d05c5453bb172b (patch) | |
tree | fb953c6bfcfe40da0efdf7b679afc089bd288254 /devices/src/usb | |
parent | 62affa765921321f3bba39db95b41f28b9fc4e03 (diff) | |
download | crosvm-526672672ef801d726686c0241d05c5453bb172b.tar crosvm-526672672ef801d726686c0241d05c5453bb172b.tar.gz crosvm-526672672ef801d726686c0241d05c5453bb172b.tar.bz2 crosvm-526672672ef801d726686c0241d05c5453bb172b.tar.lz crosvm-526672672ef801d726686c0241d05c5453bb172b.tar.xz crosvm-526672672ef801d726686c0241d05c5453bb172b.tar.zst crosvm-526672672ef801d726686c0241d05c5453bb172b.zip |
usb: add xhci abi.
Add xhci abi structs. BUG=chromium:831850 TEST=cargo test Change-Id: I80cf96a2bd52c1db0ebd7e6bdb90b45a5b2d03bd Reviewed-on: https://chromium-review.googlesource.com/1144264 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Tested-by: Jingkui Wang <jkwang@google.com> Reviewed-by: Dmitry Torokhov <dtor@chromium.org> Reviewed-by: Zach Reizner <zachr@chromium.org>
Diffstat (limited to 'devices/src/usb')
-rw-r--r-- | devices/src/usb/xhci/mod.rs | 4 | ||||
-rw-r--r-- | devices/src/usb/xhci/xhci_abi.rs | 513 | ||||
-rw-r--r-- | devices/src/usb/xhci/xhci_abi_schema.rs | 543 |
3 files changed, 1060 insertions, 0 deletions
diff --git a/devices/src/usb/xhci/mod.rs b/devices/src/usb/xhci/mod.rs index 6802bb7..53986d4 100644 --- a/devices/src/usb/xhci/mod.rs +++ b/devices/src/usb/xhci/mod.rs @@ -7,4 +7,8 @@ mod mmio_register; mod mmio_space; #[allow(dead_code)] +mod xhci_abi; +#[allow(dead_code)] +mod xhci_abi_schema; +#[allow(dead_code)] mod xhci_regs; diff --git a/devices/src/usb/xhci/xhci_abi.rs b/devices/src/usb/xhci/xhci_abi.rs new file mode 100644 index 0000000..16ee663 --- /dev/null +++ b/devices/src/usb/xhci/xhci_abi.rs @@ -0,0 +1,513 @@ +// 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. + +pub use super::xhci_abi_schema::*; +use data_model::DataInit; +use std; + +unsafe impl DataInit for Trb {} +unsafe impl DataInit for NormalTrb {} +unsafe impl DataInit for SetupStageTrb {} +unsafe impl DataInit for DataStageTrb {} +unsafe impl DataInit for StatusStageTrb {} +unsafe impl DataInit for IsochTrb {} +unsafe impl DataInit for LinkTrb {} +unsafe impl DataInit for EventDataTrb {} +unsafe impl DataInit for NoopTrb {} +unsafe impl DataInit for DisableSlotCommandTrb {} +unsafe impl DataInit for AddressDeviceCommandTrb {} +unsafe impl DataInit for ConfigureEndpointCommandTrb {} +unsafe impl DataInit for EvaluateContextCommandTrb {} +unsafe impl DataInit for ResetEndpointCommandTrb {} +unsafe impl DataInit for StopEndpointCommandTrb {} +unsafe impl DataInit for SetTRDequeuePointerCommandTrb {} +unsafe impl DataInit for ResetDeviceCommandTrb {} +unsafe impl DataInit for TransferEventTrb {} +unsafe impl DataInit for CommandCompletionEventTrb {} +unsafe impl DataInit for PortStatusChangeEventTrb {} +unsafe impl DataInit for EventRingSegmentTableEntry {} +unsafe impl DataInit for InputControlContext {} +unsafe impl DataInit for SlotContext {} +unsafe impl DataInit for EndpointContext {} + +unsafe impl DataInit for DeviceContext {} +unsafe impl DataInit for AddressedTrb {} + +unsafe impl TrbCast for Trb {} +unsafe impl TrbCast for NormalTrb {} +unsafe impl TrbCast for SetupStageTrb {} +unsafe impl TrbCast for DataStageTrb {} +unsafe impl TrbCast for StatusStageTrb {} +unsafe impl TrbCast for IsochTrb {} +unsafe impl TrbCast for LinkTrb {} +unsafe impl TrbCast for EventDataTrb {} +unsafe impl TrbCast for NoopTrb {} +unsafe impl TrbCast for DisableSlotCommandTrb {} +unsafe impl TrbCast for AddressDeviceCommandTrb {} +unsafe impl TrbCast for ConfigureEndpointCommandTrb {} +unsafe impl TrbCast for EvaluateContextCommandTrb {} +unsafe impl TrbCast for ResetEndpointCommandTrb {} +unsafe impl TrbCast for StopEndpointCommandTrb {} +unsafe impl TrbCast for SetTRDequeuePointerCommandTrb {} +unsafe impl TrbCast for ResetDeviceCommandTrb {} +unsafe impl TrbCast for TransferEventTrb {} +unsafe impl TrbCast for CommandCompletionEventTrb {} +unsafe impl TrbCast for PortStatusChangeEventTrb {} + +/// Associate real type of trb. +pub trait TypedTrb { + const TY: TrbType; +} + +impl TypedTrb for Trb { + const TY: TrbType = TrbType::Reserved; +} + +impl TypedTrb for NormalTrb { + const TY: TrbType = TrbType::Normal; +} + +impl TypedTrb for SetupStageTrb { + const TY: TrbType = TrbType::SetupStage; +} + +impl TypedTrb for DataStageTrb { + const TY: TrbType = TrbType::DataStage; +} + +impl TypedTrb for StatusStageTrb { + const TY: TrbType = TrbType::StatusStage; +} + +impl TypedTrb for IsochTrb { + const TY: TrbType = TrbType::Isoch; +} + +impl TypedTrb for LinkTrb { + const TY: TrbType = TrbType::Link; +} + +impl TypedTrb for EventDataTrb { + const TY: TrbType = TrbType::EventData; +} + +impl TypedTrb for NoopTrb { + const TY: TrbType = TrbType::Noop; +} + +impl TypedTrb for DisableSlotCommandTrb { + const TY: TrbType = TrbType::DisableSlotCommand; +} + +impl TypedTrb for AddressDeviceCommandTrb { + const TY: TrbType = TrbType::AddressDeviceCommand; +} + +impl TypedTrb for ConfigureEndpointCommandTrb { + const TY: TrbType = TrbType::ConfigureEndpointCommand; +} + +impl TypedTrb for EvaluateContextCommandTrb { + const TY: TrbType = TrbType::EvaluateContextCommand; +} + +impl TypedTrb for ResetEndpointCommandTrb { + const TY: TrbType = TrbType::ResetEndpointCommand; +} + +impl TypedTrb for StopEndpointCommandTrb { + const TY: TrbType = TrbType::StopEndpointCommand; +} + +impl TypedTrb for SetTRDequeuePointerCommandTrb { + const TY: TrbType = TrbType::SetTRDequeuePointerCommand; +} + +impl TypedTrb for ResetDeviceCommandTrb { + const TY: TrbType = TrbType::ResetDeviceCommand; +} + +impl TypedTrb for TransferEventTrb { + const TY: TrbType = TrbType::TransferEvent; +} + +impl TypedTrb for CommandCompletionEventTrb { + const TY: TrbType = TrbType::CommandCompletionEvent; +} + +impl TypedTrb for PortStatusChangeEventTrb { + const TY: TrbType = TrbType::PortStatusChangeEvent; +} + +/// All trb structs have the same size. One trb could be safely casted to another, though the +/// values might be invalid. +pub unsafe trait TrbCast: DataInit + TypedTrb { + fn cast<T: TrbCast>(&self) -> &T { + T::from_slice(self.as_slice()).unwrap() + } + + fn cast_mut<T: TrbCast>(&mut self) -> &mut T { + T::from_mut_slice(self.as_mut_slice()).unwrap() + } + + fn checked_cast<T: TrbCast>(&self) -> Option<&T> { + if Trb::from_slice(self.as_slice()) + .unwrap() + .trb_type() + .unwrap() + != T::TY + { + return None; + } + Some(T::from_slice(self.as_slice()).unwrap()) + } + + fn checked_mut_cast<T: TrbCast>(&mut self) -> Option<&mut T> { + if Trb::from_slice(self.as_slice()) + .unwrap() + .trb_type() + .unwrap() + != T::TY + { + return None; + } + Some(T::from_mut_slice(self.as_mut_slice()).unwrap()) + } +} + +impl Trb { + /// Get trb type. + pub fn trb_type(&self) -> Option<TrbType> { + TrbType::from_raw(self.get_trb_type()) + } + + /// Get debug string, the string will be printed with correct trb type and + /// fields. + pub fn debug_str(&self) -> String { + let trb_type = match self.trb_type() { + None => return format!("unexpected trb type: {:?}", self), + Some(t) => t, + }; + match trb_type { + TrbType::Reserved => format!("reserved trb type"), + TrbType::Normal => { + let t = self.cast::<NormalTrb>(); + format!("trb: {:?}", t) + } + TrbType::SetupStage => { + let t = self.cast::<SetupStageTrb>(); + format!("trb: {:?}", t) + } + TrbType::DataStage => { + let t = self.cast::<DataStageTrb>(); + format!("trb: {:?}", t) + } + TrbType::StatusStage => { + let t = self.cast::<StatusStageTrb>(); + format!("trb: {:?}", t) + } + TrbType::Isoch => { + let t = self.cast::<IsochTrb>(); + format!("trb: {:?}", t) + } + TrbType::Link => { + let t = self.cast::<LinkTrb>(); + format!("trb: {:?}", t) + } + TrbType::EventData => { + let t = self.cast::<EventDataTrb>(); + format!("trb: {:?}", t) + } + TrbType::Noop => { + let t = self.cast::<NoopTrb>(); + format!("trb: {:?}", t) + } + TrbType::EnableSlotCommand => format!("trb: enable slot command {:?}", self), + TrbType::DisableSlotCommand => { + let t = self.cast::<DisableSlotCommandTrb>(); + format!("trb: {:?}", t) + } + TrbType::AddressDeviceCommand => { + let t = self.cast::<AddressDeviceCommandTrb>(); + format!("trb: {:?}", t) + } + TrbType::ConfigureEndpointCommand => { + let t = self.cast::<ConfigureEndpointCommandTrb>(); + format!("trb: {:?}", t) + } + TrbType::EvaluateContextCommand => { + let t = self.cast::<EvaluateContextCommandTrb>(); + format!("trb: {:?}", t) + } + TrbType::ResetEndpointCommand => { + let t = self.cast::<ResetEndpointCommandTrb>(); + format!("trb: {:?}", t) + } + TrbType::StopEndpointCommand => { + let t = self.cast::<StopEndpointCommandTrb>(); + format!("trb: {:?}", t) + } + TrbType::SetTRDequeuePointerCommand => { + let t = self.cast::<SetTRDequeuePointerCommandTrb>(); + format!("trb: {:?}", t) + } + TrbType::ResetDeviceCommand => { + let t = self.cast::<ResetDeviceCommandTrb>(); + format!("trb: {:?}", t) + } + TrbType::NoopCommand => format!("trb: noop command {:?}", self), + TrbType::TransferEvent => { + let t = self.cast::<TransferEventTrb>(); + format!("trb: {:?}", t) + } + TrbType::CommandCompletionEvent => { + let t = self.cast::<CommandCompletionEventTrb>(); + format!("trb: {:?}", t) + } + TrbType::PortStatusChangeEvent => { + let t = self.cast::<PortStatusChangeEventTrb>(); + format!("trb: {:?}", t) + } + } + } + + /// Get cycle bit. + pub fn get_cycle_bit(&self) -> bool { + self.get_cycle() != 0 + } + + /// Set cyle bit. + pub fn set_cycle_bit(&mut self, b: bool) { + match b { + true => self.set_cycle(1u8), + false => self.set_cycle(0u8), + } + } + + /// Get chain bit. + pub fn get_chain_bit(&self) -> bool { + match self.trb_type() { + Some(TrbType::Normal) => self.cast::<NormalTrb>().get_chain() != 0, + Some(TrbType::DataStage) => self.cast::<DataStageTrb>().get_chain() != 0, + Some(TrbType::StatusStage) => self.cast::<StatusStageTrb>().get_chain() != 0, + Some(TrbType::Isoch) => self.cast::<IsochTrb>().get_chain() != 0, + Some(TrbType::Noop) => self.cast::<NoopTrb>().get_chain() != 0, + Some(TrbType::Link) => self.cast::<LinkTrb>().get_chain() != 0, + Some(TrbType::EventData) => self.cast::<EventDataTrb>().get_chain() != 0, + _ => false, + } + } + + /// Get interrupt target. + pub fn interrupter_target(&self) -> u8 { + const STATUS_INTERRUPTER_TARGET_OFFSET: u8 = 22; + (self.get_status() >> STATUS_INTERRUPTER_TARGET_OFFSET) as u8 + } + + /// Only some of trb types could appear in transfer ring. + pub fn can_be_in_transfer_ring(&self) -> bool { + match self.trb_type().unwrap() { + TrbType::Normal + | TrbType::SetupStage + | TrbType::DataStage + | TrbType::StatusStage + | TrbType::Isoch + | TrbType::Link + | TrbType::EventData + | TrbType::Noop => true, + _ => false, + } + } + + /// Length of this transfer. + pub fn transfer_length(&self) -> u32 { + const STATUS_TRANSFER_LENGTH_MASK: u32 = 0x1ffff; + match self.trb_type().unwrap() { + TrbType::Normal | TrbType::SetupStage | TrbType::DataStage | TrbType::Isoch => { + self.get_status() & STATUS_TRANSFER_LENGTH_MASK + } + _ => 0, + } + } + + /// Returns true if interrupt is required on completion. + pub fn interrupt_on_completion(&self) -> bool { + const FLAGS_INTERRUPT_ON_COMPLETION_MASK: u16 = 0x10; + (self.get_flags() & FLAGS_INTERRUPT_ON_COMPLETION_MASK) > 0 + } + + /// Returns true if this trb is immediate data. + pub fn immediate_data(&self) -> bool { + const FLAGS_IMMEDIATE_DATA_MASK: u16 = 0x20; + match self.trb_type().unwrap() { + TrbType::Normal | TrbType::SetupStage | TrbType::DataStage | TrbType::Isoch => { + (self.get_flags() & FLAGS_IMMEDIATE_DATA_MASK) != 0 + } + _ => false, + } + } +} + +/// Trait for enum that could be converted from raw u8. +pub trait PrimitiveEnum: Sized { + fn from_raw(val: u8) -> Option<Self>; +} + +/// All kinds of trb. +#[derive(PartialEq, Debug)] +pub enum TrbType { + Reserved = 0, + Normal = 1, + SetupStage = 2, + DataStage = 3, + StatusStage = 4, + Isoch = 5, + Link = 6, + EventData = 7, + Noop = 8, + EnableSlotCommand = 9, + DisableSlotCommand = 10, + AddressDeviceCommand = 11, + ConfigureEndpointCommand = 12, + EvaluateContextCommand = 13, + ResetEndpointCommand = 14, + StopEndpointCommand = 15, + SetTRDequeuePointerCommand = 16, + ResetDeviceCommand = 17, + NoopCommand = 23, + TransferEvent = 32, + CommandCompletionEvent = 33, + PortStatusChangeEvent = 34, +} + +impl PrimitiveEnum for TrbType { + fn from_raw(val: u8) -> Option<Self> { + match val { + 0 => Some(TrbType::Reserved), + 1 => Some(TrbType::Normal), + 2 => Some(TrbType::SetupStage), + 3 => Some(TrbType::DataStage), + 4 => Some(TrbType::StatusStage), + 5 => Some(TrbType::Isoch), + 6 => Some(TrbType::Link), + 7 => Some(TrbType::EventData), + 8 => Some(TrbType::Noop), + 9 => Some(TrbType::EnableSlotCommand), + 10 => Some(TrbType::DisableSlotCommand), + 11 => Some(TrbType::AddressDeviceCommand), + 12 => Some(TrbType::ConfigureEndpointCommand), + 13 => Some(TrbType::EvaluateContextCommand), + 14 => Some(TrbType::ResetEndpointCommand), + 15 => Some(TrbType::StopEndpointCommand), + 16 => Some(TrbType::SetTRDequeuePointerCommand), + 17 => Some(TrbType::ResetDeviceCommand), + 23 => Some(TrbType::NoopCommand), + 32 => Some(TrbType::TransferEvent), + 33 => Some(TrbType::CommandCompletionEvent), + 34 => Some(TrbType::PortStatusChangeEvent), + _ => None, + } + } +} + +/// Completion code of trb types. +pub enum TrbCompletionCode { + Success = 1, + TransactionError = 4, + TrbError = 5, + NoSlotsAvailableError = 9, + SlotNotEnabledError = 11, + ShortPacket = 13, + ContextStateError = 19, +} + +impl PrimitiveEnum for TrbCompletionCode { + fn from_raw(val: u8) -> Option<Self> { + match val { + 1 => Some(TrbCompletionCode::Success), + 4 => Some(TrbCompletionCode::TransactionError), + 5 => Some(TrbCompletionCode::TrbError), + 9 => Some(TrbCompletionCode::NoSlotsAvailableError), + 11 => Some(TrbCompletionCode::SlotNotEnabledError), + 13 => Some(TrbCompletionCode::ShortPacket), + 19 => Some(TrbCompletionCode::ContextStateError), + _ => None, + } + } +} + +/// State of device slot. +#[derive(PartialEq, Debug)] +pub enum DeviceSlotState { + // The same value (0) is used for both the enabled and disabled states. See + // xhci spec table 60. + DisabledOrEnabled = 0, + Default = 1, + Addressed = 2, + Configured = 3, +} + +impl PrimitiveEnum for DeviceSlotState { + fn from_raw(val: u8) -> Option<Self> { + match val { + 0 => Some(DeviceSlotState::DisabledOrEnabled), + 1 => Some(DeviceSlotState::Default), + 2 => Some(DeviceSlotState::Addressed), + 3 => Some(DeviceSlotState::Configured), + _ => None, + } + } +} + +impl SlotContext { + /// Set slot context state. + pub fn state(&self) -> Option<DeviceSlotState> { + DeviceSlotState::from_raw(self.get_slot_state()) + } + + /// Get slot context state. + pub fn set_state(&mut self, state: DeviceSlotState) { + self.set_slot_state(state as u8); + } +} + +/// State of endpoint. +pub enum EndpointState { + Disabled = 0, + Running = 1, +} + +impl PrimitiveEnum for EndpointState { + fn from_raw(val: u8) -> Option<Self> { + match val { + 0 => Some(EndpointState::Disabled), + 1 => Some(EndpointState::Running), + _ => None, + } + } +} + +impl EndpointContext { + /// Get endpoint context state. + pub fn state(&self) -> Option<EndpointState> { + EndpointState::from_raw(self.get_endpoint_state()) + } + + /// Set endpoint context state. + pub fn set_state(&mut self, state: EndpointState) { + self.set_endpoint_state(state as u8); + } +} + +impl InputControlContext { + /// Get drop context flag. + pub fn drop_context_flag(&self, idx: u8) -> bool { + (self.get_drop_context_flags() & (1 << idx)) != 0 + } + + /// Get add context flag. + pub fn add_context_flag(&self, idx: u8) -> bool { + (self.get_add_context_flags() & (1 << idx)) != 0 + } +} diff --git a/devices/src/usb/xhci/xhci_abi_schema.rs b/devices/src/usb/xhci/xhci_abi_schema.rs new file mode 100644 index 0000000..8174ce8 --- /dev/null +++ b/devices/src/usb/xhci/xhci_abi_schema.rs @@ -0,0 +1,543 @@ +// 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 bit_field::*; +use std; + +// TODO(jkwang) move these to bitfield crate. +type B0 = BitField0; +type B1 = BitField1; +type B2 = BitField2; +type B3 = BitField3; +type B4 = BitField4; +type B5 = BitField5; +type B6 = BitField6; +type B7 = BitField7; +type B8 = BitField8; +type B9 = BitField9; +type B10 = BitField10; +type B11 = BitField11; +type B12 = BitField12; +type B13 = BitField13; +type B14 = BitField14; +type B15 = BitField15; +type B16 = BitField16; +type B17 = BitField17; +type B18 = BitField18; +type B19 = BitField19; +type B20 = BitField20; +type B21 = BitField21; +type B22 = BitField22; +type B23 = BitField23; +type B24 = BitField24; +type B25 = BitField25; +type B26 = BitField26; +type B27 = BitField27; +type B28 = BitField28; +type B29 = BitField29; +type B30 = BitField30; +type B31 = BitField31; +type B32 = BitField32; +type B33 = BitField33; +type B34 = BitField34; +type B35 = BitField35; +type B36 = BitField36; +type B37 = BitField37; +type B38 = BitField38; +type B39 = BitField39; +type B40 = BitField40; +type B41 = BitField41; +type B42 = BitField42; +type B43 = BitField43; +type B44 = BitField44; +type B45 = BitField45; +type B46 = BitField46; +type B47 = BitField47; +type B48 = BitField48; +type B49 = BitField49; +type B50 = BitField50; +type B51 = BitField51; +type B52 = BitField52; +type B53 = BitField53; +type B54 = BitField54; +type B55 = BitField55; +type B56 = BitField56; +type B57 = BitField57; +type B58 = BitField58; +type B59 = BitField59; +type B60 = BitField60; +type B61 = BitField61; +type B62 = BitField62; +type B63 = BitField63; +type B64 = BitField64; + +// Fixed size of all TRB types. +const TRB_SIZE: usize = 16; + +// Size of segment table. +const SEGMENT_TABLE_SIZE: usize = 16; + +// Generic TRB struct containing only fields common to all types. +#[bitfield] +#[derive(Clone, Copy, PartialEq)] +pub struct Trb { + parameter: B64, + status: B32, + cycle: B1, + flags: B9, + trb_type: B6, + control: B16, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct NormalTrb { + data_buffer: B64, + trb_transfer_length: B17, + td_size: B5, + interrupter_target: B10, + cycle: B1, + evaluate_next_trb: B1, + interrupt_on_short_packet: B1, + no_snoop: B1, + chain: B1, + interrupt_on_completion: B1, + immediate_data: B1, + reserved: B2, + block_event_interrupt: B1, + trb_type: B6, + reserved1: B16, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct SetupStageTrb { + request_type: B8, + request: B8, + value: B16, + index: B16, + length: B16, + trb_transfer_length: B17, + reserved0: B5, + interrupter_target: B10, + cycle: B1, + reserved1: B4, + interrupt_on_completion: B1, + immediate_data: B1, + reserved2: B3, + trb_type: B6, + transfer_type: B2, + reserved3: B14, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct DataStageTrb { + data_buffer_pointer: B64, + trb_transfer_length: B17, + td_size: B5, + interrupter_target: B10, + cycle: B1, + evaluate_next_trb: B1, + interrupt_on_short_packet: B1, + no_snoop: B1, + chain: B1, + interrupt_on_completion: B1, + immediate_data: B1, + reserved0: B3, + trb_type: B6, + direction: B1, + reserved1: B15, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct StatusStageTrb { + reserved0: B64, + reserved1: B22, + interrupter_target: B10, + cycle: B1, + evaluate_next_trb: B1, + reserved2: B2, + chain: B1, + interrupt_on_completion: B1, + reserved3: B4, + trb_type: B6, + direction: B1, + reserved4: B15, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct IsochTrb { + data_buffer_pointer: B64, + trb_transfer_length: B17, + td_size: B5, + interrupter_target: B10, + cycle: B1, + evaulate_nex_trb: B1, + interrupt_on_short_packet: B1, + no_snoop: B1, + chain: B1, + interrupt_on_completion: B1, + immediate_data: B1, + transfer_burst_count: B2, + block_event_interrupt: B1, + trb_type: B6, + tlbpc: B4, + frame_id: B11, + sia: B1, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct LinkTrb { + ring_segment_pointer: B64, + reserved0: B22, + interrupter_target: B10, + cycle: B1, + toggle_cycle: B1, + reserved1: B2, + chain: B1, + interrupt_on_completion: B1, + reserved2: B4, + trb_type: B6, + reserved3: B16, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct EventDataTrb { + event_data: B64, + reserved0: B22, + interrupter_target: B10, + cycle: B1, + evaluate_next_trb: B1, + reserved1: B2, + chain: B1, + interrupt_on_completion: B1, + reserved2: B3, + block_event_interrupt: B1, + trb_type: B6, + reserved3: B16, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct NoopTrb { + reserved0: B64, + reserved1: B22, + interrupter_target: B10, + cycle: B1, + evaluate_next_trb: B1, + reserved2: B2, + chain: B1, + interrupt_on_completion: B1, + reserved3: B4, + trb_type: B6, + reserved4: B16, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct DisableSlotCommandTrb { + reserved0: B32, + reserved1: B32, + reserved2: B32, + cycle: B1, + reserved3: B9, + trb_type: B6, + reserved4: B8, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct AddressDeviceCommandTrb { + input_context_pointer: B64, + reserved: B32, + cycle: B1, + reserved2: B8, + block_set_address_request: B1, + trb_type: B6, + reserved3: B8, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct ConfigureEndpointCommandTrb { + input_context_pointer: B64, + reserved0: B32, + cycle: B1, + reserved1: B8, + deconfigure: B1, + trb_type: B6, + reserved2: B8, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct EvaluateContextCommandTrb { + input_context_pointer: B64, + reserved0: B32, + cycle: B1, + reserved1: B9, + trb_type: B6, + reserved2: B8, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct ResetEndpointCommandTrb { + reserved0: B32, + reserved1: B32, + reserved2: B32, + cycle: B1, + reserved3: B8, + transfer_state_preserve: B1, + trb_type: B6, + endpoint_id: B5, + reserved4: B3, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct StopEndpointCommandTrb { + reserved0: B32, + reserved1: B32, + reserved2: B32, + cycle: B1, + reserved3: B9, + trb_type: B6, + endpoint_id: B5, + reserved4: B2, + suspend: B1, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct SetTRDequeuePointerCommandTrb { + dequeue_cycle_state: B1, + stream_context_type: B3, + dequeue_ptr: B60, + reserved0: B16, + stream_id: B16, + cycle: B1, + reserved1: B9, + trb_type: B6, + endpoint_id: B5, + reserved3: B2, + suspend: B1, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct ResetDeviceCommandTrb { + reserved0: B32, + reserved1: B32, + reserved2: B32, + cycle: B1, + reserved3: B9, + trb_type: B6, + reserved4: B8, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct TransferEventTrb { + trb_pointer: B64, + trb_transfer_length: B24, + completion_code: B8, + cycle: B1, + reserved0: B1, + event_data: B1, + reserved1: B7, + trb_type: B6, + endpoint_id: B5, + reserved2: B3, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct CommandCompletionEventTrb { + trb_pointer: B64, + command_completion_parameter: B24, + completion_code: B8, + cycle: B1, + reserved: B9, + trb_type: B6, + vf_id: B8, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct PortStatusChangeEventTrb { + reserved0: B24, + port_id: B8, + reserved1: B32, + reserved2: B24, + completion_code: B8, + cycle: B1, + reserved3: B9, + trb_type: B6, + reserved4: B16, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct EventRingSegmentTableEntry { + ring_segment_base_address: B64, + ring_segment_size: B16, + reserved2: B48, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct InputControlContext { + // Xhci spec 6.2.5.1. + drop_context_flags: B32, + add_context_flags: B32, + reserved0: B32, + reserved1: B32, + reserved2: B32, + reserved3: B32, + reserved4: B32, + configuration_value: B8, + interface_number: B8, + alternate_setting: B8, + reserved5: B8, +} + +// Size of device context entries (SlotContext and EndpointContext). +pub const DEVICE_CONTEXT_ENTRY_SIZE: usize = 32usize; + +#[bitfield] +#[derive(Clone, Copy)] +pub struct SlotContext { + route_string: B20, + speed: B4, + reserved1: B1, + mtt: B1, + hub: B1, + context_entries: B5, + max_exit_latency: B16, + root_hub_port_number: B8, + num_ports: B8, + tt_hub_slot_id: B8, + tt_port_number: B8, + tt_think_time: B2, + reserved2: B4, + interrupter_target: B10, + usb_device_address: B8, + reserved3: B19, + slot_state: B5, + reserved4: B32, + reserved5: B32, + reserved6: B32, + reserved7: B32, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct EndpointContext { + endpoint_state: B3, + reserved1: B5, + mult: B2, + max_primary_streams: B5, + linear_stream_array: B1, + interval: B8, + max_esit_payload_hi: B8, + reserved2: B1, + error_count: B2, + endpoint_type: B3, + reserved3: B1, + host_initiate_disable: B1, + max_burst_size: B8, + max_packet_size: B16, + dequeue_cycle_state: B1, + reserved4: B3, + tr_dequeue_pointer: B60, + average_trb_length: B16, + max_esit_payload_lo: B16, + reserved5: B32, + reserved6: B32, + reserved7: B32, +} + +/// Device context. +#[derive(Clone, Copy, Debug)] +pub struct DeviceContext { + pub slot_context: SlotContext, + pub endpoint_context: [EndpointContext; 31], +} + +/// POD struct associates a TRB with its address in guest memory. This is +/// useful because transfer and command completion event TRBs must contain +/// pointers to the original TRB that generated the event. +#[derive(Clone, Copy)] +pub struct AddressedTrb { + pub trb: Trb, + pub gpa: u64, +} + +pub type TransferDescriptor = Vec<AddressedTrb>; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn check_struct_sizes() { + assert_eq!(std::mem::size_of::<Trb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<NormalTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<SetupStageTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<DataStageTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<StatusStageTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<IsochTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<LinkTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<EventDataTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<NoopTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<DisableSlotCommandTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<AddressDeviceCommandTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<ConfigureEndpointCommandTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<EvaluateContextCommandTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<ResetEndpointCommandTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<StopEndpointCommandTrb>(), TRB_SIZE); + assert_eq!( + std::mem::size_of::<SetTRDequeuePointerCommandTrb>(), + TRB_SIZE + ); + assert_eq!(std::mem::size_of::<ResetDeviceCommandTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<TransferEventTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<CommandCompletionEventTrb>(), TRB_SIZE); + assert_eq!(std::mem::size_of::<PortStatusChangeEventTrb>(), TRB_SIZE); + + assert_eq!( + std::mem::size_of::<EventRingSegmentTableEntry>(), + SEGMENT_TABLE_SIZE + ); + assert_eq!(std::mem::size_of::<InputControlContext>(), 32); + assert_eq!( + std::mem::size_of::<SlotContext>(), + DEVICE_CONTEXT_ENTRY_SIZE + ); + assert_eq!( + std::mem::size_of::<EndpointContext>(), + DEVICE_CONTEXT_ENTRY_SIZE + ); + assert_eq!( + std::mem::size_of::<DeviceContext>(), + 32 * DEVICE_CONTEXT_ENTRY_SIZE + ); + } +} |