]> pd.if.org Git - zos/commitdiff
scanning pci bus
authorNathan Wagner <nw@hydaspes.if.org>
Tue, 25 Oct 2016 01:36:07 +0000 (20:36 -0500)
committerNathan Wagner <nw@hydaspes.if.org>
Tue, 25 Oct 2016 01:40:31 +0000 (20:40 -0500)
pci/func.c [new file with mode: 0644]
pci/pci.c [new file with mode: 0644]
pci/pci.h [new file with mode: 0644]

diff --git a/pci/func.c b/pci/func.c
new file mode 100644 (file)
index 0000000..5f24610
--- /dev/null
@@ -0,0 +1,131 @@
+#include <stdint.h>
+
+char *pci_func_desc(uint8_t class, uint8_t sub, uint8_t prog) {
+       uint32_t funcno, special;
+
+       funcno = class << 16 | sub << 8 | prog;
+       special = class << 16 | sub << 8;
+
+       switch (special) {
+               case 0x010000: return "IDE Controller"; break;
+               case 0x020500: return "PICMG 2.14 Multi Computing"; break;
+               case 0x060700: return "RACEway Bridge"; break;
+               default: break;
+       }
+       switch (funcno) {
+               case 0x000000: return "Any device except for VGA-Compatible devices"; break;
+               case 0x000100: return "VGA-Compatible Device"; break;
+               case 0x010000: return "SCSI Bus Controller"; break;
+               case 0x010200: return "Floppy Disk Controller"; break;
+               case 0x010300: return "IPI Bus Controller"; break;
+               case 0x010400: return "RAID Controller"; break;
+               case 0x010520: return "ATA Controller (Single DMA)"; break;
+               case 0x010530: return "ATA Controller (Chained DMA)"; break;
+               case 0x010600: return "Serial ATA (Vendor Specific Interface)"; break;
+               case 0x010601: return "Serial ATA (AHCI 1.0)"; break;
+               case 0x010700: return "Serial Attached SCSI (SAS)"; break;
+               case 0x018000: return "Other Mass Storage Controller"; break;
+               case 0x020000: return "Ethernet Controller"; break;
+               case 0x020100: return "Token Ring Controller"; break;
+               case 0x020200: return "FDDI Controller"; break;
+               case 0x020300: return "ATM Controller"; break;
+               case 0x020400: return "ISDN Controller"; break;
+               case 0x020500: return "WorldFip Controller"; break;
+               case 0x028000: return "Other Network Controller"; break;
+               case 0x030000: return "VGA-Compatible Controller"; break;
+               case 0x030001: return "8512-Compatible Controller"; break;
+               case 0x030100: return "XGA Controller"; break;
+               case 0x030200: return "3D Controller (Not VGA-Compatible)"; break;
+               case 0x038000: return "Other Display Controller"; break;
+               case 0x040000: return "Video Device"; break;
+               case 0x040100: return "Audio Device"; break;
+               case 0x040200: return "Computer Telephony Device"; break;
+               case 0x048000: return "Other Multimedia Device"; break;
+               case 0x050000: return "RAM Controller"; break;
+               case 0x050100: return "Flash Controller"; break;
+               case 0x058000: return "Other Memory Controller"; break;
+               case 0x060000: return "Host Bridge"; break;
+               case 0x060100: return "ISA Bridge"; break;
+               case 0x060200: return "EISA Bridge"; break;
+               case 0x060300: return "MCA Bridge"; break;
+               case 0x060400: return "PCI-to-PCI Bridge"; break;
+               case 0x060401: return "PCI-to-PCI Bridge (Subtractive Decode)"; break;
+               case 0x060500: return "PCMCIA Bridge"; break;
+               case 0x060600: return "NuBus Bridge"; break;
+               case 0x060700: return "CardBus Bridge"; break;
+               case 0x060940: return "PCI-to-PCI Bridge (Semi-Transparent, Primary)"; break;
+               case 0x060980: return "PCI-to-PCI Bridge (Semi-Transparent, Secondary)"; break;
+               case 0x068000: return "Other Bridge Device"; break;
+               case 0x070000: return "Generic XT-Compatible Serial Controller"; break;
+               case 0x070001: return "16450-Compatible Serial Controller"; break;
+               case 0x070002: return "16550-Compatible Serial Controller"; break;
+               case 0x070003: return "16650-Compatible Serial Controller"; break;
+               case 0x070004: return "16750-Compatible Serial Controller"; break;
+               case 0x070005: return "16850-Compatible Serial Controller"; break;
+               case 0x070006: return "16950-Compatible Serial Controller"; break;
+               case 0x070100: return "Parallel Port"; break;
+               case 0x070101: return "Bi-Directional Parallel Port"; break;
+               case 0x070102: return "ECP 1.X Compliant Parallel Port"; break;
+               case 0x070103: return "IEEE 1284 Controller"; break;
+               case 0x070200: return "Multiport Serial Controller"; break;
+               case 0x070300: return "Generic Modem"; break;
+               case 0x070301: return "Hayes Compatible Modem (16450-Compatible Interface)"; break;
+               case 0x070302: return "Hayes Compatible Modem (16550-Compatible Interface)"; break;
+               case 0x070303: return "Hayes Compatible Modem (16650-Compatible Interface)"; break;
+               case 0x070304: return "Hayes Compatible Modem (16750-Compatible Interface)"; break;
+               case 0x070400: return "IEEE 488.1/2 (GPIB) Controller"; break;
+               case 0x070500: return "Smart Card"; break;
+               case 0x078000: return "Other Communications Device"; break;
+               case 0x080000: return "Generic 8259 PIC"; break;
+               case 0x080001: return "ISA PIC"; break;
+               case 0x080002: return "EISA PIC"; break;
+               case 0x080010: return "I/O APIC Interrupt Controller"; break;
+               case 0x080020: return "I/O(x) APIC Interrupt Controller"; break;
+               case 0x080100: return "Generic 8237 DMA Controller"; break;
+               case 0x080101: return "ISA DMA Controller"; break;
+               case 0x080102: return "EISA DMA Controller"; break;
+               case 0x080200: return "Generic 8254 System Timer"; break;
+               case 0x080201: return "ISA System Timer"; break;
+               case 0x080202: return "EISA System Timer"; break;
+               case 0x080300: return "Generic RTC Controller"; break;
+               case 0x080301: return "ISA RTC Controller"; break;
+               case 0x080400: return "Generic PCI Hot-Plug Controller"; break;
+               case 0x088000: return "Other System Peripheral"; break;
+               case 0x090000: return "Keyboard Controller"; break;
+               case 0x090100: return "Consumer IR Controller"; break;
+               case 0x090200: return "Audio Controller"; break;
+               case 0x090300: return "Voice Controller"; break;
+               case 0x090310: return "USB (Open Host Controller Spec"; break;
+               case 0x090320: return "USB2 Host Controller (Intel Enhanced Host Controller Interface)"; break;
+               case 0x090380: return "USB"; break;
+               case 0x090400: return "Data Controller"; break;
+               case 0x090410: return "Gameport Contrlller (Legacy)"; break;
+               case 0x090500: return "SMBus"; break;
+               case 0x090600: return "InfiniBand"; break;
+               case 0x090700: return "IPMI SMIC Interface"; break;
+               case 0x090701: return "IPMI Kybd Controller Style Interface"; break;
+               case 0x090702: return "IPMI Block Transfer Interface"; break;
+               case 0x090800: return "SERCOS Interface Standard (IEC 61491)"; break;
+               case 0x090900: return "CANbus"; break;
+               case 0x091000: return "RF Controller"; break;
+               case 0x091100: return "Bluetooth Controller"; break;
+               case 0x091200: return "Broadband Controller"; break;
+               case 0x092000: return "Ethernet Controller (802.11a)"; break;
+               case 0x092100: return "Ethernet Controller (802.11b)"; break;
+               case 0x093000: return "MIPS Processor"; break;
+               case 0x094000: return "Co-Processor"; break;
+               case 0x094010: return "IEEE 1394 Controller (1394 OpenHCI Spec)"; break;
+               case 0x098000: return "Message FIFO"; break;
+               case 0x100000: return "Network and Computing Encrpytion/Decryption"; break;
+               case 0x101000: return "Entertainment Encryption/Decryption"; break;
+               case 0x108000: return "Other Encryption/Decryption"; break;
+               case 0x110000: return "DPIO Modules"; break;
+               case 0x110100: return "Performance Counters"; break;
+               case 0x111000: return "Communications Syncrhonization Plus Time and Frequency Test/Measurment"; break;
+               case 0x112000: return "Management Card"; break;
+               case 0x118000: return "Other Data Acquisition/Signal Processing Controller"; break;
+               default: break;
+       }
+
+       return "unknown";
+}
diff --git a/pci/pci.c b/pci/pci.c
new file mode 100644 (file)
index 0000000..1f810b9
--- /dev/null
+++ b/pci/pci.c
@@ -0,0 +1,422 @@
+#include "kernel.h"
+
+#include "mem.h"
+#include "ioport.h"
+
+#include "pci.h"
+#include <string.h>
+
+/* TODO figure this out better */
+
+struct pci_class_code_desc {
+       uint8_t code;
+       char description[63];
+} pci_class_code_description[256] = {
+/* Class Code  Description */
+       {0x00, "Unclassified Device" },
+       {0x01, "Mass Storage Controller" },
+       {0x02, "Network Controller" },
+       {0x03, "Display Controller" },
+       {0x04, "Multimedia Controller" },
+       {0x05, "Memory Controller" },
+       {0x06, "Bridge" },
+       {0x07, "Communication Controller" },
+       {0x08, "Generic System Peripheral" },
+       {0x09, "Input Device Controller" },
+       {0x0A, "Docking Station" },
+       {0x0B, "Processor" },
+       {0x0C, "Serial Bus Controller" },
+       {0x0D, "Wireless Controller" },
+       {0x0E, "Intelligent Controller" },
+       {0x0F, "Satellite Communications Controller" },
+       {0x10, "Encryption Controller" },
+       {0x11, "Signal Processing Controller" },
+       {0x12, "Processing accelerators"},
+       {0x13, "Non-Essential Instrumentation"},
+       {0x14, "Reserved"},
+       {0x15, "Reserved"},
+       {0x16, "Reserved"},
+       {0x17, "Reserved"},
+       {0x18, "Reserved"},
+       {0x19, "Reserved"},
+       {0x1A, "Reserved"},
+       {0x1B, "Reserved"},
+       {0x1C, "Reserved"},
+       {0x1D, "Reserved"},
+       {0x1E, "Reserved"},
+       {0x1F, "Reserved"},
+       {0x20, "Reserved"},
+       {0x21, "Reserved"},
+       {0x22, "Reserved"},
+       {0x23, "Reserved"},
+       {0x24, "Reserved"},
+       {0x25, "Reserved"},
+       {0x26, "Reserved"},
+       {0x27, "Reserved"},
+       {0x28, "Reserved"},
+       {0x29, "Reserved"},
+       {0x2A, "Reserved"},
+       {0x2B, "Reserved"},
+       {0x2C, "Reserved"},
+       {0x2D, "Reserved"},
+       {0x2E, "Reserved"},
+       {0x2F, "Reserved"},
+       {0x30, "Reserved"},
+       {0x31, "Reserved"},
+       {0x32, "Reserved"},
+       {0x33, "Reserved"},
+       {0x34, "Reserved"},
+       {0x35, "Reserved"},
+       {0x36, "Reserved"},
+       {0x37, "Reserved"},
+       {0x38, "Reserved"},
+       {0x39, "Reserved"},
+       {0x3A, "Reserved"},
+       {0x3B, "Reserved"},
+       {0x3C, "Reserved"},
+       {0x3D, "Reserved"},
+       {0x3E, "Reserved"},
+       {0x3F, "Reserved"},
+       {0x40, "Reserved"},
+       {0x41, "Reserved"},
+       {0x42, "Reserved"},
+       {0x43, "Reserved"},
+       {0x44, "Reserved"},
+       {0x45, "Reserved"},
+       {0x46, "Reserved"},
+       {0x47, "Reserved"},
+       {0x48, "Reserved"},
+       {0x49, "Reserved"},
+       {0x4A, "Reserved"},
+       {0x4B, "Reserved"},
+       {0x4C, "Reserved"},
+       {0x4D, "Reserved"},
+       {0x4E, "Reserved"},
+       {0x4F, "Reserved"},
+       {0x50, "Reserved"},
+       {0x51, "Reserved"},
+       {0x52, "Reserved"},
+       {0x53, "Reserved"},
+       {0x54, "Reserved"},
+       {0x55, "Reserved"},
+       {0x56, "Reserved"},
+       {0x57, "Reserved"},
+       {0x58, "Reserved"},
+       {0x59, "Reserved"},
+       {0x5A, "Reserved"},
+       {0x5B, "Reserved"},
+       {0x5C, "Reserved"},
+       {0x5D, "Reserved"},
+       {0x5E, "Reserved"},
+       {0x5F, "Reserved"},
+       {0x60, "Reserved"},
+       {0x61, "Reserved"},
+       {0x62, "Reserved"},
+       {0x63, "Reserved"},
+       {0x64, "Reserved"},
+       {0x65, "Reserved"},
+       {0x66, "Reserved"},
+       {0x67, "Reserved"},
+       {0x68, "Reserved"},
+       {0x69, "Reserved"},
+       {0x6A, "Reserved"},
+       {0x6B, "Reserved"},
+       {0x6C, "Reserved"},
+       {0x6D, "Reserved"},
+       {0x6E, "Reserved"},
+       {0x6F, "Reserved"},
+       {0x70, "Reserved"},
+       {0x71, "Reserved"},
+       {0x72, "Reserved"},
+       {0x73, "Reserved"},
+       {0x74, "Reserved"},
+       {0x75, "Reserved"},
+       {0x76, "Reserved"},
+       {0x77, "Reserved"},
+       {0x78, "Reserved"},
+       {0x79, "Reserved"},
+       {0x7A, "Reserved"},
+       {0x7B, "Reserved"},
+       {0x7C, "Reserved"},
+       {0x7D, "Reserved"},
+       {0x7E, "Reserved"},
+       {0x7F, "Reserved"},
+       {0x80, "Reserved"},
+       {0x81, "Reserved"},
+       {0x82, "Reserved"},
+       {0x83, "Reserved"},
+       {0x84, "Reserved"},
+       {0x85, "Reserved"},
+       {0x86, "Reserved"},
+       {0x87, "Reserved"},
+       {0x88, "Reserved"},
+       {0x89, "Reserved"},
+       {0x8A, "Reserved"},
+       {0x8B, "Reserved"},
+       {0x8C, "Reserved"},
+       {0x8D, "Reserved"},
+       {0x8E, "Reserved"},
+       {0x8F, "Reserved"},
+       {0x90, "Reserved"},
+       {0x91, "Reserved"},
+       {0x92, "Reserved"},
+       {0x93, "Reserved"},
+       {0x94, "Reserved"},
+       {0x95, "Reserved"},
+       {0x96, "Reserved"},
+       {0x97, "Reserved"},
+       {0x98, "Reserved"},
+       {0x99, "Reserved"},
+       {0x9A, "Reserved"},
+       {0x9B, "Reserved"},
+       {0x9C, "Reserved"},
+       {0x9D, "Reserved"},
+       {0x9E, "Reserved"},
+       {0x9F, "Reserved"},
+       {0xA0, "Reserved"},
+       {0xA1, "Reserved"},
+       {0xA2, "Reserved"},
+       {0xA3, "Reserved"},
+       {0xA4, "Reserved"},
+       {0xA5, "Reserved"},
+       {0xA6, "Reserved"},
+       {0xA7, "Reserved"},
+       {0xA8, "Reserved"},
+       {0xA9, "Reserved"},
+       {0xAA, "Reserved"},
+       {0xAB, "Reserved"},
+       {0xAC, "Reserved"},
+       {0xAD, "Reserved"},
+       {0xAE, "Reserved"},
+       {0xAF, "Reserved"},
+       {0xB0, "Reserved"},
+       {0xB1, "Reserved"},
+       {0xB2, "Reserved"},
+       {0xB3, "Reserved"},
+       {0xB4, "Reserved"},
+       {0xB5, "Reserved"},
+       {0xB6, "Reserved"},
+       {0xB7, "Reserved"},
+       {0xB8, "Reserved"},
+       {0xB9, "Reserved"},
+       {0xBA, "Reserved"},
+       {0xBB, "Reserved"},
+       {0xBC, "Reserved"},
+       {0xBD, "Reserved"},
+       {0xBE, "Reserved"},
+       {0xBF, "Reserved"},
+       {0xC0, "Reserved"},
+       {0xC1, "Reserved"},
+       {0xC2, "Reserved"},
+       {0xC3, "Reserved"},
+       {0xC4, "Reserved"},
+       {0xC5, "Reserved"},
+       {0xC6, "Reserved"},
+       {0xC7, "Reserved"},
+       {0xC8, "Reserved"},
+       {0xC9, "Reserved"},
+       {0xCA, "Reserved"},
+       {0xCB, "Reserved"},
+       {0xCC, "Reserved"},
+       {0xCD, "Reserved"},
+       {0xCE, "Reserved"},
+       {0xCF, "Reserved"},
+       {0xD0, "Reserved"},
+       {0xD1, "Reserved"},
+       {0xD2, "Reserved"},
+       {0xD3, "Reserved"},
+       {0xD4, "Reserved"},
+       {0xD5, "Reserved"},
+       {0xD6, "Reserved"},
+       {0xD7, "Reserved"},
+       {0xD8, "Reserved"},
+       {0xD9, "Reserved"},
+       {0xDA, "Reserved"},
+       {0xDB, "Reserved"},
+       {0xDC, "Reserved"},
+       {0xDD, "Reserved"},
+       {0xDE, "Reserved"},
+       {0xDF, "Reserved"},
+       {0xE0, "Reserved"},
+       {0xE1, "Reserved"},
+       {0xE2, "Reserved"},
+       {0xE3, "Reserved"},
+       {0xE4, "Reserved"},
+       {0xE5, "Reserved"},
+       {0xE6, "Reserved"},
+       {0xE7, "Reserved"},
+       {0xE8, "Reserved"},
+       {0xE9, "Reserved"},
+       {0xEA, "Reserved"},
+       {0xEB, "Reserved"},
+       {0xEC, "Reserved"},
+       {0xED, "Reserved"},
+       {0xEE, "Reserved"},
+       {0xEF, "Reserved"},
+       {0xF0, "Reserved"},
+       {0xF1, "Reserved"},
+       {0xF2, "Reserved"},
+       {0xF3, "Reserved"},
+       {0xF4, "Reserved"},
+       {0xF5, "Reserved"},
+       {0xF6, "Reserved"},
+       {0xF7, "Reserved"},
+       {0xF8, "Reserved"},
+       {0xF9, "Reserved"},
+       {0xFA, "Reserved"},
+       {0xFB, "Reserved"},
+       {0xFC, "Reserved"},
+       {0xFD, "Reserved"},
+       {0xFE, "Reserved"},
+       {0xFF, "Device does not fit any defined class." }
+};
+
+#define PCI_ADDR(bus, dev, func, offset) ( (uint32_t) ( \
+                         ((uint32_t)bus << 16) \
+                       | ((uint32_t)device << 11) \
+                       | ((uint32_t)function << 8) \
+                       | ((uint32_t)0x80000000U) \
+                       | (offset & 0xfc) ) )
+
+uint32_t pci_read_config(uint32_t base, uint8_t offset) {
+       uint32_t data;
+       base = base | (offset & 0xfc);
+       outport32(0xcf8, base);
+       data = inport32(0xcfc);
+       return data;
+}
+
+void pci_write_config(uint32_t base, uint8_t offset, uint32_t val) {
+       base = base | (offset & 0xfc);
+       outport32(0xcf8, base);
+       outport32(0xcfc, val);
+       return;
+}
+
+int pci_read_header(struct pci_header *h, uint8_t bus, uint8_t device, uint8_t function) {
+       uint32_t addr, data;
+       int offset;
+       uint32_t *hb;
+       int size = 0;
+
+       hb = (uint32_t *)h;
+
+       addr = 0;
+       addr =  PCI_ADDR(bus,device,function,0); /* offset 0 for device and vendor id */
+       outport32(0xcf8, addr);
+       data = inport32(0xcfc);
+       h->vendorid = data & 0xffff;
+       h->deviceid = data >> 16;
+       if (h->vendorid == 0xffff) return 0;
+
+       hb++;
+       /* might as well read in the rest */
+
+       //printk("read in vendor id %x\n", h->vendorid);
+       switch (h->headertype & 0x7F) {
+               case 0x00: size = 0x40; break; /* general device */
+               case 0x01: size = 0x40; break; /* PCI to PCI bridge */
+               case 0x02: size = 0x48; break; /* PCI to CardBus bridge */
+               default: size = 0x10; break;
+       }
+
+       for (offset = 4; offset < size ; offset += 4) {
+               addr =  PCI_ADDR(bus,device,function,offset);
+               outport32(0xcf8, addr);
+               data = inport32(0xcfc);
+               *hb++ = data;
+       }
+       return 1;
+}
+
+void pci_debug_info(struct pci_header *h) {
+       printk("pci: id %0x:%0x, type %0x, class %0x:%0x, %s / %s\n",
+                       h->vendorid, h->deviceid, h->headertype, h->classcode, h->subclass,
+                       pci_class_code_description[h->classcode].description,
+                       pci_func_desc(h->classcode, h->subclass, h->progif)
+             );
+}
+
+void pci_scan_bus(uint8_t bus);
+
+void pci_scan_device(uint8_t bus, uint8_t device) {
+       union pci_device h;
+       uint8_t function = 0;
+       struct pci_info *pci;
+
+       pci_read_header((struct pci_header *)&h, 0, device, function);
+
+       if (h.header.vendorid == 0xffff) return;
+
+       //printk("read pci header\n");
+       //pci_debug_info((struct pci_header *)&h);
+       
+       if (h.header.classcode == 0x06 && h.header.subclass == 0x04) {
+               /* this is a bridge */
+               uint8_t secbus = h.bridge.secondary_bus_number;
+               pci_scan_bus(secbus);
+       }
+
+       if (h.header.headertype & 0x80 != 0) {
+               for (function = 1; function < 8; function++) {
+                       pci_read_header((struct pci_header *)&h, 0, device, function);
+                       if (h.header.vendorid == 0xffff) continue;
+//                     pci_debug_info((struct pci_header *)&h);
+                       if (h.header.classcode == 0x06 && h.header.subclass == 0x04) {
+                               /* this is a bridge */
+                               uint8_t secbus = h.bridge.secondary_bus_number;
+                               pci_scan_bus(secbus);
+                       }
+               }
+       }
+       pci = koalloc(sizeof *pci);
+       memcpy(&pci->device, &h, sizeof h);
+       pci->base = PCI_ADDR(bus,device,function,0);
+       if (pci_devices == NULL) {
+//             printk("setting up list\n");
+               pci_devices = pci;
+               pci->next = pci;
+               pci->prev = pci;
+       } else {
+//             printk("adding to list\n");
+
+               pci->prev = pci_devices->prev;
+               pci->next = pci_devices;
+
+               pci_devices->prev->next = pci;
+               pci_devices->prev = pci;
+       }
+}
+
+void pci_scan_bus(uint8_t bus) {
+       uint8_t device;
+
+       for (device = 0; device < 32; device++) {
+               pci_scan_device(bus, device);
+       }
+}
+
+struct pci_info *pci_devices;
+paddr_t pci_start; /* the start of pci space */
+
+void pci_init() {
+       struct pci_info *dev;
+
+       /* align the start of PCI memory to 1 MB */
+       /* TODO we could probably free any remaining physical pages
+        * between the _kernel_phys_end and the new alignment
+        */
+       pci_start = mem_align(_kernel_phys_end, MB(1));
+
+       //printk("sizeof pci_header = %x\n", sizeof h);
+       //
+       /* TODO free the list if it's not null? */
+
+       pci_devices = 0;
+       pci_scan_bus(0);
+
+       for (dev = pci_devices; dev; dev = dev->next) {
+               pci_debug_info(&dev->device.header);
+               if (dev->next == pci_devices) break;
+       }
+}
diff --git a/pci/pci.h b/pci/pci.h
new file mode 100644 (file)
index 0000000..300aa2a
--- /dev/null
+++ b/pci/pci.h
@@ -0,0 +1,116 @@
+#ifndef PCI_H_
+#define PCI_H_ 1
+
+char *pci_func_desc(uint8_t class, uint8_t sub, uint8_t prog);
+void pci_write_config(uint32_t base, uint8_t offset, uint32_t val);
+uint32_t pci_read_config(uint32_t base, uint8_t offset);
+
+struct pci_header {
+       uint16_t vendorid;
+       uint16_t deviceid;
+       uint16_t command;
+       uint16_t status;
+       uint8_t  revisionid;
+       uint8_t  progif;
+       uint8_t  subclass;
+       uint8_t  classcode;
+       uint8_t  cachelinesize;
+       uint8_t  latencytimer;
+       uint8_t  headertype;
+       uint8_t  bist;
+};
+
+/* header type 0x00 */
+struct pci_general {
+       struct pci_header header;
+       uint32_t bar0;
+       uint32_t bar1;
+       uint32_t bar2;
+       uint32_t bar3;
+       uint32_t bar4;
+       uint32_t bar5;
+       uint32_t cardbuscispointer;
+       uint16_t subsystemvendorid;
+       uint16_t subsystemid;
+       uint32_t expansionrombaseaddress;
+       uint32_t capabilities_pointer; /* only low 8 bits, remainder reserved */
+       uint32_t reserved38;
+       uint8_t  interrupt_line;
+       uint8_t  interrupt_pin;
+       uint8_t  mingrant;
+       uint8_t  maxlatency;
+};
+
+/* header type 0x01 */
+struct pci_bridge {
+       struct pci_header header;
+       uint32_t bar0;
+       uint32_t bar1;
+       uint8_t  primary_bus_number;
+       uint8_t  secondary_bus_number;
+       uint8_t  subordinate_bus_number;
+       uint8_t  secondary_latency_timer;
+       uint8_t  iobase;
+       uint8_t  iolimit;
+       uint16_t secondary_status;
+       uint16_t memory_base;
+       uint16_t memory_limit;
+       uint16_t prefetchable_memory_base;
+       uint16_t prefetchable_memory_limit;
+       uint8_t  iobase_upper;
+       uint8_t  iolimit_upper;
+       uint32_t capabilities_pointer; /* only low 8 bits, remainder reserved */
+       uint32_t expansion_rom;
+       uint8_t  interrupt_line;
+       uint8_t  interrupt_pin;
+       uint16_t bridge_control;
+};
+
+/* header type 0x02 */
+struct pci_cardbus {
+       struct pci_header header;
+       uint32_t cardbussocket;
+       uint8_t  capoffset;
+       uint8_t  reserved;
+       uint16_t secondary_status;
+       uint8_t  pci_bus;
+       uint8_t  cardbus_bus;
+       uint8_t  subordinate_bus_number;
+       uint8_t  cardbus_latency_timer;
+       uint32_t memory_base0;
+       uint32_t memory_limit0;
+       uint32_t memory_base1;
+       uint32_t memory_limit1;
+       uint32_t io_base0;
+       uint32_t io_limit0;
+       uint32_t io_base1;
+       uint32_t io_limit1;
+       uint8_t  interrupt_line;
+       uint8_t  interrupt_pin;
+       uint16_t bridge_control;
+       uint16_t subsystem_device;
+       uint16_t subsystem_vendor;
+       uint32_t pccard16bitaddr;
+};
+
+union pci_device {
+       struct pci_header header;
+       struct pci_general general;
+       struct pci_bridge bridge;
+       struct pci_cardbus cardbus;
+};
+
+struct pci_info {
+       union pci_device device;
+       struct pci_info *next;
+       struct pci_info *prev;
+       uint32_t base; /* base address of pci io registers */
+       size_t bar_size[6];
+       void *bar_addr[6];
+};
+
+extern struct pci_info *pci_devices;
+
+void pci_init();
+
+#endif