summary refs log tree commit diff
path: root/devices/src/usb/xhci/xhci_abi.rs
diff options
context:
space:
mode:
Diffstat (limited to 'devices/src/usb/xhci/xhci_abi.rs')
-rw-r--r--devices/src/usb/xhci/xhci_abi.rs1048
1 files changed, 702 insertions, 346 deletions
diff --git a/devices/src/usb/xhci/xhci_abi.rs b/devices/src/usb/xhci/xhci_abi.rs
index 92f26ea..5a8748e 100644
--- a/devices/src/usb/xhci/xhci_abi.rs
+++ b/devices/src/usb/xhci/xhci_abi.rs
@@ -2,150 +2,17 @@
 // 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 bit_field::Error as BitFieldError;
+use bit_field::*;
 use data_model::DataInit;
 use std::fmt::{self, Display};
+use sys_util::GuestAddress;
 
-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;
-}
+use std;
 
-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;
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug)]
 pub enum Error {
-    UnknownTrbType(u8),
-    UnknownCompletionCode(u8),
-    UnknownDeviceSlotState(u8),
-    UnknownEndpointState(u8),
+    UnknownTrbType(BitFieldError),
     CannotCastTrb,
 }
 
@@ -156,52 +23,114 @@ impl Display for Error {
         use self::Error::*;
 
         match self {
-            UnknownTrbType(v) => write!(f, "we got an unknown trb type value: {}", v),
-            UnknownCompletionCode(v) => write!(f, "we got an unknown trb completion code: {}", v),
-            UnknownDeviceSlotState(v) => write!(f, "we got and unknown device slot state: {}", v),
-            UnknownEndpointState(v) => write!(f, "we got and unknown endpoint state: {}", v),
+            UnknownTrbType(e) => write!(f, "we got an unknown trb type value: {}", e),
             CannotCastTrb => write!(f, "cannot cast trb from raw memory"),
         }
     }
 }
 
-/// 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) -> Result<&T> {
-        T::from_slice(self.as_slice()).ok_or(Error::CannotCastTrb)
-    }
+// Fixed size of all TRB types.
+const TRB_SIZE: usize = 16;
 
-    fn cast_mut<T: TrbCast>(&mut self) -> Result<&mut T> {
-        T::from_mut_slice(self.as_mut_slice()).ok_or(Error::CannotCastTrb)
-    }
+// Size of segment table.
+const SEGMENT_TABLE_SIZE: usize = 16;
 
-    fn checked_cast<T: TrbCast>(&self) -> Result<&T> {
-        if Trb::from_slice(self.as_slice())
-            .ok_or(Error::CannotCastTrb)?
-            .trb_type()?
-            != T::TY
-        {
-            return Err(Error::CannotCastTrb);
-        }
-        T::from_slice(self.as_slice()).ok_or(Error::CannotCastTrb)
+/// All kinds of trb.
+#[bitfield]
+#[bits = 6]
+#[derive(PartialEq, Debug, Clone, Copy)]
+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,
+}
+
+/// Completion code of trb types.
+#[bitfield]
+#[bits = 8]
+#[derive(PartialEq, Debug)]
+pub enum TrbCompletionCode {
+    Success = 1,
+    TransactionError = 4,
+    TrbError = 5,
+    NoSlotsAvailableError = 9,
+    SlotNotEnabledError = 11,
+    ShortPacket = 13,
+    ContextStateError = 19,
+}
+
+/// State of device slot.
+#[bitfield]
+#[bits = 5]
+#[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,
+}
+
+/// State of endpoint.
+#[bitfield]
+#[bits = 3]
+#[derive(PartialEq, Debug)]
+pub enum EndpointState {
+    Disabled = 0,
+    Running = 1,
+}
+
+#[bitfield]
+#[bits = 60]
+#[derive(PartialEq, Debug)]
+pub struct DequeuePtr(u64);
+
+impl DequeuePtr {
+    pub fn new(addr: GuestAddress) -> Self {
+        DequeuePtr(addr.0 >> 4)
     }
 
-    fn checked_mut_cast<T: TrbCast>(&mut self) -> Result<&mut T> {
-        if Trb::from_slice(self.as_slice())
-            .ok_or(Error::CannotCastTrb)?
-            .trb_type()?
-            != T::TY
-        {
-            return Err(Error::CannotCastTrb);
-        }
-        T::from_mut_slice(self.as_mut_slice()).ok_or(Error::CannotCastTrb)
+    // Get the guest physical address.
+    pub fn get_gpa(&self) -> GuestAddress {
+        GuestAddress(self.0 << 4)
     }
 }
 
+// Generic TRB struct containing only fields common to all types.
+#[bitfield]
+#[derive(Clone, Copy, PartialEq)]
+pub struct Trb {
+    parameter: B64,
+    status: B32,
+    cycle: bool,
+    flags: B9,
+    trb_type: TrbType,
+    control: B16,
+}
+
 impl Trb {
     fn fmt_helper(&self, f: &mut fmt::Formatter) -> Result<fmt::Result> {
-        match self.trb_type()? {
+        match self.get_trb_type().map_err(Error::UnknownTrbType)? {
             TrbType::Reserved => Ok(write!(f, "reserved trb type")),
             TrbType::Normal => {
                 let t = self.cast::<NormalTrb>()?;
@@ -284,6 +213,7 @@ impl Trb {
         }
     }
 }
+
 impl Display for Trb {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.fmt_helper(f) {
@@ -294,34 +224,16 @@ impl Display for Trb {
 }
 
 impl Trb {
-    /// Get trb type.
-    pub fn trb_type(&self) -> Result<TrbType> {
-        TrbType::from_raw(self.get_trb_type())
-    }
-
-    /// 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) -> Result<bool> {
-        Ok(match self.trb_type() {
-            Ok(TrbType::Normal) => self.cast::<NormalTrb>()?.get_chain() != 0,
-            Ok(TrbType::DataStage) => self.cast::<DataStageTrb>()?.get_chain() != 0,
-            Ok(TrbType::StatusStage) => self.cast::<StatusStageTrb>()?.get_chain() != 0,
-            Ok(TrbType::Isoch) => self.cast::<IsochTrb>()?.get_chain() != 0,
-            Ok(TrbType::Noop) => self.cast::<NoopTrb>()?.get_chain() != 0,
-            Ok(TrbType::Link) => self.cast::<LinkTrb>()?.get_chain() != 0,
-            Ok(TrbType::EventData) => self.cast::<EventDataTrb>()?.get_chain() != 0,
+        Ok(match self.get_trb_type() {
+            Ok(TrbType::Normal) => self.cast::<NormalTrb>()?.get_chain(),
+            Ok(TrbType::DataStage) => self.cast::<DataStageTrb>()?.get_chain(),
+            Ok(TrbType::StatusStage) => self.cast::<StatusStageTrb>()?.get_chain(),
+            Ok(TrbType::Isoch) => self.cast::<IsochTrb>()?.get_chain(),
+            Ok(TrbType::Noop) => self.cast::<NoopTrb>()?.get_chain(),
+            Ok(TrbType::Link) => self.cast::<LinkTrb>()?.get_chain(),
+            Ok(TrbType::EventData) => self.cast::<EventDataTrb>()?.get_chain(),
             _ => false,
         })
     }
@@ -334,7 +246,7 @@ impl Trb {
 
     /// Only some of trb types could appear in transfer ring.
     pub fn can_be_in_transfer_ring(&self) -> Result<bool> {
-        match self.trb_type()? {
+        match self.get_trb_type().map_err(Error::UnknownTrbType)? {
             TrbType::Normal
             | TrbType::SetupStage
             | TrbType::DataStage
@@ -350,7 +262,7 @@ impl Trb {
     /// Length of this transfer.
     pub fn transfer_length(&self) -> Result<u32> {
         const STATUS_TRANSFER_LENGTH_MASK: u32 = 0x1ffff;
-        match self.trb_type()? {
+        match self.get_trb_type().map_err(Error::UnknownTrbType)? {
             TrbType::Normal | TrbType::SetupStage | TrbType::DataStage | TrbType::Isoch => {
                 Ok(self.get_status() & STATUS_TRANSFER_LENGTH_MASK)
             }
@@ -373,7 +285,7 @@ impl Trb {
     /// Returns true if this trb is immediate data.
     pub fn immediate_data(&self) -> Result<bool> {
         const FLAGS_IMMEDIATE_DATA_MASK: u16 = 0x20;
-        match self.trb_type()? {
+        match self.get_trb_type().map_err(Error::UnknownTrbType)? {
             TrbType::Normal | TrbType::SetupStage | TrbType::DataStage | TrbType::Isoch => {
                 Ok((self.get_flags() & FLAGS_IMMEDIATE_DATA_MASK) != 0)
             }
@@ -382,184 +294,504 @@ impl Trb {
     }
 }
 
-impl LinkTrb {
-    /// Get cycle.
-    pub fn get_cycle_bit(&self) -> bool {
-        self.get_cycle() != 0
-    }
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct NormalTrb {
+    data_buffer: B64,
+    trb_transfer_length: B17,
+    td_size: B5,
+    interrupter_target: B10,
+    cycle: bool,
+    evaluate_next_trb: B1,
+    interrupt_on_short_packet: B1,
+    no_snoop: B1,
+    chain: bool,
+    interrupt_on_completion: B1,
+    immediate_data: B1,
+    reserved: B2,
+    block_event_interrupt: B1,
+    trb_type: TrbType,
+    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: bool,
+    reserved1: B4,
+    interrupt_on_completion: B1,
+    immediate_data: B1,
+    reserved2: B3,
+    trb_type: TrbType,
+    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: bool,
+    evaluate_next_trb: B1,
+    interrupt_on_short_packet: B1,
+    no_snoop: B1,
+    chain: bool,
+    interrupt_on_completion: B1,
+    immediate_data: B1,
+    reserved0: B3,
+    trb_type: TrbType,
+    direction: B1,
+    reserved1: B15,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct StatusStageTrb {
+    reserved0: B64,
+    reserved1: B22,
+    interrupter_target: B10,
+    cycle: bool,
+    evaluate_next_trb: B1,
+    reserved2: B2,
+    chain: bool,
+    interrupt_on_completion: B1,
+    reserved3: B4,
+    trb_type: TrbType,
+    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: bool,
+    evaulate_nex_trb: B1,
+    interrupt_on_short_packet: B1,
+    no_snoop: B1,
+    chain: bool,
+    interrupt_on_completion: B1,
+    immediate_data: B1,
+    transfer_burst_count: B2,
+    block_event_interrupt: B1,
+    trb_type: TrbType,
+    tlbpc: B4,
+    frame_id: B11,
+    sia: B1,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct LinkTrb {
+    ring_segment_pointer: B64,
+    reserved0: B22,
+    interrupter_target: B10,
+    cycle: bool,
+    toggle_cycle: bool,
+    reserved1: B2,
+    chain: bool,
+    interrupt_on_completion: bool,
+    reserved2: B4,
+    trb_type: TrbType,
+    reserved3: B16,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct EventDataTrb {
+    event_data: B64,
+    reserved0: B22,
+    interrupter_target: B10,
+    cycle: bool,
+    evaluate_next_trb: B1,
+    reserved1: B2,
+    chain: bool,
+    interrupt_on_completion: B1,
+    reserved2: B3,
+    block_event_interrupt: B1,
+    trb_type: TrbType,
+    reserved3: B16,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct NoopTrb {
+    reserved0: B64,
+    reserved1: B22,
+    interrupter_target: B10,
+    cycle: bool,
+    evaluate_next_trb: B1,
+    reserved2: B2,
+    chain: bool,
+    interrupt_on_completion: B1,
+    reserved3: B4,
+    trb_type: TrbType,
+    reserved4: B16,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct DisableSlotCommandTrb {
+    reserved0: B32,
+    reserved1: B32,
+    reserved2: B32,
+    cycle: bool,
+    reserved3: B9,
+    trb_type: TrbType,
+    reserved4: B8,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct AddressDeviceCommandTrb {
+    input_context_pointer: B64,
+    reserved: B32,
+    cycle: bool,
+    reserved2: B8,
+    block_set_address_request: bool,
+    trb_type: TrbType,
+    reserved3: B8,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct ConfigureEndpointCommandTrb {
+    input_context_pointer: B64,
+    reserved0: B32,
+    cycle: bool,
+    reserved1: B8,
+    deconfigure: bool,
+    trb_type: TrbType,
+    reserved2: B8,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct EvaluateContextCommandTrb {
+    input_context_pointer: B64,
+    reserved0: B32,
+    cycle: bool,
+    reserved1: B9,
+    trb_type: TrbType,
+    reserved2: B8,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct ResetEndpointCommandTrb {
+    reserved0: B32,
+    reserved1: B32,
+    reserved2: B32,
+    cycle: bool,
+    reserved3: B8,
+    transfer_state_preserve: B1,
+    trb_type: TrbType,
+    endpoint_id: B5,
+    reserved4: B3,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct StopEndpointCommandTrb {
+    reserved0: B32,
+    reserved1: B32,
+    reserved2: B32,
+    cycle: bool,
+    reserved3: B9,
+    trb_type: TrbType,
+    endpoint_id: B5,
+    reserved4: B2,
+    suspend: B1,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct SetTRDequeuePointerCommandTrb {
+    dequeue_cycle_state: bool,
+    stream_context_type: B3,
+    dequeue_ptr: DequeuePtr,
+    reserved0: B16,
+    stream_id: B16,
+    cycle: bool,
+    reserved1: B9,
+    trb_type: TrbType,
+    endpoint_id: B5,
+    reserved3: B2,
+    suspend: B1,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct ResetDeviceCommandTrb {
+    reserved0: B32,
+    reserved1: B32,
+    reserved2: B32,
+    cycle: bool,
+    reserved3: B9,
+    trb_type: TrbType,
+    reserved4: B8,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct TransferEventTrb {
+    trb_pointer: B64,
+    trb_transfer_length: B24,
+    completion_code: TrbCompletionCode,
+    cycle: bool,
+    reserved0: B1,
+    event_data: B1,
+    reserved1: B7,
+    trb_type: TrbType,
+    endpoint_id: B5,
+    reserved2: B3,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct CommandCompletionEventTrb {
+    trb_pointer: B64,
+    command_completion_parameter: B24,
+    completion_code: TrbCompletionCode,
+    cycle: bool,
+    reserved: B9,
+    trb_type: TrbType,
+    vf_id: B8,
+    slot_id: B8,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct PortStatusChangeEventTrb {
+    reserved0: B24,
+    port_id: B8,
+    reserved1: B32,
+    reserved2: B24,
+    completion_code: TrbCompletionCode,
+    cycle: bool,
+    reserved3: B9,
+    trb_type: TrbType,
+    reserved4: B16,
+}
 
-    /// Get toggle cycle.
-    pub fn get_toggle_cycle_bit(&self) -> bool {
-        self.get_toggle_cycle() != 0
-    }
+/// Associate real type of trb.
+pub trait TypedTrb {
+    const TY: TrbType;
+}
 
-    /// set chain status.
-    pub fn set_chain_bit(&mut self, v: bool) {
-        self.set_chain(v as u8);
-    }
+impl TypedTrb for Trb {
+    const TY: TrbType = TrbType::Reserved;
+}
 
-    /// Get chain status.
-    pub fn get_chain_bit(&self) -> bool {
-        self.get_chain() != 0
-    }
+impl TypedTrb for NormalTrb {
+    const TY: TrbType = TrbType::Normal;
+}
 
-    /// Get interrupt on completion.
-    pub fn interrupt_on_completion(&self) -> bool {
-        self.get_interrupt_on_completion() != 0
-    }
+impl TypedTrb for SetupStageTrb {
+    const TY: TrbType = TrbType::SetupStage;
 }
 
-/// Trait for enum that could be converted from raw u8.
-pub trait PrimitiveTrbEnum: Sized {
-    fn from_raw(val: u8) -> Result<Self>;
+impl TypedTrb for DataStageTrb {
+    const TY: TrbType = TrbType::DataStage;
 }
 
-/// 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 TypedTrb for StatusStageTrb {
+    const TY: TrbType = TrbType::StatusStage;
 }
 
-impl PrimitiveTrbEnum for TrbType {
-    fn from_raw(val: u8) -> Result<Self> {
-        match val {
-            0 => Ok(TrbType::Reserved),
-            1 => Ok(TrbType::Normal),
-            2 => Ok(TrbType::SetupStage),
-            3 => Ok(TrbType::DataStage),
-            4 => Ok(TrbType::StatusStage),
-            5 => Ok(TrbType::Isoch),
-            6 => Ok(TrbType::Link),
-            7 => Ok(TrbType::EventData),
-            8 => Ok(TrbType::Noop),
-            9 => Ok(TrbType::EnableSlotCommand),
-            10 => Ok(TrbType::DisableSlotCommand),
-            11 => Ok(TrbType::AddressDeviceCommand),
-            12 => Ok(TrbType::ConfigureEndpointCommand),
-            13 => Ok(TrbType::EvaluateContextCommand),
-            14 => Ok(TrbType::ResetEndpointCommand),
-            15 => Ok(TrbType::StopEndpointCommand),
-            16 => Ok(TrbType::SetTRDequeuePointerCommand),
-            17 => Ok(TrbType::ResetDeviceCommand),
-            23 => Ok(TrbType::NoopCommand),
-            32 => Ok(TrbType::TransferEvent),
-            33 => Ok(TrbType::CommandCompletionEvent),
-            34 => Ok(TrbType::PortStatusChangeEvent),
-            v => Err(Error::UnknownTrbType(v)),
-        }
-    }
+impl TypedTrb for IsochTrb {
+    const TY: TrbType = TrbType::Isoch;
 }
 
-/// Completion code of trb types.
-pub enum TrbCompletionCode {
-    Success = 1,
-    TransactionError = 4,
-    TrbError = 5,
-    NoSlotsAvailableError = 9,
-    SlotNotEnabledError = 11,
-    ShortPacket = 13,
-    ContextStateError = 19,
+impl TypedTrb for LinkTrb {
+    const TY: TrbType = TrbType::Link;
 }
 
-impl PrimitiveTrbEnum for TrbCompletionCode {
-    fn from_raw(val: u8) -> Result<Self> {
-        match val {
-            1 => Ok(TrbCompletionCode::Success),
-            4 => Ok(TrbCompletionCode::TransactionError),
-            5 => Ok(TrbCompletionCode::TrbError),
-            9 => Ok(TrbCompletionCode::NoSlotsAvailableError),
-            11 => Ok(TrbCompletionCode::SlotNotEnabledError),
-            13 => Ok(TrbCompletionCode::ShortPacket),
-            19 => Ok(TrbCompletionCode::ContextStateError),
-            v => Err(Error::UnknownCompletionCode(v)),
-        }
-    }
+impl TypedTrb for EventDataTrb {
+    const TY: TrbType = TrbType::EventData;
 }
 
-/// 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 TypedTrb for NoopTrb {
+    const TY: TrbType = TrbType::Noop;
 }
 
-impl PrimitiveTrbEnum for DeviceSlotState {
-    fn from_raw(val: u8) -> Result<Self> {
-        match val {
-            0 => Ok(DeviceSlotState::DisabledOrEnabled),
-            1 => Ok(DeviceSlotState::Default),
-            2 => Ok(DeviceSlotState::Addressed),
-            3 => Ok(DeviceSlotState::Configured),
-            v => Err(Error::UnknownDeviceSlotState(v)),
-        }
-    }
+impl TypedTrb for DisableSlotCommandTrb {
+    const TY: TrbType = TrbType::DisableSlotCommand;
 }
 
-impl SlotContext {
-    /// Set slot context state.
-    pub fn state(&self) -> Result<DeviceSlotState> {
-        DeviceSlotState::from_raw(self.get_slot_state())
-    }
+impl TypedTrb for AddressDeviceCommandTrb {
+    const TY: TrbType = TrbType::AddressDeviceCommand;
+}
 
-    /// Get slot context state.
-    pub fn set_state(&mut self, state: DeviceSlotState) {
-        self.set_slot_state(state as u8);
-    }
+impl TypedTrb for ConfigureEndpointCommandTrb {
+    const TY: TrbType = TrbType::ConfigureEndpointCommand;
 }
 
-/// State of endpoint.
-pub enum EndpointState {
-    Disabled = 0,
-    Running = 1,
+impl TypedTrb for EvaluateContextCommandTrb {
+    const TY: TrbType = TrbType::EvaluateContextCommand;
 }
 
-impl PrimitiveTrbEnum for EndpointState {
-    fn from_raw(val: u8) -> Result<Self> {
-        match val {
-            0 => Ok(EndpointState::Disabled),
-            1 => Ok(EndpointState::Running),
-            v => Err(Error::UnknownEndpointState(v)),
-        }
-    }
+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 EndpointContext {
-    /// Get endpoint context state.
-    pub fn state(&self) -> Result<EndpointState> {
-        EndpointState::from_raw(self.get_endpoint_state())
+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) -> Result<&T> {
+        T::from_slice(self.as_slice()).ok_or(Error::CannotCastTrb)
+    }
+
+    fn cast_mut<T: TrbCast>(&mut self) -> Result<&mut T> {
+        T::from_mut_slice(self.as_mut_slice()).ok_or(Error::CannotCastTrb)
     }
 
-    /// Set endpoint context state.
-    pub fn set_state(&mut self, state: EndpointState) {
-        self.set_endpoint_state(state as u8);
+    fn checked_cast<T: TrbCast>(&self) -> Result<&T> {
+        if Trb::from_slice(self.as_slice())
+            .ok_or(Error::CannotCastTrb)?
+            .get_trb_type()
+            .map_err(Error::UnknownTrbType)?
+            != T::TY
+        {
+            return Err(Error::CannotCastTrb);
+        }
+        T::from_slice(self.as_slice()).ok_or(Error::CannotCastTrb)
+    }
+
+    fn checked_mut_cast<T: TrbCast>(&mut self) -> Result<&mut T> {
+        if Trb::from_slice(self.as_slice())
+            .ok_or(Error::CannotCastTrb)?
+            .get_trb_type()
+            .map_err(Error::UnknownTrbType)?
+            != T::TY
+        {
+            return Err(Error::CannotCastTrb);
+        }
+        T::from_mut_slice(self.as_mut_slice()).ok_or(Error::CannotCastTrb)
     }
 }
 
+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 {}
+
+#[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,
+}
+
 impl InputControlContext {
     /// Get drop context flag.
     pub fn drop_context_flag(&self, idx: u8) -> bool {
@@ -571,3 +803,127 @@ impl InputControlContext {
         (self.get_add_context_flags() & (1 << idx)) != 0
     }
 }
+
+// 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: DeviceSlotState,
+    reserved4: B32,
+    reserved5: B32,
+    reserved6: B32,
+    reserved7: B32,
+}
+
+#[bitfield]
+#[derive(Clone, Copy)]
+pub struct EndpointContext {
+    endpoint_state: EndpointState,
+    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: bool,
+    reserved4: B3,
+    tr_dequeue_pointer: DequeuePtr,
+    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, Debug, PartialEq)]
+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
+        );
+    }
+}