AppleUSBEHCI_UIM.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include <IOKit/platform/ApplePlatformExpert.h>
#include <IOKit/IOMemoryDescriptor.h>
#include <IOKit/IOMemoryCursor.h>
#include <IOKit/usb/IOUSBRootHubDevice.h>
#include <IOKit/usb/IOUSBLog.h>
#include "AppleUSBEHCI.h"
#include "USBTracepoints.h"
#if EHCI_USE_KPRINTF
#undef USBLog
#undef USBError
void kprintf(const char *format, ...)
__attribute__((format(printf, 1, 2)));
#define USBLog( LEVEL, FORMAT, ARGS... ) if ((LEVEL) <= EHCI_USE_KPRINTF) { kprintf( FORMAT "\n", ## ARGS ) ; }
#define USBError( LEVEL, FORMAT, ARGS... ) { kprintf( FORMAT "\n", ## ARGS ) ; }
#endif
#define super IOUSBControllerV3
static IOReturn TranslateStatusToUSBError(UInt32 status);
#pragma mark General
AppleEHCIQueueHead *
AppleUSBEHCI::MakeEmptyEndPoint(
UInt8 functionAddress,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed,
USBDeviceAddress highSpeedHub,
int highSpeedPort,
UInt8 direction)
{
UInt32 myFunctionAddress;
UInt32 myEndPointNumber;
UInt32 myMaxPacketSize, multiple;
UInt32 mySpeed = 0;
AppleEHCIQueueHead * pED;
EHCIGeneralTransferDescriptorPtr pTD;
USBLog(7, "AppleUSBEHCI[%p]::MakeEmptyEndPoint - Addr: %d, EPT#: %d, MPS: %d, speed: %d, hubAddr: %d, hubPort: %d, dir: %d", this,
functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort, direction);
if ( (highSpeedHub == 0) && (speed != kUSBDeviceSpeedHigh) )
{
USBLog(1, "AppleUSBEHCI[%p]::MakeEmptyEndPoint - new endpoint NOT fixing up speed", this);
USBTrace( kUSBTEHCI, kTPEHCIMakeEmptyEndPoint , functionAddress, endpointNumber, speed, 1 );
}
pED = FindControlBulkEndpoint(functionAddress, endpointNumber, NULL, direction);
if (pED != NULL)
{
USBLog(1, "AppleUSBEHCI[%p]::MakeEmptyEndPoint - old endpoint found, abusing %p", this, pED);
USBTrace( kUSBTEHCI, kTPEHCIMakeEmptyEndPoint , functionAddress, endpointNumber, speed, 2 );
pED->GetSharedLogical()->flags = 0xffffffff;
}
pED = AllocateQH();
if (pED == NULL)
return NULL;
USBLog(7, "AppleUSBEHCI[%p]::MakeEmptyEndPoint - new endpoint %p", this, pED);
myFunctionAddress = ((UInt32) functionAddress) << kEHCIEDFlags_FAPhase;
myEndPointNumber = ((UInt32) endpointNumber) << kEHCIEDFlags_ENPhase;
if (speed == kUSBDeviceSpeedFull)
{
mySpeed = 0;
}
else if (speed == kUSBDeviceSpeedLow)
{
mySpeed = 1 << kEHCIEDFlags_SPhase;
}
else if (speed == kUSBDeviceSpeedHigh)
{
mySpeed = 2 << kEHCIEDFlags_SPhase;
}
USBLog(7, "AppleUSBEHCI[%p]::MakeEmptyEndPoint - mySpeed %d", this, (uint32_t)mySpeed);
if( maxPacketSize > 1024 )
{
multiple = ((maxPacketSize-1)/1024)+1;
UInt32 oneMp = (maxPacketSize+(multiple-1))/multiple;
myMaxPacketSize = oneMp << kEHCIEDFlags_MPSPhase;
}
else
{
multiple = 1;
myMaxPacketSize = ((UInt32) maxPacketSize) << kEHCIEDFlags_MPSPhase;
}
pED->_direction = direction;
pED->_functionNumber = functionAddress;
pED->_endpointNumber = endpointNumber;
pED->_speed = speed;
USBLog(7, "AppleUSBEHCI[%p]::MakeEmptyEndPoint - MPS = %d, setting flags to 0x%x", this, maxPacketSize, (uint32_t)(myFunctionAddress | myEndPointNumber | myMaxPacketSize | mySpeed));
pED->GetSharedLogical()->flags = HostToUSBLong(myFunctionAddress | myEndPointNumber | myMaxPacketSize | mySpeed);
pED->GetSharedLogical()->splitFlags = HostToUSBLong( (multiple << kEHCIEDSplitFlags_MultPhase) | (highSpeedHub << kEHCIEDSplitFlags_HubAddrPhase)
| (highSpeedPort << kEHCIEDSplitFlags_PortPhase) );
pED->GetSharedLogical()->CurrqTDPtr = 0;
pED->GetSharedLogical()->AltqTDPtr = HostToUSBLong(kEHCITermFlag); pED->GetSharedLogical()->qTDFlags = 0; pED->GetSharedLogical()->BuffPtr[0] = 0;
pED->GetSharedLogical()->BuffPtr[1] = 0;
pED->GetSharedLogical()->BuffPtr[2] = 0;
pED->GetSharedLogical()->BuffPtr[3] = 0;
pED->GetSharedLogical()->BuffPtr[4] = 0;
pED->GetSharedLogical()->extBuffPtr[0] = 0;
pED->GetSharedLogical()->extBuffPtr[1] = 0;
pED->GetSharedLogical()->extBuffPtr[2] = 0;
pED->GetSharedLogical()->extBuffPtr[3] = 0;
pED->GetSharedLogical()->extBuffPtr[4] = 0;
pTD = AllocateTD(); pTD->pShared->flags = 0; pTD->pShared->nextTD = HostToUSBLong(kEHCITermFlag);
pTD->pShared->altTD = HostToUSBLong(kEHCITermFlag);
pTD->command = NULL;
USBLog(7, "AppleUSBEHCI[%p]::MakeEmptyEndPoint - pointing NextqTDPtr to %x", this, (uint32_t)pTD->pPhysical);
pED->GetSharedLogical()->NextqTDPtr = HostToUSBLong( (UInt32)pTD->pPhysical & ~0x1F);
pED->_qTD = pTD;
pED->_TailTD = pED->_qTD;
pED->_numTDs = 1;
pED->_responseToStall = 0;
pED->_inactiveTD = 0;
return pED;
}
IOReturn
AppleUSBEHCI::UIMAbortEndpoint(short functionAddress, short endpointNumber, short direction)
{
return HandleEndpointAbort(functionAddress, endpointNumber, direction, false);
}
IOReturn
AppleUSBEHCI::UIMClearEndpointStall(short functionAddress, short endpointNumber, short direction)
{
USBLog(7, "AppleUSBEHCI[%p]::UIMClearEndpointStall - endpoint %d:%d", this, functionAddress, endpointNumber);
return HandleEndpointAbort(functionAddress, endpointNumber, direction, true);
}
IOReturn
AppleUSBEHCI::UIMDeleteEndpoint(short functionAddress, short endpointNumber, short direction)
{
AppleEHCIQueueHead *pED;
AppleEHCIQueueHead *pEDQueueBack;
AppleEHCIIsochEndpoint *piEP;
USBLog(7, "AppleUSBEHCI[%p] AppleUSBEHCI::UIMDeleteEndpoint: Addr: %d, Endpoint: %d,%d", this, functionAddress,endpointNumber,direction);
if (functionAddress == _rootHubFuncAddress)
{
if ( (endpointNumber != 1) && (endpointNumber != 0) )
{
USBLog(1, "AppleUSBEHCI[%p]::UIMDeleteEndpoint: bad params - endpNumber: %d", this, endpointNumber );
USBTrace( kUSBTEHCI, kTPEHCIDeleteEndpoint, functionAddress, endpointNumber, direction, kIOReturnBadArgument );
return kIOReturnBadArgument;
}
USBLog(5, "AppleUSBEHCI[%p]::UIMDeleteEndpoint: Attempting operation on root hub", this);
return SimulateEDDelete( endpointNumber, direction);
}
piEP = OSDynamicCast(AppleEHCIIsochEndpoint, FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL));
if (piEP)
{
USBLog(5, "AppleUSBEHCI[%p]::UIMDeleteEndpoint: deleting Isoch endpoint(%p)", this, piEP);
return DeleteIsochEP(piEP);
}
pED = FindControlBulkEndpoint (functionAddress, endpointNumber, &pEDQueueBack, direction);
if(pED == NULL)
{
pED = FindInterruptEndpoint(functionAddress, endpointNumber, direction, NULL);
if(pED == NULL)
{
USBLog(5, "AppleUSBEHCI[%p]::UIMDeleteEndpoint, endpoint not found", this);
return kIOUSBEndpointNotFound;
}
USBLog(5, "AppleUSBEHCI[%p]::UIMDeleteEndpoint: deleting Int endpoint(%p)", this, pED);
unlinkIntEndpoint(pED);
ReturnInterruptBandwidth(pED);
}
else
{
USBLog(5, "AppleUSBEHCI[%p]::UIMDeleteEndpoint: unlinking async endpoint", this);
unlinkAsyncEndpoint(pED, pEDQueueBack);
}
if(pED->_qTD != pED->_TailTD) {
USBLog(5, "AppleUSBEHCI[%p]::UIMDeleteEndpoint: removing TDs", this);
EHCIUIMDoDoneQueueProcessing(pED->_qTD, kIOUSBTransactionReturned, NULL, pED->_TailTD);
pED->_qTD = pED->_TailTD;
pED->GetSharedLogical()->NextqTDPtr = HostToUSBLong(pED->_qTD->pPhysical);
IOSync();
}
if ( pED->_qTD != NULL )
{
USBLog(6, "AppleUSBEHCI[%p]::UIMDeleteEndpoint - deallocating the dummy TD", this);
DeallocateTD(pED->_qTD);
pED->_qTD = NULL;
}
USBLog(5, "AppleUSBEHCI[%p]::UIMDeleteEndpoint: Deallocating %p", this, pED);
DeallocateED(pED);
return kIOReturnSuccess;
}
#define GET_NEXT_BUFFPTR() \
do { \
offset = transferOffset; \
numSegments = 1; \
status = dmaCommand->gen64IOVMSegments(&offset, &segments, &numSegments); \
dmaAddrHighBits = (UInt32)(segments.fIOVMAddr >> 32); \
if (status || (numSegments != 1) || (dmaAddrHighBits && !_is64bit)) \
{ \
USBError(1, "AppleUSBEHCI[%p]::CreateHSIsochTransfer - could not generate segments err (%p) numSegments (%d) fLength (%d)", this, (void*)status, (int)numSegments, (int)segments.fLength); \
status = status ? status : kIOReturnInternalError; \
dmaStartAddr = 0; \
segLen = 0; \
return kIOReturnInternalError; \
} \
else \
{ \
dmaStartAddr = segments.fIOVMAddr; \
segLen = segments.fLength; \
} \
} while (0)
#define ADJUST_SEGMENT_LENGTH(OFFSET) \
do { \
if(segLen > bufferSize) \
{ \
segLen = bufferSize; \
} \
if(segLen > (kEHCIPageSize-OFFSET)) \
{ \
segLen = kEHCIPageSize-OFFSET; \
} \
} while (0)
#pragma mark ControlBulkCommon
AppleEHCIQueueHead *
AppleUSBEHCI::AddEmptyCBEndPoint(UInt8 functionAddress,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed,
USBDeviceAddress highSpeedHub,
int highSpeedPort,
UInt8 direction)
{
AppleEHCIQueueHead * CBED;
UInt32 cFlag;
UInt32 myDataToggleCntrl;
UInt32 myRL = 0;
USBLog(7, "AppleUSBEHCI[%p]::AddEmptyCBEndPoint speed %d @(%d, %d)", this, speed, highSpeedHub, highSpeedPort);
CBED = MakeEmptyEndPoint(functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort, direction);
if (CBED == NULL)
return(NULL);
cFlag = 0;
if (kEHCIEDDirectionTD == direction)
{
myDataToggleCntrl = 1 << kEHCIEDFlags_DTCPhase;
if (speed != kUSBDeviceSpeedHigh)
{
cFlag = 1 << kEHCIEDFlags_CPhase;
}
}
else
{
myDataToggleCntrl = 0;
}
if (_errataBits & kErrataEHCIUseRLvalue)
{
myRL = gEHCIRLvalue << kEHCIEDFlags_RLPhase;
}
CBED->GetSharedLogical()->flags |= HostToUSBLong(myDataToggleCntrl | cFlag | myRL);
linkAsyncEndpoint(CBED);
return CBED;
}
void AppleUSBEHCI::checkHeads(void)
{
#if defined(DONT_CHECK_UIM_QHS)
AppleEHCIQueueHead * pEDQueue;
EHCIQueueHeadShared * pQH;
pEDQueue = _AsyncHead;
if(pEDQueue == NULL)
{
return;
}
pQH = pEDQueue->GetSharedLogical();
if( (pQH->flags & kEHCIEDFlags_H) == 0)
{
USBLog(3, "AppleUSBEHCI[%p]::checkHeads ********** Head with no H bit: %lx", this, (long)pEDQueue);
}
pEDQueue = OSDynamicCast(AppleEHCIQueueHead, pEDQueue->_logicalNext);
while(pEDQueue != NULL)
{
pQH = pEDQueue->GetSharedLogical();
if( (pQH->flags & kEHCIEDFlags_H) != 0)
{
USBLog(3, "AppleUSBEHCI[%p]::checkHeads @@@@@@@@@@@ not Head with H bit: %lx", this, (long)pEDQueue);
}
pEDQueue = OSDynamicCast(AppleEHCIQueueHead, pEDQueue->_logicalNext);
}
#endif
}
AppleEHCIQueueHead *
AppleUSBEHCI::FindControlBulkEndpoint( short functionNumber,
short endpointNumber,
AppleEHCIQueueHead **pEDBack,
short direction)
{
UInt32 unique;
AppleEHCIQueueHead * pEDQueue;
AppleEHCIQueueHead * pEDQueueNext;
AppleEHCIQueueHead * pEDQueueBack;
EHCIQueueHeadShared * pQH;
short EDDirection;
unique = (UInt32) ((((UInt32) endpointNumber) << kEHCIEDFlags_ENPhase) | ((UInt32) functionNumber));
pEDQueue = _AsyncHead;
pEDQueueBack = NULL;
if(pEDQueue == NULL)
{
USBLog(7, "AppleUSBEHCI[%p]::FindControlBulkEndpoint - Active queue is empty", this);
}
else
{
if (!_pEHCIRegisters->AsyncListAddr && !_wakingFromHibernation)
{
USBLog(1, "AppleUSBEHCI[%p]::FindControlBulkEndpoint.. AsyncListAddr is NULL but _AsyncHead(L:%p, P:%08x) is not!!", this, _AsyncHead->GetSharedLogical(), (int)_AsyncHead->_sharedPhysical);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
panic("FindControlBulkEndpoint\n");
#endif
}
}
while (pEDQueue != NULL)
{
pEDQueueNext = OSDynamicCast(AppleEHCIQueueHead, pEDQueue->_logicalNext); EDDirection = pEDQueue->_direction;
pQH = pEDQueue->GetSharedLogical();
if( ( (USBToHostLong(pQH->flags) & kEHCIUniqueNumNoDirMask) == unique) && ( ((EDDirection == kEHCIEDDirectionTD) || (EDDirection) == direction)) )
{
if (pEDBack)
*pEDBack = pEDQueueBack;
checkHeads();
return pEDQueue;
}
else
{
pEDQueueBack = pEDQueue;
}
pEDQueue = pEDQueueNext;
}
pEDQueue = _InactiveAsyncHead;
if(pEDQueue == NULL)
{
checkHeads();
USBLog(7, "AppleUSBEHCI[%p]::FindControlBulkEndpoint - InactiveQueue is NULL", this);
return NULL;
}
pEDQueueBack = NULL;
do {
EDDirection = pEDQueue->_direction;
pQH = pEDQueue->GetSharedLogical();
if( ( (USBToHostLong(pQH->flags) & kEHCIUniqueNumNoDirMask) == unique) && ( ((EDDirection == kEHCIEDDirectionTD) || (EDDirection) == direction)) )
{
if(pEDQueueBack == NULL)
{
_InactiveAsyncHead = OSDynamicCast(AppleEHCIQueueHead, pEDQueue->_logicalNext);
}
else
{
pEDQueueBack->_logicalNext = pEDQueue->_logicalNext;
}
USBLog(5, "AppleUSBEHCI[%p]::FindControlBulkEndpoint (inactive) - linking to active list: %lx", this, (long)pEDQueue);
linkAsyncEndpoint(pEDQueue);
if (!_pEHCIRegisters->AsyncListAddr && !_wakingFromHibernation)
{
USBLog(1, "AppleUSBEHCI[%p]::FindControlBulkEndpoint.. AsyncListAddr is NULL after linkAsyncEndpoint!!", this);
}
if(pEDBack != NULL)
{
if(pEDQueue == _AsyncHead)
{
*pEDBack = NULL;
}
else
{
pEDQueueBack = _AsyncHead;
while(pEDQueueBack != NULL)
{
pEDQueueNext = OSDynamicCast(AppleEHCIQueueHead, pEDQueueBack->_logicalNext);
if(pEDQueueNext == pEDQueue)
{
break;
}
pEDQueueBack = pEDQueueNext;
}
*pEDBack = pEDQueueBack;
}
}
checkHeads();
return pEDQueue;
}
else
{
}
pEDQueueBack = pEDQueue;
pEDQueue = OSDynamicCast(AppleEHCIQueueHead, pEDQueue->_logicalNext);
} while (pEDQueue != NULL);
checkHeads();
return NULL;
}
#pragma mark Control
IOReturn
AppleUSBEHCI::UIMCreateControlEndpoint(UInt8 functionAddress, UInt8 endpointNumber, UInt16 maxPacketSize, UInt8 speed)
{
#pragma unused (functionAddress, endpointNumber, maxPacketSize, speed)
IOLog("EHCIUIM -- UIMCreateControlEndpoint old version called with no split params\n");
return(kIOReturnInternalError);
}
IOReturn
AppleUSBEHCI::UIMCreateControlTransfer(short functionAddress,
short endpointNumber,
IOUSBCommand* command,
void* CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
#pragma unused (functionAddress, endpointNumber, command, CBP, bufferRounding, bufferSize, direction)
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateControlTransfer- calling the wrong method (buffer)!", this);
return kIOReturnIPCError;
}
IOReturn
AppleUSBEHCI::UIMCreateControlTransfer(short functionAddress,
short endpointNumber,
IOUSBCompletion completion,
IOMemoryDescriptor* CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
#pragma unused (functionAddress, endpointNumber, completion, CBP, bufferRounding, bufferSize, direction)
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateControlTransfer- calling the wrong method!", this);
return kIOReturnIPCError;
}
IOReturn
AppleUSBEHCI::UIMCreateControlEndpoint(UInt8 functionAddress, UInt8 endpointNumber, UInt16 maxPacketSize, UInt8 speed,
USBDeviceAddress highSpeedHub, int highSpeedPort)
{
AppleEHCIQueueHead *pEP;
USBLog(3, "AppleUSBEHCI[%p]::UIMCreateControlEndpoint(%d, %d, %d, %d @(%d, %d))", this,
functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort);
if (_rootHubFuncAddress == functionAddress)
{
return(kIOReturnSuccess);
}
if( (speed == kUSBDeviceSpeedLow) && (maxPacketSize > 8) )
{
if(functionAddress != 0)
{
USBError(1, "AppleUSBEHCI[%p]::UIMCreateControlEndpoint - incorrect max packet size (%d) for low speed", this, maxPacketSize);
return kIOReturnBadArgument;
}
USBLog(3, "AppleUSBEHCI[%p]::UIMCreateControlEndpoint - changing low speed max packet from %d to 8 for dev 0", this, maxPacketSize);
maxPacketSize = 8;
}
pEP = AddEmptyCBEndPoint(functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort, kEHCIEDDirectionTD);
if (!pEP)
{
USBError(1, "AppleUSBEHCI[%p]::UIMCreateControlEndpoint - could not add empty endpoint", this);
return kIOReturnNoResources;
}
pEP->_queueType = kEHCITypeControl;
printAsyncQueue(7, "UIMCreateControlEndpoint", true, false);
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::UIMCreateControlTransfer(short functionAddress,
short endpointNumber,
IOUSBCompletion completion,
void* CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
#pragma unused (functionAddress, endpointNumber, completion, CBP, bufferRounding, bufferSize, direction)
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateControlTransfer- calling the wrong method!", this);
return kIOReturnIPCError;
}
IOReturn
AppleUSBEHCI::UIMCreateControlTransfer(short functionAddress,
short endpointNumber,
IOUSBCommand* command,
IOMemoryDescriptor* CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
AppleEHCIQueueHead * pEDQueue;
IOReturn status;
IOUSBCompletion completion = command->GetUSLCompletion();
USBLog(7, "AppleUSBEHCI[%p]::UIMCreateControlTransfer adr=%d:%d cbp=%p:%x br=%s cback=[%p:%p] dir=%d)",
this, functionAddress, endpointNumber, CBP, (uint32_t)bufferSize,
bufferRounding ? "YES":"NO", completion.target, completion.parameter, direction);
pEDQueue = FindControlBulkEndpoint(functionAddress, endpointNumber, NULL, kEHCIEDDirectionTD);
USBLog(7, "AppleUSBEHCI[%p]::UIMCreateControlTransfer -- found endpoint at %p", this, pEDQueue);
if (pEDQueue == NULL)
{
USBLog(3, "AppleUSBEHCI[%p]::UIMCreateControlTransfer- Could not find endpoint!", this);
return kIOUSBEndpointNotFound;
}
status = allocateTDs(pEDQueue, command, CBP, bufferSize, direction, true);
if (status == kIOReturnSuccess)
{
USBLog(7, "AppleUSBEHCI[%p]::UIMCreateControlTransfer allocateTDS done - CMD = 0x%x, STS = 0x%x", this, USBToHostLong(_pEHCIRegisters->USBCMD), USBToHostLong(_pEHCIRegisters->USBSTS));
printAsyncQueue(7, "UIMCreateControlTransfer", true, false);
EnableAsyncSchedule(false);
}
else
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateControlTransfer (adr=%d:%d) - allocateTDs returned error %x", this, functionAddress, endpointNumber, status);
}
return status;
}
#pragma mark AllocateTDs
IOReturn
AppleUSBEHCI::allocateTDs(AppleEHCIQueueHead* pEDQueue, IOUSBCommand *command, IOMemoryDescriptor* CBP, UInt32 bufferSize, UInt16 direction, Boolean controlTransaction)
{
EHCIGeneralTransferDescriptorPtr pTD1, pTD, pTDnew, pTDLast;
UInt32 myToggle = 0;
UInt32 myCerr = (3 << kEHCITDFlags_CerrPhase);
UInt32 debugRetryCount = 0;
UInt32 myDirection = 0;
IOByteCount transferOffset;
UInt32 pageCount;
UInt32 flags;
IOReturn status = kIOReturnSuccess;
UInt32 maxPacket;
UInt32 bytesThisTD, segment;
UInt32 curTDsegment;
UInt32 totalPhysLength;
IOPhysicalAddress dmaStartAddr;
UInt32 dmaStartOffset;
UInt32 dmaAddrHighBits;
UInt32 bytesToSchedule;
bool needNewTD = false;
UInt32 maxTDLength;
UInt16 endpoint;
IODMACommand *dmaCommand = command->GetDMACommand();
UInt64 offset;
IODMACommand::Segment64 segments;
UInt32 numSegments;
if (controlTransaction)
{
myToggle = 0; if (direction != kEHCIEDDirectionTD)
{ myToggle |= kEHCITDFlags_DT; }
}
myDirection = (UInt32) direction << kEHCITDFlags_PIDPhase;
maxPacket = (USBToHostLong(pEDQueue->GetSharedLogical()->flags) & kEHCIEDFlags_MPS) >> kEHCIEDFlags_MPSPhase;
endpoint = (USBToHostLong(pEDQueue->GetSharedLogical()->flags) & kEHCIEDFlags_EN) >> kEHCIEDFlags_ENPhase;
if ( controlTransaction && maxPacket == 0 )
{
USBLog(1, "AppleUSBEHCI[%p]::allocateTDs - maxPacket for control endpoint (%d) was 0! - returning kIOReturnNotPermitted", this, endpoint);
USBTrace( kUSBTEHCI, kTPEHCIAllocateTDs , (uintptr_t)this, endpoint, kIOReturnNotPermitted, 0);
return kIOReturnNotPermitted;
}
if ((USBToHostLong(pEDQueue->GetSharedLogical()->qTDFlags) & kEHCITDStatus_Halted) && !(controlTransaction && (endpoint == 0)))
{
USBLog(3, "AppleUSBEHCI[%p]::allocateTDs - queue for endpoint (%d) halted - returning kIOUSBPipeStalled", this, endpoint);
return kIOUSBPipeStalled;
}
pTD1 = AllocateTD();
pEDQueue->_numTDs++;
if (pTD1 == NULL)
{
USBError(1, "AppleUSBEHCI[%p]::allocateTDs can't allocate 1st new TD", this);
return kIOReturnNoMemory;
}
pTD = pTD1;
if (CBP && bufferSize)
{
if (!dmaCommand)
{
USBError(1, "AppleUSBEHCI[%p]::allocateTDs - no dmaCommand", this);
DeallocateTD(pTD);
pEDQueue->_numTDs--;
return kIOReturnNoMemory;
}
if (dmaCommand->getMemoryDescriptor() != CBP)
{
USBError(1, "AppleUSBEHCI[%p]::allocateTDs - mismatched CBP (%p) and dmaCommand memory descriptor (%p)", this, CBP, dmaCommand->getMemoryDescriptor());
DeallocateTD(pTD);
pEDQueue->_numTDs--;
return kIOReturnInternalError;
}
}
debugRetryCount = ((gUSBStackDebugFlags & kUSBDebugRetryCountMask) >> kUSBDebugRetryCountShift);
if (debugRetryCount and (debugRetryCount < 3))
{
USBLog(7, "AppleUSBEHCI[%p]::allocateTDs - using retryCount of %d", this, (int)debugRetryCount);
myCerr = debugRetryCount << kEHCITDFlags_CerrPhase;
}
if (bufferSize != 0)
{
transferOffset = 0;
curTDsegment = 0;
bytesThisTD = 0;
while (transferOffset < bufferSize)
{
offset = transferOffset;
numSegments = 1;
status = dmaCommand->gen64IOVMSegments(&offset, &segments, &numSegments);
dmaAddrHighBits = (UInt32)(segments.fIOVMAddr >> 32);
if (status || (numSegments != 1) || (dmaAddrHighBits && !_is64bit))
{
USBError(1, "AppleUSBEHCI[%p]::allocateTDs - could not generate segments err (%p) numSegments (%d) fLength (%d)", this, (void*)status, (int)numSegments, (int)segments.fLength);
status = status ? status : kIOReturnInternalError;
dmaStartAddr = 0;
totalPhysLength = 0;
return kIOReturnInternalError;
}
else
{
dmaStartAddr = segments.fIOVMAddr;
totalPhysLength = segments.fLength;
}
USBLog(7, "AppleUSBEHCI[%p]::allocateTDs - gen64IOVMSegments returned length of %d (out of %d) and start of %p:%p", this, (uint32_t)totalPhysLength, (uint32_t)bufferSize, (void*)dmaAddrHighBits, (void*)dmaStartAddr);
dmaStartOffset = (dmaStartAddr & (kEHCIPageSize-1));
bytesToSchedule = 0;
if ((curTDsegment == 0) || (dmaStartOffset == 0))
{
needNewTD = false;
if (totalPhysLength > bufferSize)
{
USBLog(5, "AppleUSBEHCI[%p]::allocateTDs - segment physical length (%d) > buffer size(%d) - truncating", this, (uint32_t)totalPhysLength, (uint32_t)bufferSize);
totalPhysLength = bufferSize;
}
maxTDLength = ((kEHCIPagesPerTD-curTDsegment) * kEHCIPageSize) - dmaStartOffset;
if (totalPhysLength > maxTDLength)
{
if ((curTDsegment == 0) && (dmaStartOffset != 0))
{
USBLog(7, "AppleUSBEHCI[%p]::allocateTDs - segment won't fit - using 4 pages for this TD", this);
bytesToSchedule = (kEHCIPagesPerTD-1) * kEHCIPageSize;
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::allocateTDs - segment is larger than 1 TD - using %d pages for this TD", this, (uint32_t)(kEHCIPagesPerTD - curTDsegment));
bytesToSchedule = (kEHCIPagesPerTD - curTDsegment) * kEHCIPageSize;
}
}
else
bytesToSchedule = totalPhysLength;
bytesThisTD += bytesToSchedule;
transferOffset += bytesToSchedule;
if( ((kEHCIPagesPerTD-1) == curTDsegment) && (maxPacket != 0) && ( (kEHCIPageSize%maxPacket) != 0) )
{
if(transferOffset < bufferSize)
{
UInt32 ovBytes;
ovBytes = bytesThisTD % maxPacket;
if(bytesToSchedule > ovBytes) {
bytesToSchedule -= ovBytes;
bytesThisTD -= ovBytes;
transferOffset -= ovBytes;
USBLog(7, "AppleUSBEHCI[%p]::allocateTDs - Adjusted for odd maxpacket: bytesToSchedule:%d, bytesThisTD:%d, transferOffset:%d, ovBytes:%d", this, (int)bytesToSchedule, (int)bytesThisTD, (int)transferOffset, (int)ovBytes);
}
}
}
if ( (transferOffset < bufferSize) && ((dmaStartOffset+bytesToSchedule) & kEHCIPageOffsetMask) )
{
USBLog(6, "AppleUSBEHCI[%p]::allocateTDs - non-last transfer didn't end at end of page (%d, %d)", this, (uint32_t)dmaStartOffset, (uint32_t)bytesToSchedule);
needNewTD = true;
}
while (bytesToSchedule)
{
pTD->pShared->extBuffPtr[curTDsegment] = HostToUSBLong(dmaAddrHighBits);
pTD->pShared->BuffPtr[curTDsegment++] = HostToUSBLong(dmaStartAddr);
dmaStartAddr += (kEHCIPageSize - dmaStartOffset);
if (_is64bit && (dmaStartAddr == 0))
dmaAddrHighBits++;
if (bytesToSchedule > (kEHCIPageSize - dmaStartOffset))
bytesToSchedule -= (kEHCIPageSize - dmaStartOffset);
else
bytesToSchedule = 0;
dmaStartOffset = 0;
}
if ( ((curTDsegment < kEHCIPagesPerTD) && (transferOffset < bufferSize)) && !needNewTD )
{
USBLog(7, "AppleUSBEHCI[%p]::allocateTDs - didn't fill up this TD (segment %d) - going back for more", this, (uint32_t)curTDsegment);
continue;
}
}
flags = kEHCITDioc;
USBLog(7, "AppleUSBEHCI[%p]::allocateTDs - i have %d bytes in %d segments", this, (uint32_t)bytesThisTD, (uint32_t)curTDsegment);
for (segment = 0; segment < curTDsegment; segment++)
{
USBLog(7, "AppleUSBEHCI[%p]::allocateTDs - addr[%d]:0x%x", this, (uint32_t)segment, (uint32_t)USBToHostLong(pTD->pShared->BuffPtr[segment]));
}
flags |= (bytesThisTD << kEHCITDFlags_BytesPhase);
pTD->tdSize = bytesThisTD; pTD->flagsAtError = 0xffffffff; pTD->errCount = 0; pTD->pShared->altTD = HostToUSBLong(pTD1->pPhysical); flags |= myDirection | myToggle | kEHCITDStatus_Active | myCerr;
pTD->traceFlag = false;
pTD->pQH = pEDQueue;
if (controlTransaction)
{
int numPackets = (bytesToSchedule +maxPacket-1)/maxPacket;
if (numPackets&1)
{
myToggle = myToggle ? 0 : (UInt32)kEHCITDFlags_DT;
}
}
else
{
myToggle = 0;
}
USBLog(7, "AppleUSBEHCI[%p]::allocateTDs - putting command into TD (%p) on ED (%p)", this, pTD, pEDQueue);
pTD->command = command; if (transferOffset >= bufferSize)
{
pTD->callbackOnTD = true;
pTD->logicalBuffer = CBP;
pTD->pShared->flags = HostToUSBLong(flags);
pTD->multiXferTransaction = command->GetMultiTransferTransaction();
pTD->finalXferInTransaction = command->GetFinalTransferInTransaction();
if ((pEDQueue->_queueType == kEHCITypeControl) || (pEDQueue->_queueType == kEHCITypeBulk))
_controlBulkTransactionsOut++;
}
else
{
pTD->callbackOnTD = false;
pTDnew = AllocateTD();
if (pTDnew == NULL)
{
status = kIOReturnNoMemory;
USBError(1, "AppleUSBEHCI[%p]::allocateTDs can't allocate new TD", this);
}
else
{
pEDQueue->_numTDs++;
pTD->pShared->nextTD = HostToUSBLong(pTDnew->pPhysical);
pTD->pLogicalNext = pTDnew;
pTD->pShared->flags = HostToUSBLong(flags); pTD = pTDnew;
curTDsegment = 0;
bytesThisTD = 0;
USBLog(7, "AppleUSBEHCI[%p]::allocateTDs - got another TD - going to fill it up too (%d, %d)", this, (uint32_t)transferOffset, (uint32_t)bufferSize);
}
}
}
}
else
{
pTD->pShared->altTD = HostToUSBLong(pTD1->pPhysical); USBLog(7, "AppleUSBEHCI[%p]::allocateTDs - (no buffer)- putting command into TD (%p) on ED (%p)", this, pTD, pEDQueue);
pTD->command = command;
pTD->callbackOnTD = true;
pTD->multiXferTransaction = command->GetMultiTransferTransaction();
pTD->finalXferInTransaction = command->GetFinalTransferInTransaction();
if ((pEDQueue->_queueType == kEHCITypeControl) || (pEDQueue->_queueType == kEHCITypeBulk))
_controlBulkTransactionsOut++;
pTD->logicalBuffer = CBP;
pTD->traceFlag = false;
pTD->pQH = pEDQueue;
flags = kEHCITDioc | myDirection | myToggle | kEHCITDStatus_Active | myCerr;
pTD->pShared->flags = HostToUSBLong(flags);
}
pTDLast = pEDQueue->_TailTD;
pTD->pShared->nextTD = HostToUSBLong(pTD1->pPhysical);
pTD->pLogicalNext = pTD1;
flags = pTD1->pShared->flags;
pTD1->pShared->flags = 0;
pTDLast->pShared->nextTD = pTD1->pShared->nextTD;
pTDLast->pShared->altTD = pTD1->pShared->altTD;
pTDLast->pShared->flags = 0;
pTDLast->pShared->BuffPtr[0] = pTD1->pShared->BuffPtr[0];
pTDLast->pShared->BuffPtr[1] = pTD1->pShared->BuffPtr[1];
pTDLast->pShared->BuffPtr[2] = pTD1->pShared->BuffPtr[2];
pTDLast->pShared->BuffPtr[3] = pTD1->pShared->BuffPtr[3];
pTDLast->pShared->BuffPtr[4] = pTD1->pShared->BuffPtr[4];
pTDLast->pShared->extBuffPtr[0] = pTD1->pShared->extBuffPtr[0];
pTDLast->pShared->extBuffPtr[1] = pTD1->pShared->extBuffPtr[1];
pTDLast->pShared->extBuffPtr[2] = pTD1->pShared->extBuffPtr[2];
pTDLast->pShared->extBuffPtr[3] = pTD1->pShared->extBuffPtr[3];
pTDLast->pShared->extBuffPtr[4] = pTD1->pShared->extBuffPtr[4];
pTDLast->pQH = pTD1->pQH;
USBLog(7, "AppleUSBEHCI[%p]::allocateTDs - transfering command from TD (%p) to TD (%p)", this, pTD1, pTDLast);
pTDLast->command = pTD1->command;
pTDLast->callbackOnTD = pTD1->callbackOnTD;
pTDLast->multiXferTransaction = pTD1->multiXferTransaction;
pTDLast->finalXferInTransaction = pTD1->finalXferInTransaction;
pTDLast->traceFlag = pTD1->traceFlag;
pTDLast->pLogicalNext = pTD1->pLogicalNext;
pTDLast->logicalBuffer = pTD1->logicalBuffer;
pTD1->pShared->nextTD = HostToUSBLong(kEHCITermFlag);
pTD1->pShared->altTD = HostToUSBLong(kEHCITermFlag);
pTD1->pLogicalNext = 0;
USBLog(7, "AppleUSBEHCI[%p]::allocateTDs - zeroing out command in TD (%p)", this, pTD1);
pTD1->command = NULL;
pTD->pShared->nextTD = HostToUSBLong(pTD1->pPhysical);
pTD->pLogicalNext = pTD1;
pEDQueue->_TailTD = pTD1;
pTDLast->pShared->flags = flags;
IOSync();
if (status)
{
USBLog(3, "AppleUSBEHCI[%p::allocateTDs returning status 0x%x", this, status);
}
USBLog(7, "AppleUSBEHCI[%p::allocateTDs end: _numTDs now %d on %p", this, (uint32_t)pEDQueue->_numTDs, pEDQueue);
return status;
}
#pragma mark Scavanging
static UInt32
mungeECHIStatus(UInt32 flags, EHCIGeneralTransferDescriptorPtr pHCDoneTD, uintptr_t hc, UInt32 busNumber )
{
AppleEHCIQueueHead * pEndpoint;
#if 0
Active CErr Halted XactErr Bytes2Xfer
-- These will be no error, halted not set
0 >0 0 0 0 normal (nc)
0 >0 0 0 >0 short packet (sp)
0 >0 0 1 >=0 (nc or sp) with
one or more retries for
XactErrors detected
-- These will be stalled, CErr still has some left
0 >0 1 0 >0 assuming no other status bits
are set, this was a STALL
response. Bytes2Xfer is a
don''t care.
0 >0 1 1 >0 STALL response (same assumption)
during some bus transaction
during the buffer a timeout,
etc. was encountered
-- Finally we have misc transaction error.
0 0 1 1 >=0 three consecutive bus transaction
errors (any of bad pid, timeout,
data crc, etc.)
Also:
If a transaction transaltor gets an error on an Int or Isoc
it returns an Err handshake. Then you find:
Ping State/Err == 1
If a TT gets 3 errors on a control or bulk transaction you get
a STALL from the TT. Ugh! how do you cope with that.
#endif
pEndpoint = pHCDoneTD->pQH;
if ((flags & kEHCITDStatus_Halted) == 0)
{
pEndpoint->_responseToStall = 0;
return kIOReturnSuccess;
}
if ( (flags & kEHCITDStatus_BuffErr) != 0)
{
if ( (flags & kEHCITDFlags_PID) == (1 << kEHCITDFlags_PIDPhase) )
{
return kOHCIITDConditionBufferOverrun;
}
else
{
return kOHCIITDConditionBufferUnderrun;
}
}
if ( (flags & kEHCITDStatus_MissedUF) != 0 )
{
USBTrace( kUSBTEHCI, kTPEHCIMungeECHIStatus, hc, flags, busNumber, 1);
}
if ( (flags & kEHCITDStatus_Babble) != 0)
{
if ( (flags & kEHCITDFlags_PID) == (1 << kEHCITDFlags_PIDPhase) )
{
return kOHCIITDConditionDataOverrun;
}
}
if ( (flags & kEHCITDFlags_Cerr) != 0)
{
if ( ((USBToHostLong(pEndpoint->GetSharedLogical()->flags) & kEHCIEDFlags_S) >> kEHCIEDFlags_SPhase) != 2)
{
if ( (USBToHostLong(pEndpoint->GetSharedLogical()->splitFlags) & kEHCIEDSplitFlags_SMask) == 0)
{
pEndpoint->_responseToStall = 1 - pEndpoint->_responseToStall; if (pEndpoint->_responseToStall == 1)
{
return kOHCIITDConditionStall;
}
else
{
return kOHCIITDConditionDeviceNotResponding;
}
}
}
return kOHCIITDConditionStall;
}
if ( (flags & kEHCITDStatus_XactErr) != 0)
{
if ( ((USBToHostLong(pEndpoint->GetSharedLogical()->flags) & kEHCIEDFlags_S) >> kEHCIEDFlags_SPhase) != 2)
{ return(kIOUSBHighSpeedSplitError);
}
USBLog(5, "mungeEHCIStatus - XactErr - not responding");
return kOHCIITDConditionDeviceNotResponding; }
if ( (flags & kEHCITDStatus_PingState) != 0) {
return kOHCIITDConditionDeviceNotResponding;
}
USBLog(1, "mungeECHIStatus condition we're not expecting 0x%x", (uint32_t)flags);
USBTrace( kUSBTEHCI, kTPEHCIMungeECHIStatus , hc, flags, kOHCIITDConditionCRC, 0);
return kOHCIITDConditionCRC;
}
IOReturn
TranslateStatusToUSBError(UInt32 status)
{
static const UInt32 statusToErrorMap[] = {
kIOReturnSuccess,
kIOUSBCRCErr,
kIOUSBBitstufErr,
kIOUSBDataToggleErr,
kIOUSBPipeStalled,
kIOReturnNotResponding,
kIOUSBPIDCheckErr,
kIOUSBWrongPIDErr,
kIOReturnOverrun,
kIOReturnUnderrun,
kIOUSBReserved1Err,
kIOUSBReserved2Err,
kIOUSBBufferOverrunErr,
kIOUSBBufferUnderrunErr,
kIOUSBNotSent1Err,
kIOUSBNotSent2Err
};
if (status > 15)
{
if (status == (UInt32) kIOUSBHighSpeedSplitError)
{
return(kIOUSBHighSpeedSplitError);
}
return kIOReturnInternalError;
}
return statusToErrorMap[status];
}
IOReturn
AppleUSBEHCI::EHCIUIMDoDoneQueueProcessing(EHCIGeneralTransferDescriptorPtr pHCDoneTD, OSStatus forceErr,
IOUSBCompletionAction safeAction, EHCIGeneralTransferDescriptorPtr stopAt)
{
UInt32 flags, transferStatus;
UInt32 bufferSizeRemaining = 0;
EHCIGeneralTransferDescriptorPtr nextTD;
OSStatus accumErr = kIOReturnSuccess;
UInt32 currentQueue;
Boolean doOnce, doLoop;
_doneQueueParams[_nextDoneQueue].pHCDoneTD = pHCDoneTD;
_doneQueueParams[_nextDoneQueue].forceErr = forceErr;
_doneQueueParams[_nextDoneQueue].safeAction = safeAction;
_doneQueueParams[_nextDoneQueue].stopAt = stopAt;
doLoop = TRUE;
doOnce = FALSE;
currentQueue = 0;
if (_nextDoneQueue)
{
if (_nextDoneQueue < 19)
{
USBLog(_nextDoneQueue > 0 ? 3 : 7, "AppleUSBEHCI[%p]::EHCIUIMDoDoneQueueProcessing queued level %d", this, (uint32_t)_nextDoneQueue);
_nextDoneQueue++;
return kIOReturnSuccess;
} else
{
USBError(1, "AppleUSBEHCI[%p]::EHCIUIMDoDoneQueueProcessing queue buffer overflow (%d)", this, (int)_nextDoneQueue);
currentQueue = _nextDoneQueue--;
doOnce = TRUE;
doLoop = FALSE;
}
}
_nextDoneQueue++;
while (doOnce || (doLoop && (currentQueue < _nextDoneQueue)))
{
doOnce = FALSE;
USBLog(7, "+AppleUSBEHCI[%p]::EHCIUIMDoDoneQueueProcessing (now at level %d)", this, (uint32_t)currentQueue);
pHCDoneTD = _doneQueueParams[currentQueue].pHCDoneTD;
forceErr = _doneQueueParams[currentQueue].forceErr;
safeAction = _doneQueueParams[currentQueue].safeAction;
stopAt = _doneQueueParams[currentQueue].stopAt;
currentQueue++;
bufferSizeRemaining = 0; accumErr = kIOReturnSuccess;
while (pHCDoneTD != NULL)
{
IOReturn errStatus;
if (pHCDoneTD == stopAt)
{
USBLog(5, "AppleUSBEHCI[%p]::EHCIUIMDoDoneQueueProcessing stop at %p", this, pHCDoneTD);
break;
}
nextTD = (EHCIGeneralTransferDescriptorPtr)pHCDoneTD->pLogicalNext;
flags = USBToHostLong(pHCDoneTD->pShared->flags);
if (forceErr != kIOReturnSuccess)
{
errStatus = forceErr;
}
else if (accumErr != kIOReturnSuccess)
{
errStatus = accumErr;
}
else
{
transferStatus = mungeECHIStatus(flags, pHCDoneTD, (uintptr_t)this, _busNumber);
if (transferStatus)
{
USBLog(4, "AppleUSBEHCI[%p]::EHCIUIMDoDoneQueueProcessing - TD (%p) - got transferStatus 0x%x with flags (0x%x)", this, pHCDoneTD, (uint32_t)transferStatus, (uint32_t)flags);
}
errStatus = TranslateStatusToUSBError(transferStatus);
accumErr = errStatus;
if (errStatus)
{
UInt32 myFlags = USBToHostLong(pHCDoneTD->pQH->GetSharedLogical()->flags);
USBLog(4, "AppleUSBEHCI[%p]::EHCIUIMDoDoneQueueProcessing - got error 0x%x (%s), for bus: 0x%x, addr: %d, ep: %d", this, errStatus, USBStringFromReturn(errStatus), (uint32_t)_busNumber, (uint32_t)((myFlags & kEHCIEDFlags_FA) >> kEHCIEDFlags_FAPhase), (uint32_t)((myFlags & kEHCIEDFlags_EN) >> kEHCIEDFlags_ENPhase));
}
}
bufferSizeRemaining += (flags & kEHCITDFlags_Bytes) >> kEHCITDFlags_BytesPhase;
if (pHCDoneTD->callbackOnTD)
{
if ( pHCDoneTD->command == NULL )
{
USBError (1, "AppleUSBEHCI[%p]::EHCIUIMDoDoneQueueProcessing pHCDoneTD->command is NULL (%p)", this, pHCDoneTD);
}
else
{
IOUSBCompletion completion = pHCDoneTD->command->GetUSLCompletion();
if (!safeAction || (safeAction == completion.action))
{
pHCDoneTD->callbackOnTD = false;
_UIMDiagnostics.totalBytes -= bufferSizeRemaining;
Complete(completion, errStatus, bufferSizeRemaining);
if(pHCDoneTD->pQH)
{
if ((pHCDoneTD->pQH->_queueType == kEHCITypeControl) || (pHCDoneTD->pQH->_queueType == kEHCITypeBulk))
{
if (!_controlBulkTransactionsOut)
{
USBError(1, "AppleUSBEHCI[%p]::EHCIUIMDoDoneQueueProcessing - _controlBulkTransactionsOut underrun!", this);
}
else
{
_controlBulkTransactionsOut--;
USBLog(7, "AppleUSBEHCI[%p]::EHCIUIMDoDoneQueueProcessing - _controlBulkTransactionsOut(%p) pHCDoneTD(%p)", this, (void*)_controlBulkTransactionsOut, pHCDoneTD);
if (!_controlBulkTransactionsOut)
{
USBLog(7, "AppleUSBEHCI[%p]::EHCIUIMDoDoneQueueProcessing - no more _controlBulkTransactionsOut - halting AsyncQueue", this);
DisableAsyncSchedule(false);
}
}
}
}
else
{
USBError(1, "The EHCI driver has detected an error [pHCDoneTD->pQH == NULL]");
}
}
else
{
USBError(1, "The EHCI driver has detected an error [safeAction != NULL]");
}
}
bufferSizeRemaining = 0; accumErr = kIOReturnSuccess;
}
pHCDoneTD->logicalBuffer = NULL;
USBLog(7, "AppleUSBEHCI[%p]::EHCIUIMDoDoneQueueProcessing - deallocating TD (%p)", this, pHCDoneTD);
if(pHCDoneTD->pQH)
{
pHCDoneTD->pQH->_numTDs--;
USBLog(7, "AppleUSBEHCI[%p]::EHCIUIMDoDoneQueueProcessing - _numTDs now: %d on %p", this, (uint32_t)pHCDoneTD->pQH->_numTDs, pHCDoneTD->pQH);
}
DeallocateTD(pHCDoneTD);
pHCDoneTD = nextTD; }
USBLog(7, "-AppleUSBEHCI[%p]::EHCIUIMDoDoneQueueProcessing", this);
}
if (doLoop)
_nextDoneQueue = 0; return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::scavengeIsocTransactions(IOUSBCompletionAction safeAction, bool reQueueTransactions)
{
IOUSBControllerIsochListElement *pDoneEl;
UInt32 cachedProducer;
UInt32 cachedConsumer;
AppleEHCIIsochEndpoint *pEP;
IOUSBControllerIsochListElement *prevEl;
IOUSBControllerIsochListElement *nextEl;
IOInterruptState intState;
intState = IOSimpleLockLockDisableInterrupt( _wdhLock );
pDoneEl = (IOUSBControllerIsochListElement*)_savedDoneQueueHead;
cachedProducer = _producerCount;
IOSimpleLockUnlockEnableInterrupt( _wdhLock, intState );
cachedConsumer = _consumerCount;
if (pDoneEl && (cachedConsumer != cachedProducer))
{
prevEl = NULL;
USBLog(7, "AppleUSBEHCI[%p]::scavengeIsocTransactions - before reversal, cachedConsumer = 0x%x", this, (uint32_t)cachedConsumer);
while (true)
{
pDoneEl->_logicalNext = prevEl;
prevEl = pDoneEl;
cachedConsumer++;
if (pDoneEl->_pEndpoint)
{
pDoneEl->_pEndpoint->onProducerQ--;
pDoneEl->_pEndpoint->onReversedList++;
}
if ( cachedProducer == cachedConsumer)
break;
pDoneEl = pDoneEl->_doneQueueLink;
}
_consumerCount = cachedConsumer;
USBLog(7, "AppleUSBEHCI[%p]::scavengeIsocTransactions - after reversal, cachedConsumer[0x%x]", this, (uint32_t)cachedConsumer);
while (pDoneEl)
{
nextEl = OSDynamicCast(IOUSBControllerIsochListElement, pDoneEl->_logicalNext);
pDoneEl->_logicalNext = NULL;
if (pDoneEl->_pEndpoint)
{
pDoneEl->_pEndpoint->onReversedList--;
}
USBLog(7, "AppleUSBEHCI[%p]::scavengeIsocTransactions - about to scavenge TD %p", this, pDoneEl);
scavengeAnIsocTD(pDoneEl, safeAction);
pDoneEl = nextEl;
}
}
if ( reQueueTransactions )
{
pEP = OSDynamicCast(AppleEHCIIsochEndpoint, _isochEPList);
while (pEP)
{
if (pEP->onReversedList)
{
USBLog(1, "AppleUSBEHCI[%p]::scavengeIsocTransactions - EP (%p) still had %d TDs on the reversed list!!", this, pEP, (uint32_t)pEP->onReversedList);
USBTrace( kUSBTEHCI, kTPEHCIScavengeIsocTransactions , (uintptr_t)this, (uintptr_t)pEP, pEP->onReversedList, 0);
}
ReturnIsochDoneQueue(pEP);
AddIsocFramesToSchedule(pEP);
pEP = OSDynamicCast(AppleEHCIIsochEndpoint, pEP->nextEP);
}
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::scavengeAnIsocTD(IOUSBControllerIsochListElement *pTD, IOUSBCompletionAction safeAction)
{
#pragma unused (safeAction)
IOUSBControllerIsochEndpoint* pEP;
IOReturn ret;
uint64_t timeStamp;
pEP = pTD->_pEndpoint;
timeStamp = mach_absolute_time();
if (pEP == NULL)
{
USBError(1, "AppleUSBEHCI[%p]::scavengeAnIsocEndPoint - could not find endpoint associated with iTD (%p)", this, pTD->_pEndpoint);
}
else
{
if (!pTD->_lowLatency)
ret = pTD->UpdateFrameList(*(AbsoluteTime*)&timeStamp); PutTDonDoneQueue(pEP, pTD, true);
}
#if 0
if (pTD->_completion.action != NULL)
{
ReturnIsocDoneQueue(pEP);
}
#endif
return(kIOReturnSuccess);
}
IOReturn
AppleUSBEHCI::scavengeAnEndpointQueue(IOUSBControllerListElement *pListElem, IOUSBCompletionAction safeAction)
{
EHCIGeneralTransferDescriptorPtr doneQueue = NULL, doneTail= NULL, qHead, qTD, qEnd;
UInt32 flags = 0, countq = 0, count = 0, flagsCErr = 0, debugRetryCount = 0;
Boolean TDisHalted, shortTransfer, foundNextTD, foundAltTD;
AppleEHCIQueueHead *pQH;
while( (pListElem != NULL) && (countq++ < 150000) )
{
count = 0;
pQH = OSDynamicCast(AppleEHCIQueueHead, pListElem);
if (pQH)
{
qTD = qHead = pQH->_qTD;
qEnd = pQH->_TailTD;
if (((qTD == NULL) || (qEnd == NULL)) && (qTD != qEnd))
{
USBError(1, "The EHCI driver found a device queue with invalid head (%p) or tail (%p) - flags 0x%x", qTD, qEnd, (uint32_t) pQH->GetSharedLogical()->flags);
}
TDisHalted = false;
shortTransfer = false;
foundNextTD = false;
foundAltTD = false;
while( qTD && (qTD != qEnd) && (count++ < 150000) )
{
flags = USBToHostLong(qTD->pShared->flags);
flagsCErr = (flags & kEHCITDFlags_Cerr) >> kEHCITDFlags_CerrPhase;
if (!flagsCErr)
{
_UIMDiagnostics.totalErrors++;
if( (gUSBStackDebugFlags & kUSBEnableErrorLogMask) != 0)
{
debugRetryCount = (gUSBStackDebugFlags & kUSBDebugRetryCountMask) >> kUSBDebugRetryCountShift;
int endpoint = (USBToHostLong(pQH->GetSharedLogical()->flags) & kEHCIEDFlags_EN) >> kEHCIEDFlags_ENPhase;
USBLog(1, "AppleUSBEHCI[%p]::scavengeAnEndpointQueue - %s TD[%p] Function(%d) EP (%d) had %d retry/retries - flagsCErr[%p] flags [%p]",
this,
(pQH->_queueType == kEHCITypeControl) ? "CONTROL" : ((pQH->_queueType == kEHCITypeBulk) ? "BULK" : "UNKNOWN"),
qTD,
(int)pQH->_functionNumber, endpoint,
(int)debugRetryCount, (void*)flagsCErr, (void*)flags);
if ( ((flags & kEHCITDStatus_XactErr) != 0) && ((flags & kEHCITDStatus_Halted) != 0) ) {
if (flags == qTD->flagsAtError)
{
qTD->errCount++;
}
else
{
qTD->errCount = 1; }
qTD->flagsAtError = flags; if (qTD->errCount < 3)
{
_UIMDiagnostics.recoveredErrors++;
if(qTD->errCount == 2)
{
_UIMDiagnostics.errors2Strikes++;
}
USBLog(1, "AppleUSBEHCI[%p]::scavengeAnEndpointQueue - halted due to bus error, try restarting the transaction (%x), err count: %d", this, (uint32_t)flags, (uint32_t)qTD->errCount);
flags &= ~ kEHCITDFlags_Status; flags |= kEHCITDStatus_Active | (1<<kEHCITDFlags_CerrPhase); qTD->pShared->flags = HostToUSBLong(flags); pQH->GetSharedLogical()->qTDFlags = HostToUSBLong(flags); IOSync();
break;
}
else
{
_UIMDiagnostics.errors3Strikes++;
USBLog(1, "AppleUSBEHCI[%p]::scavengeAnEndpointQueue - 3 consecutive errors, completing TD with error (%x), err count: %d", this, (uint32_t)flags, (uint32_t)qTD->errCount);
}
}
}
}
if(!TDisHalted && !shortTransfer)
{
if ((flags & kEHCITDStatus_Active) != 0)
{ break;
}
_UIMDiagnostics.totalBytes += qTD->tdSize;
TDisHalted = ((flags & kEHCITDStatus_Halted) != 0) ;
if (!TDisHalted)
{
shortTransfer = ((flags & kEHCITDFlags_Bytes) >> kEHCITDFlags_BytesPhase) ? true : false;
}
}
if (qTD->pPhysical == USBToHostLong(pQH->GetSharedLogical()->NextqTDPtr))
{
foundNextTD = true;
}
if (qTD->pPhysical == USBToHostLong(pQH->GetSharedLogical()->AltqTDPtr))
{
foundAltTD = true;
}
if (qTD->callbackOnTD)
{
USBLog(7, "AppleUSBEHCI[%p]::scavengeAnEndpointQueue - TD (%p) on ED (%p)", this, qTD, pQH);
if (doneQueue == NULL)
{
doneQueue = qHead;
}
else
{
doneTail->pLogicalNext = qHead;
}
doneTail = qTD;
qTD = qTD->pLogicalNext; qHead = qTD;
doneTail->pLogicalNext = NULL;
pQH->_qTD = qTD;
if (qTD == NULL)
{
USBError(1, "The EHCI driver found a NULL Transfer Descriptor - Queue flags 0x%x", (uint32_t) pQH->GetSharedLogical()->flags);
break;
}
flags = USBToHostLong(pQH->GetSharedLogical()->qTDFlags);
if (flags & kEHCITDStatus_Halted)
{
if (TDisHalted || shortTransfer)
{
flags = USBToHostLong(qTD->pShared->flags);
if (foundAltTD)
{
pQH->GetSharedLogical()->AltqTDPtr = HostToUSBLong(qTD->pPhysical);
IOSync();
}
if (foundNextTD)
{
pQH->GetSharedLogical()->NextqTDPtr = HostToUSBLong(qTD->pPhysical);
IOSync();
}
if ((flags & kEHCITDStatus_Active) != 0) {
break;
}
}
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::scavengeAnEndpointQueue - not changing live pQH[%p]", this, pQH);
}
TDisHalted = false;
shortTransfer = false;
foundNextTD = false;
foundAltTD = false;
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::scavengeAnEndpointQueue - looking past TD (%p) on ED (%p)", this, qTD, pQH);
qTD = qTD->pLogicalNext;
if (qTD == NULL)
{
USBError(1, "The EHCI driver found a NULL Transfer Descriptor - Queue flags 0x%x", (uint32_t) pQH->GetSharedLogical()->flags);
break;
}
}
}
if (count > pQH->_numTDs)
{
USBLog(1, "AppleUSBEHCI[%p]::scavengeAnEndpointQueue looks like bad ed queue, count: %d, pQH->_numTDs: %d", this, (uint32_t)count, (uint32_t)pQH->_numTDs);
USBTrace( kUSBTEHCI, kTPEHCIScavengeAnEndpointQueue , (uintptr_t)this, count, 0, 0);
}
}
pListElem = (IOUSBControllerListElement*)pListElem->_logicalNext;
}
if (doneQueue != NULL)
{
EHCIUIMDoDoneQueueProcessing(doneQueue, kIOReturnSuccess, safeAction, NULL);
}
return kIOReturnSuccess;
}
void
AppleUSBEHCI::scavengeCompletedTransactions(IOUSBCompletionAction safeAction)
{
IOReturn err, err1;
int i;
safeAction = 0;
err = scavengeIsocTransactions(safeAction, true);
if (err != kIOReturnSuccess)
{
USBLog(1, "AppleUSBEHCI[%p]::scavengeCompletedTransactions err isoch list %x", this, err);
USBTrace( kUSBTEHCI, kTPEHCIScavengeCompletedTransactions , (uintptr_t)this, err, 0, 1);
}
if ( _AsyncHead != NULL )
{
err = scavengeAnEndpointQueue(_AsyncHead, safeAction);
if (err != kIOReturnSuccess)
{
USBLog(1, "AppleUSBEHCI[%p]::scavengeCompletedTransactions err async queue %x", this, err);
USBTrace( kUSBTEHCI, kTPEHCIScavengeCompletedTransactions , (uintptr_t)this, err, 0, 2);
}
}
if ( _InactiveAsyncHead != NULL )
{
err = scavengeAnEndpointQueue(_InactiveAsyncHead, safeAction);
if (err != kIOReturnSuccess)
{
USBLog(1, "AppleUSBEHCI[%p]::scavengeCompletedTransactions err inactive async queue %x", this, err);
USBTrace( kUSBTEHCI, kTPEHCIScavengeCompletedTransactions , (uintptr_t)this, err, 0, 4);
}
}
if ( _logicalPeriodicList != NULL )
{
for(i = 0; i < kEHCIMaxPollingInterval; i++)
{
if (GetPeriodicListLogicalEntry(i) != NULL)
{
err1 = scavengeAnEndpointQueue(GetPeriodicListLogicalEntry(i), safeAction);
if (err1 != kIOReturnSuccess)
{
err = err1;
USBLog(1, "AppleUSBEHCI[%p]::scavengeCompletedTransactions err periodic queue[%d]:0x%x", this, i, err);
USBTrace( kUSBTEHCI, kTPEHCIScavengeCompletedTransactions , (uintptr_t)this, err, i, 3);
}
}
}
}
}
#pragma mark Bulk
IOReturn
AppleUSBEHCI::UIMCreateBulkEndpoint(UInt8 functionAddress,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt8 maxPacketSize)
{
#pragma unused (functionAddress, endpointNumber, direction, speed, maxPacketSize)
USBLog(1, "AppleUSBEHCI[%p] UIMCreateBulkEndpoint- calling the wrong method!", this);
return kIOReturnInternalError;
}
IOReturn
AppleUSBEHCI::UIMCreateBulkEndpoint(UInt8 functionAddress,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt16 maxPacketSize,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
AppleEHCIQueueHead *pEP;
USBLog(7, "AppleUSBEHCI[%p]::UIMCreateBulkEndpoint(adr=%d:%d, max=%d, dir=%d)", this, functionAddress, endpointNumber, maxPacketSize, direction);
if ( (direction != kUSBOut) && (direction != kUSBIn) )
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateBulkEndpoint - wrong direction %d", this, direction);
USBTrace( kUSBTEHCI, kTPEHCICreateBulkEndpoint , (uintptr_t) this, functionAddress, endpointNumber, direction);
return kIOReturnBadArgument;
}
if (highSpeedHub == 0)
speed = kUSBDeviceSpeedHigh;
else
speed = kUSBDeviceSpeedFull;
pEP = AddEmptyCBEndPoint(functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort, direction);
if (pEP == NULL)
return kIOReturnNoResources;
pEP->_queueType = kEHCITypeBulk;
printAsyncQueue(7, "UIMCreateBulkEndpoint", true, false);
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::UIMCreateBulkTransfer(IOUSBCommand* command)
{
AppleEHCIQueueHead *pEDQueue;
IOReturn status;
IOMemoryDescriptor* buffer = command->GetBuffer();
short direction = command->GetDirection();
USBLog(7, "AppleUSBEHCI[%p]::UIMCreateBulkTransfer - addr=%d:%d(%s), Timeouts:(%d,%d) cbp=%p:%x cback=[%p:%p:%p])", this,
command->GetAddress(), command->GetEndpoint(), command->GetDirection() == kUSBIn ? "in" : "out",
(uint32_t) command->GetNoDataTimeout(), (uint32_t) command->GetCompletionTimeout(),
command->GetBuffer(), (int)command->GetReqCount(),
command->GetUSLCompletion().action, command->GetUSLCompletion().target, command->GetUSLCompletion().parameter);
pEDQueue = FindControlBulkEndpoint(command->GetAddress(), command->GetEndpoint(), NULL, direction);
if (pEDQueue == NULL)
{
USBLog(3, "AppleUSBEHCI[%p]::UIMCreateBulkTransfer- Could not find endpoint for addr(%d) ep (%d)!", this, (int)command->GetAddress(), (int)command->GetEndpoint());
return kIOUSBEndpointNotFound;
}
status = allocateTDs(pEDQueue, command, buffer, command->GetReqCount(), direction, false );
if (status == kIOReturnSuccess)
{
USBLog(7, "AppleUSBEHCI[%p]::UIMCreateBulkTransfer allocateTDS done - CMD = 0x%x, STS = 0x%x", this, USBToHostLong(_pEHCIRegisters->USBCMD), USBToHostLong(_pEHCIRegisters->USBSTS));
EnableAsyncSchedule(false);
}
else
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateBulkTransfer- allocateTDs (adr=%d:%d(%s)) returned error %x", this, command->GetAddress(), command->GetEndpoint(), direction == kUSBIn ? "in" : "out", status);
USBTrace( kUSBTEHCI, kTPEHCICreateBulkTransfer, (uintptr_t)this, status, 0, 0);
}
return status;
}
IOReturn
AppleUSBEHCI::UIMCreateBulkTransfer(short functionAddress,
short endpointNumber,
IOUSBCompletion completion,
IOMemoryDescriptor * CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
#pragma unused (functionAddress, endpointNumber, completion, CBP, bufferRounding, bufferSize, direction)
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateBulkTransfer- calling the wrong method!", this);
return kIOReturnIPCError;
}
void
AppleUSBEHCI::returnTransactions(AppleEHCIQueueHead *pED, EHCIGeneralTransferDescriptor *untilThisOne, IOReturn error, bool clearToggle)
{
EHCIGeneralTransferDescriptorPtr doneQueue = NULL, doneTail= NULL;
bool removedSome = false;
USBLog(5, "AppleUSBEHCI[%p]::returnTransactions, pED(%p) until (%p), clearToggle: %d", this, pED, untilThisOne, clearToggle);
pED->print(7, this);
if (!(USBToHostLong(pED->GetSharedLogical()->qTDFlags) & kEHCITDStatus_Halted))
{
USBError(1, "AppleUSBEHCI[%p]::returnTransactions, pED (%p) NOT HALTED (qTDFlags = 0x%x)", this, pED, USBToHostLong(pED->GetSharedLogical()->qTDFlags));
}
if ((pED->_qTD != pED->_TailTD) && (pED->_qTD != untilThisOne)) {
USBLog(5, "AppleUSBEHCI[%p] returnTransactions: removing TDs", this);
removedSome = true;
if(untilThisOne == NULL)
{
untilThisOne = pED->_TailTD; }
doneQueue = pED->_qTD;
doneTail = doneQueue;
pED->_qTD = pED->_qTD->pLogicalNext;
while (pED->_qTD != untilThisOne)
{
doneTail->pLogicalNext = pED->_qTD;
doneTail = pED->_qTD;
pED->_qTD = pED->_qTD->pLogicalNext;
}
doneTail->pLogicalNext = NULL;
pED->GetSharedLogical()->AltqTDPtr = HostToUSBLong(kEHCITermFlag); pED->GetSharedLogical()->NextqTDPtr = HostToUSBLong(untilThisOne->pPhysical);
pED->_qTD = untilThisOne;
}
USBLog(5, "AppleUSBEHCI[%p]::returnTransactions, pED->qTD flags were %x", this, USBToHostLong(pED->_qTD->pShared->flags));
pED->_qTD->pShared->flags &= ~HostToUSBLong(kEHCITDStatus_Halted); IOSync();
USBLog(5, "AppleUSBEHCI[%p]::returnTransactions, pED->qTD flags now %x", this, USBToHostLong(pED->_qTD->pShared->flags));
USBLog(5, "AppleUSBEHCI[%p]::returnTransactions, pED->qTD (L:%p P:0x%x) pED->TailTD (L:%p P:0x%x)", this, pED->_qTD, (uint32_t)pED->_qTD->pPhysical, pED->_TailTD, (uint32_t)pED->_TailTD->pPhysical);
if (USBToHostLong(pED->GetSharedLogical()->NextqTDPtr) != (pED->_qTD->pPhysical & ~0x1F))
{
USBLog(5, "AppleUSBEHCI[%p]::returnTransactions - NextqTDPtr(%p) AltqTDPtr(%p) - changing NextqTDPtr(%p)", this, (void*)USBToHostLong(pED->GetSharedLogical()->NextqTDPtr), (void*)USBToHostLong(pED->GetSharedLogical()->AltqTDPtr), (void*)(pED->_qTD->pPhysical & ~0x1F));
pED->GetSharedLogical()->NextqTDPtr = HostToUSBLong( (UInt32)pED->_qTD->pPhysical & ~0x1F);
}
USBLog(5, "AppleUSBEHCI[%p]::returnTransactions: clearing ED bit, qTDFlags = %x", this, USBToHostLong(pED->GetSharedLogical()->qTDFlags));
if (clearToggle)
pED->GetSharedLogical()->qTDFlags = 0; else
pED->GetSharedLogical()->qTDFlags &= HostToUSBLong(kEHCITDFlags_DT);
IOSync();
if (doneQueue)
{
USBLog(5, "AppleUSBEHCI[%p]::returnTransactions: calling back the done queue (after ED is made active)", this);
EHCIUIMDoDoneQueueProcessing(doneQueue, error, NULL, NULL);
}
USBLog(5, "AppleUSBEHCI[%p]::returnTransactions: after bit clear, qTDFlags = %x", this, USBToHostLong(pED->GetSharedLogical()->qTDFlags));
}
void
AppleUSBEHCI::HaltAsyncEndpoint(AppleEHCIQueueHead *pED, AppleEHCIQueueHead *pEDBack)
{
if (!(USBToHostLong(pED->GetSharedLogical()->qTDFlags) & kEHCITDStatus_Halted))
{
USBLog(6, "AppleUSBEHCI[%p]::HaltAsyncEndpoint - unlinking, halting, and relinking (%p)", this, pED);
unlinkAsyncEndpoint(pED, pEDBack);
pED->GetSharedLogical()->qTDFlags |= HostToUSBLong(kEHCITDStatus_Halted);
pED->GetSharedLogical()->qTDFlags &= ~(HostToUSBLong(kEHCITDStatus_Active));
linkAsyncEndpoint(pED);
if (_myBusState == kUSBBusStateRunning)
EnableAsyncSchedule(false); }
}
IOReturn
AppleUSBEHCI::HandleEndpointAbort(short functionAddress,
short endpointNumber,
short direction,
bool clearToggle)
{
AppleEHCIQueueHead *pED;
AppleEHCIQueueHead *pEDQueueBack;
AppleEHCIIsochEndpoint *piEP;
USBLog(5, "AppleUSBEHCI[%p]::HandleEndpointAbort: Addr: %d, Endpoint: %d,%d, clearToggle: %d", this, functionAddress, endpointNumber, direction, clearToggle);
if (functionAddress == _rootHubFuncAddress)
{
if ( (endpointNumber != 1) && (endpointNumber != 0) )
{
USBLog(1, "AppleUSBEHCI[%p]::HandleEndpointAbort: bad params - endpNumber: %d", this, endpointNumber );
USBTrace( kUSBTEHCI, kTPEHCIHandleEndpointAbort , functionAddress, endpointNumber, kIOReturnBadArgument, 2 );
return kIOReturnBadArgument;
}
USBLog(5, "AppleUSBEHCI[%p]::HandleEndpointAbort: Attempting operation on root hub", this);
return SimulateEDAbort( endpointNumber, direction);
}
piEP = OSDynamicCast(AppleEHCIIsochEndpoint, FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL));
if (piEP)
{
return AbortIsochEP(piEP);
}
pED = FindControlBulkEndpoint (functionAddress, endpointNumber, &pEDQueueBack, direction);
if(pED != NULL)
{
if (pED->_aborting)
{
USBLog(1, "AppleUSBEHCI[%p]::HandleEndpointAbort - Control/Bulk endpoint [%p] already aborting - not recursing", this, pED);
return kIOUSBClearPipeStallNotRecursive;
}
pED->_aborting = true;
HaltAsyncEndpoint(pED, pEDQueueBack);
returnTransactions(pED, NULL, kIOUSBTransactionReturned, clearToggle); }
else
{
pED = FindInterruptEndpoint(functionAddress, endpointNumber, direction, NULL);
if(pED == NULL)
{
USBLog(1, "AppleUSBEHCI::HandleEndpointAbort, endpoint not found");
USBTrace( kUSBTEHCI, kTPEHCIHandleEndpointAbort , functionAddress, endpointNumber, kIOUSBEndpointNotFound, 3 );
return kIOUSBEndpointNotFound;
}
if (pED->_aborting)
{
USBLog(1, "AppleUSBEHCI[%p]::HandleEndpointAbort - Interrupt endpoint [%p] already aborting - not recursing", this, pED);
return kIOUSBClearPipeStallNotRecursive;
}
pED->_aborting = true;
HaltInterruptEndpoint(pED);
returnTransactions(pED, NULL, kIOUSBTransactionReturned, clearToggle);
}
if ( (pED->GetSharedLogical()->qTDFlags & HostToUSBLong(kEHCITDFlags_DT)) && !clearToggle )
{
USBLog(6, "AppleUSBEHCI[%p]::HandleEndpointAbort Preserving a data toggle of 1 in response to an Abort()!", this);
}
if (clearToggle)
{
pED->GetSharedLogical()->qTDFlags &= HostToUSBLong(~((UInt32)kEHCITDFlags_DT)); IOSync();
}
if(USBToHostLong(pED->GetSharedLogical()->qTDFlags) & kEHCITDStatus_Halted)
{
USBLog(1, "AppleUSBEHCI::HandleEndpointAbort, QH still halted following returnTransactions!!");
USBTrace( kUSBTEHCI, kTPEHCIHandleEndpointAbort , USBToHostLong(pED->GetSharedLogical()->qTDFlags), kEHCITDStatus_Halted, 0, 4 );
}
pED->_aborting = false;
return kIOReturnSuccess;
}
#pragma mark Async
void
AppleUSBEHCI::linkAsyncEndpoint(AppleEHCIQueueHead *CBED)
{
IOPhysicalAddress newHorizPtr;
AppleEHCIQueueHead *pEDHead = _AsyncHead;
UInt32 newPhysicalAddr = NULL;
int retries = 500;
newHorizPtr = CBED->GetPhysicalAddrWithType();
USBLog(7, "AppleUSBEHCI[%p]::linkAsynEndpoint pEDHead %p", this, pEDHead);
if(pEDHead == NULL)
{
CBED->GetSharedLogical()->flags |= HostToUSBLong(kEHCIEDFlags_H);
CBED->SetPhysicalLink(newHorizPtr);
CBED->_logicalNext = NULL;
_AsyncHead = CBED;
newPhysicalAddr = HostToUSBLong(CBED->_sharedPhysical);
if (!isInactive())
{
_pEHCIRegisters->AsyncListAddr = newPhysicalAddr;
if (_pEHCIRegisters->AsyncListAddr != newPhysicalAddr)
{
USBLog(1, "AppleUSBEHCI[%p]::linkAsyncEndpoint - AsyncListAddr did not stick right away..", this);
}
IOSync();
while (retries-- && (_pEHCIRegisters->AsyncListAddr != newPhysicalAddr))
{
if ((retries % 10) == 0)
{
USBLog(1, "AppleUSBEHCI[%p]::linkAsyncEndpoint - AsyncListAddr not sticking yet, retries=%d", this, retries);
}
}
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
if (!_pEHCIRegisters->AsyncListAddr)
panic("AppleUSBEHCI::linkAsyncEndpoint.. AsyncListAddr is NULL after filling in with CBED->_sharedPhysical!!\n");
#endif
}
else
{
USBLog(2, "AppleUSBEHCI[%p]::linkAsyncEndpoint - I am inActive, so I don't need to set AsyncListAddr", this);
}
}
else
{
CBED->SetPhysicalLink(pEDHead->GetPhysicalLink());
CBED->_logicalNext = pEDHead->_logicalNext;
pEDHead->_logicalNext = CBED;
pEDHead->SetPhysicalLink(newHorizPtr);
}
}
void AppleUSBEHCI::maybeLinkAsyncEndpoint(AppleEHCIQueueHead *CBED)
{
linkAsyncEndpoint(CBED);
}
void
AppleUSBEHCI::unlinkAsyncEndpoint(AppleEHCIQueueHead * pED, AppleEHCIQueueHead * pEDQueueBack)
{
UInt32 CMD, STS, count;
AppleEHCIQueueHead *pNewHeadED = NULL;
if( (pEDQueueBack == NULL) && (pED->_logicalNext == NULL) )
{
USBLog(7, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint: removing sole endpoint %lx", this, (long)pED);
DisableAsyncSchedule(true);
printAsyncQueue(7, "unlinkAsyncEndpoint", true, false);
pED->GetSharedLogical()->flags &= ~HostToUSBLong(kEHCIEDFlags_H);
_AsyncHead = NULL;
_pEHCIRegisters->AsyncListAddr = NULL;
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint: removing endpoint from queue %lx",this, (long)pED);
if(_AsyncHead == pED)
{
USBLog(7, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint: removing head endpoint %lx", this, (long)pED);
if (pEDQueueBack)
{
USBError(1, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint: ERROR - pEDQueueBack should be NULL at this point",this );
}
pEDQueueBack = OSDynamicCast(AppleEHCIQueueHead, pED->_logicalNext);
while (pEDQueueBack->_logicalNext)
pEDQueueBack = OSDynamicCast(AppleEHCIQueueHead, pEDQueueBack->_logicalNext);
printAsyncQueue(7, "unlinkAsyncEndpoint", true, false);
pNewHeadED = OSDynamicCast(AppleEHCIQueueHead, pED->_logicalNext);
_AsyncHead = pNewHeadED;
pEDQueueBack->SetPhysicalLink(pED->_logicalNext->GetPhysicalAddrWithType());
pED->GetSharedLogical()->flags &= ~HostToUSBLong(kEHCIEDFlags_H);
pNewHeadED->GetSharedLogical()->flags |= HostToUSBLong(kEHCIEDFlags_H);
}
else if(pEDQueueBack != NULL)
{
printAsyncQueue(7, "unlinkAsyncEndpoint", true, false);
pEDQueueBack->SetPhysicalLink(pED->GetPhysicalLink());
pEDQueueBack->_logicalNext = pED->_logicalNext;
printAsyncQueue(7, "unlinkAsyncEndpoint", true, false);
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint: ED not head, but pEDQueueBack not NULL",this);
}
if (isInactive())
{
USBLog(2, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint: I am inactive, so not worrying about STS and CMD",this);
return;
}
STS = USBToHostLong(_pEHCIRegisters->USBSTS);
CMD = USBToHostLong(_pEHCIRegisters->USBCMD);
if (CMD & kEHCICMDAsyncEnable)
{
for (count=0; (count < 100) && !(STS & kEHCISTSAsyncScheduleStatus); count++)
{
IOSleep(1);
STS = USBToHostLong(_pEHCIRegisters->USBSTS);
}
if (count)
{
USBLog(2, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint: waited %d ms for the asynch schedule to come ON in the STS register", this, (int)count);
}
if (!(STS & kEHCISTSAsyncScheduleStatus))
{
USBLog(1, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint - the schedule status didn't go ON in the STS register!!", this);
USBTrace( kUSBTEHCI, kTPEHCIUnlinkAsyncEndpoint , (uintptr_t)this, STS, kEHCISTSAsyncScheduleStatus, 1 );
}
else
{
_pEHCIRegisters->USBCMD = HostToUSBLong(CMD | kEHCICMDAsyncDoorbell);
STS = USBToHostLong(_pEHCIRegisters->USBSTS);
count = 0;
while((STS & kEHCIAAEIntBit) == 0)
{
IOSleep(1);
STS = USBToHostLong(_pEHCIRegisters->USBSTS);
count++;
if ((count % 1000) == 0)
{
USBLog(2, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint: count(%d) USBCMD(%p) USBSTS(%p) USBINTR(%p) ", this, (int)count, (void*)USBToHostLong(_pEHCIRegisters->USBCMD), (void*)USBToHostLong(_pEHCIRegisters->USBSTS), (void*)USBToHostLong(_pEHCIRegisters->USBIntr));
}
if ( count > 10000)
{
break;
}
};
USBLog(7, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint: delayed for %d ms after ringing the doorbell", this, (int)count);
_pEHCIRegisters->USBSTS = HostToUSBLong(kEHCIAAEIntBit);
IOSync();
if ((_pEHCIRegisters->AsyncListAddr & 0xFFFFFFE0) == pED->_sharedPhysical)
{
USBError(1, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint - pED[%p] seems to still be the AsyncListAddr after doorbell", this, pED);
if (pNewHeadED)
{
_pEHCIRegisters->AsyncListAddr = HostToUSBLong(pNewHeadED->_sharedPhysical);
IOSync();
}
}
}
}
else
{
USBLog(5, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint Async schedule was disabled", this);
STS = USBToHostLong(_pEHCIRegisters->USBSTS);
for (count=0; (count < 100) && (STS & kEHCISTSAsyncScheduleStatus); count++)
{
IOSleep(1);
STS = USBToHostLong(_pEHCIRegisters->USBSTS);
}
if (count)
{
USBLog(2, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint: waited %d ms for the asynch schedule to go OFF in the STS register", this, (int)count);
}
STS = USBToHostLong(_pEHCIRegisters->USBSTS);
if (STS & kEHCISTSAsyncScheduleStatus)
{
USBLog(1, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint - the schedule status didn't go OFF in the STS register!!", this);
USBTrace( kUSBTEHCI, kTPEHCIUnlinkAsyncEndpoint , (uintptr_t)this, STS, kEHCISTSAsyncScheduleStatus, 2 );
}
if (USBToHostLong(_pEHCIRegisters->AsyncListAddr) == pED->_sharedPhysical)
{
USBLog(2, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint - changing AsyncListAddr from %08x to %08x", this, _pEHCIRegisters->AsyncListAddr, (int)HostToUSBLong(_AsyncHead->_sharedPhysical));
_pEHCIRegisters->AsyncListAddr = HostToUSBLong(_AsyncHead->_sharedPhysical);
IOSync();
}
USBLog(7, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint - AsyncListAddr(%08x) pED.phys(%08x)", this, _pEHCIRegisters->AsyncListAddr, (int)pED->_sharedPhysical);
}
}
}
void
AppleUSBEHCI::printAsyncQueue(int level, const char* str, bool printSkipped, bool printTDs)
{
#pragma unused (printSkipped)
AppleEHCIQueueHead *pED = _AsyncHead;
if (pED)
{
USBLog(level, "AppleUSBEHCI[%p]::printAsyncQueue called from %s", this, str);
USBLog(level, "--------------------");
USBLog(level, "AppleUSBEHCI[%p]::printAsyncQueue: _AsyncHead[%p], AsyncListAddr[0x%x]", this, _AsyncHead, USBToHostLong(_pEHCIRegisters->AsyncListAddr));
while (pED)
{
pED->print(level, this);
if (printTDs)
{
EHCIGeneralTransferDescriptorPtr td = pED->_qTD;
while (td != pED->_TailTD)
{
printTD(td, level);
td = td->pLogicalNext;
}
}
pED = OSDynamicCast(AppleEHCIQueueHead, pED->_logicalNext);
}
}
else
{
USBLog(level, "AppleUSBEHCI[%p]::printAsyncQueue: NULL Async Queue called from %s", this, str);
}
}
void
AppleUSBEHCI::printInactiveQueue(int level, const char* str, bool printSkipped, bool printTDs)
{
#pragma unused (printSkipped)
AppleEHCIQueueHead *pED = _InactiveAsyncHead;
if (pED)
{
USBLog(level, "AppleUSBEHCI[%p]::printInactiveQueue called from %s", this, str);
USBLog(level, "--------------------");
USBLog(level, "AppleUSBEHCI[%p]::printInactiveQueue: _InactiveAsyncHead[%p]", this, _InactiveAsyncHead);
while (pED)
{
pED->print(level, this);
if (printTDs)
{
}
pED = OSDynamicCast(AppleEHCIQueueHead, pED->_logicalNext);
}
}
else
{
USBLog(level, "AppleUSBEHCI[%p]::printAsyncQueue: NULL Async Queue called from %s", this, str);
}
}
void
AppleUSBEHCI::printPeriodicList(int level, const char* str, bool printSkipped, bool printTDs)
{
#pragma unused (level, str, printTDs, printSkipped)
}
void
AppleUSBEHCI::printTD(EHCIGeneralTransferDescriptorPtr pTD, int level)
{
if(pTD == 0)
{
USBLog(level, "Attempt to print null TD");
return;
}
USBLog(level, "AppleUSBEHCI[%p]::printTD: ------pTD at %p", this, pTD);
USBLog(level, "AppleUSBEHCI[%p]::printTD: shared.nextTD: 0x%x", this, USBToHostLong(pTD->pShared->nextTD));
USBLog(level, "AppleUSBEHCI[%p]::printTD: shared.altTD: 0x%x", this, USBToHostLong(pTD->pShared->altTD));
USBLog(level, "AppleUSBEHCI[%p]::printTD: shared.flags: 0x%x", this, USBToHostLong(pTD->pShared->flags));
USBLog(level, "AppleUSBEHCI[%p]::printTD: shared.BuffPtr0: 0x%x", this, USBToHostLong(pTD->pShared->BuffPtr[0]));
USBLog(level, "AppleUSBEHCI[%p]::printTD: pEndpt: %p", this, (pTD->pQH));
USBLog(level, "AppleUSBEHCI[%p]::printTD: pPhysical: 0x%x", this, (uint32_t)(pTD->pPhysical));
USBLog(level, "AppleUSBEHCI[%p]::printTD: pLogicalNext: %p", this, (pTD->pLogicalNext));
USBLog(level, "AppleUSBEHCI[%p]::printTD: logicalBuffer: %p", this, (pTD->logicalBuffer));
USBLog(level, "AppleUSBEHCI[%p]::printTD: callbackOnTD: %s", this, pTD->callbackOnTD ? "TRUE" : "FALSE");
USBLog(level, "AppleUSBEHCI[%p]::printTD: multiXferTransaction: %s", this, pTD->multiXferTransaction ? "TRUE" : "FALSE");
USBLog(level, "AppleUSBEHCI[%p]::printTD: finalXferInTransaction: %s", this, pTD->finalXferInTransaction ? "TRUE" : "FALSE");
if (level < 7)
{
USBTrace( kUSBTEHCIDumpQueues, kTPEHCIDumpTD1, (uintptr_t)this, (uintptr_t)pTD, (uint32_t)pTD->pPhysical, (uintptr_t)pTD->pLogicalNext );
USBTrace( kUSBTEHCIDumpQueues, kTPEHCIDumpTD2, (uintptr_t)this, (uint32_t)USBToHostLong(pTD->pShared->nextTD), (uint32_t)USBToHostLong(pTD->pShared->altTD), (uint32_t)USBToHostLong(pTD->pShared->flags) );
USBTrace( kUSBTEHCIDumpQueues, kTPEHCIDumpTD3, (uintptr_t)this, (uint32_t)USBToHostLong(pTD->pShared->BuffPtr[0]), (uint32_t)USBToHostLong(pTD->pShared->BuffPtr[1]), (uint32_t)USBToHostLong(pTD->pShared->BuffPtr[2]) );
USBTrace( kUSBTEHCIDumpQueues, kTPEHCIDumpTD4, (uintptr_t)this, (uint32_t)USBToHostLong(pTD->pShared->BuffPtr[3]), (uint32_t)USBToHostLong(pTD->pShared->BuffPtr[4]), 0 );
USBTrace( kUSBTEHCIDumpQueues, kTPEHCIDumpTD5, (uintptr_t)this, (uint32_t)USBToHostLong(pTD->pShared->extBuffPtr[0]), (uint32_t)USBToHostLong(pTD->pShared->extBuffPtr[1]), (uint32_t)USBToHostLong(pTD->pShared->extBuffPtr[2]) );
USBTrace( kUSBTEHCIDumpQueues, kTPEHCIDumpTD6, (uintptr_t)this, (uint32_t)USBToHostLong(pTD->pShared->extBuffPtr[3]), (uint32_t)USBToHostLong(pTD->pShared->extBuffPtr[4]), 0 );
USBTrace( kUSBTEHCIDumpQueues, kTPEHCIDumpTD7, (uintptr_t)this, (uintptr_t)pTD->logicalBuffer, (uint32_t)pTD->callbackOnTD, (uintptr_t)pTD->multiXferTransaction );
USBTrace( kUSBTEHCIDumpQueues, kTPEHCIDumpTD8, (uintptr_t)this, (uint32_t)pTD->finalXferInTransaction, 0, 0 );
}
}
#pragma mark Interrupt
AppleEHCIQueueHead *
AppleUSBEHCI::MakeEmptyIntEndPoint(UInt8 functionAddress,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed,
USBDeviceAddress highSpeedHub,
int highSpeedPort,
UInt8 direction)
{
AppleEHCIQueueHead * intED;
UInt32 mySMask;
intED = MakeEmptyEndPoint(functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort, direction);
if (intED == NULL)
return NULL;
intED->_queueType = kEHCITypeInterrupt;
return intED;
}
AppleEHCIQueueHead *
AppleUSBEHCI::FindInterruptEndpoint(short functionNumber, short endpointNumber, short direction, IOUSBControllerListElement * *pLEBack)
{
UInt32 unique;
AppleEHCIQueueHead * pEDQueue;
IOUSBControllerListElement * pListElementBack;
IOUSBControllerListElement * pListElem;
int i;
unique = (UInt32) ((((UInt32) endpointNumber) << kEHCIEDFlags_ENPhase) | ((UInt32) functionNumber));
pListElementBack = NULL;
USBLog(7, "AppleUSBEHCI[%p]::FindInterruptEndpoint - _greatestPeriod[%d]", this, (int)_greatestPeriod);
for(i= 0; i < _greatestPeriod; i++)
{
pListElem = GetPeriodicListLogicalEntry(i);
USBLog(7, "AppleUSBEHCI[%p]::FindInterruptEndpoint - i (%d) pListElem[%p]", this, i, pListElem);
while ( pListElem != NULL)
{
pEDQueue = OSDynamicCast(AppleEHCIQueueHead, pListElem);
if (pEDQueue && (pEDQueue != _dummyIntQH[i % kEHCIMaxPollingInterval]))
{
if( ( (USBToHostLong(pEDQueue->GetSharedLogical()->flags) & kEHCIUniqueNumNoDirMask) == unique) && ( pEDQueue->_direction == (UInt8)direction) )
{
if (pLEBack)
*pLEBack = pListElementBack;
return pEDQueue;
}
}
pListElementBack = pListElem;
pListElem = pListElem->_logicalNext;
}
}
return NULL;
}
IOReturn
AppleUSBEHCI::UIMCreateInterruptEndpoint(short functionAddress,
short endpointNumber,
UInt8 direction,
short speed,
UInt16 maxPacketSize,
short pollingRate)
{
#pragma unused (functionAddress, endpointNumber, direction, speed, maxPacketSize, pollingRate)
USBError(1, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint - old version called with no split params", this);
return kIOReturnInternalError;
}
IOReturn
AppleUSBEHCI::UIMCreateInterruptEndpoint(short functionAddress,
short endpointNumber,
UInt8 direction,
short speed,
UInt16 maxPacketSize,
short pollingRate,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
int offset;
UInt16 availableBandwidth;
AppleEHCIQueueHead * pEP;
IOUSBControllerListElement * pLE;
IOUSBControllerListElement * temp;
AppleUSBEHCIHubInfo * hiPtr = NULL;
AppleUSBEHCITTInfo * ttiPtr = NULL;
IOReturn err;
UInt32 currentToggle = 0;
if (_rootHubFuncAddress == functionAddress)
{
return RootHubStartTimer32(pollingRate);
}
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::+UIMCreateInterruptEndpoint (%d, %d, %s, %s, %d, %d)", this, functionAddress, endpointNumber,
(direction == kUSBIn) ? "in" : "out",
(speed == kUSBDeviceSpeedLow) ? "lo" : (speed == kUSBDeviceSpeedFull) ? "full" : "high", maxPacketSize, pollingRate);
if( (speed == kUSBDeviceSpeedLow) && (maxPacketSize > 8) )
{
USBLog (1, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint - incorrect max packet size (%d) for low speed", this, maxPacketSize);
return kIOReturnBadArgument;
}
if (pollingRate == 0)
return kIOReturnBadArgument;
pEP = FindInterruptEndpoint(functionAddress, endpointNumber, direction, &temp);
if ( pEP != NULL )
{
IOReturn ret;
USBLog(3, "AppleUSBEHCI[%p]: UIMCreateInterruptEndpoint endpoint already existed -- deleting it", this);
currentToggle = USBToHostLong(pEP->GetSharedLogical()->qTDFlags) & (kEHCITDFlags_DT);
if ( currentToggle != 0)
{
USBLog(6,"AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint: Preserving a data toggle of 1 before of the EP that we are going to delete!", this);
}
ret = UIMDeleteEndpoint(functionAddress, endpointNumber, direction);
if ( ret != kIOReturnSuccess)
{
USBLog(3, "AppleUSBEHCI[%p]: UIMCreateInterruptEndpoint deleting endpoint returned 0x%x", this, ret);
return ret;
}
}
else
{
USBLog(5, "AppleUSBEHCI[%p]: UIMCreateInterruptEndpoint endpoint does NOT exist (this is normal)", this);
}
pEP = MakeEmptyIntEndPoint(functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort, direction);
if (pEP == NULL)
{
USBError(1, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint - could not create empty endpoint", this);
return kIOReturnNoResources;
}
pEP->_maxPacketSize = maxPacketSize;
pEP->_bInterval = pollingRate; pEP->GetSharedLogical()->qTDFlags |= HostToUSBLong(currentToggle);
if (speed == kUSBDeviceSpeedHigh)
{
if (pollingRate > 16)
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint - invalid polling rate (%d) for HS endpoint", this, pollingRate);
pollingRate = 16;
}
pEP->_pollingRate = 1 << (pollingRate-1);
}
else
{
pEP->_pollingRate = pollingRate;
if (highSpeedHub)
{
hiPtr = AppleUSBEHCIHubInfo::FindHubInfo(_hsHubs, highSpeedHub);
if (!hiPtr)
{
USBLog (1, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint - no hub in list", this);
return kIOReturnInternalError;
}
ttiPtr = hiPtr->GetTTInfo(highSpeedPort);
if (!ttiPtr)
{
USBLog (1, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint - no TT infoavailable", this);
return kIOReturnInternalError;
}
}
else
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint - classic speed endpoint with no highSpeedHub - invalid!", this);
DeallocateED(pEP);
return kIOReturnBadArgument;
}
}
err = AllocateInterruptBandwidth(pEP, ttiPtr);
if (err)
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint - AllocateInterruptBandwidth returned err(%p)", this, (void*)err);
DeallocateED(pEP);
return err;
}
if(_greatestPeriod < (pEP->_startFrame + 1))
{
_greatestPeriod = pEP->_startFrame + 1;
}
linkInterruptEndpoint(pEP);
USBLog(7, "AppleUSBEHCI[%p]::-UIMCreateInterruptEndpoint", this);
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::UIMCreateInterruptTransfer(IOUSBCommand* command)
{
IOReturn status = kIOReturnSuccess;
AppleEHCIQueueHead * pEDQueue;
IOUSBCompletion completion = command->GetUSLCompletion();
IOMemoryDescriptor* buffer = command->GetBuffer();
short direction = command->GetDirection();
USBLog(7, "AppleUSBEHCI[%p]::UIMCreateInterruptTransfer - adr=%d:%d cbp=%p:%qx br=%s cback=[%p:%p:%p])", this,
command->GetAddress(), command->GetEndpoint(), command->GetBuffer(),
(uint64_t)command->GetBuffer()->getLength(), command->GetBufferRounding()?"YES":"NO",
completion.action, completion.target,
completion.parameter);
if (_rootHubFuncAddress == command->GetAddress())
{
IODMACommand *dmaCommand = command->GetDMACommand();
IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor*)dmaCommand->getMemoryDescriptor() : NULL;
if (memDesc)
{
USBLog(3, "AppleUSBEHCI[%p]::UIMCreateInterruptTransfer - root hub interrupt transfer - clearing unneeded memDesc (%p) from dmaCommand (%p)", this, memDesc, dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
if (command->GetEndpoint() == 1)
{
status = RootHubQueueInterruptRead(buffer, command->GetReqCount(), completion);
}
else
{
Complete(completion, kIOUSBEndpointNotFound, command->GetReqCount());
status = kIOUSBEndpointNotFound;
}
return status;
}
pEDQueue = FindInterruptEndpoint(command->GetAddress(), command->GetEndpoint(), direction, NULL);
if (!pEDQueue)
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateInterruptTransfer - Endpoint not found", this);
USBTrace( kUSBTEHCI, kTPEHCICreateInterruptTransfer , (uintptr_t)this, command->GetEndpoint(), kIOUSBEndpointNotFound, 1 );
return kIOUSBEndpointNotFound;
}
if ( pEDQueue->_maxPacketSize == 0 )
{
USBLog(6, "AppleUSBEHCI[%p]::UIMCreateInterruptTransfer - maxPacketSize is 0, returning kIOUSBNotEnoughBandwidth", this);
return kIOReturnNoBandwidth;
}
status = allocateTDs(pEDQueue, command, buffer, command->GetBuffer()->getLength(), direction, false );
if(status != kIOReturnSuccess)
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateInterruptTransfer ((adr=%d:%d(%s)) allocateTDs returned error 0x%x", this, command->GetAddress(), command->GetEndpoint(), direction == kUSBIn ? "in" : "out", status);
USBTrace( kUSBTEHCI, kTPEHCICreateInterruptTransfer , (uintptr_t)this, command->GetAddress(), status, 2 );
}
else
{
EnablePeriodicSchedule(false);
}
return status;
}
IOReturn
AppleUSBEHCI::UIMCreateInterruptTransfer(
short functionAddress,
short endpointNumber,
IOUSBCompletion completion,
IOMemoryDescriptor * CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
#pragma unused (functionAddress, endpointNumber, completion, CBP, bufferRounding, bufferSize, direction)
USBLog(1, "AppleUSBEHCI[%p]UIMCreateInterruptTransfer- calling the wrong method!", this);
return kIOReturnIPCError;
}
void
AppleUSBEHCI::HaltInterruptEndpoint(AppleEHCIQueueHead *pED)
{
if (!(USBToHostLong(pED->GetSharedLogical()->qTDFlags) & kEHCITDStatus_Halted))
{
USBLog(6, "AppleUSBEHCI[%p]::HaltInterruptEndpoint - unlinking, halting, and relinking (%p)", this, pED);
unlinkIntEndpoint(pED);
pED->GetSharedLogical()->qTDFlags |= HostToUSBLong(kEHCITDStatus_Halted);
pED->GetSharedLogical()->qTDFlags &= ~(HostToUSBLong(kEHCITDStatus_Active));
linkInterruptEndpoint(pED);
}
}
static IOUSBControllerListElement*
FindIntEDqueue(IOUSBControllerListElement *start, UInt8 pollingRate)
{
AppleEHCIQueueHead *pQH;
IOUSBControllerIsochListElement *pIsoch = OSDynamicCast(IOUSBControllerIsochListElement, start);
if (pIsoch)
{
while (OSDynamicCast(IOUSBControllerIsochListElement, start->_logicalNext))
{
pIsoch = OSDynamicCast(IOUSBControllerIsochListElement, start->_logicalNext);
start = start->_logicalNext;
}
start = start->_logicalNext;
}
if (!start)
return pIsoch;
pQH = OSDynamicCast(AppleEHCIQueueHead, start);
if(pQH && (pQH->NormalizedPollingRate() < pollingRate))
{
return pIsoch;
}
while(start->_logicalNext != NULL)
{
pQH = OSDynamicCast(AppleEHCIQueueHead, pQH->_logicalNext);
if(pQH && (pQH->NormalizedPollingRate() < pollingRate))
{
break;
}
start = (IOUSBControllerListElement*)start->_logicalNext;
}
return start;
}
void
AppleUSBEHCI::linkInterruptEndpoint(AppleEHCIQueueHead *pEP)
{
short pollingRate;
UInt16 maxPacketSize;
int offset;
IOUSBControllerListElement *pLE;
UInt32 newHorizPtr;
maxPacketSize = pEP->_maxPacketSize;
offset = pEP->_startFrame;
pollingRate = pEP->NormalizedPollingRate();
USBLog(7, "AppleUSBEHCI[%p]::linkInterruptEndpoint %p rate %d", this, pEP, pollingRate);
pEP->print(7, this);
newHorizPtr = pEP->GetPhysicalAddrWithType();
while( offset < kEHCIPeriodicListEntries)
{
pLE = FindIntEDqueue(GetPeriodicListLogicalEntry(offset), pollingRate);
if(pLE == NULL)
{ if(pEP->_logicalNext == NULL)
{
pEP->_logicalNext = GetPeriodicListLogicalEntry(offset);
pEP->SetPhysicalLink(GetPeriodicListPhysicalEntry(offset));
}
else if (pEP->_logicalNext != GetPeriodicListLogicalEntry(offset))
{
USBError(1, "The Apple EHCI driver has found an endpoint with an incorrect link at the begining.");
}
SetPeriodicListEntry(offset, pEP);
USBLog(7, "AppleUSBEHCI[%p]::linkInterruptEndpoint - inserted at top of list %d - next logical (%p) next physical (%p)", this, offset, pEP->_logicalNext, (void*)pEP->GetPhysicalLink());
}
else if (pEP != pLE)
{
if(pEP->_logicalNext == NULL)
{
pEP->_logicalNext = pLE->_logicalNext;
pEP->SetPhysicalLink(pLE->GetPhysicalLink());
}
else if (pEP->_logicalNext != pLE->_logicalNext)
{
USBError(1, "The Apple EHCI driver has found an endpoint with an incorrect link in the middle.");
}
pLE->_logicalNext = pEP;
pLE->SetPhysicalLink(newHorizPtr);
USBLog(7, "AppleUSBEHCI[%p]::linkInterruptEndpoint - inserted into list %d - next logical (%p) next physical (%p)", this, offset, pEP->_logicalNext, (void*)pEP->GetPhysicalLink());
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::linkInterruptEndpoint - (%p) already linked into %d (%p)", this, pEP, offset, pLE);
}
offset += pollingRate;
}
_periodicEDsInSchedule++;
}
void
AppleUSBEHCI::unlinkIntEndpoint(AppleEHCIQueueHead * pED)
{
int i;
IOUSBControllerListElement * pListElem;
int maxPacketSize;
Boolean foundED = false;
short pollingRate;
pollingRate = pED->NormalizedPollingRate();
USBLog(7, "+AppleUSBEHCI[%p]::unlinkIntEndpoint(%p) pollingRate(%d)", this, pED, pollingRate);
maxPacketSize = (USBToHostLong(pED->GetSharedLogical()->flags) & kEHCIEDFlags_MPS) >> kEHCIEDFlags_MPSPhase;
for(i= pED->_startFrame; i < kEHCIPeriodicListEntries; i += pollingRate)
{
pListElem = GetPeriodicListLogicalEntry(i);
if (pED == pListElem)
{
SetPeriodicListEntry(i, pED->_logicalNext);
foundED = true;
USBLog(7, "AppleUSBEHCI[%p]::unlinkIntEndpoint- found ED at top of list %d, new logical=%p, new physical=0x%x", this, i, GetPeriodicListLogicalEntry(i), GetPeriodicListPhysicalEntry(i));
}
else
{
while(pListElem != NULL)
{
if (pListElem->_logicalNext == pED)
{
pListElem->_logicalNext = pED->_logicalNext;
pListElem->SetPhysicalLink(pED->GetPhysicalLink());
foundED = true;
USBLog(7, "AppleUSBEHCI[%p]::unlinkIntEndpoint- found ED in list %d, new logical=%p, new physical=%p", this, i, pED->_logicalNext, (void*)pED->GetPhysicalLink());
break;
}
pListElem = OSDynamicCast(IOUSBControllerListElement, pListElem->_logicalNext);
}
if (pListElem == NULL)
{
USBLog(7, "AppleUSBEHCI[%p]::unlinkIntEndpoint endpoint not found in list %d", this, i);
}
}
}
IOSleep(1); pED->_logicalNext = NULL;
if (foundED)
_periodicEDsInSchedule--;
USBLog(7, "-AppleUSBEHCI[%p]::unlinkIntEndpoint(%p)", this, pED);
}
#pragma mark Isoch
IOReturn
AppleUSBEHCI::UIMCreateIsochEndpoint(short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction)
{
#pragma unused (functionAddress, endpointNumber, maxPacketSize, direction)
USBError(1, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint -- old version called with no split params", this);
return kIOReturnIPCError;
}
IOReturn
AppleUSBEHCI::UIMCreateIsochEndpoint(short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
#pragma unused (functionAddress, endpointNumber, maxPacketSize, direction, highSpeedHub, highSpeedPort)
USBError(1, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint -- old version called with no interval", this);
return kIOReturnIPCError;
}
IOReturn
AppleUSBEHCI::UIMCreateIsochEndpoint(short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction,
USBDeviceAddress highSpeedHub,
int highSpeedPort,
UInt8 interval)
{
AppleEHCIIsochEndpoint *pEP;
UInt32 curMaxPacketSize;
AppleUSBEHCIHubInfo *hiPtr = NULL;
AppleUSBEHCITTInfo *ttiPtr = NULL;
UInt32 xtraRequest;
UInt32 decodedInterval;
IOReturn err;
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint(%d, %d, %d, %d, %d, %d)", this, functionAddress, endpointNumber, (uint32_t)maxPacketSize, direction, highSpeedHub, highSpeedPort);
if (highSpeedHub == 0)
{
if ((interval == 0) || (interval > 16))
{
USBError(1, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint: bad interval %d", this, interval);
return kIOReturnBadArgument;
}
decodedInterval = (1 << (interval - 1));
}
else
{
hiPtr = AppleUSBEHCIHubInfo::FindHubInfo(_hsHubs, highSpeedHub);
if (!hiPtr)
{
USBLog (1, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint - No hub in list", this);
return kIOReturnInternalError;
}
ttiPtr = hiPtr->GetTTInfo(highSpeedPort);
if (!ttiPtr)
{
USBLog (1, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint - No TTI in list", this);
return kIOReturnInternalError;
}
decodedInterval = interval;
}
pEP = OSDynamicCast(AppleEHCIIsochEndpoint, FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL));
if (pEP)
{
USBLog(5,"AppleUSBEHCI[%p]::UIMCreateIsochEndpoint endpoint already exists, attempting to change maxPacketSize to %d", this, (uint32_t)maxPacketSize);
curMaxPacketSize = pEP->maxPacketSize;
if (maxPacketSize == curMaxPacketSize)
{
USBLog(4, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint maxPacketSize (%d) the same, no change", this, (uint32_t)maxPacketSize);
return kIOReturnSuccess;
}
ReturnIsochBandwidth(pEP);
pEP->maxPacketSize = maxPacketSize;
if(maxPacketSize >1024)
{
pEP->mult = ((maxPacketSize-1)/1024)+1;
pEP->oneMPS = (maxPacketSize+(pEP->mult-1))/pEP->mult;
}
else
{
pEP->mult = 1;
pEP->oneMPS = maxPacketSize;
}
}
else
{
pEP = OSDynamicCast(AppleEHCIIsochEndpoint, CreateIsochronousEndpoint(functionAddress, endpointNumber, direction));
if (pEP == NULL)
return kIOReturnNoMemory;
pEP->highSpeedHub = highSpeedHub;
pEP->highSpeedPort = highSpeedPort;
pEP->interval = decodedInterval;
if (ttiPtr)
{
pEP->_speed = kUSBDeviceSpeedFull;
}
else
{
pEP->_speed = kUSBDeviceSpeedHigh;
if(maxPacketSize >1024)
{
pEP->mult = ((maxPacketSize-1)/1024)+1;
pEP->oneMPS = (maxPacketSize+(pEP->mult-1))/pEP->mult;
}
else
{
pEP->mult = 1;
pEP->oneMPS = maxPacketSize;
}
USBLog(5,"AppleUSBEHCI[%p]::UIMCreateIsochEndpoint high speed 2 size %d, mult %d: %d", this, (uint32_t)maxPacketSize, pEP->mult, pEP->oneMPS);
}
pEP->maxPacketSize = maxPacketSize;
pEP->inSlot = kEHCIPeriodicListEntries+1;
pEP->ttiPtr = ttiPtr;
}
err = AllocateIsochBandwidth(pEP, ttiPtr);
if (err)
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint - AllocateIsochBandwidth returned err(%p)", this, (void*)err);
pEP->maxPacketSize = 0;
DeleteIsochEP(pEP);
}
return err;
}
IOReturn
AppleUSBEHCI::AbortIsochEP(AppleEHCIIsochEndpoint* pEP)
{
UInt32 slot;
IOReturn err;
IOUSBControllerIsochListElement *pTD;
uint64_t timeStamp;
if (pEP->deferredQueue || pEP->toDoList || pEP->doneQueue || pEP->activeTDs || pEP->onToDoList || pEP->scheduledTDs || pEP->deferredTDs || pEP->onReversedList || pEP->onDoneQueue)
{
USBLog(6, "+AppleUSBEHCI[%p]::AbortIsochEP[%p] - start - _outSlot (0x%x) pEP->inSlot (0x%x) activeTDs (%d) onToDoList (%d) todo (%p) deferredTDs (%d) deferred(%p) scheduledTDs (%d) onProducerQ (%d) consumer (%d) producer (%d) onReversedList (%d) onDoneQueue (%d) doneQueue (%p)", this, pEP, _outSlot, (uint32_t)pEP->inSlot, (uint32_t)pEP->activeTDs, (uint32_t)pEP->onToDoList, pEP->toDoList, (uint32_t)pEP->deferredTDs, pEP->deferredQueue, (uint32_t)pEP->scheduledTDs, (uint32_t)pEP->onProducerQ, (uint32_t)_consumerCount, (uint32_t)_producerCount, (uint32_t)pEP->onReversedList, (uint32_t)pEP->onDoneQueue, pEP->doneQueue);
}
USBLog(7, "AppleUSBEHCI[%p]::AbortIsochEP (%p)", this, pEP);
_inAbortIsochEP = true;
pEP->aborting = true;
timeStamp = mach_absolute_time();
while (_filterInterruptActive)
;
err = scavengeIsocTransactions(NULL, false);
if (err)
{
USBLog(1, "AppleUSBEHCI[%p]::AbortIsochEP - err (0x%x) from scavengeIsocTransactions", this, err);
USBTrace( kUSBTEHCI, kTPEHCIAbortIsochEP, (uintptr_t)this, err, 0, 1 );
}
if (pEP->deferredQueue || pEP->toDoList || pEP->doneQueue || pEP->activeTDs || pEP->onToDoList || pEP->scheduledTDs || pEP->deferredTDs || pEP->onReversedList || pEP->onDoneQueue)
{
USBLog(6, "+AppleUSBEHCI[%p]::AbortIsochEP[%p] - after scavenge - _outSlot (0x%x) pEP->inSlot (0x%x) activeTDs (%d) onToDoList (%d) todo (%p) deferredTDs (%d) deferred(%p) scheduledTDs (%d) onProducerQ (%d) consumer (%d) producer (%d) onReversedList (%d) onDoneQueue (%d) doneQueue (%p)", this, pEP, _outSlot, (uint32_t)pEP->inSlot, (uint32_t)pEP->activeTDs, (uint32_t)pEP->onToDoList, pEP->toDoList, (uint32_t)pEP->deferredTDs, pEP->deferredQueue,(uint32_t) pEP->scheduledTDs, (uint32_t)pEP->onProducerQ, (uint32_t)_consumerCount, (uint32_t)_producerCount, (uint32_t)pEP->onReversedList, (uint32_t)pEP->onDoneQueue, pEP->doneQueue);
}
if ((_outSlot < kEHCIPeriodicListEntries) && (pEP->inSlot < kEHCIPeriodicListEntries))
{
bool stopAdvancing = false;
UInt32 stopSlot;
slot = _outSlot;
stopSlot = (pEP->inSlot+1) & (kEHCIPeriodicListEntries-1);
while (slot != stopSlot)
{
IOUSBControllerListElement *thing;
IOUSBControllerListElement *nextThing;
IOUSBControllerListElement *prevThing;
UInt32 nextSlot;
nextSlot = (slot+1) & (kEHCIPeriodicListEntries-1);
thing = GetPeriodicListLogicalEntry(slot);
prevThing = NULL;
if (thing == NULL && (nextSlot != pEP->inSlot))
_outSlot = nextSlot;
while(thing != NULL)
{
nextThing = (IOUSBControllerListElement*)thing->_logicalNext;
pTD = OSDynamicCast(IOUSBControllerIsochListElement, thing);
if(pTD)
{
if (pTD->_pEndpoint == pEP)
{
if (prevThing)
{
prevThing->_logicalNext = thing->_logicalNext;
prevThing->SetPhysicalLink(thing->GetPhysicalLink());
thing = prevThing; }
else
{
SetPeriodicListEntry(slot, nextThing);
thing = NULL; if (nextThing == NULL)
{
if (!stopAdvancing)
{
USBLog(7, "AppleUSBEHCI[%p]::AbortIsochEP(%p) - advancing _outslot from 0x%x to 0x%x", this, pEP, _outSlot, (uint32_t)nextSlot);
_outSlot = nextSlot;
}
else
{
USBLog(6, "AppleUSBEHCI[%p]::AbortIsochEP(%p) - would have advanced _outslot from 0x%x to 0x%x", this, pEP, _outSlot, (uint32_t)nextSlot);
}
}
}
err = pTD->UpdateFrameList(*(AbsoluteTime*)&timeStamp); OSDecrementAtomic( &(pEP->scheduledTDs));
if ( pEP->scheduledTDs < 0 )
{
USBLog(1, "AppleUSBEHCI[%p]::AbortIsochEP (%p) - scheduleTDs is negative! (%d)", this, pEP, (uint32_t)pEP->scheduledTDs);
USBTrace( kUSBTEHCI, kTPEHCIAbortIsochEP, (uintptr_t)this, (uintptr_t)pEP, (uint32_t)pEP->scheduledTDs, 2 );
}
PutTDonDoneQueue(pEP, pTD, true );
}
else if (pTD->_pEndpoint == NULL)
{
USBLog(1, "AppleUSBEHCI[%p]::AbortIsochEP (%p) - NULL endpoint in pTD %p", this, pEP, pTD);
USBTrace( kUSBTEHCI, kTPEHCIAbortIsochEP, (uintptr_t)this, (uintptr_t)pEP, (uintptr_t)pTD, 3 );
}
else
{
stopAdvancing = true;
USBLog(7, "AppleUSBEHCI[%p]::AbortIsochEP (%p) - a different EP in play (%p) - stop advancing", this, pEP, pTD->_pEndpoint);
}
}
else
{
break;
}
prevThing = thing;
thing = nextThing;
}
slot = nextSlot;
}
}
pTD = GetTDfromToDoList(pEP);
while (pTD)
{
err = pTD->UpdateFrameList(*(AbsoluteTime*)&timeStamp);
PutTDonDoneQueue(pEP, pTD, true);
pTD = GetTDfromToDoList(pEP);
}
if (pEP->scheduledTDs == 0)
{
pEP->firstAvailableFrame = 0;
pEP->inSlot = kEHCIPeriodicListEntries + 1;
}
_inAbortIsochEP = false;
IOSleep(1);
pEP->accumulatedStatus = kIOReturnAborted;
ReturnIsochDoneQueue(pEP);
pEP->accumulatedStatus = kIOReturnSuccess;
if (pEP->deferredQueue || pEP->toDoList || pEP->doneQueue || pEP->activeTDs || pEP->onToDoList || pEP->scheduledTDs || pEP->deferredTDs || pEP->onReversedList || pEP->onDoneQueue)
{
USBLog(1, "+AppleUSBEHCI[%p]::AbortIsochEP[%p] - done - _outSlot (0x%x) pEP->inSlot (0x%x) activeTDs (%d) onToDoList (%d) todo (%p) deferredTDs (%d) deferred(%p) scheduledTDs (%d) onProducerQ (%d) consumer (%d) producer (%d) onReversedList (%d) onDoneQueue (%d) doneQueue (%p)", this, pEP, _outSlot, (uint32_t)pEP->inSlot, (uint32_t)pEP->activeTDs, (uint32_t)pEP->onToDoList, pEP->toDoList, (uint32_t)pEP->deferredTDs, pEP->deferredQueue, (uint32_t)pEP->scheduledTDs, (uint32_t)pEP->onProducerQ, (uint32_t)_consumerCount, (uint32_t)_producerCount, (uint32_t)pEP->onReversedList, (uint32_t)pEP->onDoneQueue, pEP->doneQueue);
USBTrace( kUSBTEHCI, kTPEHCIAbortIsochEP, (uintptr_t)pEP, _outSlot, (uint32_t)pEP->inSlot, 4 );
USBTrace( kUSBTEHCI, kTPEHCIAbortIsochEP, (uint32_t)pEP->activeTDs, (uint32_t)pEP->onToDoList, (uintptr_t)pEP->toDoList, 5 );
USBTrace( kUSBTEHCI, kTPEHCIAbortIsochEP, (uint32_t)pEP->deferredTDs, (uintptr_t)pEP->deferredQueue, (uint32_t)pEP->scheduledTDs, 6 );
USBTrace( kUSBTEHCI, kTPEHCIAbortIsochEP, (uint32_t)pEP->onProducerQ, (uint32_t)_consumerCount, (uint32_t)_producerCount, 7 );
USBTrace( kUSBTEHCI, kTPEHCIAbortIsochEP, (uint32_t)pEP->onReversedList, (uint32_t)pEP->onDoneQueue, (uintptr_t)pEP->doneQueue, 8 );
}
else
{
USBLog(6, "-AppleUSBEHCI[%p]::AbortIsochEP[%p] - done - all clean - _outSlot (0x%x), pEP->inSlot (0x%x)", this, pEP, _outSlot, pEP->inSlot);
}
pEP->aborting = false;
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::DeleteIsochEP(AppleEHCIIsochEndpoint *pEP)
{
IOUSBControllerIsochEndpoint* curEP, *prevEP;
UInt32 currentMaxPacketSize;
USBLog(7, "AppleUSBEHCI[%p]::DeleteIsochEP (%p)", this, pEP);
if (pEP->activeTDs)
{
USBLog(6, "AppleUSBEHCI[%p]::DeleteIsochEP- there are still %d active TDs - aborting", this, (uint32_t)pEP->activeTDs);
AbortIsochEP(pEP);
if (pEP->activeTDs)
{
USBError(1, "AppleUSBEHCI[%p]::DeleteIsochEP- after abort there are STILL %d active TDs", this, (uint32_t) pEP->activeTDs);
}
}
prevEP = NULL;
curEP = _isochEPList;
while (curEP)
{
if (curEP == pEP)
{
if (prevEP)
prevEP->nextEP = curEP->nextEP;
else
_isochEPList = curEP->nextEP;
break;
}
prevEP = curEP;
curEP = curEP->nextEP;
}
currentMaxPacketSize = pEP->maxPacketSize;
ReturnIsochBandwidth(pEP);
DeallocateIsochEP(pEP);
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::CreateHSIsochTransfer(AppleEHCIIsochEndpoint * pEP, IOUSBIsocCommand * command)
{
UInt32 bufferSize;
AppleEHCIIsochTransferDescriptor *pNewITD = NULL;
IOByteCount transferOffset;
IOByteCount saveTransferOffset;
UInt32 buffPtrSlot, transfer, frameNumberIncrease;
unsigned i,j;
USBPhysicalAddress32 *buffP, *buffHighP;
UInt32 *transactionPtr = 0;
UInt32 *savedTransactionPtr = 0;
UInt32 pageOffset=0;
UInt32 page;
UInt32 frames;
UInt32 trLen;
IOPhysicalAddress dmaStartAddr;
UInt32 dmaAddrHighBits;
IOByteCount segLen;
bool lowLatency = command->GetLowLatency();
UInt32 updateFrequency = command->GetUpdateFrequency();
IOUSBIsocFrame * pFrames = command->GetFrameList();
IOUSBLowLatencyIsocFrame * pLLFrames = (IOUSBLowLatencyIsocFrame *)pFrames;
UInt32 transferCount = command->GetNumFrames();
UInt64 frameNumberStart = command->GetStartFrame();
IODMACommand * dmaCommand = command->GetDMACommand();
UInt64 offset;
IODMACommand::Segment64 segments;
UInt32 numSegments;
UInt32 transfersPerTD;
UInt32 numberOfTDs = 0;
UInt32 baseTransferIndex;
UInt32 epInterval;
IOReturn status;
epInterval = pEP->interval;
transferOffset = 0;
saveTransferOffset = 0;
transfersPerTD = (epInterval >= 8 ? 1 : (8/epInterval));
frameNumberIncrease = (epInterval <= 8 ? 1 : epInterval/8);
USBLog(7,"AppleUSBEHCI[%p]::CreateHSIsochTransfer transfersPerTD will be %d, frameNumberIncrease = %d", this, (uint32_t)transfersPerTD, (uint32_t)frameNumberIncrease);
if ( frameNumberIncrease > 1 )
{
epInterval = 8;
}
if (transferCount % transfersPerTD != 0)
{
USBLog(3,"AppleUSBEHCI[%p]::CreateHSIsochTransfer Isoch -- incomplete final TD in transfer, command->GetNumFrames() is %d, pEP->Interval is %d and so transfersPerTD is %d",
this, (int ) command->GetNumFrames(), (int ) epInterval, (int ) transfersPerTD);
return kIOReturnBadArgument;
}
for (baseTransferIndex = 0; baseTransferIndex < transferCount; baseTransferIndex += transfersPerTD)
{
bufferSize = 0;
for (transfer = 0; transfer < transfersPerTD; transfer++)
{
UInt32 microFramePayload = (lowLatency ? pLLFrames[baseTransferIndex + transfer].frReqCount : pFrames[baseTransferIndex + transfer].frReqCount);
if (microFramePayload > kUSBMaxHSIsocFrameReqCount)
{
USBLog(3,"AppleUSBEHCI[%p]::CreateHSIsochTransfer Isoch frame too big %d", this, (int )microFramePayload);
return kIOReturnBadArgument;
}
bufferSize += microFramePayload;
if (lowLatency)
{
pLLFrames[baseTransferIndex + transfer].frStatus = command->GetIsRosettaClient() ? (IOReturn) OSSwapInt32(kUSBLowLatencyIsochTransferKey) : (IOReturn) kUSBLowLatencyIsochTransferKey;
}
}
pNewITD = AllocateITD();
USBLog(7, "AppleUSBEHCI[%p]::CreateHSIsochTransfer - new iTD %p", this, pNewITD);
if (pNewITD == NULL)
{
USBLog(1,"AppleUSBEHCI[%p]::CreateHSIsochTransfer Could not allocate a new iTD", this);
USBTrace( kUSBTEHCI, kTPEHCICreateHSIsochTransfer, (uintptr_t)this, kIOReturnNoMemory, 0, 0);
return kIOReturnNoMemory;
}
pNewITD->_lowLatency = lowLatency;
pNewITD->_framesInTD = 0;
pEP->firstAvailableFrame += frameNumberIncrease;
buffP = &pNewITD->GetSharedLogical()->bufferPage0;
buffHighP = &pNewITD->GetSharedLogical()->extBufferPage0;
for (buffPtrSlot=0; buffPtrSlot < kEHCI_ITDMaxPhysicalPages; buffPtrSlot++)
{
buffP[buffPtrSlot] = 0;
buffHighP[buffPtrSlot] = 0;
}
buffPtrSlot=0;
transferOffset = saveTransferOffset;
while ((buffPtrSlot < kEHCI_ITDMaxPhysicalPages) && (bufferSize != 0))
{
GET_NEXT_BUFFPTR();
USBLog(7, "AppleUSBEHCI[%p]::CreateHSIsochTransfer - Addr (0x%x) Length (%d) BufferSize (%d)", this, (uint32_t)dmaStartAddr, (uint32_t)segLen, (uint32_t)bufferSize);
if (buffPtrSlot == 0)
{
buffP[buffPtrSlot] = HostToUSBLong( dmaStartAddr & kEHCIPageMask);
buffHighP[buffPtrSlot] = HostToUSBLong( dmaAddrHighBits );
USBLog(7, "AppleUSBEHCI[%p]::CreateHSIochTransfer - using buffer slot %d - buffP 0x%x buffHighP 0x%x", this, (int)buffPtrSlot, (int)buffP[buffPtrSlot], (int)buffHighP[buffPtrSlot]);
buffPtrSlot++;
}
else
{
if ((buffP[buffPtrSlot-1] != HostToUSBLong( dmaStartAddr & kEHCIPageMask)) || (buffHighP[buffPtrSlot-1] != HostToUSBLong( dmaAddrHighBits )))
{
buffP[buffPtrSlot] = HostToUSBLong( dmaStartAddr & kEHCIPageMask);
buffHighP[buffPtrSlot] = HostToUSBLong( dmaAddrHighBits );
USBLog(7, "AppleUSBEHCI[%p]::CreateHSIochTransfer - using buffer slot %d - buffP 0x%x buffHighP 0x%x", this, (int)buffPtrSlot, (int)buffP[buffPtrSlot], (int)buffHighP[buffPtrSlot]);
buffPtrSlot++;
}
}
pageOffset = dmaStartAddr & kEHCIPageOffsetMask;
ADJUST_SEGMENT_LENGTH(pageOffset);
transferOffset += segLen;
bufferSize -= segLen;
}
if ((buffPtrSlot >= kEHCI_ITDMaxPhysicalPages) && (bufferSize != 0))
{
USBError(1, "AppleUSBEHCI[%p]::CreateHSIochTransfer - ran out of physical page slots", this);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
panic("EHCI: HS Isoch Disjoint!\n");
#endif
return kIOReturnInternalError;
}
page = 0;
transferOffset = saveTransferOffset;
transactionPtr = &pNewITD->GetSharedLogical()->Transaction0;
for (transfer = 0; transfer < transfersPerTD; transfer++)
{
pNewITD->_framesInTD++;
trLen = (lowLatency ? pLLFrames[baseTransferIndex + transfer].frReqCount : pFrames[baseTransferIndex + transfer].frReqCount);
if (trLen)
{
GET_NEXT_BUFFPTR();
pageOffset = dmaStartAddr & kEHCIPageOffsetMask;
ADJUST_SEGMENT_LENGTH(pageOffset);
for (buffPtrSlot=0; buffPtrSlot < kEHCI_ITDMaxPhysicalPages; buffPtrSlot++)
{
if ((buffP[buffPtrSlot] == HostToUSBLong( dmaStartAddr & kEHCIPageMask)) && (buffHighP[buffPtrSlot] == HostToUSBLong( dmaAddrHighBits )))
{
page = buffPtrSlot;
USBLog(7, "AppleUSBEHCI[%p]::CreateHSIochTransfer - using physical page in slot %d for transfer %d in ITD %p", this, (int)page, (int)transfer, pNewITD);
break;
}
}
if (buffPtrSlot >= kEHCI_ITDMaxPhysicalPages)
{
USBError(1, "AppleUSBEHCI[%p]::CreateHSIochTransfer - could not find the correct physical page slot for buffP 0x%x buffHighP 0x%x", this, HostToUSBLong( dmaStartAddr & kEHCIPageMask), HostToUSBLong( dmaAddrHighBits ));
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
panic("EHCI: HS Isoch Disjoint (2)!\n");
#endif
return kIOReturnInternalError;
}
}
else
{
page = 0;
pageOffset = 0;
}
USBLog(7, "AppleUSBEHCI[%p]::CreateHSIsochTransfer - baseTransferIndex: %d, microFrame: %d, frameIndex: %d, interval %d", this, (uint32_t)baseTransferIndex, (uint32_t) transfer, (uint32_t)(baseTransferIndex + transfer), (uint32_t)epInterval);
USBLog(7, "AppleUSBEHCI[%p]::CreateHSIsochTransfer - forming transaction length (%d), pageOffset (0x%x), page (%d)", this, (uint32_t)trLen, (uint32_t)pageOffset, (uint32_t)page);
*transactionPtr = HostToUSBLong(kEHCI_ITDStatus_Active | (trLen<< kEHCI_ITDTr_LenPhase) |
(pageOffset << kEHCI_ITDTr_OffsetPhase) | (page << kEHCI_ITDTr_PagePhase) );
savedTransactionPtr = transactionPtr;
transactionPtr += epInterval;
transferOffset += trLen;
}
saveTransferOffset = transferOffset; if (lowLatency && (updateFrequency > 0) && (updateFrequency <= 8 ))
{
if (numberOfTDs % updateFrequency == 0)
{
USBLog(7, "AppleUSBEHCI[%p]::CreateHSIsochTransfer - Setting IOC bit on TD baseTransferIndex: %d, microFrame: %d, frameIndex: %d, interval %d", this, (uint32_t)baseTransferIndex, (uint32_t) transfer, (uint32_t)(baseTransferIndex + transfer), (uint32_t)epInterval);
*savedTransactionPtr |= HostToUSBLong(kEHCI_ITDTr_IOC);
}
}
pNewITD->_pFrames = pFrames; pNewITD->_frameNumber = frameNumberStart;
pNewITD->_frameIndex = baseTransferIndex;
pNewITD->_completion.action = NULL; pNewITD->_pEndpoint = pEP;
pNewITD->_requestFromRosettaClient = command->GetIsRosettaClient();
pNewITD->GetSharedLogical()->bufferPage0 |= HostToUSBLong((pEP->functionAddress << kEHCI_ITDBuf_FnAddrPhase) | (pEP->endpointNumber << kEHCI_ITDBuf_EPPhase) );
pNewITD->GetSharedLogical()->bufferPage1 |= HostToUSBLong( (pEP->oneMPS << kEHCI_ITDBuf_MPSPhase) | ((pEP->direction == kUSBIn) ? (UInt32) kEHCI_ITDBuf_IO : 0) );
pNewITD->GetSharedLogical()->bufferPage2 |= HostToUSBLong( (pEP->mult << kEHCI_ITDBuf_MultPhase) );
pNewITD->print(7);
PutTDonToDoList(pEP, pNewITD);
frameNumberStart += frameNumberIncrease;
numberOfTDs++;
}
USBLog(7, "AppleUSBEHCI[%p]::CreateHSIsochTransfer - in TD (%p) setting _completion action (%p)", this, pNewITD, pNewITD->_completion.action);
pNewITD->_completion = command->GetUSLCompletion();
if (savedTransactionPtr)
*savedTransactionPtr |= HostToUSBLong(kEHCI_ITDTr_IOC);
AddIsocFramesToSchedule(pEP);
EnablePeriodicSchedule(false);
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::CreateSplitIsochTransfer(AppleEHCIIsochEndpoint * pEP, IOUSBIsocCommand * command)
{
AppleEHCISplitIsochTransferDescriptor *pNewSITD=NULL, *pDummySITD=NULL;
IOByteCount transferOffset = 0;
UInt32 bufferSize;
UInt8 startSplitFlags;
UInt8 completeSplitFlags = 0;
UInt8 transactionPosition;
UInt8 transactionCount;
UInt8 ioc = 0;
UInt32 i;
UInt32 pageOffset;
IOPhysicalAddress dmaStartAddr;
UInt32 dmaAddrHighBits;
IOByteCount segLen;
UInt32 myStatFlags;
IOPhysicalAddress prevPhysLink = kEHCITermFlag;
bool lowLatency = command->GetLowLatency();
UInt32 updateFrequency = command->GetUpdateFrequency();
IOUSBIsocFrame * pFrames = command->GetFrameList();
IOUSBLowLatencyIsocFrame * pLLFrames = (IOUSBLowLatencyIsocFrame *)pFrames;
UInt32 frameCount = command->GetNumFrames();
UInt64 frameNumberStart = command->GetStartFrame();
IODMACommand * dmaCommand = command->GetDMACommand();
UInt64 offset;
IODMACommand::Segment64 segments;
UInt32 numSegments;
IOReturn status;
USBLog(7, "EHCI::CreateSplitIsochTransfer - pEP(%p) firstAvailableFrame(%d) frameNumberStart(%d) frameCount(%d)", pEP, (int)pEP->firstAvailableFrame, (int)frameNumberStart, (int)frameCount);
bufferSize = 0;
for ( i = 0; i < frameCount; i++)
{
if (!lowLatency)
{
if (pFrames[i].frReqCount > pEP->maxPacketSize)
{
USBLog(1,"AppleUSBEHCI[%p]::CreateSplitIsochTransfer - Isoch frame (%d) too big (%d) MPS (%d)", this, (uint32_t)(i + 1), pFrames[i].frReqCount, (uint32_t)pEP->maxPacketSize);
USBTrace( kUSBTEHCI, kTPEHCICreateSplitIsochTransfer, (i + 1), pFrames[i].frReqCount, pEP->maxPacketSize, 1 );
return kIOReturnBadArgument;
}
bufferSize += pFrames[i].frReqCount;
} else
{
if (pLLFrames[i].frReqCount > kUSBMaxFSIsocEndpointReqCount)
{
USBLog(1,"AppleUSBEHCI[%p]::CreateSplitIsochTransfer(LL) - Isoch frame (%d) too big (%d) MPS (%d)", this, (uint32_t)(i + 1), pLLFrames[i].frReqCount, (uint32_t)pEP->maxPacketSize);
USBTrace( kUSBTEHCI, kTPEHCICreateSplitIsochTransfer, (i + 1), pLLFrames[i].frReqCount, pEP->maxPacketSize, 2 );
return kIOReturnBadArgument;
}
bufferSize += pLLFrames[i].frReqCount;
pLLFrames[i].frStatus = command->GetIsRosettaClient() ? (IOReturn) OSSwapInt32(kUSBLowLatencyIsochTransferKey) : (IOReturn) kUSBLowLatencyIsochTransferKey;
}
}
for ( i = 0; i < frameCount; i++)
{
UInt16 reqCount, reqLeft;
pNewSITD = AllocateSITD();
if (lowLatency)
reqCount = pLLFrames[i].frReqCount;
else
reqCount = pFrames[i].frReqCount;
USBLog(7, "AppleUSBEHCI[%p]::CreateSplitIsochTransfer - new iTD %p size (%d)", this, pNewSITD, reqCount);
if (!pNewSITD)
{
USBLog(1,"AppleUSBEHCI[%p]::CreateSplitIsochTransfer Could not allocate a new iTD", this);
USBTrace( kUSBTEHCI, kTPEHCICreateSplitIsochTransfer, (uintptr_t)this, 0, kIOReturnNoMemory, 3 );
return kIOReturnNoMemory;
}
pEP->firstAvailableFrame++;
pNewSITD->_lowLatency = lowLatency;
offset = transferOffset;
numSegments = 1;
status = dmaCommand->gen64IOVMSegments(&offset, &segments, &numSegments);
dmaAddrHighBits = (UInt32)(segments.fIOVMAddr >> 32);
if (status || (numSegments != 1) || (dmaAddrHighBits && !_is64bit))
{
USBError(1, "AppleUSBEHCI[%p]::CreateSplitIsochTransfer - could not generate segments err (%p) numSegments (%d) fLength (%d)", this, (void*)status, (int)numSegments, (int)segments.fLength);
status = status ? status : kIOReturnInternalError;
dmaStartAddr = 0;
segLen = 0;
}
else
{
dmaStartAddr = segments.fIOVMAddr;
segLen = segments.fLength;
}
pageOffset = dmaStartAddr & kEHCIPageOffsetMask;
if (segLen > reqCount)
{
segLen = reqCount;
}
if (segLen > (kEHCIPageSize-pageOffset))
{
segLen = kEHCIPageSize-pageOffset;
}
pNewSITD->GetSharedLogical()->buffPtr0 = HostToUSBLong(dmaStartAddr);
pNewSITD->GetSharedLogical()->extBuffPtr0 = HostToUSBLong(dmaAddrHighBits);
USBLog(7, "AppleUSBEHCI[%p]::CreateSplitIocTransfer - gen64IOVMSegments returned start of %p:%p; length %d", this, (void*)dmaAddrHighBits, (void*)dmaStartAddr, (uint32_t)segLen);
transferOffset += segLen;
bufferSize -= segLen;
reqLeft = reqCount - segLen;
if (reqLeft==0)
{
pNewSITD->GetSharedLogical()->buffPtr1 = 0;
pNewSITD->GetSharedLogical()->extBuffPtr1 = 0;
}
else
{
offset = transferOffset;
numSegments = 1;
status = dmaCommand->gen64IOVMSegments(&offset, &segments, &numSegments);
dmaAddrHighBits = (UInt32)(segments.fIOVMAddr >> 32);
if (status || (numSegments != 1) || (dmaAddrHighBits && !_is64bit))
{
USBError(1, "AppleUSBEHCI[%p]::CreateSplitIsochTransfer - could not generate segments err (%p) numSegments (%d) fLength (%d)", this, (void*)status, (int)numSegments, (int)segments.fLength);
status = status ? status : kIOReturnInternalError;
dmaStartAddr = 0;
segLen = 0;
}
else
{
dmaStartAddr = segments.fIOVMAddr;
segLen = segments.fLength;
}
pNewSITD->GetSharedLogical()->buffPtr1 = HostToUSBLong(dmaStartAddr & kEHCIPageMask);
pNewSITD->GetSharedLogical()->extBuffPtr1 = HostToUSBLong(dmaAddrHighBits);
if (segLen > reqLeft)
{
segLen = reqLeft;
}
if (segLen > kEHCIPageSize)
{
segLen = kEHCIPageSize;
}
USBLog(7, "AppleUSBEHCI[%p]::CreateSplitIocTransfer - gen64IOVMSegments returned start of %p:%p; length %d", this, (void*)dmaAddrHighBits, (void*)dmaStartAddr, (uint32_t)segLen);
transferOffset += segLen;
bufferSize -= segLen;
}
pNewSITD->_pFrames = pFrames;
pNewSITD->_frameNumber = frameNumberStart + i;
pNewSITD->_frameIndex = i;
USBLog(7, "EHCI::CreateSplitIsochTransfer - SITD(%p) scheduled for frame(%d)", pNewSITD, (int)pNewSITD->_frameNumber);
if (pEP->direction == kUSBOut)
{
UInt8 calcNumSS = ((reqCount-1) / kEHCIFSBytesPeruFrame) + 1;
completeSplitFlags = 0; startSplitFlags = pEP->pSPE->_SSflags;
if (calcNumSS > pEP->pSPE->_numSS)
{
USBLog(1, "AppleUSBEHCI[%p]::CreateSplitIsochTransfer - more SS needed than we have available! Error!", this);
calcNumSS = pEP->pSPE->_numSS;
}
if (calcNumSS < pEP->pSPE->_numSS)
{
USBLog(7, "AppleUSBEHCI[%p]::CreateSplitIsochTransfer - not using all of the SS we had reserved. This is OK", this);
}
if (calcNumSS > 1)
{
transactionCount = calcNumSS; transactionPosition = 1; }
else
{
transactionCount = 1; transactionPosition = 0; }
}
else
{
startSplitFlags = pEP->pSPE->_SSflags; transactionPosition = 0; transactionCount = 0; completeSplitFlags = pEP->pSPE->_CSflags; USBLog(7, "AppleUSBEHCI[%p]::CreateSplitIsochTransfer IN - SS (%x) CS (%x)", this, startSplitFlags, completeSplitFlags);
}
if (i == (frameCount-1))
{
ioc = 1;
if (!pEP->useBackPtr)
pNewSITD->_completion = command->GetUSLCompletion();
}
else if (lowLatency)
{
if (!updateFrequency)
{
ioc = (((i+1) % 8) == 0) ? 1 : 0;
}
else
ioc = (((i+1) % updateFrequency) == 0) ? 1 : 0;
}
else
ioc = 0;
pNewSITD->GetSharedLogical()->nextSITD = HostToUSBLong(kEHCITermFlag);
pNewSITD->GetSharedLogical()->routeFlags = HostToUSBLong(((pEP->direction == kUSBOut) ? 0 : (1 << kEHCIsiTDRouteDirectionPhase))
| (pEP->highSpeedPort << kEHCIsiTDRoutePortNumberPhase)
| (pEP->highSpeedHub << kEHCIsiTDRouteHubAddrPhase)
| (pEP->endpointNumber << kEHCIsiTDRouteEndpointPhase)
| (pEP->functionAddress << kEHCIsiTDRouteDeviceAddrPhase)
);
pNewSITD->GetSharedLogical()->timeFlags = HostToUSBLong((completeSplitFlags << kEHCIsiTDTimeCMaskPhase)
| (startSplitFlags << kEHCIsiTDTimeSMaskPhase)
);
myStatFlags = (ioc << kEHCIsiTDStatIOCPhase) | (reqCount << kEHCIsiTDStatLengthPhase) | kEHCIsiTDStatStatusActive;
if ((i > 0) && pEP->useBackPtr)
{
if (!(_errataBits & kErrataNoCSonSplitIsoch)) myStatFlags |= kEHCUsiTDStatStatusSplitXState; pNewSITD->GetSharedLogical()->backPtr = HostToUSBLong(prevPhysLink);
}
else
{
pNewSITD->GetSharedLogical()->backPtr = HostToUSBLong(kEHCITermFlag);
}
prevPhysLink = pNewSITD->_sharedPhysical;
pNewSITD->GetSharedLogical()->statFlags = HostToUSBLong(myStatFlags);
pNewSITD->GetSharedLogical()->buffPtr1 |= HostToUSBLong( (transactionPosition << kEHCIsiTDBuffPtr1TPPhase)
| (transactionCount));
pNewSITD->_pEndpoint = pEP;
pNewSITD->_requestFromRosettaClient = command->GetIsRosettaClient();
PutTDonToDoList(pEP, pNewSITD);
}
if (pEP->useBackPtr)
{
pDummySITD = AllocateSITD();
pDummySITD->GetSharedLogical()->nextSITD = HostToUSBLong(kEHCITermFlag);
pDummySITD->GetSharedLogical()->routeFlags = pNewSITD->GetSharedLogical()->routeFlags;
pDummySITD->GetSharedLogical()->timeFlags = HostToUSBLong((completeSplitFlags & 0x03) << kEHCIsiTDTimeCMaskPhase); myStatFlags = kEHCIsiTDStatIOC | kEHCIsiTDStatStatusActive;
if (!(_errataBits & kErrataNoCSonSplitIsoch)) myStatFlags |= kEHCUsiTDStatStatusSplitXState;
pDummySITD->GetSharedLogical()->statFlags = HostToUSBLong(myStatFlags);
pDummySITD->GetSharedLogical()->buffPtr0 = pNewSITD->GetSharedLogical()->buffPtr0;
pDummySITD->GetSharedLogical()->buffPtr1 = pNewSITD->GetSharedLogical()->buffPtr1;
pDummySITD->GetSharedLogical()->extBuffPtr0 = pNewSITD->GetSharedLogical()->extBuffPtr0;
pDummySITD->GetSharedLogical()->extBuffPtr1 = pNewSITD->GetSharedLogical()->extBuffPtr1;
pDummySITD->GetSharedLogical()->backPtr = HostToUSBLong(prevPhysLink);
pDummySITD->_completion = command->GetUSLCompletion();
pDummySITD->_pEndpoint = pEP;
pDummySITD->_pFrames = pFrames;
pDummySITD->_frameNumber = pNewSITD->_frameNumber+1;
pDummySITD->_isDummySITD = true;
PutTDonToDoList(pEP, pDummySITD);
}
AddIsocFramesToSchedule(pEP);
EnablePeriodicSchedule(false);
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::UIMCreateIsochTransfer( short functionAddress,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameStart,
IOMemoryDescriptor *pBuffer,
UInt32 frameCount,
IOUSBIsocFrame *pFrames)
{
#pragma unused (functionAddress, endpointNumber, completion, direction, frameStart, pBuffer, frameCount, pFrames)
USBError(1, "AppleUSBEHCI::UIMCreateIsochTransfer - old method");
return kIOReturnIPCError;
}
IOReturn
AppleUSBEHCI::UIMCreateIsochTransfer( short functionAddress,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameNumberStart,
IOMemoryDescriptor *pBuffer,
UInt32 frameCount,
IOUSBLowLatencyIsocFrame *pFrames,
UInt32 updateFrequency)
{
#pragma unused (functionAddress, endpointNumber, completion, direction, frameNumberStart, pBuffer, frameCount, pFrames, updateFrequency)
USBError(1, "AppleUSBEHCI::UIMCreateIsochTransfer(LL) - old method");
return kIOReturnIPCError;
}
IOReturn
AppleUSBEHCI::UIMCreateIsochTransfer(IOUSBIsocCommand *command)
{
IOReturn err;
AppleEHCIIsochEndpoint * pEP;
UInt64 maxOffset;
UInt64 curFrameNumber = GetFrameNumber();
UInt64 frameDiff;
UInt32 diff32;
USBLog(7, "AppleUSBEHCI[%p]::UIMCreateIsochTransfer - adr=%d:%d IOMD=%p, frameStart: %qd, count: %d, pFrames: %p", this,
command->GetAddress(), command->GetEndpoint(),
command->GetBuffer(),
command->GetStartFrame(), (uint32_t)command->GetNumFrames(), command->GetFrameList());
if ( (command->GetNumFrames() == 0) || (command->GetNumFrames() > 1000) )
{
USBLog(3,"AppleUSBEHCI[%p]::UIMCreateIsochTransfer bad frameCount: %d", this, (uint32_t)command->GetNumFrames());
return kIOReturnBadArgument;
}
pEP = OSDynamicCast(AppleEHCIIsochEndpoint, FindIsochronousEndpoint(command->GetAddress(), command->GetEndpoint(), command->GetDirection(), NULL));
if (pEP == NULL)
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateIsochTransfer - Endpoint not found", this);
USBTrace( kUSBTEHCI, kTPEHCICreateIsochTransfer, (uintptr_t)this, 0, 0, kIOUSBEndpointNotFound );
return kIOUSBEndpointNotFound;
}
if ( pEP->aborting )
{
USBLog(3, "AppleUSBEHCI[%p]::UIMCreateIsochTransfer - sent request while aborting endpoint. Returning kIOReturnNotPermitted", this);
return kIOReturnNotPermitted;
}
if (command->GetStartFrame() < pEP->firstAvailableFrame)
{
USBLog(3,"AppleUSBEHCI[%p]::UIMCreateIsochTransfer: no overlapping frames - EP (%p) frameNumberStart: %qd, pEP->firstAvailableFrame: %qd. Returning 0x%x", this, pEP, command->GetStartFrame(), pEP->firstAvailableFrame, kIOReturnIsoTooOld);
return kIOReturnIsoTooOld;
}
maxOffset = _frameListSize;
pEP->firstAvailableFrame = command->GetStartFrame();
if (command->GetStartFrame() <= curFrameNumber)
{
if (command->GetStartFrame() < (curFrameNumber - maxOffset))
{
USBLog(3,"AppleUSBEHCI[%p]::UIMCreateIsochTransfer request frame WAY too old. frameNumberStart: %d, curFrameNumber: %d. Returning 0x%x", this, (uint32_t)command->GetStartFrame(), (uint32_t) curFrameNumber, kIOReturnIsoTooOld);
return kIOReturnIsoTooOld;
}
USBLog(5,"AppleUSBEHCI[%p]::UIMCreateIsochTransfer WARNING! curframe later than requested, expect some notSent errors! frameNumberStart: %d, curFrameNumber: %d. USBIsocFrame Ptr: %p, First ITD: %p", this, (uint32_t)command->GetStartFrame(), (uint32_t)curFrameNumber, command->GetFrameList(), pEP->toDoEnd);
}
else
{ if (command->GetStartFrame() > (curFrameNumber + maxOffset))
{
USBLog(3,"AppleUSBEHCI[%p]::UIMCreateIsochTransfer request frame too far ahead! frameNumberStart: %d, curFrameNumber: %d", this, (uint32_t)command->GetStartFrame(), (uint32_t) curFrameNumber);
return kIOReturnIsoTooNew;
}
frameDiff = command->GetStartFrame() - curFrameNumber;
diff32 = (UInt32)frameDiff;
if (diff32 < _istKeepAwayFrames)
{
USBLog(5,"AppleUSBEHCI[%p]::UIMCreateIsochTransfer WARNING! - frameNumberStart less than 2 ms (is %d)! frameNumberStart: %d, curFrameNumber: %d", this, (uint32_t) diff32, (uint32_t)command->GetStartFrame(), (uint32_t) curFrameNumber);
}
}
if (!command->GetDMACommand() || !command->GetDMACommand()->getMemoryDescriptor())
{
USBError(1, "AppleUSBEHCI[%p]::UIMCreateIsochTransfer - no DMA Command or missing memory descriptor", this);
return kIOReturnBadArgument;
}
USBLog(7, "AppleUSBEHCI[%p]::UIMCreateIsochTransfer - pEP (%p) command (%p) HSHub (%s)", this, pEP, command, pEP->highSpeedHub ? "true" : "false");
if (pEP->highSpeedHub)
return CreateSplitIsochTransfer(pEP, command);
else
return CreateHSIsochTransfer(pEP, command);
}
void
AppleUSBEHCI::AddIsocFramesToSchedule(AppleEHCIIsochEndpoint *pEP)
{
UInt64 currFrame, startFrame, finFrame;
IOUSBControllerIsochListElement *pTD = NULL;
AppleEHCISplitIsochTransferDescriptor *pSITD = NULL;
UInt16 nextSlot, firstOutSlot;
uint64_t timeStamp;
bool fetchNewTDFromToDoList = true;
bool lostRegisterAccess = false;
if (pEP->toDoList == NULL)
{
USBLog(7, "AppleUSBEHCI[%p]::AddIsocFramesToSchedule - no frames to add fn:%d EP:%d", this, pEP->functionAddress, pEP->endpointNumber);
return;
}
if (pEP->aborting)
{
USBLog(1, "AppleUSBEHCI[%p]::AddIsocFramesToSchedule - EP (%p) is aborting - not adding", this, pEP);
USBTrace( kUSBTEHCI, kTPEHCIAddIsocFramesToSchedule, (uintptr_t)this, pEP->functionAddress, pEP->endpointNumber, 1 );
return;
}
if ((pEP->doneQueue != NULL) && (pEP->doneEnd == NULL))
{
USBError(1, "AppleUSBEHCI::AddIsocFramesToSchedule - inconsistent EP queue. pEP[%p] doneQueue[%p] doneEnd[%p] doneQueue->_logicalNext[%p] onDoneQueue[%d]", pEP, pEP->doneQueue, pEP->doneEnd, pEP->doneQueue->_logicalNext, (int)pEP->onDoneQueue);
IOSleep(1); }
USBLog(7, "AppleUSBEHCI[%p]::AddIsocFramesToSchedule - scheduledTDs = %d, deferredTDs = %d", this, (uint32_t)pEP->scheduledTDs, (uint32_t)pEP->deferredTDs);
if (_pEHCIRegisters->USBSTS == kEHCIInvalidRegisterValue)
{
USBLog(1, "AppleUSBEHCI[%p]::AddIsocFramesToSchedule - registers not accessible. Giving up", this);
return;
}
if (!IOSimpleLockTryLock(_isochScheduleLock))
{
USBError(1, "AppleUSBEHCI[%p]::AddIsocFramesToSchedule - could not obtain scheduling lock", this);
return;
}
currFrame = GetFrameNumber();
startFrame = currFrame;
timeStamp = mach_absolute_time();
while(pEP->toDoList->_frameNumber <= (currFrame+_istKeepAwayFrames)) {
IOReturn ret;
UInt64 newCurrFrame;
pTD = GetTDfromToDoList(pEP);
ret = pTD->UpdateFrameList(*(AbsoluteTime*)&timeStamp); if (pEP->scheduledTDs > 0)
PutTDonDeferredQueue(pEP, pTD);
else
{
PutTDonDoneQueue(pEP, pTD, true);
}
if (pEP->toDoList == NULL)
{
IOSimpleLockUnlock(_isochScheduleLock);
USBLog(7, "AppleUSBEHCI[%p]::AddIsocFramesToSchedule - calling thread_call_enter1(_returnIsochDoneQueueThread) scheduledTDs = %d, deferredTDs = %d", this, (uint32_t)pEP->scheduledTDs, (uint32_t)pEP->deferredTDs);
bool alreadyQueued = thread_call_enter1(_returnIsochDoneQueueThread, (thread_call_param_t) pEP);
if ( alreadyQueued )
{
USBLog(1, "AppleUSBEHCI[%p]::AddIsocFramesToSchedule - thread_call_enter1(_returnIsochDoneQueueThread) was NOT scheduled. That's not good", this);
USBTrace( kUSBTEHCI, kTPEHCIAddIsocFramesToSchedule, (uintptr_t)this, 0, 0, 2 );
}
return;
}
newCurrFrame = GetFrameNumber();
if (newCurrFrame == 0)
{
lostRegisterAccess = true; break;
}
if (newCurrFrame > currFrame)
{
currFrame = newCurrFrame;
}
}
if (!lostRegisterAccess)
{
firstOutSlot = currFrame & (kEHCIPeriodicListEntries-1);
currFrame = pEP->toDoList->_frameNumber;
pEP->inSlot = currFrame & (kEHCIPeriodicListEntries-1);
do
{
nextSlot = (pEP->inSlot + 1) & (kEHCIPeriodicListEntries-1);
if (pEP->inSlot == _outSlot)
{
break;
}
if ( nextSlot == _outSlot) {
break;
}
if ( fetchNewTDFromToDoList )
{
pTD = GetTDfromToDoList(pEP);
pSITD = OSDynamicCast(AppleEHCISplitIsochTransferDescriptor, pTD);
}
if (currFrame == pTD->_frameNumber)
{
IOUSBControllerListElement *linkAfter = NULL;
IOUSBControllerIsochListElement *prevIsochLE; AppleEHCISplitIsochTransferDescriptor *prevSITD;
if (_outSlot > kEHCIPeriodicListEntries)
{
_outSlot = firstOutSlot;
}
if (pEP->pSPE)
{
prevIsochLE = OSDynamicCast(IOUSBControllerIsochListElement, GetPeriodicListLogicalEntry(pEP->inSlot));
while (prevIsochLE)
{
prevSITD = OSDynamicCast(AppleEHCISplitIsochTransferDescriptor, prevIsochLE);
if (prevSITD)
{
AppleEHCIIsochEndpoint *pPrevEP = OSDynamicCast(AppleEHCIIsochEndpoint, prevSITD->_pEndpoint);
if (pPrevEP && pPrevEP->pSPE && (pPrevEP->pSPE->_myTT == pEP->pSPE->_myTT) && (pPrevEP->pSPE->_startTime < pEP->pSPE->_startTime))
linkAfter = prevSITD;
}
prevIsochLE = OSDynamicCast(IOUSBControllerIsochListElement, prevIsochLE->_logicalNext);
}
}
if (linkAfter)
{
pTD->SetPhysicalLink(linkAfter->GetPhysicalLink());
pTD->_logicalNext = linkAfter->_logicalNext;
linkAfter->_logicalNext = pTD;
linkAfter->SetPhysicalLink(pTD->GetPhysicalAddrWithType());
}
else
{
pTD->SetPhysicalLink(GetPeriodicListPhysicalEntry(pEP->inSlot));
pTD->_logicalNext = GetPeriodicListLogicalEntry(pEP->inSlot);
SetPeriodicListEntry(pEP->inSlot, pTD);
}
OSIncrementAtomic(&(pEP->scheduledTDs));
fetchNewTDFromToDoList = true;
}
else
{
fetchNewTDFromToDoList = false;
}
if (!pSITD || !(pSITD->_isDummySITD))
{
currFrame++;
pEP->inSlot = nextSlot;
}
} while(pEP->toDoList != NULL);
finFrame = GetFrameNumber();
}
IOSimpleLockUnlock(_isochScheduleLock);
if (!lostRegisterAccess && (finFrame - startFrame) > 1)
{
USBLog(1, "AppleUSBEHCI[%p]::AddIsocFramesToSchedule - end - startFrame(0x%qx) finFrame(0x%qx)", this, startFrame, finFrame);
}
USBLog(7, "AppleUSBEHCI[%p]::AddIsocFramesToSchedule - finished, currFrame: %qx", this, GetFrameNumber() );
}
IOReturn
AppleUSBEHCI::UIMHubMaintenance(USBDeviceAddress highSpeedHub, UInt32 highSpeedPort, UInt32 command, UInt32 flags)
{
#pragma unused (highSpeedPort)
AppleUSBEHCIHubInfo *hiPtr;
switch (command)
{
case kUSBHSHubCommandAddHub:
USBLog(7, "AppleUSBEHCI[%p]::UIMHubMaintenance - adding hub %d with flags 0x%x", this, highSpeedHub, (uint32_t)flags);
hiPtr = AppleUSBEHCIHubInfo::AddHubInfo(&_hsHubs, highSpeedHub, flags);
if (!hiPtr)
return kIOReturnNoMemory;
USBLog(7, "AppleUSBEHCI[%p]::UIMHubMaintenance - done creating new hub (%p) for address (%d)", this, hiPtr, highSpeedHub);
break;
case kUSBHSHubCommandRemoveHub:
USBLog(7, "AppleUSBEHCI[%p]::UIMHubMaintenance - deleting hub %d", this, highSpeedHub);
AppleUSBEHCIHubInfo::DeleteHubInfo(&_hsHubs, highSpeedHub); break;
default:
return kIOReturnBadArgument;
}
return kIOReturnSuccess;
}
#define kEHCIUIMScratchFirstActiveFrame 0
void
AppleUSBEHCI::ReturnOneTransaction(EHCIGeneralTransferDescriptor *transaction,
AppleEHCIQueueHead *pED,
AppleEHCIQueueHead *pEDBack,
IOReturn err,
Boolean inactive) {
if(!inactive)
{
HaltAsyncEndpoint(pED, pEDBack);
}
while(transaction!= NULL)
{
if(transaction->callbackOnTD)
{
if (!transaction->multiXferTransaction)
{
USBLog(2, "AppleUSBEHCI[%p]::ReturnOneTransaction - found the end of a non-multi transaction(%p)!", this, transaction);
transaction = transaction->pLogicalNext;
break;
}
else if (transaction->finalXferInTransaction)
{
USBLog(2, "AppleUSBEHCI[%p]::ReturnOneTransaction - found the end of a MULTI transaction(%p)!", this, transaction);
transaction = transaction->pLogicalNext;
break;
}
else
{
USBLog(2, "AppleUSBEHCI[%p]::ReturnOneTransaction - returning the non-end of a MULTI transaction(%p)!", this, transaction);
}
}
transaction = transaction->pLogicalNext;
}
if(transaction == NULL)
{
USBLog(1, "AppleUSBEHCI[%p]::ReturnOneTransaction - returning all TDs on the queue", this);
USBTrace( kUSBTEHCI, kTPEHCIReturnOneTransaction, (uintptr_t)this, err, 0, 0);
}
returnTransactions(pED, transaction, err, true);
}
UInt32
AppleUSBEHCI::findBufferRemaining(AppleEHCIQueueHead *pED)
{
UInt32 flags, bufferSizeRemaining;
flags = USBToHostLong(pED->GetSharedLogical()->qTDFlags);
bufferSizeRemaining = (flags & kEHCITDFlags_Bytes) >> kEHCITDFlags_BytesPhase;
return(bufferSizeRemaining);
}
IOReturn
AppleUSBEHCI::ReturnAllOutstandingAsyncIO(void)
{
AppleEHCIQueueHead *pED;
AppleEHCIQueueHead *pEDBack = NULL, *pEDBack1 = NULL;
IOPhysicalAddress pTDPhys;
EHCIGeneralTransferDescriptor *pTD;
EHCIQueueHeadShared *pQH;
int loop;
USBLog(2, "AppleUSBEHCI[%p]::ReturnAllOutstandingAsyncIO - _AsyncHead(%p) _InactiveAsyncHead(%p) activeIsochTransfers(%d) activeInterruptTransfers(%d)", this, _AsyncHead, _InactiveAsyncHead, (int)_activeIsochTransfers, (int)_activeInterruptTransfers);
for (loop = 0; loop < 2; loop++)
{
pED = loop ? _AsyncHead : _InactiveAsyncHead;
for (; pED != 0; pED = (AppleEHCIQueueHead *)pED->_logicalNext)
{
USBLog(2, "AppleUSBEHCI[%p]::ReturnAllOutstandingAsyncIO - checking ED [%p] on %s", this, pED, loop ? "AsyncList" : "InactiveAsyncHead");
pED->print(7, this);
pEDBack = pEDBack1;
pEDBack1 = pED;
pQH = pED->GetSharedLogical();
pTDPhys = USBToHostLong(pQH->CurrqTDPtr) & kEHCIEDTDPtrMask;
pTD = pED->_qTD;
if (!pTD)
{
USBLog(2, "AppleUSBEHCI[%p]::ReturnAllOutstandingAsyncIO - no TD", this);
continue;
}
if (!pTD->command)
{
USBLog(2, "AppleUSBEHCI[%p]::ReturnAllOutstandingAsyncIO - found a TD without a command - moving on", this);
continue;
}
if (pTD == pED->_TailTD)
{
USBLog(2, "AppleUSBEHCI[%p]::ReturnAllOutstandingAsyncIO - ED (%p) - TD is TAIL but there is a command - pTD (%p)", this, pED, pTD);
pED->print(5, this);
}
USBLog(2, "AppleUSBEHCI[%p]::ReturnAllOutstandingAsyncIO - Found a TD [%p] on QH [%p] which I will return", this, pTD, pED);
pED->print(2, this);
ReturnOneTransaction(pTD, pED, pEDBack, kIOReturnNoDevice, true);
}
}
return kIOReturnSuccess;
}
bool
AppleUSBEHCI::CheckEDListForTimeouts(AppleEHCIQueueHead *head)
{
AppleEHCIQueueHead *pED = head;
AppleEHCIQueueHead *pEDBack = NULL, *pEDBack1 = NULL;
IOPhysicalAddress pTDPhys;
EHCIGeneralTransferDescriptor *pTD;
EHCIQueueHeadShared *pQH;
UInt32 noDataTimeout;
UInt32 completionTimeout;
UInt32 rem;
UInt64 curFrame = GetFrameNumber();
if (curFrame == 0)
{
USBLog(2, "AppleUSBEHCI[%p]::CheckEDListForTimeouts - curFrame is 0, not doing anything", this);
return false;
}
for (; pED != 0; pED = (AppleEHCIQueueHead *)pED->_logicalNext)
{
USBLog(7, "AppleUSBEHCI[%p]::CheckEDListForTimeouts - checking ED [%p]", this, pED);
pED->print(7, this);
pEDBack = pEDBack1;
pEDBack1 = pED;
pQH = pED->GetSharedLogical();
pTDPhys = USBToHostLong(pQH->CurrqTDPtr) & kEHCIEDTDPtrMask;
pTD = pED->_qTD;
if (!pTD)
{
USBLog(7, "AppleUSBEHCI[%p]::CheckEDListForTimeouts - no TD", this);
continue;
}
if(head != _InactiveAsyncHead)
{
if( (pTD == pED->_TailTD) && ((pQH->qTDFlags & kEHCITDStatus_Active) == 0) ) {
if(pTDPhys == pED->_lastSeenTD)
{
if ((curFrame - pED->_lastSeenFrame) >= 750) {
USBLog(5, "AppleUSBEHCI[%p]::CheckEDListForTimeouts - found a QH (%lx) Inactive for long enough, trimming", this, (long)pED);
unlinkAsyncEndpoint(pED, pEDBack);
if( (pQH->qTDFlags & kEHCITDStatus_Active) != 0) {
USBError(1, "AppleUSBEHCI[%p]::CheckEDListForTimeouts - pEDQueue: %p, became active while unlinking, let this be scavenged from the inactive queue", this, pED);
}
pED->_logicalNext = _InactiveAsyncHead;
_InactiveAsyncHead = pED;
return(true); }
else
{
}
}
else
{
pED->_lastSeenTD = pTDPhys; pED->_lastSeenFrame = curFrame;
}
}
else
{
pED->_lastSeenTD = 0; }
}
if (!pTD->command)
{
USBLog(7, "AppleUSBEHCI[%p]::CheckEDListForTimeouts - found a TD without a command - moving on", this);
continue;
}
if (pTD == pED->_TailTD)
{
USBLog(1, "AppleUSBEHCI[%p]::CheckEDListForTimeouts - ED (%p) - TD is TAIL but there is a command - pTD (%p)", this, pED, pTD);
USBTrace( kUSBTEHCI, kTPEHCICheckEDListForTimeouts, (uintptr_t)this, (uintptr_t)pED, (uintptr_t)pTD, 0);
pED->print(5, this);
}
if((pTDPhys != pTD->pPhysical) && !(pED->GetSharedLogical()->qTDFlags & USBToHostLong(kEHCITDStatus_Halted | kEHCITDStatus_Active) ))
{
USBLog(6, "AppleUSBEHCI[%p]::CheckEDListForTimeouts - pED (%p) - mismatched logical and physical - TD (L:%p - P:%p) will be scavenged later", this, pED, pTD, (void*)pTD->pPhysical);
pED->print(7, this);
printTD(pTD, 7);
if (pTD->pLogicalNext)
printTD(pTD->pLogicalNext, 7);
continue;
}
noDataTimeout = pTD->command->GetNoDataTimeout();
completionTimeout = pTD->command->GetCompletionTimeout();
if (completionTimeout)
{
UInt32 firstActiveFrame = pTD->command->GetUIMScratch(kEHCIUIMScratchFirstActiveFrame);
if (!firstActiveFrame)
{
pTD->command->SetUIMScratch(kEHCIUIMScratchFirstActiveFrame, curFrame);
continue;
}
if ((curFrame - firstActiveFrame) >= completionTimeout)
{
uint32_t myFlags = USBToHostLong(pED->GetSharedLogical()->flags);
USBLog(2, "AppleUSBEHCI[%p]::CheckEDListForTimeout - Found a TD [%p] on QH [%p] past the completion deadline, timing out! (0x%x - 0x%x)", this, pTD, pED, (uint32_t)curFrame, (uint32_t)firstActiveFrame);
USBError(1, "AppleUSBEHCI[%p]::Found a transaction past the completion deadline on bus 0x%x, timing out! (Addr: %d, EP: %d)", this, (uint32_t) _busNumber, ((myFlags & kEHCIEDFlags_FA) >> kEHCIEDFlags_FAPhase), ((myFlags & kEHCIEDFlags_EN) >> kEHCIEDFlags_ENPhase) );
pED->print(2, this);
_UIMDiagnostics.timeouts++;
ReturnOneTransaction(pTD, pED, pEDBack, kIOUSBTransactionTimeout, head == _InactiveAsyncHead);
continue;
}
}
if (!noDataTimeout)
continue;
if (!pTD->lastFrame || (pTD->lastFrame > curFrame))
{
pTD->lastFrame = curFrame;
pTD->lastRemaining = findBufferRemaining(pED );
continue;
}
rem = findBufferRemaining(pED );
if (pTD->lastRemaining != rem)
{
pTD->lastRemaining = rem;
pTD->lastFrame = curFrame;
continue;
}
if ((UInt32)(curFrame - pTD->lastFrame) >= noDataTimeout)
{
uint32_t myFlags = USBToHostLong(pED->GetSharedLogical()->flags);
USBLog(2, "AppleUSBEHCI[%p]CheckEDListForTimeout: Found a transaction (%p) which hasn't moved in 5 seconds, timing out! (0x%x - 0x%x)", this, pTD, (uint32_t)curFrame, (uint32_t)pTD->lastFrame);
USBError(1, "AppleUSBEHCI[%p]::Found a transaction which hasn't moved in 5 seconds on bus 0x%x, timing out! (Addr: %d, EP: %d)", this, (uint32_t) _busNumber, ((myFlags & kEHCIEDFlags_FA) >> kEHCIEDFlags_FAPhase), ((myFlags & kEHCIEDFlags_EN) >> kEHCIEDFlags_ENPhase) );
_UIMDiagnostics.timeouts++;
ReturnOneTransaction(pTD, pED, pEDBack, kIOUSBTransactionTimeout, head == _InactiveAsyncHead);
continue;
}
}
return(false);
}
void
AppleUSBEHCI::UIMCheckForTimeouts(void)
{
AbsoluteTime currentTime;
AbsoluteTime lastRootHubChangeTime;
UInt64 elapsedTime = 0;
bool allPortsDisconnected = false;
UInt32 usbcmd;
UInt32 usbsts;
UInt32 retries = 0;
if ( isInactive() || !_controllerAvailable )
{
ReturnAllOutstandingAsyncIO();
return;
}
if ((_myBusState != kUSBBusStateRunning) || _wakingFromHibernation )
{
if (_controlBulkTransactionsOut)
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCheckForTimeouts - aborting check with outstanding transactions! _myBusState(%d) _wakingFromHibernation(%s)", this, (int)_myBusState, _wakingFromHibernation ? "TRUE" : "FALSE");
USBTrace( kUSBTEHCI, kTPEHCICheckForTimeouts, (uintptr_t)this, _myBusState, _wakingFromHibernation, 0);
}
return;
}
usbcmd = USBToHostLong(_pEHCIRegisters->USBCMD);
usbsts = USBToHostLong(_pEHCIRegisters->USBSTS);
if (usbcmd & kEHCICMDAsyncEnable)
{
if (!(usbsts & kEHCISTSAsyncScheduleStatus))
{
_asynchScheduleUnsynchCount++;
USBLog(6, "AppleUSBEHCI[%p]::UIMCheckForTimeouts - Async USBCMD and USBSTS not synched ON (#%d)", this, _asynchScheduleUnsynchCount);
if (!(_asynchScheduleUnsynchCount % 10))
{
USBError(1, "AppleUSBEHCI[%p]::UIMCheckForTimeouts - Async USBCMD(0x%x) and USBSTS(0x%x) not synched ON (#%d)", this, (int)USBToHostLong(_pEHCIRegisters->USBCMD), (int)USBToHostLong(_pEHCIRegisters->USBSTS), _asynchScheduleUnsynchCount);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
showRegisters(1, "UIMCheckForTimeouts");
#endif
}
}
else
_asynchScheduleUnsynchCount = 0;
}
else
{
if (usbsts & kEHCISTSAsyncScheduleStatus)
{
_asynchScheduleUnsynchCount++;
USBLog(6, "AppleUSBEHCI[%p]::UIMCheckForTimeouts - Async USBCMD and USBSTS not synched OFF (#%d)", this, _asynchScheduleUnsynchCount);
if (!(_asynchScheduleUnsynchCount % 10))
{
USBError(1, "AppleUSBEHCI[%p]::UIMCheckForTimeouts - Async USBCMD(0x%x) and USBSTS(0x%x) not synched OFF (#%d)", this, (int)USBToHostLong(_pEHCIRegisters->USBCMD), (int)USBToHostLong(_pEHCIRegisters->USBSTS), _asynchScheduleUnsynchCount);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
showRegisters(1, "UIMCheckForTimeouts");
#endif
}
}
else
_asynchScheduleUnsynchCount = 0;
}
if (usbcmd & kEHCICMDPeriodicEnable)
{
if (!(usbsts & kEHCISTSPeriodicScheduleStatus))
{
_periodicScheduleUnsynchCount++;
USBLog(6, "AppleUSBEHCI[%p]::UIMCheckForTimeouts - Periodic USBCMD and USBSTS not synched ON (#%d)", this, _periodicScheduleUnsynchCount);
if (!(_periodicScheduleUnsynchCount % 10))
{
USBError(1, "AppleUSBEHCI[%p]::UIMCheckForTimeouts - Periodic USBCMD(0x%x) and USBSTS(0x%x) not synched ON (#%d)", this, (int)USBToHostLong(_pEHCIRegisters->USBCMD), (int)USBToHostLong(_pEHCIRegisters->USBSTS), _periodicScheduleUnsynchCount);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
showRegisters(1, "UIMCheckForTimeouts");
#endif
}
}
else
_periodicScheduleUnsynchCount = 0;
}
else
{
if (usbsts & kEHCISTSPeriodicScheduleStatus)
{
_periodicScheduleUnsynchCount++;
USBLog(6, "AppleUSBEHCI[%p]::UIMCheckForTimeouts - Periodic USBCMD and USBSTS not synched ON (#%d)", this, _periodicScheduleUnsynchCount);
if (!(_periodicScheduleUnsynchCount % 10))
{
USBError(1, "AppleUSBEHCI[%p]::UIMCheckForTimeouts - Periodic USBCMD(0x%x) and USBSTS(0x%x) not synched OFF (#%d)", this, (int)USBToHostLong(_pEHCIRegisters->USBCMD), (int)USBToHostLong(_pEHCIRegisters->USBSTS), _periodicScheduleUnsynchCount);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
showRegisters(1, "UIMCheckForTimeouts");
#endif
}
}
else
_periodicScheduleUnsynchCount = 0;
}
while(CheckEDListForTimeouts(_AsyncHead))
{
if (retries++ > 100)
{
USBError(1, "AppleUSBEHCI[%p]::UIMCheckForTimeouts - exceeded 100 calls to CheckEDListForTimeouts on the AsyncHead!", this);
break;
}
}
CheckEDListForTimeouts(_InactiveAsyncHead);
}
IOReturn
AppleUSBEHCI::GetFrameNumberWithTime(UInt64* frameNumber, AbsoluteTime *theTime)
{
if (!_commandGate)
return kIOReturnUnsupported;
return _commandGate->runAction(GatedGetFrameNumberWithTime, frameNumber, theTime);
}
IOReturn
AppleUSBEHCI::GatedGetFrameNumberWithTime(OSObject *owner, void* arg0, void* arg1, void* arg2, void* arg3)
{
#pragma unused (arg2, arg3)
AppleUSBEHCI *me = (AppleUSBEHCI*)owner;
UInt64 *frameNumber = (UInt64*)arg0;
AbsoluteTime *theTime = (AbsoluteTime*)arg1;
*frameNumber = me->_anchorFrame;
*theTime = me->_anchorTime;
return kIOReturnSuccess;
}
#pragma mark Disabled Endpoints
IOReturn
AppleUSBEHCI::UIMEnableAddressEndpoints(USBDeviceAddress address, bool enable)
{
UInt32 slot;
IOReturn err;
AppleEHCIQueueHead *pQH = NULL;
AppleEHCIQueueHead *pPrevQH = NULL;
IOUSBControllerListElement * pLEBack;
IOUSBControllerListElement * pLE;
int i;
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAddressEndpoints(%d, %s)", this, (int)address, enable ? "true" : "false");
printAsyncQueue(7, "+UIMEnableAddressEndpoints", true, false);
showRegisters(7, "+UIMEnableAddressEndpoints");
if (enable)
{
pQH = _disabledQHList;
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAddressEndpoints- looking for QHs for address (%d) in the disabled queue", this, address);
while (pQH)
{
if (pQH->_functionNumber == address)
{
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAddressEndpoints- found matching QH[%p] on disabled list - reenabling", this, pQH);
if (pPrevQH)
pPrevQH->_logicalNext = pQH->_logicalNext;
else
_disabledQHList = OSDynamicCast(AppleEHCIQueueHead, pQH->_logicalNext);
pQH->_logicalNext = NULL;
switch (pQH->_queueType)
{
case kEHCITypeControl:
case kEHCITypeBulk:
maybeLinkAsyncEndpoint(pQH);
break;
case kEHCITypeInterrupt:
linkInterruptEndpoint(pQH);
break;
default:
USBError(1, "AppleUSBEHCI[%p]::UIMEnableAddressEndpoints- found QH[%p] with unknown type(%d)", this, pQH, pQH->_queueType);
break;
}
if (pPrevQH)
pQH = OSDynamicCast(AppleEHCIQueueHead, pPrevQH->_logicalNext);
else
pQH = _disabledQHList;
}
else
{
pPrevQH = pQH;
pQH = OSDynamicCast(AppleEHCIQueueHead, pQH->_logicalNext);
}
}
}
else
{
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAddressEndpoints- looking for endpoints for device address(%d) to disable", this, address);
pQH = _AsyncHead;
while (pQH)
{
if (pQH->_functionNumber == address)
{
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAddressEndpoints- found matching QH[%p] with _queueType (%d) on AsyncList - disabling", this, pQH, pQH->_queueType);
unlinkAsyncEndpoint(pQH, pPrevQH);
pQH->_logicalNext = _disabledQHList;
_disabledQHList = pQH;
pQH = pPrevQH;
}
pPrevQH = pQH;
pQH = pQH ? OSDynamicCast(AppleEHCIQueueHead, pQH->_logicalNext) : _AsyncHead;
}
pQH = _InactiveAsyncHead;
while (pQH)
{
if (pQH->_functionNumber == address)
{
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAddressEndpoints- found matching QH[%p] with _queueType (%d) on inactive list", this, pQH, pQH->_queueType);
if(_InactiveAsyncHead == pQH)
{
_InactiveAsyncHead = OSDynamicCast(AppleEHCIQueueHead, pQH->_logicalNext);
}
else
{
pPrevQH->_logicalNext = pQH->_logicalNext;
}
pQH->_logicalNext = _disabledQHList;
_disabledQHList = pQH;
pQH = pPrevQH;
}
pPrevQH = pQH;
pQH = pQH ? OSDynamicCast(AppleEHCIQueueHead, pQH->_logicalNext) : _InactiveAsyncHead;
}
pLEBack = NULL;
for(i= 0; i < _greatestPeriod; i++)
{
pLE = GetPeriodicListLogicalEntry(i);
while ( pLE != NULL)
{
pQH = OSDynamicCast(AppleEHCIQueueHead, pLE);
if (pQH)
{
if (pQH->_functionNumber == address)
{
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAddressEndpoints- found matching QH[%p] with _queueType (%d) on periodic list - disabling", this, pQH, pQH->_queueType);
unlinkIntEndpoint(pQH);
pQH->_logicalNext = _disabledQHList;
_disabledQHList = pQH;
pLE = pLEBack;
}
}
pLEBack = pLE;
pLE = pLE ? pLE->_logicalNext : GetPeriodicListLogicalEntry(i);
}
}
}
pQH = _disabledQHList;
if (!pQH)
{
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAddressEndpoints - list is now empty", this);
}
else
{
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAddressEndpoints - new list:", this);
while (pQH)
{
USBLog(5, "\t[%p]", pQH);
pQH = OSDynamicCast(AppleEHCIQueueHead, pQH->_logicalNext);
}
}
printAsyncQueue(7, "-UIMEnableAddressEndpoints", true, false);
showRegisters(7, "-UIMEnableAddressEndpoints");
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::UIMEnableAllEndpoints(bool enable)
{
UInt32 slot;
IOReturn err;
AppleEHCIQueueHead *pQH = NULL;
IOUSBControllerListElement * pLEBack;
IOUSBControllerListElement * pLE;
int i;
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAllEndpoints(%s)", this, enable ? "true" : "false");
showRegisters(7, "+UIMEnableAllEndpoints");
printAsyncQueue(7, "+UIMEnableAllEndpoints", true, false);
if (enable)
{
pQH = _disabledQHList;
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAllEndpoints- looking for QHs in the disabled queue", this);
while (pQH)
{
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAllEndpoints- found QH[%p] on disabled list - reenabling", this, pQH);
_disabledQHList = OSDynamicCast(AppleEHCIQueueHead, pQH->_logicalNext);
pQH->_logicalNext = NULL;
switch (pQH->_queueType)
{
case kEHCITypeControl:
case kEHCITypeBulk:
maybeLinkAsyncEndpoint(pQH);
break;
case kEHCITypeInterrupt:
linkInterruptEndpoint(pQH);
break;
default:
USBError(1, "AppleUSBEHCI[%p]::UIMEnableAllEndpoints- found QH[%p] with unknown type(%d)", this, pQH, pQH->_queueType);
break;
}
pQH = _disabledQHList;
}
}
else
{
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAllEndpoints- disabling endpoints", this);
pQH = _AsyncHead;
while (pQH)
{
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAllEndpoints- found matching QH[%p] with _queueType (%d) on AsyncList - disabling", this, pQH, pQH->_queueType);
unlinkAsyncEndpoint(pQH, NULL);
pQH->_logicalNext = _disabledQHList;
_disabledQHList = pQH;
pQH = _AsyncHead;
}
pQH = _InactiveAsyncHead;
while (pQH)
{
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAllEndpoints- found matching QH[%p] with _queueType (%d) on inactive list", this, pQH, pQH->_queueType);
_InactiveAsyncHead = OSDynamicCast(AppleEHCIQueueHead, pQH->_logicalNext);
pQH->_logicalNext = _disabledQHList;
_disabledQHList = pQH;
pQH = _InactiveAsyncHead;
}
pLEBack = NULL;
for(i= 0; i < _greatestPeriod; i++)
{
GetPeriodicListLogicalEntry(i);
while ( pLE != NULL)
{
pQH = OSDynamicCast(AppleEHCIQueueHead, pLE);
if (pQH)
{
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAllEndpoints- found matching QH[%p] with _queueType (%d) on periodic list - disabling", this, pQH, pQH->_queueType);
unlinkIntEndpoint(pQH);
pQH->_logicalNext = _disabledQHList;
_disabledQHList = pQH;
}
pLE = GetPeriodicListLogicalEntry(i);
}
}
}
pQH = _disabledQHList;
if (!pQH)
{
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAllEndpoints - list is now empty", this);
}
else
{
USBLog(5, "AppleUSBEHCI[%p]::UIMEnableAllEndpoints - new list:", this);
while (pQH)
{
USBLog(5, "\t[%p]", pQH);
pQH = OSDynamicCast(AppleEHCIQueueHead, pQH->_logicalNext);
}
}
showRegisters(7, "-UIMEnableAllEndpoints");
printAsyncQueue(7, "-UIMEnableAllEndpoints", true, false);
return kIOReturnSuccess;
}
#pragma mark Periodic Scheduling
IOReturn
AppleUSBEHCI::AllocateInterruptBandwidth(AppleEHCIQueueHead *pED, AppleUSBEHCITTInfo *pTT)
{
int frameNum, uFrameNum;
int effectiveFrame, effectiveuFrame;
int index;
UInt8 startFrame = 0xFF;
UInt8 startuFrame = 0xFF; UInt16 minBandwidthUsed = 0xFFFF;
bool undoAllocation = false;
IOReturn err;
UInt16 realPollingRate, realMPS, FSbytesNeeded, HSallocation;
UInt32 splitFlags;
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateInterruptBandwidth - pED[%p] _speed(%d)", this, pED, (int)pED->_speed);
if (pED->_speed == kUSBDeviceSpeedHigh)
{
if (pED->_pollingRate > (kEHCIMaxPollingInterval * kEHCIuFramesPerFrame))
pED->_pollingRate = kEHCIMaxPollingInterval * kEHCIuFramesPerFrame;
}
else
{
if (pED->_pollingRate > kEHCIMaxPollingInterval)
realPollingRate = kEHCIMaxPollingInterval;
else
{
int count = 0;
realPollingRate = pED->_pollingRate;
while ((realPollingRate >> count) != 1)
count++;
realPollingRate = (1 << count);
}
pED->_pollingRate = realPollingRate;
}
if (pED->_maxPacketSize == 0)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateInterruptBandwidth - 0 MPS always succeeds!", this);
pED->_startFrame = 0;
pED->_startuFrame = 0;
return kIOReturnSuccess;
}
ShowPeriodicBandwidthUsed(gEHCIBandwidthLogLevel, "+AllocateInterruptBandwidth");
if (pED->_speed == kUSBDeviceSpeedHigh)
{
if (pED->_direction == kUSBIn)
{
HSallocation = kEHCIHSTokenChangeDirectionOverhead + kEHCIHSDataChangeDirectionOverhead + kEHCIHSHandshakeOverhead + _controllerThinkTime;
}
else
{
HSallocation = kEHCIHSTokenSameDirectionOverhead + kEHCIHSDataSameDirectionOverhead + kEHCIHSHandshakeOverhead + _controllerThinkTime;
}
HSallocation += ((pED->_maxPacketSize * 7) / 6);
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateInterruptBandwidth - pEP[%p] HSallocation[%d]", this, pED, HSallocation);
for (index = 0; index < pED->_pollingRate; index++)
{
if (_periodicBandwidthUsed[index / kEHCIuFramesPerFrame][index % kEHCIuFramesPerFrame] < minBandwidthUsed)
{
startFrame = index / kEHCIuFramesPerFrame;
startuFrame = index % kEHCIuFramesPerFrame;
minBandwidthUsed = _periodicBandwidthUsed[startFrame][startuFrame];
}
}
if ((startFrame == 0xFF) || (startuFrame == 0xFF))
{
USBLog(1, "AppleUSBEHCI[%p]::AllocateInterruptBandwidth - could not find bandwidth", this);
return kIOReturnNoBandwidth;
}
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateInterruptBandwidth - using startFrame[%d] startuFrame[%d]", this, startFrame, startuFrame);
pED->_startFrame = startFrame;
pED->_startuFrame = startuFrame;
for (index = (pED->_startFrame * kEHCIuFramesPerFrame) + pED->_startuFrame;
index < (kEHCIMaxPollingInterval * kEHCIuFramesPerFrame);
index += pED->_pollingRate)
{
UInt16 frameNum = index / kEHCIuFramesPerFrame;
UInt16 uFrameNum = index % kEHCIuFramesPerFrame;
pED->GetSharedLogical()->splitFlags |= HostToUSBLong(1 << (uFrameNum));
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateInterruptBandwidth - adding %d bytes to frameNum(%d) uFrameNum(%d)", this, HSallocation, frameNum, uFrameNum);
err = ReservePeriodicBandwidth(frameNum, uFrameNum, HSallocation);
if (err == kIOReturnNoBandwidth)
{
USBLog(1, "AppleUSBEHCI[%p]::AllocateInterruptBandwidth - not enough bandwidth", this);
undoAllocation = true;
}
}
if (undoAllocation)
{
for (index = (pED->_startFrame * kEHCIuFramesPerFrame) + pED->_startuFrame;
index < (kEHCIMaxPollingInterval * kEHCIuFramesPerFrame);
index += pED->_pollingRate)
{
UInt16 frameNum = index / kEHCIuFramesPerFrame;
UInt16 uFrameNum = index % kEHCIuFramesPerFrame;
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateInterruptBandwidth - returning %d bytes to frameNum(%d) uFrameNum(%d)", this, HSallocation, frameNum, uFrameNum);
ReleasePeriodicBandwidth(frameNum, uFrameNum, HSallocation);
}
err = kIOReturnNoBandwidth;
}
else
{
ShowPeriodicBandwidthUsed(gEHCIBandwidthLogLevel, "-AllocateInterruptBandwidth");
err = kIOReturnSuccess;
}
}
else
{
if (!pTT)
{
USBLog(1, "AppleUSBEHCI[%p]::AllocateInterruptBandwidth.. no pTT, cannot proceed", this);
err = kIOReturnBadArgument;
goto ErrorExit;
}
pTT->ShowHSSplitTimeUsed(gEHCIBandwidthLogLevel, "+AllocateInterruptBandwidth");
if (pED->_speed == kUSBDeviceSpeedFull)
{
FSbytesNeeded = kEHCIFSSplitInterruptOverhead + pTT->_thinkTime + pED->_maxPacketSize;
}
else
{
FSbytesNeeded = kEHCILSSplitInterruptOverhead + pTT->_thinkTime + (8 * pED->_maxPacketSize);
}
realMPS = (pED->_maxPacketSize * 7) / 6;
pED->_pSPE = AppleUSBEHCISplitPeriodicEndpoint::NewSplitPeriodicEndpoint(pTT, kUSBInterrupt, pED, FSbytesNeeded, pED->_pollingRate);
if (!pED->_pSPE)
{
USBLog (1, "AppleUSBEHCI[%p]::AllocateInterruptBandwidth - no SplitPeriodicEndpoint available", this);
err = kIOReturnNoMemory;
goto ErrorExit;
}
err = pTT->AllocatePeriodicBandwidth(pED->_pSPE);
if (err)
{
USBLog (1, "AppleUSBEHCI[%p]::AllocateInterruptBandwidth - pTT->AllocatePeriodicBandwidth returned err(%p)", this, (void*)err);
pED->_pSPE->release();
pED->_pSPE = NULL;
goto ErrorExit;
}
pED->_startFrame = pED->_pSPE->_startFrame;
err = AllocateHSPeriodicSplitBandwidth(pED->_pSPE);
splitFlags = USBToHostLong(pED->GetSharedLogical()->splitFlags);
splitFlags &= ~(kEHCIEDSplitFlags_SMask + kEHCIEDSplitFlags_CMask);
splitFlags |= (pED->_pSPE->_SSflags << kEHCIEDSplitFlags_SMaskPhase);
splitFlags |= (pED->_pSPE->_CSflags << kEHCIEDSplitFlags_CMaskPhase);
pED->GetSharedLogical()->splitFlags = HostToUSBLong(splitFlags);
pTT->CalculateSPEsToAdjustAfterChange(pED->_pSPE, true);
AdjustSPEs(pED->_pSPE, true);
pTT->ShowHSSplitTimeUsed(gEHCIBandwidthLogLevel, "-AllocateInterruptBandwidth");
ShowPeriodicBandwidthUsed(gEHCIBandwidthLogLevel, "-AllocateInterruptBandwidth");
pTT->print(gEHCIBandwidthLogLevel, "-AllocateInterruptBandwidth");
err = kIOReturnSuccess;
}
ErrorExit:
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateInterruptBandwidth - returning 0x%x(%s)", this, err, USBStringFromReturn(err));
return err;
}
IOReturn
AppleUSBEHCI::ReturnInterruptBandwidth(AppleEHCIQueueHead *pED)
{
int index;
IOReturn err;
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReturnInterruptBandwidth - pED[%p] _speed(%d)", this, pED, (int)pED->_speed);
if (pED->_maxPacketSize == 0)
{
if (pED->_pSPE)
{
USBLog(1, "AppleUSBEHCI[%p]::ReturnInterruptBandwidth - 0 MPS - unexpected _pSPE(%p) in pED(%p)", this, pED->_pSPE, pED);
}
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReturnInterruptBandwidth - 0 MPS always succeeds (no bandwidth to return)!", this);
return kIOReturnSuccess;
}
ShowPeriodicBandwidthUsed(gEHCIBandwidthLogLevel, "+ReturnInterruptBandwidth");
pED->print(gEHCIBandwidthLogLevel, this);
if (pED->_speed == kUSBDeviceSpeedHigh)
{
UInt16 HSallocation;
if (pED->_direction == kUSBIn)
{
HSallocation = kEHCIHSTokenChangeDirectionOverhead + kEHCIHSDataChangeDirectionOverhead + kEHCIHSHandshakeOverhead + _controllerThinkTime;
}
else
{
HSallocation = kEHCIHSTokenSameDirectionOverhead + kEHCIHSDataSameDirectionOverhead + kEHCIHSHandshakeOverhead + _controllerThinkTime;
}
HSallocation += ((pED->_maxPacketSize * 7) / 6);
for (index = (pED->_startFrame * kEHCIuFramesPerFrame) + pED->_startuFrame;
index < (kEHCIMaxPollingInterval * kEHCIuFramesPerFrame);
index += pED->_pollingRate)
{
UInt16 frameNum = index / kEHCIuFramesPerFrame;
UInt16 uFrameNum = index % kEHCIuFramesPerFrame;
ReleasePeriodicBandwidth(frameNum, uFrameNum, HSallocation);
}
ShowPeriodicBandwidthUsed(gEHCIBandwidthLogLevel, "-ReturnInterruptBandwidth");
return kIOReturnSuccess;
}
if (!pED->_pSPE)
{
USBLog (1, "AppleUSBEHCI[%p]::ReturnInterruptBandwidth - no SplitPeriodicEndpoint available", this);
return kIOReturnInternalError;
}
if (!pED->_pSPE->_myTT)
{
USBLog (1, "AppleUSBEHCI[%p]::ReturnInterruptBandwidth - no TT available", this);
return kIOReturnInternalError;
}
pED->_pSPE->_myTT->ShowHSSplitTimeUsed(gEHCIBandwidthLogLevel, "+ReturnInterruptBandwidth");
err = pED->_pSPE->_myTT->DeallocatePeriodicBandwidth(pED->_pSPE);
pED->_pSPE->_FSBytesUsed = 0;
if (err)
{
USBLog (1, "AppleUSBEHCI[%p]::ReturnInterruptBandwidth - pTT->ReturnInterruptBandwidth returned err(%p)", this, (void*)err);
return err;
}
ReturnHSPeriodicSplitBandwidth(pED->_pSPE);
pED->_pSPE->_myTT->CalculateSPEsToAdjustAfterChange(pED->_pSPE, false);
AdjustSPEs(pED->_pSPE, false);
pED->_pSPE->_myTT->ShowHSSplitTimeUsed(gEHCIBandwidthLogLevel, "-ReturnInterruptBandwidth");
ShowPeriodicBandwidthUsed(gEHCIBandwidthLogLevel, "-ReturnInterruptBandwidth");
pED->_pSPE->_myTT->print(gEHCIBandwidthLogLevel, "-ReturnInterruptBandwidth");
pED->_pSPE->release();
pED->_pSPE = NULL;
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::AllocateIsochBandwidth(AppleEHCIIsochEndpoint *pEP, AppleUSBEHCITTInfo *pTT)
{
UInt16 minBandwidthUsed = 0xFFFF;
UInt8 startFrame = 0xFF;
UInt8 startuFrame = 0xFF; bool undoAllocation = false;
UInt16 FSbytesNeeded, HSallocation;
int index;
IOReturn err;
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateIsochBandwidth - pEP[%p] _speed(%d) maxPacketSize(%d)", this, pEP, (int)pEP->_speed, (int)pEP->maxPacketSize);
if (pEP->maxPacketSize == 0)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateIsochBandwidth - 0 MPS always succeeds!", this);
return kIOReturnSuccess;
}
ShowPeriodicBandwidthUsed(gEHCIBandwidthLogLevel, "+AllocateIsochBandwidth");
if (pEP->_speed == kUSBDeviceSpeedHigh)
{
if (pEP->interval > (kEHCIMaxPollingInterval * kEHCIuFramesPerFrame))
pEP->interval = kEHCIMaxPollingInterval * kEHCIuFramesPerFrame;
if (pEP->direction == kUSBIn)
{
HSallocation = kEHCIHSTokenChangeDirectionOverhead + kEHCIHSDataChangeDirectionOverhead + kEHCIHSHandshakeOverhead + _controllerThinkTime;
}
else
{
HSallocation = kEHCIHSTokenSameDirectionOverhead + kEHCIHSDataSameDirectionOverhead + kEHCIHSHandshakeOverhead + _controllerThinkTime;
}
HSallocation += ((pEP->maxPacketSize * 7) / 6);
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateIsochBandwidth - pEP[%p] HSallocation[%d]", this, pEP, HSallocation);
for (index = 0; index < (int)pEP->interval; index++)
{
if (_periodicBandwidthUsed[index / kEHCIuFramesPerFrame][index % kEHCIuFramesPerFrame] < minBandwidthUsed)
{
startFrame = index / kEHCIuFramesPerFrame;
startuFrame = index % kEHCIuFramesPerFrame;
minBandwidthUsed = _periodicBandwidthUsed[startFrame][startuFrame];
}
}
if ((startFrame == 0xFF) || (startuFrame == 0xFF))
{
USBLog(1, "AppleUSBEHCI[%p]::AllocateIsochBandwidth - could not find bandwidth", this);
return kIOReturnNoBandwidth;
}
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateIsochBandwidth - using startFrame[%d] startuFrame[%d]", this, startFrame, startuFrame);
pEP->_startFrame = startFrame;
pEP->_startuFrame = startuFrame;
for (index = (pEP->_startFrame * kEHCIuFramesPerFrame) + pEP->_startuFrame;
index < (kEHCIMaxPollingInterval * kEHCIuFramesPerFrame);
index += pEP->interval)
{
UInt16 frameNum = index / kEHCIuFramesPerFrame;
UInt16 uFrameNum = index % kEHCIuFramesPerFrame;
err = ReservePeriodicBandwidth(frameNum, uFrameNum, HSallocation);
if (err == kIOReturnNoBandwidth)
{
USBLog(1, "AppleUSBEHCI[%p]::AllocateIsochBandwidth - not enough bandwidth", this);
undoAllocation = true;
}
}
if (undoAllocation)
{
for (index = (pEP->_startFrame * kEHCIuFramesPerFrame) + pEP->_startuFrame;
index < (kEHCIMaxPollingInterval * kEHCIuFramesPerFrame);
index += pEP->interval)
{
UInt16 frameNum = index / kEHCIuFramesPerFrame;
UInt16 uFrameNum = index % kEHCIuFramesPerFrame;
ReleasePeriodicBandwidth(frameNum, uFrameNum, HSallocation);
}
return kIOReturnNoBandwidth;
}
ShowPeriodicBandwidthUsed(gEHCIBandwidthLogLevel, "-AllocateIsochBandwidth");
return kIOReturnSuccess;
}
if (!pTT)
{
USBLog(1, "AppleUSBEHCI[%p]::AllocateIsochBandwidth.. no pTT, cannot proceed", this);
return kIOReturnInternalError;
}
pTT->ShowHSSplitTimeUsed(gEHCIBandwidthLogLevel, "+AllocateIsochBandwidth");
FSbytesNeeded = kEHCIFSSplitIsochOverhead + pTT->_thinkTime + pEP->maxPacketSize;
if (pEP->interval != 1)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateIsochBandwidth.. interval != 1. unexpected. fixing.", this);
pEP->interval = 1;
}
if (pEP->pSPE)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateIsochBandwidth - reusing pSPE(%p)", this, pEP->pSPE);
pEP->pSPE->_FSBytesUsed = FSbytesNeeded;
}
else
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateIsochBandwidth - FSBytesNeeded(%d) creating SPE", this, FSbytesNeeded);
pEP->pSPE = AppleUSBEHCISplitPeriodicEndpoint::NewSplitPeriodicEndpoint(pTT, kUSBIsoc, pEP, FSbytesNeeded, pEP->interval);
}
if (!pEP->pSPE)
{
USBLog (1, "AppleUSBEHCI[%p]::AllocateIsochBandwidth - no SplitPeriodicEndpoint available", this);
return kIOReturnInternalError;
}
err = pTT->AllocatePeriodicBandwidth(pEP->pSPE);
if (err)
{
USBLog (gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateIsochBandwidth - pTT->AllocatePeriodicBandwidth returned err(%p)", this, (void*)err);
pEP->pSPE->release();
pEP->pSPE = NULL;
return err;
}
pEP->_startFrame = pEP->pSPE->_startFrame;
err = AllocateHSPeriodicSplitBandwidth(pEP->pSPE);
pTT->ShowHSSplitTimeUsed(gEHCIBandwidthLogLevel, "-AllocateIsochBandwidth");
ShowPeriodicBandwidthUsed(gEHCIBandwidthLogLevel, "-AllocateIsochBandwidth");
pTT->CalculateSPEsToAdjustAfterChange(pEP->pSPE, true);
AdjustSPEs(pEP->pSPE, true);
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateIsochBandwidth - returning kIOReturnSuccess!", this);
pEP->print(gEHCIBandwidthLogLevel);
pTT->ShowHSSplitTimeUsed(gEHCIBandwidthLogLevel, "-AllocateIsochBandwidth");
ShowPeriodicBandwidthUsed(gEHCIBandwidthLogLevel, "-AllocateIsochBandwidth");
pTT->print(gEHCIBandwidthLogLevel, "-AllocateIsochBandwidth");
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::ReturnIsochBandwidth(AppleEHCIIsochEndpoint *pEP)
{
int index;
IOReturn err;
UInt16 HSallocation;
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReturnIsochBandwidth - pEP[%p] _speed(%d)", this, pEP, (int)pEP->_speed);
if (pEP->maxPacketSize == 0)
{
if (pEP->pSPE)
{
USBLog(1, "AppleUSBEHCI[%p]::ReturnIsochBandwidth - 0 MPS - unexpected pSPE(%p) in pEP(%p)", this, pEP->pSPE, pEP);
}
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReturnIsochBandwidth - 0 MPS always succeeds (no bandwidth to return)!", this);
return kIOReturnSuccess;
}
ShowPeriodicBandwidthUsed(gEHCIBandwidthLogLevel, "+ReturnIsochBandwidth");
if (pEP->_speed == kUSBDeviceSpeedHigh)
{
if (pEP->direction == kUSBIn)
{
HSallocation = kEHCIHSTokenChangeDirectionOverhead + kEHCIHSDataChangeDirectionOverhead + kEHCIHSHandshakeOverhead + _controllerThinkTime;
}
else
{
HSallocation = kEHCIHSTokenSameDirectionOverhead + kEHCIHSDataSameDirectionOverhead + kEHCIHSHandshakeOverhead + _controllerThinkTime;
}
HSallocation += ((pEP->maxPacketSize * 7) / 6); for (index = (pEP->_startFrame * kEHCIuFramesPerFrame) + pEP->_startuFrame;
index < (kEHCIMaxPollingInterval * kEHCIuFramesPerFrame);
index += pEP->interval)
{
UInt16 frameNum = index / kEHCIuFramesPerFrame;
UInt16 uFrameNum = index % kEHCIuFramesPerFrame;
ReleasePeriodicBandwidth(frameNum, uFrameNum, HSallocation);
}
ShowPeriodicBandwidthUsed(gEHCIBandwidthLogLevel, "-ReturnIsochBandwidth");
return kIOReturnSuccess;
}
if (!pEP->pSPE)
{
USBLog (1, "AppleUSBEHCI[%p]::ReturnIsochBandwidth - no SplitPeriodicEndpoint available", this);
return kIOReturnInternalError;
}
if (!pEP->pSPE->_myTT)
{
USBLog(1, "AppleUSBEHCI[%p]::ReturnIsochBandwidth.. no pTT, cannot proceed", this);
return kIOReturnInternalError;
}
pEP->pSPE->_myTT->ShowHSSplitTimeUsed(gEHCIBandwidthLogLevel, "+ReturnIsochBandwidth");
err = pEP->pSPE->_myTT->DeallocatePeriodicBandwidth(pEP->pSPE);
pEP->pSPE->_FSBytesUsed = 0;
if (err)
{
USBLog (1, "AppleUSBEHCI[%p]::ReturnIsochBandwidth - pTT->DeallocatePeriodicBandwidth returned err(%p)", this, (void*)err);
return err;
}
ReturnHSPeriodicSplitBandwidth(pEP->pSPE);
pEP->pSPE->_myTT->CalculateSPEsToAdjustAfterChange(pEP->pSPE, false);
AdjustSPEs(pEP->pSPE, false);
pEP->pSPE->_myTT->ShowHSSplitTimeUsed(gEHCIBandwidthLogLevel, "-ReturnIsochBandwidth");
ShowPeriodicBandwidthUsed(gEHCIBandwidthLogLevel, "-ReturnIsochBandwidth");
pEP->pSPE->_myTT->print(gEHCIBandwidthLogLevel, "-ReturnIsochBandwidth");
pEP->pSPE->release();
pEP->pSPE = NULL;
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReturnIsochBandwidth - returning kIOReturnSuccess!", this);
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::AllocateHSPeriodicSplitBandwidth(AppleUSBEHCISplitPeriodicEndpoint *pSPE)
{
int frameNum, uFrameNum;
int effectiveFrame, effectiveuFrame;
int index;
SInt8 startuFrame;
UInt8 lastCSuFrame; UInt16 SSoverhead, CSoverhead; bool undoAllocation = false;
UInt16 realMPS;
IOReturn err;
startuFrame = (pSPE->_startTime / kEHCIFSBytesPeruFrame) - 1;
pSPE->_SSflags = 0;
pSPE->_CSflags = 0;
if (pSPE->_direction == kUSBOut)
{
SSoverhead = kEHCIHSSplitSameDirectionOverhead + kEHCIHSDataSameDirectionOverhead + _controllerThinkTime;
CSoverhead = (pSPE->_epType == kUSBInterrupt) ? kEHCIHSSplitChangeDirectionOverhead + kEHCIHSHandshakeOverhead + _controllerThinkTime : 0;
}
else
{
SSoverhead = kEHCIHSSplitSameDirectionOverhead + _controllerThinkTime;
CSoverhead = kEHCIHSSplitChangeDirectionOverhead + kEHCIHSDataChangeDirectionOverhead + _controllerThinkTime;
}
if (pSPE->_epType == kUSBIsoc)
{
if (pSPE->_direction == kUSBOut)
{
pSPE->_numCS = 0;
pSPE->_numSS = ((pSPE->_isochEP->maxPacketSize - 1) / kEHCIFSBytesPeruFrame) + 1;
}
else
{
lastCSuFrame = ((pSPE->_startTime + pSPE->_FSBytesUsed) / kEHCIFSBytesPeruFrame) + 1;
pSPE->_numSS = 1;
pSPE->_numCS = lastCSuFrame - (startuFrame + 1);
if (lastCSuFrame <=6)
{
if ((startuFrame + 1) == 0)
pSPE->_numCS++;
else
pSPE->_numCS += 2;
}
else if (lastCSuFrame == 7)
{
if ((startuFrame + 1) != 0)
pSPE->_numCS++;
}
}
realMPS = (pSPE->_isochEP->maxPacketSize * 7) / 6;
}
else
{
pSPE->_numSS = 1;
if (startuFrame < 5) pSPE->_numCS = 3;
else
pSPE->_numCS = 2;
realMPS = (pSPE->_intEP->_maxPacketSize * 7) / 6;
}
undoAllocation = false;
USBLog (gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateHSPeriodicSplitBandwidth - calculating the frames - SSoverhead(%d) CSoverhead(%d)", this, SSoverhead, CSoverhead);
for (frameNum = pSPE->_startFrame; frameNum < kEHCIMaxPollingInterval; frameNum += pSPE->_period)
{
int hostuFrame;
for (index = 0, uFrameNum = startuFrame; uFrameNum < startuFrame + pSPE->_numSS; uFrameNum++, index++)
{
UInt16 bytesToAllocate = 0;
if (pSPE->_direction == kUSBOut)
{
bytesToAllocate = realMPS - (kEHCIFSBytesPeruFrame * index);
}
if (bytesToAllocate > kEHCIFSBytesPeruFrame)
bytesToAllocate = kEHCIFSBytesPeruFrame;
hostuFrame = uFrameNum + 1;
effectiveFrame = frameNum;
effectiveuFrame = uFrameNum;
if (uFrameNum < 0)
{
effectiveFrame = (frameNum > 0) ? frameNum - 1 : kEHCIMaxPollingInterval - 1;
effectiveuFrame = kEHCIuFramesPerFrame - 1;
}
else if (uFrameNum >= kEHCIuFramesPerFrame)
{
effectiveFrame = (frameNum + 1) % kEHCIMaxPollingInterval;
effectiveuFrame = uFrameNum % kEHCIuFramesPerFrame;
}
USBLog (gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateHSPeriodicSplitBandwidth - SS index(%d) uFrameNum(%d) bytesToAllocate(%d) effectiveFrame(%d) effectiveuFrame(%d)", this, index, uFrameNum, bytesToAllocate, effectiveFrame, effectiveuFrame);
if (hostuFrame >= kEHCIuFramesPerFrame)
{
USBLog(1, "AppleUSBEHCI[%p]::AllocateHSPeriodicSplitBandwidth - SS can't go into the next frame", this);
}
if (frameNum == pSPE->_startFrame)
{
USBLog (gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateHSPeriodicSplitBandwidth - setting a SS in host uFrame(%d)", this, hostuFrame);
pSPE->_SSflags |= (1 << hostuFrame);
}
err = ReservePeriodicBandwidth(effectiveFrame, effectiveuFrame, SSoverhead+bytesToAllocate);
if (err == kIOReturnNoBandwidth)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateHSPeriodicSplitBandwidth - not enough bandwidth", this);
undoAllocation = true;
}
}
for (uFrameNum = (startuFrame + pSPE->_numSS + 1); uFrameNum < (startuFrame + pSPE->_numSS + 1 + pSPE->_numCS); uFrameNum++)
{
hostuFrame = uFrameNum + 1;
effectiveFrame = frameNum;
effectiveuFrame = uFrameNum;
if (uFrameNum < 0)
{
effectiveFrame = (frameNum > 0) ? frameNum - 1 : kEHCIMaxPollingInterval - 1;
effectiveuFrame = kEHCIuFramesPerFrame - 1;
}
else if (uFrameNum >= kEHCIuFramesPerFrame)
{
effectiveFrame = (frameNum + 1) % kEHCIMaxPollingInterval;
effectiveuFrame = uFrameNum % kEHCIuFramesPerFrame;
}
USBLog (gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateHSPeriodicSplitBandwidth - CS index(%d) uFrameNum(%d) effectiveFrame(%d) effectiveuFrame(%d)", this, index, uFrameNum, effectiveFrame, effectiveuFrame);
if (frameNum == pSPE->_startFrame)
{
if (hostuFrame >= kEHCIuFramesPerFrame)
{
pSPE->_CSflags |= (1 << (hostuFrame % kEHCIuFramesPerFrame));
pSPE->_wraparound = true;
}
else
{
USBLog (gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateHSPeriodicSplitBandwidth - setting a CS in host uFrame(%d)", this, hostuFrame);
pSPE->_CSflags |= (1 << hostuFrame);
}
}
err = ReservePeriodicBandwidth(effectiveFrame, effectiveuFrame, CSoverhead);
if (pSPE->_direction == kUSBIn)
{
if (pSPE->_myTT->_HSSplitINBytesUsed[effectiveFrame][effectiveuFrame] < kEHCIFSBytesPeruFrame)
{
UInt16 spaceAvailable = kEHCIFSBytesPeruFrame - pSPE->_myTT->_HSSplitINBytesUsed[effectiveFrame][effectiveuFrame];
UInt16 bytesToAllocate = realMPS;
if (spaceAvailable < bytesToAllocate)
bytesToAllocate = spaceAvailable;
err = ReservePeriodicBandwidth(effectiveFrame, effectiveuFrame, bytesToAllocate);
}
if (realMPS > kEHCIFSBytesPeruFrame)
{
pSPE->_myTT->ReserveHSSplitINBytes(effectiveFrame, effectiveuFrame, kEHCIFSBytesPeruFrame);
}
else
{
pSPE->_myTT->ReserveHSSplitINBytes(effectiveFrame, effectiveuFrame, realMPS);
}
if (err == kIOReturnNoBandwidth)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AllocateHSPeriodicSplitBandwidth - not enough bandwidth", this);
undoAllocation = true;
}
}
}
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::ReturnHSPeriodicSplitBandwidth(AppleUSBEHCISplitPeriodicEndpoint *pSPE)
{
UInt8 lastCSuFrame; UInt16 bytesToReturn;
UInt16 SSoverhead, CSoverhead; int frameNum, uFrameNum;
int effectiveFrame, effectiveuFrame;
int hostuFrame, index;
SInt8 startuFrame; UInt16 realMPS;
IOReturn err;
if (pSPE->_direction == kUSBOut)
{
SSoverhead = kEHCIHSSplitSameDirectionOverhead + kEHCIHSDataSameDirectionOverhead + _controllerThinkTime;
CSoverhead = (pSPE->_epType == kUSBInterrupt) ? kEHCIHSSplitChangeDirectionOverhead + kEHCIHSHandshakeOverhead + _controllerThinkTime : 0;
}
else
{
SSoverhead = kEHCIHSSplitSameDirectionOverhead + _controllerThinkTime;
CSoverhead = kEHCIHSSplitChangeDirectionOverhead + kEHCIHSDataChangeDirectionOverhead + _controllerThinkTime;
}
if (pSPE->_epType == kUSBIsoc)
{
realMPS = (pSPE->_isochEP->maxPacketSize * 7) / 6;
}
else
{
realMPS = (pSPE->_intEP->_maxPacketSize * 7) / 6;
}
if (!realMPS)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReturnHSPeriodicSplitBandwidth - pSPE[%p] has no maxPacketSize - nothing to do..", this, pSPE);
return kIOReturnSuccess;
}
lastCSuFrame = ((pSPE->_startTime + pSPE->_FSBytesUsed) / kEHCIFSBytesPeruFrame) + 1;
startuFrame = (pSPE->_startTime / kEHCIFSBytesPeruFrame) - 1;
for (frameNum = pSPE->_startFrame; frameNum < kEHCIMaxPollingInterval; frameNum += pSPE->_period)
{
for (index = 0, uFrameNum = startuFrame; uFrameNum < startuFrame + pSPE->_numSS; uFrameNum++, index++)
{
UInt16 bytesAllocated = 0;
if (pSPE->_direction == kUSBOut)
{
bytesAllocated = realMPS - (kEHCIFSBytesPeruFrame * index);
}
if (bytesAllocated > kEHCIFSBytesPeruFrame)
bytesAllocated = kEHCIFSBytesPeruFrame;
hostuFrame = uFrameNum + 1;
effectiveFrame = frameNum;
effectiveuFrame = uFrameNum;
if (uFrameNum < 0)
{
effectiveFrame = (frameNum > 0) ? frameNum - 1 : kEHCIMaxPollingInterval - 1;
effectiveuFrame = kEHCIuFramesPerFrame - 1;
}
else if (uFrameNum >= kEHCIuFramesPerFrame)
{
effectiveFrame = (frameNum + 1) % kEHCIMaxPollingInterval;
effectiveuFrame = uFrameNum % kEHCIuFramesPerFrame;
}
USBLog (gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReturnHSPeriodicSplitBandwidth - SS index(%d) uFrameNum(%d) bytesAllocated(%d) effectiveFrame(%d) effectiveuFrame(%d)", this, index, uFrameNum, bytesAllocated, effectiveFrame, effectiveuFrame);
ReleasePeriodicBandwidth(effectiveFrame, effectiveuFrame, SSoverhead + bytesAllocated);
}
for (uFrameNum = (startuFrame + pSPE->_numSS + 1); uFrameNum < (startuFrame + pSPE->_numSS + 1 + pSPE->_numCS); uFrameNum++)
{
hostuFrame = uFrameNum + 1;
effectiveFrame = frameNum;
effectiveuFrame = uFrameNum;
if (uFrameNum < 0)
{
effectiveFrame = (frameNum > 0) ? frameNum - 1 : kEHCIMaxPollingInterval - 1;
effectiveuFrame = kEHCIuFramesPerFrame - 1;
}
else if (uFrameNum >= kEHCIuFramesPerFrame)
{
effectiveFrame = (frameNum + 1) % kEHCIMaxPollingInterval;
effectiveuFrame = uFrameNum % kEHCIuFramesPerFrame;
}
ReleasePeriodicBandwidth(effectiveFrame, effectiveuFrame, CSoverhead);
if (pSPE->_direction == kUSBIn)
{
bytesToReturn = realMPS;
if (bytesToReturn > kEHCIFSBytesPeruFrame)
bytesToReturn = kEHCIFSBytesPeruFrame;
pSPE->_myTT->ReleaseHSSplitINBytes(effectiveFrame, effectiveuFrame, bytesToReturn);
if (pSPE->_myTT->_HSSplitINBytesUsed[effectiveFrame][effectiveuFrame] < kEHCIFSBytesPeruFrame)
{
bytesToReturn = kEHCIFSBytesPeruFrame - pSPE->_myTT->_HSSplitINBytesUsed[effectiveFrame][effectiveuFrame];
if (realMPS < bytesToReturn)
bytesToReturn = realMPS;
ReleasePeriodicBandwidth(effectiveFrame, effectiveuFrame, bytesToReturn);
}
}
}
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::AdjustSPEs(AppleUSBEHCISplitPeriodicEndpoint *pSPEChanged, bool added)
{
AppleUSBEHCISplitPeriodicEndpoint *pSPE;
AppleUSBEHCITTInfo *pTT = pSPEChanged ? pSPEChanged->_myTT : NULL;
if (!pTT)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AdjustSPEs - no TT - can't do anything!", this);
return kIOReturnInternalError;
}
while (pTT->_pSPEsToAdjust->getCount())
{
UInt16 newStartTime;
pSPE = (AppleUSBEHCISplitPeriodicEndpoint*)pTT->_pSPEsToAdjust->getFirstObject();
pSPE->print(gEHCIBandwidthLogLevel);
pTT->_pSPEsToAdjust->removeObject(pSPE);
newStartTime = pSPE->CalculateNewStartTimeFromChange(pSPEChanged);
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AdjustSPEs - candidate(%p) newStartTime(%d)", this, pSPE, newStartTime);
if (added)
{
if (newStartTime < pSPE->_startTime)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AdjustSPEs - newStartTime(%d) should be >= old _startTime (%d)", this, newStartTime, pSPE->_startTime);
}
}
else
{
if (newStartTime > pSPE->_startTime)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AdjustSPEs - newStartTime(%d) should be <= old _startTime (%d)", this, newStartTime, pSPE->_startTime);
}
}
ReturnHSPeriodicSplitBandwidth(pSPE);
pSPE->_startTime = newStartTime;
pSPE->_SSflags = 0;
pSPE->_CSflags = 0;
AllocateHSPeriodicSplitBandwidth(pSPE);
if (pSPE->_epType == kUSBInterrupt)
{
UInt32 splitFlags;
splitFlags = USBToHostLong(pSPE->_intEP->GetSharedLogical()->splitFlags);
splitFlags &= ~(kEHCIEDSplitFlags_SMask + kEHCIEDSplitFlags_CMask);
splitFlags |= (pSPE->_SSflags << kEHCIEDSplitFlags_SMaskPhase);
splitFlags |= (pSPE->_CSflags << kEHCIEDSplitFlags_CMaskPhase);
pSPE->_intEP->GetSharedLogical()->splitFlags = HostToUSBLong(splitFlags);
}
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::AdjustSPEs - done with pSPE(%p)", this, pSPE);
pSPE->print(gEHCIBandwidthLogLevel);
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::ReservePeriodicBandwidth(int frame, int uFrame, UInt16 bandwidth)
{
if (!bandwidth)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReservePeriodicBandwidth - 0 bandwidth - nothing to do", this);
return kIOReturnSuccess;
}
if (bandwidth > kEHCIHSMaxPeriodicBytesPeruFrame)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReservePeriodicBandwidth - ERROR: bandwidth(%d) too big", this, (int)bandwidth);
return kIOReturnBadArgument;
}
if ((frame < 0) || (frame > kEHCIMaxPollingInterval))
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReservePeriodicBandwidth - ERROR: invalid frame(%d)", this, frame);
return kIOReturnBadArgument;
}
if ((uFrame < 0) || (uFrame > kEHCIuFramesPerFrame))
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReservePeriodicBandwidth - ERROR: invalid uFrame(%d)", this, uFrame);
return kIOReturnBadArgument;
}
_periodicBandwidthUsed[frame][uFrame] += bandwidth;
if (_periodicBandwidthUsed[frame][uFrame] > kEHCIHSMaxPeriodicBytesPeruFrame)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReservePeriodicBandwidth - frame[%d] uFrame[%d] reserved space(%d) over the limit - could be OK", this, frame, uFrame, _periodicBandwidthUsed[frame][uFrame]);
return kIOReturnNoBandwidth;
}
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReservePeriodicBandwidth - frame[%d] uFrame[%d] reserved bandwidth(%d)", this, frame, uFrame, _periodicBandwidthUsed[frame][uFrame]);
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::ReleasePeriodicBandwidth(int frame, int uFrame, UInt16 bandwidth)
{
if (!bandwidth)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReleasePeriodicBandwidth - 0 bandwidth - nothing to do", this);
return kIOReturnSuccess;
}
if (bandwidth > kEHCIHSMaxPeriodicBytesPeruFrame)
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReleasePeriodicBandwidth - ERROR: bandwidth(%d) too big", this, (int)bandwidth);
return kIOReturnBadArgument;
}
if ((frame < 0) || (frame > kEHCIMaxPollingInterval))
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReleasePeriodicBandwidth - ERROR: invalid frame(%d)", this, frame);
return kIOReturnBadArgument;
}
if ((uFrame < 0) || (uFrame > kEHCIuFramesPerFrame))
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReleasePeriodicBandwidth - ERROR: invalid uFrame(%d)", this, uFrame);
return kIOReturnBadArgument;
}
if (bandwidth > _periodicBandwidthUsed[frame][uFrame])
{
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReleasePeriodicBandwidth - ERROR: trying to release(%d) more than you have(%d) - i will take it to zero", this, (int)bandwidth, _periodicBandwidthUsed[frame][uFrame]);
_periodicBandwidthUsed[frame][uFrame] = 0;
return kIOReturnBadArgument;
}
_periodicBandwidthUsed[frame][uFrame] -= bandwidth;
USBLog(gEHCIBandwidthLogLevel, "AppleUSBEHCI[%p]::ReleasePeriodicBandwidth - frame[%d] uFrame[%d] reserved bandwidth(%d)", this, frame, uFrame, _periodicBandwidthUsed[frame][uFrame]);
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::ShowPeriodicBandwidthUsed(int level, const char *fromStr)
{
int frame;
USBLog(level, "AppleUSBEHCI[%p]::ShowPeriodicBandwidthUsed called from %s", this, fromStr);
for (frame = 0; frame < kEHCIMaxPollingInterval; frame++)
USBLog(level, "AppleUSBEHCI[%p]::ShowPeriodicBandwidthUsed - Frame %2.2d: [%3.3d] [%3.3d] [%3.3d] [%3.3d] [%3.3d] [%3.3d] [%3.3d] [%3.3d]",
this, frame,
_periodicBandwidthUsed[frame][0],
_periodicBandwidthUsed[frame][1],
_periodicBandwidthUsed[frame][2],
_periodicBandwidthUsed[frame][3],
_periodicBandwidthUsed[frame][4],
_periodicBandwidthUsed[frame][5],
_periodicBandwidthUsed[frame][6],
_periodicBandwidthUsed[frame][7]);
return kIOReturnSuccess;
}