use super::Type;
use bit_field::BitField;
use core::convert::{TryFrom, TryInto};
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
allowed! {
enum {
TransferEvent,
CommandCompletion,
PortStatusChange,
BandwidthRequest,
Doorbell,
HostController,
DeviceNotification,
MfindexWrap
}
}
impl TryFrom<[u32; 4]> for Allowed {
type Error = [u32; 4];
fn try_from(raw: [u32; 4]) -> Result<Self, Self::Error> {
try_from!(
raw =>
TransferEvent,
CommandCompletion,
PortStatusChange,
BandwidthRequest,
Doorbell,
HostController,
DeviceNotification,
MfindexWrap,
);
Err(raw)
}
}
macro_rules! completion_code {
($name:ident) => {
impl $name {
pub fn completion_code(&self) -> Result<CompletionCode, u8> {
let c: u8 = self.0[2].get_bits(24..=31).try_into().unwrap();
CompletionCode::from_u8(c).ok_or(c)
}
}
};
}
macro_rules! event {
($name:ident,$full:expr,$ty:expr) => {
add_trb_with_default!($name, $full, $ty);
completion_code!($name);
};
}
macro_rules! impl_debug_for_event_trb{
($name:ident{})=>{
impl_debug_for_trb!($name{
completion_code
});
};
($name:ident {
$($method:ident),*
})=>{
impl_debug_for_trb!($name{
completion_code,
$($method),*
});
}
}
event!(
PortStatusChange,
"Port Status Change Event TRB",
Type::PortStatusChange
);
reserved!(PortStatusChange(Type::PortStatusChange){
[0]0..=23;
[1]0..=31;
[2]0..=23;
[3]1..=9;
[3]16..=31;
});
impl PortStatusChange {
ro_field!([0](24..=31), port_id, "Port ID", u8);
}
impl_debug_for_event_trb!(PortStatusChange { port_id });
event!(TransferEvent, "Transfer Event TRB", Type::TransferEvent);
reserved!(TransferEvent(Type::TransferEvent){
[3]1..=1;
[3]3..=9;
[3]21..=23;
});
impl TransferEvent {
#[must_use]
pub fn trb_pointer(&self) -> u64 {
let l: u64 = self.0[0].into();
let u: u64 = self.0[1].into();
(u << 32) | l
}
ro_field!([2](0..=23), trb_transfer_length, "TRB Transfer Length", u32);
ro_bit!([3](2), event_data, "Event Data");
ro_field!([3](16..=20), endpoint_id, "Endpoint ID", u8);
ro_field!([3](24..=31), slot_id, "Slot ID", u8);
}
impl_debug_for_event_trb!(TransferEvent {
trb_pointer,
trb_transfer_length,
event_data,
endpoint_id,
slot_id
});
event!(
CommandCompletion,
"Command Completion Event TRB",
Type::CommandCompletion
);
reserved!(CommandCompletion(Type::CommandCompletion){
[0]0..=3;
[3]1..=9;
});
impl CommandCompletion {
#[must_use]
pub fn command_trb_pointer(&self) -> u64 {
let l: u64 = self.0[0].into();
let u: u64 = self.0[1].into();
(u << 32) | l
}
ro_field!(
[2](0..=23),
command_completion_parameter,
"Command Completion Parameter",
u32
);
ro_field!([3](16..=23), vf_id, "VF ID", u8);
ro_field!([3](24..=31), slot_id, "Slot ID", u8);
}
impl_debug_for_event_trb!(CommandCompletion {
command_trb_pointer,
command_completion_parameter,
vf_id,
slot_id
});
event!(
BandwidthRequest,
"Bandwidth Request Event TRB",
Type::BandwidthRequest
);
reserved!(BandwidthRequest(Type::BandwidthRequest){
[0]0..=31;
[1]0..=31;
[2]0..=23;
[3]1..=9;
[3]16..=23;
});
impl BandwidthRequest {
ro_field!([3](24..=31), slot_id, "Slot ID", u8);
}
impl_debug_for_event_trb!(BandwidthRequest { slot_id });
event!(Doorbell, "Doorbell Event TRB", Type::Doorbell);
reserved!(Doorbell(Type::Doorbell){
[0]5..=31;
[1]0..=31;
[2]0..=23;
[3]1..=9;
});
impl Doorbell {
ro_field!([0](0..=4), db_reason, "DB Reason", u8);
ro_field!([3](16..=23), vf_id, "VF ID", u8);
ro_field!([3](24..=31), slot_id, "Slot ID", u8);
}
impl_debug_for_event_trb!(Doorbell {
db_reason,
vf_id,
slot_id
});
event!(
HostController,
"Host Controller Event TRB",
Type::HostController
);
reserved!(HostController(Type::HostController){
[0]0..=31;
[1]0..=31;
[2]0..=23;
[3]1..=9;
[3]16..=31;
});
impl_debug_for_event_trb!(HostController {});
event!(
DeviceNotification,
"Device Notification Event TRB",
Type::DeviceNotification
);
reserved!(DeviceNotification(Type::DeviceNotification){
[0]0..=31;
[1]0..=31;
[2]0..=23;
[3]1..=9;
[3]16..=31;
});
impl DeviceNotification {
ro_field!([0](4..=7), notification_type, "Notification Type", u8);
#[must_use]
pub fn device_notification_data(&self) -> u64 {
let l: u64 = self.0[0].get_bits(8..=31).into();
let u: u64 = self.0[1].into();
((u << 32) | l) >> 8
}
ro_field!([3](24..=31), slot_id, "Slot ID", u8);
}
impl_debug_for_event_trb!(DeviceNotification {
notification_type,
device_notification_data,
slot_id
});
event!(MfindexWrap, "MFINDEX Wrap Event TRB", Type::MfindexWrap);
reserved!(MfindexWrap(Type::MfindexWrap){
[0]0..=3;
[2]0..=23;
[3]1..=9;
[3]16..=23;
});
impl_debug_for_event_trb!(MfindexWrap {});
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, FromPrimitive)]
pub enum CompletionCode {
Invalid = 0,
Success = 1,
DataBufferError = 2,
BabbleDetectedError = 3,
UsbTransactionError = 4,
TrbError = 5,
StallError = 6,
ResourceError = 7,
BandwidthError = 8,
NoSlotsAvailableError = 9,
InvalidStreamTypeError = 10,
SlotNotEnabledError = 11,
EndpointNotEnabledError = 12,
ShortPacket = 13,
RingUnderrun = 14,
RingOverrun = 15,
VfEventRingFullError = 16,
ParameterError = 17,
BandwidthOverrunError = 18,
ContextStateError = 19,
NoPingResponseError = 20,
EventRingFullError = 21,
IncompatibleDeviceError = 22,
MissedServiceError = 23,
CommandRingStopped = 24,
CommandAborted = 25,
Stopped = 26,
StoppedLengthInvalid = 27,
StoppedShortPacket = 28,
MaxExitLatencyTooLargeError = 29,
IsochBufferOverrun = 31,
EventLostError = 32,
UndefinedError = 33,
InvalidStreamIdError = 34,
SecondaryBandwidthError = 35,
SplitTransactionError = 36,
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn try_from_macro() {
let raw = [
0x00c8_8800, 0x0000_0000, 0x01_000000, 0x0000_8401, ];
assert_eq!(
Allowed::try_from(raw),
Ok(Allowed::CommandCompletion(
CommandCompletion::try_from(raw).unwrap()
)),
);
}
}