* More work on the finisher thread

* Reworked SubmitTrasfer method
* Implemented CancelQueuedTransfers
* Minor clean up


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23722 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Salvatore Benedetto
2008-01-24 20:43:45 +00:00
parent bc1dc61522
commit 5f061e0b6b
3 changed files with 179 additions and 88 deletions
+125 -38
View File
@@ -454,11 +454,16 @@ OHCI::_FinishTransfer()
if (semCount > 0) if (semCount > 0)
acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0);
uint32 done_list = fHcca->done_head & ~OHCI_DONE_INTERRUPTS;
// If done_head is zero, there are not processed descriptors
// in the done list and we have been woken up by CancelQueuedTransfers
// or CancelQueuedIsochronousTransfers in order to do some clean up
// and back to sleep.
if (done_list) {
// Pull out the done list and reverse its order // Pull out the done list and reverse its order
// for both general and isochronous descriptors // for both general and isochronous descriptors
ohci_general_td *current, *top; ohci_general_td *current, *top;
ohci_isochronous_td *isoCurrent, *isoTop; ohci_isochronous_td *isoCurrent, *isoTop;
uint32 done_list = fHcca->done_head & ~OHCI_DONE_INTERRUPTS;
for ( top = NULL, isoTop = NULL ; done_list != 0; ) { for ( top = NULL, isoTop = NULL ; done_list != 0; ) {
if ((current = _FindDescriptorInHash(done_list))) { if ((current = _FindDescriptorInHash(done_list))) {
done_list = current->next_physical_descriptor; done_list = current->next_physical_descriptor;
@@ -473,13 +478,14 @@ OHCI::_FinishTransfer()
continue; continue;
} }
// TODO: Should I panic here? :) // TODO: Should I panic here? :)
TRACE_ERROR(("usb_ohci: address 0x%08lx not found!\n",done_list)); TRACE_ERROR(("usb_ohci: address 0x%08lx not found!\n",
done_list));
break; break;
} }
// Acknowledge the interrupt // Acknowledge the interrupt
// TODO: Move the acknowledgement in the interrupt handler. The done_head // TODO: Move the acknowledgement in the interrupt handler.
// value can be passed through a shared variable. // The done_head value can be passed through a shared variable.
fHcca->done_head = 0; fHcca->done_head = 0;
_WriteReg(OHCI_INTERRUPT_ENABLE, OHCI_WRITEBACK_DONE_HEAD); _WriteReg(OHCI_INTERRUPT_ENABLE, OHCI_WRITEBACK_DONE_HEAD);
@@ -488,17 +494,26 @@ OHCI::_FinishTransfer()
= (ohci_isochronous_td *)isoCurrent->next_done_descriptor) { = (ohci_isochronous_td *)isoCurrent->next_done_descriptor) {
// TODO: Process isochronous descriptors // TODO: Process isochronous descriptors
} }
// Now process the general list // Now process the general list
for (current = top; current != NULL; ) { for (current = top; current != NULL; ) {
ohci_general_td *next = (ohci_general_td *)current->next_done_descriptor; ohci_general_td *next
// TODO: Handle cancelled and timeout = (ohci_general_td *)current->next_done_descriptor;
transfer_data *transfer = (transfer_data *)current->transfer;
if (transfer->canceled) {
// Clear canceled transfer later on
current = next;
continue;
}
bool transferDone = false;
status_t callbackStatus = B_OK;
uint32 conditionCode = OHCI_TD_GET_CONDITION_CODE(current->flags); uint32 conditionCode = OHCI_TD_GET_CONDITION_CODE(current->flags);
if (conditionCode != OHCI_NO_ERROR) { if (conditionCode != OHCI_NO_ERROR) {
// Endpoint is halted // Endpoint is halted: unlink all descriptors belonging to
// 1. Unlink the transfer // the failed transfer from the endpoint and restart the
// 2. Free all descriptors of the transfer // endpoint.
// 3. Notify the caller.
// 4. Restart the endpoint
// NOTE: There can(should) not be more than one // NOTE: There can(should) not be more than one
// invalid descriptor from the same transfer in the // invalid descriptor from the same transfer in the
// done list, as the controller halt the endpoint right // done list, as the controller halt the endpoint right
@@ -509,38 +524,59 @@ OHCI::_FinishTransfer()
TRACE(("usb_ohci: transfer failed! ohci error code: %d\n", TRACE(("usb_ohci: transfer failed! ohci error code: %d\n",
conditionCode)); conditionCode));
// Unlink the transfer _RemoveTransferFromEndpoint(transfer);
// TODO: check the return value
transfer_data *transfer = (transfer_data *)current->transfer;
_UnlinkTransfer(transfer);
// Free all descriptors of this transfer // TODO: Fix the following with the appropriate error
callbackStatus = B_DEV_MULTIPLE_ERRORS;
transferDone = true;
continue;
} else if (current->is_last)
transferDone = true;
if (transferDone) {
size_t actualLength = 0;
if (callbackStatus == B_OK) {
// TODO
}
_UnlinkTransfer(transfer);
transfer->transfer->Finished(callbackStatus, actualLength);
// Update next before current gets deleted
next = (ohci_general_td *)current->next_done_descriptor; next = (ohci_general_td *)current->next_done_descriptor;
_FreeDescriptorChain(transfer->first_descriptor); _FreeDescriptorChain(transfer->first_descriptor);
// Restart the endpoint
// TODO: what if there are other transfer to this endpoint?
ohci_endpoint_descriptor *endpoint
= (ohci_endpoint_descriptor *)transfer->endpoint;
endpoint->head_physical_descriptor = 0;
// Notify the caller
transfer->transfer->Finished(B_CANCELED, 0);
delete transfer->transfer; delete transfer->transfer;
delete transfer; delete transfer;
continue;
}
current = next;
} }
if (current->is_last) {
// TODO: Trasfer completed
} }
// Quick 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; current = next;
} }
} }
} }
void
OHCI::_RemoveTransferFromEndpoint(transfer_data *transfer)
{
// TODO
}
status_t status_t
OHCI::_UnlinkTransfer(transfer_data *transfer) OHCI::_UnlinkTransfer(transfer_data *transfer)
{ {
@@ -660,14 +696,14 @@ OHCI::SubmitTransfer(Transfer *transfer)
return _SubmitControlRequest(transfer); return _SubmitControlRequest(transfer);
} }
if ((type & USB_OBJECT_INTERRUPT_PIPE) || (type & USB_OBJECT_BULK_PIPE)) { if ((type & USB_OBJECT_BULK_PIPE)) {
// TODO TRACE(("usb_ohci: submitting bulk transfer\n"));
return B_OK; return _SubmitBulkTransfer(transfer);
} }
if ((type & USB_OBJECT_ISO_PIPE)) { if (((type & USB_OBJECT_ISO_PIPE) || (type & USB_OBJECT_INTERRUPT_PIPE))) {
TRACE(("usb_ohci: submitting isochronous transfer\n")); TRACE(("usb_ohci: submitting periodic transfer\n"));
return _SubmitIsochronousTransfer(transfer); return _SubmitPeriodicTransfer(transfer);
} }
TRACE_ERROR(("usb_ohci: tried to submit transfer for unknown pipe" TRACE_ERROR(("usb_ohci: tried to submit transfer for unknown pipe"
@@ -759,6 +795,14 @@ OHCI::_SubmitControlRequest(Transfer *transfer)
} }
status_t
OHCI::_SubmitBulkTransfer(Transfer *transfer)
{
// TODO
return B_ERROR;
}
status_t status_t
OHCI::_AddPendingTransfer(Transfer *transfer, ohci_endpoint_descriptor *endpoint, OHCI::_AddPendingTransfer(Transfer *transfer, ohci_endpoint_descriptor *endpoint,
ohci_general_td *firstDescriptor, ohci_general_td *dataDescriptor, bool directionIn) ohci_general_td *firstDescriptor, ohci_general_td *dataDescriptor, bool directionIn)
@@ -802,7 +846,7 @@ OHCI::_AddPendingTransfer(Transfer *transfer, ohci_endpoint_descriptor *endpoint
status_t status_t
OHCI::_SubmitIsochronousTransfer(Transfer *transfer) OHCI::_SubmitPeriodicTransfer(Transfer *transfer)
{ {
return B_ERROR; return B_ERROR;
} }
@@ -835,7 +879,6 @@ OHCI::_FreeDescriptorChain(ohci_general_td *topDescriptor)
_FreeGeneralDescriptor(current); _FreeGeneralDescriptor(current);
current = next; current = next;
} }
} }
@@ -1023,7 +1066,6 @@ OHCI::GetPortStatus(uint8 index, usb_port_status *status)
if (portStatus & OHCI_RH_PORTSTATUS_PPS) if (portStatus & OHCI_RH_PORTSTATUS_PPS)
status->status |= PORT_STATUS_POWER; status->status |= PORT_STATUS_POWER;
// change // change
if (portStatus & OHCI_RH_PORTSTATUS_CSC) if (portStatus & OHCI_RH_PORTSTATUS_CSC)
status->change |= PORT_STATUS_CONNECTION; status->change |= PORT_STATUS_CONNECTION;
@@ -1199,7 +1241,7 @@ OHCI::_InsertEndpointForPipe(Pipe *pipe)
uint32 flags = 0; uint32 flags = 0;
flags |= OHCI_ENDPOINT_SKIP; flags |= OHCI_ENDPOINT_SKIP;
// Set up flag field for the endpoint // Set up device and endpoint address
flags |= OHCI_ENDPOINT_SET_DEVICE_ADDRESS(pipe->DeviceAddress()) flags |= OHCI_ENDPOINT_SET_DEVICE_ADDRESS(pipe->DeviceAddress())
| OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(pipe->EndpointAddress()); | OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(pipe->EndpointAddress());
@@ -1251,7 +1293,7 @@ OHCI::_InsertEndpointForPipe(Pipe *pipe)
break; break;
case USB_OBJECT_ISO_PIPE: case 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;
head = fDummyIsochronous; head = fDummyIsochronous;
break; break;
case USB_OBJECT_INTERRUPT_PIPE: case USB_OBJECT_INTERRUPT_PIPE:
@@ -1306,5 +1348,50 @@ OHCI::_ReadReg(uint32 reg)
status_t status_t
OHCI::CancelQueuedTransfers(Pipe *pipe, bool force) OHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
{ {
if (pipe->Type() & USB_OBJECT_ISO_PIPE)
return _CancelQueuedIsochronousTransfers(pipe, force);
if (!Lock())
return B_ERROR;
transfer_data *current = fFirstTransfer;
while (current) {
if (current->transfer->TransferPipe() == pipe) {
// Check if the skip bit is already set
if (!(current->endpoint->flags & OHCI_ENDPOINT_SKIP)) {
current->endpoint->flags |= OHCI_ENDPOINT_SKIP;
// In case the controller is processing
// this endpoint, wait for it to finish
snooze(1000);
}
// Clear the endpoint
current->endpoint->head_physical_descriptor = NULL;
current->endpoint->tail_physical_descriptor = NULL;
current->endpoint->head_logical_descriptor = NULL;
current->endpoint->tail_logical_descriptor = NULL;
if (!force) {
// If the transfer is canceled by force, the one causing the
// cancel is probably not the one who initiated the transfer
// and the callback is likely not safe anymore
current->transfer->Finished(B_CANCELED, 0);
}
current->canceled = true;
}
current = current->link;
}
Unlock();
// notify the finisher so it can clean up the canceled transfers
release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
return B_OK;
}
status_t
OHCI::_CancelQueuedIsochronousTransfers(Pipe *pipe, bool force)
{
// TODO
return B_ERROR; return B_ERROR;
} }
+6 -2
View File
@@ -100,14 +100,16 @@ static int32 _InterruptHandler(void *data);
ohci_general_td *first, ohci_general_td *first,
ohci_general_td *data, ohci_general_td *data,
bool directionIn); bool directionIn);
status_t _CancelQueuedIsochronousTransfers(
Pipe *pipe, bool force);
status_t _UnlinkTransfer(transfer_data *transfer); status_t _UnlinkTransfer(transfer_data *transfer);
static int32 _FinishThread(void *data); static int32 _FinishThread(void *data);
void _FinishTransfer(); void _FinishTransfer();
status_t _SubmitControlRequest(Transfer *transfer); status_t _SubmitControlRequest(Transfer *transfer);
status_t _SubmitIsochronousTransfer( status_t _SubmitBulkTransfer(Transfer *transfer);
Transfer *transfer); status_t _SubmitPeriodicTransfer(Transfer *transfer);
// Endpoint related methods // Endpoint related methods
ohci_endpoint_descriptor *_AllocateEndpoint(); ohci_endpoint_descriptor *_AllocateEndpoint();
@@ -115,6 +117,8 @@ static int32 _FinishThread(void *data);
ohci_endpoint_descriptor *endpoint); ohci_endpoint_descriptor *endpoint);
status_t _InsertEndpointForPipe(Pipe *pipe); status_t _InsertEndpointForPipe(Pipe *pipe);
status_t _RemoveEndpointForPipe(Pipe *pipe); status_t _RemoveEndpointForPipe(Pipe *pipe);
void _RemoveTransferFromEndpoint(
transfer_data *transfer);
ohci_endpoint_descriptor *_FindInterruptEndpoint(uint8 interval); ohci_endpoint_descriptor *_FindInterruptEndpoint(uint8 interval);
// Transfer descriptor related methods // Transfer descriptor related methods
@@ -346,7 +346,7 @@ typedef struct ohci_general_td
void *next_logical_descriptor; // Logical pointer next descriptor void *next_logical_descriptor; // Logical pointer next descriptor
void *next_done_descriptor; // Used for the done descriptor list void *next_done_descriptor; // Used for the done descriptor list
size_t buffer_size; // Size of the buffer size_t buffer_size; // Size of the buffer
void *transfer; // Pointer to the transfer void *transfer; // Pointer to the transfer_data
bool is_last; // Last descriptor of the transfer bool is_last; // Last descriptor of the transfer
}; };