use heterob::{bit_numbering::Lsb, endianness::Le, P2, P3, P4};
use super::CapabilityDataError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MsiX {
pub message_control: MessageControl,
pub table: Table,
pub pending_bit_array: PendingBitArray,
}
impl MsiX {
pub const SIZE: usize = 2 + 4 + 4;
}
impl From<[u8; MsiX::SIZE]> for MsiX {
fn from(bytes: [u8; MsiX::SIZE]) -> Self {
let Le((mc, t, pba)) = P3(bytes).into();
Self {
message_control: From::<u16>::from(mc),
table: From::<u32>::from(t),
pending_bit_array: From::<u32>::from(pba),
}
}
}
impl<'a> TryFrom<&'a [u8]> for MsiX {
type Error = CapabilityDataError;
fn try_from(slice: &'a [u8]) -> Result<Self, Self::Error> {
slice
.get(..Self::SIZE)
.and_then(|slice| <[u8; Self::SIZE]>::try_from(slice).ok())
.ok_or(CapabilityDataError {
name: "MSI-X",
size: Self::SIZE,
})
.map(Self::from)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MessageControl {
pub table_size: u16,
pub function_mask: bool,
pub msi_x_enable: bool,
}
impl From<u16> for MessageControl {
fn from(word: u16) -> Self {
let Lsb((table_size, (), function_mask, msi_x_enable)) = P4::<_, 11, 3, 1, 1>(word).into();
Self {
table_size,
function_mask,
msi_x_enable,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Bir {
Bar10h,
Bar14h,
Bar18h,
Bar1Ch,
Bar20h,
Bar24h,
Reserved(u8),
}
impl From<u8> for Bir {
fn from(byte: u8) -> Self {
match byte {
0 => Self::Bar10h,
1 => Self::Bar14h,
2 => Self::Bar18h,
3 => Self::Bar1Ch,
4 => Self::Bar20h,
5 => Self::Bar24h,
v => Self::Reserved(v),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Table {
pub bir: Bir,
pub offset: u32,
}
impl From<u32> for Table {
fn from(word: u32) -> Self {
let Lsb((bir, offset)) = P2::<_, 3, 29>(word).into();
let _: u32 = offset;
Self {
bir: From::<u8>::from(bir),
offset: offset << 3,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PendingBitArray {
pub bir: Bir,
pub offset: u32,
}
impl From<u32> for PendingBitArray {
fn from(word: u32) -> Self {
let Lsb((bir, offset)) = P2::<_, 3, 29>(word).into();
let _: u32 = offset;
Self {
bir: From::<u8>::from(bir),
offset: offset << 3,
}
}
}