We cannot use the condition codes to determine if a transfer descriptor is
processed. The controller may initialize it to any value when starting to process the descriptor. If a controller did that it was possible that we thought a transfer was already done even if it actually just started. Transfers would then return that weren't processed, returning uninitialized buffers. Instead of relying on the condition codes we now check that the head and tail pointers are the same. This guarantees that all transfer descriptors of the endpoint at hand are completed. Reverted r32534 again as this one fixes the problem for real. The same things that were mentioned there could happen here essentially, so in the worst case the device or controller could stall because of freeing in-use structures. Fixes #4067. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32551 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
66dde0a85d
commit
c265fd23cd
@ -888,6 +888,18 @@ OHCI::_FinishTransfers()
|
||||
ohci_general_td *descriptor = transfer->first_descriptor;
|
||||
status_t callbackStatus = B_OK;
|
||||
|
||||
ohci_endpoint_descriptor *endpoint = transfer->endpoint;
|
||||
if ((endpoint->head_physical_descriptor & OHCI_ENDPOINT_HEAD_MASK)
|
||||
!= endpoint->tail_physical_descriptor) {
|
||||
// there are still active transfers on this endpoint, we need
|
||||
// to wait for all of them to complete, otherwise we'd read
|
||||
// a potentially bogus data toggle value below
|
||||
TRACE("endpoint %p still has active tds\n", endpoint);
|
||||
lastTransfer = transfer;
|
||||
transfer = transfer->link;
|
||||
continue;
|
||||
}
|
||||
|
||||
while (descriptor && !transfer->canceled) {
|
||||
uint32 status = OHCI_TD_GET_CONDITION_CODE(descriptor->flags);
|
||||
if (status == OHCI_TD_CONDITION_NOT_ACCESSED) {
|
||||
@ -899,7 +911,6 @@ OHCI::_FinishTransfers()
|
||||
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
|
||||
@ -1035,7 +1046,7 @@ OHCI::_FinishTransfers()
|
||||
|
||||
// get the last data toggle and store it for next time
|
||||
transfer->transfer->TransferPipe()->SetDataToggle(
|
||||
(transfer->endpoint->head_physical_descriptor
|
||||
(endpoint->head_physical_descriptor
|
||||
& OHCI_ENDPOINT_TOGGLE_CARRY) != 0);
|
||||
|
||||
if (transfer->transfer->IsFragmented()) {
|
||||
@ -1078,7 +1089,7 @@ status_t
|
||||
OHCI::_SubmitRequest(Transfer *transfer)
|
||||
{
|
||||
usb_request_data *requestData = transfer->RequestData();
|
||||
bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0;
|
||||
bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) != 0;
|
||||
|
||||
ohci_general_td *setupDescriptor
|
||||
= _CreateGeneralDescriptor(sizeof(usb_request_data));
|
||||
@ -1231,7 +1242,7 @@ OHCI::_SwitchEndpointTail(ohci_endpoint_descriptor *endpoint,
|
||||
tail->next_logical_descriptor = first->next_logical_descriptor;
|
||||
|
||||
// the first descriptor becomes the new tail
|
||||
first->flags = OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED);
|
||||
first->flags = 0;
|
||||
first->buffer_physical = 0;
|
||||
first->next_physical_descriptor = 0;
|
||||
first->last_physical_byte_address = 0;
|
||||
@ -1247,6 +1258,7 @@ OHCI::_SwitchEndpointTail(ohci_endpoint_descriptor *endpoint,
|
||||
// update the endpoint tail pointer to reflect the change
|
||||
endpoint->tail_logical_descriptor = first;
|
||||
endpoint->tail_physical_descriptor = (uint32)first->physical_address;
|
||||
TRACE("switched tail from %p to %p\n", tail, first);
|
||||
|
||||
#if 0
|
||||
_PrintEndpoint(endpoint);
|
||||
@ -1410,7 +1422,7 @@ OHCI::_InsertEndpointForPipe(Pipe *pipe)
|
||||
return B_ERROR;
|
||||
} else {
|
||||
ohci_general_td *tail = _CreateGeneralDescriptor(0);
|
||||
tail->flags = OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED);
|
||||
tail->flags = 0;
|
||||
endpoint->tail_logical_descriptor = tail;
|
||||
endpoint->head_physical_descriptor = tail->physical_address;
|
||||
endpoint->tail_physical_descriptor = tail->physical_address;
|
||||
|
Loading…
Reference in New Issue
Block a user