#pragma once
#include <luna/Types.h>

namespace PCI
{
    enum Field : u32
    {
        VendorID = 0x00,
        DeviceID = 0x02,
        Command = 0x04,
        Status = 0x06,

        RevisionID = 0x08,
        ProgIF = 0x09,
        Subclass = 0x0a,
        Class = 0x0b,

        HeaderType = 0x0e,

        SecondaryBus = 0x19
    };

    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;
        };

        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);
}