--- /dev/null
+#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;
+ }
+}