summary refs log tree commit diff
diff options
context:
space:
mode:
authorJingkui Wang <jkwang@google.com>2019-04-09 14:30:21 -0700
committerchrome-bot <chrome-bot@chromium.org>2019-05-25 02:31:16 -0700
commit6c1e23eee3065b3f3d6fc4fb992ac9884dbabf68 (patch)
tree63514ac56b73078479bc662a8f9514b05e11cc85
parenta27f3a74d3c54fe944489f54432862144a8868b3 (diff)
downloadcrosvm-6c1e23eee3065b3f3d6fc4fb992ac9884dbabf68.tar
crosvm-6c1e23eee3065b3f3d6fc4fb992ac9884dbabf68.tar.gz
crosvm-6c1e23eee3065b3f3d6fc4fb992ac9884dbabf68.tar.bz2
crosvm-6c1e23eee3065b3f3d6fc4fb992ac9884dbabf68.tar.lz
crosvm-6c1e23eee3065b3f3d6fc4fb992ac9884dbabf68.tar.xz
crosvm-6c1e23eee3065b3f3d6fc4fb992ac9884dbabf68.tar.zst
crosvm-6c1e23eee3065b3f3d6fc4fb992ac9884dbabf68.zip
crosvm: update xhci abi to use new bit_field features
We don't need schema anymore. Will use bool and custom enums.

BUG=None
TEST=local build and run crosvm

Change-Id: I1396916878f2903b17a75f375aee4eec1ced0583
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1564780
Tested-by: kokoro <noreply+kokoro@google.com>
Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
-rw-r--r--bit_field/bit_field_derive/bit_field_derive.rs2
-rw-r--r--devices/src/usb/xhci/command_ring_controller.rs6
-rw-r--r--devices/src/usb/xhci/device_slot.rs68
-rw-r--r--devices/src/usb/xhci/event_ring.rs28
-rw-r--r--devices/src/usb/xhci/interrupter.rs12
-rw-r--r--devices/src/usb/xhci/mod.rs2
-rw-r--r--devices/src/usb/xhci/ring_buffer.rs26
-rw-r--r--devices/src/usb/xhci/ring_buffer_controller.rs15
-rw-r--r--devices/src/usb/xhci/scatter_gather_buffer.rs11
-rw-r--r--devices/src/usb/xhci/xhci_abi.rs1048
-rw-r--r--devices/src/usb/xhci/xhci_abi_schema.rs543
-rw-r--r--devices/src/usb/xhci/xhci_transfer.rs7
12 files changed, 794 insertions, 974 deletions
diff --git a/bit_field/bit_field_derive/bit_field_derive.rs b/bit_field/bit_field_derive/bit_field_derive.rs
index 8a9fb50..7084e22 100644
--- a/bit_field/bit_field_derive/bit_field_derive.rs
+++ b/bit_field/bit_field_derive/bit_field_derive.rs
@@ -179,7 +179,7 @@ fn bitfield_enum_with_width_impl(
         impl bit_field::BitFieldSpecifier for #ident {
             const FIELD_WIDTH: u8 = #bits;
             type SetterType = Self;
-            type GetterType = Result<Self, bit_field::Error>;
+            type GetterType = std::result::Result<Self, bit_field::Error>;
 
             #[inline]
             fn from_u64(val: u64) -> Self::GetterType {
diff --git a/devices/src/usb/xhci/command_ring_controller.rs b/devices/src/usb/xhci/command_ring_controller.rs
index 6c84fc6..e893194 100644
--- a/devices/src/usb/xhci/command_ring_controller.rs
+++ b/devices/src/usb/xhci/command_ring_controller.rs
@@ -311,7 +311,7 @@ impl CommandRingTrbHandler {
         let slot_id = trb.get_slot_id();
         let endpoint_id = trb.get_endpoint_id();
         // See Set TR Dequeue Pointer Trb in spec.
-        let dequeue_ptr = trb.get_dequeue_ptr() << 4;
+        let dequeue_ptr = trb.get_dequeue_ptr().get_gpa().offset();
         let completion_code = {
             if valid_slot_id(slot_id) {
                 self.slot(slot_id)?
@@ -341,7 +341,7 @@ impl TransferDescriptorHandler for CommandRingTrbHandler {
         // Command descriptor always consist of a single TRB.
         assert_eq!(descriptor.len(), 1);
         let atrb = &descriptor[0];
-        let command_result = match atrb.trb.trb_type() {
+        let command_result = match atrb.trb.get_trb_type() {
             Ok(TrbType::EnableSlotCommand) => self.enable_slot(atrb, complete_event),
             Ok(TrbType::DisableSlotCommand) => self.disable_slot(atrb, complete_event),
             Ok(TrbType::AddressDeviceCommand) => self.address_device(atrb, complete_event),
@@ -376,7 +376,7 @@ impl TransferDescriptorHandler for CommandRingTrbHandler {
                 warn!(
                     // We are not handling type 14,15,16. See table 6.4.6.
                     "Unexpected command ring trb type: {}",
-                    atrb.trb.get_trb_type()
+                    atrb.trb
                 );
                 match self.interrupter.lock().send_command_completion_trb(
                     TrbCompletionCode::TrbError,
diff --git a/devices/src/usb/xhci/device_slot.rs b/devices/src/usb/xhci/device_slot.rs
index d3d556a..c6738f5 100644
--- a/devices/src/usb/xhci/device_slot.rs
+++ b/devices/src/usb/xhci/device_slot.rs
@@ -6,14 +6,15 @@ use super::interrupter::Interrupter;
 use super::transfer_ring_controller::{TransferRingController, TransferRingControllerError};
 use super::usb_hub::{self, UsbHub};
 use super::xhci_abi::{
-    AddressDeviceCommandTrb, ConfigureEndpointCommandTrb, DeviceContext, DeviceSlotState,
-    EndpointContext, EndpointState, Error as TrbError, EvaluateContextCommandTrb,
+    AddressDeviceCommandTrb, ConfigureEndpointCommandTrb, DequeuePtr, DeviceContext,
+    DeviceSlotState, EndpointContext, EndpointState, EvaluateContextCommandTrb,
     InputControlContext, SlotContext, TrbCompletionCode, DEVICE_CONTEXT_ENTRY_SIZE,
 };
 use super::xhci_regs::{valid_slot_id, MAX_PORTS, MAX_SLOTS};
 use crate::register_space::Register;
 use crate::usb::xhci::ring_buffer_stop_cb::{fallible_closure, RingBufferStopCallback};
 use crate::utils::{EventLoop, FailHandle};
+use bit_field::Error as BitFieldError;
 use std::fmt::{self, Display};
 use std::mem::size_of;
 use std::sync::atomic::{AtomicBool, Ordering};
@@ -28,7 +29,8 @@ pub enum Error {
     WriteGuestMemory(GuestMemoryError),
     WeakReferenceUpgrade,
     CallbackFailed,
-    GetSlotContextState(TrbError),
+    GetSlotContextState(BitFieldError),
+    GetEndpointState(BitFieldError),
     GetPort(u8),
     GetTrc(u8),
     BadInputContextAddr(GuestAddress),
@@ -49,6 +51,7 @@ impl Display for Error {
             WeakReferenceUpgrade => write!(f, "failed to upgrade weak reference"),
             CallbackFailed => write!(f, "callback failed"),
             GetSlotContextState(e) => write!(f, "failed to get slot context state: {}", e),
+            GetEndpointState(e) => write!(f, "failed to get endpoint state: {}", e),
             GetPort(v) => write!(f, "failed to get port: {}", v),
             GetTrc(v) => write!(f, "failed to get trc: {}", v),
             BadInputContextAddr(addr) => write!(f, "bad input context address: {}", addr),
@@ -310,9 +313,10 @@ impl DeviceSlot {
             }
         };
         let context = self.get_device_context()?;
-        // TODO(jkwang) Refactor the code to have bitfield return enum.
-        if context.endpoint_context[endpoint_index].get_endpoint_state()
-            == EndpointState::Running as u8
+        if context.endpoint_context[endpoint_index]
+            .get_endpoint_state()
+            .map_err(Error::GetEndpointState)?
+            == EndpointState::Running
         {
             usb_debug!("endpoint is started, start transfer ring");
             transfer_ring_controller.start();
@@ -350,7 +354,7 @@ impl DeviceSlot {
                     let mut device_context = slot.get_device_context()?;
                     device_context
                         .slot_context
-                        .set_state(DeviceSlotState::DisabledOrEnabled);
+                        .set_slot_state(DeviceSlotState::DisabledOrEnabled);
                     slot.set_device_context(device_context)?;
                     slot.reset();
                     usb_debug!(
@@ -378,11 +382,11 @@ impl DeviceSlot {
         let device_context = self.get_device_context()?;
         let state = device_context
             .slot_context
-            .state()
+            .get_slot_state()
             .map_err(Error::GetSlotContextState)?;
         match state {
             DeviceSlotState::DisabledOrEnabled => {}
-            DeviceSlotState::Default if trb.get_block_set_address_request() == 0 => {}
+            DeviceSlotState::Default if !trb.get_block_set_address_request() => {}
             _ => {
                 error!("slot {} has unexpected slot state", self.slot_id);
                 return Ok(TrbCompletionCode::ContextStateError);
@@ -424,10 +428,10 @@ impl DeviceSlot {
         );
 
         // Assign slot ID as device address if block_set_address_request is not set.
-        if trb.get_block_set_address_request() > 0 {
+        if trb.get_block_set_address_request() {
             device_context
                 .slot_context
-                .set_state(DeviceSlotState::Default);
+                .set_slot_state(DeviceSlotState::Default);
         } else {
             let port = self.hub.get_port(port_id).ok_or(Error::GetPort(port_id))?;
             match port.get_backend_device().as_mut() {
@@ -444,24 +448,24 @@ impl DeviceSlot {
                 .set_usb_device_address(self.slot_id);
             device_context
                 .slot_context
-                .set_state(DeviceSlotState::Addressed);
+                .set_slot_state(DeviceSlotState::Addressed);
         }
 
         // TODO(jkwang) trc should always exists. Fix this.
         self.get_trc(0)
             .ok_or(Error::GetTrc(0))?
-            .set_dequeue_pointer(GuestAddress(
-                device_context.endpoint_context[0].get_tr_dequeue_pointer() << 4,
-            ));
+            .set_dequeue_pointer(
+                device_context.endpoint_context[0]
+                    .get_tr_dequeue_pointer()
+                    .get_gpa(),
+            );
 
         self.get_trc(0)
             .ok_or(Error::GetTrc(0))?
-            .set_consumer_cycle_state(
-                device_context.endpoint_context[0].get_dequeue_cycle_state() > 0,
-            );
+            .set_consumer_cycle_state(device_context.endpoint_context[0].get_dequeue_cycle_state());
 
         usb_debug!("Setting endpoint 0 to running");
-        device_context.endpoint_context[0].set_state(EndpointState::Running);
+        device_context.endpoint_context[0].set_endpoint_state(EndpointState::Running);
         self.set_device_context(device_context)?;
         Ok(TrbCompletionCode::Success)
     }
@@ -472,7 +476,7 @@ impl DeviceSlot {
         trb: &ConfigureEndpointCommandTrb,
     ) -> Result<TrbCompletionCode> {
         usb_debug!("configuring endpoint");
-        let input_control_context = if trb.get_deconfigure() > 0 {
+        let input_control_context = if trb.get_deconfigure() {
             // From section 4.6.6 of the xHCI spec:
             // Setting the deconfigure (DC) flag to '1' in the Configure Endpoint Command
             // TRB is equivalent to setting Input Context Drop Context flags 2-31 to '1'
@@ -500,7 +504,7 @@ impl DeviceSlot {
             }
         }
 
-        if trb.get_deconfigure() > 0 {
+        if trb.get_deconfigure() {
             self.set_state(DeviceSlotState::Addressed)?;
         } else {
             self.set_state(DeviceSlotState::Configured)?;
@@ -572,7 +576,7 @@ impl DeviceSlot {
                     s.drop_one_endpoint(i)?;
                 }
                 let mut ctx = s.get_device_context()?;
-                ctx.slot_context.set_state(DeviceSlotState::Default);
+                ctx.slot_context.set_slot_state(DeviceSlotState::Default);
                 ctx.slot_context.set_context_entries(1);
                 ctx.slot_context.set_root_hub_port_number(0);
                 s.set_device_context(ctx)?;
@@ -636,7 +640,8 @@ impl DeviceSlot {
             Some(trc) => {
                 trc.set_dequeue_pointer(GuestAddress(ptr));
                 let mut ctx = self.get_device_context()?;
-                ctx.endpoint_context[index].set_tr_dequeue_pointer(ptr >> 4);
+                ctx.endpoint_context[index]
+                    .set_tr_dequeue_pointer(DequeuePtr::new(GuestAddress(ptr)));
                 self.set_device_context(ctx)?;
                 Ok(TrbCompletionCode::Success)
             }
@@ -677,14 +682,17 @@ impl DeviceSlot {
             device_context_index,
         )
         .map_err(Error::CreateTransferController)?;
-        trc.set_dequeue_pointer(GuestAddress(
-            device_context.endpoint_context[transfer_ring_index].get_tr_dequeue_pointer() << 4,
-        ));
+        trc.set_dequeue_pointer(
+            device_context.endpoint_context[transfer_ring_index]
+                .get_tr_dequeue_pointer()
+                .get_gpa(),
+        );
         trc.set_consumer_cycle_state(
-            device_context.endpoint_context[transfer_ring_index].get_dequeue_cycle_state() > 0,
+            device_context.endpoint_context[transfer_ring_index].get_dequeue_cycle_state(),
         );
         self.set_trc(transfer_ring_index, Some(trc));
-        device_context.endpoint_context[transfer_ring_index].set_state(EndpointState::Running);
+        device_context.endpoint_context[transfer_ring_index]
+            .set_endpoint_state(EndpointState::Running);
         self.set_device_context(device_context)
     }
 
@@ -692,7 +700,7 @@ impl DeviceSlot {
         let endpoint_index = (device_context_index - 1) as usize;
         self.set_trc(endpoint_index, None);
         let mut ctx = self.get_device_context()?;
-        ctx.endpoint_context[endpoint_index].set_state(EndpointState::Disabled);
+        ctx.endpoint_context[endpoint_index].set_endpoint_state(EndpointState::Disabled);
         self.set_device_context(ctx)
     }
 
@@ -752,7 +760,7 @@ impl DeviceSlot {
 
     fn set_state(&self, state: DeviceSlotState) -> Result<()> {
         let mut ctx = self.get_device_context()?;
-        ctx.slot_context.set_state(state);
+        ctx.slot_context.set_slot_state(state);
         self.set_device_context(ctx)
     }
 }
diff --git a/devices/src/usb/xhci/event_ring.rs b/devices/src/usb/xhci/event_ring.rs
index 4b510f1..fcaff23 100644
--- a/devices/src/usb/xhci/event_ring.rs
+++ b/devices/src/usb/xhci/event_ring.rs
@@ -80,7 +80,7 @@ impl EventRing {
         }
         // Event is write twice to avoid race condition.
         // Guest kernel use cycle bit to check ownership, thus we should write cycle last.
-        trb.set_cycle_bit(!self.producer_cycle_state);
+        trb.set_cycle(!self.producer_cycle_state);
         self.mem
             .write_obj_at_addr(trb, self.enqueue_pointer)
             .map_err(Error::MemoryWrite)?;
@@ -88,7 +88,7 @@ impl EventRing {
         // Updating the cycle state bit should always happen after updating other parts.
         fence(Ordering::SeqCst);
 
-        trb.set_cycle_bit(self.producer_cycle_state);
+        trb.set_cycle(self.producer_cycle_state);
 
         // Offset of cycle state byte.
         const CYCLE_STATE_OFFSET: usize = 12usize;
@@ -275,7 +275,7 @@ mod test {
         assert_eq!(er.is_empty(), false);
         let t: Trb = gm.read_obj_from_addr(GuestAddress(0x100)).unwrap();
         assert_eq!(t.get_control(), 1);
-        assert_eq!(t.get_cycle(), 1);
+        assert_eq!(t.get_cycle(), true);
 
         trb.set_control(2);
         assert_eq!(er.add_event(trb.clone()).unwrap(), ());
@@ -285,7 +285,7 @@ mod test {
             .read_obj_from_addr(GuestAddress(0x100 + trb_size))
             .unwrap();
         assert_eq!(t.get_control(), 2);
-        assert_eq!(t.get_cycle(), 1);
+        assert_eq!(t.get_cycle(), true);
 
         trb.set_control(3);
         assert_eq!(er.add_event(trb.clone()).unwrap(), ());
@@ -295,7 +295,7 @@ mod test {
             .read_obj_from_addr(GuestAddress(0x100 + 2 * trb_size))
             .unwrap();
         assert_eq!(t.get_control(), 3);
-        assert_eq!(t.get_cycle(), 1);
+        assert_eq!(t.get_cycle(), true);
 
         // Fill second table.
         trb.set_control(4);
@@ -304,7 +304,7 @@ mod test {
         assert_eq!(er.is_empty(), false);
         let t: Trb = gm.read_obj_from_addr(GuestAddress(0x200)).unwrap();
         assert_eq!(t.get_control(), 4);
-        assert_eq!(t.get_cycle(), 1);
+        assert_eq!(t.get_cycle(), true);
 
         trb.set_control(5);
         assert_eq!(er.add_event(trb.clone()).unwrap(), ());
@@ -314,7 +314,7 @@ mod test {
             .read_obj_from_addr(GuestAddress(0x200 + trb_size))
             .unwrap();
         assert_eq!(t.get_control(), 5);
-        assert_eq!(t.get_cycle(), 1);
+        assert_eq!(t.get_cycle(), true);
 
         trb.set_control(6);
         assert_eq!(er.add_event(trb.clone()).unwrap(), ());
@@ -324,7 +324,7 @@ mod test {
             .read_obj_from_addr(GuestAddress(0x200 + 2 * trb_size as u64))
             .unwrap();
         assert_eq!(t.get_control(), 6);
-        assert_eq!(t.get_cycle(), 1);
+        assert_eq!(t.get_cycle(), true);
 
         // Fill third table.
         trb.set_control(7);
@@ -333,7 +333,7 @@ mod test {
         assert_eq!(er.is_empty(), false);
         let t: Trb = gm.read_obj_from_addr(GuestAddress(0x300)).unwrap();
         assert_eq!(t.get_control(), 7);
-        assert_eq!(t.get_cycle(), 1);
+        assert_eq!(t.get_cycle(), true);
 
         trb.set_control(8);
         assert_eq!(er.add_event(trb.clone()).unwrap(), ());
@@ -344,7 +344,7 @@ mod test {
             .read_obj_from_addr(GuestAddress(0x300 + trb_size))
             .unwrap();
         assert_eq!(t.get_control(), 8);
-        assert_eq!(t.get_cycle(), 1);
+        assert_eq!(t.get_cycle(), true);
 
         // Add the last trb will result in error.
         match er.add_event(trb.clone()) {
@@ -367,7 +367,7 @@ mod test {
             .read_obj_from_addr(GuestAddress(0x300 + trb_size))
             .unwrap();
         assert_eq!(t.get_control(), 8);
-        assert_eq!(t.get_cycle(), 1);
+        assert_eq!(t.get_cycle(), true);
 
         // Add the last trb will result in error.
         match er.add_event(trb.clone()) {
@@ -388,7 +388,7 @@ mod test {
         let t: Trb = gm.read_obj_from_addr(GuestAddress(0x100)).unwrap();
         assert_eq!(t.get_control(), 10);
         // cycle bit should be reversed.
-        assert_eq!(t.get_cycle(), 0);
+        assert_eq!(t.get_cycle(), false);
 
         trb.set_control(11);
         assert_eq!(er.add_event(trb.clone()).unwrap(), ());
@@ -398,7 +398,7 @@ mod test {
             .read_obj_from_addr(GuestAddress(0x100 + trb_size))
             .unwrap();
         assert_eq!(t.get_control(), 11);
-        assert_eq!(t.get_cycle(), 0);
+        assert_eq!(t.get_cycle(), false);
 
         trb.set_control(12);
         assert_eq!(er.add_event(trb.clone()).unwrap(), ());
@@ -408,6 +408,6 @@ mod test {
             .read_obj_from_addr(GuestAddress(0x100 + 2 * trb_size))
             .unwrap();
         assert_eq!(t.get_control(), 12);
-        assert_eq!(t.get_cycle(), 0);
+        assert_eq!(t.get_cycle(), false);
     }
 }
diff --git a/devices/src/usb/xhci/interrupter.rs b/devices/src/usb/xhci/interrupter.rs
index a896fb4..c58ae59 100644
--- a/devices/src/usb/xhci/interrupter.rs
+++ b/devices/src/usb/xhci/interrupter.rs
@@ -87,8 +87,8 @@ impl Interrupter {
             .cast_mut::<PortStatusChangeEventTrb>()
             .map_err(Error::CastTrb)?;
         psctrb.set_port_id(port_id);
-        psctrb.set_completion_code(TrbCompletionCode::Success as u8);
-        psctrb.set_trb_type(TrbType::PortStatusChangeEvent as u8);
+        psctrb.set_completion_code(TrbCompletionCode::Success);
+        psctrb.set_trb_type(TrbType::PortStatusChangeEvent);
         self.add_event(trb)
     }
 
@@ -105,8 +105,8 @@ impl Interrupter {
             .map_err(Error::CastTrb)?;
         ctrb.set_trb_pointer(trb_addr.0);
         ctrb.set_command_completion_parameter(0);
-        ctrb.set_completion_code(completion_code as u8);
-        ctrb.set_trb_type(TrbType::CommandCompletionEvent as u8);
+        ctrb.set_completion_code(completion_code);
+        ctrb.set_trb_type(TrbType::CommandCompletionEvent);
         ctrb.set_vf_id(0);
         ctrb.set_slot_id(slot_id);
         self.add_event(trb)
@@ -126,9 +126,9 @@ impl Interrupter {
         let event_trb = trb.cast_mut::<TransferEventTrb>().map_err(Error::CastTrb)?;
         event_trb.set_trb_pointer(trb_pointer);
         event_trb.set_trb_transfer_length(transfer_length);
-        event_trb.set_completion_code(completion_code as u8);
+        event_trb.set_completion_code(completion_code);
         event_trb.set_event_data(event_data.into());
-        event_trb.set_trb_type(TrbType::TransferEvent as u8);
+        event_trb.set_trb_type(TrbType::TransferEvent);
         event_trb.set_endpoint_id(endpoint_id);
         event_trb.set_slot_id(slot_id);
         self.add_event(trb)
diff --git a/devices/src/usb/xhci/mod.rs b/devices/src/usb/xhci/mod.rs
index c652e90..42cdef5 100644
--- a/devices/src/usb/xhci/mod.rs
+++ b/devices/src/usb/xhci/mod.rs
@@ -15,8 +15,6 @@ mod xhci;
 #[allow(dead_code)]
 mod xhci_abi;
 #[allow(dead_code)]
-mod xhci_abi_schema;
-#[allow(dead_code)]
 mod xhci_regs;
 
 pub mod scatter_gather_buffer;
diff --git a/devices/src/usb/xhci/ring_buffer.rs b/devices/src/usb/xhci/ring_buffer.rs
index 72c9ec0..a178ebb 100644
--- a/devices/src/usb/xhci/ring_buffer.rs
+++ b/devices/src/usb/xhci/ring_buffer.rs
@@ -67,14 +67,14 @@ impl RingBuffer {
     pub fn dequeue_transfer_descriptor(&mut self) -> Result<Option<TransferDescriptor>> {
         let mut td: TransferDescriptor = TransferDescriptor::new();
         while let Some(addressed_trb) = self.get_current_trb()? {
-            if let Ok(TrbType::Link) = addressed_trb.trb.trb_type() {
+            if let Ok(TrbType::Link) = addressed_trb.trb.get_trb_type() {
                 let link_trb = addressed_trb
                     .trb
                     .cast::<LinkTrb>()
                     .map_err(Error::CastTrb)?;
                 self.dequeue_pointer = GuestAddress(link_trb.get_ring_segment_pointer());
                 self.consumer_cycle_state =
-                    self.consumer_cycle_state != link_trb.get_toggle_cycle_bit();
+                    self.consumer_cycle_state != link_trb.get_toggle_cycle();
                 continue;
             }
 
@@ -131,7 +131,7 @@ impl RingBuffer {
         usb_debug!("{}: trb read from memory {:?}", self.name.as_str(), trb);
         // If cycle bit of trb does not equal consumer cycle state, the ring is empty.
         // This trb is invalid.
-        if trb.get_cycle_bit() != self.consumer_cycle_state {
+        if trb.get_cycle() != self.consumer_cycle_state {
             usb_debug!(
                 "cycle bit does not match, self cycle {}",
                 self.consumer_cycle_state
@@ -163,9 +163,9 @@ mod test {
         //  trb 2  |   trb 4  |   trb 6
         //  l trb  -   l trb  -   l trb to 0x100
         let mut trb = NormalTrb::new();
-        trb.set_trb_type(TrbType::Normal as u8);
+        trb.set_trb_type(TrbType::Normal);
         trb.set_data_buffer(1);
-        trb.set_chain(1);
+        trb.set_chain(true);
         gm.write_obj_at_addr(trb.clone(), GuestAddress(0x100))
             .unwrap();
 
@@ -174,7 +174,7 @@ mod test {
             .unwrap();
 
         let mut ltrb = LinkTrb::new();
-        ltrb.set_trb_type(TrbType::Link as u8);
+        ltrb.set_trb_type(TrbType::Link);
         ltrb.set_ring_segment_pointer(0x200);
         gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + 2 * trb_size))
             .unwrap();
@@ -184,7 +184,7 @@ mod test {
 
         // Chain bit is false.
         trb.set_data_buffer(4);
-        trb.set_chain(0);
+        trb.set_chain(false);
         gm.write_obj_at_addr(trb, GuestAddress(0x200 + 1 * trb_size))
             .unwrap();
 
@@ -193,12 +193,12 @@ mod test {
             .unwrap();
 
         trb.set_data_buffer(5);
-        trb.set_chain(1);
+        trb.set_chain(true);
         gm.write_obj_at_addr(trb, GuestAddress(0x300)).unwrap();
 
         // Chain bit is false.
         trb.set_data_buffer(6);
-        trb.set_chain(0);
+        trb.set_chain(false);
         gm.write_obj_at_addr(trb, GuestAddress(0x300 + 1 * trb_size))
             .unwrap();
 
@@ -237,9 +237,9 @@ mod test {
         let mut transfer_ring = RingBuffer::new(String::new(), gm.clone());
 
         let mut trb = NormalTrb::new();
-        trb.set_trb_type(TrbType::Normal as u8);
+        trb.set_trb_type(TrbType::Normal);
         trb.set_data_buffer(1);
-        trb.set_chain(1);
+        trb.set_chain(true);
         gm.write_obj_at_addr(trb.clone(), GuestAddress(0x100))
             .unwrap();
 
@@ -248,9 +248,9 @@ mod test {
             .unwrap();
 
         let mut ltrb = LinkTrb::new();
-        ltrb.set_trb_type(TrbType::Link as u8);
+        ltrb.set_trb_type(TrbType::Link);
         ltrb.set_ring_segment_pointer(0x200);
-        ltrb.set_toggle_cycle(1);
+        ltrb.set_toggle_cycle(true);
         gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + 2 * trb_size))
             .unwrap();
 
diff --git a/devices/src/usb/xhci/ring_buffer_controller.rs b/devices/src/usb/xhci/ring_buffer_controller.rs
index 201441a..8dd5426 100644
--- a/devices/src/usb/xhci/ring_buffer_controller.rs
+++ b/devices/src/usb/xhci/ring_buffer_controller.rs
@@ -238,7 +238,6 @@ where
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::utils::FailHandle;
     use std::mem::size_of;
     use std::sync::mpsc::{channel, Sender};
 
@@ -253,7 +252,7 @@ mod tests {
             complete_event: EventFd,
         ) -> std::result::Result<(), ()> {
             for atrb in descriptor {
-                assert_eq!(atrb.trb.trb_type().unwrap(), TrbType::Normal);
+                assert_eq!(atrb.trb.get_trb_type().unwrap(), TrbType::Normal);
                 self.sender.send(atrb.trb.get_parameter() as i32).unwrap();
             }
             complete_event.write(1).unwrap();
@@ -271,9 +270,9 @@ mod tests {
         //  trb 2  |   trb 4  |   trb 6
         //  l trb  -   l trb  -   l trb to 0x100
         let mut trb = NormalTrb::new();
-        trb.set_trb_type(TrbType::Normal as u8);
+        trb.set_trb_type(TrbType::Normal);
         trb.set_data_buffer(1);
-        trb.set_chain(1);
+        trb.set_chain(true);
         gm.write_obj_at_addr(trb.clone(), GuestAddress(0x100))
             .unwrap();
 
@@ -282,7 +281,7 @@ mod tests {
             .unwrap();
 
         let mut ltrb = LinkTrb::new();
-        ltrb.set_trb_type(TrbType::Link as u8);
+        ltrb.set_trb_type(TrbType::Link);
         ltrb.set_ring_segment_pointer(0x200);
         gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + 2 * trb_size))
             .unwrap();
@@ -292,7 +291,7 @@ mod tests {
 
         // Chain bit is false.
         trb.set_data_buffer(4);
-        trb.set_chain(0);
+        trb.set_chain(false);
         gm.write_obj_at_addr(trb, GuestAddress(0x200 + 1 * trb_size))
             .unwrap();
 
@@ -301,12 +300,12 @@ mod tests {
             .unwrap();
 
         trb.set_data_buffer(5);
-        trb.set_chain(1);
+        trb.set_chain(true);
         gm.write_obj_at_addr(trb, GuestAddress(0x300)).unwrap();
 
         // Chain bit is false.
         trb.set_data_buffer(6);
-        trb.set_chain(0);
+        trb.set_chain(false);
         gm.write_obj_at_addr(trb, GuestAddress(0x300 + 1 * trb_size))
             .unwrap();
 
diff --git a/devices/src/usb/xhci/scatter_gather_buffer.rs b/devices/src/usb/xhci/scatter_gather_buffer.rs
index da43b33..0150e4f 100644
--- a/devices/src/usb/xhci/scatter_gather_buffer.rs
+++ b/devices/src/usb/xhci/scatter_gather_buffer.rs
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 use super::xhci_abi::{Error as TrbError, NormalTrb, TransferDescriptor, TrbCast, TrbType};
+use bit_field::Error as BitFieldError;
 use std::fmt::{self, Display};
 use sys_util::{GuestAddress, GuestMemory, GuestMemoryError};
 
@@ -10,7 +11,7 @@ use sys_util::{GuestAddress, GuestMemory, GuestMemoryError};
 pub enum Error {
     ReadGuestMemory(GuestMemoryError),
     WriteGuestMemory(GuestMemoryError),
-    UnknownTrbType(TrbError),
+    UnknownTrbType(BitFieldError),
     CastTrb(TrbError),
     BadTrbType(TrbType),
 }
@@ -42,7 +43,7 @@ impl ScatterGatherBuffer {
     /// Create a new buffer from transfer descriptor.
     pub fn new(mem: GuestMemory, td: TransferDescriptor) -> Result<ScatterGatherBuffer> {
         for atrb in &td {
-            let trb_type = atrb.trb.trb_type().map_err(Error::UnknownTrbType)?;
+            let trb_type = atrb.trb.get_trb_type().map_err(Error::UnknownTrbType)?;
             if trb_type != TrbType::Normal
                 && trb_type != TrbType::DataStage
                 && trb_type != TrbType::Isoch
@@ -138,21 +139,21 @@ mod test {
 
         let mut trb = Trb::new();
         let ntrb = trb.cast_mut::<NormalTrb>().unwrap();
-        ntrb.set_trb_type(TrbType::Normal as u8);
+        ntrb.set_trb_type(TrbType::Normal);
         ntrb.set_data_buffer(0x100);
         ntrb.set_trb_transfer_length(4);
         td.push(AddressedTrb { trb, gpa: 0 });
 
         let mut trb = Trb::new();
         let ntrb = trb.cast_mut::<NormalTrb>().unwrap();
-        ntrb.set_trb_type(TrbType::Normal as u8);
+        ntrb.set_trb_type(TrbType::Normal);
         ntrb.set_data_buffer(0x200);
         ntrb.set_trb_transfer_length(2);
         td.push(AddressedTrb { trb, gpa: 0 });
 
         let mut trb = Trb::new();
         let ntrb = trb.cast_mut::<NormalTrb>().unwrap();
-        ntrb.set_trb_type(TrbType::Normal as u8);
+        ntrb.set_trb_type(TrbType::Normal);
         ntrb.set_data_buffer(0x300);
         ntrb.set_trb_transfer_length(1);
         td.push(AddressedTrb { trb, gpa: 0 });
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
+        );
+    }
+}
diff --git a/devices/src/usb/xhci/xhci_abi_schema.rs b/devices/src/usb/xhci/xhci_abi_schema.rs
deleted file mode 100644
index 91ca7c1..0000000
--- a/devices/src/usb/xhci/xhci_abi_schema.rs
+++ /dev/null
@@ -1,543 +0,0 @@
-// 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, 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
-        );
-    }
-}
diff --git a/devices/src/usb/xhci/xhci_transfer.rs b/devices/src/usb/xhci/xhci_transfer.rs
index eb0c782..e166c1a 100644
--- a/devices/src/usb/xhci/xhci_transfer.rs
+++ b/devices/src/usb/xhci/xhci_transfer.rs
@@ -10,6 +10,7 @@ use super::xhci_abi::{
     TrbCompletionCode, TrbType,
 };
 use super::xhci_regs::MAX_INTERRUPTER;
+use bit_field::Error as BitFieldError;
 use std::cmp::min;
 use std::fmt::{self, Display};
 use std::mem;
@@ -21,7 +22,7 @@ use usb_util::usb_transfer::TransferStatus;
 
 #[derive(Debug)]
 pub enum Error {
-    TrbType(TrbError),
+    TrbType(BitFieldError),
     CastTrb(TrbError),
     TransferLength(TrbError),
     BadTrbType(TrbType),
@@ -114,7 +115,7 @@ impl XhciTransferType {
     pub fn new(mem: GuestMemory, td: TransferDescriptor) -> Result<XhciTransferType> {
         // We can figure out transfer type from the first trb.
         // See transfer descriptor description in xhci spec for more details.
-        match td[0].trb.trb_type().map_err(Error::TrbType)? {
+        match td[0].trb.get_trb_type().map_err(Error::TrbType)? {
             TrbType::Normal => {
                 let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
                 Ok(XhciTransferType::Normal(buffer))
@@ -329,7 +330,7 @@ impl XhciTransfer {
                 || (atrb.trb.interrupt_on_short_packet() && edtla > bytes_transferred)
             {
                 // For details about event data trb and EDTLA, see spec 4.11.5.2.
-                if atrb.trb.trb_type().map_err(Error::TrbType)? == TrbType::EventData {
+                if atrb.trb.get_trb_type().map_err(Error::TrbType)? == TrbType::EventData {
                     let tlength = min(edtla, bytes_transferred);
                     self.interrupter
                         .lock()