#pragma once #include namespace PCI { enum Field : u32 { VendorID = 0x00, DeviceID = 0x02, Command = 0x04, Status = 0x06, RevisionID = 0x08, ProgIF = 0x09, Subclass = 0x0a, Class = 0x0b, HeaderType = 0x0e, BAR0 = 0x10, BAR1 = 0x14, BAR2 = 0x18, BAR3 = 0x1c, SecondaryBus = 0x19, InterruptLine = 0x3c, }; enum CommandField : u16 { CMD_IO_SPACE = 1 << 0, CMD_MEMORY_SPACE = 1 << 1, CMD_BUS_MASTER = 1 << 2, CMD_SPECIAL_CYCLES = 1 << 3, CMD_MEMORY_WRITE_AND_INVALIDATE = 1 << 4, CMD_VGA_PALETTE_SNOOP = 1 << 5, CMD_PARITY_ERROR_RESPONSE = 1 << 6, CMD_SERR = 1 << 8, CMD_FAST_BACK_TO_BACK = 1 << 9, CMD_INTERRUPT_DISABLE = 1 << 10, }; struct BAR { public: BAR(u32 raw); bool is_iospace() { return m_raw & 0x01; } bool is_memory_space() { return !is_iospace(); } u16 port() { return (u16)(m_raw & 0xfffffffc); } u8 type() { return (m_raw >> 1) & 0x03; } bool is_prefetchable() { return m_raw & (1 << 3); } u32 address_32bit() { return m_raw & 0xFFFFFFF0; } private: u32 m_raw; }; struct Device { struct ID { u16 vendor; u16 device; }; struct Type { u8 klass; u8 subclass; u8 prog_if; }; struct Address { u32 bus; u32 slot; u32 function; }; BAR getBAR(u8 index) const; ID id; Type type; Address address; }; typedef void (*Callback)(const Device&); struct Match { i16 klass { -1 }; i16 subclass { -1 }; i16 prog_if { -1 }; }; constexpr u16 INVALID_ID = 0xFFFF; // Architecture-dependent. u8 read8(const Device::Address& address, u32 field); u16 read16(const Device::Address& address, u32 field); u32 read32(const Device::Address& address, u32 field); void write8(const Device::Address& address, u32 field, u8 value); void write16(const Device::Address& address, u32 field, u16 value); void write32(const Device::Address& address, u32 field, u32 value); Device::ID read_id(const Device::Address& address); Device::Type read_type(const Device::Address& address); void scan(Callback callback, Match match); }