pcitool 0.1.0

Tool and library for portable access to PCI bus configuration registres.
Documentation
use std::fmt;

use pcics::{
    capabilities::pci_express::DeviceType,
    extended_capabilities::multicast::{
        McBaseAddress, McOverlayBar, Multicast, MulticastCapability, MulticastControl,
    },
};

use super::Flag;

pub struct MulticastView<'a> {
    pub data: &'a Multicast,
    pub verbose: usize,
    pub maybe_device_type: Option<&'a DeviceType>,
}
impl<'a> fmt::Display for MulticastView<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let MulticastView {
            data:
                Multicast {
                    multicast_capability:
                        MulticastCapability {
                            mc_max_group,
                            mc_window_size_requested,
                            mc_ecrc_regeneration_supported,
                        },
                    multicast_control:
                        MulticastControl {
                            mc_num_group,
                            mc_enable,
                        },
                    mc_base_address:
                        McBaseAddress {
                            mc_index_position,
                            mc_base_address,
                        },
                    mc_receive,
                    mc_block_all,
                    mc_block_untranslated,
                    mc_overlay_bar,
                },
            verbose,
            maybe_device_type,
        } = self;
        writeln!(f, "Multicast")?;
        if verbose < &2 {
            return Ok(());
        }
        write!(f, "\t\tMcastCap: MaxGroups {:}", mc_max_group + 1)?;
        let is_ep_or_rcip = matches!(
            maybe_device_type,
            Some(DeviceType::Endpoint { .. } | DeviceType::RootComplexIntegratedEndpoint)
        );
        if is_ep_or_rcip {
            write!(
                f,
                ", WindowSz {} ({} bytes)",
                mc_window_size_requested,
                1i32.wrapping_shl(*mc_window_size_requested as u32),
            )?;
        }
        if matches!(
            maybe_device_type,
            Some(
                DeviceType::RootPort { .. }
                    | DeviceType::UpstreamPort { .. }
                    | DeviceType::DownstreamPort { .. }
            )
        ) {
            writeln!(f, ", ECRCRegen{}", Flag(*mc_ecrc_regeneration_supported))?;
        }
        writeln!(
            f,
            "\t\tMcastCtl: NumGroups {}, Enable{}",
            mc_num_group + 1,
            Flag(*mc_enable)
        )?;
        writeln!(
            f,
            "\t\tMcastBAR: IndexPos {}, BaseAddr {:016x}",
            mc_index_position, mc_base_address
        )?;
        writeln!(f, "\t\tMcastReceiveVec:      {:016x}", mc_receive)?;
        writeln!(f, "\t\tMcastBlockAllVec:     {:016x}", mc_block_all)?;
        writeln!(
            f,
            "\t\tMcastBlockUntransVec: {:016x}",
            mc_block_untranslated
        )?;

        if is_ep_or_rcip {
            return Ok(());
        }
        if let Some(McOverlayBar {
            mc_overlay_size,
            mc_overlay_bar,
        }) = mc_overlay_bar
        {
            write!(f, "\t\tMcastOverlayBAR: OverlaySize {} ", mc_overlay_size)?;
            if mc_overlay_size >= &6 {
                write!(f, "({} bytes)", 1i32.wrapping_shl(*mc_overlay_size as u32))?;
            } else {
                write!(f, "(disabled)")?;
            }
            writeln!(f, ", BaseAddr {:016}", mc_overlay_bar)?;
        }
        Ok(())
    }
}