Add basic PCI driver
This commit is contained in:
parent
49ddb47ad4
commit
af8e5aca64
28
kernel/include/io/PCI.h
Normal file
28
kernel/include/io/PCI.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace PCI
|
||||
{
|
||||
struct DeviceID
|
||||
{
|
||||
uint16_t vendor;
|
||||
uint16_t device;
|
||||
};
|
||||
struct DeviceType
|
||||
{
|
||||
uint8_t dev_class;
|
||||
uint8_t dev_subclass;
|
||||
uint8_t prog_if;
|
||||
uint8_t revision;
|
||||
};
|
||||
uint32_t raw_address(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset);
|
||||
void raw_write8(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint8_t value);
|
||||
void raw_write16(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint16_t value);
|
||||
void raw_write32(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint32_t value);
|
||||
uint8_t raw_read8(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset);
|
||||
uint16_t raw_read16(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset);
|
||||
uint32_t raw_read32(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset);
|
||||
DeviceID get_device_id(uint32_t bus, uint32_t slot, uint32_t function);
|
||||
DeviceType get_device_type(uint32_t bus, uint32_t slot, uint32_t function);
|
||||
void scan(void (*callback)(PCI::DeviceID&, PCI::DeviceType&));
|
||||
}
|
111
kernel/src/io/PCI.cpp
Normal file
111
kernel/src/io/PCI.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
#define MODULE "pci"
|
||||
|
||||
#include "io/PCI.h"
|
||||
#include "io/IO.h"
|
||||
#include "log/Log.h"
|
||||
#include "thread/Spinlock.h"
|
||||
|
||||
#define PCI_ADDRESS 0xCF8
|
||||
#define PCI_VALUE 0xCFC
|
||||
|
||||
#define PCI_VENDOR_FIELD 0x0
|
||||
#define PCI_DEVICE_FIELD 0x2
|
||||
#define PCI_SUBCLASS_FIELD 0xa
|
||||
#define PCI_CLASS_FIELD 0xb
|
||||
#define PCI_REVISION_ID_FIELD 0x8
|
||||
#define PCI_PROG_IF_FIELD 0x9
|
||||
#define PCI_HEADER_TYPE_FIELD 0xe
|
||||
#define PCI_SECONDARY_BUS_NUMBER_FIELD 0x19
|
||||
|
||||
Spinlock pci_lock;
|
||||
|
||||
uint32_t PCI::raw_address(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset)
|
||||
{
|
||||
return 0x80000000 | (bus << 16) | (slot << 11) | (function << 8) | ((offset)&0xFC);
|
||||
}
|
||||
|
||||
void PCI::raw_write8(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint8_t value)
|
||||
{
|
||||
IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset));
|
||||
IO::outl(PCI_VALUE, (uint32_t)value);
|
||||
}
|
||||
|
||||
void PCI::raw_write16(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint16_t value)
|
||||
{
|
||||
IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset));
|
||||
IO::outl(PCI_VALUE, (uint32_t)value);
|
||||
}
|
||||
|
||||
void PCI::raw_write32(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset, uint32_t value)
|
||||
{
|
||||
IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset));
|
||||
IO::outl(PCI_VALUE, value);
|
||||
}
|
||||
|
||||
uint8_t PCI::raw_read8(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset)
|
||||
{
|
||||
IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset));
|
||||
return IO::inl(PCI_VALUE + (offset & 3));
|
||||
}
|
||||
|
||||
uint16_t PCI::raw_read16(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset)
|
||||
{
|
||||
IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset));
|
||||
return IO::inl(PCI_VALUE + (offset & 2));
|
||||
}
|
||||
|
||||
uint32_t PCI::raw_read32(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset)
|
||||
{
|
||||
IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset));
|
||||
return IO::inl(PCI_VALUE);
|
||||
}
|
||||
|
||||
PCI::DeviceID PCI::get_device_id(uint32_t bus, uint32_t slot, uint32_t function)
|
||||
{
|
||||
uint16_t vendor = PCI::raw_read16(bus, slot, function, PCI_VENDOR_FIELD);
|
||||
uint16_t device = PCI::raw_read16(bus, slot, function, PCI_DEVICE_FIELD);
|
||||
return {vendor, device};
|
||||
}
|
||||
|
||||
PCI::DeviceType PCI::get_device_type(uint32_t bus, uint32_t slot, uint32_t function)
|
||||
{
|
||||
uint8_t dev_subclass = PCI::raw_read8(bus, slot, function, PCI_SUBCLASS_FIELD);
|
||||
uint8_t dev_class = PCI::raw_read8(bus, slot, function, PCI_CLASS_FIELD);
|
||||
uint8_t prog_if = PCI::raw_read8(bus, slot, function, PCI_PROG_IF_FIELD);
|
||||
uint8_t revision = PCI::raw_read8(bus, slot, function, PCI_REVISION_ID_FIELD);
|
||||
return {dev_class, dev_subclass, prog_if, revision};
|
||||
}
|
||||
|
||||
static void pci_scan_bus(uint8_t bus, void (*callback)(PCI::DeviceID&, PCI::DeviceType&))
|
||||
{
|
||||
for (uint8_t slot = 0; slot < 32; slot++)
|
||||
{
|
||||
uint8_t num_functions = 1;
|
||||
for (uint8_t function = 0; function < num_functions; function++)
|
||||
{
|
||||
PCI::DeviceID device_id = PCI::get_device_id(bus, slot, function);
|
||||
if (device_id.vendor == 0xFFFF || device_id.device == 0xFFFF) continue;
|
||||
PCI::DeviceType device_type = PCI::get_device_type(bus, slot, function);
|
||||
uint8_t header = PCI::raw_read8(bus, slot, function, PCI_HEADER_TYPE_FIELD);
|
||||
if (header & 0x80) // multi function device
|
||||
{
|
||||
num_functions = 8;
|
||||
}
|
||||
if ((header & 0x7F) == 1)
|
||||
{
|
||||
uint8_t sub_bus = PCI::raw_read8(bus, slot, function, PCI_SECONDARY_BUS_NUMBER_FIELD);
|
||||
pci_scan_bus(sub_bus, callback);
|
||||
}
|
||||
pci_lock.release();
|
||||
callback(device_id, device_type);
|
||||
pci_lock.acquire();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PCI::scan(void (*callback)(PCI::DeviceID&, PCI::DeviceType&))
|
||||
{
|
||||
pci_lock.acquire();
|
||||
pci_scan_bus(0, callback);
|
||||
pci_lock.release();
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
#include "interrupts/IDT.h"
|
||||
#include "interrupts/Install.h"
|
||||
#include "interrupts/Interrupts.h"
|
||||
#include "io/PCI.h"
|
||||
#include "io/PIC.h"
|
||||
#include "io/Serial.h"
|
||||
#include "log/Log.h"
|
||||
@ -128,5 +129,10 @@ extern "C" void _start()
|
||||
|
||||
kinfoln("Interrupts enabled");
|
||||
|
||||
PCI::scan([](PCI::DeviceID& dev_id, PCI::DeviceType& dev_type) {
|
||||
kinfoln("Found PCI device %x:%x, class %x, subclass %x, prog if %x, revision %d", dev_id.vendor, dev_id.device,
|
||||
dev_type.dev_class, dev_type.dev_subclass, dev_type.prog_if, dev_type.revision);
|
||||
});
|
||||
|
||||
while (1) Scheduler::sleep(200);
|
||||
}
|
Loading…
Reference in New Issue
Block a user