* Completely rework how transfer finishing is implemented. It is now using

pretty much the same strategy as UHCI. This does not leverage the done queue
  the hardware provides us, but as it saves a lot of other overhead and allows
  the structures to be smaller I think it is overall worth it.
* Removed now unnecessary stuff from the transfer descriptor struct.
* Directly acknowledge the done head interrupt as we do not use it either.
* Activate control endpoints by removing the skip bit when a transfer is scheduled.
* Correct the way the first descriptor is determined (the current tail becomes
  the first descriptor while the current first descriptor becomes the tail).
* Remove the head_logical_descriptor field from the endpoint structure, as this
  would simply get out of sync with the first td with no real way of updating.
* Stub out RemoveTransferFromEndpoint() as this needs reworking.
* Correct CreateDescriptorChain() signature and implement the method.
* Add ReadDescriptorChain() and ReadActualLength() to process finished transfers.
* Prepare for actual data transfers by renaming/regrouping transfer types.
* Fully clear out the new tail when switching (for the sake of it)
* Add some helpers and definitions to the hardware header.
* Add debugging facilities.

With all this transfers can now actually be scheduled and they are processed
when done. This brings control transfers to a usable state so setting the
device address and reading out/setting the configuration works. That means you
can now view your device using usb_dev_info, but since any other transfer type
besides control transfers isn't implemented yet the device will most probably
not yet do anything useful.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25546 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2008-05-18 19:34:25 +00:00
parent 3aecf8aa00
commit 408a8ff36a
3 changed files with 388 additions and 199 deletions

View File

@ -383,19 +383,19 @@ OHCI::SubmitTransfer(Transfer *transfer)
return fRootHub->ProcessTransfer(this, transfer);
uint32 type = transfer->TransferPipe()->Type();
if ((type & USB_OBJECT_CONTROL_PIPE)) {
TRACE(("usb_ohci: submitting control request\n"));
return _SubmitControlTransfer(transfer);
if (type & USB_OBJECT_CONTROL_PIPE) {
TRACE(("usb_ohci: submitting request\n"));
return _SubmitRequest(transfer);
}
if ((type & USB_OBJECT_BULK_PIPE)) {
TRACE(("usb_ohci: submitting bulk transfer\n"));
return _SubmitBulkTransfer(transfer);
if ((type & USB_OBJECT_BULK_PIPE) || (type & USB_OBJECT_INTERRUPT_PIPE)) {
TRACE(("usb_ohci: submitting bulk/interrupt transfer\n"));
return _SubmitTransfer(transfer);
}
if (((type & USB_OBJECT_ISO_PIPE) || (type & USB_OBJECT_INTERRUPT_PIPE))) {
TRACE(("usb_ohci: submitting periodic transfer\n"));
return _SubmitPeriodicTransfer(transfer);
if (type & USB_OBJECT_ISO_PIPE) {
TRACE(("usb_ohci: submitting isochronous transfer\n"));
return _SubmitIsochronousTransfer(transfer);
}
TRACE_ERROR(("usb_ohci: tried to submit transfer for unknown pipe"
@ -425,8 +425,6 @@ OHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
}
// Clear the endpoint
current->endpoint->head_logical_descriptor
= current->endpoint->tail_logical_descriptor;
current->endpoint->head_physical_descriptor
= current->endpoint->tail_physical_descriptor;
@ -729,7 +727,8 @@ OHCI::_Interrupt()
if (status & OHCI_WRITEBACK_DONE_HEAD) {
TRACE(("usb_ohci: transfer descriptors processed\n"));
// Acknowledge it in the finisher thread, not here.
fHcca->done_head = 0;
acknowledge |= OHCI_WRITEBACK_DONE_HEAD;
result = B_INVOKE_SCHEDULER;
finishTransfers = true;
}
@ -764,10 +763,10 @@ OHCI::_Interrupt()
status_t
OHCI::_AddPendingTransfer(Transfer *transfer,
ohci_endpoint_descriptor *endpoint, ohci_general_td *firstDescriptor,
ohci_general_td *dataDescriptor, bool directionIn)
ohci_endpoint_descriptor *endpoint, ohci_general_td *dataDescriptor,
ohci_general_td *lastDescriptor, bool directionIn)
{
if (!transfer || !endpoint || !firstDescriptor)
if (!transfer || !endpoint || !lastDescriptor)
return B_BAD_VALUE;
transfer_data *data = new(std::nothrow) transfer_data;
@ -782,8 +781,10 @@ OHCI::_AddPendingTransfer(Transfer *transfer,
data->transfer = transfer;
data->endpoint = endpoint;
data->first_descriptor = firstDescriptor;
// the current tail will become the fist descriptor
data->first_descriptor = (ohci_general_td *)endpoint->tail_logical_descriptor;
data->data_descriptor = dataDescriptor;
data->last_descriptor = lastDescriptor;
data->incoming = directionIn;
data->canceled = false;
data->link = NULL;
@ -813,40 +814,6 @@ OHCI::_CancelQueuedIsochronousTransfers(Pipe *pipe, bool force)
}
status_t
OHCI::_UnlinkTransfer(transfer_data *transfer)
{
if (!Lock())
return B_ERROR;
if (transfer == fFirstTransfer) {
// It was the first element
fFirstTransfer = fFirstTransfer->link;
if (transfer == fLastTransfer) {
// Also the only one
fLastTransfer = NULL;
}
} else {
transfer_data *current = fFirstTransfer->link;
transfer_data *previous = fFirstTransfer;
while (current != NULL) {
if (current == transfer) {
previous->link = current->link;
if (current == fLastTransfer)
fLastTransfer = previous;
break;
}
previous = current;
current = current->link;
}
}
Unlock();
return B_OK;
}
int32
OHCI::_FinishThread(void *data)
{
@ -868,134 +835,188 @@ OHCI::_FinishTransfers()
if (semCount > 0)
acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0);
uint32 doneList = fHcca->done_head & ~OHCI_DONE_INTERRUPTS;
// If done_head is zero, there are no processed descriptors
// in the done list and we have been woken up by CancelQueuedTransfers
// or CancelQueuedIsochronousTransfers in order to do some clean up.
if (doneList) {
// Pull out the done list and reverse its order
// for both general and isochronous descriptors
ohci_general_td *current = NULL;
ohci_general_td *top = NULL;
ohci_isochronous_td *isoCurrent = NULL;
ohci_isochronous_td *isoTop = NULL;
while (doneList != 0) {
current = NULL; //_FindDescriptorInHash(doneList);
if (current != NULL) {
doneList = current->next_physical_descriptor;
current->next_done_descriptor = (void *)top;
top = current;
continue;
if (!Lock())
continue;
TRACE(("usb_ohci: finishing transfers (first transfer: %p; last"
" transfer: %p)\n", fFirstTransfer, fLastTransfer));
transfer_data *lastTransfer = NULL;
transfer_data *transfer = fFirstTransfer;
Unlock();
while (transfer) {
bool transferDone = false;
ohci_general_td *descriptor = transfer->first_descriptor;
status_t callbackStatus = B_OK;
while (descriptor) {
uint32 status = OHCI_TD_GET_CONDITION_CODE(descriptor->flags);
if (status == OHCI_TD_CONDITION_NOT_ACCESSED) {
// td is still active
TRACE(("usb_ohci: td %p still active\n", descriptor));
break;
}
isoCurrent = NULL; //_FindIsoDescriptorInHash(doneList);
if (isoCurrent != NULL) {
doneList = isoCurrent->next_physical_descriptor;
isoCurrent->next_done_descriptor = (void *)isoTop;
isoTop = isoCurrent;
continue;
}
if (status != OHCI_TD_CONDITION_NO_ERROR) {
// an error occured, but we must ensure that the td
// was actually done
ohci_endpoint_descriptor *endpoint = transfer->endpoint;
if (endpoint->head_physical_descriptor & OHCI_ENDPOINT_HALTED) {
// the endpoint is halted, this guaratees us that this
// descriptor has passed (we don't know if the endpoint
// was halted because of this td, but we do not need
// to know, as when it was halted by another td this
// still ensures that this td was handled before).
TRACE_ERROR(("usb_ohci: td error: 0x%08lx\n", status));
TRACE_ERROR(("usb_ohci: address 0x%08lx not found!\n", doneList));
break;
}
switch (status) {
case OHCI_TD_CONDITION_CRC_ERROR:
case OHCI_TD_CONDITION_BIT_STUFFING:
case OHCI_TD_CONDITION_TOGGLE_MISMATCH:
callbackStatus = B_DEV_CRC_ERROR;
break;
// Acknowledge the interrupt
// TODO: Move the acknowledgement in the interrupt handler.
// The done_head value can be passed through a shared variable.
fHcca->done_head = 0;
_WriteReg(OHCI_INTERRUPT_STATUS, OHCI_WRITEBACK_DONE_HEAD);
case OHCI_TD_CONDITION_STALL:
callbackStatus = B_DEV_STALLED;
break;
// Process isochronous list first
for (isoCurrent = isoTop; isoCurrent != NULL; isoCurrent
= (ohci_isochronous_td *)isoCurrent->next_done_descriptor) {
// TODO: Process isochronous descriptors
}
case OHCI_TD_CONDITION_NO_RESPONSE:
callbackStatus = B_TIMED_OUT;
break;
// Now process the general list
for (current = top; current != NULL;) {
ohci_general_td *next
= (ohci_general_td *)current->next_done_descriptor;
case OHCI_TD_CONDITION_PID_CHECK_FAILURE:
callbackStatus = B_DEV_BAD_PID;
break;
transfer_data *transfer = (transfer_data *)current->transfer;
if (transfer->canceled) {
// Clear canceled transfer later on
current = next;
continue;
}
case OHCI_TD_CONDITION_UNEXPECTED_PID:
callbackStatus = B_DEV_UNEXPECTED_PID;
break;
bool transferDone = false;
status_t callbackStatus = B_OK;
uint32 conditionCode = OHCI_TD_GET_CONDITION_CODE(current->flags);
if (conditionCode != OHCI_NO_ERROR) {
// Endpoint is halted: unlink all descriptors belonging to
// the failed transfer from the endpoint and restart the
// endpoint.
// NOTE: There can(should) not be more than one
// invalid descriptor from the same transfer in the
// done list, as the controller halts the endpoint right
// away if a descriptor fails. This means that, if we reversed
// the order of the done list (which we did), there is
// no reason to look for more failed descriptors in the
// done list from the same transfer, as *BSD code does.
TRACE_ERROR(("usb_ohci: transfer failed! ohci error code: %lu\n",
conditionCode));
case OHCI_TD_CONDITION_DATA_OVERRUN:
callbackStatus = B_DEV_DATA_OVERRUN;
break;
// Remove remaining descriptors from the same transfer
if (!current->is_last)
_RemoveTransferFromEndpoint(transfer);
case OHCI_TD_CONDITION_DATA_UNDERRUN:
callbackStatus = B_DEV_DATA_UNDERRUN;
break;
// TODO: Fix the following with the appropriate error
callbackStatus = B_DEV_MULTIPLE_ERRORS;
transferDone = true;
} else if (current->is_last)
transferDone = true;
case OHCI_TD_CONDITION_BUFFER_OVERRUN:
callbackStatus = B_DEV_FIFO_OVERRUN;
break;
if (transferDone) {
size_t actualLength = 0;
if (callbackStatus == B_OK) {
if (transfer->data_descriptor && transfer->incoming) {
// Read data out
} else {
// How much was transfered?
case OHCI_TD_CONDITION_BUFFER_UNDERRUN:
callbackStatus = B_DEV_FIFO_UNDERRUN;
break;
default:
callbackStatus = B_ERROR;
break;
}
if (transfer->transfer->IsFragmented()) {
// TODO
}
transferDone = true;
break;
} else {
// an error occured but the endpoint is not halted so
// the td is in fact still active
TRACE(("usb_ohci: td %p active with error\n", descriptor));
break;
}
}
// the td has complete without an error
TRACE(("usb_ohci: td %p done\n", descriptor));
if (descriptor == transfer->last_descriptor
|| descriptor->buffer_physical != 0) {
// this is the last td of the transfer or a short packet
callbackStatus = B_OK;
transferDone = true;
break;
}
descriptor
= (ohci_general_td *)descriptor->next_logical_descriptor;
}
if (!transferDone) {
lastTransfer = transfer;
transfer = transfer->link;
continue;
}
// remove the transfer from the list first so we are sure
// it doesn't get canceled while we still process it
transfer_data *next = transfer->link;
if (Lock()) {
if (lastTransfer)
lastTransfer->link = transfer->link;
if (transfer == fFirstTransfer)
fFirstTransfer = transfer->link;
if (transfer == fLastTransfer)
fLastTransfer = lastTransfer;
transfer->link = NULL;
Unlock();
}
// break the descriptor chain on the last descriptor
transfer->last_descriptor->next_logical_descriptor = NULL;
TRACE(("usb_ohci: transfer %p done\n", transfer));
// if canceled the callback has already been called
if (!transfer->canceled) {
size_t actualLength = 0;
if (callbackStatus == B_OK) {
if (transfer->data_descriptor && transfer->incoming) {
// data to read out
iovec *vector = transfer->transfer->Vector();
size_t vectorCount = transfer->transfer->VectorCount();
transfer->transfer->PrepareKernelAccess();
actualLength = _ReadDescriptorChain(
transfer->data_descriptor,
vector, vectorCount);
} else {
// read the actual length that was sent
actualLength = _ReadActualLength(
transfer->first_descriptor);
}
_UnlinkTransfer(transfer);
transfer->transfer->Finished(callbackStatus, actualLength);
next = (ohci_general_td *)current->next_done_descriptor;
_FreeDescriptorChain(transfer->first_descriptor);
if (transfer->transfer->IsFragmented()) {
// this transfer may still have data left
TRACE(("usb_ohci: advancing fragmented transfer\n"));
transfer->transfer->AdvanceByFragment(actualLength);
if (transfer->transfer->VectorLength() > 0) {
TRACE(("usb_ohci: still %ld bytes left on transfer\n",
transfer->transfer->VectorLength()));
// TODO actually resubmit the transfer
}
delete transfer->transfer;
delete transfer;
// the transfer is done, but we already set the
// actualLength with AdvanceByFragment()
actualLength = 0;
}
}
current = next;
transfer->transfer->Finished(callbackStatus, actualLength);
}
}
// Quickly look for canceled transfer before we go back to sleep
transfer_data *current = fFirstTransfer;
while (current) {
transfer_data *next = current->link;
if (current->canceled) {
_UnlinkTransfer(current);
_FreeDescriptorChain(current->first_descriptor);
delete current->transfer;
delete current;
}
current = next;
// free the descriptors
_FreeDescriptorChain(transfer->first_descriptor);
// TODO: in case of cancel/error adjust the endpoint head and
// restart the endpoint by clearing the halt
delete transfer->transfer;
delete transfer;
transfer = next;
}
}
}
status_t
OHCI::_SubmitControlTransfer(Transfer *transfer)
OHCI::_SubmitRequest(Transfer *transfer)
{
usb_request_data *requestData = transfer->RequestData();
bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0;
@ -1008,9 +1029,9 @@ OHCI::_SubmitControlTransfer(Transfer *transfer)
}
setupDescriptor->flags = OHCI_TD_DIRECTION_PID_SETUP
| OHCI_TD_NO_CONDITION_CODE
| OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED)
| OHCI_TD_TOGGLE_0
| OHCI_TD_SET_DELAY_INTERRUPT(7);
| OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE);
ohci_general_td *statusDescriptor = _CreateGeneralDescriptor(0);
if (!statusDescriptor) {
@ -1021,9 +1042,9 @@ OHCI::_SubmitControlTransfer(Transfer *transfer)
statusDescriptor->flags
= (directionIn ? OHCI_TD_DIRECTION_PID_OUT : OHCI_TD_DIRECTION_PID_IN)
| OHCI_TD_NO_CONDITION_CODE
| OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED)
| OHCI_TD_TOGGLE_1
| OHCI_TD_SET_DELAY_INTERRUPT(0);
| OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE);
iovec vector;
vector.iov_base = requestData;
@ -1057,8 +1078,8 @@ OHCI::_SubmitControlTransfer(Transfer *transfer)
// Append Transfer
ohci_endpoint_descriptor *endpoint
= (ohci_endpoint_descriptor *)transfer->TransferPipe()->ControllerCookie();
result = _AddPendingTransfer(transfer, endpoint, setupDescriptor,
dataDescriptor, directionIn);
result = _AddPendingTransfer(transfer, endpoint, dataDescriptor,
statusDescriptor, directionIn);
if (result < B_OK) {
TRACE_ERROR(("usb_ohci: failed to add pending transfer\n"));
_FreeDescriptorChain(setupDescriptor);
@ -1069,13 +1090,14 @@ OHCI::_SubmitControlTransfer(Transfer *transfer)
_SwitchEndpointTail(endpoint, setupDescriptor, statusDescriptor);
// Tell the controller to process the control list
endpoint->flags &= ~OHCI_ENDPOINT_SKIP;
_WriteReg(OHCI_COMMAND_STATUS, OHCI_CONTROL_LIST_FILLED);
return B_OK;
}
status_t
OHCI::_SubmitBulkTransfer(Transfer *transfer)
OHCI::_SubmitTransfer(Transfer *transfer)
{
// TODO
return B_ERROR;
@ -1083,7 +1105,7 @@ OHCI::_SubmitBulkTransfer(Transfer *transfer)
status_t
OHCI::_SubmitPeriodicTransfer(Transfer *transfer)
OHCI::_SubmitIsochronousTransfer(Transfer *transfer)
{
return B_ERROR;
}
@ -1104,32 +1126,29 @@ OHCI::_SwitchEndpointTail(ohci_endpoint_descriptor *endpoint,
tail->next_logical_descriptor = first->next_logical_descriptor;
// the first descriptor becomes the new tail
tail = first;
tail->buffer_size = 0;
tail->buffer_logical = NULL;
tail->next_logical_descriptor = NULL;
_LinkDescriptors(last, tail);
first->flags = 0;
first->buffer_physical = 0;
first->next_physical_descriptor = 0;
first->last_physical_byte_address = 0;
first->buffer_size = 0;
first->buffer_logical = NULL;
first->next_logical_descriptor = NULL;
_LinkDescriptors(last, first);
// update the endpoint tail pointer to reflect the change
endpoint->tail_logical_descriptor = tail;
endpoint->tail_physical_descriptor = (uint32)tail->physical_address;
endpoint->tail_logical_descriptor = first;
endpoint->tail_physical_descriptor = (uint32)first->physical_address;
#if 0
_PrintEndpoint(endpoint);
_PrintDescriptorChain(tail);
#endif
}
void
OHCI::_RemoveTransferFromEndpoint(transfer_data *transfer)
{
// TODO: Add lock for endpoint
ohci_endpoint_descriptor *endpoint = transfer->endpoint;
ohci_general_td *next = (ohci_general_td *)endpoint->head_logical_descriptor;
// Find the first descriptor of a different transfer.
// Worst scenario we get the dummy descriptor
while ((transfer_data *)next->transfer == transfer)
next = (ohci_general_td *)next->next_logical_descriptor;
// Update head
endpoint->head_logical_descriptor = next;
endpoint->head_physical_descriptor = next->physical_address;
}
@ -1148,7 +1167,6 @@ OHCI::_AllocateEndpoint()
endpoint->flags = OHCI_ENDPOINT_SKIP;
endpoint->physical_address = (addr_t)physicalAddress;
endpoint->head_logical_descriptor = NULL;
endpoint->head_physical_descriptor = 0;
endpoint->tail_logical_descriptor = NULL;
endpoint->tail_physical_descriptor = 0;
@ -1256,16 +1274,15 @@ OHCI::_InsertEndpointForPipe(Pipe *pipe)
return B_ERROR;
} else {
ohci_general_td *tail = _CreateGeneralDescriptor(0);
endpoint->head_logical_descriptor = tail;
endpoint->tail_logical_descriptor = tail;
endpoint->head_physical_descriptor = tail->physical_address;
endpoint->tail_physical_descriptor = tail->physical_address;
}
if (!_LockEndpoints()) {
if (endpoint->head_logical_descriptor) {
if (endpoint->tail_logical_descriptor) {
_FreeGeneralDescriptor(
(ohci_general_td *)endpoint->head_logical_descriptor);
(ohci_general_td *)endpoint->tail_logical_descriptor);
}
_FreeEndpoint(endpoint);
@ -1352,9 +1369,42 @@ OHCI::_FreeGeneralDescriptor(ohci_general_td *descriptor)
status_t
OHCI::_CreateDescriptorChain(ohci_general_td **_firstDescriptor,
ohci_general_td **_lastDescriptor, uint8 direction, size_t bufferSize)
ohci_general_td **_lastDescriptor, uint32 direction, size_t bufferSize)
{
return B_ERROR;
size_t blockSize = 8192;
int32 descriptorCount = (bufferSize + blockSize - 1) / blockSize;
if (descriptorCount == 0)
descriptorCount = 1;
ohci_general_td *firstDescriptor = NULL;
ohci_general_td *lastDescriptor = *_firstDescriptor;
for (int32 i = 0; i < descriptorCount; i++) {
ohci_general_td *descriptor = _CreateGeneralDescriptor(
min_c(blockSize, bufferSize));
if (!descriptor) {
_FreeDescriptorChain(firstDescriptor);
return B_NO_MEMORY;
}
descriptor->flags = direction
| OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED)
| OHCI_TD_TOGGLE_CARRY
| OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE);
// link to previous
if (lastDescriptor)
_LinkDescriptors(lastDescriptor, descriptor);
bufferSize -= blockSize;
lastDescriptor = descriptor;
if (!firstDescriptor)
firstDescriptor = descriptor;
}
*_firstDescriptor = firstDescriptor;
*_lastDescriptor = lastDescriptor;
return B_OK;
}
@ -1427,6 +1477,87 @@ OHCI::_WriteDescriptorChain(ohci_general_td *topDescriptor, iovec *vector,
}
size_t
OHCI::_ReadDescriptorChain(ohci_general_td *topDescriptor, iovec *vector,
size_t vectorCount)
{
ohci_general_td *current = topDescriptor;
size_t actualLength = 0;
size_t vectorIndex = 0;
size_t vectorOffset = 0;
size_t bufferOffset = 0;
while (current && OHCI_TD_GET_CONDITION_CODE(current->flags)
!= OHCI_TD_CONDITION_NOT_ACCESSED) {
if (!current->buffer_logical)
break;
size_t bufferSize = current->buffer_size;
if (current->buffer_physical != 0) {
bufferSize = current->last_physical_byte_address
- current->buffer_physical + 1;
}
while (true) {
size_t length = min_c(bufferSize - bufferOffset,
vector[vectorIndex].iov_len - vectorOffset);
TRACE(("usb_ohci: copying %ld bytes to vectorOffset %ld from"
" bufferOffset %ld at index %ld of %ld\n", length, vectorOffset,
bufferOffset, vectorIndex, vectorCount));
memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
(uint8 *)current->buffer_logical + bufferOffset, length);
actualLength += length;
vectorOffset += length;
bufferOffset += length;
if (vectorOffset >= vector[vectorIndex].iov_len) {
if (++vectorIndex >= vectorCount) {
TRACE(("usb_ohci: read descriptor chain (%ld bytes, no more vectors)\n", actualLength));
return actualLength;
}
vectorOffset = 0;
}
if (bufferOffset >= bufferSize) {
bufferOffset = 0;
break;
}
}
current = (ohci_general_td *)current->next_logical_descriptor;
}
TRACE(("usb_ohci: read descriptor chain (%ld bytes)\n", actualLength));
return actualLength;
}
size_t
OHCI::_ReadActualLength(ohci_general_td *topDescriptor)
{
ohci_general_td *current = topDescriptor;
size_t actualLength = 0;
while (current && OHCI_TD_GET_CONDITION_CODE(current->flags)
!= OHCI_TD_CONDITION_NOT_ACCESSED) {
size_t length = current->buffer_size;
if (current->buffer_physical != 0) {
length = current->last_physical_byte_address
- current->buffer_physical + 1;
}
actualLength += length;
current = (ohci_general_td *)current->next_logical_descriptor;
}
TRACE(("usb_ohci: read actual length (%ld bytes)\n", actualLength));
return actualLength;
}
void
OHCI::_LinkDescriptors(ohci_general_td *first, ohci_general_td *second)
{
@ -1476,3 +1607,36 @@ OHCI::_ReadReg(uint32 reg)
{
return *(volatile uint32 *)(fOperationalRegisters + reg);
}
void
OHCI::_PrintEndpoint(ohci_endpoint_descriptor *endpoint)
{
dprintf("usb_ohci: endpoint %p\n", endpoint);
dprintf("\tflags........... 0x%08lx\n", endpoint->flags);
dprintf("\ttail_physical... 0x%08lx\n", endpoint->tail_physical_descriptor);
dprintf("\thead_physical... 0x%08lx\n", endpoint->head_physical_descriptor);
dprintf("\tnext_physical... 0x%08lx\n", endpoint->next_physical_endpoint);
dprintf("\tphysical........ 0x%08lx\n", endpoint->physical_address);
dprintf("\ttail_logical.... %p\n", endpoint->tail_logical_descriptor);
dprintf("\tnext_logical.... %p\n", endpoint->next_logical_endpoint);
}
void
OHCI::_PrintDescriptorChain(ohci_general_td *topDescriptor)
{
while (topDescriptor) {
dprintf("usb_ohci: descriptor %p\n", topDescriptor);
dprintf("\tflags........... 0x%08lx\n", topDescriptor->flags);
dprintf("\tbuffer_physical. 0x%08lx\n", topDescriptor->buffer_physical);
dprintf("\tnext_physical... 0x%08lx\n", topDescriptor->next_physical_descriptor);
dprintf("\tlast_byte....... 0x%08lx\n", topDescriptor->last_physical_byte_address);
dprintf("\tphysical........ 0x%08lx\n", topDescriptor->physical_address);
dprintf("\tbuffer_size..... %lu\n", topDescriptor->buffer_size);
dprintf("\tbuffer_logical.. %p\n", topDescriptor->buffer_logical);
dprintf("\tnext_logical.... %p\n", topDescriptor->next_logical_descriptor);
topDescriptor = (ohci_general_td *)topDescriptor->next_logical_descriptor;
}
}

View File

@ -24,6 +24,7 @@ typedef struct transfer_data_s {
ohci_endpoint_descriptor *endpoint;
ohci_general_td *first_descriptor;
ohci_general_td *data_descriptor;
ohci_general_td *last_descriptor;
bool incoming;
bool canceled;
transfer_data_s *link;
@ -63,8 +64,8 @@ static int32 _InterruptHandler(void *data);
// Transfer functions
status_t _AddPendingTransfer(Transfer *transfer,
ohci_endpoint_descriptor *endpoint,
ohci_general_td *first,
ohci_general_td *data,
ohci_general_td *dataDescriptor,
ohci_general_td *lastDescriptor,
bool directionIn);
status_t _CancelQueuedIsochronousTransfers(
Pipe *pipe, bool force);
@ -73,9 +74,10 @@ static int32 _InterruptHandler(void *data);
static int32 _FinishThread(void *data);
void _FinishTransfers();
status_t _SubmitControlTransfer(Transfer *transfer);
status_t _SubmitBulkTransfer(Transfer *transfer);
status_t _SubmitPeriodicTransfer(Transfer *transfer);
status_t _SubmitRequest(Transfer *transfer);
status_t _SubmitTransfer(Transfer *transfer);
status_t _SubmitIsochronousTransfer(
Transfer *transfer);
void _SwitchEndpointTail(
ohci_endpoint_descriptor *endpoint,
@ -101,15 +103,19 @@ static int32 _FinishThread(void *data);
status_t _CreateDescriptorChain(
ohci_general_td **firstDescriptor,
ohci_general_td **lastDescriptor,
uint8 direction,
uint32 direction,
size_t bufferSize);
void _FreeDescriptorChain(
ohci_general_td *topDescriptor);
size_t _WriteDescriptorChain(
ohci_general_td *topDescriptor,
iovec *vector,
size_t vectorCount);
iovec *vector, size_t vectorCount);
size_t _ReadDescriptorChain(
ohci_general_td *topDescriptor,
iovec *vector, size_t vectorCount);
size_t _ReadActualLength(
ohci_general_td *topDescriptor);
void _LinkDescriptors(ohci_general_td *first,
ohci_general_td *second);
@ -126,6 +132,12 @@ static int32 _FinishThread(void *data);
inline void _WriteReg(uint32 reg, uint32 value);
inline uint32 _ReadReg(uint32 reg);
// Debug functions
void _PrintEndpoint(
ohci_endpoint_descriptor *endpoint);
void _PrintDescriptorChain(
ohci_general_td *topDescriptor);
static pci_module_info *sPCIModule;
pci_info *fPCIInfo;
Stack *fStack;

View File

@ -207,7 +207,7 @@
// Root Hub port status (n) register (section 7.4.4)
// --------------------------------
#define OHCI_RH_PORT_STATUS(n) (0x50 + (n) * 4)// 1 based indexing
#define OHCI_RH_PORT_STATUS(n) (0x54 + (n) * 4)// 0 based indexing
#define OHCI_RH_PORTSTATUS_CCS 0x00000001 // Current Connection Status
#define OHCI_RH_PORTSTATUS_PES 0x00000002 // Port Enable Status
#define OHCI_RH_PORTSTATUS_PSS 0x00000004 // Port Suspend Status
@ -301,7 +301,6 @@ typedef struct {
// Software part
addr_t physical_address; // Physical pointer to this address
void *tail_logical_descriptor; // Queue tail logical pointer
void *head_logical_descriptor; // Queue head logical pointer
void *next_logical_endpoint; // Logical pointer to the next endpoint
} ohci_endpoint_descriptor;
@ -342,9 +341,6 @@ typedef struct {
size_t buffer_size; // Size of the buffer
void *buffer_logical; // Logical pointer to the buffer
void *next_logical_descriptor; // Logical pointer next descriptor
void *next_done_descriptor; // Used for the done descriptor list
void *transfer; // Pointer to the transfer_data
bool is_last; // Last descriptor of the transfer
} ohci_general_td;
#define OHCI_BUFFER_ROUNDING 0x00040000
@ -354,7 +350,6 @@ typedef struct {
#define OHCI_TD_DIRECTION_PID_IN 0x00100000
#define OHCI_TD_GET_DELAY_INTERRUPT(x) (((x) >> 21) & 7)
#define OHCI_TD_SET_DELAY_INTERRUPT(x) ((x) << 21)
#define OHCI_TD_NO_INTERRUPT 0x00e00000
#define OHCI_TD_INTERRUPT_MASK 0x00e00000
#define OHCI_TD_TOGGLE_CARRY 0x00000000
#define OHCI_TD_TOGGLE_0 0x02000000
@ -362,7 +357,25 @@ typedef struct {
#define OHCI_TD_TOGGLE_MASK 0x03000000
#define OHCI_TD_GET_ERROR_COUNT(x) (((x) >> 26) & 3)
#define OHCI_TD_GET_CONDITION_CODE(x) ((x) >> 28)
#define OHCI_TD_NO_CONDITION_CODE 0xf0000000
#define OHCI_TD_SET_CONDITION_CODE(x) ((x) << 28)
#define OHCI_TD_CONDITION_CODE_MASK 0xf0000000
#define OHCI_TD_INTERRUPT_IMMEDIATE 0x00
#define OHCI_TD_INTERRUPT_NONE 0x07
#define OHCI_TD_CONDITION_NO_ERROR 0x00
#define OHCI_TD_CONDITION_CRC_ERROR 0x01
#define OHCI_TD_CONDITION_BIT_STUFFING 0x02
#define OHCI_TD_CONDITION_TOGGLE_MISMATCH 0x03
#define OHCI_TD_CONDITION_STALL 0x04
#define OHCI_TD_CONDITION_NO_RESPONSE 0x05
#define OHCI_TD_CONDITION_PID_CHECK_FAILURE 0x06
#define OHCI_TD_CONDITION_UNEXPECTED_PID 0x07
#define OHCI_TD_CONDITION_DATA_OVERRUN 0x08
#define OHCI_TD_CONDITION_DATA_UNDERRUN 0x09
#define OHCI_TD_CONDITION_BUFFER_OVERRUN 0x0c
#define OHCI_TD_CONDITION_BUFFER_UNDERRUN 0x0d
#define OHCI_TD_CONDITION_NOT_ACCESSED 0x0f
#define OHCI_GENERAL_TD_ALIGN 16