* Handle the data == first and last == first case as this can occure for

single td bulk transfers.
* Implement SubmitTransfer() for bulk transfers (interrupts will use the exact
  same code path, but as their endpoints aren't yet setup, interrupt transfers
  won't work).
* Handle the cancel case when finishing transfers. The descriptors of the
  canceled transfers cannot be accessed by the controller so they can be freed.

Bulk transfers should work now, so devices only using control and bulk transfers
should too (anything using usb_disk for example). Note though that a transfer
error will cause the whole thing to fail miserably as the error case is not
yet handled correctly (failed descriptors aren't removed from the endpoint).
Therefore I suggest not testing with the memory stick with that important
presentation you haven't stored anywhere else...

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25549 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2008-05-18 21:15:07 +00:00
parent 1eace5fc53
commit 016ce5dd54
2 changed files with 82 additions and 15 deletions

View File

@ -763,8 +763,9 @@ OHCI::_Interrupt()
status_t status_t
OHCI::_AddPendingTransfer(Transfer *transfer, OHCI::_AddPendingTransfer(Transfer *transfer,
ohci_endpoint_descriptor *endpoint, ohci_general_td *dataDescriptor, ohci_endpoint_descriptor *endpoint, ohci_general_td *firstDescriptor,
ohci_general_td *lastDescriptor, bool directionIn) ohci_general_td *dataDescriptor, ohci_general_td *lastDescriptor,
bool directionIn)
{ {
if (!transfer || !endpoint || !lastDescriptor) if (!transfer || !endpoint || !lastDescriptor)
return B_BAD_VALUE; return B_BAD_VALUE;
@ -781,14 +782,25 @@ OHCI::_AddPendingTransfer(Transfer *transfer,
data->transfer = transfer; data->transfer = transfer;
data->endpoint = endpoint; data->endpoint = endpoint;
// 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->incoming = directionIn;
data->canceled = false; data->canceled = false;
data->link = NULL; data->link = NULL;
// the current tail will become the fist descriptor
data->first_descriptor = (ohci_general_td *)endpoint->tail_logical_descriptor;
// the data and first descriptors might be the same
if (dataDescriptor == firstDescriptor)
data->data_descriptor = data->first_descriptor;
else
data->data_descriptor = dataDescriptor;
// even the last and the first descriptor might be the same
if (lastDescriptor == firstDescriptor)
data->last_descriptor = data->first_descriptor;
else
data->last_descriptor = lastDescriptor;
if (!Lock()) { if (!Lock()) {
delete data; delete data;
return B_ERROR; return B_ERROR;
@ -849,7 +861,7 @@ OHCI::_FinishTransfers()
ohci_general_td *descriptor = transfer->first_descriptor; ohci_general_td *descriptor = transfer->first_descriptor;
status_t callbackStatus = B_OK; status_t callbackStatus = B_OK;
while (descriptor) { while (descriptor && !transfer->canceled) {
uint32 status = OHCI_TD_GET_CONDITION_CODE(descriptor->flags); uint32 status = OHCI_TD_GET_CONDITION_CODE(descriptor->flags);
if (status == OHCI_TD_CONDITION_NOT_ACCESSED) { if (status == OHCI_TD_CONDITION_NOT_ACCESSED) {
// td is still active // td is still active
@ -938,6 +950,15 @@ OHCI::_FinishTransfers()
= (ohci_general_td *)descriptor->next_logical_descriptor; = (ohci_general_td *)descriptor->next_logical_descriptor;
} }
if (transfer->canceled) {
// when a transfer is canceled, all transfers to that endpoint
// are canceled by setting the head pointer to the tail pointer
// which causes all of the tds to become "free" (as they are
// inaccessible and not accessed anymore (as setting the head
// pointer required disabling the endpoint))
transferDone = true;
}
if (!transferDone) { if (!transferDone) {
lastTransfer = transfer; lastTransfer = transfer;
transfer = transfer->link; transfer = transfer->link;
@ -1075,18 +1096,18 @@ OHCI::_SubmitRequest(Transfer *transfer)
_LinkDescriptors(setupDescriptor, statusDescriptor); _LinkDescriptors(setupDescriptor, statusDescriptor);
} }
// Append Transfer // Add to the transfer list
ohci_endpoint_descriptor *endpoint ohci_endpoint_descriptor *endpoint
= (ohci_endpoint_descriptor *)transfer->TransferPipe()->ControllerCookie(); = (ohci_endpoint_descriptor *)transfer->TransferPipe()->ControllerCookie();
result = _AddPendingTransfer(transfer, endpoint, dataDescriptor, result = _AddPendingTransfer(transfer, endpoint, setupDescriptor,
statusDescriptor, directionIn); dataDescriptor, statusDescriptor, directionIn);
if (result < B_OK) { if (result < B_OK) {
TRACE_ERROR(("usb_ohci: failed to add pending transfer\n")); TRACE_ERROR(("usb_ohci: failed to add pending transfer\n"));
_FreeDescriptorChain(setupDescriptor); _FreeDescriptorChain(setupDescriptor);
return result; return result;
} }
// Append descriptor chain to the endpoint // Add the descriptor chain to the endpoint
_SwitchEndpointTail(endpoint, setupDescriptor, statusDescriptor); _SwitchEndpointTail(endpoint, setupDescriptor, statusDescriptor);
// Tell the controller to process the control list // Tell the controller to process the control list
@ -1099,8 +1120,49 @@ OHCI::_SubmitRequest(Transfer *transfer)
status_t status_t
OHCI::_SubmitTransfer(Transfer *transfer) OHCI::_SubmitTransfer(Transfer *transfer)
{ {
// TODO Pipe *pipe = transfer->TransferPipe();
return B_ERROR; bool directionIn = (pipe->Direction() == Pipe::In);
ohci_general_td *firstDescriptor = NULL;
ohci_general_td *lastDescriptor = NULL;
status_t result = _CreateDescriptorChain(&firstDescriptor, &lastDescriptor,
directionIn ? OHCI_TD_DIRECTION_PID_IN : OHCI_TD_DIRECTION_PID_OUT,
transfer->VectorLength());
if (result < B_OK)
return result;
// Set the last descriptor to generate an interrupt
lastDescriptor->flags &= ~OHCI_TD_INTERRUPT_MASK;
lastDescriptor->flags |=
OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE);
if (!directionIn) {
_WriteDescriptorChain(firstDescriptor, transfer->Vector(),
transfer->VectorCount());
}
// Add to the transfer list
ohci_endpoint_descriptor *endpoint
= (ohci_endpoint_descriptor *)pipe->ControllerCookie();
result = _AddPendingTransfer(transfer, endpoint, firstDescriptor,
firstDescriptor, lastDescriptor, directionIn);
if (result < B_OK) {
TRACE_ERROR(("usb_ohci: failed to add pending transfer\n"));
_FreeDescriptorChain(firstDescriptor);
return result;
}
// Add the descriptor chain to the endpoint
_SwitchEndpointTail(endpoint, firstDescriptor, lastDescriptor);
endpoint->flags &= ~OHCI_ENDPOINT_SKIP;
if (pipe->Type() & USB_OBJECT_BULK_PIPE) {
// Tell the controller to process the bulk list
_WriteReg(OHCI_COMMAND_STATUS, OHCI_BULK_LIST_FILLED);
}
return B_OK;
} }
@ -1133,7 +1195,11 @@ OHCI::_SwitchEndpointTail(ohci_endpoint_descriptor *endpoint,
first->buffer_size = 0; first->buffer_size = 0;
first->buffer_logical = NULL; first->buffer_logical = NULL;
first->next_logical_descriptor = NULL; first->next_logical_descriptor = NULL;
_LinkDescriptors(last, first);
if (first == last)
_LinkDescriptors(tail, first);
else
_LinkDescriptors(last, first);
// update the endpoint tail pointer to reflect the change // update the endpoint tail pointer to reflect the change
endpoint->tail_logical_descriptor = first; endpoint->tail_logical_descriptor = first;
@ -1265,7 +1331,7 @@ OHCI::_InsertEndpointForPipe(Pipe *pipe)
return B_ERROR; return B_ERROR;
} }
// Create (necessary) dummy descriptor // Create (necessary) tail descriptor
if (pipe->Type() & USB_OBJECT_ISO_PIPE) { if (pipe->Type() & USB_OBJECT_ISO_PIPE) {
// Set the isochronous bit format // Set the isochronous bit format
endpoint->flags |= OHCI_ENDPOINT_ISOCHRONOUS_FORMAT; endpoint->flags |= OHCI_ENDPOINT_ISOCHRONOUS_FORMAT;

View File

@ -64,6 +64,7 @@ static int32 _InterruptHandler(void *data);
// Transfer functions // Transfer functions
status_t _AddPendingTransfer(Transfer *transfer, status_t _AddPendingTransfer(Transfer *transfer,
ohci_endpoint_descriptor *endpoint, ohci_endpoint_descriptor *endpoint,
ohci_general_td *firstDescriptor,
ohci_general_td *dataDescriptor, ohci_general_td *dataDescriptor,
ohci_general_td *lastDescriptor, ohci_general_td *lastDescriptor,
bool directionIn); bool directionIn);