use heterob::{
bit_numbering::Lsb,
endianness::{Le, LeBytesTryInto},
Seq, P2, P3, P5, P10,
};
use super::{ExtendedCapabilityDataError, ExtendedCapabilityHeaderPlaceholder};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Multicast {
pub multicast_capability: MulticastCapability,
pub multicast_control: MulticastControl,
pub mc_base_address: McBaseAddress,
pub mc_receive: u64,
pub mc_block_all: u64,
pub mc_block_untranslated: u64,
pub mc_overlay_bar: Option<McOverlayBar>,
}
impl Multicast {
pub const SIZE: usize = 0x30;
}
impl TryFrom<&[u8]> for Multicast {
type Error = ExtendedCapabilityDataError;
fn try_from<'a>(slice: &[u8]) -> Result<Self, Self::Error> {
let Seq {
head:
Le((
ExtendedCapabilityHeaderPlaceholder,
multicast_capability,
multicast_control,
mc_base_address,
rcv_l,
rcv_h,
blk_all_l,
blk_all_h,
blk_untr_l,
blk_untr_h,
)),
tail,
} = P10(slice)
.try_into()
.map_err(|_| ExtendedCapabilityDataError {
name: "Multicast",
size: Self::SIZE,
})?;
let _: (u32, u32, u32, u32, u32, u32) =
(rcv_l, rcv_h, blk_all_l, blk_all_h, blk_untr_l, blk_untr_h);
let multicast_capability: MulticastCapability = From::<u16>::from(multicast_capability);
let mc_overlay_bar = tail
.le_bytes_try_into()
.map(|Seq { head, .. }| From::<u64>::from(head))
.ok();
Ok(Self {
multicast_capability,
multicast_control: From::<u16>::from(multicast_control),
mc_base_address: From::<u64>::from(mc_base_address),
mc_receive: (rcv_l as u64) | (rcv_h as u64) << 32,
mc_block_all: (blk_all_l as u64) | (blk_all_h as u64) << 32,
mc_block_untranslated: (blk_untr_l as u64) | (blk_untr_h as u64) << 32,
mc_overlay_bar,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MulticastCapability {
pub mc_max_group: u8,
pub mc_window_size_requested: u8,
pub mc_ecrc_regeneration_supported: bool,
}
impl From<u16> for MulticastCapability {
fn from(word: u16) -> Self {
let Lsb((mc_max_group, (), mc_window_size_requested, (), mc_ecrc_regeneration_supported)) =
P5::<_, 6, 2, 6, 1, 1>(word).into();
Self {
mc_max_group,
mc_window_size_requested,
mc_ecrc_regeneration_supported,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MulticastControl {
pub mc_num_group: u8,
pub mc_enable: bool,
}
impl From<u16> for MulticastControl {
fn from(word: u16) -> Self {
let Lsb((mc_num_group, (), mc_enable)) = P3::<_, 6, 9, 1>(word).into();
Self {
mc_num_group,
mc_enable,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct McBaseAddress {
pub mc_index_position: u8,
pub mc_base_address: u64,
}
impl From<u64> for McBaseAddress {
fn from(qword: u64) -> Self {
let Lsb((mc_index_position, (), mc_base_address)) = P3::<_, 6, 6, 52>(qword).into();
let _: u64 = mc_base_address;
Self {
mc_index_position,
mc_base_address: mc_base_address << 12,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct McOverlayBar {
pub mc_overlay_size: u8,
pub mc_overlay_bar: u64,
}
impl From<u64> for McOverlayBar {
fn from(qword: u64) -> Self {
let Lsb((mc_overlay_size, mc_overlay_bar)) = P2::<_, 6, 58>(qword).into();
let _: u64 = mc_overlay_bar;
Self {
mc_overlay_size,
mc_overlay_bar: mc_overlay_bar << 6,
}
}
}