freebsd_network: probes each driver and only attach the best probe.

* related bug #10088.
This commit is contained in:
Jérôme Duval
2013-10-15 20:28:55 +02:00
parent 7895042a8a
commit fc3b9496eb
+78 -59
View File
@@ -42,14 +42,13 @@ int32 gDeviceCount;
static status_t static status_t
init_root_device(driver_t *driver, device_t *_root, device_t *_child) init_root_device(device_t *_root)
{ {
static driver_t sRootDriver = { static driver_t sRootDriver = {
"pci", "pci",
NULL, NULL,
sizeof(struct root_device_softc) sizeof(struct root_device_softc)
}; };
device_t child;
device_t root = device_add_child(NULL, NULL, 0); device_t root = device_add_child(NULL, NULL, 0);
if (root == NULL) if (root == NULL)
@@ -65,14 +64,21 @@ init_root_device(driver_t *driver, device_t *_root, device_t *_child)
root->driver = &sRootDriver; root->driver = &sRootDriver;
root->root = root; root->root = root;
child = device_add_child(root, driver->name, 0); 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(root, driver->name, 0);
if (child == NULL) { if (child == NULL) {
device_delete_child(NULL, root);
return B_ERROR; return B_ERROR;
} }
if (_root != NULL)
*_root = root;
if (_child != NULL) if (_child != NULL)
*_child = child; *_child = child;
@@ -94,51 +100,53 @@ status_t
_fbsd_init_hardware(driver_t *drivers[]) _fbsd_init_hardware(driver_t *drivers[])
{ {
status_t status = B_ENTRY_NOT_FOUND; status_t status = B_ENTRY_NOT_FOUND;
int index; device_t root;
pci_info *info;
driver_t *driver = NULL;
int i = 0;
if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK) if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK)
return B_ERROR; return B_ERROR;
for (index = 0; status != B_OK && drivers[index]; index++) { status = init_root_device(&root);
device_t child, root; if (status != B_OK)
pci_info *info; goto err;
int i;
if (init_root_device(drivers[index], &root, &child) != B_OK) { for (info = get_pci_info(root); gPci->get_nth_pci_info(i, info) == B_OK;
dprintf("%s: creating device failed.\n", gDriverName); i++) {
put_module(B_PCI_MODULE_NAME); int index;
return B_ERROR; driver = NULL;
}
TRACE(("%s: init_hardware(%p)\n", gDriverName, drivers[index])); for (index = 0; drivers[index] && gDeviceCount < MAX_DEVICES
&& driver == NULL; index++) {
if (child->methods.probe == NULL) {
dprintf("%s: driver has no device_probe method.\n", gDriverName);
device_delete_child(NULL, root);
put_module(B_PCI_MODULE_NAME);
return B_ERROR;
}
info = get_pci_info(root);
for (i = 0; gPci->get_nth_pci_info(i, info) == B_OK; i++) {
int result; int result;
result = child->methods.probe(child); device_t device;
status = add_child_device(drivers[index], root, &device);
if (status < B_OK)
break;
result = device->methods.probe(device);
if (result >= 0) { if (result >= 0) {
TRACE(("%s, found %s at %d\n", gDriverName, TRACE(("%s, found %s at %d\n", gDriverName,
device_get_desc(child), i)); device_get_desc(device), i));
status = B_OK; driver = drivers[index];
break;
} }
device_delete_child(root, device);
} }
device_delete_child(NULL, root); if (driver != NULL)
break;
} }
if (status < B_OK) device_delete_child(NULL, root);
TRACE(("%s: no hardware found.\n", gDriverName));
if (driver == NULL) {
status = B_ERROR;
TRACE(("%s: no hardware found.\n", gDriverName));
}
err:
put_module(B_PCI_MODULE_NAME); put_module(B_PCI_MODULE_NAME);
TRACE(("%s: status 0x%lx\n", gDriverName, status));
return status; return status;
} }
@@ -150,8 +158,8 @@ _fbsd_init_drivers(driver_t *drivers[])
status_t status; status_t status;
int i = 0; int i = 0;
int index = 0; int index = 0;
pci_info *info;
dprintf("%s: init_driver(%p)\n", gDriverName, drivers[index]); device_t root;
status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPci); status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPci);
if (status < B_OK) if (status < B_OK)
@@ -189,42 +197,53 @@ _fbsd_init_drivers(driver_t *drivers[])
if (status < B_OK) if (status < B_OK)
goto err6; goto err6;
while (drivers[index] && gDeviceCount < MAX_DEVICES) { status = init_root_device(&root);
device_t root, device; if (status != B_OK)
bool found = false; goto err7;
pci_info *info;
status = init_root_device(drivers[index], &root, &device); for (info = get_pci_info(root); gPci->get_nth_pci_info(i, info) == B_OK;
if (status < B_OK) i++) {
break; int best = 0;
driver_t *driver = NULL;
info = get_pci_info(root); for (index = 0; drivers[index] && gDeviceCount < MAX_DEVICES; index++) {
int result;
device_t device;
status = add_child_device(drivers[index], root, &device);
if (status < B_OK)
break;
for (; gPci->get_nth_pci_info(i, info) == B_OK; i++) { result = device->methods.probe(device);
if (device->methods.probe(device) < 0) if (result >= 0 && (driver == NULL || result > best)) {
continue; TRACE(("%s, found %s at %d (%d)\n", gDriverName,
device_get_desc(device), i, result));
if (device_attach(device) == 0) driver = drivers[index];
found = true; best = result;
}
i++; device_delete_child(root, device);
break;
} }
if (!found) { if (driver != NULL) {
device_delete_child(NULL, root); device_t device;
i = 0; status = add_child_device(driver, root, &device);
if (drivers[++index]) if (status != B_OK)
dprintf("%s: init_driver(%p)\n", gDriverName, drivers[index]); break;
if (device_attach(device) == 0) {
dprintf("%s: init_driver(%p) at %d\n", gDriverName, driver, i);
} else
device_delete_child(root, device);
} }
} }
if (gDeviceCount > 0) if (gDeviceCount > 0)
return B_OK; return B_OK;
device_delete_child(NULL, root);
if (status == B_OK) if (status == B_OK)
status = B_ERROR; status = B_ERROR;
err7:
uninit_wlan_stack(); uninit_wlan_stack();
err6: err6: