From a69e04b96ecde4e73bb1ab229dea9b1176b8e05f Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Mon, 19 May 2008 00:04:08 +0000 Subject: [PATCH] * Implement removal of failed transfers. The head pointer will be moved past the failed transfer if the transfer in question is found to be the offending one. Probably not quite enough and still untested. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25558 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/busses/usb/ohci.cpp | 35 ++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/busses/usb/ohci.cpp b/src/add-ons/kernel/busses/usb/ohci.cpp index ea935d7a4c..e079799a0e 100644 --- a/src/add-ons/kernel/busses/usb/ohci.cpp +++ b/src/add-ons/kernel/busses/usb/ohci.cpp @@ -964,6 +964,7 @@ OHCI::_FinishTransfers() // 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)) + callbackStatus = B_OK; transferDone = true; } @@ -1031,10 +1032,14 @@ OHCI::_FinishTransfers() transfer->transfer->Finished(callbackStatus, actualLength); } + if (callbackStatus != B_OK) { + // remove the transfer and make the head pointer valid again + // (including clearing the halt state) + _RemoveTransferFromEndpoint(transfer); + } + // 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; @@ -1223,6 +1228,32 @@ OHCI::_SwitchEndpointTail(ohci_endpoint_descriptor *endpoint, void OHCI::_RemoveTransferFromEndpoint(transfer_data *transfer) { + // The transfer failed and the endpoint was halted. This means that the + // endpoint head pointer might point somewhere into the descriptor chain + // of this transfer. As we do not know if this transfer actually caused + // the halt on the endpoint we have to make sure this is the case. If we + // find the head to point to somewhere into the descriptor chain then + // simply advancing the head pointer to the link of the last transfer + // will bring the endpoint into a valid state again. This operation is + // safe as the endpoint is currently halted and we therefore can change + // the head pointer. + ohci_endpoint_descriptor *endpoint = transfer->endpoint; + ohci_general_td *descriptor = transfer->first_descriptor; + while (descriptor) { + if (endpoint->head_physical_descriptor == descriptor->physical_address) { + // This descriptor caused the halt. Advance the head pointer. This + // will either move the head to the next valid transfer that can + // then be restarted, or it will move the head to the tail when + // there are no more transfer descriptors. Setting the head will + // also clear the halt state as it is stored in the first bit of + // the head pointer. + endpoint->head_physical_descriptor + = transfer->last_descriptor->next_physical_descriptor; + return; + } + + descriptor = (ohci_general_td *)descriptor->next_logical_descriptor; + } }