use heterob::{bit_numbering::Lsb, endianness::Le, Seq, P2, P4, P9};
use super::ExtendedCapabilityDataError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TphRequester<'a> {
pub tph_requester_capability: TphRequesterCapability<'a>,
pub tph_requester_control: TphRequesterControl,
}
impl<'a> TryFrom<&'a [u8]> for TphRequester<'a> {
type Error = ExtendedCapabilityDataError;
fn try_from(slice: &'a [u8]) -> Result<Self, Self::Error> {
let Seq {
head: Le((tph_requester_capability, tph_requester_control)),
tail,
} = P2(slice)
.try_into()
.map_err(|_| ExtendedCapabilityDataError {
name: "TPH Requester",
size: 8,
})?;
let Lsb((
no_st_mode_supported,
interrupt_vector_mode_supported,
device_specific_mode_supported,
(),
extended_tph_requester_supported,
st_table_location,
(),
st_table_size,
(),
)) = P9::<u32, 1, 1, 1, 5, 1, 2, 5, 11, 5>(tph_requester_capability).into();
let _: (u8, u16) = (st_table_location, st_table_size);
let end = (st_table_size as usize) * 2 + 2;
let st_table = match st_table_location {
0b00 => StTable::NotPresent,
0b01 => {
if let (0..=63, Some(data)) = (st_table_size, tail.get(..end)) {
StTable::Valid {
size: st_table_size,
data,
}
} else {
StTable::Invalid {
size: st_table_size,
data: tail,
}
}
}
0b10 => StTable::MsiXTable {
size: st_table_size,
},
0b11 => StTable::Reserved,
_ => unreachable!(),
};
Ok(Self {
tph_requester_capability: TphRequesterCapability {
no_st_mode_supported,
interrupt_vector_mode_supported,
device_specific_mode_supported,
extended_tph_requester_supported,
st_table,
},
tph_requester_control: From::<u32>::from(tph_requester_control),
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TphRequesterCapability<'a> {
pub no_st_mode_supported: bool,
pub interrupt_vector_mode_supported: bool,
pub device_specific_mode_supported: bool,
pub extended_tph_requester_supported: bool,
pub st_table: StTable<'a>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StTable<'a> {
NotPresent,
Valid { size: u16, data: &'a [u8] },
Invalid { size: u16, data: &'a [u8] },
MsiXTable { size: u16 },
Reserved,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TphStTableEntry {
pub st_lower: u8,
pub st_upper: u8,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TphRequesterControl {
pub st_mode_select: StModeSelect,
pub tph_requester_enable: TphRequesterEnable,
}
impl From<u32> for TphRequesterControl {
fn from(dword: u32) -> Self {
let Lsb((st_mode_select, (), tph_requester_enable, ())) =
P4::<_, 3, 5, 2, 22>(dword).into();
Self {
st_mode_select: From::<u8>::from(st_mode_select),
tph_requester_enable: From::<u8>::from(tph_requester_enable),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StModeSelect {
NoStMode,
InterruptVectorMode,
DeviceSpecificMode,
Reserved(u8),
}
impl From<u8> for StModeSelect {
fn from(byte: u8) -> Self {
match byte {
0b00 => Self::NoStMode,
0b01 => Self::InterruptVectorMode,
0b10 => Self::DeviceSpecificMode,
v => Self::Reserved(v),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TphRequesterEnable {
NotPermitted,
TphPermitted,
Reserved,
TphAndExtendedTphPermitted,
}
impl From<u8> for TphRequesterEnable {
fn from(byte: u8) -> Self {
match byte {
0b00 => Self::NotPermitted,
0b01 => Self::TphPermitted,
0b10 => Self::Reserved,
0b11 => Self::TphAndExtendedTphPermitted,
_ => unreachable!(),
}
}
}