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 <waddlesplash@gmail.com>
This commit is contained in:
parent
1eebcfa03e
commit
3d0c08efaf
@ -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;
|
||||
}
|
||||
|
||||
|
@ -12,9 +12,10 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <module.h>
|
||||
#include <PCI.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <PCI_x86.h>
|
||||
#include <bus/PCI.h>
|
||||
#include <USB3.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user