diff --git a/src/add-ons/kernel/drivers/network/ether/dec21xxx/glue.c b/src/add-ons/kernel/drivers/network/ether/dec21xxx/glue.c index 3d749a0859..3e267cbb5d 100644 --- a/src/add-ons/kernel/drivers/network/ether/dec21xxx/glue.c +++ b/src/add-ons/kernel/drivers/network/ether/dec21xxx/glue.c @@ -33,14 +33,14 @@ extern driver_t *DRIVER_MODULE_NAME(dc, pci); extern driver_t *DRIVER_MODULE_NAME(de, pci); status_t -__haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[])) +__haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[], driver_t *[])) { driver_t *drivers[] = { DRIVER_MODULE_NAME(dc, pci), DRIVER_MODULE_NAME(de, pci), NULL }; - return (*handler)(drivers); + return (*handler)(drivers, NULL); } diff --git a/src/add-ons/kernel/drivers/network/ether/ipro1000/glue.c b/src/add-ons/kernel/drivers/network/ether/ipro1000/glue.c index 86c4079d69..dd61e4df9c 100644 --- a/src/add-ons/kernel/drivers/network/ether/ipro1000/glue.c +++ b/src/add-ons/kernel/drivers/network/ether/ipro1000/glue.c @@ -18,12 +18,12 @@ NO_HAIKU_REENABLE_INTERRUPTS(); status_t -__haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[])) +__haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[], driver_t *[])) { driver_t *drivers[] = { DRIVER_MODULE_NAME(em, pci), DRIVER_MODULE_NAME(igb, pci), NULL }; - return (*handler)(drivers); + return (*handler)(drivers, NULL); } diff --git a/src/add-ons/kernel/drivers/network/ether/pcnet/glue.c b/src/add-ons/kernel/drivers/network/ether/pcnet/glue.c index 0539e02a10..a49d3ca9a1 100644 --- a/src/add-ons/kernel/drivers/network/ether/pcnet/glue.c +++ b/src/add-ons/kernel/drivers/network/ether/pcnet/glue.c @@ -46,14 +46,14 @@ extern driver_t *DRIVER_MODULE_NAME(pcn, pci); status_t -__haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[])) +__haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[], driver_t *[])) { driver_t *drivers[] = { DRIVER_MODULE_NAME(le, pci), DRIVER_MODULE_NAME(pcn, pci), NULL }; - return (*handler)(drivers); + return (*handler)(drivers, NULL); } diff --git a/src/libs/compat/freebsd_network/Jamfile b/src/libs/compat/freebsd_network/Jamfile index 84fa65053b..3686985433 100644 --- a/src/libs/compat/freebsd_network/Jamfile +++ b/src/libs/compat/freebsd_network/Jamfile @@ -14,15 +14,6 @@ SubDirCcFlags [ FDefines _KERNEL=1 ] ; SubDirC++Flags [ FDefines _KERNEL=1 ] ; KernelStaticLibrary libfreebsd_network.a : - bus.cpp - bus_dma.cpp - callout.cpp - clock.c - condvar.cpp - device.c - device_hooks.c - driver.c - eventhandler.c fbsd_ether.c fbsd_if_media.c fbsd_kern_mbuf.c @@ -34,6 +25,19 @@ KernelStaticLibrary libfreebsd_network.a : fbsd_subr_bufring.c fbsd_subr_sbuf.c fbsd_time.c + fbsd_usb_error.c + fbsd_usb_util.c + fbsd_usb_lookup.c + + bus.cpp + bus_dma.cpp + callout.cpp + clock.c + condvar.cpp + device.c + device_hooks.c + driver.c + eventhandler.c firmware.c if.c libkern.cpp @@ -50,6 +54,8 @@ KernelStaticLibrary libfreebsd_network.a : sysinit.c taskqueue.c unit.cpp + usb.cpp + usb_util.c ; rule MIIHeaderGen diff --git a/src/libs/compat/freebsd_network/compat/sys/haiku-module.h b/src/libs/compat/freebsd_network/compat/sys/haiku-module.h index ef28192c2a..14f5a6bbeb 100644 --- a/src/libs/compat/freebsd_network/compat/sys/haiku-module.h +++ b/src/libs/compat/freebsd_network/compat/sys/haiku-module.h @@ -80,14 +80,14 @@ typedef struct { __fbsd_ ## name ## _ ## busname -status_t _fbsd_init_hardware(driver_t *driver[]); -status_t _fbsd_init_drivers(driver_t *driver[]); -status_t _fbsd_uninit_drivers(driver_t *driver[]); +status_t _fbsd_init_hardware(driver_t* pci_drivers[], driver_t* uhub_drivers[]); +status_t _fbsd_init_drivers(); +status_t _fbsd_uninit_drivers(); extern const char *gDriverName; driver_t *__haiku_select_miibus_driver(device_t dev); driver_t *__haiku_probe_miibus(device_t dev, driver_t *drivers[]); -status_t __haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[])); +status_t __haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[], driver_t *[])); status_t init_wlan_stack(void); void uninit_wlan_stack(void); @@ -112,11 +112,11 @@ status_t wlan_close(void*); } \ status_t init_driver() \ { \ - return __haiku_handle_fbsd_drivers_list(_fbsd_init_drivers); \ + return _fbsd_init_drivers(); \ } \ void uninit_driver() \ { \ - __haiku_handle_fbsd_drivers_list(_fbsd_uninit_drivers); \ + _fbsd_uninit_drivers(); \ } \ const char **publish_devices() \ { return gDeviceNameList; } \ @@ -140,12 +140,12 @@ status_t wlan_close(void*); #define HAIKU_FBSD_DRIVER_GLUE(publicname, name, busname) \ extern driver_t* DRIVER_MODULE_NAME(name, busname); \ - status_t __haiku_handle_fbsd_drivers_list(status_t (*proc)(driver_t *[])) {\ + status_t __haiku_handle_fbsd_drivers_list(status_t (*proc)(driver_t *[], driver_t *[])) {\ driver_t *drivers[] = { \ DRIVER_MODULE_NAME(name, busname), \ NULL \ }; \ - return (*proc)(drivers); \ + return (*proc)(drivers, NULL); \ } \ HAIKU_FBSD_DRIVERS_GLUE(publicname); @@ -154,12 +154,12 @@ status_t wlan_close(void*); #define HAIKU_FBSD_WLAN_DRIVER_GLUE(publicname, name, busname) \ extern driver_t *DRIVER_MODULE_NAME(name, busname); \ - status_t __haiku_handle_fbsd_drivers_list(status_t (*proc)(driver_t *[])) {\ + status_t __haiku_handle_fbsd_drivers_list(status_t (*proc)(driver_t *[], driver_t *[])) {\ driver_t *drivers[] = { \ DRIVER_MODULE_NAME(name, busname), \ NULL \ }; \ - return (*proc)(drivers); \ + return (*proc)(drivers, NULL); \ } \ HAIKU_FBSD_WLAN_DRIVERS_GLUE(publicname); diff --git a/src/libs/compat/freebsd_network/device.h b/src/libs/compat/freebsd_network/device.h index 0b9d22b609..7b08131452 100644 --- a/src/libs/compat/freebsd_network/device.h +++ b/src/libs/compat/freebsd_network/device.h @@ -29,13 +29,21 @@ extern "C" { #endif struct root_device_softc { + enum { + BUS_INVALID = 0, + BUS_pci, + BUS_uhub, + } bus; + struct pci_info pci_info; bool is_msi; bool is_msix; + + struct freebsd_usb_device* usb_dev; }; enum { - DEVICE_OPEN = 1 << 0, + DEVICE_OPEN = 1 << 0, DEVICE_CLOSED = 1 << 1, DEVICE_NON_BLOCK = 1 << 2, DEVICE_DESC_ALLOCED = 1 << 3, diff --git a/src/libs/compat/freebsd_network/driver.c b/src/libs/compat/freebsd_network/driver.c index e750f8f7b9..4eada982ff 100644 --- a/src/libs/compat/freebsd_network/driver.c +++ b/src/libs/compat/freebsd_network/driver.c @@ -1,17 +1,10 @@ /* - * 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. + * Copyright 2007-2010, Axel Dörfler. All rights reserved. + * Copyright 2009-2022, Haiku, Inc. 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" @@ -20,7 +13,6 @@ #include #include -#include #include @@ -28,6 +20,10 @@ #include #include +#include +#include +#include + //#define TRACE_DRIVER #ifdef TRACE_DRIVER @@ -39,7 +35,10 @@ static struct { driver_t* driver; - pci_info info; + int bus; + struct pci_info pci_info; + struct freebsd_usb_device usb_dev; + struct usb_attach_arg uaa; } sProbedDevices[MAX_DEVICES]; const char* gDeviceNameList[MAX_DEVICES + 1]; @@ -48,12 +47,17 @@ int32 gDeviceCount; static status_t -init_root_device(device_t *_root) +init_root_device(device_t *_root, int bus_type) { - static driver_t sRootDriver = { + static driver_t sRootDriverPCI = { "pci", NULL, - sizeof(struct root_device_softc) + sizeof(struct root_device_softc), + }; + static driver_t sRootDriverUSB = { + "uhub", + NULL, + sizeof(struct root_device_softc), }; device_t root = device_add_child(NULL, NULL, 0); @@ -67,7 +71,15 @@ init_root_device(device_t *_root) } bzero(root->softc, sizeof(struct root_device_softc)); - root->driver = &sRootDriver; + + if (bus_type == BUS_pci) + root->driver = &sRootDriverPCI; + else if (bus_type == BUS_uhub) + root->driver = &sRootDriverUSB; + else + panic("unknown bus type"); + ((struct root_device_softc*)root->softc)->bus = bus_type; + root->root = root; if (_root != NULL) @@ -81,9 +93,8 @@ 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) { + if (child == NULL) return B_ERROR; - } if (_child != NULL) *_child = child; @@ -92,43 +103,50 @@ add_child_device(driver_t* driver, device_t root, device_t* _child) } -static pci_info * -get_pci_info(struct device *device) +static void +uninit_probed_devices() { - return &((struct root_device_softc *)device->softc)->pci_info; + for (int p = 0; sProbedDevices[p].bus != BUS_INVALID; p++) { + if (sProbedDevices[p].bus == BUS_pci) { + gPci->unreserve_device(sProbedDevices[p].pci_info.bus, + sProbedDevices[p].pci_info.device, sProbedDevices[p].pci_info.function, + gDriverName, NULL); + } else if (sProbedDevices->bus == BUS_uhub) { + usb_cleanup_device(&sProbedDevices[p].usb_dev); + } + } } // #pragma mark - Haiku Driver API -status_t -_fbsd_init_hardware(driver_t *drivers[]) +static status_t +init_hardware_pci(driver_t* drivers[]) { status_t status; - int i = 0, p = 0, index = 0; + int i = 0; pci_info* info; device_t root; - status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPci); + int p = 0; + while (sProbedDevices[p].bus != BUS_INVALID) + p++; + status = init_pci(); if (status != B_OK) return status; - status = init_root_device(&root); + status = init_root_device(&root, BUS_pci); 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++) { + bool found = false; + for (info = get_device_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++) { + for (int index = 0; drivers[index] != NULL; index++) { int result; device_t device = NULL; status = add_child_device(drivers[index], root, &device); @@ -155,14 +173,17 @@ _fbsd_init_hardware(driver_t *drivers[]) gDriverName, info->bus, info->device, info->function); continue; } + sProbedDevices[p].bus = BUS_pci; sProbedDevices[p].driver = driver; - sProbedDevices[p].info = *info; + sProbedDevices[p].pci_info = *info; + found = true; p++; } + sProbedDevices[p].bus = BUS_INVALID; device_delete_child(NULL, root); - if (p > 0) + if (found) return B_OK; uninit_pci(); @@ -170,13 +191,102 @@ _fbsd_init_hardware(driver_t *drivers[]) } -status_t -_fbsd_init_drivers(driver_t *drivers[]) +static status_t +init_hardware_uhub(driver_t* drivers[]) { status_t status; - int p = 0; + device_t root; - status = init_mutexes(); + int p = 0; + while (sProbedDevices[p].bus != BUS_INVALID) + p++; + + status = init_usb(); + if (status != B_OK) + return status; + + status = init_root_device(&root, BUS_uhub); + if (status != B_OK) + return status; + + bool found = false; + uint32 cookie = 0; + struct freebsd_usb_device udev = {}; + while ((status = get_next_usb_device(&cookie, &udev)) == B_OK) { + int best = 0; + driver_t* driver = NULL; + + struct usb_attach_arg uaa; + status = get_usb_device_attach_arg(&udev, &uaa); + if (status != B_OK) + continue; + + for (int index = 0; drivers[index] != NULL; index++) { + int result; + device_t device = NULL; + status = add_child_device(drivers[index], root, &device); + if (status < B_OK) + break; + + device_set_ivars(device, &uaa); + + 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; + + sProbedDevices[p].bus = BUS_uhub; + sProbedDevices[p].driver = driver; + sProbedDevices[p].usb_dev = udev; + sProbedDevices[p].uaa = uaa; + sProbedDevices[p].uaa.device = &sProbedDevices[p].usb_dev; + + // We just "transferred ownership" of usb_dev to sProbedDevices. + memset(&udev, 0, sizeof(udev)); + + found = true; + p++; + } + sProbedDevices[p].bus = BUS_INVALID; + + device_delete_child(NULL, root); + usb_cleanup_device(&udev); + + if (found) + return B_OK; + + uninit_usb(); + return B_NOT_SUPPORTED; +} + + +status_t +_fbsd_init_hardware(driver_t* pci_drivers[], driver_t* uhub_drivers[]) +{ + sProbedDevices[0].bus = BUS_INVALID; + + if (pci_drivers != NULL) + init_hardware_pci(pci_drivers); + + if (uhub_drivers != NULL) + init_hardware_uhub(uhub_drivers); + + return (sProbedDevices[0].bus != BUS_INVALID) ? B_OK : B_NOT_SUPPORTED; +} + + +status_t +_fbsd_init_drivers() +{ + status_t status = init_mutexes(); if (status < B_OK) goto err2; @@ -200,20 +310,27 @@ _fbsd_init_drivers(driver_t *drivers[]) if (status < B_OK) goto err6; - for (p = 0; sProbedDevices[p].driver != NULL; p++) { - pci_info* info; + for (int p = 0; sProbedDevices[p].bus != BUS_INVALID; p++) { device_t root, device = NULL; - status = init_root_device(&root); + status = init_root_device(&root, sProbedDevices[p].bus); if (status != B_OK) break; - info = get_pci_info(root); - *info = sProbedDevices[p].info; + if (sProbedDevices[p].bus == BUS_pci) { + pci_info* info = get_device_pci_info(root); + *info = sProbedDevices[p].pci_info; + } else if (sProbedDevices[p].bus == BUS_uhub) { + struct root_device_softc* root_softc = (struct root_device_softc*)root->softc; + root_softc->usb_dev = &sProbedDevices[p].usb_dev; + } status = add_child_device(sProbedDevices[p].driver, root, &device); if (status != B_OK) break; + if (sProbedDevices[p].bus == BUS_uhub) + device_set_ivars(device, &sProbedDevices[p].uaa); + // some drivers expect probe() to be called before attach() // (i.e. they set driver softc in probe(), etc.) if (device->methods.probe(device) >= 0 @@ -243,12 +360,9 @@ err4: 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); - } + uninit_probed_devices(); + uninit_usb(); uninit_pci(); return status; @@ -256,16 +370,10 @@ err2: status_t -_fbsd_uninit_drivers(driver_t *drivers[]) +_fbsd_uninit_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++) { + for (int i = 0; i < gDeviceCount; i++) device_delete_child(NULL, gDevices[i]->root_device); - } uninit_wlan_stack(); uninit_sysinit(); @@ -275,12 +383,9 @@ _fbsd_uninit_drivers(driver_t *drivers[]) 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); - } + uninit_probed_devices(); + uninit_usb(); uninit_pci(); return B_OK; diff --git a/src/libs/compat/freebsd_network/pci.cpp b/src/libs/compat/freebsd_network/pci.cpp index ecbd2e554c..8726ab03fd 100644 --- a/src/libs/compat/freebsd_network/pci.cpp +++ b/src/libs/compat/freebsd_network/pci.cpp @@ -59,6 +59,8 @@ pci_info* get_device_pci_info(device_t device) { struct root_device_softc* root_softc = (struct root_device_softc*)device->root->softc; + if (root_softc->bus != root_device_softc::BUS_pci) + return NULL; return &root_softc->pci_info; }