/*
* Copyright 2007, Hugo Santos. All Rights Reserved.
* Copyright 2007, Axel Dörfler, axeld@pinc-software.de. All Rights Reserved.
* Copyright 2004, Marcus Overhagen. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
/*! Driver functions that adapt the FreeBSD driver to Haiku's driver API.
The actual driver functions are exported by the HAIKU_FBSD_DRIVER_GLUE
macro, and just call the functions here.
*/
#include "device.h"
#include "sysinit.h"
#include <stdlib.h>
#include <sys/sockio.h>
#include <Drivers.h>
#include <ether_driver.h>
#include <PCI_x86.h>
#include <compat/sys/haiku-module.h>
#include <compat/sys/bus.h>
#include <compat/sys/mbuf.h>
#include <compat/net/ethernet.h>
//#define TRACE_DRIVER
#ifdef TRACE_DRIVER
# define TRACE(x) dprintf x
#else
# define TRACE(x)
#endif
static struct {
driver_t* driver;
pci_info info;
} sProbedDevices[MAX_DEVICES];
const char* gDeviceNameList[MAX_DEVICES + 1];
struct ifnet* gDevices[MAX_DEVICES];
int32 gDeviceCount;
static status_t
init_root_device(device_t *_root)
{
static driver_t sRootDriver = {
"pci",
NULL,
sizeof(struct root_device_softc)
};
device_t root = device_add_child(NULL, NULL, 0);
if (root == NULL)
return B_NO_MEMORY;
root->softc = malloc(sizeof(struct root_device_softc));
if (root->softc == NULL) {
device_delete_child(NULL, root);
return B_NO_MEMORY;
}
bzero(root->softc, sizeof(struct root_device_softc));
root->driver = &sRootDriver;
root->root = root;
if (_root != NULL)
*_root = root;
return B_OK;
}
static status_t
add_child_device(driver_t* driver, device_t root, device_t* _child)
{
device_t child = device_add_child_driver(root, driver->name, driver, 0);
if (child == NULL) {
return B_ERROR;
}
if (_child != NULL)
*_child = child;
return B_OK;
}
static pci_info *
get_pci_info(struct device *device)
{
return &((struct root_device_softc *)device->softc)->pci_info;
}
// #pragma mark - Haiku Driver API
status_t
_fbsd_init_hardware(driver_t *drivers[])
{
status_t status;
int i = 0, p = 0, index = 0;
pci_info* info;
device_t root;
status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPci);
if (status != B_OK)
return status;
// if it fails we just don't support x86 specific features (like MSIs)
if (get_module(B_PCI_X86_MODULE_NAME, (module_info **)&gPCIx86) != B_OK)
gPCIx86 = NULL;
status = init_root_device(&root);
if (status != B_OK)
return status;
for (p = 0; p <= MAX_DEVICES; p++)
sProbedDevices[i].driver = NULL;
p = 0;
for (info = get_pci_info(root); gPci->get_nth_pci_info(i, info) == B_OK;
i++) {
int best = 0;
driver_t* driver = NULL;
for (index = 0; drivers[index] && gDeviceCount < MAX_DEVICES; index++) {
int result;
device_t device = NULL;
status = add_child_device(drivers[index], root, &device);
if (status < B_OK)
break;
result = device->methods.probe(device);
if (result >= 0 && (driver == NULL || result > best)) {
TRACE(("%s, found %s at %d (%d)\n", gDriverName,
device_get_desc(device), i, result));
driver = drivers[index];
best = result;
}
device_delete_child(root, device);
}
if (driver == NULL)
continue;
// We've found a driver; now try to reserve the device and store it
if (gPci->reserve_device(info->bus, info->device, info->function,
gDriverName, NULL) != B_OK) {
dprintf("%s: Failed to reserve PCI:%d:%d:%d\n",
gDriverName, info->bus, info->device, info->function);
continue;
}
sProbedDevices[p].driver = driver;
sProbedDevices[p].info = *info;
p++;
}
device_delete_child(NULL, root);
if (p > 0)
return B_OK;
put_module(B_PCI_MODULE_NAME);
if (gPCIx86 != NULL)
put_module(B_PCI_X86_MODULE_NAME);
return B_NOT_SUPPORTED;
}
status_t
_fbsd_init_drivers(driver_t *drivers[])
{
status_t status;
int p = 0;
status = init_mutexes();
if (status < B_OK)
goto err2;
status = init_mbufs();
if (status < B_OK)
goto err3;
status = init_callout();
if (status < B_OK)
goto err4;
init_bounce_pages();
if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES)) {
status = init_taskqueues();
if (status < B_OK)
goto err5;
}
init_sysinit();
status = init_wlan_stack();
if (status < B_OK)
goto err6;
for (p = 0; sProbedDevices[p].driver != NULL; p++) {
pci_info* info;
device_t root, device = NULL;
status = init_root_device(&root);
if (status != B_OK)
break;
info = get_pci_info(root);
*info = sProbedDevices[p].info;
status = add_child_device(sProbedDevices[p].driver, root, &device);
if (status != B_OK)
break;
// some drivers expect probe() to be called before attach()
// (i.e. they set driver softc in probe(), etc.)
if (device->methods.probe(device) >= 0
&& device_attach(device) == 0) {
dprintf("%s: init_driver(%p)\n", gDriverName,
sProbedDevices[p].driver);
} else
device_delete_child(NULL, root);
}
if (gDeviceCount > 0)
return B_OK;
if (status == B_OK)
status = B_ERROR;
err7:
uninit_wlan_stack();
err6:
uninit_sysinit();
if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
uninit_taskqueues();
err5:
uninit_bounce_pages();
uninit_callout();
err4:
uninit_mbufs();
err3:
uninit_mutexes();
err2:
for (p = 0; sProbedDevices[p].driver != NULL; p++) {
gPci->unreserve_device(sProbedDevices[p].info.bus,
sProbedDevices[p].info.device, sProbedDevices[p].info.function,
gDriverName, NULL);
}
put_module(B_PCI_MODULE_NAME);
if (gPCIx86 != NULL)
put_module(B_PCI_X86_MODULE_NAME);
return status;
}
status_t
_fbsd_uninit_drivers(driver_t *drivers[])
{
int i, p;
for (i = 0; drivers[i]; i++)
TRACE(("%s: uninit_driver(%p)\n", gDriverName, drivers[i]));
for (i = 0; i < gDeviceCount; i++) {
device_delete_child(NULL, gDevices[i]->root_device);
}
uninit_wlan_stack();
uninit_sysinit();
if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
uninit_taskqueues();
uninit_bounce_pages();
uninit_callout();
uninit_mbufs();
uninit_mutexes();
for (p = 0; sProbedDevices[p].driver != NULL; p++) {
gPci->unreserve_device(sProbedDevices[p].info.bus,
sProbedDevices[p].info.device, sProbedDevices[p].info.function,
gDriverName, NULL);
}
put_module(B_PCI_MODULE_NAME);
if (gPCIx86 != NULL)
put_module(B_PCI_X86_MODULE_NAME);
return B_OK;
}
↑ V729 Function body contains the 'err7' label that is not used by any 'goto' statements.