* Renamed fFinishTransfer to fLastTransfer (I don't even know why I called it
so in the first place) * Renamed local variable descriptor to current in the finisher thread * Using next_done_descriptor instead of next_logical_descriptor, as the latest is used to keep track of all descriptors that belongs to the transfer * Added _UnlinkTransfer private method * Implemented _FreeDescriptorChain * Moved endpoint pointer from the ohci_general_td structur to the transfer_data_s structure, ad the ohci_general_td has already a transfer_data_s pointer which can be used to the endpoint pointer reducing ridundancy. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23701 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
a08f19d598
commit
27d7771a1e
@ -71,7 +71,7 @@ OHCI::OHCI(pci_info *info, Stack *stack)
|
||||
fDummyBulk(NULL),
|
||||
fDummyIsochronous(NULL),
|
||||
fFirstTransfer(NULL),
|
||||
fFinishTransfer(NULL),
|
||||
fLastTransfer(NULL),
|
||||
fFinishThread(-1),
|
||||
fStopFinishThread(false),
|
||||
fRootHub(NULL),
|
||||
@ -456,20 +456,20 @@ OHCI::_FinishTransfer()
|
||||
|
||||
// Pull out the done list and reverse its order
|
||||
// for both general and isochronous descriptors
|
||||
ohci_general_td *descriptor, *top;
|
||||
ohci_isochronous_td *isoDescriptor, *isoTop;
|
||||
ohci_general_td *current, *top;
|
||||
ohci_isochronous_td *isoCurrent, *isoTop;
|
||||
uint32 done_list = fHcca->done_head & ~OHCI_DONE_INTERRUPTS;
|
||||
for ( top = NULL, isoTop = NULL ; done_list != 0; ) {
|
||||
if ((descriptor = _FindDescriptorInHash(done_list))) {
|
||||
done_list = descriptor->next_physical_descriptor;
|
||||
descriptor->next_logical_descriptor = (void *)top;
|
||||
top = descriptor;
|
||||
if ((current = _FindDescriptorInHash(done_list))) {
|
||||
done_list = current->next_physical_descriptor;
|
||||
current->next_done_descriptor = (void *)top;
|
||||
top = current;
|
||||
continue;
|
||||
}
|
||||
if ((isoDescriptor = _FindIsoDescriptorInHash(done_list))) {
|
||||
done_list = isoDescriptor->next_physical_descriptor;
|
||||
isoDescriptor->next_logical_descriptor = (void *)isoTop;
|
||||
isoTop = isoDescriptor;
|
||||
if ((isoCurrent = _FindIsoDescriptorInHash(done_list))) {
|
||||
done_list = isoCurrent->next_physical_descriptor;
|
||||
isoCurrent->next_done_descriptor = (void *)isoTop;
|
||||
isoTop = isoCurrent;
|
||||
continue;
|
||||
}
|
||||
// TODO: Should I panic here? :)
|
||||
@ -477,29 +477,101 @@ OHCI::_FinishTransfer()
|
||||
break;
|
||||
}
|
||||
|
||||
// Process the list
|
||||
for (isoDescriptor = isoTop; isoDescriptor != NULL; isoDescriptor
|
||||
= (ohci_isochronous_td *)isoDescriptor->next_logical_descriptor) {
|
||||
// TODO: Process isochronous descriptors
|
||||
}
|
||||
for (descriptor = top; descriptor != NULL; descriptor
|
||||
= (ohci_general_td *)descriptor->next_logical_descriptor) {
|
||||
// TODO: Process general descriptors
|
||||
if (OHCI_TD_GET_CONDITION_CODE(descriptor->flags) == OHCI_NO_ERROR) {
|
||||
if (descriptor->is_last) {
|
||||
// Trasfer completed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Acknowledge the interrupt
|
||||
// TODO: Move the acknowledgement in the interrupt handler. The done_head
|
||||
// value can be passed through a shared variable.
|
||||
fHcca->done_head = 0;
|
||||
_WriteReg(OHCI_INTERRUPT_ENABLE, OHCI_WRITEBACK_DONE_HEAD);
|
||||
|
||||
// Process isochronous list first
|
||||
for (isoCurrent = isoTop; isoCurrent != NULL; isoCurrent
|
||||
= (ohci_isochronous_td *)isoCurrent->next_done_descriptor) {
|
||||
// TODO: Process isochronous descriptors
|
||||
}
|
||||
// Now process the general list
|
||||
for (current = top; current != NULL; ) {
|
||||
ohci_general_td *next = (ohci_general_td *)current->next_done_descriptor;
|
||||
// TODO: Handle cancelled and timeout
|
||||
uint32 conditionCode = OHCI_TD_GET_CONDITION_CODE(current->flags);
|
||||
if (conditionCode != OHCI_NO_ERROR) {
|
||||
// Endpoint is halted
|
||||
// 1. Unlink the transfer
|
||||
// 2. Free all descriptors of the transfer
|
||||
// 3. Notify the caller.
|
||||
// 4. Restart the endpoint
|
||||
// NOTE: There can(should) not be more than one
|
||||
// invalid descriptor from the same transfer in the
|
||||
// done list, as the controller halt the endpoint right
|
||||
// away if a descriptor fails. This means that, if we reversed
|
||||
// the order of the done list (which we did), there is
|
||||
// not reason to look for more failed descriptors in the
|
||||
// done list from the same transfer, as *BSD code does.
|
||||
TRACE(("usb_ohci: transfer failed! ohci error code: %d\n",
|
||||
conditionCode));
|
||||
|
||||
// Unlink the transfer
|
||||
// TODO: check the return value
|
||||
transfer_data *transfer = (transfer_data *)current->transfer;
|
||||
_UnlinkTransfer(transfer);
|
||||
|
||||
// Free all descriptors of this transfer
|
||||
next = (ohci_general_td *)current->next_done_descriptor;
|
||||
_FreeDescriptorChain(transfer->top);
|
||||
|
||||
// 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;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current->is_last) {
|
||||
// TODO: Trasfer completed
|
||||
}
|
||||
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
OHCI::_UnlinkTransfer(transfer_data *transfer)
|
||||
{
|
||||
if (Lock()) {
|
||||
if (transfer == fFirstTransfer) {
|
||||
// It was the first element
|
||||
fFirstTransfer = fFirstTransfer->link;
|
||||
if (transfer == fLastTransfer)
|
||||
// Also the only one
|
||||
fLastTransfer = NULL;
|
||||
} else {
|
||||
transfer_data *data = fFirstTransfer->link;
|
||||
transfer_data *previous = fFirstTransfer;
|
||||
while (data != NULL) {
|
||||
if (data == transfer) {
|
||||
previous->link = data->link;
|
||||
if (data == fLastTransfer)
|
||||
fLastTransfer = previous;
|
||||
break;
|
||||
}
|
||||
previous = data;
|
||||
data = data->link;
|
||||
}
|
||||
}
|
||||
Unlock();
|
||||
return B_OK;
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
OHCI::_AddDescriptorToHash(ohci_general_td *descriptor)
|
||||
{
|
||||
@ -720,9 +792,17 @@ OHCI::_CreateDescriptorChain(ohci_general_td **_firstDescriptor,
|
||||
|
||||
|
||||
void
|
||||
OHCI::_FreeDescriptorChain(ohci_general_td *top)
|
||||
OHCI::_FreeDescriptorChain(ohci_general_td *topDescriptor)
|
||||
{
|
||||
// TODO
|
||||
ohci_general_td *current = topDescriptor;
|
||||
ohci_general_td *next = NULL;
|
||||
|
||||
while (current) {
|
||||
next = (ohci_general_td *)current->next_logical_descriptor;
|
||||
_FreeGeneralDescriptor(current);
|
||||
current = next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -19,11 +19,12 @@ struct pci_module_info;
|
||||
class OHCIRootHub;
|
||||
|
||||
typedef struct transfer_data_s {
|
||||
Transfer *transfer;
|
||||
ohci_general_td *top;
|
||||
bool incoming;
|
||||
bool canceled;
|
||||
transfer_data_s *link;
|
||||
Transfer *transfer;
|
||||
ohci_endpoint_descriptor *endpoint;
|
||||
ohci_general_td *top;
|
||||
bool incoming;
|
||||
bool canceled;
|
||||
transfer_data_s *link;
|
||||
} transfer_data;
|
||||
|
||||
// --------------------------------------
|
||||
@ -97,6 +98,7 @@ static int32 _InterruptHandler(void *data);
|
||||
ohci_general_td *first,
|
||||
ohci_general_td *last,
|
||||
bool directionIn);
|
||||
status_t _UnlinkTransfer(transfer_data *transfer);
|
||||
|
||||
static int32 _FinishThread(void *data);
|
||||
void _FinishTransfer();
|
||||
@ -178,7 +180,7 @@ static pci_module_info *sPCIModule;
|
||||
|
||||
// Maintain a linked list of transfer
|
||||
transfer_data *fFirstTransfer;
|
||||
transfer_data *fFinishTransfer;
|
||||
transfer_data *fLastTransfer;
|
||||
sem_id fFinishTransfersSem;
|
||||
thread_id fFinishThread;
|
||||
bool fStopFinishThread;
|
||||
|
@ -344,9 +344,8 @@ typedef struct ohci_general_td
|
||||
addr_t physical_address; // Physical address of this descriptor
|
||||
void *buffer_logical; // Logical pointer to the buffer
|
||||
void *next_logical_descriptor; // Logical pointer next descriptor
|
||||
void *next_done_descriprtor; // Used for collision in the hash table
|
||||
void *next_done_descriptor; // Used for the done descriptor list
|
||||
size_t buffer_size; // Size of the buffer
|
||||
void *endpoint; // Necessary when there is an error
|
||||
void *transfer; // Pointer to the transfer
|
||||
bool is_last; // Last descriptor of the transfer
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user