Update the config_manager and pci modules.

This now reports better and starts configuring the busses we find.

There is still a long way to go but this another step on the way.

NB the information comes from 2 different methods and presently doesn't
   agree This is known and will be fixed, so please don't start yelling
   that it's broken! If people have strange debug information please
   let me have a copy so I can try to debug further :)


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@403 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
David Reid 2002-07-23 21:28:35 +00:00
parent 459de0d777
commit f8e2c34c67
2 changed files with 415 additions and 134 deletions

View File

@ -11,6 +11,7 @@
#include <errno.h>
#include <debug.h>
#include <string.h>
#include <memheap.h>
/* This is normally turned off. Turning it on (1) will provide a more
* verbose description of the PCI devices found, though most of the extra
@ -18,6 +19,11 @@
*/
#define THE_FULL_MONTY 0
static pci_module_info *pcim = NULL;
static void pci_scan_bus(uint8 bus);
static void pci_bridge(uint8 bus, uint8 dev, uint8 func);
#define B_CONFIG_MANAGER_FOR_BUS_MODULE_NAME "bus_managers/config_manager/bus/v1"
static status_t cfdm_get_next_device_info(bus_type bus, uint64 *cookie,
@ -28,22 +34,102 @@ static status_t cfdm_get_next_device_info(bus_type bus, uint64 *cookie,
return 0;
}
static char *decode_class_base(uint8 base)
static char *decode_class(uint8 base, uint8 sub_class)
{
switch(base) {
case 0x00: return "legacy";
case 0x01: return "mass storage controller";
case 0x02: return "network controller";
case 0x03: return "display controller";
case 0x04: return "multimedia device";
case PCI_early:
switch (sub_class) {
case PCI_early_not_vga:
return "legacy (non VGA)";
case PCI_early_vga:
return "legacy VGA";
}
case 0x01:
switch (sub_class) {
case PCI_scsi:
return "mass storage controller: scsi";
case PCI_ide:
return "mass storage controller: ide";
case PCI_floppy:
return "mass storage controller: floppy";
case PCI_ipi:
return "mass storage controller: ipi";
case PCI_raid:
return "mass storage controller: raid";
case PCI_mass_storage_other:
return "mass storage controller: other";
}
case 0x02:
switch (sub_class) {
case PCI_ethernet:
return "network controller: ethernet";
case PCI_token_ring:
return "network controller: token ring";
case PCI_fddi:
return "network controller: fddi";
case PCI_atm:
return "network controller: atm";
case PCI_network_other:
return "network controller: other";
}
case 0x03:
switch (sub_class) {
case PCI_vga:
return "display controller: vga";
case PCI_xga:
return "display controller: xga";
case PCI_display_other:
return "display controller: other";
}
case 0x04:
switch (sub_class) {
case PCI_video:
return "multimedia device: video";
case PCI_audio:
return "multimedia device: audio";
case PCI_multimedia_other:
return "multimedia device: other";
}
case 0x05: return "memory controller";
case 0x06: return "bridge controller";
case 0x06:
switch (sub_class) {
case PCI_host:
return "bridge controller: host bridge";
case PCI_isa:
return "bridge controller: isa";
case PCI_eisa:
return "bridge controller: eisa";
case PCI_microchannel:
return "bridge controller: microchannel";
case PCI_pci:
return "bridge controller: PCI";
case PCI_pcmcia:
return "bridge controller: PC Card";
case PCI_nubus:
return "bridge controller: nubus";
case PCI_cardbus:
return "bridge controller: CardBus";
case PCI_bridge_other:
return "bridge controller: other";
}
case 0x07: return "simple comms controller";
case 0x08: return "base system peripheral";
case 0x09: return "input device";
case 0x0a: return "docking station";
case 0x0b: return "processor";
case 0x0c: return "serial bus controller";
case 0x0c:
switch (sub_class) {
case PCI_firewire:
return "bus controller: IEEE1394 FireWire";
case PCI_access:
return "bus controller: ACCESS.bus";
case PCI_ssa:
return "bus controller: SSA";
case PCI_usb:
return "bus controller: USB";
case PCI_fibre_channel:
return "bus controller: fibre channel";
}
case 0x0d: return "wireless";
case 0x0e: return "intelligent i/o ??";
case 0x0f: return "satellite";
@ -53,108 +139,237 @@ static char *decode_class_base(uint8 base)
}
}
/* XXX - these are only listed as they're the ones that my system has!
* I'm committing mainly so I don't have to keep adjusting this file each
* time I commit a change. I'm NOT suggesting others add their codes here.
* The level of detail offered is useful if you're working on this, otherwise
* it's just nice to have. Adding all the data we need will add over 270k to
* the build!
*/
static char *decode_vendor(uint16 vendor)
{
switch(vendor) {
case 0x102b: return "Matrox";
case 0x10b7: return "3Com";
case 0x11ad: return "Lite-On";
case 0x1385: return "NetGear";
case 0x8086: return "Intel";
default: return "unknown";
}
}
static char *decode_device(uint16 dev)
{
switch(dev) {
case 0x0002: return "NGMC169B, 10/100 Ethernet (NetGear FA310TX)";
case 0x051a: return "MGA 1064SG, Hurricane/Cyclone 64-bit graphics chip";
case 0x7110: return "82371AB/EB/MB, PIIX4/4E/4M ISA Bridge";
case 0x7111: return "82371AB/EB/MB, PIIX4/4E/4M IDE Controller";
case 0x7112: return "82371AB/EB/MB, PIIX4/4E/4M USB Interface";
case 0x7113: return "82371AB/EB/MB, PIIX4/4E/4M Power Management Controller";
case 0x7190: return "82443BX/ZX, 440BX/ZX AGPset Host Bridge";
case 0x7191: return "82443BX/ZX, 440BX/ZX AGPset PCI-to-PCI bridge";
case 0x7192: return "82443BX/ZX, 440BX/ZX chipset Host-to-PCI Bridge";
case 0x9055: return "3C905B-TX, Fast Etherlink 10/100 PCI TX NIC";
default: return "unknown";
}
}
static void show_pci_details(struct pci_info *p, pci_module_info *pcim)
{
dprintf("PCI device found:\n");
dprintf("\tvendor id : %02x [%s]\n", p->vendor_id, decode_vendor(p->vendor_id));
dprintf("\tdevice id : %02x [%s]\n", p->device_id, decode_device(p->device_id));
#if THE_FULL_MONTY
dprintf("\tbus : %d\n", p->bus);
dprintf("\tdevice : %d\n", p->device);
dprintf("\tfunction : %d\n", p->function);
dprintf("\trevision : %02x\n", p->revision);
dprintf("\tclass_api : %02x\n", p->class_api);
dprintf("\tclass_sub : %02x\n", p->class_sub);
#ifdef THE_FULL_MONTY
uint16 ss_vend, ss_dev;
#endif
dprintf("\tclass_base : %02x [%s]\n", p->class_base, decode_class_base(p->class_base));
uint8 irq = 0;
if (p->header_type == PCI_header_type_generic)
irq = p->u.h0.interrupt_line;
else
irq = p->u.h1.interrupt_line;
dprintf("0x%04x:0x%04x : ", p->vendor_id, p->device_id);
if (irq > 0)
dprintf("irq %d : ", irq);
dprintf("location %d:%d:%d : ", p->bus, p->device, p->function);
dprintf("class %02x:%02x:%02x", p->class_base, p->class_sub,
p->class_api);
dprintf(" => %s\n", decode_class(p->class_base, p->class_sub));
#if THE_FULL_MONTY
dprintf("\trevision : %02x\n", p->revision);
dprintf("\tstatus : %04x\n",
pcim->read_pci_config(p->bus, p->device, p->function, PCI_status, 2));
dprintf("\tcommand : %04x\n",
pcim->read_pci_config(p->bus, p->device, p->function, PCI_command, 2));
dprintf("\tbase address: %08lx\n",
dprintf("\tbase address: %08x\n",
pcim->read_pci_config(p->bus, p->device, p->function, PCI_base_registers, 4));
dprintf("\tline_size : %02x\n", p->line_size);
dprintf("\theader_type : %02x\n", p->header_type);
dprintf("\tbist : %02x\n", p->bist);
if (p->header_type == 0) {
dprintf("Header Type 0\n");
if (p->header_type == PCI_header_type_generic) {
dprintf("Header Type 0 (Generic)\n");
dprintf("\tcardbus_cis : %08lx\n", p->u.h0.cardbus_cis);
dprintf("\tsubsystem_id : %04x\n", p->u.h0.subsystem_id);
dprintf("\tsubsystem_vendor_id : %04x [%s]\n", p->u.h0.subsystem_vendor_id,
decode_vendor(p->u.h0.subsystem_vendor_id));
dprintf("\trom_base_pci : %08lx\n", p->u.h0.rom_base_pci);
dprintf("\tinterrupt_line : %02x\n", p->u.h0.interrupt_line);
dprintf("\tinterrupt_pin : %02x\n", p->u.h0.interrupt_pin);
} else if (p->header_type == 1) {
ss_vend = p->u.h0.subsystem_vendor_id;
ss_dev = p->u.h0.subsystem_id;
} else if (p->header_type == PCI_header_type_PCI_to_PCI_bridge) {
dprintf("Header Type 1 (PCI-PCI bridge)\n");
dprintf("\trom_base_pci : %08lx\n", p->u.h1.rom_base_pci);
dprintf("\tinterrupt_line : %02x\n", p->u.h1.interrupt_line);
dprintf("\tinterrupt_pin : %02x\n", p->u.h1.interrupt_pin);
dprintf("\t2ndry status : %04x\n", p->u.h1.secondary_status);
dprintf("\tmemory_base : %04x\n", p->u.h1.memory_base);
dprintf("\tprimary_bus : %d\n", p->u.h1.primary_bus);
dprintf("\tsecondary_bus : %d\n", p->u.h1.secondary_bus);
dprintf("\tbridge control : %02x\n", p->u.h1.bridge_control);
ss_vend = p->u.h1.subsystem_vendor_id;
ss_dev = p->u.h1.subsystem_id;
}
dprintf("\tsubsystem_id : %04x\n", ss_dev);
dprintf("\tsubsystem_vendor_id : %04x\n", ss_vend);
#endif
}
/* XXX - move these to a header file */
#define PCI_VENDOR_INTEL 0x8086
#define PCI_PRODUCT_INTEL_82371AB_ISA 0x7110 /* PIIX4 ISA */
#define PCI_PRODUCT_INTEL_82371AB_IDE 0x7111 /* PIIX4 IDE */
#define PCI_PRODUCT_INTEL_82371AB_USB 0x7112 /* PIIX4 USB */
#define PCI_PRODUCT_INTEL_82371AB_PMC 0x7113 /* PIIX4 Power Management */
#define PCI_PRODUCT_INTEL_82443BX 0x7190
#define PCI_PRODUCT_INTEL_82443BX_AGP 0x7191
#define PCI_PRODUCT_INTEL_82443BX_NOAGP 0x7192
/* Borrowed from NetBSD.
* Some Host bridges need to have fixes applied.
*/
static void fixup_host_bridge(uint8 bus, uint8 dev, uint8 func)
{
uint16 vendor, device;
vendor = pcim->read_pci_config(bus, dev, func, PCI_vendor_id, 2);
device = pcim->read_pci_config(bus, dev, func, PCI_device_id, 2);
switch (vendor) {
case PCI_VENDOR_INTEL:
switch (device) {
case PCI_PRODUCT_INTEL_82443BX_AGP:
case PCI_PRODUCT_INTEL_82443BX_NOAGP: {
/* BIOS bug workaround
* While the datasheet indicates that the only valid setting
* for "Idle/Pipeline DRAM Leadoff Timing (IPLDT)" is 01,
* some BIOS's do not set these correctly, so we check and
* correct if required.
*/
uint16 bcreg = pcim->read_pci_config(bus, dev, func, 0x76, 2);
if ((bcreg & 0x0300) != 0x0100) {
dprintf("Intel 82443BX Host Bridge: Fixing IPDLT setting\n");
bcreg &= ~0x0300;
bcreg |= 0x100;
pcim->write_pci_config(bus, dev, func, 0x76, 2, bcreg);
}
break;
}
}
}
}
/* Given a vendor/device pairing, do we need to scan through
* the entire set of funtions? normally the return will be 0,
* implying we don't need to, but for some it will be 1 which
* means scan all functions.
* This function may seem overkill but it prevents scanning
* functions we don't need to and shoudl reduce the possibility of
* duplicates being detected.
*/
static int pci_quirk_multifunction(uint16 vendor, uint16 device)
{
switch (vendor) {
case PCI_VENDOR_INTEL:
switch (device) {
case PCI_PRODUCT_INTEL_82371AB_ISA:
case PCI_PRODUCT_INTEL_82371AB_IDE:
case PCI_PRODUCT_INTEL_82371AB_USB:
case PCI_PRODUCT_INTEL_82371AB_PMC:
return 1;
}
}
return 0;
}
/* pci_bridge()
* The values passed in specify the "device" on the bus being searched
* that has been identified as a PCI-PCI bridge. We now setup that bridge
* and scan the bus it defines.
* The bus is initially taken off-line, scanned and then put back on-line
*/
static void pci_bridge(uint8 bus, uint8 dev, uint8 func)
{
uint16 command = 0;
uint8 mybus = bus + 1;
command = pcim->read_pci_config(bus, dev, func, PCI_command, 2);
command &= ~ 0x03;
pcim->write_pci_config(bus, dev, func, PCI_command, 2, command);
/* Bus is now off line */
pcim->write_pci_config(bus, dev, func, PCI_primary_bus, 1, bus);
pcim->write_pci_config(bus, dev, func, PCI_secondary_bus, 1, mybus);
pcim->write_pci_config(bus, dev, func, PCI_subordinate_bus, 1, 0xff);
dprintf("PCI-PCI bridge at %d:%d:%d configured as bus %d\n", bus, dev, func, mybus);
pci_scan_bus(mybus);
/* Not strictly correct, but close enough... */
command |= 0x03;
pcim->write_pci_config(bus, dev, func, PCI_command, 2, command);
}
static void pci_device_probe(uint8 bus, uint8 dev, uint8 func)
{
uint8 base_class, sub_class;
uint8 type;
if (func > 0) {
uint16 vend = pcim->read_pci_config(bus, dev, func, PCI_vendor_id, 2);
if (vend == 0xffff)
return;
}
type = pcim->read_pci_config(bus, dev, func, PCI_header_type, 1);
type &= PCI_header_type_mask;
base_class = pcim->read_pci_config(bus, dev, func, PCI_class_base, 1);
sub_class = pcim->read_pci_config(bus, dev, func, PCI_class_sub, 1);
if (base_class == PCI_bridge) {
if (sub_class == PCI_host)
fixup_host_bridge(bus, dev, func);
if (sub_class == PCI_pci) {
pci_bridge(bus, dev, func);
return;
}
}
dprintf("device at %d:%d:%d => %s\n", bus, dev, func,
decode_class(base_class, sub_class));
}
/* pci_bus()
* Scan a bus for PCI devices. For each device that's a possible
* we get the vendor_id. If it's 0xffff then it's not a valid
* device so we move on.
* Valid devices then have their header_type checked to detrmine how
* many functions we need to check. However, some devices that support
* multiple functions have a header_type of 0 (generic) so we also check
* for these using pci_quirk_multifunction().
* If it's a multifunction device we scan all 8 possible functions,
* otherwise we just probe the first one.
*/
static void pci_scan_bus(uint8 bus)
{
uint8 dev = 0, func = 0;
uint16 vend = 0;
for (dev = 0; dev < 32; dev++) {
vend = pcim->read_pci_config(bus, dev, 0, PCI_vendor_id, 2);
if (vend != 0xffff) {
uint16 device = pcim->read_pci_config(bus, dev, func, PCI_device_id, 2);
uint8 type = pcim->read_pci_config(bus, dev, func, PCI_header_type, 1);
uint8 nfunc = 8;
type &= PCI_header_type_mask;
if ((type & PCI_multifunction) == 0 &&
!pci_quirk_multifunction(vend, device))
nfunc = 1;
for (func = 0; func < nfunc; func++)
pci_device_probe(bus, dev, func);
}
}
}
static status_t test_me(void)
{
pci_module_info *pcim;
pci_info apci;
long index = 0;
if (get_module(B_PCI_MODULE_NAME, (module_info**)&pcim) != 0) {
dprintf("config_manager: test_me: failed to load PCI module\n");
return -1;
}
while (pcim->get_nth_pci_info(index++, &apci) == 0) {
show_pci_details(&apci, pcim);
}
put_module(B_PCI_MODULE_NAME);
return 0;
}
@ -164,6 +379,11 @@ static int cfdm_std_ops(int32 op, ...)
switch(op) {
case B_MODULE_INIT:
dprintf( "config_manager: device modules: init\n" );
if (get_module(B_PCI_MODULE_NAME, (module_info**)&pcim) != 0) {
dprintf("config_manager: failed to load PCI module\n");
return -1;
}
pci_scan_bus(0);
test_me();
break;
case B_MODULE_UNINIT:

View File

@ -74,59 +74,105 @@ struct pci_config *pci_list;
#define CONFIG_REQ_PORT 0xCF8
#define CONFIG_DATA_PORT 0xCFC
#define CONFIG_REQ(bus, device, func, offs) (0x80000000 | (bus << 16) | \
(((device << 3) | (func & 0x07)) << 8) | \
(offs & ~3))
static uint32 read_pci_config(uchar bus, uchar device, uchar function, uchar offset, uchar size)
#define CONFIG_ADDR_1(bus, device, func, reg) \
(0x80000000 | (bus << 16) | (device << 11) | (func << 8) | (reg & ~3))
#define CONFIG_ADDR_2(dev, reg) \
(uint16)(0xC00 | (dev << 8) | reg)
static uint32 read_pci_config(uchar bus, uchar device, uchar function, uchar reg, uchar size)
{
if (pci_mode == 1) {
/* write request details */
out32(CONFIG_REQ(bus, device, function, offset), 0xCF8);
out32(CONFIG_ADDR_1(bus, device, function, reg), CONFIG_REQ_PORT);
/* Now read data back from the data port...
* offset for 1 byte can be 1,2 or 3
* offset for 2 bytes can be 1 or 2
*/
switch (size) {
case 1:
return in8 (CONFIG_DATA_PORT + (offset & 3));
return in8 (CONFIG_DATA_PORT + (reg & 3));
case 2:
return in16(CONFIG_DATA_PORT + (offset & 2));
return in16(CONFIG_DATA_PORT + (reg & 2));
case 4:
return in32(CONFIG_DATA_PORT + offset);
return in32(CONFIG_DATA_PORT + reg);
default:
dprintf("read_pci_config: called for %d bytes!!\n", size);
dprintf("ERROR: read_pci_config: called for %d bytes!!\n", size);
}
} else if (pci_mode == 2) {
dprintf("PCI: Config Mechanism 2 not yet supported!\n");
uint32 rv = 0;
if (device & 0x10)
return EINVAL;
out8((uint8)(0xF0 | (function << 1)), 0xCF8);
out8(bus, 0xCFA);
switch (size) {
case 1:
rv = in8 (CONFIG_ADDR_2(device, reg));
break;
case 2:
rv = in16(CONFIG_ADDR_2(device, reg));
break;
case 4:
rv = in32(CONFIG_ADDR_2(device, reg));
break;
default:
dprintf("ERROR: read_pci_config: called for %d bytes!!\n", size);
}
out8(0, 0xCF8);
return rv;
} else
dprintf("PCI: Config Mechanism %d isn't known!\n", pci_mode);
return 0;
}
static void write_pci_config(uchar bus, uchar device, uchar function, uchar offset,
uchar size, uint32 value)
static void write_pci_config(uchar bus, uchar device, uchar function, uchar reg,
uchar size, uint32 value)
{
if (pci_mode == 1) {
/* write request details */
out32(CONFIG_REQ(bus, device, function, offset), 0xCF8);
out32(CONFIG_ADDR_1(bus, device, function, reg), CONFIG_REQ_PORT);
/* Now read data back from the data port...
* offset for 1 byte can be 1,2 or 3
* offset for 2 bytes can be 1 or 2
*/
switch (size) {
case 1:
out8 (value, CONFIG_DATA_PORT + (offset & 3));
out8 (value, CONFIG_DATA_PORT + (reg & 3));
break;
case 2:
out16(value, CONFIG_DATA_PORT + (offset & 2));
out16(value, CONFIG_DATA_PORT + (reg & 2));
break;
case 4:
out32(value, CONFIG_DATA_PORT + offset);
out32(value, CONFIG_DATA_PORT + reg);
break;
default:
dprintf("read_pci_config: called for %d bytes!!\n", size);
dprintf("ERROR: write_pci_config: called for %d bytes!!\n", size);
}
} else if (pci_mode == 2) {
dprintf("PCI: Config Mechanism 2 not yet supported\n");
if (device & 0x10)
return;
out8((uint8)(0xF0 | (function << 1)), 0xCF8);
out8(bus, 0xCFA);
switch (size) {
case 1:
out8 (value, CONFIG_ADDR_2(device, reg));
break;
case 2:
out16(value, CONFIG_ADDR_2(device, reg));
break;
case 4:
out32(value, CONFIG_ADDR_2(device, reg));
break;
default:
dprintf("ERROR: write_pci_config: called for %d bytes!!\n", size);
}
out8(0, 0xCF8);
} else
dprintf("PCI: Config Mechanism %d isn't known!\n", pci_mode);
@ -221,7 +267,6 @@ static int check_pci(void)
return -1;
}
static void scan_pci(void)
{
int bus, dev, func;
@ -238,7 +283,6 @@ static void scan_pci(void)
struct found_pci_device *npcid = NULL;
uint16 vendor_id = read_pci_config(bus, dev, func, 0, 2);
uint16 device_id;
uint8 int_line = 0, int_pin = 0;
/* If we get 0xffff then there is no device here. As there can't
* be any gaps in function allocation this tells us that we
* can move onto the next device/bus
@ -276,61 +320,76 @@ static void scan_pci(void)
}
/* basic header */
pcii->vendor_id = vendor_id;
pcii->device_id = device_id;
pcii->bus = bus;
pcii->device = dev;
pcii->function = func;
pcii->vendor_id = vendor_id;
pcii->device_id = device_id;
pcii->revision = read_pci_config(bus, dev, func, PCI_revision, 1);
pcii->class_api = read_pci_config(bus, dev, func, PCI_class_api, 1);
pcii->class_sub = read_pci_config(bus, dev, func, PCI_class_sub, 1);
pcii->class_base = read_pci_config(bus, dev, func, PCI_class_base, 1);
pcii->line_size = read_pci_config(bus, dev, func, PCI_line_size, 1);
pcii->latency = read_pci_config(bus, dev, func, PCI_latency, 1);
pcii->header_type = read_pci_config(bus, dev, func, PCI_header_type, 1);
pcii->bist = read_pci_config(bus, dev, func, PCI_bist, 1);
int_line = read_pci_config(bus, dev, func, PCI_interrupt_line, 1);
int_pin = read_pci_config(bus, dev, func, PCI_interrupt_pin, 1);
/* device type specific headers based on header_type declared */
if (pcii->header_type == 0) {
/* header type 0 */
pcii->u.h0.cardbus_cis = read_pci_config(bus, dev, func, PCI_cardbus_cis, 4);
pcii->u.h0.subsystem_id = read_pci_config(bus, dev, func, PCI_subsystem_id, 2);
pcii->u.h0.subsystem_vendor_id = read_pci_config(bus, dev, func, PCI_subsystem_vendor_id, 2);
pcii->u.h0.rom_base_pci = read_pci_config(bus, dev, func, PCI_rom_base, 4);
pcii->u.h0.interrupt_line = int_line;
pcii->u.h0.interrupt_pin = int_pin;
} else if (pcii->header_type == 1) {
/* header_type 1 */
/* PCI-PCI bridge - may be used for AGP */
pcii->u.h1.rom_base_pci = read_pci_config(bus, dev, func, PCI_bridge_rom_base, 4);
pcii->u.h1.primary_bus = read_pci_config(bus, dev, func, PCI_primary_bus, 1);
pcii->u.h1.secondary_bus = read_pci_config(bus, dev, func, PCI_secondary_bus, 1);
pcii->u.h1.secondary_latency = read_pci_config(bus, dev, func, PCI_secondary_latency, 1);
pcii->u.h1.secondary_status = read_pci_config(bus, dev, func, PCI_secondary_status, 2);
pcii->u.h1.subordinate_bus = read_pci_config(bus, dev, func, PCI_subordinate_bus, 1);
pcii->u.h1.io_base = read_pci_config(bus, dev, func, PCI_io_base, 1);
pcii->u.h1.io_limit = read_pci_config(bus, dev, func, PCI_io_limit, 1);
pcii->u.h1.memory_base = read_pci_config(bus, dev, func, PCI_memory_base, 2);
pcii->u.h1.memory_limit = read_pci_config(bus, dev, func, PCI_memory_limit, 2);
pcii->u.h1.prefetchable_memory_base = read_pci_config(bus, dev, func, PCI_prefetchable_memory_base, 2);
pcii->u.h1.prefetchable_memory_limit = read_pci_config(bus, dev, func, PCI_prefetchable_memory_limit, 2);
pcii->u.h1.bridge_control = read_pci_config(bus, dev, func, PCI_bridge_control, 1);
pcii->u.h1.interrupt_line = int_line;
pcii->u.h1.interrupt_pin = int_pin;
} else if (pcii->header_type == 0x80) {
/* ??? */
}
pcii->header_type = read_pci_config(bus, dev, func, PCI_header_type, 1);
pcii->header_type &= PCI_header_type_mask;
npcid->info = pcii;
/* Add the device to the list */
insque(npcid, &pci_dev_list);
}
/* next device */
}
/* next bus */
}
}
static void fill_pci_structure(pci_info *pcii)
{
uint8 bus = pcii->bus, dev = pcii->device, func = pcii->function;
uint8 int_line = 0, int_pin = 0;
pcii->latency = read_pci_config(bus, dev, func, PCI_latency, 1);
pcii->bist = read_pci_config(bus, dev, func, PCI_bist, 1);
pcii->line_size = read_pci_config(bus, dev, func, PCI_line_size, 1);
int_line = read_pci_config(bus, dev, func, PCI_interrupt_line, 1);
int_pin = read_pci_config(bus, dev, func, PCI_interrupt_pin, 1);
int_pin &= PCI_pin_mask;
/* device type specific headers based on header_type declared */
if (pcii->header_type == PCI_header_type_generic) {
/* header type 0 */
pcii->u.h0.cardbus_cis = read_pci_config(bus, dev, func, PCI_cardbus_cis, 4);
pcii->u.h0.subsystem_id = read_pci_config(bus, dev, func, PCI_subsystem_id, 2);
pcii->u.h0.subsystem_vendor_id = read_pci_config(bus, dev, func, PCI_subsystem_vendor_id, 2);
pcii->u.h0.rom_base_pci = read_pci_config(bus, dev, func, PCI_rom_base, 4);
pcii->u.h0.interrupt_line = int_line;
pcii->u.h0.interrupt_pin = int_pin;
} else if (pcii->header_type == PCI_header_type_PCI_to_PCI_bridge) {
/* header_type 1 */
/* PCI-PCI bridge - may be used for AGP */
pcii->u.h1.rom_base_pci = read_pci_config(bus, dev, func, PCI_bridge_rom_base, 4);
pcii->u.h1.primary_bus = read_pci_config(bus, dev, func, PCI_primary_bus, 1);
pcii->u.h1.secondary_bus = read_pci_config(bus, dev, func, PCI_secondary_bus, 1);
pcii->u.h1.secondary_latency = read_pci_config(bus, dev, func, PCI_secondary_latency, 1);
pcii->u.h1.secondary_status = read_pci_config(bus, dev, func, PCI_secondary_status, 2);
pcii->u.h1.subordinate_bus = read_pci_config(bus, dev, func, PCI_subordinate_bus, 1);
pcii->u.h1.memory_base = read_pci_config(bus, dev, func, PCI_memory_base, 2);
pcii->u.h1.memory_limit = read_pci_config(bus, dev, func, PCI_memory_limit, 2);
pcii->u.h1.prefetchable_memory_base = read_pci_config(bus, dev, func, PCI_prefetchable_memory_base, 2);
pcii->u.h1.prefetchable_memory_limit = read_pci_config(bus, dev, func, PCI_prefetchable_memory_limit, 2);
pcii->u.h1.bridge_control = read_pci_config(bus, dev, func, PCI_bridge_control, 1);
pcii->u.h1.subsystem_vendor_id = read_pci_config(bus, dev, func, PCI_sub_vendor_id_1, 2);
pcii->u.h1.subsystem_id = read_pci_config(bus, dev, func, PCI_sub_device_id_1, 2);
pcii->u.h1.interrupt_line = int_line;
pcii->u.h1.interrupt_pin = int_pin;
} else if (pcii->header_type == PCI_header_type_cardbus) {
pcii->u.h2.subsystem_vendor_id = read_pci_config(bus, dev, func, PCI_sub_vendor_id_2, 2);
pcii->u.h2.subsystem_id = read_pci_config(bus, dev, func, PCI_sub_device_id_2, 2);
}else if (pcii->header_type == PCI_multifunction) {
dprintf("PCI: multifunction device detected\n");
/* ??? */
}
}
@ -367,6 +426,8 @@ static long get_nth_pci_info(long index, pci_info *copyto)
*/
if (iter > 0 || !fpd->info)
return B_DEV_ID_ERROR;
fill_pci_structure(fpd->info);
memcpy(copyto, fpd->info, sizeof(pci_info));
return 0;