Newer
Older
tree-os / src / kernel / drivers / pci / pci.c
#include <_stdio.h>
#include <pci.h>
#include <ports.h>
#include <stdint.h>
#include <task.h>
#include <util.h>

char *classNames[] = {
    "Unclassified",
    "Mass Storage Controller",
    "Network controller",
    "Display controller",
    "Multimedia controller",
    "Memory Controller",
    "Bridge",
    "Simple Communication controller",
    "Base System Peripheral",
    "Input Device controller",
    "Docking station",
    "Processor",
    "Serial bus controller",
    "Wireless controller",
    "intelligent controller",
    "sattelite communication controller",
    "encryption controller",
    "signal processing controller",
    "processing accelerator",
    "non-essential instrumentation",
};

uint8_t pciConfigReadByte(uint32_t bus, uint32_t device, uint32_t function,
                          uint8_t offset) {
    uint32_t address = ((bus << 16) | (device << 11) | (function << 8) |
                        (offset & 0xFC) | 0x80000000);
    asm("cli");
    outi(0xCF8, address);
    uint8_t result = (ini(0xCFC) >> ((offset % 4) * 8));
    asm("sti");
    return result;
}

uint16_t pciConfigReadWord(uint8_t bus, uint8_t device, uint8_t function,
                           uint8_t offset) {
    return (uint16_t)pciConfigReadByte(bus, device, function, offset) |
           ((uint16_t)pciConfigReadByte(bus, device, function, offset + 1)
            << 8);
}

uint8_t getHeaderType(uint8_t bus, uint8_t device, uint8_t function) {
    return pciConfigReadByte(bus, device, function, 0x0E);
}

uint16_t getVendorID(uint8_t bus, uint8_t device, uint8_t function) {
    return pciConfigReadWord(bus, device, function, 0);
}

void checkFunction(uint8_t bus, uint8_t device, uint8_t function) {
    uint8_t class = pciConfigReadByte(bus, device, function, 0xB);
    uint8_t subclass = pciConfigReadByte(bus, device, function, 0xA);
    printf("function %i:%i:%i -> %i:%i, a %s\n", bus, device, function, class,
           subclass, classNames[class]);
}

void checkDevice(uint8_t bus, uint8_t device) {
    uint16_t vendorID = getVendorID(bus, device, 0);
    if (vendorID == 0xFFFF) {
        return;
    }
    if (getHeaderType(bus, device, 0) & 0x08) {
        // multifunction device
        for (int function = 0; function < 8; function++) {
            if (getVendorID(bus, device, function) != 0xFFFF) {
                checkFunction(bus, device, function);
            }
        }
    } else {
        checkFunction(bus, device, 0);
    }
}

void checkBus(uint8_t bus) {
    for (uint8_t device = 0; device < 32; device++) {
        checkDevice(bus, device);
    }
}

void scanPCIDevices() {
    printf("scanning pci devices...\n");
    if (!(getHeaderType(0, 0, 0) & 0x80)) {
        printf("discovored a single pci host controller\n");
        checkBus(0);
    } else {
        for (uint8_t bus = 0; bus < 8; bus++) {
            checkBus(bus);
        }
    }
    yields();
}