new PCI bus scanning & configuration code as C++ class
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4856 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,189 @@
|
|||||||
|
#include <KernelExport.h>
|
||||||
|
#include <PCI.h>
|
||||||
|
#include "util/kernel_cpp.h"
|
||||||
|
#include "pci_priv.h"
|
||||||
|
#include "pci.h"
|
||||||
|
|
||||||
|
static PCI *pcidb;
|
||||||
|
|
||||||
|
void
|
||||||
|
pci_init(void)
|
||||||
|
{
|
||||||
|
pcidb = new PCI;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pci_uninit(void)
|
||||||
|
{
|
||||||
|
delete pcidb;
|
||||||
|
}
|
||||||
|
|
||||||
|
long
|
||||||
|
pci_get_nth_pci_info(long index, pci_info *outInfo)
|
||||||
|
{
|
||||||
|
return pcidb->GetNthPciInfo(index, outInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PCI::PCI()
|
||||||
|
{
|
||||||
|
fRootBus.parent = 0;
|
||||||
|
fRootBus.bus = 0;
|
||||||
|
fRootBus.child = 0;
|
||||||
|
|
||||||
|
DiscoverBus(&fRootBus);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PCI::~PCI()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
PCI::GetNthPciInfo(long index, pci_info *outInfo)
|
||||||
|
{
|
||||||
|
long curindex = 0;
|
||||||
|
return GetNthPciInfo(&fRootBus, &curindex, index, outInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
PCI::GetNthPciInfo(PCIBus *bus, long *curindex, long wantindex, pci_info *outInfo)
|
||||||
|
{
|
||||||
|
// maps tree structure to linear indexed view
|
||||||
|
PCIDev *dev = bus->child;
|
||||||
|
while (dev) {
|
||||||
|
if (*curindex == wantindex) {
|
||||||
|
*outInfo = dev->info;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
*curindex += 1;
|
||||||
|
if (dev->child && B_OK == GetNthPciInfo(dev->child, curindex, wantindex, outInfo))
|
||||||
|
return B_OK;
|
||||||
|
dev = dev->next;
|
||||||
|
}
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PCI::DiscoverBus(PCIBus *bus)
|
||||||
|
{
|
||||||
|
dprintf("PCI: DiscoverBus, bus %u\n", bus->bus);
|
||||||
|
|
||||||
|
for (int dev = 0; dev < gMaxBusDevices; dev++) {
|
||||||
|
uint16 vendor_id = pci_read_config(bus->bus, dev, 0, PCI_vendor_id, 2);
|
||||||
|
if (vendor_id == 0xffff)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8 type = pci_read_config(bus->bus, dev, 0, PCI_header_type, 1);
|
||||||
|
int nfunc = (type & PCI_multifunction) ? 8 : 1;
|
||||||
|
for (int func = 0; func < nfunc; func++)
|
||||||
|
DiscoverDevice(bus, dev, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PCI::DiscoverDevice(PCIBus *bus, uint8 dev, uint8 func)
|
||||||
|
{
|
||||||
|
dprintf("PCI: DiscoverDevice, bus %u, dev %u, func %u\n", bus->bus, dev, func);
|
||||||
|
|
||||||
|
uint16 device_id = pci_read_config(bus->bus, dev, func, PCI_device_id, 2);
|
||||||
|
if (device_id == 0xffff)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PCIDev *newdev = CreateDevice(bus, dev, func);
|
||||||
|
|
||||||
|
uint8 base_class = pci_read_config(bus->bus, dev, func, PCI_class_base, 1);
|
||||||
|
uint8 sub_class = pci_read_config(bus->bus, dev, func, PCI_class_sub, 1);
|
||||||
|
if (base_class == PCI_bridge && sub_class == PCI_pci) {
|
||||||
|
uint8 secondary_bus = pci_read_config(bus->bus, dev, func, PCI_secondary_bus, 1);
|
||||||
|
PCIBus *newbus = CreateBus(newdev, secondary_bus);
|
||||||
|
DiscoverBus(newbus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PCIBus *
|
||||||
|
PCI::CreateBus(PCIDev *parent, uint8 bus)
|
||||||
|
{
|
||||||
|
PCIBus *newbus = new PCIBus;
|
||||||
|
newbus->parent = parent;
|
||||||
|
newbus->bus = bus;
|
||||||
|
newbus->child = 0;
|
||||||
|
|
||||||
|
// append
|
||||||
|
parent->child = newbus;
|
||||||
|
|
||||||
|
return newbus;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PCIDev *
|
||||||
|
PCI::CreateDevice(PCIBus *parent, uint8 dev, uint8 func)
|
||||||
|
{
|
||||||
|
dprintf("PCI: CreateDevice, bus %u, dev %u, func %u:\n", parent->bus, dev, func);
|
||||||
|
|
||||||
|
PCIDev *newdev = new PCIDev;
|
||||||
|
newdev->next = 0;
|
||||||
|
newdev->parent = parent;
|
||||||
|
newdev->child = 0;
|
||||||
|
newdev->bus = parent->bus;
|
||||||
|
newdev->dev = dev;
|
||||||
|
newdev->func = func;
|
||||||
|
|
||||||
|
ReadPciBasicInfo(newdev);
|
||||||
|
|
||||||
|
dprintf("PCI: vendor 0x%04x, device 0x%04x, class_base 0x%02x, class_sub 0x%02x\n",
|
||||||
|
newdev->info.vendor_id, newdev->info.device_id, newdev->info.class_base, newdev->info.class_sub);
|
||||||
|
|
||||||
|
// append
|
||||||
|
if (parent->child == 0) {
|
||||||
|
parent->child = newdev;
|
||||||
|
} else {
|
||||||
|
PCIDev *sub = parent->child;
|
||||||
|
while (sub->next)
|
||||||
|
sub = sub->next;
|
||||||
|
sub->next = newdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PCI::ReadPciBasicInfo(PCIDev *dev)
|
||||||
|
{
|
||||||
|
dev->info.vendor_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_vendor_id, 2);
|
||||||
|
dev->info.device_id = pci_read_config(dev->bus, dev->dev, dev->func, PCI_device_id, 2);
|
||||||
|
dev->info.bus = dev->bus;
|
||||||
|
dev->info.device = dev->dev;
|
||||||
|
dev->info.function = dev->func;
|
||||||
|
dev->info.revision = pci_read_config(dev->bus, dev->dev, dev->func, PCI_revision, 1);
|
||||||
|
dev->info.class_api = pci_read_config(dev->bus, dev->dev, dev->func, PCI_class_api, 1);
|
||||||
|
dev->info.class_sub = pci_read_config(dev->bus, dev->dev, dev->func, PCI_class_sub, 1);
|
||||||
|
dev->info.class_base = pci_read_config(dev->bus, dev->dev, dev->func, PCI_class_base, 1);
|
||||||
|
dev->info.line_size = pci_read_config(dev->bus, dev->dev, dev->func, PCI_line_size, 1);
|
||||||
|
dev->info.latency = pci_read_config(dev->bus, dev->dev, dev->func, PCI_latency, 1);
|
||||||
|
dev->info.header_type = pci_read_config(dev->bus, dev->dev, dev->func, PCI_header_type, 1);
|
||||||
|
dev->info.header_type &= PCI_header_type_mask; // this masks off the multifunction bit
|
||||||
|
dev->info.bist = pci_read_config(dev->bus, dev->dev, dev->func, PCI_bist, 1);
|
||||||
|
dev->info.reserved = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PCI::ReadPciHeaderInfo(PCIDev *dev)
|
||||||
|
{
|
||||||
|
switch (dev->info.header_type) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dprintf("PCI: Header type unknown (%d)\n", dev->info.header_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void pci_init(void);
|
||||||
|
void pci_uninit(void);
|
||||||
|
long pci_get_nth_pci_info(long index, pci_info *outInfo);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
struct PCIBus;
|
||||||
|
struct PCIDev;
|
||||||
|
|
||||||
|
struct PCIBus
|
||||||
|
{
|
||||||
|
PCIDev *parent;
|
||||||
|
uint8 bus;
|
||||||
|
PCIDev *child;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PCIDev
|
||||||
|
{
|
||||||
|
PCIDev *next;
|
||||||
|
PCIBus *parent;
|
||||||
|
PCIBus *child;
|
||||||
|
uint8 bus;
|
||||||
|
uint8 dev;
|
||||||
|
uint8 func;
|
||||||
|
pci_info info;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PCI
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PCI();
|
||||||
|
~PCI();
|
||||||
|
|
||||||
|
status_t GetNthPciInfo(long index, pci_info *outInfo);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void DiscoverBus(PCIBus *bus);
|
||||||
|
void DiscoverDevice(PCIBus *bus, uint8 dev, uint8 func);
|
||||||
|
|
||||||
|
PCIDev *CreateDevice(PCIBus *parent, uint8 dev, uint8 func);
|
||||||
|
PCIBus *CreateBus(PCIDev *parent, uint8 bus);
|
||||||
|
|
||||||
|
status_t GetNthPciInfo(PCIBus *bus, long *curindex, long wantindex, pci_info *outInfo);
|
||||||
|
void ReadPciBasicInfo(PCIDev *dev);
|
||||||
|
void ReadPciHeaderInfo(PCIDev *dev);
|
||||||
|
|
||||||
|
private:
|
||||||
|
PCIBus fRootBus;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user