quinn-os/pci.c
2015-09-03 14:22:38 +10:00

126 lines
4.1 KiB
C

#include "io.h"
#include "pci.h"
#include "string.h"
#include "memory.h"
#include "console.h"
struct pci_device **pci_devices;
int pci_device_count;
unsigned long pci_config_read_dword(unsigned short bus, unsigned short slot, unsigned short func, unsigned short offset) {
unsigned long address;
unsigned long lbus = (unsigned long)bus;
unsigned long lslot = (unsigned long)slot;
unsigned long lfunc = (unsigned long)func;
unsigned long tmp = 0;
address = (unsigned long)((lbus << 16) | (lslot << 11) | (lfunc << 8) | (offset & 0xfc) | ((unsigned long)0x80000000));
outportl(0xCF8, address);
tmp = inportl(0xCFC);
return tmp;
}
unsigned short pci_config_read_word(unsigned short bus, unsigned short slot, unsigned short func, unsigned short offset) {
unsigned long address;
unsigned long lbus = (unsigned long)bus;
unsigned long lslot = (unsigned long)slot;
unsigned long lfunc = (unsigned long)func;
unsigned short tmp = 0;
address = (unsigned long)((lbus << 16) | (lslot << 11) | (lfunc << 8) | (offset & 0xfc) | ((unsigned long)0x80000000));
outportl(0xCF8, address);
tmp = (unsigned short)((inportl(0xCFC) >> ((offset & 2) * 8)) & 0xffff);
return tmp;
}
void pci_read_bases_00(struct pci_device *dev) {
dev->base[0] = pci_config_read_dword(dev->bus, dev->slot, dev->func, 0x10);
dev->base[1] = pci_config_read_dword(dev->bus, dev->slot, dev->func, 0x14);
dev->base[2] = pci_config_read_dword(dev->bus, dev->slot, dev->func, 0x18);
dev->base[3] = pci_config_read_dword(dev->bus, dev->slot, dev->func, 0x1C);
dev->base[4] = pci_config_read_dword(dev->bus, dev->slot, dev->func, 0x20);
dev->base[5] = pci_config_read_dword(dev->bus, dev->slot, dev->func, 0x24);
}
void init_pci(void) {
int bus;
int slot;
int func;
struct pci_device tmp_device;
pci_device_count = 0;
for (bus = 0; bus < 4; bus++) {
for (slot = 0; slot < 32; slot++) {
for (func = 0; func < 8; func++) {
if ((tmp_device.vendor = pci_config_read_word(bus, slot, 0, 0)) != 0xFFFF) {
if (func && !(tmp_device.header_type & 0x80)) {
continue;
}
tmp_device.header_type = pci_config_read_word(bus, slot, func, 14) & 0x00FF;
tmp_device.device = pci_config_read_word(bus, slot, func, 2);
tmp_device.classtype = (pci_config_read_word(bus, slot, func, 10)>>8) & 0x00FF;
tmp_device.subclasstype = pci_config_read_word(bus, slot, func, 10) & 0x00FF;
tmp_device.bus = bus;
tmp_device.slot = slot;
tmp_device.func = func;
if ((tmp_device.header_type & 0x3F) == 0x00) {
pci_read_bases_00(&tmp_device);
tmp_device.irq = pci_config_read_word(bus, slot, func, 0x3c) & 0x00FF;
}
if (pci_device_count == 0) {
pci_devices = (struct pci_device **)malloc(sizeof(struct pci_device *));
} else {
pci_devices = (struct pci_device **)realloc(pci_devices, sizeof(struct pci_device *) * (pci_device_count + 1));
}
pci_devices[pci_device_count] = (struct pci_device *)malloc(sizeof(struct pci_device));
memcpy((char *)pci_devices[pci_device_count], (char *)&tmp_device, sizeof(struct pci_device));
pci_device_count++;
}
}
}
}
kprintf("Found %d PCI devices\n", pci_device_count);
}
int pci_find_device(unsigned char classt, unsigned char subclasst, struct pci_device **device, int offset) {
int i;
int count = 0;
for (i=0;i<pci_device_count;i++) {
if (pci_devices[i]->classtype == classt && pci_devices[i]->subclasstype == subclasst) {
if (count < offset) {
count++;
continue;
}
*device = pci_devices[i];
return 1;
}
}
return 0;
}
int pci_find_device_by_vendor(unsigned short vendort, unsigned short devicet, struct pci_device **device, int offset) {
int i;
int count = 0;
for (i=0;i<pci_device_count;i++) {
if (pci_devices[i]->vendor == vendort && pci_devices[i]->device == devicet) {
if (count < offset) {
count++;
continue;
}
*device = pci_devices[i];
return 1;
}
}
return 0;
}