Big change to the way that PCI works.
- make pci into a true module now. - the pci module builds and keeps a linked list of devices it finds, with a filled in pci_info structure - pci module detects (at runtime) whcih config mech to use, though to date only mech 1 is implemented - pci module does sanity check and warns if it fails - config manager loads pci module and calls get_nth_pci_info to iterate through the list printing details - pci is no longer called directly from the bus init function there is still lots to do and I've tried to make sure that there are plenty of comments in the pci.c file. I've also left the previous code in place until we move on a little further when it will be removed. This has been working with no problems on my system and doesn't change any functionality as we don't have any devices that need PCI in our build yet. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@319 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -13,17 +13,15 @@ KernelLd
|
||||
-Bdynamic -shared
|
||||
:
|
||||
:
|
||||
addons/kernel/bus_managers/config_manager
|
||||
addons/kernel/config_manager
|
||||
;
|
||||
|
||||
KernelStaticLibrary libbus :
|
||||
<$(SOURCE_GRIST)>bus_init.c
|
||||
<$(SOURCE_GRIST)>bus_man.c
|
||||
|
||||
<$(SOURCE_GRIST)>pci/pci.c
|
||||
<$(SOURCE_GRIST)>pci/pci_bus.c
|
||||
:
|
||||
-fno-pic
|
||||
-fno-pic -D_KERNEL_MODE
|
||||
;
|
||||
|
||||
SubInclude OBOS_TOP src kernel core addons bus_managers isa ;
|
||||
SubInclude OBOS_TOP src kernel core addons bus_managers pci ;
|
||||
|
||||
@@ -6,18 +6,18 @@
|
||||
#include <memheap.h>
|
||||
#include <debug.h>
|
||||
#include <bus.h>
|
||||
|
||||
#ifdef ARCH_x86
|
||||
#include <pci_bus.h>
|
||||
#endif
|
||||
#include <config_manager.h>
|
||||
|
||||
int bus_init(kernel_args *ka)
|
||||
{
|
||||
struct config_manager_for_driver_module_info *cfm;
|
||||
|
||||
bus_man_init(ka);
|
||||
|
||||
#ifdef ARCH_x86
|
||||
pci_bus_init(ka);
|
||||
#endif
|
||||
if (get_module(B_CONFIG_MANAGER_FOR_DRIVER_MODULE_NAME,
|
||||
(module_info**)&cfm) == 0) {
|
||||
dprintf("bus_init: loaded the config_manager\n");
|
||||
}
|
||||
|
||||
#if 0
|
||||
{
|
||||
|
||||
@@ -9,14 +9,138 @@
|
||||
#include <ISA.h>
|
||||
#include <bus_manager.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
#include <string.h>
|
||||
|
||||
#define B_CONFIG_MANAGER_FOR_BUS_MODULE_NAME "bus_managers/config_manager/driver/v1"
|
||||
/* 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
|
||||
* information is only useful if you're working on this code.
|
||||
*/
|
||||
#define THE_FULL_MONTY 0
|
||||
|
||||
static status_t get_next_device_info(bus_type bus, uint64 *cookie,
|
||||
#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,
|
||||
struct device_info *info, uint32 len)
|
||||
{
|
||||
dprintf("get_next_device_info(bus = %d, cookie = %lld)\n",
|
||||
bus, *cookie);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *decode_class_base(uint8 base)
|
||||
{
|
||||
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 0x05: return "memory controller";
|
||||
case 0x06: return "bridge controller";
|
||||
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 0x0d: return "wireless";
|
||||
case 0x0e: return "intelligent i/o ??";
|
||||
case 0x0f: return "satellite";
|
||||
case 0x10: return "encryption";
|
||||
case 0x11: return "signal processing";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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);
|
||||
#endif
|
||||
|
||||
dprintf("\tclass_base : %02x [%s]\n", p->class_base, decode_class_base(p->class_base));
|
||||
|
||||
#if THE_FULL_MONTY
|
||||
dprintf("\tline_size : %02x\n", p->line_size);
|
||||
dprintf("\theader_type : %02x\n", p->header_type);
|
||||
|
||||
if (p->header_type == 0) {
|
||||
dprintf("Header Type 0\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);
|
||||
} else if (p->header_type == 1) {
|
||||
dprintf("Header Type 1 (PCI-PCI bridge)\n");
|
||||
dprintf("\trom_base_pci : %08lx\n", p->u.h1.rom_base_pci);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
put_module(B_PCI_MODULE_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* device_modules */
|
||||
@@ -25,6 +149,7 @@ static int cfdm_std_ops(int32 op, ...)
|
||||
switch(op) {
|
||||
case B_MODULE_INIT:
|
||||
dprintf( "config_manager: device modules: init\n" );
|
||||
test_me();
|
||||
break;
|
||||
case B_MODULE_UNINIT:
|
||||
dprintf( "config_manager: device modules: uninit\n" );
|
||||
@@ -55,11 +180,11 @@ static int cfbm_std_ops(int32 op, ...)
|
||||
struct config_manager_for_driver_module_info cfdm = {
|
||||
{
|
||||
B_CONFIG_MANAGER_FOR_DRIVER_MODULE_NAME,
|
||||
0,
|
||||
B_KEEP_LOADED,
|
||||
cfdm_std_ops
|
||||
},
|
||||
|
||||
NULL, /* get_next_device_info */
|
||||
&cfdm_get_next_device_info, /* get_next_device_info */
|
||||
NULL, /* get_device_info_for */
|
||||
NULL, /* get_size_of_current_configuration_for */
|
||||
NULL, /* get_current_configuration_for */
|
||||
@@ -74,7 +199,7 @@ struct config_manager_for_driver_module_info cfdm = {
|
||||
struct config_manager_for_driver_module_info cfbm = {
|
||||
{
|
||||
B_CONFIG_MANAGER_FOR_BUS_MODULE_NAME,
|
||||
0,
|
||||
B_KEEP_LOADED,
|
||||
cfbm_std_ops
|
||||
},
|
||||
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
SubDir OBOS_TOP src kernel core addons bus_managers isa ;
|
||||
|
||||
KernelObjects isa.c : -fno-pic ;
|
||||
KernelObjects isa.c : -fno-pic -D_KERNEL_MODE ;
|
||||
|
||||
KernelLd isa
|
||||
:
|
||||
<$(SOURCE_GRIST)>isa.o
|
||||
kernel.so
|
||||
:
|
||||
$(OBOS_TOP)/src/kernel/core/addons/ldscripts/$(OBOS_ARCH)/addon.ld
|
||||
:
|
||||
-Bdynamic -shared
|
||||
:
|
||||
:
|
||||
addons/kernel/isa
|
||||
;
|
||||
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
SubDir OBOS_TOP src kernel core addons bus_managers pci ;
|
||||
|
||||
KernelStaticLibrary libbuspci : pci.c pci_bus.c ;
|
||||
|
||||
KernelLd
|
||||
pci
|
||||
:
|
||||
<$(SOURCE_GRIST)>pci.o
|
||||
<$(SOURCE_GRIST)>pci_bus.o
|
||||
kernel.so
|
||||
:
|
||||
$(OBOS_TOP)/src/kernel/core/addons/ldscripts/$(OBOS_ARCH)/addon.ld
|
||||
:
|
||||
-Bdynamic -shared
|
||||
:
|
||||
:
|
||||
addons/kernel/pci
|
||||
;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <vm.h>
|
||||
#include <devfs.h>
|
||||
#include <khash.h>
|
||||
#include <errno.h>
|
||||
#include <Errors.h>
|
||||
|
||||
#include <arch/cpu.h>
|
||||
#include <arch/int.h>
|
||||
@@ -25,17 +25,343 @@
|
||||
|
||||
#include "pci_p.h" // private includes
|
||||
|
||||
struct found_pci_device {
|
||||
struct found_pci_device *next;
|
||||
struct found_pci_device *prev;
|
||||
pci_info *info;
|
||||
};
|
||||
|
||||
static struct found_pci_device pci_dev_list;
|
||||
|
||||
struct pci_config {
|
||||
struct pci_config *next;
|
||||
char *full_path;
|
||||
struct pci_cfg *cfg;
|
||||
};
|
||||
|
||||
/* The pci_mode we're using, defaults to 1 as this is more common */
|
||||
static int pci_mode = 1;
|
||||
|
||||
/* If we have configuration mechanism one we have devices 0 - 32 per bus, if
|
||||
* we only have configuration mechanism two we have devices 0 - 16
|
||||
* XXX - set this when we determine which configuration mechanism we have
|
||||
*/
|
||||
static int bus_max_devices = 32;
|
||||
|
||||
struct pci_config *pci_list;
|
||||
|
||||
/* PCI has 2 Configuration Mechanisms. We need to decide which one the
|
||||
* PCI Host Bridge is speaking and then speak to it correctly. This is decided
|
||||
* in set_pci_mechanism() where the pci_mode value is set to the appropriate
|
||||
* value and the bus_max_devices value is set correctly.
|
||||
*
|
||||
* Mechanism 1
|
||||
* ===========
|
||||
* Mechanism 1 is the more common one found on modern computers, so presently
|
||||
* that's the one that has been tested and added.
|
||||
*
|
||||
* This has 2 ranges, one for addressing and for data. Basically we write in the details of
|
||||
* the configuration information we want (bus, device and function) and then either
|
||||
* read or write from the data port.
|
||||
*
|
||||
* Apparently most modern hardware no longer has Configuration Type #2.
|
||||
*
|
||||
* XXX - add code for Mechanism Two
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#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)
|
||||
{
|
||||
if (pci_mode == 1) {
|
||||
/* write request details */
|
||||
out32(CONFIG_REQ(bus, device, function, offset), 0xCF8);
|
||||
/* 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));
|
||||
case 2:
|
||||
return in16(CONFIG_DATA_PORT + (offset & 2));
|
||||
case 4:
|
||||
return in32(CONFIG_DATA_PORT + offset);
|
||||
default:
|
||||
dprintf("read_pci_config: called for %d bytes!!\n", size);
|
||||
}
|
||||
} else if (pci_mode == 2) {
|
||||
dprintf("PCI: Config Mechanism 2 not yet supported!\n");
|
||||
} 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)
|
||||
{
|
||||
if (pci_mode == 1) {
|
||||
/* write request details */
|
||||
out32(CONFIG_REQ(bus, device, function, offset), 0xCF8);
|
||||
/* 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));
|
||||
case 2:
|
||||
out16(value, CONFIG_DATA_PORT + (offset & 2));
|
||||
case 4:
|
||||
out32(value, CONFIG_DATA_PORT + offset);
|
||||
default:
|
||||
dprintf("read_pci_config: called for %d bytes!!\n", size);
|
||||
}
|
||||
} else if (pci_mode == 2) {
|
||||
dprintf("PCI: Config Mechanism 2 not yet supported\n");
|
||||
} else
|
||||
dprintf("PCI: Config Mechanism %d isn't known!\n", pci_mode);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* set_pci_mechanism()
|
||||
* Try to determine which configuration mechanism the PCI Host Bridge
|
||||
* wants to deal with.
|
||||
* XXX - we really should add code to detect and use a PCI BIOS if one
|
||||
* exists, and this code then becomes the fallback. For now we'll
|
||||
* just use this.
|
||||
*/
|
||||
static int set_pci_mechanism(void)
|
||||
{
|
||||
uint32 ckval = 0x80000000;
|
||||
/* Start by looking for the older and more limited mechanism 2
|
||||
* as the test will probably work for mechanism 1 as well.
|
||||
*
|
||||
* This code copied/adapted from OpenBSD
|
||||
*/
|
||||
#define PCI_MODE2_ENABLE 0x0cf8
|
||||
#define PCI_MODE2_FORWARD 0x0cfa
|
||||
out8(0, PCI_MODE2_ENABLE);
|
||||
out8(0, PCI_MODE2_FORWARD);
|
||||
if (in8(PCI_MODE2_ENABLE) == 0 &&
|
||||
in8(PCI_MODE2_FORWARD) == 0) {
|
||||
dprintf("PCI_Mechanism 2 test passed\n");
|
||||
bus_max_devices = 16;
|
||||
pci_mode = 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we get here, the first test (for mechanism 2) failed, so there
|
||||
* is a good chance this one will pass. Basically enable then disable and
|
||||
* make sure we have the same values.
|
||||
*/
|
||||
#define PCI_MODE1_ADDRESS 0x0cf8
|
||||
out32(ckval, PCI_MODE1_ADDRESS);
|
||||
if (in32(PCI_MODE1_ADDRESS) == ckval) {
|
||||
out32(0, PCI_MODE1_ADDRESS);
|
||||
if (in32(PCI_MODE1_ADDRESS) == 0) {
|
||||
dprintf("PCI_Mechanism 1 test passed\n");
|
||||
bus_max_devices = 32;
|
||||
pci_mode = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("PCI: Failed to find a valid PCI Configuration Mechanism!\n"
|
||||
"PCI: disabled\n");
|
||||
pci_mode = 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check_pci()
|
||||
* Basically PCI bus #0 "should" contain a PCI Host Bridge.
|
||||
* This can be identified by the 8 bit pci class base of 0x06.
|
||||
*
|
||||
* XXX - this is pretty simplistic and needs improvement. In particular
|
||||
* some Intel & Compaq bridges don't have the correct class base set.
|
||||
* Need to review these. For the time being if this sanity check
|
||||
* fails it won't be a hanging offense, but it will generate a
|
||||
* message asking for the info to be sent to the kernel list so we
|
||||
* can refine this code. :) Assuming anyone ever looks at the
|
||||
* debug output!
|
||||
*
|
||||
* returns 0 if PCI seems to be OK
|
||||
* -1 if PCI fails the test
|
||||
*/
|
||||
static int check_pci(void)
|
||||
{
|
||||
int dev = 0;
|
||||
|
||||
/* Scan through the first 16 devices on bus 0 looking for
|
||||
* a PCI Host Bridge
|
||||
*/
|
||||
for (dev = 0; dev < bus_max_devices; dev++) {
|
||||
uint8 val = read_pci_config(0, dev, 0, PCI_class_base, 1);
|
||||
if (val == 0x06)
|
||||
return 0;
|
||||
}
|
||||
/* Bit wordy, but it needs to be :( */
|
||||
dprintf("*** PCI Warning! ***\n"
|
||||
"The PCI sanity check appears to have failed on your system.\n"
|
||||
"This is probably due to the test being used, so please email\n"
|
||||
"\t[email protected]\n"
|
||||
"Your assistance will help improve this test :)\n"
|
||||
"***\n"
|
||||
"PCI will attempt to continue normally.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void scan_pci(void)
|
||||
{
|
||||
int bus, dev, func;
|
||||
|
||||
/* We can have up to 255 busses */
|
||||
for(bus = 0; bus < 255; bus++) {
|
||||
/* Each bus can have up to 32 devices on it */
|
||||
for(dev = 0; dev < bus_max_devices; dev++) {
|
||||
/* Each device can have up to 8 functions */
|
||||
for (func = 0; func < 8; func++) {
|
||||
pci_info *pcii = NULL;
|
||||
struct found_pci_device *npcid = NULL;
|
||||
uint16 val = read_pci_config(bus, dev, func, 0, 2);
|
||||
/* If we get 0xffff then there is noe device here. As there can't
|
||||
* be any gaps in function allocation this tells us that we
|
||||
* can move onto the next device/bus
|
||||
*/
|
||||
if (val == 0xffff)
|
||||
break;
|
||||
|
||||
/* At present we will add a device to our list if we get here,
|
||||
* but we may want to review if we need to add 8 version of the
|
||||
* same device if only the functions differ?
|
||||
*/
|
||||
if ((pcii = (pci_info*)kmalloc(sizeof(pci_info))) == NULL) {
|
||||
dprintf("Failed to get memory for a pic_info structure in scan_pci\n");
|
||||
return;
|
||||
}
|
||||
if ((npcid = (struct found_pci_device*)kmalloc(sizeof(struct found_pci_device))) == NULL) {
|
||||
kfree(pcii);
|
||||
dprintf("scan_pci: failed to kmalloc memory for found_pci_device structure\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pcii->vendor_id = val;
|
||||
pcii->device_id = read_pci_config(bus, dev, func, PCI_device_id, 2);
|
||||
pcii->bus = bus;
|
||||
pcii->device = dev;
|
||||
pcii->function = func;
|
||||
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);
|
||||
|
||||
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);
|
||||
} else if (pcii->header_type == 1) {
|
||||
/* header_type 1 */
|
||||
/* bridge */
|
||||
pcii->u.h1.rom_base_pci = read_pci_config(bus, dev, func, PCI_bridge_rom_base, 4);
|
||||
} else if (pcii->header_type == 0x80) {
|
||||
/* ??? */
|
||||
}
|
||||
|
||||
npcid->info = pcii;
|
||||
/* Add the device to the list */
|
||||
insque(npcid, &pci_dev_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX - check the return values from this function. */
|
||||
static long get_nth_pci_info(long index, pci_info *copyto)
|
||||
{
|
||||
/* We copy the index and then decrement it.
|
||||
* We also set the start found_pci_device pointer to
|
||||
* the first device found and inserted.
|
||||
* XXX - see discussion below.
|
||||
*/
|
||||
long iter = index;
|
||||
struct found_pci_device *fpd = pci_dev_list.prev;
|
||||
|
||||
/* iterate through the list until we have iter == 0
|
||||
* NB we go in "reverse" as the devices are inserted into the
|
||||
* list at the start, so going "forward" would give us the last
|
||||
* device first.
|
||||
* XXX - do we want to reverse this decision and go "forwards"?
|
||||
* this should reduce the number of tries we make to find
|
||||
* a "device" as the system devices are the first ones found
|
||||
* and therefore the last ones to be returned.
|
||||
* XXX - if we do decide to reverse the order we need to be very
|
||||
* careful about which function # gets found first and returned.
|
||||
*/
|
||||
while (iter-- > 0 && fpd && fpd != &pci_dev_list)
|
||||
fpd = fpd->prev;
|
||||
|
||||
/* 2 cases we bail here.
|
||||
* 1) we don't have enough devices to fulfill the request
|
||||
* e.g. user asked for dev #31 but we only have 30
|
||||
* 2) The found_device_structure has a NULL pointer for
|
||||
* info, which would cause a segfault when we try to memcpy!
|
||||
*/
|
||||
if (iter > 0 || !fpd->info)
|
||||
return B_DEV_ID_ERROR;
|
||||
|
||||
memcpy(copyto, fpd->info, sizeof(pci_info));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* I/O routines */
|
||||
static uint8 pci_read_io_8(int mapped_io_addr)
|
||||
{
|
||||
return in8(mapped_io_addr);
|
||||
}
|
||||
|
||||
static void pci_write_io_8(int mapped_io_addr, uint8 value)
|
||||
{
|
||||
out8(value, mapped_io_addr);
|
||||
}
|
||||
|
||||
static uint16 pci_read_io_16(int mapped_io_addr)
|
||||
{
|
||||
return in16(mapped_io_addr);
|
||||
}
|
||||
|
||||
static void pci_write_io_16(int mapped_io_addr, uint16 value)
|
||||
{
|
||||
out16(value, mapped_io_addr);
|
||||
}
|
||||
|
||||
static uint32 pci_read_io_32(int mapped_io_addr )
|
||||
{
|
||||
return in32(mapped_io_addr);
|
||||
}
|
||||
|
||||
static void pci_write_io_32(int mapped_io_addr, uint32 value)
|
||||
{
|
||||
out32(value, mapped_io_addr);
|
||||
}
|
||||
|
||||
static int pci_open(const char *name, uint32 flags, void * *_cookie)
|
||||
{
|
||||
// struct pci_cookie *cookie;
|
||||
struct pci_config *c = (struct pci_config *)kmalloc(sizeof(struct pci_config));
|
||||
|
||||
/* name points at the devfs_vnode so this is safe as we have to have a shorter
|
||||
@@ -185,11 +511,33 @@ int pci_bus_init(kernel_args *ka)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pci_module_init(void)
|
||||
{
|
||||
/* init the double linked list */
|
||||
pci_dev_list.next = pci_dev_list.prev = &pci_dev_list;
|
||||
|
||||
/* Determine how we communicate with the PCI Host Bridge */
|
||||
if (set_pci_mechanism() == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check PCI is valid and we can use it.
|
||||
* Presently we don't do anything with this other than run it and
|
||||
* inform the user if we pass/fail. If we fail we print a big message
|
||||
* asking the user to get in touch to let us know about their system so
|
||||
* we can refine the test.
|
||||
*/
|
||||
check_pci();
|
||||
/* Get our initial list of devices */
|
||||
scan_pci();
|
||||
}
|
||||
|
||||
static int std_ops(int32 op, ...)
|
||||
{
|
||||
switch(op) {
|
||||
case B_MODULE_INIT:
|
||||
dprintf( "PCI: init\n" );
|
||||
pci_module_init();
|
||||
break;
|
||||
case B_MODULE_UNINIT:
|
||||
dprintf( "PCI: uninit\n" );
|
||||
@@ -210,14 +558,20 @@ struct pci_module_info pci_module = {
|
||||
NULL// &pci_rescan
|
||||
},
|
||||
|
||||
NULL,// &read_io_8,
|
||||
NULL,// &write_io_8,
|
||||
NULL,// &read_io_16,
|
||||
NULL,// &write_io_16,
|
||||
NULL,// &read_io_32,
|
||||
NULL,// &write_io_32,
|
||||
NULL,// &get_nth_pci_info,
|
||||
NULL,// &read_pci_config,
|
||||
NULL,// &write_pci_config,
|
||||
&pci_read_io_8,
|
||||
&pci_write_io_8,
|
||||
&pci_read_io_16,
|
||||
&pci_write_io_16,
|
||||
&pci_read_io_32,
|
||||
&pci_write_io_32,
|
||||
&get_nth_pci_info,
|
||||
&read_pci_config,
|
||||
&write_pci_config,
|
||||
NULL,// &ram_address
|
||||
};
|
||||
|
||||
module_info *modules[] = {
|
||||
(module_info *)&pci_module,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user