Work in progress on xHCI bus driver.
* added more traces, coding style * added xhci_td, xhci_endpoint structs. * SubmitRequest: this links a 3-stage TD control request into the endpoint ring. * _InsertEndpointForPipe: when a pipe is created, configure the endpoint and set up the controller cookie. * CreateDescriptor and FreeDescriptor: allocates memory for a TD. * _LinkDescriptorForPipe: link a TD in an endpoint ring. * _UnlinkDescriptorForPipe: unlink a TD * AllocateDevice: slot number zero isn't valid. stick the slot number to the device struct. configure the default endpoint before calling SetAddress. address is found in the device context instead of the input context. device address passed to the USB stack has to begin with 1. * Ring: check for invalid slot/endpoint combination. ring the slot doorbell instead of the doorbell 0. * Root hub: fixed USB version. * HandleTransferComplete: finds out the TD which submitted a transfer.
This commit is contained in:
parent
319a3798bc
commit
2b31b4a88c
@ -12,7 +12,7 @@
|
||||
|
||||
Device::Device(Object *parent, int8 hubAddress, uint8 hubPort,
|
||||
usb_device_descriptor &desc, int8 deviceAddress, usb_speed speed,
|
||||
bool isRootHub)
|
||||
bool isRootHub, void *controllerCookie)
|
||||
: Object(parent),
|
||||
fDeviceDescriptor(desc),
|
||||
fInitOK(false),
|
||||
@ -23,7 +23,8 @@ Device::Device(Object *parent, int8 hubAddress, uint8 hubPort,
|
||||
fSpeed(speed),
|
||||
fDeviceAddress(deviceAddress),
|
||||
fHubAddress(hubAddress),
|
||||
fHubPort(hubPort)
|
||||
fHubPort(hubPort),
|
||||
fControllerCookie(controllerCookie)
|
||||
{
|
||||
TRACE("creating device\n");
|
||||
|
||||
@ -455,20 +456,20 @@ Device::InitEndpoints(int32 interfaceIndex)
|
||||
direction = Pipe::In;
|
||||
|
||||
switch (endpoint->descr->attributes & 0x03) {
|
||||
case 0x00: /* Control Endpoint */
|
||||
case USB_ENDPOINT_ATTR_CONTROL: /* Control Endpoint */
|
||||
pipe = new(std::nothrow) ControlPipe(this);
|
||||
direction = Pipe::Default;
|
||||
break;
|
||||
|
||||
case 0x01: /* Isochronous Endpoint */
|
||||
case USB_ENDPOINT_ATTR_ISOCHRONOUS: /* Isochronous Endpoint */
|
||||
pipe = new(std::nothrow) IsochronousPipe(this);
|
||||
break;
|
||||
|
||||
case 0x02: /* Bulk Endpoint */
|
||||
case USB_ENDPOINT_ATTR_BULK: /* Bulk Endpoint */
|
||||
pipe = new(std::nothrow) BulkPipe(this);
|
||||
break;
|
||||
|
||||
case 0x03: /* Interrupt Endpoint */
|
||||
case USB_ENDPOINT_ATTR_INTERRUPT: /* Interrupt Endpoint */
|
||||
pipe = new(std::nothrow) InterruptPipe(this);
|
||||
break;
|
||||
}
|
||||
|
@ -480,7 +480,8 @@ public:
|
||||
uint8 hubPort,
|
||||
usb_device_descriptor &desc,
|
||||
int8 deviceAddress,
|
||||
usb_speed speed, bool isRootHub);
|
||||
usb_speed speed, bool isRootHub,
|
||||
void *controllerCookie = NULL);
|
||||
virtual ~Device();
|
||||
|
||||
status_t InitCheck();
|
||||
@ -535,6 +536,11 @@ virtual status_t BuildDeviceName(char *string,
|
||||
{ return fHubAddress; }
|
||||
uint8 HubPort() const { return fHubPort; }
|
||||
|
||||
void SetControllerCookie(void *cookie)
|
||||
{ fControllerCookie = cookie; }
|
||||
void * ControllerCookie() const
|
||||
{ return fControllerCookie; }
|
||||
|
||||
// Convenience functions for standard requests
|
||||
virtual status_t SetFeature(uint16 selector);
|
||||
virtual status_t ClearFeature(uint16 selector);
|
||||
@ -554,6 +560,7 @@ private:
|
||||
int8 fHubAddress;
|
||||
uint8 fHubPort;
|
||||
ControlPipe * fDefaultPipe;
|
||||
void * fControllerCookie;
|
||||
};
|
||||
|
||||
|
||||
|
@ -422,6 +422,55 @@ XHCI::SubmitTransfer(Transfer *transfer)
|
||||
Pipe *pipe = transfer->TransferPipe();
|
||||
if (pipe->Type() & USB_OBJECT_ISO_PIPE)
|
||||
return B_UNSUPPORTED;
|
||||
if (pipe->Type() & USB_OBJECT_CONTROL_PIPE)
|
||||
return SubmitRequest(transfer);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
XHCI::SubmitRequest(Transfer *transfer)
|
||||
{
|
||||
Pipe *pipe = transfer->TransferPipe();
|
||||
usb_request_data *requestData = transfer->RequestData();
|
||||
bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) != 0;
|
||||
|
||||
TRACE("SubmitRequest()\n");
|
||||
|
||||
xhci_td *setupDescriptor = CreateDescriptor(sizeof(usb_request_data));
|
||||
|
||||
// set SetupStage
|
||||
uint8 index = 0;
|
||||
setupDescriptor->trbs[index].dwtrb2 = TRB_2_IRQ(0) | TRB_2_BYTES(8);
|
||||
setupDescriptor->trbs[index].dwtrb3 = TRB_3_TYPE(TRB_TYPE_SETUP_STAGE)
|
||||
| TRB_3_IDT_BIT | TRB_3_CYCLE_BIT;
|
||||
if (requestData->Length > 0) {
|
||||
setupDescriptor->trbs[index].dwtrb3 |= directionIn ? TRB_3_TRT_IN
|
||||
: TRB_3_TRT_OUT;
|
||||
}
|
||||
memcpy(&setupDescriptor->trbs[index].qwtrb0, requestData,
|
||||
sizeof(usb_request_data));
|
||||
|
||||
index++;
|
||||
|
||||
// set DataStage if any
|
||||
// set StatusStage
|
||||
setupDescriptor->trbs[index].dwtrb2 = TRB_2_IRQ(0);
|
||||
setupDescriptor->trbs[index].dwtrb3 = TRB_3_TYPE(TRB_TYPE_STATUS_STAGE)
|
||||
| (directionIn ? 0 : TRB_3_DIR_IN) | TRB_3_CYCLE_BIT | TRB_3_IOC_BIT;
|
||||
|
||||
setupDescriptor->last_used = index;
|
||||
|
||||
xhci_endpoint *endpoint = (xhci_endpoint *)pipe->ControllerCookie();
|
||||
uint8 id = XHCI_ENDPOINT_ID(pipe);
|
||||
if (id >= XHCI_MAX_ENDPOINTS)
|
||||
return B_BAD_VALUE;
|
||||
setupDescriptor->transfer = transfer;
|
||||
_LinkDescriptorForPipe(setupDescriptor, endpoint);
|
||||
|
||||
TRACE("SubmitRequest() request linked\n");
|
||||
|
||||
Ring(endpoint->device->slot, id);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@ -440,11 +489,11 @@ XHCI::NotifyPipeChange(Pipe *pipe, usb_change change)
|
||||
TRACE("pipe change %d for pipe %p\n", change, pipe);
|
||||
switch (change) {
|
||||
case USB_CHANGE_CREATED:
|
||||
case USB_CHANGE_DESTROYED: {
|
||||
// ToDo: we should create and keep a single queue head
|
||||
// for all transfers to/from this pipe
|
||||
_InsertEndpointForPipe(pipe);
|
||||
break;
|
||||
case USB_CHANGE_DESTROYED:
|
||||
_RemoveEndpointForPipe(pipe);
|
||||
break;
|
||||
}
|
||||
|
||||
case USB_CHANGE_PIPE_POLICY_CHANGED: {
|
||||
// ToDo: for isochronous pipes we might need to adapt to new
|
||||
@ -533,6 +582,52 @@ XHCI::AddTo(Stack *stack)
|
||||
}
|
||||
|
||||
|
||||
xhci_td *
|
||||
XHCI::CreateDescriptor(size_t bufferSize)
|
||||
{
|
||||
xhci_td *result;
|
||||
addr_t physicalAddress;
|
||||
|
||||
if (fStack->AllocateChunk((void **)&result, (void**)&physicalAddress,
|
||||
sizeof(xhci_td)) < B_OK) {
|
||||
TRACE_ERROR("failed to allocate a transfer descriptor\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result->this_phy = (addr_t)physicalAddress;
|
||||
result->buffer_size = bufferSize;
|
||||
if (bufferSize <= 0) {
|
||||
result->buffer_log = NULL;
|
||||
result->buffer_phy = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (fStack->AllocateChunk(&result->buffer_log, (void **)&result->buffer_phy,
|
||||
bufferSize) < B_OK) {
|
||||
TRACE_ERROR("unable to allocate space for the buffer\n");
|
||||
fStack->FreeChunk(result, (void *)result->this_phy, sizeof(xhci_td));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XHCI::FreeDescriptor(xhci_td *descriptor)
|
||||
{
|
||||
if (!descriptor)
|
||||
return;
|
||||
|
||||
if (descriptor->buffer_log) {
|
||||
fStack->FreeChunk(descriptor->buffer_log,
|
||||
(void *)descriptor->buffer_phy, descriptor->buffer_size);
|
||||
}
|
||||
|
||||
fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(xhci_td));
|
||||
}
|
||||
|
||||
|
||||
Device *
|
||||
XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
|
||||
usb_speed speed)
|
||||
@ -548,7 +643,7 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (slot > fSlotCount) {
|
||||
if (slot == 0 || slot > fSlotCount) {
|
||||
TRACE_ERROR("AllocateDevice() bad slot\n");
|
||||
return NULL;
|
||||
}
|
||||
@ -561,9 +656,11 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
|
||||
struct xhci_device *device = &fDevices[slot];
|
||||
memset(device, 0, sizeof(struct xhci_device));
|
||||
device->state = XHCI_STATE_ENABLED;
|
||||
device->slot = slot;
|
||||
|
||||
device->input_ctx_area = fStack->AllocateArea((void **)&device->input_ctx,
|
||||
(void**)&device->input_ctx_addr, sizeof(*device->input_ctx), "XHCI input context");
|
||||
(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;
|
||||
@ -587,6 +684,9 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
|
||||
}
|
||||
|
||||
device->input_ctx->slot.dwslot0 = SLOT_0_NUM_ENTRIES(1) | SLOT_0_ROUTE(route);
|
||||
//device->input_ctx->slot.dwslot0 =
|
||||
// SLOT_0_NUM_ENTRIES(XHCI_MAX_ENDPOINTS - 1) | SLOT_0_ROUTE(route);
|
||||
|
||||
// add the speed
|
||||
switch (speed) {
|
||||
case USB_SPEED_LOWSPEED:
|
||||
@ -606,7 +706,7 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
|
||||
break;
|
||||
}
|
||||
|
||||
device->input_ctx->slot.dwslot1 = SLOT_1_RH_PORT(rhPort);
|
||||
device->input_ctx->slot.dwslot1 = SLOT_1_RH_PORT(rhPort); // TODO enable power save
|
||||
device->input_ctx->slot.dwslot2 = SLOT_2_IRQ_TARGET(0);
|
||||
if (0)
|
||||
device->input_ctx->slot.dwslot2 |= SLOT_2_PORT_NUM(hubPort);
|
||||
@ -664,18 +764,31 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (SetAddress(device->input_ctx_addr, 1, slot) != B_OK) {
|
||||
device->endpoints[0].device = device;
|
||||
device->endpoints[0].td_head = NULL;
|
||||
device->endpoints[0].trbs = device->trbs[0];
|
||||
device->endpoints[0].used = 0;
|
||||
device->endpoints[0].current = 0;
|
||||
device->endpoints[0].trb_addr = device->trb_addr;
|
||||
|
||||
// device should get to default state (bsr = 1)
|
||||
if (SetAddress(device->input_ctx_addr, 0, slot) != B_OK) {
|
||||
TRACE_ERROR("unable to set address\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8 deviceAddress = SLOT_3_DEVICE_ADDRESS(device->input_ctx->slot.dwslot3);
|
||||
device->state = XHCI_STATE_DEFAULT;
|
||||
device->address = SLOT_3_DEVICE_ADDRESS_GET(device->device_ctx->slot.dwslot3);
|
||||
|
||||
TRACE("deviceAddress 0x%x\n", deviceAddress);
|
||||
TRACE("device: address 0x%x state 0x%lx\n", device->address,
|
||||
SLOT_3_SLOT_STATE_GET(device->device_ctx->slot.dwslot3));
|
||||
TRACE("endpoint0 state 0x%lx\n",
|
||||
ENDPOINT_0_STATE_GET(device->device_ctx->endpoints[0].dwendpoint0));
|
||||
|
||||
// Create a temporary pipe with the new address
|
||||
ControlPipe pipe(parent);
|
||||
pipe.InitCommon(deviceAddress, 0, speed, Pipe::Default, 8, 0, hubAddress,
|
||||
pipe.SetControllerCookie(&device->endpoints[0]);
|
||||
pipe.InitCommon(device->address + 1, 0, speed, Pipe::Default, 8, 0, hubAddress,
|
||||
hubPort);
|
||||
|
||||
// Get the device descriptor
|
||||
@ -698,13 +811,16 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort,
|
||||
|
||||
if (actualLength != 8) {
|
||||
TRACE_ERROR("error while getting the device descriptor\n");
|
||||
FreeAddress(deviceAddress);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TRACE("device_class: %d device_subclass %d device_protocol %d\n",
|
||||
deviceDescriptor.device_class, deviceDescriptor.device_subclass,
|
||||
deviceDescriptor.device_protocol);
|
||||
|
||||
TRACE("creating new device\n");
|
||||
Device *deviceObject = new(std::nothrow) Device(parent, hubAddress, hubPort,
|
||||
deviceDescriptor, deviceAddress, speed, false);
|
||||
deviceDescriptor, device->address + 1, speed, false, device);
|
||||
if (!deviceObject) {
|
||||
TRACE_ERROR("no memory to allocate device\n");
|
||||
return NULL;
|
||||
@ -731,6 +847,114 @@ XHCI::FreeDevice(Device *device)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
XHCI::_InsertEndpointForPipe(Pipe *pipe)
|
||||
{
|
||||
if (pipe->ControllerCookie() != NULL
|
||||
|| pipe->Parent()->Type() != USB_OBJECT_DEVICE) {
|
||||
// default pipe is already referenced
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
Device* usbDevice = (Device *)pipe->Parent();
|
||||
struct xhci_device *device = (struct xhci_device *)
|
||||
usbDevice->ControllerCookie();
|
||||
if (usbDevice->Parent() == RootObject())
|
||||
return B_OK;
|
||||
if (device == NULL) {
|
||||
panic("_InsertEndpointForPipe device is NULL\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
uint8 id = XHCI_ENDPOINT_ID(pipe);
|
||||
if (id >= XHCI_MAX_ENDPOINTS)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
device->endpoints[id].device = device;
|
||||
device->endpoints[id].trbs = device->trbs[id];
|
||||
device->endpoints[id].td_head = NULL;
|
||||
device->endpoints[id].used = 0;
|
||||
device->endpoints[id].trb_addr = device->trb_addr
|
||||
+ id * sizeof(device->trbs[0]);
|
||||
pipe->SetControllerCookie(&device->endpoints[id]);
|
||||
|
||||
TRACE("_InsertEndpointForPipe for pipe %p at id %d\n", pipe, id);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
XHCI::_RemoveEndpointForPipe(Pipe *pipe)
|
||||
{
|
||||
if (pipe->Parent()->Type() != USB_OBJECT_DEVICE)
|
||||
return B_OK;
|
||||
//Device* device = (Device *)pipe->Parent();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
XHCI::_LinkDescriptorForPipe(xhci_td *descriptor, xhci_endpoint *endpoint)
|
||||
{
|
||||
TRACE("_LinkDescriptorForPipe\n");
|
||||
if (endpoint->used >= XHCI_MAX_TRANSFERS)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
endpoint->used++;
|
||||
if (endpoint->td_head == NULL)
|
||||
descriptor-> next = NULL;
|
||||
else
|
||||
descriptor->next = endpoint->td_head;
|
||||
endpoint->td_head = descriptor;
|
||||
|
||||
uint8 current = endpoint->current;
|
||||
uint8 next = (current + 1) % (XHCI_MAX_TRANSFERS - 1);
|
||||
|
||||
// compute next link
|
||||
uint8 lastUsed = descriptor->last_used;
|
||||
addr_t addr = endpoint->trb_addr + next * sizeof(struct xhci_trb);
|
||||
descriptor->trbs[lastUsed + 1].qwtrb0 = addr;
|
||||
descriptor->trbs[lastUsed + 1].dwtrb2 = TRB_2_IRQ(0);
|
||||
descriptor->trbs[lastUsed + 1].dwtrb3 = TRB_3_TYPE(TRB_TYPE_LINK)
|
||||
| TRB_3_IOC_BIT | TRB_3_CYCLE_BIT;
|
||||
|
||||
endpoint->trbs[next]->qwtrb0 = 0;
|
||||
endpoint->trbs[next]->dwtrb2 = 0;
|
||||
endpoint->trbs[next]->dwtrb3 = 0;
|
||||
|
||||
endpoint->trbs[current]->qwtrb0 = descriptor->this_phy;
|
||||
endpoint->trbs[current]->dwtrb2 = TRB_2_IRQ(0);
|
||||
endpoint->trbs[current]->dwtrb3 = TRB_3_TYPE(TRB_TYPE_LINK)
|
||||
| TRB_3_CYCLE_BIT;
|
||||
endpoint->current = next;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
XHCI::_UnlinkDescriptorForPipe(xhci_td *descriptor, xhci_endpoint *endpoint)
|
||||
{
|
||||
TRACE("_UnlinkDescriptorForPipe\n");
|
||||
endpoint->used--;
|
||||
if (descriptor == endpoint->td_head)
|
||||
endpoint->td_head = descriptor->next;
|
||||
else {
|
||||
for (xhci_td *td = endpoint->td_head; td->next != NULL; td = td->next) {
|
||||
if (td->next == descriptor) {
|
||||
td->next = descriptor->next;
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endpoint->used++;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
XHCI::ConfigureEndpoint(uint8 slot, uint8 number, uint8 type, uint64 ringAddr, uint16 interval,
|
||||
uint8 maxPacketCount, uint8 mult, uint8 fpsShift, uint16 maxPacketSize,
|
||||
@ -1003,22 +1227,28 @@ XHCI::Interrupt()
|
||||
uint32 temp = ReadRunReg32(XHCI_IMAN(0));
|
||||
WriteOpReg(XHCI_STS, status);
|
||||
WriteRunReg32(XHCI_IMAN(0), temp);
|
||||
TRACE("STS: %lx IRQ_PENDING: %lx\n", status, temp);
|
||||
|
||||
int32 result = B_HANDLED_INTERRUPT;
|
||||
|
||||
if (status & STS_HCH) {
|
||||
if ((status & STS_HCH) != 0) {
|
||||
TRACE_ERROR("Host Controller halted\n");
|
||||
return result;
|
||||
}
|
||||
if (status & STS_HSE) {
|
||||
if ((status & STS_HSE) != 0) {
|
||||
TRACE_ERROR("Host System Error\n");
|
||||
return result;
|
||||
}
|
||||
if (status & STS_HCE) {
|
||||
if ((status & STS_HCE) != 0) {
|
||||
TRACE_ERROR("Host Controller Error\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((status & STS_EINT) == 0) {
|
||||
TRACE("STS: %lx IRQ_PENDING: %lx\n", status, temp);
|
||||
return B_UNHANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
TRACE("Event Interrupt\n");
|
||||
uint16 i = fEventIdx;
|
||||
uint8 j = fEventCcs;
|
||||
uint8 t = 2;
|
||||
@ -1038,6 +1268,13 @@ XHCI::Interrupt()
|
||||
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;
|
||||
@ -1065,12 +1302,17 @@ XHCI::Interrupt()
|
||||
|
||||
|
||||
void
|
||||
XHCI::Ring()
|
||||
XHCI::Ring(uint8 slot, uint8 endpoint)
|
||||
{
|
||||
TRACE("Ding Dong!\n")
|
||||
WriteDoorReg32(XHCI_DOORBELL(0), 0);
|
||||
TRACE("Ding Dong! slot:%d endpoint %d\n", slot, endpoint)
|
||||
if ((slot == 0 && endpoint > 0) || (slot > 0 && endpoint == 0))
|
||||
panic("Ring() invalid slot/endpoint combination\n");
|
||||
if (slot > fSlotCount || endpoint > XHCI_MAX_ENDPOINTS)
|
||||
panic("Ring() invalid slot or endpoint\n");
|
||||
WriteDoorReg32(XHCI_DOORBELL(slot), XHCI_DOORBELL_TARGET(endpoint)
|
||||
| XHCI_DOORBELL_STREAMID(0));
|
||||
/* Flush PCI posted writes */
|
||||
ReadDoorReg32(XHCI_DOORBELL(0));
|
||||
ReadDoorReg32(XHCI_DOORBELL(slot));
|
||||
}
|
||||
|
||||
|
||||
@ -1130,6 +1372,32 @@ XHCI::HandleCmdComplete(xhci_trb *trb)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XHCI::HandleTransferComplete(xhci_trb *trb)
|
||||
{
|
||||
TRACE("HandleTransferComplete trb %p\n", trb);
|
||||
addr_t source = trb->qwtrb0;
|
||||
//uint8 completionCode = TRB_2_COMP_CODE_GET(trb->dwtrb2);
|
||||
//uint32 remainder = TRB_2_REM(trb->dwtrb2);
|
||||
uint8 endpointNumber = TRB_3_ENDPOINT(trb->dwtrb3);
|
||||
uint8 slot = TRB_3_SLOT(trb->dwtrb3);
|
||||
|
||||
if (slot > fSlotCount)
|
||||
TRACE_ERROR("invalid slot\n");
|
||||
if (endpointNumber == 0 || endpointNumber > XHCI_MAX_ENDPOINTS)
|
||||
TRACE_ERROR("invalid endpoint\n");
|
||||
|
||||
xhci_device *device = &fDevices[slot];
|
||||
xhci_endpoint *endpoint = &device->endpoints[endpointNumber];
|
||||
for (xhci_td *td = endpoint->td_head; td != NULL; td = td->next) {
|
||||
int64 offset = source - td->this_phy;
|
||||
TRACE("HandleTransferComplete td %p offset %lld\n", td, offset);
|
||||
_UnlinkDescriptorForPipe(td, endpoint);
|
||||
FreeDescriptor(td);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
XHCI::DoCommand(xhci_trb *trb)
|
||||
{
|
||||
@ -1137,7 +1405,7 @@ XHCI::DoCommand(xhci_trb *trb)
|
||||
return B_ERROR;
|
||||
|
||||
QueueCommand(trb);
|
||||
Ring();
|
||||
Ring(0, 0);
|
||||
|
||||
if (acquire_sem(fCmdCompSem) < B_OK) {
|
||||
Unlock();
|
||||
@ -1159,6 +1427,7 @@ XHCI::DoCommand(xhci_trb *trb)
|
||||
|
||||
trb->dwtrb2 = fCmdResult[0];
|
||||
trb->dwtrb3 = fCmdResult[1];
|
||||
TRACE("Storing trb 0x%08lx 0x%08lx\n", trb->dwtrb2, trb->dwtrb3);
|
||||
|
||||
Unlock();
|
||||
return status;
|
||||
@ -1190,7 +1459,7 @@ XHCI::EnableSlot(uint8 *slot)
|
||||
return status;
|
||||
|
||||
*slot = TRB_3_SLOT_GET(trb.dwtrb3);
|
||||
return B_OK;
|
||||
return *slot != 0 ? B_OK : B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -17,18 +17,48 @@
|
||||
|
||||
struct pci_info;
|
||||
struct pci_module_info;
|
||||
struct xhci_td;
|
||||
struct xhci_device;
|
||||
struct xhci_endpoint;
|
||||
class XHCIRootHub;
|
||||
|
||||
|
||||
enum xhci_state {
|
||||
XHCI_STATE_DISABLED = 0,
|
||||
XHCI_STATE_ENABLED,
|
||||
XHCI_STATE_DEFAULT,
|
||||
XHCI_STATE_ADDRESSED,
|
||||
XHCI_STATE_CONFIGURED,
|
||||
};
|
||||
|
||||
|
||||
struct xhci_device {
|
||||
typedef struct xhci_td {
|
||||
struct xhci_trb trbs[18];
|
||||
|
||||
addr_t buffer_phy;
|
||||
addr_t this_phy; // A physical pointer to this address
|
||||
void *buffer_log; // Pointer to the logical buffer
|
||||
size_t buffer_size; // Size of the buffer
|
||||
|
||||
struct xhci_td *next;
|
||||
uint8 last_used;
|
||||
Transfer *transfer;
|
||||
} xhci_td __attribute__((__aligned__(16)));
|
||||
|
||||
|
||||
typedef struct xhci_endpoint {
|
||||
xhci_device *device;
|
||||
xhci_td *td_head;
|
||||
struct xhci_trb (*trbs)[XHCI_MAX_TRANSFERS];
|
||||
addr_t trb_addr;
|
||||
uint8 used;
|
||||
uint8 current;
|
||||
} xhci_endpoint;
|
||||
|
||||
|
||||
typedef struct xhci_device {
|
||||
uint8 slot;
|
||||
uint8 address;
|
||||
enum xhci_state state;
|
||||
area_id trb_area;
|
||||
addr_t trb_addr;
|
||||
@ -41,7 +71,9 @@ struct xhci_device {
|
||||
area_id device_ctx_area;
|
||||
addr_t device_ctx_addr;
|
||||
struct xhci_device_ctx *device_ctx;
|
||||
};
|
||||
|
||||
xhci_endpoint endpoints[XHCI_MAX_ENDPOINTS - 1];
|
||||
} xhci_device;
|
||||
|
||||
|
||||
class XHCI : public BusManager {
|
||||
@ -51,6 +83,7 @@ public:
|
||||
|
||||
status_t Start();
|
||||
virtual status_t SubmitTransfer(Transfer *transfer);
|
||||
status_t SubmitRequest(Transfer *transfer);
|
||||
virtual status_t CancelQueuedTransfers(Pipe *pipe, bool force);
|
||||
|
||||
virtual status_t NotifyPipeChange(Pipe *pipe,
|
||||
@ -68,6 +101,9 @@ public:
|
||||
uint16 maxPacketSize, uint16 maxFrameSize);
|
||||
virtual void FreeDevice(Device *device);
|
||||
|
||||
status_t _InsertEndpointForPipe(Pipe *pipe);
|
||||
status_t _RemoveEndpointForPipe(Pipe *pipe);
|
||||
|
||||
// Port operations for root hub
|
||||
uint8 PortCount() const { return fPortCount; }
|
||||
status_t GetPortStatus(uint8 index,
|
||||
@ -92,12 +128,22 @@ private:
|
||||
static int32 FinishThread(void *data);
|
||||
void FinishTransfers();
|
||||
|
||||
// Descriptor
|
||||
xhci_td * CreateDescriptor(size_t bufferSize);
|
||||
void FreeDescriptor(xhci_td *descriptor);
|
||||
|
||||
status_t _LinkDescriptorForPipe(xhci_td *descriptor,
|
||||
xhci_endpoint *endpoint);
|
||||
status_t _UnlinkDescriptorForPipe(xhci_td *descriptor,
|
||||
xhci_endpoint *endpoint);
|
||||
|
||||
// Command
|
||||
void QueueCommand(xhci_trb *trb);
|
||||
void HandleCmdComplete(xhci_trb *trb);
|
||||
void HandleTransferComplete(xhci_trb *trb);
|
||||
status_t DoCommand(xhci_trb *trb);
|
||||
//Doorbell
|
||||
void Ring();
|
||||
void Ring(uint8 slot, uint8 endpoint);
|
||||
|
||||
// Commands
|
||||
status_t Noop();
|
||||
|
@ -42,8 +42,9 @@
|
||||
// USB Status Register
|
||||
#define STS_HCH (1 << 0)
|
||||
#define STS_HSE (1 << 2)
|
||||
#define STS_EINT (1 << 3)
|
||||
#define STS_PCD (1 << 4)
|
||||
#define STS_CNR (1<<11)
|
||||
#define STS_CNR (1 << 11)
|
||||
#define STS_HCE (1 << 12)
|
||||
#define XHCI_PAGESIZE 0x08 // PAGE SIZE
|
||||
#define XHCI_DNCTRL 0x14
|
||||
@ -81,6 +82,11 @@
|
||||
|
||||
// Host Controller Doorbell Registers
|
||||
#define XHCI_DOORBELL(n) (0x0000 + (4 * (n)))
|
||||
#define XHCI_DOORBELL_TARGET(x) ((x) & 0xff)
|
||||
#define XHCI_DOORBELL_TARGET_GET(x) ((x) & 0xff)
|
||||
#define XHCI_DOORBELL_STREAMID(x) (((x) & 0xffff) << 16)
|
||||
#define XHCI_DOORBELL_STREAMID_GET(x) (((x) >> 16) & 0xffff)
|
||||
|
||||
|
||||
// Extended Capabilities
|
||||
#define XECP_ID(x) ((x) & 0xff)
|
||||
@ -400,4 +406,8 @@ struct xhci_device_ctx {
|
||||
};
|
||||
|
||||
|
||||
#define XHCI_ENDPOINT_ID(pipe) (2 * pipe->EndpointAddress() \
|
||||
+ (pipe->Direction() != Pipe::Out ? 1 : 0))
|
||||
|
||||
|
||||
#endif // !XHCI_HARDWARE_H
|
||||
|
@ -23,7 +23,7 @@ static usb_device_descriptor sXHCIRootHubDevice =
|
||||
9, // Max packet size on endpoint 0
|
||||
0, // Vendor ID
|
||||
0, // Product ID
|
||||
0x003, // Version
|
||||
0x300, // Version
|
||||
1, // Index of manufacturer string
|
||||
2, // Index of product string
|
||||
0, // Index of serial number string
|
||||
|
Loading…
Reference in New Issue
Block a user