From 319a3798bc05579e8be813c2524bc89864bae489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Thu, 22 Dec 2011 21:40:10 +0100 Subject: [PATCH] Work in progress on XHCI bus driver. * USB Core: Hub: pass more correct speed, port and address for USB3 devices. Transfer: doesn't care for bandwidth computation for super speed. BusManager: Make AllocateDevice() and FreeDevice() virtual, XHCI needs to setup a slot and an address for the device. Add USB_SPEED_WIRELESS usb_speed definition. Add USB2.0 erratum definition and some USB3 definitions * XHCI: Find outs which port supports SuperSpeed or not. Override AllocateDevice() to configure slot and address for a connected device. Override FreeDevice() to free ressources associated to a slot. Add context struct definitions. --- src/add-ons/kernel/bus_managers/usb/Hub.cpp | 11 +- .../kernel/bus_managers/usb/Transfer.cpp | 7 + .../kernel/bus_managers/usb/usb_private.h | 7 +- .../kernel/bus_managers/usb/usbspec_private.h | 19 + src/add-ons/kernel/busses/usb/xhci.cpp | 341 +++++++++++++++++- src/add-ons/kernel/busses/usb/xhci.h | 47 ++- src/add-ons/kernel/busses/usb/xhci_hardware.h | 116 +++++- src/add-ons/kernel/busses/usb/xhci_rh.cpp | 1 - 8 files changed, 528 insertions(+), 21 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/usb/Hub.cpp b/src/add-ons/kernel/bus_managers/usb/Hub.cpp index 04b4ce61ef..df51aeac4d 100644 --- a/src/add-ons/kernel/bus_managers/usb/Hub.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Hub.cpp @@ -7,6 +7,7 @@ * Niels S. Reedijk */ + #include "usb_private.h" #include @@ -128,7 +129,7 @@ Hub::UpdatePortStatus(uint8 index) // get the current port status size_t actualLength = 0; status_t result = DefaultPipe()->SendRequest(USB_REQTYPE_CLASS | USB_REQTYPE_OTHER_IN, - USB_REQUEST_GET_STATUS, 0, index + 1, sizeof(usb_port_status), + USB_REQUEST_GET_STATUS, 0, index + 1, sizeof(usb_port_status), (void *)&fPortStatus[index], sizeof(usb_port_status), &actualLength); if (result < B_OK || actualLength < sizeof(usb_port_status)) { @@ -247,9 +248,11 @@ Hub::Explore(change_item **changeList) } usb_speed speed = USB_SPEED_FULLSPEED; - if (fPortStatus[i].status & PORT_STATUS_LOW_SPEED) + if (fDeviceDescriptor.usb_version == 0x300) + speed = USB_SPEED_SUPER; + else if (fPortStatus[i].status & PORT_STATUS_LOW_SPEED) speed = USB_SPEED_LOWSPEED; - if (fPortStatus[i].status & PORT_STATUS_HIGH_SPEED) + else if (fPortStatus[i].status & PORT_STATUS_HIGH_SPEED) speed = USB_SPEED_HIGHSPEED; // either let the device inherit our addresses (if we are @@ -258,7 +261,7 @@ Hub::Explore(change_item **changeList) // transaction translator for the device. int8 hubAddress = HubAddress(); uint8 hubPort = HubPort(); - if (Speed() == USB_SPEED_HIGHSPEED) { + if (Speed() == USB_SPEED_HIGHSPEED || fDeviceDescriptor.usb_version == 0x300) { hubAddress = DeviceAddress(); hubPort = i + 1; } diff --git a/src/add-ons/kernel/bus_managers/usb/Transfer.cpp b/src/add-ons/kernel/bus_managers/usb/Transfer.cpp index c9aeb73c16..cc599521f7 100644 --- a/src/add-ons/kernel/bus_managers/usb/Transfer.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Transfer.cpp @@ -274,6 +274,13 @@ Transfer::_CalculateBandwidth() break; } + case USB_SPEED_SUPER: + { + // TODO it should only be useful for isochronous type + bandwidthNS = 0; + break; + } + default: // We should never get here TRACE("speed unknown"); diff --git a/src/add-ons/kernel/bus_managers/usb/usb_private.h b/src/add-ons/kernel/bus_managers/usb/usb_private.h index 191d1602f1..1194b2db26 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb_private.h +++ b/src/add-ons/kernel/bus_managers/usb/usb_private.h @@ -91,7 +91,8 @@ typedef enum { USB_SPEED_FULLSPEED, USB_SPEED_HIGHSPEED, USB_SPEED_SUPER, - USB_SPEED_MAX = USB_SPEED_SUPER + USB_SPEED_WIRELESS, + USB_SPEED_MAX = USB_SPEED_WIRELESS } usb_speed; @@ -201,10 +202,10 @@ virtual status_t InitCheck(); int8 AllocateAddress(); void FreeAddress(int8 address); - Device * AllocateDevice(Hub *parent, +virtual Device * AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort, usb_speed speed); - void FreeDevice(Device *device); +virtual void FreeDevice(Device *device); virtual status_t Start(); virtual status_t Stop(); diff --git a/src/add-ons/kernel/bus_managers/usb/usbspec_private.h b/src/add-ons/kernel/bus_managers/usb/usbspec_private.h index 4b46b48a54..5e70ad2b96 100644 --- a/src/add-ons/kernel/bus_managers/usb/usbspec_private.h +++ b/src/add-ons/kernel/bus_managers/usb/usbspec_private.h @@ -87,16 +87,23 @@ struct usb_port_status //The bits in the usb_port_status struct // USB 1.1 spec page 274 +// USB2_LinkPowerMangement_ECN[final].pdf page 25 #define PORT_STATUS_CONNECTION 0x0001 #define PORT_STATUS_ENABLE 0x0002 #define PORT_STATUS_SUSPEND 0x0004 #define PORT_STATUS_OVER_CURRENT 0x0008 #define PORT_STATUS_RESET 0x0010 +#define PORT_STATUS_L1 0x0020 #define PORT_STATUS_POWER 0x0100 #define PORT_STATUS_LOW_SPEED 0x0200 #define PORT_STATUS_HIGH_SPEED 0x0400 #define PORT_STATUS_TEST 0x0800 #define PORT_STATUS_INDICATOR 0x1000 +// USB 3.0 spec table 10-11 +#define PORT_STATUS_SS_LINK_STATE 0x01e0 +#define PORT_STATUS_SS_POWER 0x0200 +#define PORT_STATUS_SS_SPEED 0x1c00 + //The feature requests with ports @@ -114,4 +121,16 @@ struct usb_port_status #define C_PORT_OVER_CURRENT 19 #define C_PORT_RESET 20 +// USB 3.0 spec table 10-8 +#define PORT_LINK_STATE 5 +#define PORT_U1_TIMEOUT 23 +#define PORT_U2_TIMEOUT 24 +#define C_PORT_LINK_STATE 25 +#define C_PORT_CONFIG_ERROR 26 +#define C_PORT_REMOTE_WAKE_MASK 27 +#define PORT_BH_PORT_RESET 28 +#define C_PORT_BH_PORT_RESET 29 +#define PORT_FORCE_LINKPM_STATE 30 + + #endif // _USBSPEC_PRIVATE_H diff --git a/src/add-ons/kernel/busses/usb/xhci.cpp b/src/add-ons/kernel/busses/usb/xhci.cpp index a67c50ea19..b249c4f2dc 100644 --- a/src/add-ons/kernel/busses/usb/xhci.cpp +++ b/src/add-ons/kernel/busses/usb/xhci.cpp @@ -7,6 +7,7 @@ * Authors: * Michael Lotz * Jian Chiang + * Jérôme Duval */ @@ -198,6 +199,10 @@ XHCI::XHCI(pci_info *info, Stack *stack) install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, InterruptHandler, (void *)this, 0); + memset(fPortSpeeds, 0, sizeof(fPortSpeeds)); + memset(fPortSlots, 0, sizeof(fPortSlots)); + memset(fDevices, 0, sizeof(fDevices)); + fInitOK = true; TRACE("XHCI host controller driver constructed\n"); } @@ -247,6 +252,35 @@ XHCI::Start() fSlotCount = HCS_MAX_SLOTS(capabilities); WriteOpReg(XHCI_CONFIG, fSlotCount); + // find out which protocol is used for each port + uint8 portFound = 0; + uint32 cparams = ReadCapReg32(XHCI_HCCPARAMS); + uint32 eec = 0xffffffff; + uint32 eecp = HCS0_XECP(cparams) << 2; + for (; eecp != 0 && XECP_NEXT(eec) && portFound < fPortCount; + eecp += XECP_NEXT(eec) << 2) { + eec = ReadCapReg32(eecp); + if (XECP_ID(eec) != XHCI_SUPPORTED_PROTOCOLS_CAPID) + continue; + if (XHCI_SUPPORTED_PROTOCOLS_0_MAJOR(eec) > 3) + continue; + uint32 temp = ReadCapReg32(eecp + 8); + uint32 offset = XHCI_SUPPORTED_PROTOCOLS_1_OFFSET(temp); + uint32 count = XHCI_SUPPORTED_PROTOCOLS_1_COUNT(temp); + if (offset == 0 || count == 0) + continue; + offset--; + for (uint32 i = offset; i < offset + count; i++) { + if (XHCI_SUPPORTED_PROTOCOLS_0_MAJOR(eec) == 0x3) + fPortSpeeds[i] = USB_SPEED_SUPER; + else + fPortSpeeds[i] = USB_SPEED_HIGHSPEED; + TRACE("speed for port %ld is %s\n", i, + fPortSpeeds[i] == USB_SPEED_SUPER ? "super" : "high"); + } + portFound += count; + } + uint32 params2 = ReadCapReg32(XHCI_HCSPARAMS2); fScratchpadCount = HCS_MAX_SC_BUFFERS(params2); if (fScratchpadCount > XHCI_MAX_SCRATCHPADS) { @@ -254,6 +288,10 @@ XHCI::Start() return B_ERROR; } + uint32 params3 = ReadCapReg32(XHCI_HCSPARAMS3); + fExitLatMax = HCS_U1_DEVICE_LATENCY(params3) + + HCS_U2_DEVICE_LATENCY(params3); + WriteOpReg(XHCI_DNCTRL, 0); // allocate Device Context Base Address array @@ -495,6 +533,272 @@ XHCI::AddTo(Stack *stack) } +Device * +XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort, + usb_speed speed) +{ + TRACE("AllocateDevice hubAddress %d hubPort %d speed %d\n", hubAddress, + hubPort, speed); + GetPortSpeed(hubPort - 1, &speed); + TRACE("speed %d\n", speed); + + uint8 slot = XHCI_MAX_SLOTS; + if (EnableSlot(&slot) != B_OK) { + TRACE_ERROR("AllocateDevice() failed enable slot\n"); + return NULL; + } + + if (slot > fSlotCount) { + TRACE_ERROR("AllocateDevice() bad slot\n"); + return NULL; + } + + if (fDevices[slot].state != XHCI_STATE_DISABLED) { + TRACE_ERROR("AllocateDevice() slot already used\n"); + return NULL; + } + + struct xhci_device *device = &fDevices[slot]; + memset(device, 0, sizeof(struct xhci_device)); + device->state = XHCI_STATE_ENABLED; + + device->input_ctx_area = fStack->AllocateArea((void **)&device->input_ctx, + (void**)&device->input_ctx_addr, sizeof(*device->input_ctx), "XHCI input context"); + if (device->input_ctx_area < B_OK) { + TRACE_ERROR("unable to create a input context area\n"); + return NULL; + } + + device->input_ctx->input.dropFlags = 0; + device->input_ctx->input.addFlags = 3; + + uint32 route = 0; + uint8 routePort = hubPort; + uint8 rhPort = 0; + for (Device *hubDevice = parent; hubDevice != RootObject(); + hubDevice = (Device *)hubDevice->Parent()) { + route *= 16; + if (hubPort > 15) + route += 15; + else + route += routePort; + rhPort = routePort; + routePort = hubDevice->HubPort(); + } + + device->input_ctx->slot.dwslot0 = SLOT_0_NUM_ENTRIES(1) | SLOT_0_ROUTE(route); + // add the speed + switch (speed) { + case USB_SPEED_LOWSPEED: + device->input_ctx->slot.dwslot0 |= SLOT_0_SPEED(2); + break; + case USB_SPEED_HIGHSPEED: + device->input_ctx->slot.dwslot0 |= SLOT_0_SPEED(3); + break; + case USB_SPEED_FULLSPEED: + device->input_ctx->slot.dwslot0 |= SLOT_0_SPEED(1); + break; + case USB_SPEED_SUPER: + device->input_ctx->slot.dwslot0 |= SLOT_0_SPEED(4); + break; + default: + TRACE_ERROR("unknown usb speed\n"); + break; + } + + device->input_ctx->slot.dwslot1 = SLOT_1_RH_PORT(rhPort); + device->input_ctx->slot.dwslot2 = SLOT_2_IRQ_TARGET(0); + if (0) + device->input_ctx->slot.dwslot2 |= SLOT_2_PORT_NUM(hubPort); + device->input_ctx->slot.dwslot3 = SLOT_3_SLOT_STATE(0) | SLOT_3_DEVICE_ADDRESS(0); + + TRACE("slot 0x%lx 0x%lx 0x%lx 0x%lx\n", device->input_ctx->slot.dwslot0, + device->input_ctx->slot.dwslot1, device->input_ctx->slot.dwslot2, + device->input_ctx->slot.dwslot3); + + device->device_ctx_area = fStack->AllocateArea((void **)&device->device_ctx, + (void**)&device->device_ctx_addr, sizeof(*device->device_ctx), "XHCI device context"); + if (device->device_ctx_area < B_OK) { + TRACE_ERROR("unable to create a device context area\n"); + delete_area(device->input_ctx_area); + return NULL; + } + + device->trb_area = fStack->AllocateArea((void **)&device->trbs, + (void**)&device->trb_addr, sizeof(*device->trbs), "XHCI endpoint trbs"); + if (device->trb_area < B_OK) { + TRACE_ERROR("unable to create a device trbs area\n"); + delete_area(device->input_ctx_area); + delete_area(device->device_ctx_area); + return NULL; + } + + for (uint32 i = 0; i < XHCI_MAX_ENDPOINTS; i++) { + struct xhci_trb *linkTrb = &(*device->trbs)[i][XHCI_MAX_TRANSFERS - 1]; + linkTrb->qwtrb0 = device->trb_addr + i * sizeof(device->trbs[0]); + linkTrb->dwtrb2 = TRB_2_IRQ(0); + linkTrb->dwtrb3 = TRB_3_CYCLE_BIT | TRB_3_TYPE(TRB_TYPE_LINK); + } + + // set up slot pointer to device context + fDcba->baseAddress[slot] = device->device_ctx_addr; + + size_t maxPacketSize; + switch (speed) { + case USB_SPEED_LOWSPEED: + case USB_SPEED_FULLSPEED: + maxPacketSize = 8; + break; + case USB_SPEED_HIGHSPEED: + maxPacketSize = 64; + break; + default: + maxPacketSize = 512; + break; + } + + // configure the Control endpoint 0 (type 4) + if (ConfigureEndpoint(slot, 0, 4, device->trb_addr, 0, 1, 1, 0, + maxPacketSize, maxPacketSize) != B_OK) { + TRACE_ERROR("unable to configure default control endpoint\n"); + return NULL; + } + + if (SetAddress(device->input_ctx_addr, 1, slot) != B_OK) { + TRACE_ERROR("unable to set address\n"); + return NULL; + } + + uint8 deviceAddress = SLOT_3_DEVICE_ADDRESS(device->input_ctx->slot.dwslot3); + + TRACE("deviceAddress 0x%x\n", deviceAddress); + + // Create a temporary pipe with the new address + ControlPipe pipe(parent); + pipe.InitCommon(deviceAddress, 0, speed, Pipe::Default, 8, 0, hubAddress, + hubPort); + + // Get the device descriptor + // Just retrieve the first 8 bytes of the descriptor -> minimum supported + // size of any device. It is enough because it includes the device type. + + size_t actualLength = 0; + usb_device_descriptor deviceDescriptor; + + TRACE("getting the device descriptor\n"); + pipe.SendRequest( + USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD, // type + USB_REQUEST_GET_DESCRIPTOR, // request + USB_DESCRIPTOR_DEVICE << 8, // value + 0, // index + 8, // length + (void *)&deviceDescriptor, // buffer + 8, // buffer length + &actualLength); // actual length + + if (actualLength != 8) { + TRACE_ERROR("error while getting the device descriptor\n"); + FreeAddress(deviceAddress); + return NULL; + } + + TRACE("creating new device\n"); + Device *deviceObject = new(std::nothrow) Device(parent, hubAddress, hubPort, + deviceDescriptor, deviceAddress, speed, false); + if (!deviceObject) { + TRACE_ERROR("no memory to allocate device\n"); + return NULL; + } + fPortSlots[hubPort] = slot; + TRACE("AllocateDevice() port %d slot %d\n", hubPort, slot); + return deviceObject; +} + + +void +XHCI::FreeDevice(Device *device) +{ + uint8 slot = fPortSlots[device->HubPort()]; + TRACE("FreeDevice() port %d slot %d\n", device->HubPort(), slot); + DisableSlot(slot); + fDcba->baseAddress[slot] = 0; + fPortSlots[device->HubPort()] = 0; + delete_area(fDevices[slot].trb_area); + delete_area(fDevices[slot].input_ctx_area); + delete_area(fDevices[slot].device_ctx_area); + fDevices[slot].state = XHCI_STATE_DISABLED; + delete device; +} + + +status_t +XHCI::ConfigureEndpoint(uint8 slot, uint8 number, uint8 type, uint64 ringAddr, uint16 interval, + uint8 maxPacketCount, uint8 mult, uint8 fpsShift, uint16 maxPacketSize, + uint16 maxFrameSize) +{ + struct xhci_device *device = &fDevices[slot]; + struct xhci_endpoint_ctx *endpoint = &device->input_ctx->endpoints[number]; + + if (mult == 0 || maxPacketCount == 0) + return B_BAD_VALUE; + + maxPacketCount--; + + endpoint->dwendpoint0 = ENDPOINT_0_STATE(0) | ENDPOINT_0_MAXPSTREAMS(0); + // add mult for isochronous and interrupt types + // add interval + endpoint->dwendpoint1 = ENDPOINT_1_EPTYPE(type) + | ENDPOINT_1_MAXBURST(maxPacketCount) + | ENDPOINT_1_MAXPACKETSIZE(maxPacketSize) + | ENDPOINT_1_CERR(3); + endpoint->qwendpoint2 = ENDPOINT_2_DCS_BIT | ringAddr; + // 8 for Control endpoint + switch (type) { + case 4: + endpoint->dwendpoint4 = ENDPOINT_4_AVGTRBLENGTH(8); + break; + case 1: + case 3: + case 5: + case 7: + endpoint->dwendpoint4 = ENDPOINT_4_AVGTRBLENGTH(maxFrameSize) + | ENDPOINT_4_MAXESITPAYLOAD(maxFrameSize); + break; + } + + TRACE("endpoint 0x%lx 0x%lx 0x%llx 0x%lx\n", endpoint->dwendpoint0, + endpoint->dwendpoint1, endpoint->qwendpoint2, endpoint->dwendpoint4); + + return B_OK; +} + + +status_t +XHCI::GetPortSpeed(uint8 index, usb_speed *speed) +{ + if (fPortSpeeds[index] == USB_SPEED_SUPER) + *speed = USB_SPEED_SUPER; + else { + uint32 portStatus = ReadOpReg(XHCI_PORTSC(index)); + + switch (PS_SPEED_GET(portStatus)) { + case 3: + *speed = USB_SPEED_HIGHSPEED; + break; + case 2: + *speed = USB_SPEED_LOWSPEED; + break; + case 1: + *speed = USB_SPEED_FULLSPEED; + break; + default: + *speed = USB_SPEED_SUPER; + } + } + return B_OK; +} + + status_t XHCI::GetPortStatus(uint8 index, usb_port_status *status) { @@ -503,7 +807,7 @@ XHCI::GetPortStatus(uint8 index, usb_port_status *status) status->status = status->change = 0; uint32 portStatus = ReadOpReg(XHCI_PORTSC(index)); - TRACE("port status=0x%08lx\n", portStatus); + //TRACE("port status=0x%08lx\n", portStatus); // build the status switch (PS_SPEED_GET(portStatus)) { @@ -525,8 +829,12 @@ XHCI::GetPortStatus(uint8 index, usb_port_status *status) status->status |= PORT_STATUS_OVER_CURRENT; if (portStatus & PS_PR) status->status |= PORT_STATUS_RESET; - if (portStatus & PS_PP) - status->status |= PORT_STATUS_POWER; + if (portStatus & PS_PP) { + if (fPortSpeeds[index] == USB_SPEED_SUPER) + status->status |= PORT_STATUS_SS_POWER; + else + status->status |= PORT_STATUS_POWER; + } // build the change if (portStatus & PS_CSC) @@ -538,6 +846,13 @@ XHCI::GetPortStatus(uint8 index, usb_port_status *status) if (portStatus & PS_PRC) status->change |= PORT_STATUS_RESET; + if (fPortSpeeds[index] == USB_SPEED_SUPER) { + if (portStatus & PS_PLC) + status->change |= PORT_LINK_STATE; + if (portStatus & PS_WRC) + status->change |= PORT_BH_PORT_RESET; + } + return B_OK; } @@ -573,6 +888,7 @@ XHCI::SetPortFeature(uint8 index, uint16 feature) default: return B_BAD_VALUE; } + ReadOpReg(portRegister); return B_OK; } @@ -598,28 +914,31 @@ XHCI::ClearPortFeature(uint8 index, uint16 feature) portStatus &= ~PS_PLS_MASK; WriteOpReg(portRegister, portStatus | PS_XDEV_U0 | PS_LWS); } - return B_OK; + break; case PORT_ENABLE: WriteOpReg(portRegister, portStatus | PS_PED); - return B_OK; + break; case PORT_POWER: WriteOpReg(portRegister, portStatus & ~PS_PP); - return B_OK; + break; case C_PORT_CONNECTION: WriteOpReg(portRegister, portStatus | PS_CSC); - return B_OK; + break; case C_PORT_ENABLE: WriteOpReg(portRegister, portStatus | PS_PEC); - return B_OK; + break; case C_PORT_OVER_CURRENT: WriteOpReg(portRegister, portStatus | PS_OCC); - return B_OK; + break; case C_PORT_RESET: WriteOpReg(portRegister, portStatus | PS_PRC); - return B_OK; + break; + default: + return B_BAD_VALUE; } - return B_BAD_VALUE; + ReadOpReg(portRegister); + return B_OK; } diff --git a/src/add-ons/kernel/busses/usb/xhci.h b/src/add-ons/kernel/busses/usb/xhci.h index f35e8dbb6a..124c857e9a 100644 --- a/src/add-ons/kernel/busses/usb/xhci.h +++ b/src/add-ons/kernel/busses/usb/xhci.h @@ -5,6 +5,7 @@ * Authors: * Michael Lotz * Jian Chiang + * Jérôme Duval */ #ifndef XHCI_H #define XHCI_H @@ -19,6 +20,30 @@ struct pci_module_info; class XHCIRootHub; +enum xhci_state { + XHCI_STATE_DISABLED = 0, + XHCI_STATE_ENABLED, + XHCI_STATE_ADDRESSED, + XHCI_STATE_CONFIGURED, +}; + + +struct xhci_device { + enum xhci_state state; + area_id trb_area; + addr_t trb_addr; + struct xhci_trb (*trbs)[XHCI_MAX_ENDPOINTS - 1][XHCI_MAX_TRANSFERS]; + + area_id input_ctx_area; + addr_t input_ctx_addr; + struct xhci_input_device_ctx *input_ctx; + + area_id device_ctx_area; + addr_t device_ctx_addr; + struct xhci_device_ctx *device_ctx; +}; + + class XHCI : public BusManager { public: XHCI(pci_info *info, Stack *stack); @@ -33,12 +58,25 @@ public: static status_t AddTo(Stack *stack); + virtual Device * AllocateDevice(Hub *parent, + int8 hubAddress, uint8 hubPort, + usb_speed speed); + status_t ConfigureEndpoint(uint8 slot, uint8 number, + uint8 type, uint64 ringAddr, + uint16 interval, uint8 maxPacketCount, + uint8 mult, uint8 fpsShift, + uint16 maxPacketSize, uint16 maxFrameSize); + virtual void FreeDevice(Device *device); + // Port operations for root hub uint8 PortCount() const { return fPortCount; } - status_t GetPortStatus(uint8 index, usb_port_status *status); + status_t GetPortStatus(uint8 index, + usb_port_status *status); status_t SetPortFeature(uint8 index, uint16 feature); status_t ClearPortFeature(uint8 index, uint16 feature); + status_t GetPortSpeed(uint8 index, usb_speed *speed); + virtual const char * TypeName() const { return "xhci"; } private: @@ -131,16 +169,23 @@ private: // Port management uint8 fPortCount; uint8 fSlotCount; + usb_speed fPortSpeeds[XHCI_MAX_PORTS]; + uint8 fPortSlots[XHCI_MAX_PORTS]; // Scratchpad uint8 fScratchpadCount; area_id fScratchpadArea[XHCI_MAX_SCRATCHPADS]; void * fScratchpad[XHCI_MAX_SCRATCHPADS]; + // Devices + struct xhci_device fDevices[XHCI_MAX_DEVICES]; + uint16 fEventIdx; uint16 fCmdIdx; uint8 fEventCcs; uint8 fCmdCcs; + + uint32 fExitLatMax; }; diff --git a/src/add-ons/kernel/busses/usb/xhci_hardware.h b/src/add-ons/kernel/busses/usb/xhci_hardware.h index 2838981591..1b567ec1b5 100644 --- a/src/add-ons/kernel/busses/usb/xhci_hardware.h +++ b/src/add-ons/kernel/busses/usb/xhci_hardware.h @@ -4,6 +4,7 @@ * * Authors: * Jian Chiang + * Jérôme Duval */ #ifndef XHCI_HARDWARE_H #define XHCI_HARDWARE_H @@ -92,6 +93,14 @@ #define XHCI_LEGCTLSTS 0x04 #define XHCI_LEGCTLSTS_DISABLE_SMI ((0x3 << 1) + (0xff << 5) + (0x7 << 17)) +#define XHCI_SUPPORTED_PROTOCOLS_CAPID 0x02 +#define XHCI_SUPPORTED_PROTOCOLS_0_MINOR(x) (((x) >> 16) & 0xff) +#define XHCI_SUPPORTED_PROTOCOLS_0_MAJOR(x) (((x) >> 24) & 0xff) + +#define XHCI_SUPPORTED_PROTOCOLS_1_COUNT(x) (((x) >> 8) & 0xff) +#define XHCI_SUPPORTED_PROTOCOLS_1_OFFSET(x) (((x) >> 0) & 0xff) + + // Port status Registers // Section 5.4.8 @@ -244,9 +253,12 @@ #define XHCI_MAX_EVENTS (16 * 13) #define XHCI_MAX_COMMANDS (16 * 1) -#define XHCI_MAX_SLOTS 256 +#define XHCI_MAX_SLOTS 255 #define XHCI_MAX_PORTS 127 +#define XHCI_MAX_ENDPOINTS 32 #define XHCI_MAX_SCRATCHPADS 32 +#define XHCI_MAX_DEVICES 128 +#define XHCI_MAX_TRANSFERS 4 struct xhci_trb { @@ -286,4 +298,106 @@ struct xhci_device_context_array { }; +struct xhci_slot_ctx { + uint32 dwslot0; + uint32 dwslot1; + uint32 dwslot2; + uint32 dwslot3; + uint32 reserved[4]; +}; + +#define SLOT_0_ROUTE(x) ((x) & 0xFFFFF) +#define SLOT_0_ROUTE_GET(x) ((x) & 0xFFFFF) +#define SLOT_0_SPEED(x) (((x) & 0xF) << 20) +#define SLOT_0_SPEED_GET(x) (((x) >> 20) & 0xF) +#define SLOT_0_MTT_BIT (1U << 25) +#define SLOT_0_HUB_BIT (1U << 26) +#define SLOT_0_NUM_ENTRIES(x) (((x) & 0x1F) << 27) +#define SLOT_0_NUM_ENTRIES_GET(x) (((x) >> 27) & 0x1F) + +#define SLOT_1_MAX_EXIT_LATENCY(x) ((x) & 0xFFFF) +#define SLOT_1_MAX_EXIT_LATENCY_GET(x) ((x) & 0xFFFF) +#define SLOT_1_RH_PORT(x) (((x) & 0xFF) << 16) +#define SLOT_1_RH_PORT_GET(x) (((x) >> 16) & 0xFF) +#define SLOT_1_NUM_PORTS(x) (((x) & 0xFF) << 24) +#define SLOT_1_NUM_PORTS_GET(x) (((x) >> 24) & 0xFF) + +#define SLOT_2_TT_HUB_SLOT(x) ((x) & 0xFF) +#define SLOT_2_TT_HUB_SLOT(x) ((x) & 0xFF) +#define SLOT_2_PORT_NUM(x) (((x) & 0xFF) << 8) +#define SLOT_2_PORT_NUM_GET(x) (((x) >> 8) & 0xFF) +#define SLOT_2_TT_TIME(x) (((x) & 0x3) << 16) +#define SLOT_2_TT_TIME_GET(x) (((x) >> 16) & 0x3) +#define SLOT_2_IRQ_TARGET(x) (((x) & 0x1F) << 27) +#define SLOT_2_IRQ_TARGET_GET(x) (((x) >> 27) & 0x1f) + +#define SLOT_3_DEVICE_ADDRESS(x) ((x) & 0xFF) +#define SLOT_3_DEVICE_ADDRESS_GET(x) ((x) & 0xFF) +#define SLOT_3_SLOT_STATE(x) (((x) & 0x1F) << 27) +#define SLOT_3_SLOT_STATE_GET(x) (((x) >> 27) & 0x1F) + + +struct xhci_endpoint_ctx { + uint32 dwendpoint0; + uint32 dwendpoint1; + uint64 qwendpoint2; + uint32 dwendpoint4; + uint32 reserved[3]; +}; + + +#define ENDPOINT_0_STATE(x) ((x) & 0x3) +#define ENDPOINT_0_STATE_GET(x) ((x) & 0x3) +#define ENDPOINT_0_MULT(x) (((x) & 0x3) << 8) +#define ENDPOINT_0_MULT_GET(x) (((x) >> 8) & 0x3) +#define ENDPOINT_0_MAXPSTREAMS(x) (((x) & 0x1F) << 10) +#define ENDPOINT_0_MAXPSTREAMS_GET(x) (((x) >> 10) & 0x1F) +#define ENDPOINT_0_LSA_BIT (1U << 15) +#define ENDPOINT_0_INTERVAL(x) (((x) & 0xFF) << 16) +#define ENDPOINT_0_INTERVAL_GET(x) (((x) >> 16) & 0xFF) + +#define ENDPOINT_1_CERR(x) (((x) & 0x3) << 1) +#define ENDPOINT_1_CERR_GET(x) (((x) >> 1) & 0x3) +#define ENDPOINT_1_EPTYPE(x) (((x) & 0x7) << 3) +#define ENDPOINT_1_EPTYPE_GET(x) (((x) >> 3) & 0x7) +#define ENDPOINT_1_HID_BIT (1U << 7) +#define ENDPOINT_1_MAXBURST(x) (((x) & 0xFF) << 8) +#define ENDPOINT_1_MAXBURST_GET(x) (((x) >> 8) & 0xFF) +#define ENDPOINT_1_MAXPACKETSIZE(x) (((x) & 0xFFFF) << 16) +#define ENDPOINT_1_MAXPACKETSIZE_GET(x) (((x) >> 16) & 0xFFFF) + +#define ENDPOINT_2_DCS_BIT (1U << 0) + +#define ENDPOINT_4_AVGTRBLENGTH(x) ((x) & 0xFFFF) +#define ENDPOINT_4_AVGTRBLENGTH_GET(x) ((x) & 0xFFFF) +#define ENDPOINT_4_MAXESITPAYLOAD(x) (((x) & 0xFFFF) << 16) +#define ENDPOINT_4_MAXESITPAYLOAD_GET(x) (((x) >> 16) & 0xFFFF) + + +struct xhci_stream_ctx { + uint64 qwstream0; + uint32 reserved[2]; +}; + + +struct xhci_input_ctx { + uint32 dropFlags; + uint32 addFlags; + uint32 reserved[6]; +}; + + +struct xhci_input_device_ctx { + struct xhci_input_ctx input; + struct xhci_slot_ctx slot; + struct xhci_endpoint_ctx endpoints[XHCI_MAX_ENDPOINTS - 1]; +}; + + +struct xhci_device_ctx { + struct xhci_slot_ctx slot; + struct xhci_endpoint_ctx endpoints[XHCI_MAX_ENDPOINTS - 1]; +}; + + #endif // !XHCI_HARDWARE_H diff --git a/src/add-ons/kernel/busses/usb/xhci_rh.cpp b/src/add-ons/kernel/busses/usb/xhci_rh.cpp index 7b7cbd3894..514850f02a 100644 --- a/src/add-ons/kernel/busses/usb/xhci_rh.cpp +++ b/src/add-ons/kernel/busses/usb/xhci_rh.cpp @@ -8,7 +8,6 @@ */ -#define TRACE_USB #include "xhci.h" #define USB_MODULE_NAME "xhci roothub"