Rust XHCI Data Structure Types.
This commit is contained in:
parent
d5d7e2c7ab
commit
8b022a6b24
11 changed files with 809 additions and 4 deletions
17
rust/Cargo.lock
generated
17
rust/Cargo.lock
generated
|
|
@ -19,6 +19,17 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitfield-struct"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8769c4854c5ada2852ddf6fd09d15cf43d4c2aaeccb4de6432f5402f08a6003b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "convert_case"
|
name = "convert_case"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
|
|
@ -32,7 +43,7 @@ dependencies = [
|
||||||
name = "denali"
|
name = "denali"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitfield-struct",
|
"bitfield-struct 0.8.0",
|
||||||
"mammoth",
|
"mammoth",
|
||||||
"pci",
|
"pci",
|
||||||
"yellowstone-yunq",
|
"yellowstone-yunq",
|
||||||
|
|
@ -88,7 +99,7 @@ dependencies = [
|
||||||
name = "pci"
|
name = "pci"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitfield-struct",
|
"bitfield-struct 0.8.0",
|
||||||
"mammoth",
|
"mammoth",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -193,7 +204,7 @@ dependencies = [
|
||||||
name = "voyageurs"
|
name = "voyageurs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitfield-struct",
|
"bitfield-struct 0.12.1",
|
||||||
"mammoth",
|
"mammoth",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,5 @@ version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitfield-struct = "0.8.0"
|
bitfield-struct = "0.12"
|
||||||
mammoth = { path = "../../lib/mammoth/" }
|
mammoth = { path = "../../lib/mammoth/" }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
use crate::xhci::data_structures::{EndpointContext, SlotContext};
|
||||||
|
|
||||||
|
#[repr(C, align(64))]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct DeviceContext {
|
||||||
|
slot_context: SlotContext,
|
||||||
|
endpoint_context_0: EndpointContext,
|
||||||
|
endpoint_contexts: [EndpointContext; 30],
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(size_of::<DeviceContext>() == 0x400);
|
||||||
206
rust/sys/voyageurs/src/xhci/data_structures/endpoint_context.rs
Normal file
206
rust/sys/voyageurs/src/xhci/data_structures/endpoint_context.rs
Normal file
|
|
@ -0,0 +1,206 @@
|
||||||
|
use bitfield_struct::{bitenum, bitfield};
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[bitenum]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum EndpointState {
|
||||||
|
/// The endpoint is not operationa.
|
||||||
|
Disabled = 0,
|
||||||
|
/// The endpoint is operational, either waiting for a doorbell ring or processing TDs.
|
||||||
|
Running = 1,
|
||||||
|
/// The endpoint is halted due to a Halt condition detected on the USB. SW shall issue
|
||||||
|
/// Reset Endpoint Command to recover from the Halt condition and transition to the Stopped
|
||||||
|
/// state. SW may manipulate the Transfer Ring while in this state
|
||||||
|
Halted = 2,
|
||||||
|
/// The endpoint is not running due to a Stop Endpoint Command or recovering
|
||||||
|
/// from a Halt condition. SW may manipulate the Transfer Ring while in this state.
|
||||||
|
Stopped = 3,
|
||||||
|
/// The endpoint is not running due to a TRB Error. SW may manipulate the Transfer
|
||||||
|
/// Ring while in this state.
|
||||||
|
Error = 4,
|
||||||
|
#[fallback]
|
||||||
|
Unknown = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[bitenum]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum EndpointType {
|
||||||
|
#[fallback]
|
||||||
|
NotValid = 0,
|
||||||
|
IsochOut = 1,
|
||||||
|
BulkOut = 2,
|
||||||
|
InterruptOut = 3,
|
||||||
|
Control = 4,
|
||||||
|
IsochIn = 5,
|
||||||
|
BulkIn = 6,
|
||||||
|
InterruptIn = 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield(u64)]
|
||||||
|
pub struct EndpointContextFields {
|
||||||
|
/// Endpoint State (EP State). The Endpoint State identifies the current operational state of the
|
||||||
|
/// endpoint.
|
||||||
|
///
|
||||||
|
/// As Output, a Running to Halted transition is forced by the xHC if a STALL condition is detected
|
||||||
|
/// on the endpoint. A Running to Error transition is forced by the xHC if a TRB Error condition is
|
||||||
|
/// detected.
|
||||||
|
///
|
||||||
|
/// As Input, this field is initialized to ‘0’ by software.
|
||||||
|
///
|
||||||
|
/// Refer to section 4.8.3 for more information on Endpoint State.
|
||||||
|
#[bits(3)]
|
||||||
|
pub endpoint_state: EndpointState,
|
||||||
|
#[bits(5)]
|
||||||
|
__: u8,
|
||||||
|
/// Mult. If LEC = ‘0’, then this field indicates the maximum number of bursts within an Interval that
|
||||||
|
/// this endpoint supports. Mult is a “zero-based” value, where 0 to 3 represents 1 to 4 bursts,
|
||||||
|
/// respectively. The valid range of values is ‘0’ to ‘2’.111 This field shall be ‘0’ for all endpoint types
|
||||||
|
/// except for SS Isochronous.
|
||||||
|
///
|
||||||
|
/// If LEC = ‘1’, then this field shall be RsvdZ and Mult is calculated as:
|
||||||
|
/// ROUNDUP(Max ESIT Payload / Max Packet Size / (Max Burst Size + 1)) - 1
|
||||||
|
#[bits(2)]
|
||||||
|
pub mult: u8,
|
||||||
|
/// Max Primary Streams (MaxPStreams). This field identifies the maximum number of Primary
|
||||||
|
/// Stream IDs this endpoint supports. Valid values are defined below. If the value of this field is ‘0’,
|
||||||
|
/// then the TR Dequeue Pointer field shall point to a Transfer Ring. If this field is > '0' then the TR
|
||||||
|
/// Dequeue Pointer field shall point to a Primary Stream Context Array. Refer to section 4.12 for
|
||||||
|
/// more information.
|
||||||
|
///
|
||||||
|
/// A value of ‘0’ indicates that Streams are not supported by this endpoint and the Endpoint
|
||||||
|
/// Context TR Dequeue Pointer field references a Transfer Ring.
|
||||||
|
///
|
||||||
|
/// A value of ‘1’ to ‘15’ indicates that the Primary Stream ID Width is MaxPstreams+1 and the
|
||||||
|
/// Primary Stream Array contains 2MaxPStreams+1 entries.
|
||||||
|
///
|
||||||
|
/// For SS Bulk endpoints, the range of valid values for this field is defined by the MaxPSASize field
|
||||||
|
/// in the HCCPARAMS1 register (refer to Table 5-13).
|
||||||
|
///
|
||||||
|
/// This field shall be '0' for all SS Control, Isoch, and Interrupt endpoints, and for all non-SS
|
||||||
|
/// endpoints.
|
||||||
|
#[bits(5)]
|
||||||
|
pub max_primary_streams: u8,
|
||||||
|
/// Linear Stream Array (LSA). This field identifies how a Stream ID shall be interpreted.
|
||||||
|
/// Setting this bit to a value of ‘1’ shall disable Secondary Stream Arrays and a Stream ID shall be
|
||||||
|
/// interpreted as a linear index into the Primary Stream Array, where valid values for MaxPStreams
|
||||||
|
/// are ‘1’ to ‘15’.
|
||||||
|
///
|
||||||
|
/// A value of ‘0’ shall enable Secondary Stream Arrays, where the low order (MaxPStreams+1) bits
|
||||||
|
/// of a Stream ID shall be interpreted as a linear index into the Primary Stream Array, where valid
|
||||||
|
/// values for MaxPStreams are ‘1’ to ‘7’. And the high order bits of a Stream ID shall be interpreted
|
||||||
|
/// as a linear index into the Secondary Stream Array.
|
||||||
|
///
|
||||||
|
/// If MaxPStreams = ‘0’, this field RsvdZ.
|
||||||
|
///
|
||||||
|
/// Refer to section 4.12.2 for more information
|
||||||
|
pub linear_stream_array: bool,
|
||||||
|
/// Interval. The period between consecutive requests to a USB endpoint to send or receive data.
|
||||||
|
/// Expressed in 125 μs. increments. The period is calculated as 125 μs. * 2Interval; e.g., an Interval
|
||||||
|
/// value of 0 means a period of 125 μs. (20 = 1 * 125 μs.), a value of 1 means a period of 250 μs. (21
|
||||||
|
/// = 2 * 125 μs.), a value of 4 means a period of 2 ms. (24 = 16 * 125 μs.), etc. Refer to Table 6-12
|
||||||
|
/// for legal Interval field values. See further discussion of this field below. Refer to section 6.2.3.6
|
||||||
|
/// for more information.
|
||||||
|
pub interval: u8,
|
||||||
|
/// Max Endpoint Service Time Interval Payload High (Max ESIT Payload Hi). If LEC = '1', then this
|
||||||
|
/// field indicates the high order 8 bits of the Max ESIT Payload value. If LEC = '0', then this field
|
||||||
|
/// shall be RsvdZ. Refer to section 6.2.3.8 for more information.
|
||||||
|
pub max_esit_payload_hi: u8,
|
||||||
|
__: bool,
|
||||||
|
/// Error Count (CErr)112. This field defines a 2-bit down count, which identifies the number of
|
||||||
|
/// consecutive USB Bus Errors allowed while executing a TD. If this field is programmed with a
|
||||||
|
/// non-zero value when the Endpoint Context is initialized, the xHC loads this value into an internal
|
||||||
|
/// Bus Error Counter before executing a USB transaction and decrements it if the transaction fails.
|
||||||
|
/// If the Bus Error Counter counts from ‘1’ to ‘0’, the xHC ceases execution of the TRB, sets the
|
||||||
|
/// endpoint to the Halted state, and generates a USB Transaction Error Event for the TRB that
|
||||||
|
/// caused the internal Bus Error Counter to decrement to ‘0’. If system software programs this field
|
||||||
|
/// to ‘0’, the xHC shall not count errors for TRBs on the Endpoint’s Transfer Ring and there shall be
|
||||||
|
/// no limit on the number of TRB retries. Refer to section 4.10.2.7 for more information on the
|
||||||
|
/// operation of the Bus Error Counter.
|
||||||
|
///
|
||||||
|
/// Note: CErr does not apply to Isoch endpoints and shall be set to ‘0’ if EP Type = Isoch Out ('1') or
|
||||||
|
/// Isoch In ('5').
|
||||||
|
#[bits(2)]
|
||||||
|
pub error_count: u8,
|
||||||
|
/// Endpoint Type (EP Type). This field identifies whether an Endpoint Context is Valid, and if so,
|
||||||
|
/// what type of endpoint the context defines.
|
||||||
|
#[bits(3)]
|
||||||
|
pub endpoint_type: EndpointType,
|
||||||
|
__: bool,
|
||||||
|
/// Host Initiate Disable (HID). This field affects Stream enabled endpoints, allowing the Host
|
||||||
|
/// Initiated Stream selection feature to be disabled for the endpoint. Setting this bit to a value of
|
||||||
|
/// ‘1’ shall disable the Host Initiated Stream selection feature. A value of ‘0’ will enable normal
|
||||||
|
/// Stream operation. Refer to section 4.12.1.1 for more information.
|
||||||
|
pub host_initiate_disable: bool,
|
||||||
|
/// Max Burst Size. This field indicates to the xHC the maximum number of consecutive USB
|
||||||
|
/// transactions that should be executed per scheduling opportunity. This is a “zero-based” value,
|
||||||
|
/// where 0 to 15 represents burst sizes of 1 to 16, respectively. Refer to section 6.2.3.4 for more
|
||||||
|
/// information.
|
||||||
|
pub max_burst_size: u8,
|
||||||
|
/// Max Packet Size. This field indicates the maximum packet size in bytes that this endpoint is
|
||||||
|
/// capable of sending or receiving when configured. Refer to section 6.2.3.5 for more information
|
||||||
|
pub max_packet_size: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield(u64)]
|
||||||
|
pub struct TRDequeuePointer {
|
||||||
|
/// Dequeue Cycle State (DCS). This bit identifies the value of the xHC Consumer Cycle State (CCS)
|
||||||
|
/// flag for the TRB referenced by the TR Dequeue Pointer. Refer to section 4.9.2 for more
|
||||||
|
/// information. This field shall be ‘0’ if MaxPStreams > ‘0’
|
||||||
|
pub dequeue_cycle_state: bool,
|
||||||
|
#[bits(3)]
|
||||||
|
__: u8,
|
||||||
|
/// TR Dequeue Pointer. As Input, this field represents the high order bits of the 64-bit base
|
||||||
|
/// address of a Transfer Ring or a Stream Context Array associated with this endpoint. If
|
||||||
|
/// MaxPStreams = '0' then this field shall point to a Transfer Ring. If MaxPStreams > '0' then this
|
||||||
|
/// field shall point to a Stream Context Array.
|
||||||
|
///
|
||||||
|
/// As Output, if MaxPStreams = ‘0’ this field shall be used by the xHC to store the value of the
|
||||||
|
/// Dequeue Pointer when the endpoint enters the Halted or Stopped states, and the value of the
|
||||||
|
/// this field shall be undefined when the endpoint is not in the Halted or Stopped states. if
|
||||||
|
/// MaxPStreams > ‘0’ then this field shall point to a Stream Context Array.
|
||||||
|
/// The memory structure referenced by this physical memory pointer shall be aligned to a 16-byte
|
||||||
|
/// boundary.
|
||||||
|
#[bits(60)]
|
||||||
|
tr_deque_pointer: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TRDequeuePointer {
|
||||||
|
pub fn pointer(self) -> u64 {
|
||||||
|
self.tr_deque_pointer() << 4
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_pointer(&mut self, tr_deque_pointer: u64) {
|
||||||
|
self.set_tr_deque_pointer(tr_deque_pointer >> 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_pointer(self, tr_deque_pointer: u64) -> Self {
|
||||||
|
self.with_tr_deque_pointer(tr_deque_pointer >> 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield(u64)]
|
||||||
|
struct AdditionalFields {
|
||||||
|
/// Average TRB Length. This field represents the average Length of the TRBs executed by this
|
||||||
|
/// endpoint. The value of this field shall be greater than ‘0’. Refer to section 4.14.1.1 and the
|
||||||
|
/// implementation note TRB Lengths and System Bus Bandwidth for more information.
|
||||||
|
/// The xHC shall use this parameter to calculate system bus bandwidth requirements
|
||||||
|
pub average_trb_length: u16,
|
||||||
|
/// Max Endpoint Service Time Interval Payload Low (Max ESIT Payload Lo). This field indicates
|
||||||
|
/// the low order 16 bits of the Max ESIT Payload. The Max ESIT Payload represents the total
|
||||||
|
/// number of bytes this endpoint will transfer during an ESIT. This field is only valid for periodic
|
||||||
|
/// endpoints. Refer to section 6.2.3.8 for more information.
|
||||||
|
pub max_esit_payload_lo: u16,
|
||||||
|
__: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct EndpointContext {
|
||||||
|
pub fields: EndpointContextFields,
|
||||||
|
pub tr_deque_pointer: TRDequeuePointer,
|
||||||
|
additional_fields: AdditionalFields,
|
||||||
|
__: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(size_of::<EndpointContext>() == 0x20);
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
use core::ops::{Index, IndexMut};
|
||||||
|
|
||||||
|
use mammoth::physical_box::PhysicalBox;
|
||||||
|
|
||||||
|
use crate::xhci::data_structures::TrbRingSegment;
|
||||||
|
|
||||||
|
#[repr(align(64))]
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct EventRingSegmentTableEntry {
|
||||||
|
/// Ring Segment Base Address Hi and Lo. These fields represent the high order bits of the 64-bit
|
||||||
|
/// base address of the Event Ring Segment.
|
||||||
|
/// The memory structure referenced by this physical memory pointer shall begin on a 64-byte
|
||||||
|
/// address boundary.
|
||||||
|
pub ring_segment_base_address: u64,
|
||||||
|
/// Ring Segment Size. This field defines the number of TRBs supported by the ring segment, Valid
|
||||||
|
/// values for this field are 16 to 4096, i.e. an Event Ring segment shall contain at least 16 entries
|
||||||
|
pub ring_segment_size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventRingSegmentTableEntry {
|
||||||
|
pub fn update_from_trb_ring(&mut self, trb_ring: &TrbRingSegment) {
|
||||||
|
mammoth::debug!("RSTE: {:0x}", self as *const _ as usize);
|
||||||
|
self.ring_segment_base_address = trb_ring.physical_address() as u64;
|
||||||
|
assert!(self.ring_segment_base_address.is_multiple_of(64));
|
||||||
|
unsafe {
|
||||||
|
core::ptr::write_volatile(
|
||||||
|
&mut self.ring_segment_size as *mut u64,
|
||||||
|
trb_ring.len() as u64,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
assert!(self.ring_segment_size >= 16);
|
||||||
|
assert!(self.ring_segment_size <= 4096);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EventRingSegmentTable(PhysicalBox<[EventRingSegmentTableEntry]>);
|
||||||
|
|
||||||
|
impl EventRingSegmentTable {
|
||||||
|
pub fn new(size: usize) -> Self {
|
||||||
|
Self(PhysicalBox::default_with_count(
|
||||||
|
EventRingSegmentTableEntry::default(),
|
||||||
|
size,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn physical_address(&self) -> usize {
|
||||||
|
self.0.physical_address()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for EventRingSegmentTable {
|
||||||
|
type Output = EventRingSegmentTableEntry;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
&self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for EventRingSegmentTable {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
&mut self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
33
rust/sys/voyageurs/src/xhci/data_structures/input_context.rs
Normal file
33
rust/sys/voyageurs/src/xhci/data_structures/input_context.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
use bitfield_struct::bitfield;
|
||||||
|
|
||||||
|
use crate::xhci::data_structures::{EndpointContext, SlotContext};
|
||||||
|
|
||||||
|
#[bitfield(u32)]
|
||||||
|
pub struct InputControlContextSettings {
|
||||||
|
configuration_value: u8,
|
||||||
|
interface_number: u8,
|
||||||
|
alternate_setting: u8,
|
||||||
|
__: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct InputControlContext {
|
||||||
|
pub drop_context_flags: u32,
|
||||||
|
pub add_context_flags: u32,
|
||||||
|
__: [u32; 5],
|
||||||
|
settings: InputControlContextSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(size_of::<InputControlContext>() == 0x20);
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct InputContext {
|
||||||
|
pub input_control_context: InputControlContext,
|
||||||
|
pub slot_context: SlotContext,
|
||||||
|
pub endpoint_context_0: EndpointContext,
|
||||||
|
pub endpoint_contexts: [EndpointContext; 30],
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(size_of::<InputContext>() == 0x420);
|
||||||
15
rust/sys/voyageurs/src/xhci/data_structures/mod.rs
Normal file
15
rust/sys/voyageurs/src/xhci/data_structures/mod.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
mod device_context;
|
||||||
|
mod endpoint_context;
|
||||||
|
mod event_ring_segment_table;
|
||||||
|
mod input_context;
|
||||||
|
mod slot_context;
|
||||||
|
mod trb;
|
||||||
|
mod trb_ring_segment;
|
||||||
|
|
||||||
|
pub use device_context::*;
|
||||||
|
pub use endpoint_context::*;
|
||||||
|
pub use event_ring_segment_table::*;
|
||||||
|
pub use input_context::*;
|
||||||
|
pub use slot_context::*;
|
||||||
|
pub use trb::*;
|
||||||
|
pub use trb_ring_segment::*;
|
||||||
134
rust/sys/voyageurs/src/xhci/data_structures/slot_context.rs
Normal file
134
rust/sys/voyageurs/src/xhci/data_structures/slot_context.rs
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
use bitfield_struct::bitfield;
|
||||||
|
|
||||||
|
#[bitfield(u128)]
|
||||||
|
pub struct SlotContextFields {
|
||||||
|
/// Route String. This field is used by hubs to route packets to the correct downstream port. The
|
||||||
|
/// format of the Route String is defined in section 8.9 the USB3 specification.
|
||||||
|
/// As Input, this field shall be set for all USB devices, irrespective of their speed, to indicate their
|
||||||
|
/// location in the USB topology.
|
||||||
|
#[bits(20)]
|
||||||
|
pub route_string: u32,
|
||||||
|
/// Speed. This field is deprecated in this version of the specification and shall be Reserved.
|
||||||
|
/// This field indicates the speed of the device. Refer to the PORTSC Port Speed field in Table 5-27
|
||||||
|
/// for the definition of the valid values
|
||||||
|
#[bits(4)]
|
||||||
|
pub speed: u8,
|
||||||
|
__: bool,
|
||||||
|
/// Multi-TT (MTT). This flag is set to '1' by software if this is a High-speed hub that supports
|
||||||
|
/// Multiple TTs and the Multiple TT Interface has been enabled by software, or if this is a Low-
|
||||||
|
/// /Full-speed device or Full-speed hub and connected to the xHC through a parent108 High-speed
|
||||||
|
/// hub that supports Multiple TTs and the Multiple TT Interface of the parent hub has been
|
||||||
|
/// enabled by software, or ‘0’ if not.
|
||||||
|
pub multi_tt: bool,
|
||||||
|
/// Hub. This flag is set to '1' by software if this device is a USB hub, or '0' if it is a USB function
|
||||||
|
pub hub: bool,
|
||||||
|
/// Context Entries. This field identifies the index of the last valid Endpoint Context within this
|
||||||
|
/// Device Context structure. The value of ‘0’ is Reserved and is not a valid entry for this field. Valid
|
||||||
|
/// entries for this field shall be in the range of 1-31. This field indicates the size of the Device
|
||||||
|
/// Context structure. For example, ((Context Entries+1) * 32 bytes) = Total bytes for this structure.
|
||||||
|
///
|
||||||
|
/// Note, Output Context Entries values are written by the xHC, and Input Context Entries values are
|
||||||
|
/// written by software.
|
||||||
|
#[bits(5)]
|
||||||
|
pub context_entries: u8,
|
||||||
|
/// Max Exit Latency. The Maximum Exit Latency is in microseconds, and indicates the worst case
|
||||||
|
/// time it takes to wake up all the links in the path to the device, given the current USB link level
|
||||||
|
/// power management settings.
|
||||||
|
///
|
||||||
|
/// Refer to section 4.23.5.2 for more information on the use of this field.
|
||||||
|
pub max_exit_latency: u16,
|
||||||
|
/// Root Hub Port Number. This field identifies the Root Hub Port Number used to access the USB
|
||||||
|
/// device. Refer to section 4.19.7 for port numbering information.
|
||||||
|
///
|
||||||
|
/// Note: Ports are numbered from 1 to MaxPorts
|
||||||
|
pub root_hub_port_number: u8,
|
||||||
|
/// Number of Ports. If this device is a hub (Hub = ‘1’), then this field is set by software to identify
|
||||||
|
/// the number of downstream facing ports supported by the hub. Refer to the bNbrPorts field
|
||||||
|
/// description in the Hub Descriptor (Table 11-13) of the USB2 spec. If this device is not a hub (Hub
|
||||||
|
/// = ‘0’), then this field shall be ‘0
|
||||||
|
pub number_of_ports: u8,
|
||||||
|
/// Parent Hub Slot ID. If this device is Low-/Full-speed and connected through a High-speed hub,
|
||||||
|
/// then this field shall contain the Slot ID of the parent High-speed hub109.
|
||||||
|
///
|
||||||
|
/// For SS and SSP bus instance, if this device is connected through a higher rank hub110 then this
|
||||||
|
/// field shall contain the Slot ID of the parent hub. For example, a Gen1 x1 connected behind a
|
||||||
|
/// Gen1 x2 hub, or Gen1 x2 device connected behind Gen2 x2 hub.
|
||||||
|
///
|
||||||
|
/// This field shall be ‘0’ if any of the following are true:
|
||||||
|
/// Device is attached to a Root Hub port
|
||||||
|
/// Device is a High-Speed device
|
||||||
|
/// Device is the highest rank SS/SSP device supported by xHCI
|
||||||
|
pub parent_hub_slot_id: u8,
|
||||||
|
/// Parent Port Number. If this device is Low-/Full-speed and connected through a High-speed
|
||||||
|
/// hub, then this field shall contain the number of the downstream facing port of the parent High-
|
||||||
|
/// speed hub109.
|
||||||
|
/// For SS and SSP bus instance, if this device is connected through a higher rank hub110 then this
|
||||||
|
/// field shall contain the number of the downstream facing port of the parent hub. For example, a
|
||||||
|
/// Gen1 x1 connected behind a Gen1 x2 hub, or Gen1 x2 device connected behind Gen2 x2 hub.
|
||||||
|
/// This field shall be ‘0’ if any of the following are true:
|
||||||
|
/// Device is attached to a Root Hub port
|
||||||
|
/// Device is a High-Speed device
|
||||||
|
/// Device is the highest rank SS/SSP device supported by xH
|
||||||
|
pub parent_port_number: u8,
|
||||||
|
/// TT Think Time (TTT). If this is a High-speed hub (Hub = ‘1’ and Speed = High-Speed), then this
|
||||||
|
/// field shall be set by software to identify the time the TT of the hub requires to proceed to the
|
||||||
|
/// next full-/low-speed transaction.
|
||||||
|
/// Value Think Time
|
||||||
|
/// 0 TT requires at most 8 FS bit times of inter-transaction gap on a full-/low-speed
|
||||||
|
/// downstream bus.
|
||||||
|
/// 1 TT requires at most 16 FS bit times.
|
||||||
|
/// 2 TT requires at most 24 FS bit times.
|
||||||
|
/// 3 TT requires at most 32 FS bit times.
|
||||||
|
/// Refer to the TT Think Time sub-field of the wHubCharacteristics field description in the Hub
|
||||||
|
/// Descriptor (Table 11-13) and section 11.18.2 of the USB2 spec for more information on TT
|
||||||
|
/// Think Time. If this device is not a High-speed hub (Hub = ‘0’ or Speed != High-speed), then this
|
||||||
|
/// field shall be ‘0’.
|
||||||
|
#[bits(2)]
|
||||||
|
pub tt_think_time: u8,
|
||||||
|
#[bits(4)]
|
||||||
|
__: u8,
|
||||||
|
/// Interrupter Target. This field defines the index of the Interrupter that will receive Bandwidth
|
||||||
|
/// Request Events and Device Notification Events generated by this slot, or when a Ring Underrun
|
||||||
|
/// or Ring Overrun condition is reported (refer to section 4.10.3.1). Valid values are between 0 and
|
||||||
|
/// MaxIntrs-1
|
||||||
|
#[bits(10)]
|
||||||
|
pub interrupter_target: u16,
|
||||||
|
/// USB Device Address. This field identifies the address assigned to the USB device by the xHC,
|
||||||
|
/// and is set upon the successful completion of a Set Address Command. Refer to the USB2 spec
|
||||||
|
/// for a more detailed description.
|
||||||
|
///
|
||||||
|
/// As Output, this field is invalid if the Slot State = Disabled or Default.
|
||||||
|
/// As Input, software shall initialize the field to ‘0’.
|
||||||
|
pub usb_device_address: u8,
|
||||||
|
|
||||||
|
#[bits(19)]
|
||||||
|
__: u32,
|
||||||
|
|
||||||
|
/// Slot State. This field is updated by the xHC when a Device Slot transitions from one state to
|
||||||
|
/// another.
|
||||||
|
/// Value Slot State
|
||||||
|
/// 0 Disabled/Enabled
|
||||||
|
/// 1 Default
|
||||||
|
/// 2 Addressed
|
||||||
|
/// 3 Configured
|
||||||
|
/// 31-4 Reserved
|
||||||
|
///
|
||||||
|
/// Slot States are defined in section 4.5.3.
|
||||||
|
///
|
||||||
|
/// As Output, since software initializes all fields of the Device Context data structure to ‘0’, this field
|
||||||
|
/// shall initially indicate the Disabled state.
|
||||||
|
///
|
||||||
|
/// As Input, software shall initialize the field to ‘0’.
|
||||||
|
/// Refer to section 4.5.3 for more information on Slot State.
|
||||||
|
#[bits(5)]
|
||||||
|
pub slot_state: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct SlotContext {
|
||||||
|
pub fields: SlotContextFields,
|
||||||
|
__: u128,
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(size_of::<SlotContext>() == 0x20);
|
||||||
279
rust/sys/voyageurs/src/xhci/data_structures/trb.rs
Normal file
279
rust/sys/voyageurs/src/xhci/data_structures/trb.rs
Normal file
|
|
@ -0,0 +1,279 @@
|
||||||
|
use bitfield_struct::{bitenum, bitfield};
|
||||||
|
|
||||||
|
#[bitenum]
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub enum TrbType {
|
||||||
|
#[fallback]
|
||||||
|
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,
|
||||||
|
ForceEventCommand = 18,
|
||||||
|
NegotiateBandwidthCommand = 19,
|
||||||
|
SetLatencyToleranceValueCommand = 20,
|
||||||
|
GetPortBandwidthCommand = 21,
|
||||||
|
ForceHeaderCommand = 22,
|
||||||
|
NoOpCommand = 23,
|
||||||
|
GetExtendedPropertyCommand = 24,
|
||||||
|
SetExtendedPropertyCommand = 25,
|
||||||
|
TransferEvent = 32,
|
||||||
|
CommandCompletionEvent = 33,
|
||||||
|
PortStatusChangeEvent = 34,
|
||||||
|
BandwidthRequestEvent = 35,
|
||||||
|
DoorbellEvent = 36,
|
||||||
|
HostControllerEvent = 37,
|
||||||
|
DeviceNotificationEvent = 38,
|
||||||
|
MFINDEXWrapEvent = 39,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield(u128)]
|
||||||
|
pub struct TransferRequestBlock {
|
||||||
|
pub parameter: u64,
|
||||||
|
pub status: u32,
|
||||||
|
pub cycle: bool,
|
||||||
|
evaluate_next: bool,
|
||||||
|
flag_2: bool,
|
||||||
|
flag_3: bool,
|
||||||
|
flag_4: bool,
|
||||||
|
flag_5: bool,
|
||||||
|
flag_6: bool,
|
||||||
|
flag_7: bool,
|
||||||
|
flag_8: bool,
|
||||||
|
flag_9: bool,
|
||||||
|
#[bits(6)]
|
||||||
|
pub trb_type: TrbType,
|
||||||
|
control: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TransferRequestBlock {}
|
||||||
|
|
||||||
|
pub trait TypedTrb
|
||||||
|
where
|
||||||
|
Self: Into<u128> + From<u128> + Copy,
|
||||||
|
{
|
||||||
|
fn from_trb(trb: TransferRequestBlock) -> Self {
|
||||||
|
trb.into_bits().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_trb(self) -> TransferRequestBlock {
|
||||||
|
Into::<u128>::into(self).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield(u128)]
|
||||||
|
pub struct TrbNoOp {
|
||||||
|
__: u64,
|
||||||
|
#[bits(22)]
|
||||||
|
__: u32,
|
||||||
|
#[bits(10, default = 0)]
|
||||||
|
interrupter_target: u16,
|
||||||
|
cycle: bool,
|
||||||
|
evaluate_next: bool,
|
||||||
|
__: bool,
|
||||||
|
__: bool,
|
||||||
|
chain: bool,
|
||||||
|
#[bits(default = true)]
|
||||||
|
interrupt_on_completion: bool,
|
||||||
|
#[bits(4)]
|
||||||
|
__: u8,
|
||||||
|
#[bits(6, default = TrbType::NoOpCommand)]
|
||||||
|
trb_type: TrbType,
|
||||||
|
__: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypedTrb for TrbNoOp {}
|
||||||
|
|
||||||
|
#[bitfield(u128)]
|
||||||
|
pub struct TrbLink {
|
||||||
|
/// Ring Segment Pointer Hi and Lo. These fields represent the high order bits of the 64-bit base
|
||||||
|
/// address of the next Ring Segment.
|
||||||
|
/// The memory structure referenced by this physical memory pointer shall begin on a 16-byte
|
||||||
|
/// address boundary.
|
||||||
|
pub ring_segment_pointer: u64,
|
||||||
|
#[bits(22)]
|
||||||
|
__: u32,
|
||||||
|
/// Interrupter Target. This field defines the index of the Interrupter that will receive Transfer
|
||||||
|
/// Events generated by this TRB. Valid values are between 0 and MaxIntrs-1.
|
||||||
|
/// This field is ignored by the xHC on Command Rings.
|
||||||
|
#[bits(10)]
|
||||||
|
pub interrupter_target: u16,
|
||||||
|
/// Cycle bit (C). This bit is used to mark the Enqueue Pointer location of a Transfer or Command
|
||||||
|
/// Ring.
|
||||||
|
pub cycle: bool,
|
||||||
|
/// Toggle Cycle (TC). When set to ‘1’, the xHC shall toggle its interpretation of the Cycle bit. When
|
||||||
|
/// cleared to ‘0’, the xHC shall continue to the next segment using its current interpretation of the
|
||||||
|
/// Cycle bit.
|
||||||
|
pub toggle_cycle: bool,
|
||||||
|
__: bool,
|
||||||
|
__: bool,
|
||||||
|
/// Chain bit (CH). Set to ‘1’ by software to associate this TRB with the next TRB on the Ring. A
|
||||||
|
/// Transfer Descriptor (TD) is defined as one or more TRBs. The Chain bit is used to identify the
|
||||||
|
/// TRBs that comprise a TD. Refer to section 4.11.7 for more information on Link TRB placement
|
||||||
|
/// within a TD. On a Command Ring this bit is ignored by the xHC.
|
||||||
|
#[bits(default = true)]
|
||||||
|
chain: bool,
|
||||||
|
/// Interrupt On Completion (IOC). If this bit is set to ‘1’, it specifies that when this TRB completes,
|
||||||
|
/// the Host Controller shall notify the system of the completion by placing an Event TRB on the
|
||||||
|
/// Event ring and sending an interrupt at the next interrupt threshold.
|
||||||
|
pub interrupt_on_completion: bool,
|
||||||
|
#[bits(4)]
|
||||||
|
__: u8,
|
||||||
|
/// TRB Type. This field is set to Link TRB type. Refer to Table 6-91 for the definition of the Type
|
||||||
|
/// TRB IDs.
|
||||||
|
#[bits(6, default = TrbType::Link)]
|
||||||
|
trb_type: TrbType,
|
||||||
|
__: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypedTrb for TrbLink {}
|
||||||
|
|
||||||
|
#[bitfield(u128)]
|
||||||
|
pub struct TrbTransferEvent {
|
||||||
|
pub transfer_trb_pointer: u64,
|
||||||
|
|
||||||
|
#[bits(24)]
|
||||||
|
pub trb_transfer_lenght: u32,
|
||||||
|
|
||||||
|
/// Completion Code. This field encodes the completion status of the command that generated the
|
||||||
|
/// event. Refer to the respective command definition for a list of the possible Completion Codes
|
||||||
|
/// associated with the command. Refer to section 6.4.5 for an enumerated list of possible error
|
||||||
|
/// conditions.
|
||||||
|
pub completion_code: u8,
|
||||||
|
#[bits(10)]
|
||||||
|
__: u16,
|
||||||
|
/// TRB Type. This field identifies the type of the TRB. Refer to Table 6-91 for the definition of the
|
||||||
|
/// Command Completion Event TRB type ID
|
||||||
|
#[bits(6, default=TrbType::TransferEvent)]
|
||||||
|
pub trb_type: TrbType,
|
||||||
|
|
||||||
|
#[bits(5)]
|
||||||
|
pub endpoint_id: u8,
|
||||||
|
#[bits(3)]
|
||||||
|
__: u8,
|
||||||
|
|
||||||
|
pub slot_id: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypedTrb for TrbTransferEvent {}
|
||||||
|
|
||||||
|
#[bitenum]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum CommandCompletionCode {
|
||||||
|
#[fallback]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Invalid = 0,
|
||||||
|
Success = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield(u128)]
|
||||||
|
pub struct TrbCommandCompletion {
|
||||||
|
/// Command TRB Pointer Hi and Lo. This field represents the high order bits of the 64-bit address
|
||||||
|
/// of the Command TRB that generated this event. Note that this field is not valid for some
|
||||||
|
/// Completion Code values. Refer to Table 6-90 for specific cases.
|
||||||
|
///
|
||||||
|
/// The memory structure referenced by this physical memory pointer shall be aligned on a 16-byte
|
||||||
|
/// address boundary.
|
||||||
|
pub command_trb_pointer: u64,
|
||||||
|
/// Command Completion Parameter. This field may optionally be set by a command. Refer to
|
||||||
|
/// section 4.6.6.1 for specific usage. If a command does not utilize this field it shall be treated as
|
||||||
|
/// RsvdZ.
|
||||||
|
#[bits(24)]
|
||||||
|
pub command_completion_parameter: u64,
|
||||||
|
/// Completion Code. This field encodes the completion status of the command that generated the
|
||||||
|
/// event. Refer to the respective command definition for a list of the possible Completion Codes
|
||||||
|
/// associated with the command. Refer to section 6.4.5 for an enumerated list of possible error
|
||||||
|
/// conditions.
|
||||||
|
pub completion_code: u8,
|
||||||
|
/// Cycle bit (C). This bit is used to mark the Dequeue Pointer of an Event Ring
|
||||||
|
pub cycle_bit: bool,
|
||||||
|
#[bits(9)]
|
||||||
|
__: u16,
|
||||||
|
/// TRB Type. This field identifies the type of the TRB. Refer to Table 6-91 for the definition of the
|
||||||
|
/// Command Completion Event TRB type ID
|
||||||
|
#[bits(6, default=TrbType::CommandCompletionEvent)]
|
||||||
|
pub trb_type: TrbType,
|
||||||
|
/// VF ID. The ID of the Virtual Function that generated the event. Note that this field is valid only if
|
||||||
|
/// Virtual Functions are enabled. If they are not enabled this field shall be cleared to ‘0’.
|
||||||
|
pub vf_id: u8,
|
||||||
|
/// Slot ID. The Slot ID field shall be updated by the xHC to reflect the slot associated with the
|
||||||
|
/// command that generated the event, with the following exceptions:
|
||||||
|
///
|
||||||
|
/// - The Slot ID shall be cleared to ‘0’ for No Op, Set Latency Tolerance Value, Get Port Bandwidth,
|
||||||
|
/// and Force Event Commands.
|
||||||
|
///
|
||||||
|
/// - The Slot ID shall be set to the ID of the newly allocated Device Slot for the Enable Slot
|
||||||
|
/// Command.
|
||||||
|
///
|
||||||
|
/// - The value of Slot ID shall be vendor defined when generated by a vendor defined command.
|
||||||
|
///
|
||||||
|
/// This value is used as an index in the Device Context Base Address Array to select the Device
|
||||||
|
/// Context of the source device. If this Event is due to a Host Controller Command, then this field
|
||||||
|
/// shall be cleared to ‘0’.
|
||||||
|
pub slot_id: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypedTrb for TrbCommandCompletion {}
|
||||||
|
|
||||||
|
#[bitfield(u128)]
|
||||||
|
pub struct TrbPortStatusChangeEvent {
|
||||||
|
#[bits(24)]
|
||||||
|
__: u32,
|
||||||
|
pub port_id: u8,
|
||||||
|
__: u32,
|
||||||
|
#[bits(24)]
|
||||||
|
__: u32,
|
||||||
|
pub completion_code: u8,
|
||||||
|
#[bits(10)]
|
||||||
|
__: u16,
|
||||||
|
#[bits(6, default=TrbType::PortStatusChangeEvent)]
|
||||||
|
trb_type: TrbType,
|
||||||
|
__: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypedTrb for TrbPortStatusChangeEvent {}
|
||||||
|
|
||||||
|
#[bitfield(u128)]
|
||||||
|
pub struct TrbEnableSlotCommand {
|
||||||
|
__: u64,
|
||||||
|
__: u32,
|
||||||
|
#[bits(10)]
|
||||||
|
__: u16,
|
||||||
|
#[bits(6, default=TrbType::EnableSlotCommand)]
|
||||||
|
trb_type: TrbType,
|
||||||
|
#[bits(5)]
|
||||||
|
slot_type: u8,
|
||||||
|
#[bits(11)]
|
||||||
|
__: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypedTrb for TrbEnableSlotCommand {}
|
||||||
|
|
||||||
|
#[bitfield(u128)]
|
||||||
|
pub struct TrbAddressDeviceCommand {
|
||||||
|
pub input_context_pointer: u64,
|
||||||
|
__: u32,
|
||||||
|
#[bits(9)]
|
||||||
|
__: u16,
|
||||||
|
pub block_set_address_request: bool,
|
||||||
|
#[bits(6, default=TrbType::AddressDeviceCommand)]
|
||||||
|
trb_typ: TrbType,
|
||||||
|
__: u8,
|
||||||
|
pub slot_id: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypedTrb for TrbAddressDeviceCommand {}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
use core::{
|
||||||
|
ops::{Index, IndexMut},
|
||||||
|
slice::SliceIndex,
|
||||||
|
};
|
||||||
|
|
||||||
|
use mammoth::physical_box::PhysicalBox;
|
||||||
|
|
||||||
|
use crate::xhci::data_structures::TransferRequestBlock;
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct TrbRingSegment(PhysicalBox<[TransferRequestBlock]>);
|
||||||
|
|
||||||
|
impl TrbRingSegment {
|
||||||
|
pub fn new(size: usize) -> Self {
|
||||||
|
Self(PhysicalBox::default_with_count(
|
||||||
|
TransferRequestBlock::default(),
|
||||||
|
size,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn physical_address(&self) -> usize {
|
||||||
|
self.0.physical_address()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> Index<I> for TrbRingSegment
|
||||||
|
where
|
||||||
|
I: SliceIndex<[TransferRequestBlock]>,
|
||||||
|
{
|
||||||
|
type Output = I::Output;
|
||||||
|
|
||||||
|
fn index(&self, index: I) -> &Self::Output {
|
||||||
|
&self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> IndexMut<I> for TrbRingSegment
|
||||||
|
where
|
||||||
|
I: SliceIndex<[TransferRequestBlock]>,
|
||||||
|
{
|
||||||
|
fn index_mut(&mut self, index: I) -> &mut Self::Output {
|
||||||
|
&mut self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
|
pub mod data_structures;
|
||||||
pub mod registers;
|
pub mod registers;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue