mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 06:58:22 +00:00
135 lines
3.0 KiB
C
135 lines
3.0 KiB
C
#include <arch/pci.h>
|
|
#include <arch/acpi.h>
|
|
#include <arch/io.h>
|
|
#include <kernel/alloc.h>
|
|
#include <stdio.h>
|
|
|
|
pci_enumeration* enumerations;
|
|
|
|
#define CONFIG_ADDRESS 0xCF8
|
|
#define CONFIG_DATA 0xCFC
|
|
|
|
uint32_t legacy_readdata(int bus, int device, int func, int reg){
|
|
|
|
uint32_t address = reg << 2;
|
|
address |= (func & 0b111) << 8;
|
|
address |= (device & 0b11111) << 11;
|
|
address |= (bus & 0xFF) << 16;
|
|
address |= 1 << 31;
|
|
|
|
outd(CONFIG_ADDRESS, address);
|
|
|
|
return ind(CONFIG_DATA);
|
|
|
|
}
|
|
|
|
static inline bool legacy_exists(int bus, int device, int func){
|
|
return legacy_readdata(bus, device, func, 0) != 0xFFFFFFFF;
|
|
}
|
|
|
|
static pci_enumeration* allocnewenum(){
|
|
|
|
pci_enumeration* enumeration;
|
|
|
|
if(!enumerations){
|
|
enumeration = alloc(sizeof(pci_enumeration));
|
|
}
|
|
else{
|
|
while(enumeration->next != NULL)
|
|
enumeration = enumeration->next;
|
|
|
|
enumeration->next = alloc(sizeof(pci_enumeration));
|
|
enumeration = enumeration->next;
|
|
}
|
|
|
|
return enumeration;
|
|
}
|
|
|
|
static void legacy_copyheader(pci_enumeration* dev, size_t size){
|
|
size_t count = size / 4;
|
|
uint32_t* where = (uint32_t*)dev->header;
|
|
|
|
for(size_t i = 0; i < count; ++i)
|
|
*where++ = legacy_readdata(dev->bus, dev->device, dev->function, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t legacy_getcapabilityoffset(size_t id, pci_enumeration* enumeration){
|
|
|
|
// does this device have a capability list
|
|
|
|
if(enumeration->header->status & (1 << 4) == 0) return 0;
|
|
|
|
size_t offset = ((pci_deviceheader*)enumeration->header)->capabilities>> 2;
|
|
|
|
while(offset){
|
|
uint32_t word = legacy_readdata(enumeration->bus, enumeration->device, enumeration->function, offset);
|
|
|
|
size_t targetid = word & 0xFF;
|
|
|
|
if(targetid == id)
|
|
return offset;
|
|
|
|
offset = (word >> 8) & 0xFF;
|
|
offset >>= 2;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static void legacy_enumeratedevice(int bus, int device){
|
|
|
|
// if the device is multifunction, scan and enumerate all 8. else, only one
|
|
|
|
size_t functioncount = ((legacy_readdata(bus, device, 0, 3) >> 16) & 0xFF) != 0 ? 8 : 1;
|
|
|
|
for(size_t function = 0; function < functioncount; ++function){
|
|
if(!legacy_exists(bus, device, function))
|
|
continue;
|
|
|
|
pci_enumeration* enumeration = allocnewenum();
|
|
|
|
enumeration->bus = bus;
|
|
enumeration->device = device;
|
|
enumeration->function = function;
|
|
|
|
// type with multifunction masked off
|
|
size_t type = (legacy_readdata(bus, device, function, 3) >> 16) & 0x7F;
|
|
|
|
size_t headersize = type == PCI_CARDBUS_HEADER ? PCI_CARDBUS_HEADERSIZE : PCI_OTHER_HEADERSIZE;
|
|
|
|
enumeration->header = alloc(headersize);
|
|
|
|
legacy_copyheader(enumeration, headersize);
|
|
|
|
printf("PCI: %02x:%02x.%x %02x%02x: %04x:%04x (rev %2x) \n", bus, device, function, enumeration->header->class, enumeration->header->subclass, enumeration->header->vendor, enumeration->header->device, enumeration->header->revision);
|
|
}
|
|
|
|
}
|
|
|
|
static void legacy_enumeration(){
|
|
|
|
for(size_t bus = 0; bus < 1; ++bus){
|
|
for(size_t device = 0; device < 32; ++device){
|
|
if(legacy_exists(bus, device, 0))
|
|
legacy_enumeratedevice(bus, device);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void pci_enumerate(){
|
|
|
|
// TODO PCIe enumeration
|
|
|
|
legacy_enumeration();
|
|
|
|
|
|
}
|