XHCI improvements
* remove the xhci cmd complete thread * creation of the scratchpad area * wait for running status after starting the controller * increase delays on controller reset (250ms instead of 100ms) * use of SpinLocker from AutoLock.h * add a DoCommand() method to queue a command, ring and wait for the event response * add a method for each command * XHCI_PORTSC macro was off 1 port * add definitions for TRB types, Completion Codes.
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
#include <USB3.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <util/AutoLock.h>
|
||||
|
||||
#define TRACE_USB
|
||||
#include "xhci.h"
|
||||
|
||||
@@ -67,7 +69,6 @@ XHCI::XHCI(pci_info *info, Stack *stack)
|
||||
fDcbaArea(-1),
|
||||
fSpinlock(B_SPINLOCK_INITIALIZER),
|
||||
fCmdCompSem(-1),
|
||||
fCmdCompThread(-1),
|
||||
fFinishTransfersSem(-1),
|
||||
fFinishThread(-1),
|
||||
fStopThreads(false),
|
||||
@@ -75,6 +76,7 @@ XHCI::XHCI(pci_info *info, Stack *stack)
|
||||
fRootHubAddress(0),
|
||||
fPortCount(0),
|
||||
fSlotCount(0),
|
||||
fScratchpadCount(0),
|
||||
fEventIdx(0),
|
||||
fCmdIdx(0),
|
||||
fEventCcs(1),
|
||||
@@ -99,13 +101,13 @@ XHCI::XHCI(pci_info *info, Stack *stack)
|
||||
|
||||
// map the registers
|
||||
uint32 offset = fPCIInfo->u.h0.base_registers[0] & (B_PAGE_SIZE - 1);
|
||||
addr_t physicalAddress = fPCIInfo->u.h0.base_registers[0] - offset;
|
||||
phys_addr_t physicalAddress = fPCIInfo->u.h0.base_registers[0] - offset;
|
||||
size_t mapSize = (fPCIInfo->u.h0.base_register_sizes[0] + offset
|
||||
+ B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
|
||||
|
||||
TRACE("map physical memory 0x%08lx (base: 0x%08lx; offset: %lx); size: %ld\n",
|
||||
fPCIInfo->u.h0.base_registers[0], physicalAddress, offset,
|
||||
fPCIInfo->u.h0.base_register_sizes[0]);
|
||||
TRACE("map physical memory 0x%08lx (base: 0x%08" B_PRIxPHYSADDR "; offset:"
|
||||
" %lx); size: %ld\n", fPCIInfo->u.h0.base_registers[0],
|
||||
physicalAddress, offset, fPCIInfo->u.h0.base_register_sizes[0]);
|
||||
|
||||
fRegisterArea = map_physical_memory("XHCI memory mapped registers",
|
||||
physicalAddress, mapSize, B_ANY_KERNEL_BLOCK_ADDRESS,
|
||||
@@ -191,11 +193,6 @@ XHCI::XHCI(pci_info *info, Stack *stack)
|
||||
B_NORMAL_PRIORITY, (void *)this);
|
||||
resume_thread(fFinishThread);
|
||||
|
||||
// create command complete service thread
|
||||
fCmdCompThread = spawn_kernel_thread(CmdCompThread, "xhci cmd complete thread",
|
||||
B_NORMAL_PRIORITY, (void *)this);
|
||||
resume_thread(fCmdCompThread);
|
||||
|
||||
// Install the interrupt handler
|
||||
TRACE("installing interrupt handler\n");
|
||||
install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
|
||||
@@ -218,8 +215,9 @@ XHCI::~XHCI()
|
||||
delete_sem(fFinishTransfersSem);
|
||||
delete_area(fRegisterArea);
|
||||
delete_area(fErstArea);
|
||||
for (uint32 i = 0; i < fScratchpadCount; i++)
|
||||
delete_area(fScratchpadArea[i]);
|
||||
delete_area(fDcbaArea);
|
||||
wait_for_thread(fCmdCompThread, &result);
|
||||
wait_for_thread(fFinishThread, &result);
|
||||
put_module(B_PCI_MODULE_NAME);
|
||||
}
|
||||
@@ -240,29 +238,60 @@ XHCI::Start()
|
||||
// read port count from capability register
|
||||
uint32 capabilities = ReadCapReg32(XHCI_HCSPARAMS1);
|
||||
|
||||
uint8 portsCount = HCS_MAX_PORTS(capabilities);
|
||||
if (portsCount == 0) {
|
||||
TRACE_ERROR("Invalid number of ports: %u\n", portsCount);
|
||||
fPortCount = HCS_MAX_PORTS(capabilities);
|
||||
if (fPortCount == 0) {
|
||||
TRACE_ERROR("Invalid number of ports: %u\n", fPortCount);
|
||||
fPortCount = 0;
|
||||
return B_ERROR;
|
||||
}
|
||||
fPortCount = portsCount;
|
||||
fSlotCount = HCS_MAX_SLOTS(capabilities);
|
||||
WriteOpReg(XHCI_CONFIG, fSlotCount);
|
||||
|
||||
void *dmaAddress;
|
||||
fDcbaArea = fStack->AllocateArea((void **)&fDcba, &dmaAddress,
|
||||
sizeof(uint64) * XHCI_MAX_SLOTS, "DCBA Area");
|
||||
uint32 params2 = ReadCapReg32(XHCI_HCSPARAMS2);
|
||||
fScratchpadCount = HCS_MAX_SC_BUFFERS(params2);
|
||||
if (fScratchpadCount > XHCI_MAX_SCRATCHPADS) {
|
||||
TRACE_ERROR("Invalid number of scratchpads: %u\n", fScratchpadCount);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
WriteOpReg(XHCI_DNCTRL, 0);
|
||||
|
||||
// allocate Device Context Base Address array
|
||||
addr_t dmaAddress;
|
||||
fDcbaArea = fStack->AllocateArea((void **)&fDcba, (void**)&dmaAddress,
|
||||
sizeof(*fDcba), "DCBA Area");
|
||||
if (fDcbaArea < B_OK) {
|
||||
TRACE_ERROR("unable to create the DCBA area\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
memset(fDcba, 0, sizeof(uint64) * XHCI_MAX_SLOTS);
|
||||
TRACE("setting DCBAAP\n");
|
||||
WriteOpReg(XHCI_DCBAAP_LO, (uint32)dmaAddress);
|
||||
WriteOpReg(XHCI_DCBAAP_HI, 0);
|
||||
memset(fDcba, 0, sizeof(*fDcba));
|
||||
memset(fScratchpadArea, 0, sizeof(fScratchpadArea));
|
||||
memset(fScratchpad, 0, sizeof(fScratchpad));
|
||||
|
||||
fErstArea = fStack->AllocateArea((void **)&fErst, &dmaAddress,
|
||||
(MAX_COMMANDS + MAX_EVENTS) * sizeof(xhci_trb)
|
||||
// setting the first address to the scratchpad array address
|
||||
fDcba->baseAddress[0] = dmaAddress
|
||||
+ offsetof(struct xhci_device_context_array, scratchpad);
|
||||
|
||||
// fill up the scratchpad array with scratchpad pages
|
||||
for (uint32 i = 0; i < fScratchpadCount; i++) {
|
||||
addr_t scratchDmaAddress;
|
||||
fScratchpadArea[i] = fStack->AllocateArea((void **)&fScratchpad[i],
|
||||
(void**)&scratchDmaAddress, B_PAGE_SIZE, "Scratchpad Area");
|
||||
if (fScratchpadArea[i] < B_OK) {
|
||||
TRACE_ERROR("unable to create the scratchpad area\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
fDcba->scratchpad[i] = scratchDmaAddress;
|
||||
}
|
||||
|
||||
TRACE("setting DCBAAP %lx\n", dmaAddress);
|
||||
WriteOpReg(XHCI_DCBAAP_LO, (uint32)dmaAddress);
|
||||
WriteOpReg(XHCI_DCBAAP_HI, /*(uint32)(dmaAddress >> 32)*/0);
|
||||
|
||||
// allocate Event Ring Segment Table
|
||||
uint8 *addr;
|
||||
fErstArea = fStack->AllocateArea((void **)&addr, (void**)&dmaAddress,
|
||||
(XHCI_MAX_COMMANDS + XHCI_MAX_EVENTS) * sizeof(xhci_trb)
|
||||
+ sizeof(xhci_erst_element),
|
||||
"USB XHCI ERST CMD_RING and EVENT_RING Area");
|
||||
|
||||
@@ -271,16 +300,18 @@ XHCI::Start()
|
||||
delete_area(fDcbaArea);
|
||||
return B_ERROR;
|
||||
}
|
||||
memset(fErst, 0, (MAX_COMMANDS + MAX_EVENTS) * sizeof(xhci_trb)
|
||||
fErst = (xhci_erst_element *)addr;
|
||||
memset(fErst, 0, (XHCI_MAX_COMMANDS + XHCI_MAX_EVENTS) * sizeof(xhci_trb)
|
||||
+ sizeof(xhci_erst_element));
|
||||
|
||||
fErst->rs_addr = (uint32)dmaAddress + sizeof(xhci_erst_element);
|
||||
fErst->rs_size = MAX_EVENTS;
|
||||
// fill with Event Ring Segment Base Address and Event Ring Segment Size
|
||||
fErst->rs_addr = (uint64)(dmaAddress + sizeof(xhci_erst_element));
|
||||
fErst->rs_size = XHCI_MAX_EVENTS;
|
||||
fErst->rsvdz = 0;
|
||||
|
||||
uint32 addr = (uint32)fErst + sizeof(xhci_erst_element);
|
||||
addr += sizeof(xhci_erst_element);
|
||||
fEventRing = (xhci_trb *)addr;
|
||||
addr += MAX_EVENTS * sizeof(xhci_trb);
|
||||
addr += XHCI_MAX_EVENTS * sizeof(xhci_trb);
|
||||
fCmdRing = (xhci_trb *)addr;
|
||||
|
||||
TRACE("setting ERST size\n");
|
||||
@@ -288,27 +319,37 @@ XHCI::Start()
|
||||
|
||||
TRACE("setting ERDP addr = 0x%llx\n", fErst->rs_addr);
|
||||
WriteRunReg32(XHCI_ERDP_LO(0), (uint32)fErst->rs_addr);
|
||||
WriteRunReg32(XHCI_ERDP_HI(0), (uint32)(fErst->rs_addr >> 32));
|
||||
WriteRunReg32(XHCI_ERDP_HI(0), /*(uint32)(fErst->rs_addr >> 32)*/0);
|
||||
|
||||
TRACE("setting ERST base addr = 0x%llx\n", (uint64)dmaAddress);
|
||||
TRACE("setting ERST base addr = 0x%lx\n", dmaAddress);
|
||||
WriteRunReg32(XHCI_ERSTBA_LO(0), (uint32)dmaAddress);
|
||||
WriteRunReg32(XHCI_ERSTBA_HI(0), 0);
|
||||
WriteRunReg32(XHCI_ERSTBA_HI(0), /*(uint32)(dmaAddress >> 32)*/0);
|
||||
|
||||
addr = fErst->rs_addr + MAX_EVENTS * sizeof(xhci_trb);
|
||||
TRACE("setting CRCR addr = 0x%llx\n", (uint64)addr);
|
||||
WriteOpReg(XHCI_CRCR_LO, addr | CRCR_RCS);
|
||||
WriteOpReg(XHCI_CRCR_HI, 0);
|
||||
dmaAddress += sizeof(xhci_erst_element) + XHCI_MAX_EVENTS * sizeof(xhci_trb);
|
||||
TRACE("setting CRCR addr = 0x%lx\n", dmaAddress);
|
||||
WriteOpReg(XHCI_CRCR_LO, (uint32)dmaAddress | CRCR_RCS);
|
||||
WriteOpReg(XHCI_CRCR_HI, /*(uint32)(dmaAddress >> 32)*/0);
|
||||
//link trb
|
||||
fCmdRing[MAX_COMMANDS - 1].qwtrb0 = addr;
|
||||
fCmdRing[XHCI_MAX_COMMANDS - 1].qwtrb0 = dmaAddress;
|
||||
|
||||
TRACE("setting interrupt rate\n");
|
||||
WriteRunReg32(XHCI_IMOD(0), 160);//4000 irq/s
|
||||
WriteRunReg32(XHCI_IMOD(0), 160); // 25000 irq/s
|
||||
|
||||
TRACE("enabling interrupt\n");
|
||||
WriteRunReg32(XHCI_IMAN(0), ReadRunReg32(XHCI_IMAN(0)) | IMAN_INTR_ENA);
|
||||
|
||||
WriteOpReg(XHCI_CMD, CMD_RUN | CMD_EIE | CMD_HSEIE);
|
||||
|
||||
// wait for start up state
|
||||
int32 tries = 100;
|
||||
while ((ReadOpReg(XHCI_STS) & STS_HCH) != 0) {
|
||||
snooze(1000);
|
||||
if (tries-- < 0) {
|
||||
TRACE_ERROR("start up timeout\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fRootHubAddress = AllocateAddress();
|
||||
fRootHub = new(std::nothrow) XHCIRootHub(RootObject(), fRootHubAddress);
|
||||
if (!fRootHub) {
|
||||
@@ -324,8 +365,10 @@ XHCI::Start()
|
||||
SetRootHub(fRootHub);
|
||||
|
||||
TRACE_ALWAYS("successfully started the controller\n");
|
||||
#ifdef TRACE_USB
|
||||
TRACE("No-Op test\n");
|
||||
QueueNoop();
|
||||
Noop();
|
||||
#endif
|
||||
return BusManager::Start();
|
||||
}
|
||||
|
||||
@@ -337,6 +380,11 @@ XHCI::SubmitTransfer(Transfer *transfer)
|
||||
if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress)
|
||||
return fRootHub->ProcessTransfer(this, transfer);
|
||||
|
||||
TRACE("SubmitTransfer()\n");
|
||||
Pipe *pipe = transfer->TransferPipe();
|
||||
if (pipe->Type() & USB_OBJECT_ISO_PIPE)
|
||||
return B_UNSUPPORTED;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -458,7 +506,7 @@ XHCI::GetPortStatus(uint8 index, usb_port_status *status)
|
||||
TRACE("port status=0x%08lx\n", portStatus);
|
||||
|
||||
// build the status
|
||||
switch(PS_SPEED_GET(portStatus)) {
|
||||
switch (PS_SPEED_GET(portStatus)) {
|
||||
case 3:
|
||||
status->status |= PORT_STATUS_HIGH_SPEED;
|
||||
break;
|
||||
@@ -502,32 +550,30 @@ XHCI::SetPortFeature(uint8 index, uint16 feature)
|
||||
return B_BAD_INDEX;
|
||||
|
||||
uint32 portRegister = XHCI_PORTSC(index);
|
||||
uint32 portStatus = ReadOpReg(portRegister);
|
||||
uint32 portStatus = ReadOpReg(portRegister) & ~PS_CLEAR;
|
||||
|
||||
switch (feature) {
|
||||
case PORT_SUSPEND:
|
||||
if ((portStatus & PS_PED ) == 0 || (portStatus & PS_PR)
|
||||
if ((portStatus & PS_PED) == 0 || (portStatus & PS_PR)
|
||||
|| (portStatus & PS_PLS_MASK) >= PS_XDEV_U3) {
|
||||
TRACE_ERROR("USB core suspending device not in U0/U1/U2.\n");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
portStatus &= ~PS_CLEAR;
|
||||
portStatus &= ~PS_PLS_MASK;
|
||||
portStatus |= PS_LWS | PS_XDEV_U3;
|
||||
WriteOpReg(portRegister, portStatus);
|
||||
return B_OK;
|
||||
WriteOpReg(portRegister, portStatus | PS_LWS | PS_XDEV_U3);
|
||||
break;
|
||||
|
||||
case PORT_RESET:
|
||||
portStatus &= ~PS_CLEAR;
|
||||
WriteOpReg(portRegister, portStatus | PS_PR);
|
||||
return B_OK;
|
||||
break;
|
||||
|
||||
case PORT_POWER:
|
||||
portStatus &= ~PS_CLEAR;
|
||||
WriteOpReg(portRegister, portStatus | PS_PP);
|
||||
return B_OK;
|
||||
break;
|
||||
default:
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
return B_BAD_VALUE;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -539,8 +585,7 @@ XHCI::ClearPortFeature(uint8 index, uint16 feature)
|
||||
return B_BAD_INDEX;
|
||||
|
||||
uint32 portRegister = XHCI_PORTSC(index);
|
||||
uint32 portStatus = ReadOpReg(portRegister);
|
||||
portStatus &= ~PS_CLEAR;
|
||||
uint32 portStatus = ReadOpReg(portRegister) & ~PS_CLEAR;
|
||||
|
||||
switch (feature) {
|
||||
case PORT_SUSPEND:
|
||||
@@ -550,7 +595,6 @@ XHCI::ClearPortFeature(uint8 index, uint16 feature)
|
||||
if (portStatus & PS_XDEV_U3) {
|
||||
if ((portStatus & PS_PED) == 0)
|
||||
return B_BAD_VALUE;
|
||||
portStatus &= ~PS_CLEAR;
|
||||
portStatus &= ~PS_PLS_MASK;
|
||||
WriteOpReg(portRegister, portStatus | PS_XDEV_U0 | PS_LWS);
|
||||
}
|
||||
@@ -598,20 +642,26 @@ XHCI::ControllerHalt()
|
||||
status_t
|
||||
XHCI::ControllerReset()
|
||||
{
|
||||
WriteOpReg(XHCI_CMD, CMD_HCRST);
|
||||
TRACE("ControllerReset() cmd: 0x%lx sts: 0x%lx\n", ReadOpReg(XHCI_CMD),
|
||||
ReadOpReg(XHCI_STS));
|
||||
WriteOpReg(XHCI_CMD, ReadOpReg(XHCI_CMD) | CMD_HCRST);
|
||||
|
||||
int32 tries = 100;
|
||||
int32 tries = 250;
|
||||
while (ReadOpReg(XHCI_CMD) & CMD_HCRST) {
|
||||
snooze(1000);
|
||||
if (tries-- < 0)
|
||||
if (tries-- < 0) {
|
||||
TRACE("ControllerReset() failed CMD_HCRST\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
tries = 100;
|
||||
tries = 250;
|
||||
while (ReadOpReg(XHCI_STS) & STS_CNR) {
|
||||
snooze(1000);
|
||||
if (tries-- < 0)
|
||||
if (tries-- < 0) {
|
||||
TRACE("ControllerReset() failed STS_CNR\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
@@ -628,7 +678,7 @@ XHCI::InterruptHandler(void *data)
|
||||
int32
|
||||
XHCI::Interrupt()
|
||||
{
|
||||
acquire_spinlock(&fSpinlock);
|
||||
SpinLocker _(&fSpinlock);
|
||||
|
||||
uint32 status = ReadOpReg(XHCI_STS);
|
||||
uint32 temp = ReadRunReg32(XHCI_IMAN(0));
|
||||
@@ -637,7 +687,11 @@ XHCI::Interrupt()
|
||||
TRACE("STS: %lx IRQ_PENDING: %lx\n", status, temp);
|
||||
|
||||
int32 result = B_HANDLED_INTERRUPT;
|
||||
|
||||
|
||||
if (status & STS_HCH) {
|
||||
TRACE_ERROR("Host Controller halted\n");
|
||||
return result;
|
||||
}
|
||||
if (status & STS_HSE) {
|
||||
TRACE_ERROR("Host System Error\n");
|
||||
return result;
|
||||
@@ -649,19 +703,19 @@ XHCI::Interrupt()
|
||||
uint16 i = fEventIdx;
|
||||
uint8 j = fEventCcs;
|
||||
uint8 t = 2;
|
||||
|
||||
|
||||
while (1) {
|
||||
temp = fEventRing[i].dwtrb3;
|
||||
uint8 k = (temp & TRB_3_CYCLE_BIT) ? 1 : 0;
|
||||
if (j != k)
|
||||
break;
|
||||
|
||||
uint8 event = TRB_TYPE_GET(temp);
|
||||
uint8 event = TRB_3_TYPE_GET(temp);
|
||||
|
||||
TRACE("event[%u] = %u (0x%016llx 0x%08lx 0x%08lx)\n", i, event,
|
||||
fEventRing[i].qwtrb0, fEventRing[i].dwtrb2, fEventRing[i].dwtrb3);
|
||||
switch (event) {
|
||||
case TRB_COMPLETION:
|
||||
case TRB_TYPE_COMMAND_COMPLETION:
|
||||
HandleCmdComplete(&fEventRing[i]);
|
||||
result = B_INVOKE_SCHEDULER;
|
||||
break;
|
||||
@@ -671,7 +725,7 @@ XHCI::Interrupt()
|
||||
}
|
||||
|
||||
i++;
|
||||
if (i == MAX_EVENTS) {
|
||||
if (i == XHCI_MAX_EVENTS) {
|
||||
i = 0;
|
||||
j ^= 1;
|
||||
if (!--t)
|
||||
@@ -687,9 +741,6 @@ XHCI::Interrupt()
|
||||
WriteRunReg32(XHCI_ERDP_LO(0), (uint32)addr);
|
||||
WriteRunReg32(XHCI_ERDP_HI(0), (uint32)(addr >> 32));
|
||||
|
||||
|
||||
release_spinlock(&fSpinlock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -714,7 +765,7 @@ XHCI::QueueCommand(xhci_trb *trb)
|
||||
j = fCmdCcs;
|
||||
|
||||
TRACE("command[%u] = %lx (0x%016llx, 0x%08lx, 0x%08lx)\n",
|
||||
i, TRB_TYPE_GET(trb->dwtrb3),
|
||||
i, TRB_3_TYPE_GET(trb->dwtrb3),
|
||||
trb->qwtrb0, trb->dwtrb2, trb->dwtrb3);
|
||||
|
||||
fCmdRing[i].qwtrb0 = trb->qwtrb0;
|
||||
@@ -728,15 +779,14 @@ XHCI::QueueCommand(xhci_trb *trb)
|
||||
temp &= ~TRB_3_TC_BIT;
|
||||
fCmdRing[i].dwtrb3 = temp;
|
||||
|
||||
fCmdAddr = fErst->rs_addr + (MAX_EVENTS + i) * sizeof(xhci_trb);
|
||||
fCmdAddr = fErst->rs_addr + (XHCI_MAX_EVENTS + i) * sizeof(xhci_trb);
|
||||
|
||||
i++;
|
||||
|
||||
if (i == (MAX_COMMANDS - 1)) {
|
||||
if (i == (XHCI_MAX_COMMANDS - 1)) {
|
||||
temp = TRB_3_TYPE(TRB_TYPE_LINK) | TRB_3_TC_BIT;
|
||||
if (j)
|
||||
temp = TRB_3_CYCLE_BIT | TRB_TYPE(TRB_LINK);
|
||||
else
|
||||
temp = TRB_TYPE(TRB_LINK);
|
||||
temp |= TRB_3_CYCLE_BIT;
|
||||
fCmdRing[i].dwtrb3 = temp;
|
||||
|
||||
i = 0;
|
||||
@@ -761,54 +811,176 @@ XHCI::HandleCmdComplete(xhci_trb *trb)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XHCI::QueueNoop()
|
||||
status_t
|
||||
XHCI::DoCommand(xhci_trb *trb)
|
||||
{
|
||||
xhci_trb trb;
|
||||
uint32 temp;
|
||||
if (!Lock())
|
||||
return B_ERROR;
|
||||
|
||||
trb.qwtrb0 = 0;
|
||||
trb.dwtrb2 = 0;
|
||||
temp = TRB_TYPE(TRB_TR_NOOP);
|
||||
trb.dwtrb3 = temp;
|
||||
cpu_status state = disable_interrupts();
|
||||
acquire_spinlock(&fSpinlock);
|
||||
QueueCommand(&trb);
|
||||
QueueCommand(trb);
|
||||
Ring();
|
||||
release_spinlock(&fSpinlock);
|
||||
restore_interrupts(state);
|
||||
|
||||
if (acquire_sem(fCmdCompSem) < B_OK) {
|
||||
Unlock();
|
||||
return B_ERROR;
|
||||
}
|
||||
// eat up sems that have been released by multiple interrupts
|
||||
int32 semCount = 0;
|
||||
get_sem_count(fCmdCompSem, &semCount);
|
||||
if (semCount > 0)
|
||||
acquire_sem_etc(fCmdCompSem, semCount, B_RELATIVE_TIMEOUT, 0);
|
||||
|
||||
status_t status = B_OK;
|
||||
TRACE("Command Complete\n");
|
||||
if (TRB_2_COMP_CODE_GET(fCmdResult[0]) != COMP_SUCCESS) {
|
||||
TRACE_ERROR("unsuccessful no-op command %ld\n",
|
||||
TRB_2_COMP_CODE_GET(fCmdResult[0]));
|
||||
status = B_IO_ERROR;
|
||||
}
|
||||
|
||||
trb->dwtrb2 = fCmdResult[0];
|
||||
trb->dwtrb3 = fCmdResult[1];
|
||||
|
||||
Unlock();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
XHCI::CmdCompThread(void *data)
|
||||
status_t
|
||||
XHCI::Noop()
|
||||
{
|
||||
((XHCI *)data)->CmdComplete();
|
||||
xhci_trb trb;
|
||||
trb.qwtrb0 = 0;
|
||||
trb.dwtrb2 = 0;
|
||||
trb.dwtrb3 = TRB_3_TYPE(TRB_TYPE_CMD_NOOP);
|
||||
|
||||
return DoCommand(&trb);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
XHCI::EnableSlot(uint8 *slot)
|
||||
{
|
||||
xhci_trb trb;
|
||||
trb.qwtrb0 = 0;
|
||||
trb.dwtrb2 = 0;
|
||||
trb.dwtrb3 = TRB_3_TYPE(TRB_TYPE_ENABLE_SLOT);
|
||||
|
||||
status_t status = DoCommand(&trb);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
*slot = TRB_3_SLOT_GET(trb.dwtrb3);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XHCI::CmdComplete()
|
||||
status_t
|
||||
XHCI::DisableSlot(uint8 slot)
|
||||
{
|
||||
while (!fStopThreads) {
|
||||
if (acquire_sem(fCmdCompSem) < B_OK)
|
||||
continue;
|
||||
xhci_trb trb;
|
||||
trb.qwtrb0 = 0;
|
||||
trb.dwtrb2 = 0;
|
||||
trb.dwtrb3 = TRB_3_TYPE(TRB_TYPE_DISABLE_SLOT) | TRB_3_SLOT(slot);
|
||||
|
||||
// eat up sems that have been released by multiple interrupts
|
||||
int32 semCount = 0;
|
||||
get_sem_count(fCmdCompSem, &semCount);
|
||||
if (semCount > 0)
|
||||
acquire_sem_etc(fCmdCompSem, semCount, B_RELATIVE_TIMEOUT, 0);
|
||||
return DoCommand(&trb);
|
||||
}
|
||||
|
||||
TRACE("Command Complete\n");
|
||||
if (COMP_CODE_GET(fCmdResult[0]) != COMP_SUCCESS) {
|
||||
TRACE_ERROR("unsuccessful no-op command\n");
|
||||
//continue;
|
||||
}
|
||||
snooze(1000000 * 5);
|
||||
QueueNoop();
|
||||
}
|
||||
|
||||
status_t
|
||||
XHCI::SetAddress(uint64 inputContext, bool bsr, uint8 slot)
|
||||
{
|
||||
xhci_trb trb;
|
||||
trb.qwtrb0 = inputContext;
|
||||
trb.dwtrb2 = 0;
|
||||
trb.dwtrb3 = TRB_3_TYPE(TRB_TYPE_ADDRESS_DEVICE) | TRB_3_SLOT(slot);
|
||||
|
||||
if (bsr)
|
||||
trb.dwtrb3 |= TRB_3_BSR_BIT;
|
||||
|
||||
return DoCommand(&trb);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
XHCI::ConfigureEndpoint(uint64 inputContext, bool deconfigure, uint8 slot)
|
||||
{
|
||||
xhci_trb trb;
|
||||
trb.qwtrb0 = inputContext;
|
||||
trb.dwtrb2 = 0;
|
||||
trb.dwtrb3 = TRB_3_TYPE(TRB_TYPE_CONFIGURE_ENDPOINT) | TRB_3_SLOT(slot);
|
||||
|
||||
if (deconfigure)
|
||||
trb.dwtrb3 |= TRB_3_DCEP_BIT;
|
||||
|
||||
return DoCommand(&trb);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
XHCI::EvaluateContext(uint64 inputContext, uint8 slot)
|
||||
{
|
||||
xhci_trb trb;
|
||||
trb.qwtrb0 = inputContext;
|
||||
trb.dwtrb2 = 0;
|
||||
trb.dwtrb3 = TRB_3_TYPE(TRB_TYPE_EVALUATE_CONTEXT) | TRB_3_SLOT(slot);
|
||||
|
||||
return DoCommand(&trb);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
XHCI::ResetEndpoint(bool preserve, uint8 endpoint, uint8 slot)
|
||||
{
|
||||
xhci_trb trb;
|
||||
trb.qwtrb0 = 0;
|
||||
trb.dwtrb2 = 0;
|
||||
trb.dwtrb3 = TRB_3_TYPE(TRB_TYPE_RESET_ENDPOINT) | TRB_3_SLOT(slot)
|
||||
| TRB_3_ENDPOINT(endpoint);
|
||||
if (preserve)
|
||||
trb.dwtrb3 |= TRB_3_PRSV_BIT;
|
||||
|
||||
return DoCommand(&trb);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
XHCI::StopEndpoint(bool suspend, uint8 endpoint, uint8 slot)
|
||||
{
|
||||
xhci_trb trb;
|
||||
trb.qwtrb0 = 0;
|
||||
trb.dwtrb2 = 0;
|
||||
trb.dwtrb3 = TRB_3_TYPE(TRB_TYPE_STOP_ENDPOINT) | TRB_3_SLOT(slot)
|
||||
| TRB_3_ENDPOINT(endpoint);
|
||||
if (suspend)
|
||||
trb.dwtrb3 |= TRB_3_SUSPEND_ENDPOINT_BIT;
|
||||
|
||||
return DoCommand(&trb);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
XHCI::SetTRDequeue(uint64 dequeue, uint16 stream, uint8 endpoint, uint8 slot)
|
||||
{
|
||||
xhci_trb trb;
|
||||
trb.qwtrb0 = dequeue;
|
||||
trb.dwtrb2 = TRB_2_STREAM(stream);
|
||||
trb.dwtrb3 = TRB_3_TYPE(TRB_TYPE_SET_TR_DEQUEUE) | TRB_3_SLOT(slot)
|
||||
| TRB_3_ENDPOINT(endpoint);
|
||||
|
||||
return DoCommand(&trb);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
XHCI::ResetDevice(uint8 slot)
|
||||
{
|
||||
xhci_trb trb;
|
||||
trb.qwtrb0 = 0;
|
||||
trb.dwtrb2 = 0;
|
||||
trb.dwtrb3 = TRB_3_TYPE(TRB_TYPE_RESET_DEVICE) | TRB_3_SLOT(slot);
|
||||
|
||||
return DoCommand(&trb);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,45 +14,11 @@
|
||||
#include "xhci_hardware.h"
|
||||
|
||||
|
||||
#define MAX_EVENTS (16 * 13)
|
||||
#define MAX_COMMANDS (16 * 1)
|
||||
#define XHCI_MAX_SLOTS 256
|
||||
#define XHCI_MAX_PORTS 127
|
||||
|
||||
|
||||
struct pci_info;
|
||||
struct pci_module_info;
|
||||
class XHCIRootHub;
|
||||
|
||||
|
||||
struct xhci_trb {
|
||||
uint64 qwtrb0;
|
||||
uint32 dwtrb2;
|
||||
uint32 dwtrb3;
|
||||
};
|
||||
|
||||
|
||||
struct xhci_segment {
|
||||
xhci_trb * trbs;
|
||||
xhci_segment * next;
|
||||
};
|
||||
|
||||
|
||||
struct xhci_ring {
|
||||
xhci_segment * first_seg;
|
||||
xhci_trb * enqueue;
|
||||
xhci_trb * dequeue;
|
||||
};
|
||||
|
||||
|
||||
// Section 6.5
|
||||
struct xhci_erst_element {
|
||||
uint64 rs_addr;
|
||||
uint32 rs_size;
|
||||
uint32 rsvdz;
|
||||
} __attribute__((__aligned__(64)));
|
||||
|
||||
|
||||
class XHCI : public BusManager {
|
||||
public:
|
||||
XHCI(pci_info *info, Stack *stack);
|
||||
@@ -68,12 +34,12 @@ public:
|
||||
static status_t AddTo(Stack *stack);
|
||||
|
||||
// Port operations for root hub
|
||||
uint8 PortCount() { return fPortCount; };
|
||||
uint8 PortCount() const { return fPortCount; }
|
||||
status_t GetPortStatus(uint8 index, usb_port_status *status);
|
||||
status_t SetPortFeature(uint8 index, uint16 feature);
|
||||
status_t ClearPortFeature(uint8 index, uint16 feature);
|
||||
|
||||
virtual const char * TypeName() const { return "xhci"; };
|
||||
virtual const char * TypeName() const { return "xhci"; }
|
||||
|
||||
private:
|
||||
// Controller resets
|
||||
@@ -91,14 +57,27 @@ private:
|
||||
// Command
|
||||
void QueueCommand(xhci_trb *trb);
|
||||
void HandleCmdComplete(xhci_trb *trb);
|
||||
|
||||
status_t DoCommand(xhci_trb *trb);
|
||||
//Doorbell
|
||||
void Ring();
|
||||
|
||||
//no-op
|
||||
void QueueNoop();
|
||||
static int32 CmdCompThread(void *data);
|
||||
void CmdComplete();
|
||||
// Commands
|
||||
status_t Noop();
|
||||
status_t EnableSlot(uint8 *slot);
|
||||
status_t DisableSlot(uint8 slot);
|
||||
status_t SetAddress(uint64 inputContext, bool bsr,
|
||||
uint8 slot);
|
||||
status_t ConfigureEndpoint(uint64 inputContext,
|
||||
bool deconfigure, uint8 slot);
|
||||
status_t EvaluateContext(uint64 inputContext,
|
||||
uint8 slot);
|
||||
status_t ResetEndpoint(bool preserve, uint8 endpoint,
|
||||
uint8 slot);
|
||||
status_t StopEndpoint(bool suspend, uint8 endpoint,
|
||||
uint8 slot);
|
||||
status_t SetTRDequeue(uint64 dequeue, uint16 stream,
|
||||
uint8 endpoint, uint8 slot);
|
||||
status_t ResetDevice(uint8 slot);
|
||||
|
||||
// Operational register functions
|
||||
inline void WriteOpReg(uint32 reg, uint32 value);
|
||||
@@ -136,12 +115,11 @@ private:
|
||||
uint32 fCmdResult[2];
|
||||
|
||||
area_id fDcbaArea;
|
||||
uint8 * fDcba;
|
||||
struct xhci_device_context_array * fDcba;
|
||||
|
||||
spinlock fSpinlock;
|
||||
|
||||
sem_id fCmdCompSem;
|
||||
thread_id fCmdCompThread;
|
||||
sem_id fFinishTransfersSem;
|
||||
thread_id fFinishThread;
|
||||
bool fStopThreads;
|
||||
@@ -154,6 +132,11 @@ private:
|
||||
uint8 fPortCount;
|
||||
uint8 fSlotCount;
|
||||
|
||||
// Scratchpad
|
||||
uint8 fScratchpadCount;
|
||||
area_id fScratchpadArea[XHCI_MAX_SCRATCHPADS];
|
||||
void * fScratchpad[XHCI_MAX_SCRATCHPADS];
|
||||
|
||||
uint16 fEventIdx;
|
||||
uint16 fCmdIdx;
|
||||
uint8 fEventCcs;
|
||||
|
||||
@@ -14,10 +14,16 @@
|
||||
#define XHCI_HCIVERSION 0x02 // Interface Version Number
|
||||
#define XHCI_HCSPARAMS1 0x04 // Structural Parameters 1
|
||||
// HCSPARAMS1
|
||||
#define HCS_MAX_SLOTS(p) (((p) >> 0) & 0xff)
|
||||
#define HCS_MAX_PORTS(p) (((p) >> 24) & 0x7f)
|
||||
#define HCS_MAX_SLOTS(p) (((p) >> 0) & 0xff)
|
||||
#define HCS_MAX_PORTS(p) (((p) >> 24) & 0x7f)
|
||||
#define XHCI_HCSPARAMS2 0x08 // Structural Parameters 2
|
||||
#define HCS_IST(p) (((p) >> 0) & 0xf)
|
||||
#define HCS_ERST_MAX(p) (((p) >> 4) & 0xf)
|
||||
#define HCS_SPR(p) (((p) >> 26) & 0x1)
|
||||
#define HCS_MAX_SC_BUFFERS(p) (((p) >> 27) & 0x1f)
|
||||
#define XHCI_HCSPARAMS3 0x0C // Structural Parameters 3
|
||||
#define HCS_U1_DEVICE_LATENCY(p) (((p) >> 0) & 0xff)
|
||||
#define HCS_U2_DEVICE_LATENCY(p) (((p) >> 16) & 0xffff)
|
||||
#define XHCI_HCCPARAMS 0x10 // Capability Parameters
|
||||
#define XHCI_DBOFF 0x14 // Doorbell Register offset
|
||||
#define XHCI_RTSOFF 0x18 // Runtime Register Space offset
|
||||
@@ -39,6 +45,7 @@
|
||||
#define STS_CNR (1<<11)
|
||||
#define STS_HCE (1 << 12)
|
||||
#define XHCI_PAGESIZE 0x08 // PAGE SIZE
|
||||
#define XHCI_DNCTRL 0x14
|
||||
// Section 5.4.5
|
||||
#define XHCI_CRCR_LO 0x18
|
||||
#define XHCI_CRCR_HI 0x1C
|
||||
@@ -72,7 +79,7 @@
|
||||
|
||||
|
||||
// Host Controller Doorbell Registers
|
||||
#define XHCI_DOORBELL(n) (0x0000 + (4 * (n)))
|
||||
#define XHCI_DOORBELL(n) (0x0000 + (4 * (n)))
|
||||
|
||||
// Extended Capabilities
|
||||
#define XECP_ID(x) ((x) & 0xff)
|
||||
@@ -88,7 +95,7 @@
|
||||
|
||||
// Port status Registers
|
||||
// Section 5.4.8
|
||||
#define XHCI_PORTSC(n) (0x3F0 + (0x10 * (n)))
|
||||
#define XHCI_PORTSC(n) (0x400 + (0x10 * (n)))
|
||||
#define PS_CCS (1 << 0)
|
||||
#define PS_PED (1 << 1)
|
||||
#define PS_OCA (1 << 3)
|
||||
@@ -116,18 +123,167 @@
|
||||
|
||||
|
||||
// Completion Code
|
||||
#define COMP_CODE_GET(x) (((x) >> 24) & 0xff)
|
||||
#define COMP_SUCCESS 0x01
|
||||
#define TRB_2_COMP_CODE_GET(x) (((x) >> 24) & 0xff)
|
||||
#define COMP_INVALID 0
|
||||
#define COMP_SUCCESS 1
|
||||
#define COMP_DATA_BUFFER 2
|
||||
#define COMP_BABBLE 3
|
||||
#define COMP_USB_TRANSACTION 4
|
||||
#define COMP_TRB 5
|
||||
#define COMP_STALL 6
|
||||
#define COMP_RESOURCE 7
|
||||
#define COMP_BANDWIDTH 8
|
||||
#define COMP_NO_SLOTS 9
|
||||
#define COMP_INVALID_STREAM 10
|
||||
#define COMP_SLOT_NOT_ENABLED 11
|
||||
#define COMP_ENDPOINT_NOT_ENABLED 12
|
||||
#define COMP_SHORT_PACKET 13
|
||||
#define COMP_RING_UNDERRUN 14
|
||||
#define COMP_RING_OVERRUN 15
|
||||
#define COMP_VF_RING_FULL 16
|
||||
#define COMP_PARAMETER 17
|
||||
#define COMP_BANDWIDTH_OVERRUN 18
|
||||
#define COMP_CONTEXT_STATE 19
|
||||
#define COMP_NO_PING_RESPONSE 20
|
||||
#define COMP_EVENT_RING_FULL 21
|
||||
#define COMP_INCOMPATIBLE_DEVICE 22
|
||||
#define COMP_MISSED_SERVICE 23
|
||||
#define COMP_COMMAND_RING_STOPPED 24
|
||||
#define COMP_COMMAND_ABORTED 25
|
||||
#define COMP_STOPPED 26
|
||||
#define COMP_LENGTH_INVALID 27
|
||||
#define COMP_MAX_EXIT_LATENCY 29
|
||||
#define COMP_ISOC_OVERRUN 31
|
||||
#define COMP_EVENT_LOST 32
|
||||
#define COMP_UNDEFINED 33
|
||||
#define COMP_INVALID_STREAM_ID 34
|
||||
#define COMP_SECONDARY_BANDWIDTH 35
|
||||
#define COMP_SPLIT_TRANSACTION 36
|
||||
|
||||
#define TRB_2_TD_SIZE(x) (((x) & 0x1F) << 17)
|
||||
#define TRB_2_TD_SIZE_GET(x) (((x) >> 17) & 0x1F)
|
||||
#define TRB_2_REM(x) ((x) & 0xFFFFFF)
|
||||
#define TRB_2_REM_GET(x) ((x) & 0xFFFFFF)
|
||||
#define TRB_2_BYTES(x) ((x) & 0x1FFFF)
|
||||
#define TRB_2_BYTES_GET(x) ((x) & 0x1FFFF)
|
||||
#define TRB_2_IRQ(x) (((x) & 0x3FF) << 22)
|
||||
#define TRB_2_IRQ_GET(x) (((x) >> 22) & 0x3FF)
|
||||
#define TRB_2_STREAM(x) (((x) & 0xFF) << 16)
|
||||
#define TRB_2_STREAM_GET(x) (((x) >> 16) & 0xFF)
|
||||
|
||||
#define TRB_3_TYPE(x) (((x) & 0x3F) << 10)
|
||||
#define TRB_3_TYPE_GET(x) (((x) >> 10) & 0x3F)
|
||||
// TRB Type (table 131)
|
||||
#define TRB_TYPE_NORMAL 1
|
||||
#define TRB_TYPE_SETUP_STAGE 2
|
||||
#define TRB_TYPE_DATA_STAGE 3
|
||||
#define TRB_TYPE_STATUS_STAGE 4
|
||||
#define TRB_TYPE_ISOCH 5
|
||||
#define TRB_TYPE_LINK 6
|
||||
#define TRB_TYPE_EVENT_DATA 7
|
||||
#define TRB_TYPE_TR_NOOP 8
|
||||
// commands
|
||||
#define TRB_TYPE_ENABLE_SLOT 9
|
||||
#define TRB_TYPE_DISABLE_SLOT 10
|
||||
#define TRB_TYPE_ADDRESS_DEVICE 11
|
||||
#define TRB_TYPE_CONFIGURE_ENDPOINT 12
|
||||
#define TRB_TYPE_EVALUATE_CONTEXT 13
|
||||
#define TRB_TYPE_RESET_ENDPOINT 14
|
||||
#define TRB_TYPE_STOP_ENDPOINT 15
|
||||
#define TRB_TYPE_SET_TR_DEQUEUE 16
|
||||
#define TRB_TYPE_RESET_DEVICE 17
|
||||
#define TRB_TYPE_FORCE_EVENT 18
|
||||
#define TRB_TYPE_NEGOCIATE_BW 19
|
||||
#define TRB_TYPE_SET_LATENCY_TOLERANCE 20
|
||||
#define TRB_TYPE_GET_PORT_BW 21
|
||||
#define TRB_TYPE_FORCE_HEADER 22
|
||||
#define TRB_TYPE_CMD_NOOP 23
|
||||
// events
|
||||
#define TRB_TYPE_TRANSFER 32
|
||||
#define TRB_TYPE_COMMAND_COMPLETION 33
|
||||
#define TRB_TYPE_PORT_STATUS_CHANGE 34
|
||||
#define TRB_TYPE_BANDWIDTH_REQUEST 35
|
||||
#define TRB_TYPE_DOORBELL 36
|
||||
#define TRB_TYPE_HOST_CONTROLLER 37
|
||||
#define TRB_TYPE_DEVICE_NOTIFICATION 38
|
||||
#define TRB_TYPE_MFINDEX_WRAP 39
|
||||
// vendor
|
||||
#define TRB_TYPE_NEC_COMMAND_COMPLETION 48
|
||||
#define TRB_TYPE_NEC_GET_FIRMWARE_REV 49
|
||||
|
||||
// TRB Type
|
||||
#define TRB_TYPE(x) ((x) << 10)
|
||||
#define TRB_TYPE_GET(x) (((x) >> 10) & 0x3F)
|
||||
#define TRB_LINK 6
|
||||
#define TRB_TR_NOOP 8
|
||||
#define TRB_TRANSFER 32
|
||||
#define TRB_COMPLETION 33
|
||||
#define TRB_3_CYCLE_BIT (1U << 0)
|
||||
#define TRB_3_TC_BIT (1U << 1)
|
||||
#define TRB_3_ENT_BIT (1U << 1)
|
||||
#define TRB_3_ISP_BIT (1U << 2)
|
||||
#define TRB_3_NSNOOP_BIT (1U << 3)
|
||||
#define TRB_3_CHAIN_BIT (1U << 4)
|
||||
#define TRB_3_IOC_BIT (1U << 5)
|
||||
#define TRB_3_IDT_BIT (1U << 6)
|
||||
#define TRB_3_BEI_BIT (1U << 9)
|
||||
#define TRB_3_DCEP_BIT (1U << 9)
|
||||
#define TRB_3_PRSV_BIT (1U << 9)
|
||||
#define TRB_3_BSR_BIT (1U << 9)
|
||||
#define TRB_3_TRT_MASK (3U << 16)
|
||||
#define TRB_3_DIR_IN (1U << 16)
|
||||
#define TRB_3_TRT_OUT (2U << 16)
|
||||
#define TRB_3_TRT_IN (3U << 16)
|
||||
#define TRB_3_SUSPEND_ENDPOINT_BIT (1U << 23)
|
||||
#define TRB_3_ISO_SIA_BIT (1U << 31)
|
||||
|
||||
#define TRB_3_TBC(x) (((x) & 0x3) << 7)
|
||||
#define TRB_3_TBC_GET(x) (((x) >> 7) & 0x3)
|
||||
#define TRB_3_TLBPC(x) (((x) & 0xf) << 16)
|
||||
#define TRB_3_TLBPC_GET(x) (((x) >> 16) & 0xf)
|
||||
#define TRB_3_ENDPOINT(x) (((x) & 0xf) << 16)
|
||||
#define TRB_3_ENDPOINT_GET(x) (((x) >> 16) & 0xf)
|
||||
#define TRB_3_FRID(x) (((x) & 0x7ff) << 20)
|
||||
#define TRB_3_FRID_GET(x) (((x) >> 20) & 0x7ff)
|
||||
#define TRB_3_SLOT(x) (((x) & 0xff) << 24)
|
||||
#define TRB_3_SLOT_GET(x) (((x) >> 24) & 0xff)
|
||||
|
||||
|
||||
#define XHCI_MAX_EVENTS (16 * 13)
|
||||
#define XHCI_MAX_COMMANDS (16 * 1)
|
||||
#define XHCI_MAX_SLOTS 256
|
||||
#define XHCI_MAX_PORTS 127
|
||||
#define XHCI_MAX_SCRATCHPADS 32
|
||||
|
||||
|
||||
struct xhci_trb {
|
||||
uint64 qwtrb0;
|
||||
uint32 dwtrb2;
|
||||
uint32 dwtrb3;
|
||||
} __attribute__((__aligned__(4)));;
|
||||
|
||||
|
||||
struct xhci_segment {
|
||||
xhci_trb * trbs;
|
||||
xhci_segment * next;
|
||||
};
|
||||
|
||||
|
||||
struct xhci_ring {
|
||||
xhci_segment * first_seg;
|
||||
xhci_trb * enqueue;
|
||||
xhci_trb * dequeue;
|
||||
};
|
||||
|
||||
|
||||
// Section 6.5
|
||||
struct xhci_erst_element {
|
||||
uint64 rs_addr;
|
||||
uint32 rs_size;
|
||||
uint32 rsvdz;
|
||||
} __attribute__((__aligned__(64)));
|
||||
|
||||
|
||||
struct xhci_device_context_array {
|
||||
uint64 baseAddress[XHCI_MAX_SLOTS];
|
||||
struct {
|
||||
uint64 padding;
|
||||
} __attribute__((__aligned__(64)));
|
||||
uint64 scratchpad[XHCI_MAX_SCRATCHPADS];
|
||||
};
|
||||
|
||||
|
||||
#endif // !XHCI_HARDWARE_H
|
||||
|
||||
Reference in New Issue
Block a user