USB OHCI: Support for isochronous transfers
Finishing and refactoring the draft, initially implemented during April-May 2012 NOTE: startingFrameNumber returned to device contains the number of the next free frame right after the last packed of submitted data. For more details please Look into corresponding [haiku-development] discussion started at 03 Jul 2013. Partially fixes #1045.
This commit is contained in:
parent
883b8dd0b9
commit
cf58476ccc
@ -62,6 +62,19 @@
|
||||
#define USB_ENDPOINT_ATTR_INTERRUPT 0x03
|
||||
#define USB_ENDPOINT_ATTR_MASK 0x03
|
||||
|
||||
/* Synchronization - isochrnous endpoints only */
|
||||
#define USB_ENDPOINT_ATTR_NO_SYNCHRONIZE 0x00
|
||||
#define USB_ENDPOINT_ATTR_ASYNCRONOUS 0x04
|
||||
#define USB_ENDPOINT_ATTR_ADAPTIVE_SYNCHRO 0x08
|
||||
#define USB_ENDPOINT_ATTR_SYNCHRONOUS 0x0C
|
||||
#define USB_ENDPOINT_ATTR_SYNCHRONIZE_MASK 0x0C
|
||||
|
||||
/* Usage Type - isochrnous endpoints only */
|
||||
#define USB_ENDPOINT_ATTR_DATA_USAGE 0x00
|
||||
#define USB_ENDPOINT_ATTR_FEEDBACK_USAGE 0x10
|
||||
#define USB_ENDPOINT_ATTR_IMPLICIT_USAGE 0x20
|
||||
#define USB_ENDPOINT_ATTR_USAGE_MASK 0x30
|
||||
|
||||
#define USB_ENDPOINT_ADDR_DIR_IN 0x80
|
||||
#define USB_ENDPOINT_ADDR_DIR_OUT 0x00
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* Copyright 2005-2008, Haiku Inc. All rights reserved.
|
||||
* Copyright 2005-2013, Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Jan-Rixt Van Hoye
|
||||
* Salvatore Benedetto <salvatore.benedetto@gmail.com>
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* Siarzhuk Zharski <imker@gmx.li>
|
||||
*/
|
||||
|
||||
#include <module.h>
|
||||
@ -74,6 +75,7 @@ OHCI::OHCI(pci_info *info, Stack *stack)
|
||||
fFinishThread(-1),
|
||||
fStopFinishThread(false),
|
||||
fProcessingPipe(NULL),
|
||||
fFrameBandwidth(NULL),
|
||||
fRootHub(NULL),
|
||||
fRootHubAddress(0),
|
||||
fPortCount(0),
|
||||
@ -312,6 +314,12 @@ OHCI::OHCI(pci_info *info, Stack *stack)
|
||||
fPortCount = numberOfPorts;
|
||||
TRACE("port count is %d\n", fPortCount);
|
||||
|
||||
// Create the array that will keep bandwidth information
|
||||
fFrameBandwidth = new(std::nothrow) uint16[NUMBER_OF_FRAMES];
|
||||
|
||||
for (int32 i = 0; i < NUMBER_OF_FRAMES; i++)
|
||||
fFrameBandwidth[i] = MAX_AVAILABLE_BANDWIDTH;
|
||||
|
||||
// Create semaphore the finisher thread will wait for
|
||||
fFinishTransfersSem = create_sem(0, "OHCI Finish Transfers");
|
||||
if (fFinishTransfersSem < B_OK) {
|
||||
@ -378,6 +386,7 @@ OHCI::~OHCI()
|
||||
_FreeEndpoint(fInterruptEndpoints[i]);
|
||||
}
|
||||
|
||||
delete [] fFrameBandwidth;
|
||||
delete [] fInterruptEndpoints;
|
||||
delete fRootHub;
|
||||
|
||||
@ -459,9 +468,6 @@ OHCI::SubmitTransfer(Transfer *transfer)
|
||||
status_t
|
||||
OHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
|
||||
{
|
||||
if (pipe->Type() & USB_OBJECT_ISO_PIPE)
|
||||
return _CancelQueuedIsochronousTransfers(pipe, force);
|
||||
|
||||
if (!Lock())
|
||||
return B_ERROR;
|
||||
|
||||
@ -487,6 +493,25 @@ OHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
|
||||
= current->endpoint->tail_physical_descriptor;
|
||||
|
||||
if (!force) {
|
||||
if (pipe->Type() & USB_OBJECT_ISO_PIPE) {
|
||||
ohci_isochronous_td *descriptor
|
||||
= (ohci_isochronous_td *)current->first_descriptor;
|
||||
while (descriptor) {
|
||||
uint16 frame = OHCI_ITD_GET_STARTING_FRAME(
|
||||
descriptor->flags);
|
||||
_ReleaseIsochronousBandwidth(frame,
|
||||
OHCI_ITD_GET_FRAME_COUNT(descriptor->flags));
|
||||
if (descriptor
|
||||
== (ohci_isochronous_td*)current->last_descriptor)
|
||||
// this is the last ITD of the transfer
|
||||
break;
|
||||
|
||||
descriptor
|
||||
= (ohci_isochronous_td *)
|
||||
descriptor->next_done_descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -914,10 +939,55 @@ OHCI::_AddPendingTransfer(Transfer *transfer,
|
||||
|
||||
|
||||
status_t
|
||||
OHCI::_CancelQueuedIsochronousTransfers(Pipe *pipe, bool force)
|
||||
OHCI::_AddPendingIsochronousTransfer(Transfer *transfer,
|
||||
ohci_endpoint_descriptor *endpoint, ohci_isochronous_td *firstDescriptor,
|
||||
ohci_isochronous_td *lastDescriptor, bool directionIn)
|
||||
{
|
||||
// TODO
|
||||
return B_ERROR;
|
||||
if (!transfer || !endpoint || !lastDescriptor)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
transfer_data *data = new(std::nothrow) transfer_data;
|
||||
if (!data)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t result = transfer->InitKernelAccess();
|
||||
if (result < B_OK) {
|
||||
delete data;
|
||||
return result;
|
||||
}
|
||||
|
||||
data->transfer = transfer;
|
||||
data->endpoint = endpoint;
|
||||
data->incoming = directionIn;
|
||||
data->canceled = false;
|
||||
data->link = NULL;
|
||||
|
||||
// the current tail will become the first descriptor
|
||||
data->first_descriptor = (ohci_general_td*)endpoint->tail_logical_descriptor;
|
||||
|
||||
// the data and first descriptors are the same
|
||||
data->data_descriptor = data->first_descriptor;
|
||||
|
||||
// the last and the first descriptor might be the same
|
||||
if (lastDescriptor == firstDescriptor)
|
||||
data->last_descriptor = data->first_descriptor;
|
||||
else
|
||||
data->last_descriptor = (ohci_general_td*)lastDescriptor;
|
||||
|
||||
if (!Lock()) {
|
||||
delete data;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (fLastTransfer)
|
||||
fLastTransfer->link = data;
|
||||
else
|
||||
fFirstTransfer = data;
|
||||
|
||||
fLastTransfer = data;
|
||||
Unlock();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -957,10 +1027,20 @@ OHCI::_FinishTransfers()
|
||||
ohci_endpoint_descriptor *endpoint = transfer->endpoint;
|
||||
status_t callbackStatus = B_OK;
|
||||
|
||||
if (endpoint->flags & OHCI_ENDPOINT_ISOCHRONOUS_FORMAT) {
|
||||
transfer_data *next = transfer->link;
|
||||
if (_FinishIsochronousTransfer(transfer, &lastTransfer)) {
|
||||
delete transfer->transfer;
|
||||
delete transfer;
|
||||
}
|
||||
transfer = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
MutexLocker endpointLocker(endpoint->lock);
|
||||
|
||||
if ((endpoint->head_physical_descriptor & OHCI_ENDPOINT_HEAD_MASK)
|
||||
!= endpoint->tail_physical_descriptor) {
|
||||
!= 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
|
||||
@ -991,49 +1071,7 @@ OHCI::_FinishTransfers()
|
||||
// still ensures that this td was handled before).
|
||||
TRACE_ERROR("td error: 0x%08" B_PRIx32 "\n", status);
|
||||
|
||||
switch (status) {
|
||||
case OHCI_TD_CONDITION_CRC_ERROR:
|
||||
case OHCI_TD_CONDITION_BIT_STUFFING:
|
||||
case OHCI_TD_CONDITION_TOGGLE_MISMATCH:
|
||||
callbackStatus = B_DEV_CRC_ERROR;
|
||||
break;
|
||||
|
||||
case OHCI_TD_CONDITION_STALL:
|
||||
callbackStatus = B_DEV_STALLED;
|
||||
break;
|
||||
|
||||
case OHCI_TD_CONDITION_NO_RESPONSE:
|
||||
callbackStatus = B_TIMED_OUT;
|
||||
break;
|
||||
|
||||
case OHCI_TD_CONDITION_PID_CHECK_FAILURE:
|
||||
callbackStatus = B_DEV_BAD_PID;
|
||||
break;
|
||||
|
||||
case OHCI_TD_CONDITION_UNEXPECTED_PID:
|
||||
callbackStatus = B_DEV_UNEXPECTED_PID;
|
||||
break;
|
||||
|
||||
case OHCI_TD_CONDITION_DATA_OVERRUN:
|
||||
callbackStatus = B_DEV_DATA_OVERRUN;
|
||||
break;
|
||||
|
||||
case OHCI_TD_CONDITION_DATA_UNDERRUN:
|
||||
callbackStatus = B_DEV_DATA_UNDERRUN;
|
||||
break;
|
||||
|
||||
case OHCI_TD_CONDITION_BUFFER_OVERRUN:
|
||||
callbackStatus = B_DEV_FIFO_OVERRUN;
|
||||
break;
|
||||
|
||||
case OHCI_TD_CONDITION_BUFFER_UNDERRUN:
|
||||
callbackStatus = B_DEV_FIFO_UNDERRUN;
|
||||
break;
|
||||
|
||||
default:
|
||||
callbackStatus = B_ERROR;
|
||||
break;
|
||||
}
|
||||
callbackStatus = _GetStatusOfConditionCode(status);
|
||||
|
||||
transferDone = true;
|
||||
break;
|
||||
@ -1163,6 +1201,141 @@ OHCI::_FinishTransfers()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
OHCI::_FinishIsochronousTransfer(transfer_data *transfer,
|
||||
transfer_data **_lastTransfer)
|
||||
{
|
||||
status_t callbackStatus = B_OK;
|
||||
size_t actualLength = 0;
|
||||
uint32 packet = 0;
|
||||
|
||||
if (transfer->canceled)
|
||||
callbackStatus = B_CANCELED;
|
||||
else {
|
||||
// at first check if ALL ITDs are retired by HC
|
||||
ohci_isochronous_td *descriptor
|
||||
= (ohci_isochronous_td *)transfer->first_descriptor;
|
||||
while (descriptor) {
|
||||
if (OHCI_TD_GET_CONDITION_CODE(descriptor->flags)
|
||||
== OHCI_TD_CONDITION_NOT_ACCESSED) {
|
||||
TRACE("ITD %p still active\n", descriptor);
|
||||
*_lastTransfer = transfer;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (descriptor == (ohci_isochronous_td*)transfer->last_descriptor) {
|
||||
// this is the last ITD of the transfer
|
||||
descriptor = (ohci_isochronous_td *)transfer->first_descriptor;
|
||||
break;
|
||||
}
|
||||
|
||||
descriptor
|
||||
= (ohci_isochronous_td *)descriptor->next_done_descriptor;
|
||||
}
|
||||
|
||||
while (descriptor) {
|
||||
uint32 status = OHCI_TD_GET_CONDITION_CODE(descriptor->flags);
|
||||
if (status != OHCI_TD_CONDITION_NO_ERROR) {
|
||||
TRACE_ERROR("ITD error: 0x%08" B_PRIx32 "\n", status);
|
||||
// spec says that in most cases condition code
|
||||
// of retired ITDs is set to NoError, but for the
|
||||
// time overrun it can be DataOverrun. We assume
|
||||
// the _first_ occurience of such error as status
|
||||
// reported to the callback
|
||||
if (callbackStatus == B_OK)
|
||||
callbackStatus = _GetStatusOfConditionCode(status);
|
||||
}
|
||||
|
||||
usb_isochronous_data *isochronousData
|
||||
= transfer->transfer->IsochronousData();
|
||||
|
||||
uint32 frameCount = OHCI_ITD_GET_FRAME_COUNT(descriptor->flags);
|
||||
for (size_t i = 0; i < frameCount; i++, packet++) {
|
||||
usb_iso_packet_descriptor* packet_descriptor
|
||||
= &isochronousData->packet_descriptors[packet];
|
||||
|
||||
uint16 offset = descriptor->offset[OHCI_ITD_OFFSET_IDX(i)];
|
||||
uint8 code = OHCI_ITD_GET_BUFFER_CONDITION_CODE(offset);
|
||||
packet_descriptor->status = _GetStatusOfConditionCode(code);
|
||||
|
||||
// not touched by HC - sheduled too late to be processed
|
||||
// in the requested frame - so we ignore it too
|
||||
if (packet_descriptor->status == B_DEV_TOO_LATE)
|
||||
continue;
|
||||
|
||||
size_t len = OHCI_ITD_GET_BUFFER_LENGTH(offset);
|
||||
if (!transfer->incoming)
|
||||
len = packet_descriptor->request_length - len;
|
||||
|
||||
packet_descriptor->actual_length = len;
|
||||
actualLength += len;
|
||||
}
|
||||
|
||||
uint16 frame = OHCI_ITD_GET_STARTING_FRAME(descriptor->flags);
|
||||
_ReleaseIsochronousBandwidth(frame,
|
||||
OHCI_ITD_GET_FRAME_COUNT(descriptor->flags));
|
||||
|
||||
TRACE("ITD %p done\n", descriptor);
|
||||
|
||||
if (descriptor == (ohci_isochronous_td*)transfer->last_descriptor)
|
||||
break;
|
||||
|
||||
descriptor
|
||||
= (ohci_isochronous_td *)descriptor->next_done_descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
// remove the transfer from the list first so we are sure
|
||||
// it doesn't get canceled while we still process it
|
||||
if (Lock()) {
|
||||
if (*_lastTransfer)
|
||||
(*_lastTransfer)->link = transfer->link;
|
||||
|
||||
if (transfer == fFirstTransfer)
|
||||
fFirstTransfer = transfer->link;
|
||||
if (transfer == fLastTransfer)
|
||||
fLastTransfer = *_lastTransfer;
|
||||
|
||||
// store the currently processing pipe here so we can wait
|
||||
// in cancel if we are processing something on the target pipe
|
||||
if (!transfer->canceled)
|
||||
fProcessingPipe = transfer->transfer->TransferPipe();
|
||||
|
||||
transfer->link = NULL;
|
||||
Unlock();
|
||||
}
|
||||
|
||||
// break the descriptor chain on the last descriptor
|
||||
transfer->last_descriptor->next_logical_descriptor = NULL;
|
||||
TRACE("iso.transfer %p done with status 0x%08" B_PRIx32 " len:%ld\n",
|
||||
transfer, callbackStatus, actualLength);
|
||||
|
||||
// if canceled the callback has already been called
|
||||
if (!transfer->canceled) {
|
||||
if (callbackStatus == B_OK && actualLength > 0) {
|
||||
if (transfer->data_descriptor && transfer->incoming) {
|
||||
// data to read out
|
||||
iovec *vector = transfer->transfer->Vector();
|
||||
size_t vectorCount = transfer->transfer->VectorCount();
|
||||
|
||||
transfer->transfer->PrepareKernelAccess();
|
||||
_ReadIsochronousDescriptorChain(
|
||||
(ohci_isochronous_td*)transfer->data_descriptor,
|
||||
vector, vectorCount);
|
||||
}
|
||||
}
|
||||
|
||||
transfer->transfer->Finished(callbackStatus, actualLength);
|
||||
fProcessingPipe = NULL;
|
||||
}
|
||||
|
||||
_FreeIsochronousDescriptorChain(
|
||||
(ohci_isochronous_td*)transfer->first_descriptor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
OHCI::_SubmitRequest(Transfer *transfer)
|
||||
{
|
||||
@ -1307,8 +1480,58 @@ OHCI::_SubmitTransfer(Transfer *transfer)
|
||||
status_t
|
||||
OHCI::_SubmitIsochronousTransfer(Transfer *transfer)
|
||||
{
|
||||
TRACE_ERROR("isochronous transfers not implemented\n");
|
||||
return B_ERROR;
|
||||
Pipe *pipe = transfer->TransferPipe();
|
||||
bool directionIn = (pipe->Direction() == Pipe::In);
|
||||
usb_isochronous_data *isochronousData = transfer->IsochronousData();
|
||||
|
||||
ohci_isochronous_td *firstDescriptor = NULL;
|
||||
ohci_isochronous_td *lastDescriptor = NULL;
|
||||
status_t result = _CreateIsochronousDescriptorChain(&firstDescriptor,
|
||||
&lastDescriptor, transfer);
|
||||
|
||||
if (firstDescriptor == 0 || lastDescriptor == 0)
|
||||
return B_ERROR;
|
||||
|
||||
if (result < B_OK)
|
||||
return result;
|
||||
|
||||
// Set the last descriptor to generate an interrupt
|
||||
lastDescriptor->flags &= ~OHCI_ITD_INTERRUPT_MASK;
|
||||
// let the controller retire last ITD
|
||||
lastDescriptor->flags |= OHCI_ITD_SET_DELAY_INTERRUPT(1);
|
||||
|
||||
// If direction is out set every descriptor data
|
||||
if (pipe->Direction() == Pipe::Out)
|
||||
_WriteIsochronousDescriptorChain(firstDescriptor,
|
||||
transfer->Vector(), transfer->VectorCount());
|
||||
else
|
||||
// Initialize the packet descriptors
|
||||
for (uint32 i = 0; i < isochronousData->packet_count; i++) {
|
||||
isochronousData->packet_descriptors[i].actual_length = 0;
|
||||
isochronousData->packet_descriptors[i].status = B_NO_INIT;
|
||||
}
|
||||
|
||||
// Add to the transfer list
|
||||
ohci_endpoint_descriptor *endpoint
|
||||
= (ohci_endpoint_descriptor *)pipe->ControllerCookie();
|
||||
|
||||
MutexLocker endpointLocker(endpoint->lock);
|
||||
result = _AddPendingIsochronousTransfer(transfer, endpoint,
|
||||
firstDescriptor, lastDescriptor, directionIn);
|
||||
if (result < B_OK) {
|
||||
TRACE_ERROR("failed to add pending iso.transfer:"
|
||||
"0x%08" B_PRIx32 "\n", result);
|
||||
_FreeIsochronousDescriptorChain(firstDescriptor);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Add the descriptor chain to the endpoint
|
||||
_SwitchIsochronousEndpointTail(endpoint, firstDescriptor, lastDescriptor);
|
||||
endpointLocker.Unlock();
|
||||
|
||||
endpoint->flags &= ~OHCI_ENDPOINT_SKIP;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -1352,6 +1575,54 @@ OHCI::_SwitchEndpointTail(ohci_endpoint_descriptor *endpoint,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
OHCI::_SwitchIsochronousEndpointTail(ohci_endpoint_descriptor *endpoint,
|
||||
ohci_isochronous_td *first, ohci_isochronous_td *last)
|
||||
{
|
||||
// fill in the information of the first descriptor into the current tail
|
||||
ohci_isochronous_td *tail
|
||||
= (ohci_isochronous_td*)endpoint->tail_logical_descriptor;
|
||||
tail->flags = first->flags;
|
||||
tail->buffer_page_byte_0 = first->buffer_page_byte_0;
|
||||
tail->next_physical_descriptor = first->next_physical_descriptor;
|
||||
tail->last_byte_address = first->last_byte_address;
|
||||
tail->buffer_size = first->buffer_size;
|
||||
tail->buffer_logical = first->buffer_logical;
|
||||
tail->next_logical_descriptor = first->next_logical_descriptor;
|
||||
tail->next_done_descriptor = first->next_done_descriptor;
|
||||
|
||||
// the first descriptor becomes the new tail
|
||||
first->flags = 0;
|
||||
first->buffer_page_byte_0 = 0;
|
||||
first->next_physical_descriptor = 0;
|
||||
first->last_byte_address = 0;
|
||||
first->buffer_size = 0;
|
||||
first->buffer_logical = NULL;
|
||||
first->next_logical_descriptor = NULL;
|
||||
first->next_done_descriptor = NULL;
|
||||
|
||||
for (int i = 0; i < OHCI_ITD_NOFFSET; i++) {
|
||||
tail->offset[i] = first->offset[i];
|
||||
first->offset[i] = 0;
|
||||
}
|
||||
|
||||
if (first == last)
|
||||
_LinkIsochronousDescriptors(tail, first, NULL);
|
||||
else
|
||||
_LinkIsochronousDescriptors(last, first, NULL);
|
||||
|
||||
// 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);
|
||||
_PrintDescriptorChain(tail);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
OHCI::_RemoveTransferFromEndpoint(transfer_data *transfer)
|
||||
{
|
||||
@ -1515,9 +1786,11 @@ OHCI::_InsertEndpointForPipe(Pipe *pipe)
|
||||
if (pipe->Type() & USB_OBJECT_ISO_PIPE) {
|
||||
// Set the isochronous bit format
|
||||
endpoint->flags |= OHCI_ENDPOINT_ISOCHRONOUS_FORMAT;
|
||||
// TODO
|
||||
_FreeEndpoint(endpoint);
|
||||
return B_ERROR;
|
||||
ohci_isochronous_td *tail = _CreateIsochronousDescriptor(0);
|
||||
tail->flags = 0;
|
||||
endpoint->tail_logical_descriptor = tail;
|
||||
endpoint->head_physical_descriptor = tail->physical_address;
|
||||
endpoint->tail_physical_descriptor = tail->physical_address;
|
||||
} else {
|
||||
ohci_general_td *tail = _CreateGeneralDescriptor(0);
|
||||
tail->flags = 0;
|
||||
@ -1691,6 +1964,191 @@ OHCI::_FreeDescriptorChain(ohci_general_td *topDescriptor)
|
||||
}
|
||||
|
||||
|
||||
ohci_isochronous_td *
|
||||
OHCI::_CreateIsochronousDescriptor(size_t bufferSize)
|
||||
{
|
||||
ohci_isochronous_td *descriptor = NULL;
|
||||
phys_addr_t physicalAddress;
|
||||
|
||||
if (fStack->AllocateChunk((void **)&descriptor, &physicalAddress,
|
||||
sizeof(ohci_isochronous_td)) != B_OK) {
|
||||
TRACE_ERROR("failed to allocate isochronous descriptor\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
descriptor->physical_address = (uint32)physicalAddress;
|
||||
descriptor->next_physical_descriptor = 0;
|
||||
descriptor->next_logical_descriptor = NULL;
|
||||
descriptor->next_done_descriptor = NULL;
|
||||
descriptor->buffer_size = bufferSize;
|
||||
if (bufferSize == 0) {
|
||||
descriptor->buffer_page_byte_0 = 0;
|
||||
descriptor->buffer_logical = NULL;
|
||||
descriptor->last_byte_address = 0;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
if (fStack->AllocateChunk(&descriptor->buffer_logical,
|
||||
&physicalAddress, bufferSize) != B_OK) {
|
||||
TRACE_ERROR("failed to allocate space for iso.buffer\n");
|
||||
fStack->FreeChunk(descriptor, descriptor->physical_address,
|
||||
sizeof(ohci_isochronous_td));
|
||||
return NULL;
|
||||
}
|
||||
descriptor->buffer_page_byte_0 = (uint32)physicalAddress;
|
||||
descriptor->last_byte_address
|
||||
= descriptor->buffer_page_byte_0 + bufferSize - 1;
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
OHCI::_FreeIsochronousDescriptor(ohci_isochronous_td *descriptor)
|
||||
{
|
||||
if (!descriptor)
|
||||
return;
|
||||
|
||||
if (descriptor->buffer_logical) {
|
||||
fStack->FreeChunk(descriptor->buffer_logical,
|
||||
descriptor->buffer_page_byte_0, descriptor->buffer_size);
|
||||
}
|
||||
|
||||
fStack->FreeChunk((void *)descriptor, descriptor->physical_address,
|
||||
sizeof(ohci_general_td));
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
OHCI::_CreateIsochronousDescriptorChain(ohci_isochronous_td **_firstDescriptor,
|
||||
ohci_isochronous_td **_lastDescriptor, Transfer *transfer)
|
||||
{
|
||||
Pipe *pipe = transfer->TransferPipe();
|
||||
usb_isochronous_data *isochronousData = transfer->IsochronousData();
|
||||
|
||||
size_t dataLength = transfer->VectorLength();
|
||||
size_t packet_count = isochronousData->packet_count;
|
||||
|
||||
if (packet_count == 0) {
|
||||
TRACE_ERROR("isochronous packet_count should not be equal to zero.");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
size_t packetSize = dataLength / packet_count;
|
||||
if (dataLength % packet_count != 0)
|
||||
packetSize++;
|
||||
|
||||
if (packetSize > pipe->MaxPacketSize()) {
|
||||
TRACE_ERROR("isochronous packetSize %ld is bigger"
|
||||
" than pipe MaxPacketSize %ld.", packetSize, pipe->MaxPacketSize());
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
uint16 bandwidth = transfer->Bandwidth() / packet_count;
|
||||
if (transfer->Bandwidth() % packet_count != 0)
|
||||
bandwidth++;
|
||||
|
||||
ohci_isochronous_td *firstDescriptor = NULL;
|
||||
ohci_isochronous_td *lastDescriptor = *_firstDescriptor;
|
||||
|
||||
// the frame number currently processed by the host controller
|
||||
uint16 currentFrame = fHcca->current_frame_number & 0xFFFF;
|
||||
uint16 safeFrames = 5;
|
||||
|
||||
// The entry where to start inserting the first Isochronous descriptor
|
||||
// real frame number may differ in case provided one has not bandwidth
|
||||
if (isochronousData->flags & USB_ISO_ASAP ||
|
||||
isochronousData->starting_frame_number == NULL)
|
||||
// We should stay about 5-10 ms ahead of the controller
|
||||
// USB1 frame is equal to 1 ms
|
||||
currentFrame += safeFrames;
|
||||
else
|
||||
currentFrame = *isochronousData->starting_frame_number;
|
||||
|
||||
uint16 packets = packet_count;
|
||||
uint16 frameOffset = 0;
|
||||
while (packets > 0) {
|
||||
// look for up to 8 continous frames with available bandwidth
|
||||
uint16 frameCount = 0;
|
||||
while (frameCount < min_c(OHCI_ITD_NOFFSET, packets)
|
||||
&& _AllocateIsochronousBandwidth(frameOffset + currentFrame
|
||||
+ frameCount, bandwidth))
|
||||
frameCount++;
|
||||
|
||||
if (frameCount == 0) {
|
||||
// starting frame has no bandwidth for our transaction - try next
|
||||
if (++frameOffset >= 0xFFFF) {
|
||||
TRACE_ERROR("failed to allocate bandwidth\n");
|
||||
_FreeIsochronousDescriptorChain(firstDescriptor);
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
ohci_isochronous_td *descriptor = _CreateIsochronousDescriptor(
|
||||
packetSize * frameCount);
|
||||
|
||||
if (!descriptor) {
|
||||
TRACE_ERROR("failed to allocate ITD\n");
|
||||
_ReleaseIsochronousBandwidth(currentFrame + frameOffset, frameCount);
|
||||
_FreeIsochronousDescriptorChain(firstDescriptor);
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
uint16 pageOffset = descriptor->buffer_page_byte_0 & 0xfff;
|
||||
descriptor->buffer_page_byte_0 &= ~0xfff;
|
||||
for (uint16 i = 0; i < frameCount; i++) {
|
||||
descriptor->offset[OHCI_ITD_OFFSET_IDX(i)]
|
||||
= OHCI_ITD_MK_OFFS(pageOffset + packetSize * i);
|
||||
}
|
||||
|
||||
descriptor->flags = OHCI_ITD_SET_FRAME_COUNT(frameCount)
|
||||
| OHCI_ITD_SET_CONDITION_CODE(OHCI_ITD_CONDITION_NOT_ACCESSED)
|
||||
| OHCI_ITD_SET_DELAY_INTERRUPT(OHCI_ITD_INTERRUPT_NONE)
|
||||
| OHCI_ITD_SET_STARTING_FRAME(currentFrame + frameOffset);
|
||||
|
||||
// the last packet may be shorter than other ones in this transfer
|
||||
if (packets <= OHCI_ITD_NOFFSET)
|
||||
descriptor->last_byte_address
|
||||
+= dataLength - packetSize * (packet_count);
|
||||
|
||||
// link to previous
|
||||
if (lastDescriptor)
|
||||
_LinkIsochronousDescriptors(lastDescriptor, descriptor, descriptor);
|
||||
|
||||
lastDescriptor = descriptor;
|
||||
if (!firstDescriptor)
|
||||
firstDescriptor = descriptor;
|
||||
|
||||
packets -= frameCount;
|
||||
|
||||
frameOffset += frameCount;
|
||||
|
||||
if (packets == 0 && isochronousData->starting_frame_number)
|
||||
*isochronousData->starting_frame_number = currentFrame + frameOffset;
|
||||
}
|
||||
|
||||
*_firstDescriptor = firstDescriptor;
|
||||
*_lastDescriptor = lastDescriptor;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
OHCI::_FreeIsochronousDescriptorChain(ohci_isochronous_td *topDescriptor)
|
||||
{
|
||||
ohci_isochronous_td *current = topDescriptor;
|
||||
ohci_isochronous_td *next = NULL;
|
||||
|
||||
while (current) {
|
||||
next = (ohci_isochronous_td *)current->next_done_descriptor;
|
||||
_FreeIsochronousDescriptor(current);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
OHCI::_WriteDescriptorChain(ohci_general_td *topDescriptor, iovec *vector,
|
||||
size_t vectorCount)
|
||||
@ -1746,6 +2204,61 @@ OHCI::_WriteDescriptorChain(ohci_general_td *topDescriptor, iovec *vector,
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
OHCI::_WriteIsochronousDescriptorChain(ohci_isochronous_td *topDescriptor,
|
||||
iovec *vector, size_t vectorCount)
|
||||
{
|
||||
ohci_isochronous_td *current = topDescriptor;
|
||||
size_t actualLength = 0;
|
||||
size_t vectorIndex = 0;
|
||||
size_t vectorOffset = 0;
|
||||
size_t bufferOffset = 0;
|
||||
|
||||
while (current) {
|
||||
if (!current->buffer_logical)
|
||||
break;
|
||||
|
||||
while (true) {
|
||||
size_t length = min_c(current->buffer_size - bufferOffset,
|
||||
vector[vectorIndex].iov_len - vectorOffset);
|
||||
|
||||
TRACE("copying %ld bytes to bufferOffset %ld from"
|
||||
" vectorOffset %ld at index %ld of %ld\n", length, bufferOffset,
|
||||
vectorOffset, vectorIndex, vectorCount);
|
||||
memcpy((uint8 *)current->buffer_logical + bufferOffset,
|
||||
(uint8 *)vector[vectorIndex].iov_base + vectorOffset, length);
|
||||
|
||||
actualLength += length;
|
||||
vectorOffset += length;
|
||||
bufferOffset += length;
|
||||
|
||||
if (vectorOffset >= vector[vectorIndex].iov_len) {
|
||||
if (++vectorIndex >= vectorCount) {
|
||||
TRACE("wrote descriptor chain (%ld bytes, no"
|
||||
" more vectors)\n", actualLength);
|
||||
return actualLength;
|
||||
}
|
||||
|
||||
vectorOffset = 0;
|
||||
}
|
||||
|
||||
if (bufferOffset >= current->buffer_size) {
|
||||
bufferOffset = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!current->next_logical_descriptor)
|
||||
break;
|
||||
|
||||
current = (ohci_isochronous_td *)current->next_logical_descriptor;
|
||||
}
|
||||
|
||||
TRACE("wrote descriptor chain (%ld bytes)\n", actualLength);
|
||||
return actualLength;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
OHCI::_ReadDescriptorChain(ohci_general_td *topDescriptor, iovec *vector,
|
||||
size_t vectorCount)
|
||||
@ -1805,6 +2318,59 @@ OHCI::_ReadDescriptorChain(ohci_general_td *topDescriptor, iovec *vector,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
OHCI::_ReadIsochronousDescriptorChain(ohci_isochronous_td *topDescriptor,
|
||||
iovec *vector, size_t vectorCount)
|
||||
{
|
||||
ohci_isochronous_td *current = topDescriptor;
|
||||
size_t actualLength = 0;
|
||||
size_t vectorIndex = 0;
|
||||
size_t vectorOffset = 0;
|
||||
size_t bufferOffset = 0;
|
||||
|
||||
while (current && OHCI_ITD_GET_CONDITION_CODE(current->flags)
|
||||
!= OHCI_ITD_CONDITION_NOT_ACCESSED) {
|
||||
size_t bufferSize = current->buffer_size;
|
||||
if (current->buffer_logical != NULL && bufferSize > 0) {
|
||||
while (true) {
|
||||
size_t length = min_c(bufferSize - bufferOffset,
|
||||
vector[vectorIndex].iov_len - vectorOffset);
|
||||
|
||||
TRACE("copying %ld bytes to vectorOffset %ld from bufferOffset"
|
||||
" %ld at index %ld of %ld\n", length, vectorOffset,
|
||||
bufferOffset, vectorIndex, vectorCount);
|
||||
memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
|
||||
(uint8 *)current->buffer_logical + bufferOffset, length);
|
||||
|
||||
actualLength += length;
|
||||
vectorOffset += length;
|
||||
bufferOffset += length;
|
||||
|
||||
if (vectorOffset >= vector[vectorIndex].iov_len) {
|
||||
if (++vectorIndex >= vectorCount) {
|
||||
TRACE("read descriptor chain (%ld bytes, "
|
||||
"no more vectors)\n", actualLength);
|
||||
return;
|
||||
}
|
||||
|
||||
vectorOffset = 0;
|
||||
}
|
||||
|
||||
if (bufferOffset >= bufferSize) {
|
||||
bufferOffset = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
current = (ohci_isochronous_td *)current->next_done_descriptor;
|
||||
}
|
||||
|
||||
TRACE("read descriptor chain (%ld bytes)\n", actualLength);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
OHCI::_ReadActualLength(ohci_general_td *topDescriptor)
|
||||
{
|
||||
@ -1836,18 +2402,85 @@ OHCI::_LinkDescriptors(ohci_general_td *first, ohci_general_td *second)
|
||||
}
|
||||
|
||||
|
||||
ohci_isochronous_td *
|
||||
OHCI::_CreateIsochronousDescriptor()
|
||||
void
|
||||
OHCI::_LinkIsochronousDescriptors(ohci_isochronous_td *first,
|
||||
ohci_isochronous_td *second, ohci_isochronous_td *nextDone)
|
||||
{
|
||||
// TODO
|
||||
return NULL;
|
||||
first->next_physical_descriptor = second->physical_address;
|
||||
first->next_logical_descriptor = second;
|
||||
first->next_done_descriptor = nextDone;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
OHCI::_AllocateIsochronousBandwidth(uint16 frame, uint16 size)
|
||||
{
|
||||
frame %= NUMBER_OF_FRAMES;
|
||||
if (size > fFrameBandwidth[frame])
|
||||
return false;
|
||||
|
||||
fFrameBandwidth[frame]-= size;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
OHCI::_FreeIsochronousDescriptor(ohci_isochronous_td *descriptor)
|
||||
OHCI::_ReleaseIsochronousBandwidth(uint16 startFrame, uint16 frameCount)
|
||||
{
|
||||
// TODO
|
||||
for (size_t index = 0; index < frameCount; index++) {
|
||||
uint16 frame = (startFrame + index) % NUMBER_OF_FRAMES;
|
||||
fFrameBandwidth[frame] = MAX_AVAILABLE_BANDWIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
OHCI::_GetStatusOfConditionCode(uint8 conditionCode)
|
||||
{
|
||||
switch (conditionCode) {
|
||||
case OHCI_TD_CONDITION_NO_ERROR:
|
||||
return B_OK;
|
||||
|
||||
case OHCI_TD_CONDITION_CRC_ERROR:
|
||||
case OHCI_TD_CONDITION_BIT_STUFFING:
|
||||
case OHCI_TD_CONDITION_TOGGLE_MISMATCH:
|
||||
return B_DEV_CRC_ERROR;
|
||||
|
||||
case OHCI_TD_CONDITION_STALL:
|
||||
return B_DEV_STALLED;
|
||||
|
||||
case OHCI_TD_CONDITION_NO_RESPONSE:
|
||||
return B_TIMED_OUT;
|
||||
|
||||
case OHCI_TD_CONDITION_PID_CHECK_FAILURE:
|
||||
return B_DEV_BAD_PID;
|
||||
|
||||
case OHCI_TD_CONDITION_UNEXPECTED_PID:
|
||||
return B_DEV_UNEXPECTED_PID;
|
||||
|
||||
case OHCI_TD_CONDITION_DATA_OVERRUN:
|
||||
return B_DEV_DATA_OVERRUN;
|
||||
|
||||
case OHCI_TD_CONDITION_DATA_UNDERRUN:
|
||||
return B_DEV_DATA_UNDERRUN;
|
||||
|
||||
case OHCI_TD_CONDITION_BUFFER_OVERRUN:
|
||||
return B_DEV_FIFO_OVERRUN;
|
||||
|
||||
case OHCI_TD_CONDITION_BUFFER_UNDERRUN:
|
||||
return B_DEV_FIFO_UNDERRUN;
|
||||
|
||||
case OHCI_TD_CONDITION_NOT_ACCESSED:
|
||||
return B_DEV_PENDING;
|
||||
|
||||
case 0x0E:
|
||||
return B_DEV_TOO_LATE; // PSW: _NOT_ACCESSED
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@ -1882,7 +2515,7 @@ OHCI::_ReadReg(uint32 reg)
|
||||
void
|
||||
OHCI::_PrintEndpoint(ohci_endpoint_descriptor *endpoint)
|
||||
{
|
||||
TRACE_ALWAYS("endpoint %p\n", endpoint);
|
||||
dprintf("endpoint %p\n", endpoint);
|
||||
dprintf("\tflags........... 0x%08" B_PRIx32 "\n", endpoint->flags);
|
||||
dprintf("\ttail_physical... 0x%08" B_PRIx32 "\n", endpoint->tail_physical_descriptor);
|
||||
dprintf("\thead_physical... 0x%08" B_PRIx32 "\n", endpoint->head_physical_descriptor);
|
||||
@ -1897,7 +2530,7 @@ void
|
||||
OHCI::_PrintDescriptorChain(ohci_general_td *topDescriptor)
|
||||
{
|
||||
while (topDescriptor) {
|
||||
TRACE_ALWAYS("descriptor %p\n", topDescriptor);
|
||||
dprintf("descriptor %p\n", topDescriptor);
|
||||
dprintf("\tflags........... 0x%08" B_PRIx32 "\n", topDescriptor->flags);
|
||||
dprintf("\tbuffer_physical. 0x%08" B_PRIx32 "\n", topDescriptor->buffer_physical);
|
||||
dprintf("\tnext_physical... 0x%08" B_PRIx32 "\n", topDescriptor->next_physical_descriptor);
|
||||
@ -1910,3 +2543,30 @@ OHCI::_PrintDescriptorChain(ohci_general_td *topDescriptor)
|
||||
topDescriptor = (ohci_general_td *)topDescriptor->next_logical_descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
OHCI::_PrintDescriptorChain(ohci_isochronous_td *topDescriptor)
|
||||
{
|
||||
while (topDescriptor) {
|
||||
dprintf("iso.descriptor %p\n", topDescriptor);
|
||||
dprintf("\tflags........... 0x%08" B_PRIx32 "\n", topDescriptor->flags);
|
||||
dprintf("\tbuffer_pagebyte0 0x%08" B_PRIx32 "\n", topDescriptor->buffer_page_byte_0);
|
||||
dprintf("\tnext_physical... 0x%08" B_PRIx32 "\n", topDescriptor->next_physical_descriptor);
|
||||
dprintf("\tlast_byte....... 0x%08" B_PRIx32 "\n", topDescriptor->last_byte_address);
|
||||
dprintf("\toffset:\n\t0x%04x 0x%04x 0x%04x 0x%04x\n"
|
||||
"\t0x%04x 0x%04x 0x%04x 0x%04x\n",
|
||||
topDescriptor->offset[0], topDescriptor->offset[1],
|
||||
topDescriptor->offset[2], topDescriptor->offset[3],
|
||||
topDescriptor->offset[4], topDescriptor->offset[5],
|
||||
topDescriptor->offset[6], topDescriptor->offset[7]);
|
||||
dprintf("\tphysical........ 0x%08" B_PRIx32 "\n", topDescriptor->physical_address);
|
||||
dprintf("\tbuffer_size..... %lu\n", topDescriptor->buffer_size);
|
||||
dprintf("\tbuffer_logical.. %p\n", topDescriptor->buffer_logical);
|
||||
dprintf("\tnext_logical.... %p\n", topDescriptor->next_logical_descriptor);
|
||||
dprintf("\tnext_done....... %p\n", topDescriptor->next_done_descriptor);
|
||||
|
||||
topDescriptor = (ohci_isochronous_td *)topDescriptor->next_done_descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* Copyright 2005-2008, Haiku Inc. All rights reserved.
|
||||
* Copyright 2005-2013, Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Jan-Rixt Van Hoye
|
||||
* Salvatore Benedetto <salvatore.benedetto@gmail.com>
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* Siarzhuk Zharski <imker@gmx.li>
|
||||
*/
|
||||
#ifndef OHCI_H
|
||||
#define OHCI_H
|
||||
@ -69,12 +70,20 @@ static int32 _InterruptHandler(void *data);
|
||||
ohci_general_td *dataDescriptor,
|
||||
ohci_general_td *lastDescriptor,
|
||||
bool directionIn);
|
||||
status_t _CancelQueuedIsochronousTransfers(
|
||||
Pipe *pipe, bool force);
|
||||
status_t _AddPendingIsochronousTransfer(
|
||||
Transfer *transfer,
|
||||
ohci_endpoint_descriptor *endpoint,
|
||||
ohci_isochronous_td *firstDescriptor,
|
||||
ohci_isochronous_td *lastDescriptor,
|
||||
bool directionIn);
|
||||
|
||||
status_t _UnlinkTransfer(transfer_data *transfer);
|
||||
|
||||
static int32 _FinishThread(void *data);
|
||||
void _FinishTransfers();
|
||||
bool _FinishIsochronousTransfer(
|
||||
transfer_data *transfer,
|
||||
transfer_data **_lastTransfer);
|
||||
|
||||
status_t _SubmitRequest(Transfer *transfer);
|
||||
status_t _SubmitTransfer(Transfer *transfer);
|
||||
@ -85,6 +94,11 @@ static int32 _FinishThread(void *data);
|
||||
ohci_endpoint_descriptor *endpoint,
|
||||
ohci_general_td *first,
|
||||
ohci_general_td *last);
|
||||
void _SwitchIsochronousEndpointTail(
|
||||
ohci_endpoint_descriptor *endpoint,
|
||||
ohci_isochronous_td *first,
|
||||
ohci_isochronous_td *last);
|
||||
|
||||
void _RemoveTransferFromEndpoint(
|
||||
transfer_data *transfer);
|
||||
|
||||
@ -101,7 +115,6 @@ static int32 _FinishThread(void *data);
|
||||
size_t bufferSize);
|
||||
void _FreeGeneralDescriptor(
|
||||
ohci_general_td *descriptor);
|
||||
|
||||
status_t _CreateDescriptorChain(
|
||||
ohci_general_td **firstDescriptor,
|
||||
ohci_general_td **lastDescriptor,
|
||||
@ -110,22 +123,48 @@ static int32 _FinishThread(void *data);
|
||||
void _FreeDescriptorChain(
|
||||
ohci_general_td *topDescriptor);
|
||||
|
||||
ohci_isochronous_td * _CreateIsochronousDescriptor(
|
||||
size_t bufferSize);
|
||||
void _FreeIsochronousDescriptor(
|
||||
ohci_isochronous_td *descriptor);
|
||||
status_t _CreateIsochronousDescriptorChain(
|
||||
ohci_isochronous_td **firstDescriptor,
|
||||
ohci_isochronous_td **lastDescriptor,
|
||||
Transfer *transfer);
|
||||
void _FreeIsochronousDescriptorChain(
|
||||
ohci_isochronous_td *topDescriptor);
|
||||
|
||||
size_t _WriteDescriptorChain(
|
||||
ohci_general_td *topDescriptor,
|
||||
iovec *vector, size_t vectorCount);
|
||||
size_t _ReadDescriptorChain(
|
||||
ohci_general_td *topDescriptor,
|
||||
iovec *vector, size_t vectorCount);
|
||||
|
||||
size_t _WriteIsochronousDescriptorChain(
|
||||
ohci_isochronous_td *topDescriptor,
|
||||
iovec *vector, size_t vectorCount);
|
||||
void _ReadIsochronousDescriptorChain(
|
||||
ohci_isochronous_td *topDescriptor,
|
||||
iovec *vector, size_t vectorCount);
|
||||
|
||||
size_t _ReadActualLength(
|
||||
ohci_general_td *topDescriptor);
|
||||
|
||||
void _LinkDescriptors(ohci_general_td *first,
|
||||
ohci_general_td *second);
|
||||
void _LinkIsochronousDescriptors(
|
||||
ohci_isochronous_td *first,
|
||||
ohci_isochronous_td *second,
|
||||
ohci_isochronous_td *nextDone);
|
||||
|
||||
ohci_isochronous_td * _CreateIsochronousDescriptor();
|
||||
void _FreeIsochronousDescriptor(
|
||||
ohci_isochronous_td *descriptor);
|
||||
bool _AllocateIsochronousBandwidth(uint16 frame,
|
||||
uint16 size);
|
||||
void _ReleaseIsochronousBandwidth(
|
||||
uint16 startFrame, uint16 count);
|
||||
|
||||
status_t _GetStatusOfConditionCode(
|
||||
uint8 conditionCode);
|
||||
// Private locking
|
||||
bool _LockEndpoints();
|
||||
void _UnlockEndpoints();
|
||||
@ -139,6 +178,8 @@ inline uint32 _ReadReg(uint32 reg);
|
||||
ohci_endpoint_descriptor *endpoint);
|
||||
void _PrintDescriptorChain(
|
||||
ohci_general_td *topDescriptor);
|
||||
void _PrintDescriptorChain(
|
||||
ohci_isochronous_td *topDescriptor);
|
||||
|
||||
static pci_module_info * sPCIModule;
|
||||
static pci_x86_module_info * sPCIx86Module;
|
||||
@ -167,6 +208,8 @@ static pci_x86_module_info * sPCIx86Module;
|
||||
thread_id fFinishThread;
|
||||
bool fStopFinishThread;
|
||||
Pipe * fProcessingPipe;
|
||||
// frame bandwidth watchdogs array
|
||||
uint16 * fFrameBandwidth;
|
||||
|
||||
// Root Hub
|
||||
OHCIRootHub * fRootHub;
|
||||
|
@ -12,6 +12,6 @@ resource app_version {
|
||||
variety = 0,
|
||||
internal = 0,
|
||||
short_info = "OHCI host controller driver",
|
||||
long_info = "Haiku OHCI HCD - Copyright 2005-2009, Haiku Inc."
|
||||
long_info = "Haiku OHCI HCD - Copyright 2005-2013, Haiku Inc."
|
||||
};
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* Copyright 2005-2008, Haiku Inc. All rights reserved.
|
||||
* Copyright 2005-2013, Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Jan-Rixt Van Hoye
|
||||
* Salvatore Benedetto <salvatore.benedetto@gmail.com>
|
||||
* Michael Lotz <mmlr@mlotz.ch>
|
||||
* Siarzhuk Zharski <imker@gmx.li>
|
||||
*/
|
||||
|
||||
#ifndef OHCI_HARDWARE_H
|
||||
@ -396,6 +397,8 @@ typedef struct {
|
||||
uint16 offset[OHCI_ITD_NOFFSET]; // Buffer offsets
|
||||
// Software part
|
||||
uint32 physical_address; // Physical address of this descriptor
|
||||
size_t buffer_size; // Size of the buffer
|
||||
void *buffer_logical; // Logical pointer to the buffer
|
||||
void *next_logical_descriptor; // Logical pointer next descriptor
|
||||
void *next_done_descriptor; // Used for collision in the hash table
|
||||
} ohci_isochronous_td;
|
||||
@ -404,11 +407,31 @@ typedef struct {
|
||||
#define OHCI_ITD_SET_STARTING_FRAME(x) ((x) & 0xffff)
|
||||
#define OHCI_ITD_GET_DELAY_INTERRUPT(x) (((x) >> 21) & 7)
|
||||
#define OHCI_ITD_SET_DELAY_INTERRUPT(x) ((x) << 21)
|
||||
#define OHCI_ITD_NO_INTERRUPT 0x00e00000
|
||||
#define OHCI_ITD_INTERRUPT_MASK 0x00e00000
|
||||
#define OHCI_ITD_GET_FRAME_COUNT(x) ((((x) >> 24) & 7) + 1)
|
||||
#define OHCI_ITD_SET_FRAME_COUNT(x) (((x) - 1) << 24)
|
||||
#define OHCI_ITD_GET_CONDITION_CODE(x) ((x) >> 28)
|
||||
#define OHCI_ITD_NO_CONDITION_CODE 0xf0000000
|
||||
#define OHCI_ITD_SET_CONDITION_CODE(x) ((x) << 28)
|
||||
#define OHCI_ITD_CONDITION_CODE_MASK 0xf0000000
|
||||
|
||||
#define OHCI_ITD_OFFSET_IDX(x) (x)
|
||||
|
||||
#define OHCI_ITD_INTERRUPT_IMMEDIATE 0x00
|
||||
#define OHCI_ITD_INTERRUPT_NONE 0x07
|
||||
|
||||
#define OHCI_ITD_CONDITION_NO_ERROR 0x00
|
||||
#define OHCI_ITD_CONDITION_CRC_ERROR 0x01
|
||||
#define OHCI_ITD_CONDITION_BIT_STUFFING 0x02
|
||||
#define OHCI_ITD_CONDITION_TOGGLE_MISMATCH 0x03
|
||||
#define OHCI_ITD_CONDITION_STALL 0x04
|
||||
#define OHCI_ITD_CONDITION_NO_RESPONSE 0x05
|
||||
#define OHCI_ITD_CONDITION_PID_CHECK_FAILURE 0x06
|
||||
#define OHCI_ITD_CONDITION_UNEXPECTED_PID 0x07
|
||||
#define OHCI_ITD_CONDITION_DATA_OVERRUN 0x08
|
||||
#define OHCI_ITD_CONDITION_DATA_UNDERRUN 0x09
|
||||
#define OHCI_ITD_CONDITION_BUFFER_OVERRUN 0x0c
|
||||
#define OHCI_ITD_CONDITION_BUFFER_UNDERRUN 0x0d
|
||||
#define OHCI_ITD_CONDITION_NOT_ACCESSED 0x0f
|
||||
|
||||
// TO FIX
|
||||
#define itd_pswn itd_offset // Packet Status Word
|
||||
@ -419,6 +442,10 @@ typedef struct {
|
||||
|
||||
#define OHCI_ISOCHRONOUS_TD_ALIGN 32
|
||||
|
||||
// Number of frames
|
||||
#define NUMBER_OF_FRAMES 1024
|
||||
#define MAX_AVAILABLE_BANDWIDTH 900 // Microseconds
|
||||
|
||||
// --------------------------------
|
||||
// Completion Codes (section 4.3.3)
|
||||
// --------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user