* 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:
parent
1eace5fc53
commit
016ce5dd54
@ -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;
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user