* Implement "tail switching" so that a new transfer descriptor chain can be
appended to an endpoint descriptor without locking/disabling the endpoint. * Correct the direction of the data phase of a control transfer. * Some minor cleanup. Control requests without data phase (set address for example) might actually work now, but this is still untested. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25541 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -732,10 +732,9 @@ OHCI::_Interrupt()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status & OHCI_UNRECOVERABLE_ERROR) {
|
if (status & OHCI_UNRECOVERABLE_ERROR) {
|
||||||
TRACE(("usb_ohci: unrecoverable error. Controller halted\n"));
|
TRACE_ERROR(("usb_ohci: unrecoverable error - controller halted\n"));
|
||||||
_WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET);
|
_WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET);
|
||||||
// TODO: what else?
|
// TODO: clear all pending transfers, reset and resetup the controller
|
||||||
// Perhaps, clean up all the memory.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status & OHCI_ROOT_HUB_STATUS_CHANGE) {
|
if (status & OHCI_ROOT_HUB_STATUS_CHANGE) {
|
||||||
@@ -756,8 +755,9 @@ OHCI::_Interrupt()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
OHCI::_AddPendingTransfer(Transfer *transfer, ohci_endpoint_descriptor *endpoint,
|
OHCI::_AddPendingTransfer(Transfer *transfer,
|
||||||
ohci_general_td *firstDescriptor, ohci_general_td *dataDescriptor, bool directionIn)
|
ohci_endpoint_descriptor *endpoint, ohci_general_td *firstDescriptor,
|
||||||
|
ohci_general_td *dataDescriptor, bool directionIn)
|
||||||
{
|
{
|
||||||
if (!transfer || !endpoint || !firstDescriptor)
|
if (!transfer || !endpoint || !firstDescriptor)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -1000,7 +1000,7 @@ OHCI::_SubmitControlTransfer(Transfer *transfer)
|
|||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
setupDescriptor->flags |= OHCI_TD_DIRECTION_PID_SETUP
|
setupDescriptor->flags = OHCI_TD_DIRECTION_PID_SETUP
|
||||||
| OHCI_TD_NO_CONDITION_CODE
|
| OHCI_TD_NO_CONDITION_CODE
|
||||||
| OHCI_TD_TOGGLE_0
|
| OHCI_TD_TOGGLE_0
|
||||||
| OHCI_TD_SET_DELAY_INTERRUPT(7);
|
| OHCI_TD_SET_DELAY_INTERRUPT(7);
|
||||||
@@ -1013,7 +1013,7 @@ OHCI::_SubmitControlTransfer(Transfer *transfer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
statusDescriptor->flags
|
statusDescriptor->flags
|
||||||
|= (directionIn ? OHCI_TD_DIRECTION_PID_OUT : OHCI_TD_DIRECTION_PID_IN)
|
= (directionIn ? OHCI_TD_DIRECTION_PID_OUT : OHCI_TD_DIRECTION_PID_IN)
|
||||||
| OHCI_TD_NO_CONDITION_CODE
|
| OHCI_TD_NO_CONDITION_CODE
|
||||||
| OHCI_TD_TOGGLE_1
|
| OHCI_TD_TOGGLE_1
|
||||||
| OHCI_TD_SET_DELAY_INTERRUPT(0);
|
| OHCI_TD_SET_DELAY_INTERRUPT(0);
|
||||||
@@ -1028,7 +1028,7 @@ OHCI::_SubmitControlTransfer(Transfer *transfer)
|
|||||||
if (transfer->VectorCount() > 0) {
|
if (transfer->VectorCount() > 0) {
|
||||||
ohci_general_td *lastDescriptor = NULL;
|
ohci_general_td *lastDescriptor = NULL;
|
||||||
result = _CreateDescriptorChain(&dataDescriptor, &lastDescriptor,
|
result = _CreateDescriptorChain(&dataDescriptor, &lastDescriptor,
|
||||||
directionIn ? OHCI_TD_DIRECTION_PID_OUT : OHCI_TD_DIRECTION_PID_IN,
|
directionIn ? OHCI_TD_DIRECTION_PID_IN : OHCI_TD_DIRECTION_PID_OUT,
|
||||||
transfer->VectorLength());
|
transfer->VectorLength());
|
||||||
if (result < B_OK) {
|
if (result < B_OK) {
|
||||||
_FreeGeneralDescriptor(setupDescriptor);
|
_FreeGeneralDescriptor(setupDescriptor);
|
||||||
@@ -1059,13 +1059,7 @@ OHCI::_SubmitControlTransfer(Transfer *transfer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Append descriptor chain to the endpoint
|
// Append descriptor chain to the endpoint
|
||||||
result = _AppendDescriptorChainToEndpoint(endpoint, setupDescriptor,
|
_SwitchEndpointTail(endpoint, setupDescriptor, statusDescriptor);
|
||||||
statusDescriptor);
|
|
||||||
if (result < B_OK) {
|
|
||||||
TRACE_ERROR(("usb_ohci: failed to append descriptor chain to endpoint\n"));
|
|
||||||
// TODO: Remove transfer_data from list
|
|
||||||
_FreeDescriptorChain(setupDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tell the controller to process the control list
|
// Tell the controller to process the control list
|
||||||
_WriteReg(OHCI_COMMAND_STATUS, OHCI_CONTROL_LIST_FILLED);
|
_WriteReg(OHCI_COMMAND_STATUS, OHCI_CONTROL_LIST_FILLED);
|
||||||
@@ -1088,36 +1082,30 @@ OHCI::_SubmitPeriodicTransfer(Transfer *transfer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
void
|
||||||
OHCI::_AppendDescriptorChainToEndpoint(ohci_endpoint_descriptor *endpoint,
|
OHCI::_SwitchEndpointTail(ohci_endpoint_descriptor *endpoint,
|
||||||
ohci_general_td *first, ohci_general_td *last)
|
ohci_general_td *first, ohci_general_td *last)
|
||||||
{
|
{
|
||||||
endpoint->flags |= OHCI_ENDPOINT_SKIP;
|
// fill in the information of the first descriptor into the current tail
|
||||||
snooze(1000);
|
|
||||||
|
|
||||||
// TODO: Lock on endpoint
|
|
||||||
ohci_general_td *head = (ohci_general_td *)endpoint->head_logical_descriptor;
|
|
||||||
ohci_general_td *tail = (ohci_general_td *)endpoint->tail_logical_descriptor;
|
ohci_general_td *tail = (ohci_general_td *)endpoint->tail_logical_descriptor;
|
||||||
if (head != tail) {
|
tail->flags = first->flags;
|
||||||
// Find the last real descriptor
|
tail->buffer_physical = first->buffer_physical;
|
||||||
ohci_general_td *current = head;
|
tail->next_physical_descriptor = first->next_physical_descriptor;
|
||||||
while (current->next_logical_descriptor != tail)
|
tail->last_physical_byte_address = first->last_physical_byte_address;
|
||||||
current = (ohci_general_td *)current->next_logical_descriptor;
|
tail->buffer_size = first->buffer_size;
|
||||||
// Append to current
|
tail->buffer_logical = first->buffer_logical;
|
||||||
current->next_logical_descriptor = first;
|
tail->next_logical_descriptor = first->next_logical_descriptor;
|
||||||
current->next_physical_descriptor = first->physical_address;
|
|
||||||
} else {
|
|
||||||
// Endpoint has only the dummy descriptor
|
|
||||||
endpoint->head_logical_descriptor = first;
|
|
||||||
endpoint->head_physical_descriptor = first->physical_address;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make the last descriptor point to the dummy
|
// the first descriptor becomes the new tail
|
||||||
last->next_logical_descriptor = tail;
|
tail = first;
|
||||||
last->next_physical_descriptor = tail->physical_address;
|
tail->buffer_size = 0;
|
||||||
|
tail->buffer_logical = NULL;
|
||||||
|
tail->next_logical_descriptor = NULL;
|
||||||
|
_LinkDescriptors(last, tail);
|
||||||
|
|
||||||
endpoint->flags &= ~OHCI_ENDPOINT_SKIP;
|
// update the endpoint tail pointer to reflect the change
|
||||||
return B_OK;
|
endpoint->tail_physical_descriptor = (uint32)tail->physical_address;
|
||||||
|
endpoint->tail_logical_descriptor = tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1260,13 +1248,11 @@ OHCI::_InsertEndpointForPipe(Pipe *pipe)
|
|||||||
_FreeEndpoint(endpoint);
|
_FreeEndpoint(endpoint);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
} else {
|
} else {
|
||||||
ohci_general_td *dummy = _CreateGeneralDescriptor(0);
|
ohci_general_td *tail = _CreateGeneralDescriptor(0);
|
||||||
dummy->next_logical_descriptor = NULL;
|
endpoint->head_logical_descriptor = tail;
|
||||||
dummy->next_physical_descriptor = 0;
|
endpoint->tail_logical_descriptor = tail;
|
||||||
endpoint->head_logical_descriptor = dummy;
|
endpoint->head_physical_descriptor = tail->physical_address;
|
||||||
endpoint->tail_logical_descriptor = dummy;
|
endpoint->tail_physical_descriptor = tail->physical_address;
|
||||||
endpoint->head_physical_descriptor = dummy->physical_address;
|
|
||||||
endpoint->tail_physical_descriptor = dummy->physical_address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Lock()) {
|
if (!Lock()) {
|
||||||
@@ -1317,6 +1303,9 @@ OHCI::_CreateGeneralDescriptor(size_t bufferSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
descriptor->physical_address = (addr_t)physicalAddress;
|
descriptor->physical_address = (addr_t)physicalAddress;
|
||||||
|
descriptor->next_physical_descriptor = 0;
|
||||||
|
descriptor->next_logical_descriptor = NULL;
|
||||||
|
descriptor->buffer_size = bufferSize;
|
||||||
if (bufferSize == 0) {
|
if (bufferSize == 0) {
|
||||||
descriptor->buffer_physical = 0;
|
descriptor->buffer_physical = 0;
|
||||||
descriptor->buffer_logical = NULL;
|
descriptor->buffer_logical = NULL;
|
||||||
@@ -1331,9 +1320,9 @@ OHCI::_CreateGeneralDescriptor(size_t bufferSize)
|
|||||||
sizeof(ohci_general_td));
|
sizeof(ohci_general_td));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptor->last_physical_byte_address
|
descriptor->last_physical_byte_address
|
||||||
= descriptor->buffer_physical + bufferSize - 1;
|
= descriptor->buffer_physical + bufferSize - 1;
|
||||||
|
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,12 +77,12 @@ static int32 _FinishThread(void *data);
|
|||||||
status_t _SubmitBulkTransfer(Transfer *transfer);
|
status_t _SubmitBulkTransfer(Transfer *transfer);
|
||||||
status_t _SubmitPeriodicTransfer(Transfer *transfer);
|
status_t _SubmitPeriodicTransfer(Transfer *transfer);
|
||||||
|
|
||||||
status_t _AppendDescriptorChainToEndpoint(
|
void _SwitchEndpointTail(
|
||||||
ohci_endpoint_descriptor *endpoint,
|
ohci_endpoint_descriptor *endpoint,
|
||||||
ohci_general_td *first,
|
ohci_general_td *first,
|
||||||
ohci_general_td *last);
|
ohci_general_td *last);
|
||||||
void _RemoveTransferFromEndpoint(
|
void _RemoveTransferFromEndpoint(
|
||||||
transfer_data *);
|
transfer_data *transfer);
|
||||||
|
|
||||||
// Endpoint related methods
|
// Endpoint related methods
|
||||||
ohci_endpoint_descriptor *_AllocateEndpoint();
|
ohci_endpoint_descriptor *_AllocateEndpoint();
|
||||||
|
|||||||
@@ -339,10 +339,10 @@ typedef struct {
|
|||||||
uint32 last_physical_byte_address; // Physical pointer to buffer end
|
uint32 last_physical_byte_address; // Physical pointer to buffer end
|
||||||
// Software part
|
// Software part
|
||||||
addr_t physical_address; // Physical address of this descriptor
|
addr_t physical_address; // Physical address of this descriptor
|
||||||
|
size_t buffer_size; // Size of the buffer
|
||||||
void *buffer_logical; // Logical pointer to the buffer
|
void *buffer_logical; // Logical pointer to the buffer
|
||||||
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
|
|
||||||
void *transfer; // Pointer to the transfer_data
|
void *transfer; // Pointer to the transfer_data
|
||||||
bool is_last; // Last descriptor of the transfer
|
bool is_last; // Last descriptor of the transfer
|
||||||
} ohci_general_td;
|
} ohci_general_td;
|
||||||
|
|||||||
Reference in New Issue
Block a user