Work in progress on xHCI bus driver
* added a thread to handle events, locking wasn't easy in an interrupt handler * the td struct can now track several buffers instead of just one. * use Transfer::Data*() instead of Vector*() for the time being until support for fragmented transfers is done * added CreateDescriptorChain, WriteDescriptorChain and ReadDescriptorChain, chained tds not working yet though. * added a mutex lock per enabled endpoint, lock when touching the endpoint transfer ring. * correctly configure interval and average trb length for endpoint contexts. * interrupt transfers seem to work on real hardware * xhci qemu driver doesn't advance ring dequeue pointers on link trbs, thus accessing freed trbs that could already be reused, leading to crash.
This commit is contained in:
parent
dc09611aad
commit
411272adfd
@ -124,6 +124,8 @@ XHCI::XHCI(pci_info *info, Stack *stack)
|
|||||||
fPortCount(0),
|
fPortCount(0),
|
||||||
fSlotCount(0),
|
fSlotCount(0),
|
||||||
fScratchpadCount(0),
|
fScratchpadCount(0),
|
||||||
|
fEventSem(-1),
|
||||||
|
fEventThread(-1),
|
||||||
fEventIdx(0),
|
fEventIdx(0),
|
||||||
fCmdIdx(0),
|
fCmdIdx(0),
|
||||||
fEventCcs(1),
|
fEventCcs(1),
|
||||||
@ -233,7 +235,8 @@ XHCI::XHCI(pci_info *info, Stack *stack)
|
|||||||
|
|
||||||
fCmdCompSem = create_sem(0, "XHCI Command Complete");
|
fCmdCompSem = create_sem(0, "XHCI Command Complete");
|
||||||
fFinishTransfersSem = create_sem(0, "XHCI Finish Transfers");
|
fFinishTransfersSem = create_sem(0, "XHCI Finish Transfers");
|
||||||
if (fFinishTransfersSem < B_OK || fCmdCompSem < B_OK) {
|
fEventSem = create_sem(0, "XHCI Event");
|
||||||
|
if (fFinishTransfersSem < B_OK || fCmdCompSem < B_OK || fEventSem < B_OK) {
|
||||||
TRACE_ERROR("failed to create semaphores\n");
|
TRACE_ERROR("failed to create semaphores\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -243,6 +246,11 @@ XHCI::XHCI(pci_info *info, Stack *stack)
|
|||||||
B_NORMAL_PRIORITY, (void *)this);
|
B_NORMAL_PRIORITY, (void *)this);
|
||||||
resume_thread(fFinishThread);
|
resume_thread(fFinishThread);
|
||||||
|
|
||||||
|
// create finisher service thread
|
||||||
|
fEventThread = spawn_kernel_thread(EventThread, "xhci event thread",
|
||||||
|
B_NORMAL_PRIORITY, (void *)this);
|
||||||
|
resume_thread(fEventThread);
|
||||||
|
|
||||||
// Install the interrupt handler
|
// Install the interrupt handler
|
||||||
TRACE("installing interrupt handler\n");
|
TRACE("installing interrupt handler\n");
|
||||||
install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
|
install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
|
||||||
@ -267,12 +275,14 @@ XHCI::~XHCI()
|
|||||||
fStopThreads = true;
|
fStopThreads = true;
|
||||||
delete_sem(fCmdCompSem);
|
delete_sem(fCmdCompSem);
|
||||||
delete_sem(fFinishTransfersSem);
|
delete_sem(fFinishTransfersSem);
|
||||||
|
delete_sem(fEventSem);
|
||||||
delete_area(fRegisterArea);
|
delete_area(fRegisterArea);
|
||||||
delete_area(fErstArea);
|
delete_area(fErstArea);
|
||||||
for (uint32 i = 0; i < fScratchpadCount; i++)
|
for (uint32 i = 0; i < fScratchpadCount; i++)
|
||||||
delete_area(fScratchpadArea[i]);
|
delete_area(fScratchpadArea[i]);
|
||||||
delete_area(fDcbaArea);
|
delete_area(fDcbaArea);
|
||||||
wait_for_thread(fFinishThread, &result);
|
wait_for_thread(fFinishThread, &result);
|
||||||
|
wait_for_thread(fEventThread, &result);
|
||||||
put_module(B_PCI_MODULE_NAME);
|
put_module(B_PCI_MODULE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,7 +495,7 @@ XHCI::SubmitControlRequest(Transfer *transfer)
|
|||||||
usb_request_data *requestData = transfer->RequestData();
|
usb_request_data *requestData = transfer->RequestData();
|
||||||
bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) != 0;
|
bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) != 0;
|
||||||
|
|
||||||
TRACE("SubmitControlRequest()\n");
|
TRACE("SubmitControlRequest() length %d\n", requestData->Length);
|
||||||
|
|
||||||
xhci_td *setupDescriptor = CreateDescriptor(requestData->Length);
|
xhci_td *setupDescriptor = CreateDescriptor(requestData->Length);
|
||||||
|
|
||||||
@ -505,7 +515,7 @@ XHCI::SubmitControlRequest(Transfer *transfer)
|
|||||||
|
|
||||||
if (requestData->Length > 0) {
|
if (requestData->Length > 0) {
|
||||||
// set DataStage if any
|
// set DataStage if any
|
||||||
setupDescriptor->trbs[index].qwtrb0 = setupDescriptor->buffer_phy;
|
setupDescriptor->trbs[index].qwtrb0 = setupDescriptor->buffer_phy[0];
|
||||||
setupDescriptor->trbs[index].dwtrb2 = TRB_2_IRQ(0)
|
setupDescriptor->trbs[index].dwtrb2 = TRB_2_IRQ(0)
|
||||||
| TRB_2_BYTES(requestData->Length)
|
| TRB_2_BYTES(requestData->Length)
|
||||||
| TRB_2_TD_SIZE(transfer->VectorCount());
|
| TRB_2_TD_SIZE(transfer->VectorCount());
|
||||||
@ -522,7 +532,7 @@ XHCI::SubmitControlRequest(Transfer *transfer)
|
|||||||
| ((directionIn && requestData->Length > 0) ? 0 : TRB_3_DIR_IN)
|
| ((directionIn && requestData->Length > 0) ? 0 : TRB_3_DIR_IN)
|
||||||
| TRB_3_IOC_BIT | TRB_3_CYCLE_BIT;
|
| TRB_3_IOC_BIT | TRB_3_CYCLE_BIT;
|
||||||
|
|
||||||
setupDescriptor->last_used = index;
|
setupDescriptor->trb_count = index + 1;
|
||||||
|
|
||||||
xhci_endpoint *endpoint = (xhci_endpoint *)pipe->ControllerCookie();
|
xhci_endpoint *endpoint = (xhci_endpoint *)pipe->ControllerCookie();
|
||||||
uint8 id = XHCI_ENDPOINT_ID(pipe);
|
uint8 id = XHCI_ENDPOINT_ID(pipe);
|
||||||
@ -542,33 +552,41 @@ XHCI::SubmitControlRequest(Transfer *transfer)
|
|||||||
status_t
|
status_t
|
||||||
XHCI::SubmitNormalRequest(Transfer *transfer)
|
XHCI::SubmitNormalRequest(Transfer *transfer)
|
||||||
{
|
{
|
||||||
TRACE("SubmitNormalRequest()\n");
|
TRACE("SubmitNormalRequest() length %ld\n", transfer->DataLength());
|
||||||
Pipe *pipe = transfer->TransferPipe();
|
Pipe *pipe = transfer->TransferPipe();
|
||||||
bool directionIn = (pipe->Direction() == Pipe::In);
|
|
||||||
|
|
||||||
xhci_td *normalDescriptor = CreateDescriptor(transfer->VectorLength());
|
|
||||||
|
|
||||||
// set NormalStage
|
|
||||||
uint8 index = 0;
|
|
||||||
normalDescriptor->trbs[index].qwtrb0 = normalDescriptor->buffer_phy;
|
|
||||||
normalDescriptor->trbs[index].dwtrb2 = TRB_2_IRQ(0)
|
|
||||||
| TRB_2_BYTES(transfer->VectorLength())
|
|
||||||
| TRB_2_TD_SIZE(transfer->VectorCount());
|
|
||||||
normalDescriptor->trbs[index].dwtrb3 = TRB_3_TYPE(TRB_TYPE_NORMAL)
|
|
||||||
| TRB_3_CYCLE_BIT | TRB_3_IOC_BIT;
|
|
||||||
|
|
||||||
if (!directionIn) {
|
|
||||||
memcpy(normalDescriptor->buffer_log,
|
|
||||||
(uint8 *)transfer->Vector()[0].iov_base, transfer->VectorLength());
|
|
||||||
}
|
|
||||||
normalDescriptor->last_used = index;
|
|
||||||
|
|
||||||
xhci_endpoint *endpoint = (xhci_endpoint *)pipe->ControllerCookie();
|
|
||||||
uint8 id = XHCI_ENDPOINT_ID(pipe);
|
uint8 id = XHCI_ENDPOINT_ID(pipe);
|
||||||
if (id >= XHCI_MAX_ENDPOINTS)
|
if (id >= XHCI_MAX_ENDPOINTS)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
normalDescriptor->transfer = transfer;
|
bool directionIn = (pipe->Direction() == Pipe::In);
|
||||||
_LinkDescriptorForPipe(normalDescriptor, endpoint);
|
|
||||||
|
xhci_td *descriptor = CreateDescriptorChain(transfer->DataLength());
|
||||||
|
descriptor->trb_count = descriptor->buffer_count;
|
||||||
|
|
||||||
|
// set NormalStage
|
||||||
|
uint8 index;
|
||||||
|
for (index = 0; index < descriptor->buffer_count; index++) {
|
||||||
|
descriptor->trbs[index].qwtrb0 = descriptor->buffer_phy[index];
|
||||||
|
descriptor->trbs[index].dwtrb2 = TRB_2_IRQ(0)
|
||||||
|
| TRB_2_BYTES(descriptor->buffer_size[index])
|
||||||
|
| TRB_2_TD_SIZE(descriptor->trb_count);
|
||||||
|
descriptor->trbs[index].dwtrb3 = TRB_3_TYPE(TRB_TYPE_NORMAL)
|
||||||
|
| TRB_3_CYCLE_BIT;
|
||||||
|
}
|
||||||
|
if (descriptor->trb_count > 0)
|
||||||
|
descriptor->trbs[index - 1].dwtrb3 |= TRB_3_IOC_BIT;
|
||||||
|
|
||||||
|
if (!directionIn) {
|
||||||
|
TRACE("copying out iov count %ld\n", transfer->VectorCount());
|
||||||
|
WriteDescriptorChain(descriptor, transfer->Vector(),
|
||||||
|
transfer->VectorCount());
|
||||||
|
}
|
||||||
|
/* memcpy(descriptor->buffer_log[index],
|
||||||
|
(uint8 *)transfer->Vector()[index].iov_base, transfer->VectorLength());
|
||||||
|
}*/
|
||||||
|
|
||||||
|
xhci_endpoint *endpoint = (xhci_endpoint *)pipe->ControllerCookie();
|
||||||
|
descriptor->transfer = transfer;
|
||||||
|
_LinkDescriptorForPipe(descriptor, endpoint);
|
||||||
|
|
||||||
TRACE("SubmitNormalRequest() request linked\n");
|
TRACE("SubmitNormalRequest() request linked\n");
|
||||||
|
|
||||||
@ -682,6 +700,52 @@ XHCI::AddTo(Stack *stack)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
xhci_td *
|
||||||
|
XHCI::CreateDescriptorChain(size_t bufferSize)
|
||||||
|
{
|
||||||
|
size_t packetSize = B_PAGE_SIZE * 16;
|
||||||
|
int32 trbCount = (bufferSize + packetSize - 1) / packetSize;
|
||||||
|
// keep one trb for linking
|
||||||
|
int32 tdCount = (trbCount + XHCI_MAX_TRBS_PER_TD - 2) / (XHCI_MAX_TRBS_PER_TD - 1);
|
||||||
|
|
||||||
|
xhci_td *first = NULL;
|
||||||
|
xhci_td *last = NULL;
|
||||||
|
for (int32 i = 0; i < tdCount; i++) {
|
||||||
|
xhci_td *descriptor = CreateDescriptor(0);
|
||||||
|
if (!descriptor) {
|
||||||
|
//FreeDescriptorChain(firstDescriptor);
|
||||||
|
return NULL;
|
||||||
|
} else if (first == NULL)
|
||||||
|
first = descriptor;
|
||||||
|
|
||||||
|
uint8 trbs = min_c(trbCount, XHCI_MAX_TRBS_PER_TD);
|
||||||
|
TRACE("CreateDescriptorChain trbs %d for td %ld\n", trbs, i);
|
||||||
|
for (int j = 0; j < trbs; j++) {
|
||||||
|
if (fStack->AllocateChunk(&descriptor->buffer_log[j],
|
||||||
|
(void **)&descriptor->buffer_phy[j],
|
||||||
|
min_c(packetSize, bufferSize)) < B_OK) {
|
||||||
|
TRACE_ERROR("unable to allocate space for the buffer (size %ld)\n",
|
||||||
|
bufferSize);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor->buffer_size[j] = min_c(packetSize, bufferSize);
|
||||||
|
bufferSize -= descriptor->buffer_size[j];
|
||||||
|
TRACE("CreateDescriptorChain allocated %ld for trb %d\n",
|
||||||
|
descriptor->buffer_size[j], j);
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor->buffer_count = trbs;
|
||||||
|
trbCount -= trbs;
|
||||||
|
if (last != NULL)
|
||||||
|
last->next = descriptor;
|
||||||
|
last = descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
xhci_td *
|
xhci_td *
|
||||||
XHCI::CreateDescriptor(size_t bufferSize)
|
XHCI::CreateDescriptor(size_t bufferSize)
|
||||||
{
|
{
|
||||||
@ -695,15 +759,17 @@ XHCI::CreateDescriptor(size_t bufferSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
result->this_phy = (addr_t)physicalAddress;
|
result->this_phy = (addr_t)physicalAddress;
|
||||||
result->buffer_size = bufferSize;
|
result->buffer_size[0] = bufferSize;
|
||||||
|
result->trb_count = 0;
|
||||||
|
result->buffer_count = 1;
|
||||||
if (bufferSize <= 0) {
|
if (bufferSize <= 0) {
|
||||||
result->buffer_log = NULL;
|
result->buffer_log[0] = NULL;
|
||||||
result->buffer_phy = 0;
|
result->buffer_phy[0] = 0;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fStack->AllocateChunk(&result->buffer_log,
|
if (fStack->AllocateChunk(&result->buffer_log[0],
|
||||||
(void **)&result->buffer_phy, bufferSize) < B_OK) {
|
(void **)&result->buffer_phy[0], bufferSize) < B_OK) {
|
||||||
TRACE_ERROR("unable to allocate space for the buffer (size %ld)\n",
|
TRACE_ERROR("unable to allocate space for the buffer (size %ld)\n",
|
||||||
bufferSize);
|
bufferSize);
|
||||||
fStack->FreeChunk(result, (void *)result->this_phy, sizeof(xhci_td));
|
fStack->FreeChunk(result, (void *)result->this_phy, sizeof(xhci_td));
|
||||||
@ -720,9 +786,13 @@ XHCI::FreeDescriptor(xhci_td *descriptor)
|
|||||||
if (!descriptor)
|
if (!descriptor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (descriptor->buffer_log) {
|
for (int i = 0; i < descriptor->buffer_count; i++) {
|
||||||
fStack->FreeChunk(descriptor->buffer_log,
|
if (descriptor->buffer_size[i] == 0)
|
||||||
(void *)descriptor->buffer_phy, descriptor->buffer_size);
|
continue;
|
||||||
|
TRACE("FreeDescriptor buffer %d buffer_size %ld\n", i,
|
||||||
|
descriptor->buffer_size[i]);
|
||||||
|
fStack->FreeChunk(descriptor->buffer_log[i],
|
||||||
|
(void *)descriptor->buffer_phy[i], descriptor->buffer_size[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fStack->FreeChunk(descriptor, (void *)descriptor->this_phy,
|
fStack->FreeChunk(descriptor, (void *)descriptor->this_phy,
|
||||||
@ -730,6 +800,116 @@ XHCI::FreeDescriptor(xhci_td *descriptor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
XHCI::WriteDescriptorChain(xhci_td *descriptor, iovec *vector,
|
||||||
|
size_t vectorCount)
|
||||||
|
{
|
||||||
|
xhci_td *current = descriptor;
|
||||||
|
uint8 trbIndex = 0;
|
||||||
|
size_t actualLength = 0;
|
||||||
|
uint8 vectorIndex = 0;
|
||||||
|
size_t vectorOffset = 0;
|
||||||
|
size_t bufferOffset = 0;
|
||||||
|
|
||||||
|
while (current != NULL) {
|
||||||
|
if (current->buffer_log == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
size_t length = min_c(current->buffer_size[trbIndex] - bufferOffset,
|
||||||
|
vector[vectorIndex].iov_len - vectorOffset);
|
||||||
|
|
||||||
|
TRACE("copying %ld bytes to bufferOffset %ld from"
|
||||||
|
" vectorOffset %ld at index %d of %ld\n", length, bufferOffset,
|
||||||
|
vectorOffset, vectorIndex, vectorCount);
|
||||||
|
memcpy((uint8 *)current->buffer_log[trbIndex] + bufferOffset,
|
||||||
|
(uint8 *)vector[vectorIndex].iov_base + vectorOffset, length);
|
||||||
|
|
||||||
|
actualLength += length;
|
||||||
|
vectorOffset += length;
|
||||||
|
bufferOffset += length;
|
||||||
|
|
||||||
|
if (vectorOffset >= vector[vectorIndex].iov_len) {
|
||||||
|
if (++vectorIndex >= vectorCount) {
|
||||||
|
TRACE("wrote descriptor chain (%ld bytes, no more vectors)\n",
|
||||||
|
actualLength);
|
||||||
|
return actualLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
vectorOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufferOffset >= current->buffer_size[trbIndex]) {
|
||||||
|
if (++trbIndex >= current->buffer_count)
|
||||||
|
break;
|
||||||
|
bufferOffset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current->next;
|
||||||
|
trbIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("wrote descriptor chain (%ld bytes)\n", actualLength);
|
||||||
|
return actualLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
XHCI::ReadDescriptorChain(xhci_td *descriptor, iovec *vector,
|
||||||
|
size_t vectorCount)
|
||||||
|
{
|
||||||
|
xhci_td *current = descriptor;
|
||||||
|
uint8 trbIndex = 0;
|
||||||
|
size_t actualLength = 0;
|
||||||
|
uint8 vectorIndex = 0;
|
||||||
|
size_t vectorOffset = 0;
|
||||||
|
size_t bufferOffset = 0;
|
||||||
|
|
||||||
|
while (current != NULL) {
|
||||||
|
if (current->buffer_log == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
size_t length = min_c(current->buffer_size[trbIndex] - bufferOffset,
|
||||||
|
vector[vectorIndex].iov_len - vectorOffset);
|
||||||
|
|
||||||
|
TRACE("copying %ld bytes to vectorOffset %ld from"
|
||||||
|
" bufferOffset %ld at index %d of %ld\n", length, vectorOffset,
|
||||||
|
bufferOffset, vectorIndex, vectorCount);
|
||||||
|
memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
|
||||||
|
(uint8 *)current->buffer_log[trbIndex] + bufferOffset, length);
|
||||||
|
|
||||||
|
actualLength += length;
|
||||||
|
vectorOffset += length;
|
||||||
|
bufferOffset += length;
|
||||||
|
|
||||||
|
if (vectorOffset >= vector[vectorIndex].iov_len) {
|
||||||
|
if (++vectorIndex >= vectorCount) {
|
||||||
|
TRACE("read descriptor chain (%ld bytes, no more vectors)\n",
|
||||||
|
actualLength);
|
||||||
|
return actualLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
vectorOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufferOffset >= current->buffer_size[trbIndex]) {
|
||||||
|
if (++trbIndex >= current->buffer_count)
|
||||||
|
break;
|
||||||
|
bufferOffset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current->next;
|
||||||
|
trbIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("read descriptor chain (%ld bytes)\n", actualLength);
|
||||||
|
return actualLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Device *
|
Device *
|
||||||
XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
|
XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
|
||||||
usb_speed speed)
|
usb_speed speed)
|
||||||
@ -768,6 +948,7 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(device->input_ctx, 0, sizeof(*device->input_ctx));
|
||||||
device->input_ctx->input.dropFlags = 0;
|
device->input_ctx->input.dropFlags = 0;
|
||||||
device->input_ctx->input.addFlags = 3;
|
device->input_ctx->input.addFlags = 3;
|
||||||
|
|
||||||
@ -825,6 +1006,7 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
|
|||||||
delete_area(device->input_ctx_area);
|
delete_area(device->input_ctx_area);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
memset(device->device_ctx, 0, sizeof(*device->device_ctx));
|
||||||
|
|
||||||
device->trb_area = fStack->AllocateArea((void **)&device->trbs,
|
device->trb_area = fStack->AllocateArea((void **)&device->trbs,
|
||||||
(void**)&device->trb_addr, sizeof(*device->trbs), "XHCI endpoint trbs");
|
(void**)&device->trb_addr, sizeof(*device->trbs), "XHCI endpoint trbs");
|
||||||
@ -862,7 +1044,7 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
|
|||||||
|
|
||||||
// configure the Control endpoint 0 (type 4)
|
// configure the Control endpoint 0 (type 4)
|
||||||
if (ConfigureEndpoint(slot, 0, 4, device->trb_addr, 0, 1, 1, 0,
|
if (ConfigureEndpoint(slot, 0, 4, device->trb_addr, 0, 1, 1, 0,
|
||||||
maxPacketSize, maxPacketSize) != B_OK) {
|
maxPacketSize, maxPacketSize, speed) != B_OK) {
|
||||||
TRACE_ERROR("unable to configure default control endpoint\n");
|
TRACE_ERROR("unable to configure default control endpoint\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -873,6 +1055,7 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
|
|||||||
device->endpoints[0].used = 0;
|
device->endpoints[0].used = 0;
|
||||||
device->endpoints[0].current = 0;
|
device->endpoints[0].current = 0;
|
||||||
device->endpoints[0].trb_addr = device->trb_addr;
|
device->endpoints[0].trb_addr = device->trb_addr;
|
||||||
|
mutex_init(&device->endpoints[0].lock, "xhci endpoint lock");
|
||||||
|
|
||||||
// device should get to addressed state (bsr = 0)
|
// device should get to addressed state (bsr = 0)
|
||||||
if (SetAddress(device->input_ctx_addr, false, slot) != B_OK) {
|
if (SetAddress(device->input_ctx_addr, false, slot) != B_OK) {
|
||||||
@ -974,6 +1157,13 @@ XHCI::_InsertEndpointForPipe(Pipe *pipe)
|
|||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
if (id > 0) {
|
if (id > 0) {
|
||||||
|
if (SLOT_0_NUM_ENTRIES_GET(device->device_ctx->slot.dwslot0) == 1) {
|
||||||
|
device->input_ctx->slot.dwslot0 &= ~(SLOT_0_NUM_ENTRIES(0x1f));
|
||||||
|
device->input_ctx->slot.dwslot0 |=
|
||||||
|
SLOT_0_NUM_ENTRIES(XHCI_MAX_ENDPOINTS - 1);
|
||||||
|
EvaluateContext(device->input_ctx_addr, device->slot);
|
||||||
|
}
|
||||||
|
|
||||||
device->endpoints[id].device = device;
|
device->endpoints[id].device = device;
|
||||||
device->endpoints[id].trbs = device->trbs
|
device->endpoints[id].trbs = device->trbs
|
||||||
+ id * XHCI_MAX_TRANSFERS;
|
+ id * XHCI_MAX_TRANSFERS;
|
||||||
@ -981,6 +1171,7 @@ XHCI::_InsertEndpointForPipe(Pipe *pipe)
|
|||||||
device->endpoints[id].used = 0;
|
device->endpoints[id].used = 0;
|
||||||
device->endpoints[id].trb_addr = device->trb_addr
|
device->endpoints[id].trb_addr = device->trb_addr
|
||||||
+ id * XHCI_MAX_TRANSFERS * sizeof(xhci_trb);
|
+ id * XHCI_MAX_TRANSFERS * sizeof(xhci_trb);
|
||||||
|
mutex_init(&device->endpoints[id].lock, "xhci endpoint lock");
|
||||||
|
|
||||||
TRACE("_InsertEndpointForPipe trbs device %p endpoint %p\n",
|
TRACE("_InsertEndpointForPipe trbs device %p endpoint %p\n",
|
||||||
device->trbs, device->endpoints[id].trbs);
|
device->trbs, device->endpoints[id].trbs);
|
||||||
@ -1013,7 +1204,8 @@ XHCI::_InsertEndpointForPipe(Pipe *pipe)
|
|||||||
|
|
||||||
if (ConfigureEndpoint(device->slot, id, type,
|
if (ConfigureEndpoint(device->slot, id, type,
|
||||||
device->endpoints[id].trb_addr, pipe->Interval(),
|
device->endpoints[id].trb_addr, pipe->Interval(),
|
||||||
1, 1, 0, pipe->MaxPacketSize(), pipe->MaxPacketSize()) != B_OK) {
|
1, 1, 0, pipe->MaxPacketSize(), pipe->MaxPacketSize(),
|
||||||
|
usbDevice->Speed()) != B_OK) {
|
||||||
TRACE_ERROR("unable to configure endpoint\n");
|
TRACE_ERROR("unable to configure endpoint\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
@ -1021,6 +1213,12 @@ XHCI::_InsertEndpointForPipe(Pipe *pipe)
|
|||||||
EvaluateContext(device->input_ctx_addr, device->slot);
|
EvaluateContext(device->input_ctx_addr, device->slot);
|
||||||
|
|
||||||
ConfigureEndpoint(device->input_ctx_addr, false, device->slot);
|
ConfigureEndpoint(device->input_ctx_addr, false, device->slot);
|
||||||
|
TRACE("device: address 0x%x state 0x%lx\n", device->address,
|
||||||
|
SLOT_3_SLOT_STATE_GET(device->device_ctx->slot.dwslot3));
|
||||||
|
TRACE("endpoint[0] state 0x%lx\n",
|
||||||
|
ENDPOINT_0_STATE_GET(device->device_ctx->endpoints[0].dwendpoint0));
|
||||||
|
TRACE("endpoint[%d] state 0x%lx\n", id,
|
||||||
|
ENDPOINT_0_STATE_GET(device->device_ctx->endpoints[id].dwendpoint0));
|
||||||
device->state = XHCI_STATE_CONFIGURED;
|
device->state = XHCI_STATE_CONFIGURED;
|
||||||
}
|
}
|
||||||
pipe->SetControllerCookie(&device->endpoints[id]);
|
pipe->SetControllerCookie(&device->endpoints[id]);
|
||||||
@ -1046,6 +1244,7 @@ status_t
|
|||||||
XHCI::_LinkDescriptorForPipe(xhci_td *descriptor, xhci_endpoint *endpoint)
|
XHCI::_LinkDescriptorForPipe(xhci_td *descriptor, xhci_endpoint *endpoint)
|
||||||
{
|
{
|
||||||
TRACE("_LinkDescriptorForPipe\n");
|
TRACE("_LinkDescriptorForPipe\n");
|
||||||
|
MutexLocker endpointLocker(endpoint->lock);
|
||||||
if (endpoint->used >= XHCI_MAX_TRANSFERS)
|
if (endpoint->used >= XHCI_MAX_TRANSFERS)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
@ -1062,11 +1261,10 @@ XHCI::_LinkDescriptorForPipe(xhci_td *descriptor, xhci_endpoint *endpoint)
|
|||||||
TRACE("_LinkDescriptorForPipe current %d, next %d\n", current, next);
|
TRACE("_LinkDescriptorForPipe current %d, next %d\n", current, next);
|
||||||
|
|
||||||
// compute next link
|
// compute next link
|
||||||
uint8 lastUsed = descriptor->last_used;
|
|
||||||
addr_t addr = endpoint->trb_addr + next * sizeof(struct xhci_trb);
|
addr_t addr = endpoint->trb_addr + next * sizeof(struct xhci_trb);
|
||||||
descriptor->trbs[lastUsed + 1].qwtrb0 = addr;
|
descriptor->trbs[descriptor->trb_count].qwtrb0 = addr;
|
||||||
descriptor->trbs[lastUsed + 1].dwtrb2 = TRB_2_IRQ(0);
|
descriptor->trbs[descriptor->trb_count].dwtrb2 = TRB_2_IRQ(0);
|
||||||
descriptor->trbs[lastUsed + 1].dwtrb3 = TRB_3_TYPE(TRB_TYPE_LINK)
|
descriptor->trbs[descriptor->trb_count].dwtrb3 = TRB_3_TYPE(TRB_TYPE_LINK)
|
||||||
| TRB_3_IOC_BIT | TRB_3_CYCLE_BIT;
|
| TRB_3_IOC_BIT | TRB_3_CYCLE_BIT;
|
||||||
|
|
||||||
endpoint->trbs[next].qwtrb0 = 0;
|
endpoint->trbs[next].qwtrb0 = 0;
|
||||||
@ -1092,6 +1290,7 @@ status_t
|
|||||||
XHCI::_UnlinkDescriptorForPipe(xhci_td *descriptor, xhci_endpoint *endpoint)
|
XHCI::_UnlinkDescriptorForPipe(xhci_td *descriptor, xhci_endpoint *endpoint)
|
||||||
{
|
{
|
||||||
TRACE("_UnlinkDescriptorForPipe\n");
|
TRACE("_UnlinkDescriptorForPipe\n");
|
||||||
|
MutexLocker endpointLocker(endpoint->lock);
|
||||||
endpoint->used--;
|
endpoint->used--;
|
||||||
if (descriptor == endpoint->td_head) {
|
if (descriptor == endpoint->td_head) {
|
||||||
endpoint->td_head = descriptor->next;
|
endpoint->td_head = descriptor->next;
|
||||||
@ -1115,7 +1314,7 @@ XHCI::_UnlinkDescriptorForPipe(xhci_td *descriptor, xhci_endpoint *endpoint)
|
|||||||
status_t
|
status_t
|
||||||
XHCI::ConfigureEndpoint(uint8 slot, uint8 number, uint8 type, uint64 ringAddr, uint16 interval,
|
XHCI::ConfigureEndpoint(uint8 slot, uint8 number, uint8 type, uint64 ringAddr, uint16 interval,
|
||||||
uint8 maxPacketCount, uint8 mult, uint8 fpsShift, uint16 maxPacketSize,
|
uint8 maxPacketCount, uint8 mult, uint8 fpsShift, uint16 maxPacketSize,
|
||||||
uint16 maxFrameSize)
|
uint16 maxFrameSize, usb_speed speed)
|
||||||
{
|
{
|
||||||
struct xhci_device *device = &fDevices[slot];
|
struct xhci_device *device = &fDevices[slot];
|
||||||
struct xhci_endpoint_ctx *endpoint = &device->input_ctx->endpoints[number];
|
struct xhci_endpoint_ctx *endpoint = &device->input_ctx->endpoints[number];
|
||||||
@ -1127,6 +1326,26 @@ XHCI::ConfigureEndpoint(uint8 slot, uint8 number, uint8 type, uint64 ringAddr, u
|
|||||||
|
|
||||||
endpoint->dwendpoint0 = ENDPOINT_0_STATE(0) | ENDPOINT_0_MAXPSTREAMS(0);
|
endpoint->dwendpoint0 = ENDPOINT_0_STATE(0) | ENDPOINT_0_MAXPSTREAMS(0);
|
||||||
// add mult for isochronous and interrupt types
|
// add mult for isochronous and interrupt types
|
||||||
|
switch (speed) {
|
||||||
|
case USB_SPEED_LOWSPEED:
|
||||||
|
case USB_SPEED_FULLSPEED:
|
||||||
|
fpsShift += 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (type) {
|
||||||
|
case 1:
|
||||||
|
case 5:
|
||||||
|
if (fpsShift > 3)
|
||||||
|
fpsShift--;
|
||||||
|
case 3:
|
||||||
|
case 7:
|
||||||
|
endpoint->dwendpoint0 |= ENDPOINT_0_INTERVAL(fpsShift);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
// add interval
|
// add interval
|
||||||
endpoint->dwendpoint1 = ENDPOINT_1_EPTYPE(type)
|
endpoint->dwendpoint1 = ENDPOINT_1_EPTYPE(type)
|
||||||
| ENDPOINT_1_MAXBURST(maxPacketCount)
|
| ENDPOINT_1_MAXBURST(maxPacketCount)
|
||||||
@ -1142,9 +1361,11 @@ XHCI::ConfigureEndpoint(uint8 slot, uint8 number, uint8 type, uint64 ringAddr, u
|
|||||||
case 3:
|
case 3:
|
||||||
case 5:
|
case 5:
|
||||||
case 7:
|
case 7:
|
||||||
endpoint->dwendpoint4 = ENDPOINT_4_AVGTRBLENGTH(maxFrameSize)
|
endpoint->dwendpoint4 = ENDPOINT_4_AVGTRBLENGTH(min_c(maxFrameSize,
|
||||||
| ENDPOINT_4_MAXESITPAYLOAD(maxFrameSize);
|
B_PAGE_SIZE)) | ENDPOINT_4_MAXESITPAYLOAD(maxFrameSize);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
endpoint->dwendpoint4 = ENDPOINT_4_AVGTRBLENGTH(B_PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("endpoint 0x%lx 0x%lx 0x%llx 0x%lx\n", endpoint->dwendpoint0,
|
TRACE("endpoint 0x%lx 0x%lx 0x%llx 0x%lx\n", endpoint->dwendpoint0,
|
||||||
@ -1406,55 +1627,8 @@ XHCI::Interrupt()
|
|||||||
}
|
}
|
||||||
|
|
||||||
TRACE("Event Interrupt\n");
|
TRACE("Event Interrupt\n");
|
||||||
uint16 i = fEventIdx;
|
release_sem_etc(fEventSem, 1, B_DO_NOT_RESCHEDULE);
|
||||||
uint8 j = fEventCcs;
|
return B_INVOKE_SCHEDULER;
|
||||||
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_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_TYPE_COMMAND_COMPLETION:
|
|
||||||
HandleCmdComplete(&fEventRing[i]);
|
|
||||||
result = B_INVOKE_SCHEDULER;
|
|
||||||
break;
|
|
||||||
case TRB_TYPE_TRANSFER:
|
|
||||||
HandleTransferComplete(&fEventRing[i]);
|
|
||||||
result = B_INVOKE_SCHEDULER;
|
|
||||||
break;
|
|
||||||
case TRB_TYPE_PORT_STATUS_CHANGE:
|
|
||||||
TRACE("port change detected\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
TRACE_ERROR("Unhandled event = %u\n", event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
if (i == XHCI_MAX_EVENTS) {
|
|
||||||
i = 0;
|
|
||||||
j ^= 1;
|
|
||||||
if (!--t)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fEventIdx = i;
|
|
||||||
fEventCcs = j;
|
|
||||||
|
|
||||||
uint64 addr = fErst->rs_addr + i * sizeof(xhci_trb);
|
|
||||||
addr |= ERST_EHB;
|
|
||||||
WriteRunReg32(XHCI_ERDP_LO(0), (uint32)addr);
|
|
||||||
WriteRunReg32(XHCI_ERDP_HI(0), (uint32)(addr >> 32));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1552,8 +1726,10 @@ XHCI::HandleTransferComplete(xhci_trb *trb)
|
|||||||
_UnlinkDescriptorForPipe(td, endpoint);
|
_UnlinkDescriptorForPipe(td, endpoint);
|
||||||
|
|
||||||
// add descriptor to finished list (to be processed and freed)
|
// add descriptor to finished list (to be processed and freed)
|
||||||
|
Lock();
|
||||||
td->next = fFinishedHead;
|
td->next = fFinishedHead;
|
||||||
fFinishedHead = td;
|
fFinishedHead = td;
|
||||||
|
Unlock();
|
||||||
release_sem(fFinishTransfersSem);
|
release_sem(fFinishTransfersSem);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1735,6 +1911,76 @@ XHCI::ResetDevice(uint8 slot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
XHCI::EventThread(void* data)
|
||||||
|
{
|
||||||
|
((XHCI *)data)->CompleteEvents();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
XHCI::CompleteEvents()
|
||||||
|
{
|
||||||
|
while (!fStopThreads) {
|
||||||
|
if (acquire_sem(fEventSem) < B_OK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// eat up sems that have been released by multiple interrupts
|
||||||
|
int32 semCount = 0;
|
||||||
|
get_sem_count(fEventSem, &semCount);
|
||||||
|
if (semCount > 0)
|
||||||
|
acquire_sem_etc(fEventSem, semCount, B_RELATIVE_TIMEOUT, 0);
|
||||||
|
|
||||||
|
uint16 i = fEventIdx;
|
||||||
|
uint8 j = fEventCcs;
|
||||||
|
uint8 t = 2;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
uint32 temp = fEventRing[i].dwtrb3;
|
||||||
|
uint8 k = (temp & TRB_3_CYCLE_BIT) ? 1 : 0;
|
||||||
|
if (j != k)
|
||||||
|
break;
|
||||||
|
|
||||||
|
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_TYPE_COMMAND_COMPLETION:
|
||||||
|
HandleCmdComplete(&fEventRing[i]);
|
||||||
|
break;
|
||||||
|
case TRB_TYPE_TRANSFER:
|
||||||
|
HandleTransferComplete(&fEventRing[i]);
|
||||||
|
break;
|
||||||
|
case TRB_TYPE_PORT_STATUS_CHANGE:
|
||||||
|
TRACE("port change detected\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
TRACE_ERROR("Unhandled event = %u\n", event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
if (i == XHCI_MAX_EVENTS) {
|
||||||
|
i = 0;
|
||||||
|
j ^= 1;
|
||||||
|
if (!--t)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fEventIdx = i;
|
||||||
|
fEventCcs = j;
|
||||||
|
|
||||||
|
uint64 addr = fErst->rs_addr + i * sizeof(xhci_trb);
|
||||||
|
addr |= ERST_EHB;
|
||||||
|
WriteRunReg32(XHCI_ERDP_LO(0), (uint32)addr);
|
||||||
|
WriteRunReg32(XHCI_ERDP_HI(0), (uint32)(addr >> 32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int32
|
int32
|
||||||
XHCI::FinishThread(void* data)
|
XHCI::FinishThread(void* data)
|
||||||
{
|
{
|
||||||
@ -1756,11 +2002,13 @@ XHCI::FinishTransfers()
|
|||||||
if (semCount > 0)
|
if (semCount > 0)
|
||||||
acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0);
|
acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0);
|
||||||
|
|
||||||
|
Lock();
|
||||||
TRACE("finishing transfers\n");
|
TRACE("finishing transfers\n");
|
||||||
while (fFinishedHead != NULL) {
|
while (fFinishedHead != NULL) {
|
||||||
xhci_td* td = fFinishedHead;
|
xhci_td* td = fFinishedHead;
|
||||||
fFinishedHead = td->next;
|
fFinishedHead = td->next;
|
||||||
td->next = NULL;
|
td->next = NULL;
|
||||||
|
Unlock();
|
||||||
|
|
||||||
Transfer* transfer = td->transfer;
|
Transfer* transfer = td->transfer;
|
||||||
bool directionIn = (transfer->TransferPipe()->Direction() != Pipe::Out);
|
bool directionIn = (transfer->TransferPipe()->Direction() != Pipe::Out);
|
||||||
@ -1769,15 +2017,25 @@ XHCI::FinishTransfers()
|
|||||||
// TODO check event
|
// TODO check event
|
||||||
status_t callbackStatus = B_OK;
|
status_t callbackStatus = B_OK;
|
||||||
size_t actualLength = requestData ? requestData->Length
|
size_t actualLength = requestData ? requestData->Length
|
||||||
: transfer->VectorLength();
|
: transfer->DataLength();
|
||||||
if (directionIn) {
|
TRACE("finishing transfer td %p\n", td);
|
||||||
|
if (directionIn && actualLength > 0) {
|
||||||
|
if (requestData) {
|
||||||
|
TRACE("copying in data %d bytes\n", requestData->Length);
|
||||||
memcpy((uint8 *)transfer->Vector()[0].iov_base,
|
memcpy((uint8 *)transfer->Vector()[0].iov_base,
|
||||||
td->buffer_log, actualLength);
|
td->buffer_log[0], requestData->Length);
|
||||||
|
} else {
|
||||||
|
TRACE("copying in iov count %ld\n", transfer->VectorCount());
|
||||||
|
ReadDescriptorChain(td, transfer->Vector(),
|
||||||
|
transfer->VectorCount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
transfer->Finished(callbackStatus, actualLength);
|
transfer->Finished(callbackStatus, actualLength);
|
||||||
|
|
||||||
FreeDescriptor(td);
|
FreeDescriptor(td);
|
||||||
|
Lock();
|
||||||
}
|
}
|
||||||
|
Unlock();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,16 +33,17 @@ enum xhci_state {
|
|||||||
|
|
||||||
|
|
||||||
typedef struct xhci_td {
|
typedef struct xhci_td {
|
||||||
struct xhci_trb trbs[18];
|
struct xhci_trb trbs[XHCI_MAX_TRBS_PER_TD];
|
||||||
|
|
||||||
addr_t buffer_phy;
|
|
||||||
addr_t this_phy; // A physical pointer to this address
|
addr_t this_phy; // A physical pointer to this address
|
||||||
void *buffer_log; // Pointer to the logical buffer
|
addr_t buffer_phy[XHCI_MAX_TRBS_PER_TD];
|
||||||
size_t buffer_size; // Size of the buffer
|
void *buffer_log[XHCI_MAX_TRBS_PER_TD]; // Pointer to the logical buffer
|
||||||
|
size_t buffer_size[XHCI_MAX_TRBS_PER_TD]; // Size of the buffer
|
||||||
|
uint8 buffer_count;
|
||||||
|
|
||||||
struct xhci_td *next;
|
struct xhci_td *next;
|
||||||
uint8 last_used;
|
|
||||||
Transfer *transfer;
|
Transfer *transfer;
|
||||||
|
uint8 trb_count;
|
||||||
} xhci_td __attribute__((__aligned__(16)));
|
} xhci_td __attribute__((__aligned__(16)));
|
||||||
|
|
||||||
|
|
||||||
@ -53,6 +54,7 @@ typedef struct xhci_endpoint {
|
|||||||
addr_t trb_addr;
|
addr_t trb_addr;
|
||||||
uint8 used;
|
uint8 used;
|
||||||
uint8 current;
|
uint8 current;
|
||||||
|
mutex lock;
|
||||||
} xhci_endpoint;
|
} xhci_endpoint;
|
||||||
|
|
||||||
|
|
||||||
@ -99,7 +101,8 @@ public:
|
|||||||
uint8 type, uint64 ringAddr,
|
uint8 type, uint64 ringAddr,
|
||||||
uint16 interval, uint8 maxPacketCount,
|
uint16 interval, uint8 maxPacketCount,
|
||||||
uint8 mult, uint8 fpsShift,
|
uint8 mult, uint8 fpsShift,
|
||||||
uint16 maxPacketSize, uint16 maxFrameSize);
|
uint16 maxPacketSize, uint16 maxFrameSize,
|
||||||
|
usb_speed speed);
|
||||||
virtual void FreeDevice(Device *device);
|
virtual void FreeDevice(Device *device);
|
||||||
|
|
||||||
status_t _InsertEndpointForPipe(Pipe *pipe);
|
status_t _InsertEndpointForPipe(Pipe *pipe);
|
||||||
@ -125,14 +128,24 @@ private:
|
|||||||
static int32 InterruptHandler(void *data);
|
static int32 InterruptHandler(void *data);
|
||||||
int32 Interrupt();
|
int32 Interrupt();
|
||||||
|
|
||||||
|
// Event management
|
||||||
|
static int32 EventThread(void *data);
|
||||||
|
void CompleteEvents();
|
||||||
|
|
||||||
// Transfer management
|
// Transfer management
|
||||||
static int32 FinishThread(void *data);
|
static int32 FinishThread(void *data);
|
||||||
void FinishTransfers();
|
void FinishTransfers();
|
||||||
|
|
||||||
// Descriptor
|
// Descriptor
|
||||||
xhci_td * CreateDescriptor(size_t bufferSize);
|
xhci_td * CreateDescriptor(size_t bufferSize);
|
||||||
|
xhci_td * CreateDescriptorChain(size_t bufferSize);
|
||||||
void FreeDescriptor(xhci_td *descriptor);
|
void FreeDescriptor(xhci_td *descriptor);
|
||||||
|
|
||||||
|
size_t WriteDescriptorChain(xhci_td *descriptor,
|
||||||
|
iovec *vector, size_t vectorCount);
|
||||||
|
size_t ReadDescriptorChain(xhci_td *descriptor,
|
||||||
|
iovec *vector, size_t vectorCount);
|
||||||
|
|
||||||
status_t _LinkDescriptorForPipe(xhci_td *descriptor,
|
status_t _LinkDescriptorForPipe(xhci_td *descriptor,
|
||||||
xhci_endpoint *endpoint);
|
xhci_endpoint *endpoint);
|
||||||
status_t _UnlinkDescriptorForPipe(xhci_td *descriptor,
|
status_t _UnlinkDescriptorForPipe(xhci_td *descriptor,
|
||||||
@ -230,6 +243,8 @@ private:
|
|||||||
// Devices
|
// Devices
|
||||||
struct xhci_device fDevices[XHCI_MAX_DEVICES];
|
struct xhci_device fDevices[XHCI_MAX_DEVICES];
|
||||||
|
|
||||||
|
sem_id fEventSem;
|
||||||
|
thread_id fEventThread;
|
||||||
uint16 fEventIdx;
|
uint16 fEventIdx;
|
||||||
uint16 fCmdIdx;
|
uint16 fCmdIdx;
|
||||||
uint8 fEventCcs;
|
uint8 fEventCcs;
|
||||||
|
@ -266,13 +266,14 @@
|
|||||||
#define XHCI_MAX_SCRATCHPADS 32
|
#define XHCI_MAX_SCRATCHPADS 32
|
||||||
#define XHCI_MAX_DEVICES 128
|
#define XHCI_MAX_DEVICES 128
|
||||||
#define XHCI_MAX_TRANSFERS 4
|
#define XHCI_MAX_TRANSFERS 4
|
||||||
|
#define XHCI_MAX_TRBS_PER_TD 18
|
||||||
|
|
||||||
|
|
||||||
struct xhci_trb {
|
struct xhci_trb {
|
||||||
uint64 qwtrb0;
|
uint64 qwtrb0;
|
||||||
uint32 dwtrb2;
|
uint32 dwtrb2;
|
||||||
uint32 dwtrb3;
|
uint32 dwtrb3;
|
||||||
} __attribute__((__aligned__(4)));;
|
} __attribute__((__aligned__(4)));
|
||||||
|
|
||||||
|
|
||||||
struct xhci_segment {
|
struct xhci_segment {
|
||||||
|
Loading…
Reference in New Issue
Block a user