#include "xhci.h" #include "commands.h" #include "controller.h" #include "trbRing.h" #include <hlib.h> #include <usb.h> XHCIInputContext *createInputContext(SlotXHCI *slot) { XHCIInputContext *inputContext = requestMemory(1, 0, 0); inputContext->inputControl.addContextFlags = 3; inputContext->deviceContext.slot.rootHubPort = slot->portIndex; inputContext->deviceContext.slot.interrupterTarget = 0; inputContext->deviceContext.slot.multiTT = 0; inputContext->deviceContext.slot.deviceAddress = 0; inputContext->deviceContext.slot.contextEntryCount = 1; inputContext->deviceContext.slot.speed = (slot->port->status >> 10) & 3; inputContext->deviceContext.endpoints[0].endpointType = 4; inputContext->deviceContext.endpoints[0].maxPacketSize = 8; // TODO inputContext->deviceContext.endpoints[0].maxBurstSize = 0; inputContext->deviceContext.endpoints[0].interval = 0; inputContext->deviceContext.endpoints[0].maxPrimaryStreams = 0; inputContext->deviceContext.endpoints[0].multiplier = 0; inputContext->deviceContext.endpoints[0].errorCount = 3; inputContext->deviceContext.endpoints[0].averageTRBLength = 1024; return inputContext; } UsbHostControllerInterface xhci; void *resetSlot(XHCIController *controller, uint32_t portIndex) { SlotXHCI *slot = malloc(sizeof(SlotXHCI)); slot->portIndex = portIndex; slot->controller = controller; slot->slotIndex = requestSlotIndex(controller); slot->port = &controller->operational->ports[portIndex - 1]; printf("port %i: connecting to slot %i\n", portIndex, slot->slotIndex); slot->port->status |= 1 << 4; await(serviceId, createDirectEventSave(slot->portIndex << 24)); if (!(slot->port->status & 1 << 1)) { printf("port %i reset not succesful, aborting\n", portIndex); return NULL; } slot->inputContext = createInputContext(slot); slot->controlRing = createSlotTRB(slot); controller->deviceContexts[slot->slotIndex] = malloc(sizeof(XHCIDevice)); slot->controller->deviceContextBaseAddressArray[slot->slotIndex] = U32(getPhysicalAddress( (void *)controller->deviceContexts[slot->slotIndex])); printf("port %i: addressing slot\n", portIndex); addressDevice(slot, true); addressDevice(slot, false); UsbSlot *result = malloc(sizeof(UsbSlot)); result->data = slot; result->interface = &xhci; result->portIndex = portIndex; return result; } void *init(uint32_t deviceId, uint32_t bar0, uint32_t interrupt) { UsbHostController *host = malloc(sizeof(UsbHostController)); XHCIController *controller = xhciSetup(deviceId, bar0, interrupt); host->data = controller; for (uint32_t i = 0; i < controller->portCount; i++) { if (!(controller->operational->ports[i].status & 1 << 0)) { continue; } listAdd(&host->slots, resetSlot(controller, i + 1)); } return host; } void xhciSetupEndpoints(SlotXHCI *slot, ListElement *endpoints, uint32_t configValue) { XHCIController *controller = slot->controller; XHCIInputContext *inputContext = slot->inputContext; memcpy((void *)controller->deviceContexts[slot->slotIndex], (void *)&inputContext->deviceContext, sizeof(XHCIDevice)); inputContext->inputControl.addContextFlags = 1; printf("slot context state: %x, address: %x\n", inputContext->deviceContext.slot.slotState, inputContext->deviceContext.slot.deviceAddress); foreach (endpoints, UsbEndpointDescriptor *, endpoint, { uint8_t endpointNumber = endpoint->address & 0xF; // never 0 uint8_t direction = endpoint->address >> 7; uint8_t endpointIndex = (endpointNumber)*2 - 1 + direction; XHCIEndpointContext *endpointContext = &inputContext->deviceContext.endpoints[endpointIndex]; endpointContext->maxPrimaryStreams = 0; endpointContext->interval = endpoint->interval; endpointContext->errorCount = 3; endpointContext->endpointType = direction << 2 | endpoint->attributes & 3; endpointContext->maxPacketSize = endpoint->maxPacketSize; slot->endpointRings[endpointIndex] = malloc(sizeof(TrbRing)); setupTrbRing(slot->endpointRings[endpointIndex], 256); endpointContext->transferDequeuePointerLow = U32(slot->endpointRings[endpointIndex]->physical) | 1; endpointContext->transferDequeuePointerHigh = 0; endpointContext->averageTRBLength = 2048; inputContext->inputControl.addContextFlags |= 1 << (endpointIndex + 1); inputContext->deviceContext.slot.contextEntryCount = MAX( inputContext->deviceContext.slot.contextEntryCount, endpointIndex); }) ; XHCISetupStageTRB setup = {0}; setup.requestType = 0x00; setup.request = 9; setup.value = configValue; setup.index = 0; setup.length = 0; setup.transferLength = 8; setup.interruptOnCompletion = 0; setup.interrupterTarget = 0; setup.type = 2; setup.transferType = 3; setup.immediateData = 1; XHCIStatusStageTRB status = {0}; status.inDirection = 0; status.evaluateNext = 0; status.interruptOnCompletion = 1; status.type = 4; uint32_t control = COMMAND_TYPE(12) | COMMAND_SLOT_ID(slot->slotIndex); xhciCommand(controller, U32(getPhysicalAddress((void *)inputContext)), 0, 0, control); enqueueCommand(slot->controlRing, (void *)&setup); uint32_t commandAddress = U32(enqueueCommand(slot->controlRing, (void *)&status)); uint32_t eventId = createDirectEventSave(commandAddress); slot->controller->doorbells[slot->slotIndex] = 1; await(serviceId, eventId); } void setProtocol(SlotXHCI *slot) { XHCISetupStageTRB setup = {0}; setup.requestType = 0x21; setup.request = 0x0B; setup.value = 0; setup.index = 0; setup.length = 0; setup.transferLength = 8; setup.interruptOnCompletion = 0; setup.interrupterTarget = 0; setup.type = 2; setup.transferType = 3; setup.immediateData = 1; XHCIStatusStageTRB status = {0}; status.inDirection = 1; status.evaluateNext = 0; status.interruptOnCompletion = 1; status.type = 4; enqueueCommand(slot->controlRing, (void *)&setup); uint32_t commandAddress = U32(enqueueCommand(slot->controlRing, (void *)&status)); uint32_t eventId = createDirectEventSave(commandAddress); slot->controller->doorbells[slot->slotIndex] = 1; await(serviceId, eventId); } void setIdle(SlotXHCI *slot) { XHCISetupStageTRB setup = {0}; setup.requestType = 0x21; setup.request = 0x0A; setup.value = 0; setup.index = 0; setup.length = 0; setup.transferLength = 8; setup.interruptOnCompletion = 0; setup.interrupterTarget = 0; setup.type = 2; setup.transferType = 3; setup.immediateData = 1; XHCIStatusStageTRB status = {0}; status.inDirection = 1; status.evaluateNext = 0; status.interruptOnCompletion = 1; status.type = 4; enqueueCommand(slot->controlRing, (void *)&setup); uint32_t commandAddress = U32(enqueueCommand(slot->controlRing, (void *)&status)); uint32_t eventId = createDirectEventSave(commandAddress); slot->controller->doorbells[slot->slotIndex] = 1; await(serviceId, eventId); } void setupHID(SlotXHCI *slot, uint32_t endpointIndex, void *buffer) { setProtocol(slot); setIdle(slot); XHCINormalTRB normal = {0}; normal.type = 1; normal.inDirection = 1; normal.interrupterTarget = 0; normal.interruptOnCompletion = 1; normal.interruptOnShortPacket = 1; normal.dataBuffer[0] = U32(getPhysicalAddress(buffer)); normal.transferSize = 4; while (1) { uint32_t commandAddress = U32(enqueueCommand( slot->endpointRings[endpointIndex], (void *)&normal)); uint32_t eventId = createDirectEventSave(commandAddress); slot->controller->doorbells[slot->slotIndex] = endpointIndex + 1; await(serviceId, eventId); MouseReport *report = buffer; printf("event: buttons: %i, ", report->buttons); // TODO add negative number printing support to printf if (report->x < 0) { printf("x: -%i, ", -report->x); } else { printf("x: %i, ", report->x); } if (report->y < 0) { printf("y: -%i\n", -report->y); } else { printf("y: %i\n", report->y); } // todo: sleep for at least endpoint->interval? // todo: start this loop in a fork? sleep(100); } } UsbHostControllerInterface xhci = { .initialize = init, .getDeviceDescriptor = (void *)usbGetDeviceDescriptor, .setupEndpoints = (void *)xhciSetupEndpoints, .setupHID = (void *)setupHID, .pciClass = 0x0C0330, };