From 3d0c08efaf77c4d44baa9744a6eaab046a6ad31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Wed, 28 Sep 2022 22:51:02 +0200 Subject: [PATCH] xhci: switch to the new driver API keep the stack loaded when no bus is found Change-Id: Ic2cf640ead7d94152651cea86a7977caa0920163 Reviewed-on: https://review.haiku-os.org/c/haiku/+/5708 Reviewed-by: waddlesplash --- src/add-ons/kernel/bus_managers/usb/Stack.cpp | 8 - src/add-ons/kernel/busses/usb/xhci.cpp | 377 ++++++++++++------ src/add-ons/kernel/busses/usb/xhci.h | 12 +- 3 files changed, 258 insertions(+), 139 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/usb/Stack.cpp b/src/add-ons/kernel/bus_managers/usb/Stack.cpp index b68e73b992..827807f032 100644 --- a/src/add-ons/kernel/bus_managers/usb/Stack.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Stack.cpp @@ -67,7 +67,6 @@ Stack::Stack() // EHCI and XHCI, defaulting to EHCI. The XHCI module will switch these // ports before the EHCI module discovers them. const char *moduleNames[] = { - "busses/usb/xhci", "busses/usb/uhci", "busses/usb/ohci", "busses/usb/ehci", @@ -91,11 +90,6 @@ Stack::Stack() TRACE("module %s successfully loaded\n", moduleNames[i]); } - if (fBusManagers.Count() == 0) { - TRACE_ERROR("no bus managers available\n"); - return; - } - fExploreThread = spawn_kernel_thread(ExploreThread, "usb explore", B_LOW_PRIORITY, this); resume_thread(fExploreThread); @@ -133,8 +127,6 @@ Stack::~Stack() status_t Stack::InitCheck() { - if (fBusManagers.Count() == 0) - return ENODEV; return B_OK; } diff --git a/src/add-ons/kernel/busses/usb/xhci.cpp b/src/add-ons/kernel/busses/usb/xhci.cpp index 3f751eee08..b792d34582 100644 --- a/src/add-ons/kernel/busses/usb/xhci.cpp +++ b/src/add-ons/kernel/busses/usb/xhci.cpp @@ -12,9 +12,10 @@ */ -#include -#include +#include + #include +#include #include #include @@ -23,25 +24,210 @@ #include "xhci.h" + +#define CALLED(x...) TRACE_MODULE("CALLED %s\n", __PRETTY_FUNCTION__) + + #define USB_MODULE_NAME "xhci" -pci_module_info *XHCI::sPCIModule = NULL; -pci_x86_module_info *XHCI::sPCIx86Module = NULL; +static pci_x86_module_info* sPCIx86Module = NULL; +static device_manager_info* gDeviceManager; +static usb_for_controller_interface* gUSB; -static int32 -xhci_std_ops(int32 op, ...) +#define XHCI_PCI_DEVICE_MODULE_NAME "busses/usb/xhci/pci/driver_v1" +#define XHCI_PCI_USB_BUS_MODULE_NAME "busses/usb/xhci/device_v1" + + +typedef struct { + XHCI* xhci; + pci_device_module_info* pci; + pci_device* device; + + pci_info pciinfo; + + device_node* node; + device_node* driver_node; +} xhci_pci_sim_info; + + +// #pragma mark - + + +static status_t +init_bus(device_node* node, void** bus_cookie) { - switch (op) { - case B_MODULE_INIT: - TRACE_MODULE("xhci init module\n"); - return B_OK; - case B_MODULE_UNINIT: - TRACE_MODULE("xhci uninit module\n"); - return B_OK; + CALLED(); + + driver_module_info* driver; + xhci_pci_sim_info* bus; + device_node* parent = gDeviceManager->get_parent_node(node); + gDeviceManager->get_driver(parent, &driver, (void**)&bus); + gDeviceManager->put_node(parent); + + Stack *stack; + if (gUSB->get_stack((void**)&stack) != B_OK) + return B_ERROR; + + XHCI *xhci = new(std::nothrow) XHCI(&bus->pciinfo, bus->pci, bus->device, stack); + if (xhci == NULL) { + return B_NO_MEMORY; } - return EINVAL; + if (xhci->InitCheck() < B_OK) { + TRACE_MODULE_ERROR("bus failed init check\n"); + delete xhci; + return B_ERROR; + } + + if (xhci->Start() != B_OK) { + delete xhci; + return B_ERROR; + } + + *bus_cookie = xhci; + + return B_OK; +} + + +static void +uninit_bus(void* bus_cookie) +{ + CALLED(); + XHCI* xhci = (XHCI*)bus_cookie; + delete xhci; +} + + +static status_t +register_child_devices(void* cookie) +{ + CALLED(); + xhci_pci_sim_info* bus = (xhci_pci_sim_info*)cookie; + device_node* node = bus->driver_node; + + char prettyName[25]; + sprintf(prettyName, "XHCI Controller %" B_PRIu16, 0); + + device_attr attrs[] = { + // properties of this controller for the usb bus manager + { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, + { string: prettyName }}, + { B_DEVICE_FIXED_CHILD, B_STRING_TYPE, + { string: USB_FOR_CONTROLLER_MODULE_NAME }}, + + // private data to identify the device + { NULL } + }; + + return gDeviceManager->register_node(node, XHCI_PCI_USB_BUS_MODULE_NAME, + attrs, NULL, NULL); +} + + +static status_t +init_device(device_node* node, void** device_cookie) +{ + CALLED(); + xhci_pci_sim_info* bus = (xhci_pci_sim_info*)calloc(1, + sizeof(xhci_pci_sim_info)); + if (bus == NULL) + return B_NO_MEMORY; + + pci_device_module_info* pci; + pci_device* device; + { + device_node* pciParent = gDeviceManager->get_parent_node(node); + gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci, + (void**)&device); + gDeviceManager->put_node(pciParent); + } + + bus->pci = pci; + bus->device = device; + bus->driver_node = node; + + pci_info *pciInfo = &bus->pciinfo; + pci->get_pci_info(device, pciInfo); + + if (sPCIx86Module == NULL) { + dprintf("xhci_init_device get_module B_PCI_X86_MODULE_NAME\n"); + if (get_module(B_PCI_X86_MODULE_NAME, (module_info**)&sPCIx86Module) != B_OK) + sPCIx86Module = NULL; + } + + *device_cookie = bus; + return B_OK; +} + + +static void +uninit_device(void* device_cookie) +{ + CALLED(); + xhci_pci_sim_info* bus = (xhci_pci_sim_info*)device_cookie; + free(bus); + + if (sPCIx86Module != NULL) { + dprintf("xhci_uninit_device put_module B_PCI_X86_MODULE_NAME\n"); + put_module(B_PCI_X86_MODULE_NAME); + sPCIx86Module = NULL; + } +} + + +static status_t +register_device(device_node* parent) +{ + CALLED(); + device_attr attrs[] = { + {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "XHCI PCI"}}, + {} + }; + + return gDeviceManager->register_node(parent, + XHCI_PCI_DEVICE_MODULE_NAME, attrs, NULL, NULL); +} + + +static float +supports_device(device_node* parent) +{ + CALLED(); + const char* bus; + uint16 type, subType, api; + + // make sure parent is a XHCI PCI device node + if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) + < B_OK) { + return -1; + } + + if (strcmp(bus, "pci") != 0) + return 0.0f; + + if (gDeviceManager->get_attr_uint16(parent, B_DEVICE_SUB_TYPE, &subType, + false) < B_OK + || gDeviceManager->get_attr_uint16(parent, B_DEVICE_TYPE, &type, + false) < B_OK + || gDeviceManager->get_attr_uint16(parent, B_DEVICE_INTERFACE, &api, + false) < B_OK) { + TRACE_MODULE("Could not find type/subtype/interface attributes\n"); + return -1; + } + + if (type == PCI_serial_bus && subType == PCI_usb && api == PCI_usb_xhci) { + pci_device_module_info* pci; + pci_device* device; + gDeviceManager->get_driver(parent, (driver_module_info**)&pci, + (void**)&device); + TRACE_MODULE("XHCI Device found!\n"); + + return 0.8f; + } + + return 0.0f; } @@ -90,109 +276,61 @@ xhci_error_string(uint32 error) } -usb_host_controller_info xhci_module = { - { - "busses/usb/xhci", - 0, - xhci_std_ops - }, - NULL, - XHCI::AddTo +module_dependency module_dependencies[] = { + { USB_FOR_CONTROLLER_MODULE_NAME, (module_info**)&gUSB }, + { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager }, + {} }; -module_info *modules[] = { - (module_info *)&xhci_module, +static usb_bus_interface gXHCIPCIDeviceModule = { + { + { + XHCI_PCI_USB_BUS_MODULE_NAME, + 0, + NULL + }, + NULL, // supports device + NULL, // register device + init_bus, + uninit_bus, + NULL, // register child devices + NULL, // rescan + NULL, // device removed + }, +}; + +// Root device that binds to the PCI bus. It will register an usb_bus_interface +// node for each device. +static driver_module_info sXHCIDevice = { + { + XHCI_PCI_DEVICE_MODULE_NAME, + 0, + NULL + }, + supports_device, + register_device, + init_device, + uninit_device, + register_child_devices, + NULL, // rescan + NULL, // device removed +}; + +module_info* modules[] = { + (module_info* )&sXHCIDevice, + (module_info* )&gXHCIPCIDeviceModule, NULL }; -status_t -XHCI::AddTo(Stack *stack) -{ - if (!sPCIModule) { - status_t status = get_module(B_PCI_MODULE_NAME, - (module_info **)&sPCIModule); - if (status < B_OK) { - TRACE_MODULE_ERROR("getting pci module failed! 0x%08" B_PRIx32 - "\n", status); - return status; - } - } - - TRACE_MODULE("searching devices\n"); - bool found = false; - pci_info *item = new(std::nothrow) pci_info; - if (item == NULL) { - sPCIModule = NULL; - put_module(B_PCI_MODULE_NAME); - return B_NO_MEMORY; - } - - // Try to get the PCI x86 module as well so we can enable possible MSIs. - if (sPCIx86Module == NULL && get_module(B_PCI_X86_MODULE_NAME, - (module_info **)&sPCIx86Module) != B_OK) { - // If it isn't there, that's not critical though. - TRACE_MODULE_ERROR("failed to get pci x86 module\n"); - sPCIx86Module = NULL; - } - - for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) { - if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb - && item->class_api == PCI_usb_xhci) { - TRACE_MODULE("found device at PCI:%d:%d:%d\n", - item->bus, item->device, item->function); - XHCI *bus = new(std::nothrow) XHCI(item, stack); - if (bus == NULL) { - delete item; - sPCIModule = NULL; - put_module(B_PCI_MODULE_NAME); - if (sPCIx86Module != NULL) - put_module(B_PCI_X86_MODULE_NAME); - return B_NO_MEMORY; - } - - // The bus will put the PCI modules when it is destroyed, so get - // them again to increase their reference count. - get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule); - if (sPCIx86Module != NULL) - get_module(B_PCI_X86_MODULE_NAME, (module_info **)&sPCIx86Module); - - if (bus->InitCheck() < B_OK) { - TRACE_MODULE_ERROR("bus failed init check\n"); - delete bus; - continue; - } - - // the bus took it away - item = new(std::nothrow) pci_info; - - if (bus->Start() != B_OK) { - delete bus; - continue; - } - found = true; - } - } - - // The modules will have been gotten again if we successfully - // initialized a bus, so we should put them here. - put_module(B_PCI_MODULE_NAME); - if (sPCIx86Module != NULL) - put_module(B_PCI_X86_MODULE_NAME); - - if (!found) - TRACE_MODULE_ERROR("no devices found\n"); - delete item; - return found ? B_OK : ENODEV; -} - - -XHCI::XHCI(pci_info *info, Stack *stack) +XHCI::XHCI(pci_info *info, pci_device_module_info* pci, pci_device* device, Stack *stack) : BusManager(stack), fRegisterArea(-1), fRegisters(NULL), fPCIInfo(info), + fPci(pci), + fDevice(device), fStack(stack), fIRQ(0), fUseMSI(false), @@ -228,13 +366,11 @@ XHCI::XHCI(pci_info *info, Stack *stack) fInitOK = false; // enable busmaster and memory mapped access - uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus, - fPCIInfo->device, fPCIInfo->function, PCI_command, 2); + uint16 command = fPci->read_pci_config(fDevice, PCI_command, 2); command &= ~(PCI_command_io | PCI_command_int_disable); command |= PCI_command_master | PCI_command_memory; - sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, - fPCIInfo->function, PCI_command, 2, command); + fPci->write_pci_config(fDevice, PCI_command, 2, command); // map the registers (low + high for 64-bit when requested) phys_addr_t physicalAddress = fPCIInfo->u.h0.base_registers[0]; @@ -440,9 +576,6 @@ XHCI::~XHCI() sPCIx86Module->unconfigure_msi(fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function); } - put_module(B_PCI_MODULE_NAME); - if (sPCIx86Module != NULL) - put_module(B_PCI_X86_MODULE_NAME); } @@ -450,21 +583,15 @@ void XHCI::_SwitchIntelPorts() { TRACE("Looking for EHCI owned ports\n"); - uint32 ports = sPCIModule->read_pci_config(fPCIInfo->bus, - fPCIInfo->device, fPCIInfo->function, XHCI_INTEL_USB3PRM, 4); + uint32 ports = fPci->read_pci_config(fDevice, XHCI_INTEL_USB3PRM, 4); TRACE("Superspeed Ports: 0x%" B_PRIx32 "\n", ports); - sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, - fPCIInfo->function, XHCI_INTEL_USB3_PSSEN, 4, ports); - ports = sPCIModule->read_pci_config(fPCIInfo->bus, - fPCIInfo->device, fPCIInfo->function, XHCI_INTEL_USB3_PSSEN, 4); + fPci->write_pci_config(fDevice, XHCI_INTEL_USB3_PSSEN, 4, ports); + ports = fPci->read_pci_config(fDevice, XHCI_INTEL_USB3_PSSEN, 4); TRACE("Superspeed ports now under XHCI : 0x%" B_PRIx32 "\n", ports); - ports = sPCIModule->read_pci_config(fPCIInfo->bus, - fPCIInfo->device, fPCIInfo->function, XHCI_INTEL_USB2PRM, 4); + ports = fPci->read_pci_config(fDevice, XHCI_INTEL_USB2PRM, 4); TRACE("USB 2.0 Ports : 0x%" B_PRIx32 "\n", ports); - sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, - fPCIInfo->function, XHCI_INTEL_XUSB2PR, 4, ports); - ports = sPCIModule->read_pci_config(fPCIInfo->bus, - fPCIInfo->device, fPCIInfo->function, XHCI_INTEL_XUSB2PR, 4); + fPci->write_pci_config(fDevice, XHCI_INTEL_XUSB2PR, 4, ports); + ports = fPci->read_pci_config(fDevice, XHCI_INTEL_XUSB2PR, 4); TRACE("USB 2.0 ports now under XHCI: 0x%" B_PRIx32 "\n", ports); } diff --git a/src/add-ons/kernel/busses/usb/xhci.h b/src/add-ons/kernel/busses/usb/xhci.h index 86d9a9299d..70e201aa37 100644 --- a/src/add-ons/kernel/busses/usb/xhci.h +++ b/src/add-ons/kernel/busses/usb/xhci.h @@ -17,8 +17,8 @@ struct pci_info; -struct pci_module_info; -struct pci_x86_module_info; +struct pci_device_module_info; +struct pci_device; struct xhci_td; struct xhci_device; struct xhci_endpoint; @@ -91,7 +91,7 @@ class XHCI : public BusManager { public: static status_t AddTo(Stack *stack); - XHCI(pci_info *info, Stack *stack); + XHCI(pci_info *info, pci_device_module_info* pci, pci_device* device, Stack *stack); ~XHCI(); virtual const char * TypeName() const { return "xhci"; } @@ -223,9 +223,6 @@ private: void _SwitchIntelPorts(); private: - static pci_module_info * sPCIModule; - static pci_x86_module_info *sPCIx86Module; - area_id fRegisterArea; uint8 * fRegisters; uint32 fCapabilityRegisterOffset; @@ -234,6 +231,9 @@ private: uint32 fDoorbellRegisterOffset; pci_info * fPCIInfo; + pci_device_module_info* fPci; + pci_device* fDevice; + Stack * fStack; uint8 fIRQ; bool fUseMSI;