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.
This commit is contained in:
parent
d11be97572
commit
319a3798bc
@ -7,6 +7,7 @@
|
||||
* Niels S. Reedijk
|
||||
*/
|
||||
|
||||
|
||||
#include "usb_private.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -7,6 +7,7 @@
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* Jian Chiang <j.jian.chiang@gmail.com>
|
||||
* Jérôme Duval <jerome.duval@gmail.com>
|
||||
*/
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Authors:
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* Jian Chiang <j.jian.chiang@gmail.com>
|
||||
* Jérôme Duval <jerome.duval@gmail.com>
|
||||
*/
|
||||
#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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
*
|
||||
* Authors:
|
||||
* Jian Chiang <j.jian.chiang@gmail.com>
|
||||
* Jérôme Duval <jerome.duval@gmail.com>
|
||||
*/
|
||||
#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
|
||||
|
@ -8,7 +8,6 @@
|
||||
*/
|
||||
|
||||
|
||||
#define TRACE_USB
|
||||
#include "xhci.h"
|
||||
|
||||
#define USB_MODULE_NAME "xhci roothub"
|
||||
|
Loading…
Reference in New Issue
Block a user