#ifndef _KERNEL_DEVICE_PCI_H
#define _KERNEL_DEVICE_PCI_H

#include <device/pci_info.h>
#include <libk/std.h>

#define PCI_CONFIG_ADDR 0xCF8
#define PCI_CONFIG_DATA 0xCFC

#define PCI_VENDOR_ID     0x00
#define PCI_DEVICE_ID     0x02
#define PCI_COMMAND       0x04
#define PCI_STATUS        0x06
#define PCI_REVISION_ID   0x08
#define PCI_PROG_IF       0x09
#define PCI_SUBCLASS      0x0A
#define PCI_CLASS         0x0B
#define PCI_CACHELINE     0x0C
#define PCI_LATENCY       0x0D
#define PCI_HEADER_TYPE   0x0E
#define PCI_BIST          0x0F
#define PCI_BAR0          0x10
#define PCI_BAR1          0x14
#define PCI_BAR2          0x18
#define PCI_BAR3          0x1C
#define PCI_BAR4          0x20
#define PCI_BAR5          0x24
#define PCI_INTERRUPT     0x3C
#define PCI_SECONDARY_BUS 0x09

#define PCI_BAR_IO       0x01
#define PCI_BAR_MEM32    0x02
#define PCI_BAR_MEM64    0x04
#define PCI_BAR_PREFETCH 0x08

struct pci_vendor {
  uint16_t id;
  const char* name;
};

struct pci_device_id {
  uint16_t vendor_id;
  uint16_t device_id;
  const char* name;
};

struct pci_class {
  uint8_t class;
  uint8_t subclass;
  const char* name;
};

struct pci_driver_info {
  uint8_t class;
  uint8_t subclass;
  bool (*init) (struct pci_info pci_info);
};

typedef void (*pci_cb_func_t) (struct pci_info pci_info);

void pci_init (void);

uint32_t pci_read32 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset);

void pci_write32 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t value);

uint16_t pci_read16 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset);

void pci_write16 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint16_t value);

uint8_t pci_read8 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset);

void pci_write8 (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint8_t value);

extern const struct pci_vendor pci_vendors[];

extern const struct pci_device_id pci_device_names[];

extern const struct pci_class pci_classes[];

#endif // _KERNEL_DEVICE_PCI_H
