summary refs log tree commit diff
path: root/devices/src/usb
diff options
context:
space:
mode:
authorJingkui Wang <jkwang@google.com>2018-07-18 13:26:44 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-12-25 17:55:08 -0800
commit526672672ef801d726686c0241d05c5453bb172b (patch)
treefb953c6bfcfe40da0efdf7b679afc089bd288254 /devices/src/usb
parent62affa765921321f3bba39db95b41f28b9fc4e03 (diff)
downloadcrosvm-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.rs4
-rw-r--r--devices/src/usb/xhci/xhci_abi.rs513
-rw-r--r--devices/src/usb/xhci/xhci_abi_schema.rs543
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
+        );
+    }
+}