virtfw-libhw 0.2.0

library for direct hardware access
Documentation
#![cfg(target_arch = "x86_64")]

use bitfield_struct::bitfield;

use crate::ioport;
use crate::pci::{PciDevAddr, PciHost};

const IOPORT_PCI_CMD: u16 = 0x0cf8;
const IOPORT_PCI_DATA: u16 = 0x0cfc;

#[bitfield(u32)]
pub struct PciCmd {
    #[bits(8)]
    addr: u8,
    #[bits(3)]
    func: u8,
    #[bits(5)]
    slot: u8,
    #[bits(8)]
    bus: u8,
    #[bits(7)]
    _pad: u8,
    #[bits(default = true)]
    enable: bool,
}

pub struct PciHostX86 {}

impl PciHostX86 {
    pub fn new() -> Option<Self> {
        let pcihost = Self {};
        let _ = pcihost.try_device(0, 0, 0)?;
        Some(pcihost)
    }

    fn select(&self, dev: &PciDevAddr, addr: u8) {
        let cmd = PciCmd::new()
            .with_bus(dev.bus)
            .with_slot(dev.slot)
            .with_func(dev.func)
            .with_addr(addr);
        ioport::outl(IOPORT_PCI_CMD, cmd.into());
    }
}

impl PciHost for PciHostX86 {
    fn readl(&self, dev: &PciDevAddr, addr: u8) -> u32 {
        self.select(dev, addr);
        ioport::inl(IOPORT_PCI_DATA)
    }

    fn readw(&self, dev: &PciDevAddr, addr: u8) -> u16 {
        self.select(dev, addr);
        ioport::inw(IOPORT_PCI_DATA)
    }

    fn readb(&self, dev: &PciDevAddr, addr: u8) -> u8 {
        self.select(dev, addr);
        ioport::inb(IOPORT_PCI_DATA)
    }

    fn writel(&self, dev: &PciDevAddr, addr: u8, value: u32) {
        self.select(dev, addr);
        ioport::outl(IOPORT_PCI_DATA, value);
    }

    fn writew(&self, dev: &PciDevAddr, addr: u8, value: u16) {
        self.select(dev, addr);
        ioport::outw(IOPORT_PCI_DATA, value);
    }

    fn writeb(&self, dev: &PciDevAddr, addr: u8, value: u8) {
        self.select(dev, addr);
        ioport::outb(IOPORT_PCI_DATA, value);
    }
}