From 368d09fdac9f95b8679d4a5387b745a3ed64c42b Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Tue, 9 Sep 2025 19:02:50 -0400 Subject: [PATCH] freebsd_network: Clean up attach logic and separate USB logic. USB code now goes in a separate static library. This also paves the way for supporting more busses than PCI and USB in the compat layer. Tested with realtekwifi, still works. --- .../drivers/network/ether/dec21xxx/glue.c | 6 +- .../drivers/network/ether/ipro1000/glue.c | 6 +- .../kernel/drivers/network/ether/pcnet/glue.c | 6 +- .../drivers/network/wlan/ralinkwifi/Jamfile | 1 + .../drivers/network/wlan/ralinkwifi/glue.c | 7 +- .../drivers/network/wlan/realtekwifi/Jamfile | 1 + .../drivers/network/wlan/realtekwifi/glue.c | 7 +- src/libs/compat/freebsd_network/Jamfile | 11 +- .../compat/dev/usb/usb_device.h | 2 - .../freebsd_network/compat/sys/haiku-module.h | 22 ++- .../{ => dev/usb}/fbsd_usb_error.c | 0 .../{ => dev/usb}/fbsd_usb_lookup.c | 0 .../{ => dev/usb}/fbsd_usb_util.c | 0 src/libs/compat/freebsd_network/device.c | 36 ++-- src/libs/compat/freebsd_network/device.h | 11 +- src/libs/compat/freebsd_network/driver.c | 165 +++++------------- src/libs/compat/freebsd_network/usb.cpp | 93 +++++++++- 17 files changed, 200 insertions(+), 174 deletions(-) rename src/libs/compat/freebsd_network/{ => dev/usb}/fbsd_usb_error.c (100%) rename src/libs/compat/freebsd_network/{ => dev/usb}/fbsd_usb_lookup.c (100%) rename src/libs/compat/freebsd_network/{ => dev/usb}/fbsd_usb_util.c (100%) 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 4b0503f609..544d94e2fc 100644 --- a/src/add-ons/kernel/drivers/network/ether/dec21xxx/glue.c +++ b/src/add-ons/kernel/drivers/network/ether/dec21xxx/glue.c @@ -34,15 +34,15 @@ extern void reenable_interrupts_de(device_t dev); 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 *[], driver_t *[])) +void +__haiku_init_hardware() { driver_t *drivers[] = { DRIVER_MODULE_NAME(dc, pci), DRIVER_MODULE_NAME(de, pci), NULL }; - return (*handler)(drivers, NULL); + _fbsd_init_hardware_pci(drivers); } 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 dd61e4df9c..bb1412ce8b 100644 --- a/src/add-ons/kernel/drivers/network/ether/ipro1000/glue.c +++ b/src/add-ons/kernel/drivers/network/ether/ipro1000/glue.c @@ -17,13 +17,13 @@ NO_HAIKU_CHECK_DISABLE_INTERRUPTS(); NO_HAIKU_REENABLE_INTERRUPTS(); -status_t -__haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[], driver_t *[])) +void +__haiku_init_hardware() { driver_t *drivers[] = { DRIVER_MODULE_NAME(em, pci), DRIVER_MODULE_NAME(igb, pci), NULL }; - return (*handler)(drivers, NULL); + _fbsd_init_hardware_pci(drivers); } 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 647ba38c11..d95f7732fd 100644 --- a/src/add-ons/kernel/drivers/network/ether/pcnet/glue.c +++ b/src/add-ons/kernel/drivers/network/ether/pcnet/glue.c @@ -45,15 +45,15 @@ extern driver_t *DRIVER_MODULE_NAME(le, pci); extern driver_t *DRIVER_MODULE_NAME(pcn, pci); -status_t -__haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[], driver_t *[])) +void +__haiku_init_hardware() { driver_t *drivers[] = { DRIVER_MODULE_NAME(le, pci), DRIVER_MODULE_NAME(pcn, pci), NULL }; - return (*handler)(drivers, NULL); + _fbsd_init_hardware_pci(drivers); } diff --git a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/Jamfile b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/Jamfile index fead0f50e4..9e04a3a1c8 100644 --- a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/Jamfile +++ b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/Jamfile @@ -29,6 +29,7 @@ KernelAddon ralinkwifi : glue.c : freebsd_wlan.a + freebsd_usb.a libfreebsd_network.a ; diff --git a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/glue.c b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/glue.c index b6d4ae9b2e..4e3c11572f 100644 --- a/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/glue.c +++ b/src/add-ons/kernel/drivers/network/wlan/ralinkwifi/glue.c @@ -49,8 +49,8 @@ extern driver_t* DRIVER_MODULE_NAME(run, uhub); extern driver_t* DRIVER_MODULE_NAME(rum, uhub); -status_t -__haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[], driver_t *[])) +void +__haiku_init_hardware() { driver_t *pci_drivers[] = { DRIVER_MODULE_NAME(ral, pci), @@ -63,7 +63,8 @@ __haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[], driver_t *[]) DRIVER_MODULE_NAME(rum, uhub), NULL }; - return (*handler)(pci_drivers, usb_drivers); + _fbsd_init_hardware_pci(pci_drivers); + _fbsd_init_hardware_uhub(usb_drivers); } diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/Jamfile b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/Jamfile index 94e32243ca..44dafe5248 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/Jamfile +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/Jamfile @@ -153,6 +153,7 @@ KernelAddon realtekwifi : r21au_init.c : freebsd_wlan.a + freebsd_usb.a libfreebsd_network.a ; diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/glue.c b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/glue.c index faf76d9fef..09d050ad26 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/glue.c +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/glue.c @@ -43,8 +43,8 @@ NO_HAIKU_FBSD_MII_DRIVER(); NO_HAIKU_REENABLE_INTERRUPTS(); -status_t -__haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[], driver_t *[])) +void +__haiku_init_hardware() { driver_t *pci_drivers[] = { DRIVER_MODULE_NAME(rtwn_pci, pci), @@ -54,7 +54,8 @@ __haiku_handle_fbsd_drivers_list(status_t (*handler)(driver_t *[], driver_t *[]) DRIVER_MODULE_NAME(rtwn_usb, uhub), NULL }; - return (*handler)(pci_drivers, usb_drivers); + _fbsd_init_hardware_pci(pci_drivers); + _fbsd_init_hardware_uhub(usb_drivers); } diff --git a/src/libs/compat/freebsd_network/Jamfile b/src/libs/compat/freebsd_network/Jamfile index 4d0a60a1a3..d9c8817325 100644 --- a/src/libs/compat/freebsd_network/Jamfile +++ b/src/libs/compat/freebsd_network/Jamfile @@ -20,9 +20,6 @@ KernelStaticLibrary libfreebsd_network.a : fbsd_subr_sbuf.c fbsd_time.c fbsd_timingsafe.c - fbsd_usb_error.c - fbsd_usb_util.c - fbsd_usb_lookup.c bus.cpp bus_dma.cpp @@ -48,6 +45,14 @@ KernelStaticLibrary libfreebsd_network.a : sysinit.c taskqueue.c unit.cpp + ; + +SEARCH_SOURCE += [ FDirName $(SUBDIR) dev usb ] ; + +KernelStaticLibrary freebsd_usb.a : + fbsd_usb_error.c + fbsd_usb_util.c + fbsd_usb_lookup.c usb.cpp usb_util.c ; diff --git a/src/libs/compat/freebsd_network/compat/dev/usb/usb_device.h b/src/libs/compat/freebsd_network/compat/dev/usb/usb_device.h index 8cd8931100..450f5a4df1 100644 --- a/src/libs/compat/freebsd_network/compat/dev/usb/usb_device.h +++ b/src/libs/compat/freebsd_network/compat/dev/usb/usb_device.h @@ -12,6 +12,4 @@ struct usb_device { uint32 haiku_usb_device; }; -void usb_cleanup_device(struct usb_device* udev); - #endif // _FBSD_COMPAT_USB_DEVICE_H_ 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 92036f2119..7d602b6d7a 100644 --- a/src/libs/compat/freebsd_network/compat/sys/haiku-module.h +++ b/src/libs/compat/freebsd_network/compat/sys/haiku-module.h @@ -78,14 +78,16 @@ typedef struct { __fbsd_ ## name ## _ ## busname -status_t _fbsd_init_hardware(driver_t* pci_drivers[], driver_t* uhub_drivers[]); +void __haiku_init_hardware(void); +status_t _fbsd_init_hardware(); +status_t _fbsd_init_hardware_pci(driver_t* drivers[]); +status_t _fbsd_init_hardware_uhub(driver_t* 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_drivers(device_t dev, driver_t *drivers[]); -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); @@ -106,15 +108,15 @@ status_t wlan_close(void*); int32 api_version = B_CUR_DRIVER_API_VERSION; \ status_t init_hardware() \ { \ - return __haiku_handle_fbsd_drivers_list(_fbsd_init_hardware); \ + return _fbsd_init_hardware(); \ } \ status_t init_driver() \ { \ - return _fbsd_init_drivers(); \ + return _fbsd_init_drivers(); \ } \ void uninit_driver() \ { \ - _fbsd_uninit_drivers(); \ + _fbsd_uninit_drivers(); \ } \ const char **publish_devices() \ { return gDeviceNameList; } \ @@ -138,12 +140,13 @@ 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 *[], driver_t *[])) {\ + void __haiku_init_hardware() \ + { \ driver_t *drivers[] = { \ DRIVER_MODULE_NAME(name, busname), \ NULL \ }; \ - return (*proc)(drivers, NULL); \ + _fbsd_init_hardware_pci(drivers); \ } \ HAIKU_FBSD_DRIVERS_GLUE(publicname); @@ -152,12 +155,13 @@ 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 *[], driver_t *[])) {\ + void __haiku_init_hardware() \ + { \ driver_t *drivers[] = { \ DRIVER_MODULE_NAME(name, busname), \ NULL \ }; \ - return (*proc)(drivers, NULL); \ + _fbsd_init_hardware_pci(drivers); \ } \ HAIKU_FBSD_WLAN_DRIVERS_GLUE(publicname); diff --git a/src/libs/compat/freebsd_network/fbsd_usb_error.c b/src/libs/compat/freebsd_network/dev/usb/fbsd_usb_error.c similarity index 100% rename from src/libs/compat/freebsd_network/fbsd_usb_error.c rename to src/libs/compat/freebsd_network/dev/usb/fbsd_usb_error.c diff --git a/src/libs/compat/freebsd_network/fbsd_usb_lookup.c b/src/libs/compat/freebsd_network/dev/usb/fbsd_usb_lookup.c similarity index 100% rename from src/libs/compat/freebsd_network/fbsd_usb_lookup.c rename to src/libs/compat/freebsd_network/dev/usb/fbsd_usb_lookup.c diff --git a/src/libs/compat/freebsd_network/fbsd_usb_util.c b/src/libs/compat/freebsd_network/dev/usb/fbsd_usb_util.c similarity index 100% rename from src/libs/compat/freebsd_network/fbsd_usb_util.c rename to src/libs/compat/freebsd_network/dev/usb/fbsd_usb_util.c diff --git a/src/libs/compat/freebsd_network/device.c b/src/libs/compat/freebsd_network/device.c index c97ef4e489..ae8b738ecb 100644 --- a/src/libs/compat/freebsd_network/device.c +++ b/src/libs/compat/freebsd_network/device.c @@ -506,8 +506,11 @@ bus_generic_attach(device_t dev) } else { device_printf(dev, "failed to find driver for child device\n"); } - } else + } else { + device_printf(dev, "found device driver: %s\n", + driver->name); device_set_driver(child, driver); + } } else child->methods.device_probe(child); @@ -543,31 +546,32 @@ bus_generic_detach(device_t device) driver_t * -__haiku_probe_drivers(device_t dev, driver_t *drivers[]) +__haiku_probe_drivers(device_t device, driver_t *drivers[]) { driver_t *selected = NULL; - int i, selectedResult = 0; + int best = 0; if (drivers == NULL) return NULL; - for (i = 0; drivers[i]; i++) { - device_probe_t *probe = (device_probe_t *) - resolve_device_method(drivers[i], ID_device_probe); - if (probe == NULL) - continue; + for (int i = 0; drivers[i]; i++) { + // Skip allocating the device softc and just call probe() directly. + // (Any drivers which don't support this should be patched.) + device->methods.device_register + = resolve_device_method(drivers[i], ID_device_register); + device->methods.device_probe + = resolve_device_method(drivers[i], ID_device_probe); - int result = probe(dev); - if (result >= 0) { - if (selected == NULL || result < selectedResult) { - selected = drivers[i]; - selectedResult = result; - device_printf(dev, "found %s device driver: %s\n", - dev->parent->description, selected->name); - } + int result = device->methods.device_probe(device); + if (result >= 0 && (selected == NULL || result > best)) { + selected = drivers[i]; + best = result; } } + device->methods.device_register = NULL; + device->methods.device_probe = NULL; + return selected; } diff --git a/src/libs/compat/freebsd_network/device.h b/src/libs/compat/freebsd_network/device.h index 249992f6f8..1567c5fed7 100644 --- a/src/libs/compat/freebsd_network/device.h +++ b/src/libs/compat/freebsd_network/device.h @@ -82,13 +82,12 @@ void uninit_callout(void); status_t init_pci(); void uninit_pci(); -status_t init_usb(); -void uninit_usb(); +void uninit_usb() __attribute__((weak)); -status_t get_next_usb_device(uint32* cookie, struct freebsd_usb_device* result); -status_t get_usb_device_attach_arg(struct freebsd_usb_device* device, struct usb_attach_arg* uaa); - -device_t find_root_device(int); +void report_probed_device(int bus, void* compat_device, driver_t* driver, + void (*prepare_attach)(void*, device_t), void (*free_compat_device)(void*)); +status_t init_root_device(device_t *_root, int bus_type); +device_t find_root_device(int unit); pci_info* get_device_pci_info(device_t dev); device_method_signature_t resolve_device_method(driver_t *driver, int id); diff --git a/src/libs/compat/freebsd_network/driver.c b/src/libs/compat/freebsd_network/driver.c index 582f03becc..0a52f78cd0 100644 --- a/src/libs/compat/freebsd_network/driver.c +++ b/src/libs/compat/freebsd_network/driver.c @@ -37,8 +37,10 @@ static struct { driver_t* driver; int bus; struct pci_info pci_info; - struct freebsd_usb_device usb_dev; - struct usb_attach_arg uaa; + + void* compat_device; + void (*prepare_attach)(void*, device_t); + void (*free_compat_device)(void*); } sProbedDevices[MAX_DEVICES]; const char* gDeviceNameList[MAX_DEVICES + 1]; @@ -46,7 +48,7 @@ struct ifnet* gDevices[MAX_DEVICES]; int32 gDeviceCount; -static status_t +status_t init_root_device(device_t *_root, int bus_type) { static driver_t sRootDriverPCI = { @@ -115,18 +117,41 @@ uninit_probed_devices() 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); + } else { + sProbedDevices[p].free_compat_device(sProbedDevices[p].compat_device); } } } +void +report_probed_device(int bus, void* compat_device, driver_t* driver, + void (*prepare_attach)(void*, device_t), void (*free_compat_device)(void*)) +{ + int p = 0; + while (sProbedDevices[p].bus != BUS_INVALID && p < MAX_DEVICES) + p++; + if (p == MAX_DEVICES) { + free_compat_device(compat_device); + return; + } + + sProbedDevices[p].bus = bus; + sProbedDevices[p].driver = driver; + sProbedDevices[p].compat_device = compat_device; + sProbedDevices[p].prepare_attach = prepare_attach; + sProbedDevices[p].free_compat_device = free_compat_device; + + if ((p + 1) < MAX_DEVICES) + sProbedDevices[p + 1].bus = BUS_INVALID; +} + + // #pragma mark - Haiku Driver API -static status_t -init_hardware_pci(driver_t* drivers[]) +status_t +_fbsd_init_hardware_pci(driver_t* drivers[]) { status_t status; int i = 0; @@ -154,23 +179,7 @@ init_hardware_pci(driver_t* drivers[]) device.parent = root; device.root = root; - for (int index = 0; drivers[index] != NULL; index++) { - // Skip allocating the device softc and just call probe() directly. - // (Any drivers which don't support this should be patched.) - device.methods.device_register - = resolve_device_method(drivers[index], ID_device_register); - device.methods.device_probe - = resolve_device_method(drivers[index], ID_device_probe); - - int result = device.methods.device_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; - } - } - + driver = __haiku_probe_drivers(&device, drivers); if (driver == NULL) continue; @@ -199,94 +208,12 @@ init_hardware_pci(driver_t* drivers[]) } -static status_t -init_hardware_uhub(driver_t* drivers[]) -{ - status_t status; - device_t root; - - 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; - - struct device device = {}; - device.parent = root; - device.root = root; - device_set_ivars(&device, &uaa); - - for (int index = 0; drivers[index] != NULL; index++) { - device.methods.device_register - = resolve_device_method(drivers[index], ID_device_register); - device.methods.device_probe - = resolve_device_method(drivers[index], ID_device_probe); - - int result = device.methods.device_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; - } - } - - 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[]) +_fbsd_init_hardware() { sProbedDevices[0].bus = BUS_INVALID; - if (pci_drivers != NULL) - init_hardware_pci(pci_drivers); - - if (uhub_drivers != NULL) - init_hardware_uhub(uhub_drivers); + __haiku_init_hardware(); return (sProbedDevices[0].bus != BUS_INVALID) ? B_OK : B_NOT_SUPPORTED; } @@ -328,20 +255,16 @@ _fbsd_init_drivers() if (status != B_OK) break; - 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); + if (sProbedDevices[p].bus == BUS_pci) { + pci_info* info = get_device_pci_info(root); + *info = sProbedDevices[p].pci_info; + } else { + sProbedDevices[p].prepare_attach(sProbedDevices[p].compat_device, device); + } // some drivers expect probe() to be called before attach() // (i.e. they set driver softc in probe(), etc.) @@ -376,7 +299,8 @@ err3: err2: uninit_probed_devices(); - uninit_usb(); + if (uninit_usb != NULL) + uninit_usb(); uninit_pci(); return status; @@ -399,7 +323,8 @@ _fbsd_uninit_drivers() uninit_probed_devices(); - uninit_usb(); + if (uninit_usb != NULL) + uninit_usb(); uninit_pci(); return B_OK; diff --git a/src/libs/compat/freebsd_network/usb.cpp b/src/libs/compat/freebsd_network/usb.cpp index 0007dc1a3a..63e54170e9 100644 --- a/src/libs/compat/freebsd_network/usb.cpp +++ b/src/libs/compat/freebsd_network/usb.cpp @@ -63,7 +63,7 @@ uninit_usb() } -status_t +static status_t get_next_usb_device(uint32* cookie, freebsd_usb_device* result) { // We cheat here: since USB IDs are sequential, instead of doing a @@ -114,7 +114,7 @@ get_next_usb_device(uint32* cookie, freebsd_usb_device* result) } -status_t +static status_t get_usb_device_attach_arg(struct freebsd_usb_device* device, struct usb_attach_arg* uaa) { memset(uaa, 0, sizeof(struct usb_attach_arg)); @@ -158,7 +158,7 @@ get_usb_device_attach_arg(struct freebsd_usb_device* device, struct usb_attach_a } -void +static void usb_cleanup_device(freebsd_usb_device* udev) { for (int i = 0; i < USB_MAX_EP_UNITS; i++) { @@ -168,6 +168,93 @@ usb_cleanup_device(freebsd_usb_device* udev) } +struct compat_usb_device { + freebsd_usb_device udev; + struct usb_attach_arg uaa; +}; + + +static void +free_compat_usb_device(void* cookie) +{ + compat_usb_device* compat_device = (compat_usb_device*)cookie; + usb_cleanup_device(&compat_device->udev); + free(compat_device); +} + + +static void +prepare_usb_attach(void* cookie, device_t device) +{ + compat_usb_device* compat_device = (compat_usb_device*)cookie; + + struct root_device_softc* root_softc + = (struct root_device_softc*)device->parent->softc; + root_softc->usb_dev = &compat_device->udev; + device_set_ivars(device, &compat_device->uaa); +} + + +status_t +_fbsd_init_hardware_uhub(driver_t* drivers[]) +{ + status_t status; + device_t root; + const int BUS_uhub = root_device_softc::BUS_uhub; + + 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; + + struct device device = {}; + device.parent = root; + device.root = root; + device_set_ivars(&device, &uaa); + + driver = __haiku_probe_drivers(&device, drivers); + if (driver == NULL) + continue; + + compat_usb_device* compat_device = (compat_usb_device*)malloc(sizeof(compat_usb_device)); + compat_device->udev = udev; + compat_device->uaa = uaa; + compat_device->uaa.device = &compat_device->udev; + + // We just "transferred ownership" of usb_dev to sProbedDevices. + memset(&udev, 0, sizeof(udev)); + + report_probed_device(BUS_uhub, compat_device, driver, + prepare_usb_attach, free_compat_usb_device); + found = true; + } + + device_delete_child(NULL, root); + usb_cleanup_device(&udev); + + if (found) + return B_OK; + + uninit_usb(); + return B_NOT_SUPPORTED; +} + + static usb_error_t map_usb_error(status_t err) {