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);
IOReturn
AppleUSBEHCI::UIMCreateControlEndpoint(UInt8 functionAddress, UInt8 endpointNumber, UInt16 maxPacketSize, UInt8 speed)
{
IOLog("EHCIUIM -- UIMCreateControlEndpoint old version called with no split params\n");
return(kIOReturnInternalError);
}
IOReturn
AppleUSBEHCI::UIMCreateControlEndpoint(UInt8 functionAddress, UInt8 endpointNumber, UInt16 maxPacketSize, UInt8 speed,
USBDeviceAddress highSpeedHub, int highSpeedPort)
{
AppleEHCIQueueHead *pEHCIEndpointDescriptor;
USBLog(3, "AppleUSBEHCI[%p]::UIMCreateControlEndpoint(%d, %d, %d, %d @(%d, %d))\n", 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;
}
pEHCIEndpointDescriptor = AddEmptyCBEndPoint(functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort, kEHCIEDDirectionTD);
if (!pEHCIEndpointDescriptor)
{
USBError(1, "AppleUSBEHCI[%p]::UIMCreateControlEndpoint - could not add empty endpoint", this);
return kIOReturnNoResources;
}
pEHCIEndpointDescriptor->_queueType = kEHCITypeControl;
printAsyncQueue(7, "UIMCreateControlEndpoint");
return kIOReturnSuccess;
}
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;
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->_responseToStall = 0;
return pED;
}
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;
}
void
AppleUSBEHCI::linkAsyncEndpoint(AppleEHCIQueueHead *CBED)
{
IOPhysicalAddress newHorizPtr;
AppleEHCIQueueHead *pEDHead = _AsyncHead;
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;
_pEHCIRegisters->AsyncListAddr = HostToUSBLong(CBED->_sharedPhysical);
}
else
{
CBED->SetPhysicalLink(pEDHead->GetPhysicalLink());
CBED->_logicalNext = pEDHead->_logicalNext;
pEDHead->_logicalNext = CBED;
pEDHead->SetPhysicalLink(newHorizPtr);
}
}
AppleEHCIQueueHead *
AppleUSBEHCI::AddEmptyCBEndPoint(UInt8 functionAddress,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed,
USBDeviceAddress highSpeedHub,
int highSpeedPort,
UInt8 direction)
{
AppleEHCIQueueHead * CBED;
UInt32 cFlag;
UInt32 myDataToggleCntrl;
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;
}
CBED->GetSharedLogical()->flags |= HostToUSBLong(myDataToggleCntrl | cFlag);
linkAsyncEndpoint(CBED);
return CBED;
}
IOReturn
AppleUSBEHCI::UIMCreateControlTransfer(short functionAddress,
short endpointNumber,
IOUSBCompletion completion,
void* CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateControlTransfer- calling the wrong method!", this);
return kIOReturnIPCError;
}
void
AppleUSBEHCI::printAsyncQueue(int level, const char* str)
{
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);
pED = OSDynamicCast(AppleEHCIQueueHead, pED->_logicalNext);
}
}
else
{
USBLog(level, "AppleUSBEHCI[%p]::printAsyncQueue: NULL Async Queue called from %s", this, str);
}
}
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");
}
IOReturn
AppleUSBEHCI::UIMCreateControlTransfer(short functionAddress,
short endpointNumber,
IOUSBCommand* command,
IOMemoryDescriptor* CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
AppleEHCIQueueHead * pEDQueue;
AppleEHCIQueueHead * pEDDummy;
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, &pEDDummy, 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");
EnableAsyncSchedule(false);
}
else
{
USBError(1, "AppleUSBEHCI[%p]::UIMCreateControlTransfer - allocateTDs returned error %x", this, status);
}
return status;
}
AppleEHCIQueueHead *
AppleUSBEHCI::FindControlBulkEndpoint (short functionNumber,
short endpointNumber,
AppleEHCIQueueHead **pEDBack,
short direction)
{
UInt32 unique;
AppleEHCIQueueHead * pEDQueue;
AppleEHCIQueueHead * pEDQueueBack;
short EDDirection;
unique = (UInt32) ((((UInt32) endpointNumber) << kEHCIEDFlags_ENPhase) | ((UInt32) functionNumber));
pEDQueue = _AsyncHead;
pEDQueueBack = NULL;
if(pEDQueue == NULL)
{
USBLog(7, "AppleUSBEHCI[%p]::FindControlBulkEndpoint - pEDQueue is NULL", this);
return NULL;
}
do {
EDDirection = pEDQueue->_direction;
if( ( (USBToHostLong(pEDQueue->GetSharedLogical()->flags) & kEHCIUniqueNumNoDirMask) == unique) && ( ((EDDirection == kEHCIEDDirectionTD) || (EDDirection) == direction)) )
{
if (pEDBack)
*pEDBack = pEDQueueBack;
return pEDQueue;
} else
{
pEDQueueBack = pEDQueue;
pEDQueue = OSDynamicCast(AppleEHCIQueueHead, pEDQueue->_logicalNext);
}
} while (pEDQueue != NULL);
return NULL;
}
IOReturn
AppleUSBEHCI::allocateTDs(AppleEHCIQueueHead* pEDQueue, IOUSBCommand *command, IOMemoryDescriptor* CBP, UInt32 bufferSize, UInt16 direction, Boolean controlTransaction)
{
EHCIGeneralTransferDescriptorPtr pTD1, pTD, pTDnew, pTDLast;
UInt32 myToggle = 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();
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);
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);
return kIOReturnInternalError;
}
}
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 > buffer size - truncating", this);
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 ( (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->pShared->altTD = HostToUSBLong(pTD1->pPhysical); flags |= myDirection | myToggle | kEHCITDStatus_Active | (3<<kEHCITDFlags_CerrPhase);
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
{
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 | (3<<kEHCITDFlags_CerrPhase);
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;
if (status)
{
USBLog(3, "AppleUSBEHCI[%p] CreateGeneralTransfer: returning status 0x%x", this, status);
}
return status;
}
static UInt32
mungeECHIStatus(UInt32 flags, EHCIGeneralTransferDescriptorPtr pHCDoneTD)
{
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_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 , 0, 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
{
USBLog(3, "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);
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;
Complete(completion, errStatus, bufferSizeRemaining);
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 [safeAction != NULL]");
}
}
bufferSizeRemaining = 0; accumErr = kIOReturnSuccess;
}
pHCDoneTD->logicalBuffer = NULL;
USBLog(7, "AppleUSBEHCI[%p]::EHCIUIMDoDoneQueueProcessing - deallocating TD (%p)", this, pHCDoneTD);
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)
{
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, count = 0;
Boolean TDisHalted, shortTransfer, foundNextTD, foundAltTD;
AppleEHCIQueueHead *pQH;
while( (pListElem != NULL) && (count++ < 150000) )
{
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);
if(!TDisHalted && !shortTransfer)
{
if((flags & kEHCITDStatus_Active) != 0)
{ break;
}
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);
}
if (foundNextTD)
{
pQH->GetSharedLogical()->NextqTDPtr = HostToUSBLong(qTD->pPhysical);
}
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;
}
}
}
}
pListElem = (IOUSBControllerListElement*)pListElem->_logicalNext;
}
if(doneQueue != NULL)
{
EHCIUIMDoDoneQueueProcessing(doneQueue, kIOReturnSuccess, safeAction, NULL);
}
if(count > 1000)
{
USBLog(1, "AppleUSBEHCI[%p]::scavengeAnEndpointQueue looks like bad ed queue %x", this, (uint32_t)count);
USBTrace( kUSBTEHCI, kTPEHCIScavengeAnEndpointQueue , (uintptr_t)this, count, 0, 0);
}
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 ( _logicalPeriodicList != NULL )
{
for(i= 0; i<kEHCIPeriodicListEntries; i++)
{
if(_logicalPeriodicList[i] != NULL)
{
err1 = scavengeAnEndpointQueue(_logicalPeriodicList[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);
}
}
}
}
}
IOReturn
AppleUSBEHCI::UIMCreateControlTransfer(short functionAddress,
short endpointNumber,
IOUSBCommand* command,
void* CBP,
bool bufferRounding,
UInt32 bufferSize,
short 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)
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateControlTransfer- calling the wrong method!", this);
return kIOReturnIPCError;
}
IOReturn
AppleUSBEHCI::UIMCreateBulkEndpoint(UInt8 functionAddress,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt8 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 *pEHCIEndpointDescriptor;
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;
pEHCIEndpointDescriptor = AddEmptyCBEndPoint(functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort, direction);
if (pEHCIEndpointDescriptor == NULL)
return kIOReturnNoResources;
pEHCIEndpointDescriptor->_queueType = kEHCITypeBulk;
printAsyncQueue(7, "UIMCreateBulkEndpoint");
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::UIMCreateBulkTransfer(IOUSBCommand* command)
{
AppleEHCIQueueHead *pEDQueue;
AppleEHCIQueueHead *pEDDummy;
IOReturn status;
IOMemoryDescriptor* buffer = command->GetBuffer();
short direction = command->GetDirection();
USBLog(7, "AppleUSBEHCI[%p]::UIMCreateBulkTransfer - adr=%d:%d(%s) cbp=%p:%x cback=[%p:%p:%p])", this,
command->GetAddress(), command->GetEndpoint(), direction == kUSBIn ? "in" : "out",buffer, (int)command->GetReqCount(),
command->GetUSLCompletion().action, command->GetUSLCompletion().target, command->GetUSLCompletion().parameter);
pEDQueue = FindControlBulkEndpoint(command->GetAddress(), command->GetEndpoint(), &pEDDummy, 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 returned error %x", this, 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)
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateBulkTransfer- calling the wrong method!", this);
return kIOReturnIPCError;
}
UInt16
AppleUSBEHCI::validatePollingRate(short rawPollingRate, short speed, int *offset, UInt16 *bytesAvailable)
{
UInt16 pollingRate;
int i;
UInt16 availableBandwidth[kEHCIMaxPoll];
pollingRate = rawPollingRate;
if(speed == kUSBDeviceSpeedHigh)
{
USBLog(5,"AppleUSBEHCI[%p]::validatePollingRate HS pollingRate raw: %d", this, pollingRate);
if(pollingRate <= 3)
{
pollingRate = 1;
}
else
{
if(pollingRate > 16)
{
int count = 0;
USBLog(1,"AppleUSBEHCI[%p]::validatePollingRate: illegal HS polling rate (%d), cooking like FS", this, pollingRate);
USBTrace( kUSBTEHCI, kTPEHCIValidatePollingRate, (uintptr_t)this, 0, pollingRate, 1);
while( (pollingRate >> count) != 1)
count++;
pollingRate = (1 << count);
USBLog(1,"AppleUSBEHCI[%p]::validatePollingRate: (illegal)new cooked polling rate (%d)", this, pollingRate);
USBTrace( kUSBTEHCI, kTPEHCIValidatePollingRate, (uintptr_t)this, 0, pollingRate, 2);
}
else
{
pollingRate = 1 << (pollingRate - 4);
}
}
if(pollingRate > kEHCIMaxPoll)
{
pollingRate = kEHCIMaxPoll;
}
USBLog(5,"AppleUSBEHCI[%p]::validatePollingRate HS pollingRate cooked: %d", this, pollingRate);
}
else
{
int count = 0;
USBLog(5,"AppleUSBEHCI[%p]::validatePollingRate LS/FS pollingRate raw: %d", this, pollingRate);
while( (pollingRate >> count) != 1)
count++;
pollingRate = (1 << count);
if(pollingRate > 32)
{
USBLog(5,"AppleUSBEHCI[%p]::validatePollingRate - Oops LS/FS pollingRate too high: %d, setting to 128", this, pollingRate);
pollingRate = 32;
}
else if( (pollingRate < 8) && (speed == kUSBDeviceSpeedLow) )
{
USBLog(5,"AppleUSBEHCI[%p]::validatePollingRate Oops LS pollingRate too low: %d, setting to 8.", this, pollingRate);
pollingRate = 8;
}
else if(pollingRate == 0)
{
USBLog(5,"AppleUSBEHCI[%p]::validatePollingRate Oops HS pollingRate too low: %d, setting to 1.", this, pollingRate);
pollingRate = 1;
}
USBLog(5, "AppleUSBEHCI[%p]::validatePollingRate LS/FS pollingRate cooked: %d", this, pollingRate);
}
for (i=0; i < pollingRate; i++)
availableBandwidth[i] = kEHCIMaxPeriodicBandwidth;
for (i=0; i < kEHCIMaxPoll; i++)
if (availableBandwidth[i % pollingRate] > _periodicBandwidth[i])
availableBandwidth[i % pollingRate] = _periodicBandwidth[i];
*offset = 0; *bytesAvailable = 0;
for (i=0; i < pollingRate; i++)
if (availableBandwidth[i] > *bytesAvailable)
{
*offset = i;
*bytesAvailable = availableBandwidth[i];
}
return pollingRate;
}
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 = (IOUSBControllerListElement*)start->_logicalNext;
}
start = (IOUSBControllerListElement*)start->_logicalNext;
}
if (!start)
return pIsoch;
pQH = OSDynamicCast(AppleEHCIQueueHead, start);
pollingRate--;
if(pQH && (pQH->_pollM1 < pollingRate))
{
return pIsoch;
}
while(start->_logicalNext != NULL)
{
pQH = OSDynamicCast(AppleEHCIQueueHead, pQH->_logicalNext);
if(pQH && (pQH->_pollM1 < pollingRate))
{
break;
}
start = (IOUSBControllerListElement*)start->_logicalNext;
}
return start;
}
void
AppleUSBEHCI::linkInterruptEndpoint(AppleEHCIQueueHead *pEHCIEndpointDescriptor)
{
short pollingRate;
UInt16 maxPacketSize;
int offset;
IOUSBControllerListElement *pLE;
UInt32 newHorizPtr;
maxPacketSize = pEHCIEndpointDescriptor->_maxPacketSize;
offset = pEHCIEndpointDescriptor->_offset;
pollingRate = pEHCIEndpointDescriptor->_pollM1+1;
USBLog(7, "AppleUSBEHCI[%p]::linkInterruptEndpoint %p rate %d", this, pEHCIEndpointDescriptor, pollingRate);
newHorizPtr = pEHCIEndpointDescriptor->GetPhysicalAddrWithType();
while( offset < kEHCIPeriodicListEntries)
{
pLE = FindIntEDqueue(_logicalPeriodicList[offset], pollingRate);
if(pLE == NULL)
{ if(pEHCIEndpointDescriptor->_logicalNext == NULL)
{
pEHCIEndpointDescriptor->_logicalNext = _logicalPeriodicList[offset];
pEHCIEndpointDescriptor->SetPhysicalLink(USBToHostLong(_periodicList[offset]));
}
else if (pEHCIEndpointDescriptor->_logicalNext != _logicalPeriodicList[offset])
{
USBError(1, "The Apple EHCI driver has found an endpoint with an incorrect link at the begining.");
}
_logicalPeriodicList[offset] = pEHCIEndpointDescriptor;
_periodicList[offset] = HostToUSBLong(newHorizPtr);
USBLog(7, "AppleUSBEHCI[%p]::linkInterruptEndpoint - inserted at top of list %d - next logical (%p) next physical (%p)", this, offset, pEHCIEndpointDescriptor->_logicalNext, (void*)pEHCIEndpointDescriptor->GetPhysicalLink());
}
else if (pEHCIEndpointDescriptor != pLE)
{
if(pEHCIEndpointDescriptor->_logicalNext == NULL)
{
pEHCIEndpointDescriptor->_logicalNext = pLE->_logicalNext;
pEHCIEndpointDescriptor->SetPhysicalLink(pLE->GetPhysicalLink());
}
else if (pEHCIEndpointDescriptor->_logicalNext != pLE->_logicalNext)
{
USBError(1, "The Apple EHCI driver has found an endpoint with an incorrect link in the middle.");
}
pLE->_logicalNext = pEHCIEndpointDescriptor;
pLE->SetPhysicalLink(newHorizPtr);
USBLog(7, "AppleUSBEHCI[%p]::linkInterruptEndpoint - inserted into list %d - next logical (%p) next physical (%p)", this, offset, pEHCIEndpointDescriptor->_logicalNext, (void*)pEHCIEndpointDescriptor->GetPhysicalLink());
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::linkInterruptEndpoint - (%p) already linked into %d (%p)", this, pEHCIEndpointDescriptor, offset, pLE);
}
if (offset < kEHCIMaxPoll)
_periodicBandwidth[offset] -= maxPacketSize;
offset += pollingRate;
}
_periodicEDsInSchedule++;
}
IOReturn
AppleUSBEHCI::UIMCreateInterruptEndpoint(short functionAddress,
short endpointNumber,
UInt8 direction,
short speed,
UInt16 maxPacketSize,
short 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 * pEHCIEndpointDescriptor;
IOUSBControllerListElement * pLE;
IOUSBControllerListElement * temp;
AppleUSBEHCIHubInfo * hiPtr = NULL;
short rawPollingRate = pollingRate;
if (_rootHubFuncAddress == functionAddress)
{
return RootHubStartTimer32(pollingRate);
}
USBLog(7, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint (%d, %d, %s, %d, %d)", this,
functionAddress, endpointNumber, (speed == kUSBDeviceSpeedLow) ? "lo" : "full", 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;
pEHCIEndpointDescriptor = FindInterruptEndpoint(functionAddress, endpointNumber, direction, &temp);
if ( pEHCIEndpointDescriptor != NULL )
{
IOReturn ret;
USBLog(3, "AppleUSBEHCI[%p]: UIMCreateInterruptEndpoint endpoint already existed -- deleting it", 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(3, "AppleUSBEHCI[%p]: UIMCreateInterruptEndpoint endpoint does NOT exist", this);
}
pollingRate = validatePollingRate(pollingRate, speed, &offset, &availableBandwidth);
if (maxPacketSize > availableBandwidth)
{
USBLog (1, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint - no bandwidth", this);
return kIOReturnNoBandwidth;
}
if (highSpeedHub)
{
hiPtr = AppleUSBEHCIHubInfo::GetHubInfo(&_hsHubs, highSpeedHub, highSpeedPort);
if (!hiPtr)
{
USBLog (1, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint - no hub in list", this);
return kIOReturnInternalError;
}
if (maxPacketSize > hiPtr->AvailableInterruptBandwidth())
{
USBLog (1, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint - split transaction - no bandwidth on hub or port (MPS %d, bw %d)", this, maxPacketSize, (uint32_t)hiPtr->AvailableInterruptBandwidth());
return kIOReturnNoBandwidth;
}
}
else
{
USBLog(5, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint - using offset %d with HS bandwidth of %d", this, offset, availableBandwidth);
}
pEHCIEndpointDescriptor = MakeEmptyIntEndPoint(functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort, direction);
if (pEHCIEndpointDescriptor == NULL)
{
USBError(1, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint - could not create empty endpoint", this);
return kIOReturnNoResources;
}
pEHCIEndpointDescriptor->_queueType = kEHCITypeInterrupt;
if (hiPtr)
hiPtr->AllocateInterruptBandwidth(pEHCIEndpointDescriptor, maxPacketSize);
else
{
if (rawPollingRate < 4)
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint - found a raw polling rate of %d", this, rawPollingRate);
USBTrace( kUSBTEHCI, kTPEHCICreateInterruptEndpoint, (uintptr_t)this, functionAddress, endpointNumber, rawPollingRate);
switch (rawPollingRate)
{
case 1: pEHCIEndpointDescriptor->GetSharedLogical()->splitFlags |= HostToUSBLong(0x000000FF);
break;
case 2: pEHCIEndpointDescriptor->GetSharedLogical()->splitFlags |= HostToUSBLong(0x000000055);
break;
case 3: pEHCIEndpointDescriptor->GetSharedLogical()->splitFlags |= HostToUSBLong(0x00000011);
break;
default:
pEHCIEndpointDescriptor->GetSharedLogical()->splitFlags |= HostToUSBLong(0x00000001);
}
}
else
{
pEHCIEndpointDescriptor->GetSharedLogical()->splitFlags |= HostToUSBLong(0x00000001); }
}
pEHCIEndpointDescriptor->_pollM1 = pollingRate-1;
pEHCIEndpointDescriptor->_offset = offset;
pEHCIEndpointDescriptor->_maxPacketSize = maxPacketSize;
if(_greatestPeriod < pollingRate)
{
_greatestPeriod = pollingRate;
}
linkInterruptEndpoint(pEHCIEndpointDescriptor);
USBLog(5, "-AppleUSBEHCI[%p]::UIMCreateInterruptEndpoint", this);
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::UIMCreateIsochEndpoint(short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 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)
{
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;
UInt32 xtraRequest;
IOReturn res;
UInt32 decodedInterval;
USBLog(7, "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 >= 128))
{
USBError(1, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint: bad interval %d", this, interval);
return kIOReturnBadArgument;
}
decodedInterval = (1 << (interval - 1));
}
else
{
hiPtr = AppleUSBEHCIHubInfo::GetHubInfo(&_hsHubs, highSpeedHub, highSpeedPort);
if (!hiPtr)
{
USBLog (1, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint - setting new hub info(%p) bandwidth to kUSBMaxIsocFrameReqCount", this, hiPtr);
return kIOReturnInternalError;
}
decodedInterval = interval;
}
pEP = OSDynamicCast(AppleEHCIIsochEndpoint, FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL));
if (pEP)
{
USBLog(6,"AppleUSBEHCI[%p]::UIMCreateIsochEndpoint endpoint already exists, attempting to change maxPacketSize to %d", this, (uint32_t)maxPacketSize);
if (hiPtr)
{
UInt32 currentMaxPacketSize = pEP->maxPacketSize;
res = hiPtr->ReallocateIsochBandwidth(pEP, maxPacketSize);
if ( res != kIOReturnSuccess )
{
_isochBandwidthAvail += currentMaxPacketSize;
USBLog(4, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint returned bandwidth %d, new available: %d", this, (uint32_t)currentMaxPacketSize, (uint32_t)_isochBandwidthAvail);
}
else
{
_isochBandwidthAvail = _isochBandwidthAvail + currentMaxPacketSize - maxPacketSize;
USBLog(4, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint returned bandwidth %d, claiming %d, new available: %d", this, (uint32_t)currentMaxPacketSize, (uint32_t)maxPacketSize, (uint32_t)_isochBandwidthAvail);
}
return res;
}
curMaxPacketSize = pEP->maxPacketSize;
if (maxPacketSize == curMaxPacketSize)
{
USBLog(4, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint maxPacketSize (%d) the same, no change", this, (uint32_t)maxPacketSize);
return kIOReturnSuccess;
}
if (maxPacketSize > curMaxPacketSize)
{
xtraRequest = maxPacketSize - curMaxPacketSize;
if (xtraRequest > _isochBandwidthAvail)
{
USBLog(1,"AppleUSBEHCI[%p]::UIMCreateIsochEndpoint out of bandwidth, request (extra) = %d, available: %d", this, (uint32_t)xtraRequest, (uint32_t)_isochBandwidthAvail);
USBTrace( kUSBTEHCI, kTPEHCICreateIsochEndpoint, (uintptr_t)this, (uint32_t)xtraRequest, (uint32_t)_isochBandwidthAvail, 1);
return kIOReturnNoBandwidth;
}
_isochBandwidthAvail -= xtraRequest;
USBLog(5, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint grabbing additional bandwidth: %d, new available: %d", this, (uint32_t)xtraRequest, (uint32_t)_isochBandwidthAvail);
} else
{
xtraRequest = curMaxPacketSize - maxPacketSize;
_isochBandwidthAvail += xtraRequest;
USBLog(5, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint returning some bandwidth: %d, new available: %d", this, (uint32_t)xtraRequest, (uint32_t)_isochBandwidthAvail);
}
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;
}
USBLog(5,"AppleUSBEHCI[%p]::UIMCreateIsochEndpoint high speed size %d, mult %d: %d", this, (uint32_t)maxPacketSize, pEP->mult, pEP->oneMPS);
return kIOReturnSuccess;
}
if (maxPacketSize > (hiPtr ? hiPtr->AvailableIsochBandwidth(direction) : _isochBandwidthAvail))
{
USBLog(1,"AppleUSBEHCI[%p]::UIMCreateIsochEndpoint out of bandwidth, request (extra) = %d, available: %d", this,(uint32_t) maxPacketSize, (uint32_t)(hiPtr ? hiPtr->AvailableIsochBandwidth(direction) : _isochBandwidthAvail));
USBTrace( kUSBTEHCI, kTPEHCICreateIsochEndpoint, (uintptr_t)this, maxPacketSize, (uint32_t)(hiPtr ? hiPtr->AvailableIsochBandwidth(direction) : _isochBandwidthAvail), 2 );
return kIOReturnNoBandwidth;
}
pEP = OSDynamicCast(AppleEHCIIsochEndpoint, CreateIsochronousEndpoint(functionAddress, endpointNumber, direction));
if (pEP == NULL)
return kIOReturnNoMemory;
pEP->highSpeedHub = highSpeedHub;
pEP->highSpeedPort = highSpeedPort;
if (hiPtr)
{
if (hiPtr->AllocateIsochBandwidth(pEP, maxPacketSize) != kIOReturnSuccess)
{
USBError(1, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint - could not allocate bandwidth", this);
return kIOReturnNoBandwidth;
}
}
else
{
if(maxPacketSize >1024)
{
pEP->mult = ((maxPacketSize-1)/1024)+1;
pEP->oneMPS = (maxPacketSize+(pEP->mult-1))/pEP->mult;
}
else
{
pEP->mult = 1;
pEP->oneMPS = maxPacketSize;
}
pEP->maxPacketSize = maxPacketSize;
USBLog(5,"AppleUSBEHCI[%p]::UIMCreateIsochEndpoint high speed 2 size %d, mult %d: %d", this, (uint32_t)maxPacketSize, pEP->mult, pEP->oneMPS);
}
pEP->inSlot = kEHCIPeriodicListEntries+1;
pEP->interval = decodedInterval;
pEP->hiPtr = hiPtr;
_isochBandwidthAvail -= maxPacketSize;
USBLog(4, "AppleUSBEHCI[%p]::UIMCreateIsochEndpoint success. bandwidth used = %d, new available: %d", this, (uint32_t)maxPacketSize, (uint32_t)_isochBandwidthAvail);
return kIOReturnSuccess;
}
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 = _logicalPeriodicList[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
{
_logicalPeriodicList[slot] = nextThing;
_periodicList[slot] = HostToUSBLong(thing->GetPhysicalLink());
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;
}
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);
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); 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);
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);
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); }
}
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);
}
}
IOReturn
AppleUSBEHCI::HandleEndpointAbort(short functionAddress,
short endpointNumber,
short direction,
bool clearToggle)
{
AppleEHCIQueueHead *pED;
AppleEHCIQueueHead *pEDQueueBack;
AppleEHCIIsochEndpoint *piEP;
static int reentrantFlag;
if (reentrantFlag)
{
USBLog(1, "AppleUSBEHCI[%p]::HandleEndpointAbort ReEntered!! FERG", this);
USBTrace( kUSBTEHCI, kTPEHCIHandleEndpointAbort , functionAddress, endpointNumber, direction, 1 );
}
reentrantFlag = TRUE;
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 );
reentrantFlag = FALSE;
return kIOReturnBadArgument;
}
USBLog(5, "AppleUSBEHCI[%p]::HandleEndpointAbort: Attempting operation on root hub", this);
reentrantFlag = FALSE;
return SimulateEDAbort( endpointNumber, direction);
}
piEP = OSDynamicCast(AppleEHCIIsochEndpoint, FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL));
if (piEP)
{
reentrantFlag = FALSE;
return AbortIsochEP(piEP);
}
pED = FindControlBulkEndpoint (functionAddress, endpointNumber, &pEDQueueBack, direction);
if(pED != NULL)
{
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 );
reentrantFlag = FALSE;
return kIOUSBEndpointNotFound;
}
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));
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 );
}
reentrantFlag = FALSE;
return kIOReturnSuccess;
}
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);
}
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;
for(i= 0; i < _greatestPeriod; i++)
{
pListElem = _logicalPeriodicList[i];
while ( pListElem != NULL)
{
pEDQueue = OSDynamicCast(AppleEHCIQueueHead, pListElem);
if (pEDQueue)
{
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::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;
}
status = allocateTDs(pEDQueue, command, buffer, command->GetBuffer()->getLength(), direction, false );
if(status != kIOReturnSuccess)
{
USBLog(1, "AppleUSBEHCI[%p]::UIMCreateInterruptTransfer allocateTDs failed %x", this, 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)
{
USBLog(1, "AppleUSBEHCI[%p]UIMCreateInterruptTransfer- calling the wrong method!", this);
return kIOReturnIPCError;
}
void
AppleUSBEHCI::unlinkIntEndpoint(AppleEHCIQueueHead * pED)
{
int i;
IOUSBControllerListElement * pListElem;
int maxPacketSize;
Boolean foundED = false;
USBLog(7, "+AppleUSBEHCI[%p]::unlinkIntEndpoint(%p)", this, pED);
maxPacketSize = (USBToHostLong(pED->GetSharedLogical()->flags) & kEHCIEDFlags_MPS) >> kEHCIEDFlags_MPSPhase;
for(i= pED->_offset; i < kEHCIPeriodicListEntries; i += pED->_pollM1+1)
{
pListElem = OSDynamicCast(IOUSBControllerListElement, _logicalPeriodicList[i]);
if(pED == pListElem)
{
_logicalPeriodicList[i] = pED->_logicalNext;
_periodicList[i] = HostToUSBLong(pED->GetPhysicalLink());
foundED = true;
USBLog(7, "AppleUSBEHCI[%p]::unlinkIntEndpoint- found ED at top of list %d, new logical=%p, new physical=0x%x", this, i, _logicalPeriodicList[i], USBToHostLong(_periodicList[i]));
}
else
{
while(pListElem != NULL)
{
if(pListElem->_logicalNext == pED)
{
pListElem->_logicalNext = pED->_logicalNext;
pListElem->SetPhysicalLink(pED->GetPhysicalLink());
foundED = true;
USBLog(5, "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);
}
}
if (i < kEHCIMaxPoll)
_periodicBandwidth[i] += maxPacketSize;
}
IOSleep(1); pED->_logicalNext = NULL;
if (foundED)
_periodicEDsInSchedule--;
USBLog(7, "-AppleUSBEHCI[%p]::unlinkIntEndpoint(%p)", this, pED);
}
void
AppleUSBEHCI::unlinkAsyncEndpoint(AppleEHCIQueueHead * pED, AppleEHCIQueueHead * pEDQueueBack)
{
UInt32 CMD, STS, count;
if( (pEDQueueBack == NULL) && (pED->_logicalNext == NULL) )
{
USBLog(7, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint: removing sole endpoint %lx", this, (long)pED);
DisableAsyncSchedule(true);
printAsyncQueue(7, "unlinkAsyncEndpoint");
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)
{
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");
_AsyncHead = OSDynamicCast(AppleEHCIQueueHead, pED->_logicalNext);
_pEHCIRegisters->AsyncListAddr = HostToUSBLong(pED->_logicalNext->_sharedPhysical);
pEDQueueBack->SetPhysicalLink(pED->_logicalNext->GetPhysicalAddrWithType());
pED = OSDynamicCast(AppleEHCIQueueHead , pED->_logicalNext);
pED->GetSharedLogical()->flags |= HostToUSBLong(kEHCIEDFlags_H);
printAsyncQueue(7, "unlinkAsyncEndpoint");
}
else if(pEDQueueBack != NULL)
{
printAsyncQueue(7, "unlinkAsyncEndpoint");
pEDQueueBack->SetPhysicalLink(pED->GetPhysicalLink());
pEDQueueBack->_logicalNext = pED->_logicalNext;
printAsyncQueue(7, "unlinkAsyncEndpoint");
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint: ED not head, but pEDQueueBack not NULL",this);
}
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(2, "AppleUSBEHCI[%p]::unlinkAsyncEndpoint: delayed for %d ms after ringing the doorbell", this, (int)count);
_pEHCIRegisters->USBSTS = HostToUSBLong(kEHCIAAEIntBit);
}
}
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 );
}
}
}
}
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;
if (pEP->highSpeedHub != 0)
{
AppleUSBEHCIHubInfo *hiPtr;
hiPtr = AppleUSBEHCIHubInfo::GetHubInfo(&_hsHubs, pEP->highSpeedHub, pEP->highSpeedPort);
if (hiPtr)
{
hiPtr->DeallocateIsochBandwidth(pEP);
}
}
_isochBandwidthAvail += currentMaxPacketSize;
USBLog(4, "AppleUSBEHCI[%p]::DeleteIsochEP returned bandwidth %d, new available: %d", this, (uint32_t)currentMaxPacketSize, (uint32_t)_isochBandwidthAvail);
DeallocateIsochEP(pEP);
return kIOReturnSuccess;
}
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)
return DeleteIsochEP(piEP);
pED = FindControlBulkEndpoint (functionAddress, endpointNumber, &pEDQueueBack, direction);
if(pED == NULL)
{
UInt32 splitFlags;
USBDeviceAddress highSpeedHub;
UInt8 highSpeedPort;
AppleUSBEHCIHubInfo *hiPtr;
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", this);
unlinkIntEndpoint(pED);
splitFlags = USBToHostLong(pED->GetSharedLogical()->splitFlags);
highSpeedHub = (splitFlags & kEHCIEDSplitFlags_HubAddr) >> kEHCIEDSplitFlags_HubAddrPhase;
highSpeedPort = (splitFlags & kEHCIEDSplitFlags_Port) >> kEHCIEDSplitFlags_PortPhase;
if (highSpeedHub)
{
hiPtr = AppleUSBEHCIHubInfo::GetHubInfo(&_hsHubs, highSpeedHub, highSpeedPort);
if (hiPtr)
hiPtr->DeallocateInterruptBandwidth(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);
}
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)
IOReturn
AppleUSBEHCI::CreateHSIsochTransfer(AppleEHCIIsochEndpoint * pEP, IOUSBIsocCommand * command)
{
UInt32 bufferSize;
AppleEHCIIsochTransferDescriptor *pNewITD = NULL;
IOByteCount transferOffset;
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 baseTransferIndex;
UInt32 epInterval;
IOReturn status;
epInterval = pEP->interval;
transferOffset = 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 <= 6) && (bufferSize != 0)); buffPtrSlot++)
{
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);
*(buffP++) = HostToUSBLong( dmaStartAddr & kEHCIPageMask);
*(buffHighP++) = HostToUSBLong( dmaAddrHighBits );
if (buffPtrSlot == 0)
{
pageOffset = dmaStartAddr & kEHCIPageOffsetMask;
ADJUST_SEGMENT_LENGTH(pageOffset);
}
else
{
ADJUST_SEGMENT_LENGTH(0);
}
USBLog(7, "AppleUSBEHCI[%p]::CreateHSIochTransfer - getPhysicalSegment returned start of 0x%x; length:%d ; Buff Ptr0:%x", this, (uint32_t)dmaStartAddr, (uint32_t)segLen, *(buffP-1));
transferOffset += segLen;
bufferSize -= segLen;
}
page = 0;
transactionPtr = &pNewITD->GetSharedLogical()->Transaction0;
for (transfer = 0; transfer < transfersPerTD; transfer++)
{
pNewITD->_framesInTD++;
trLen = (lowLatency ? pLLFrames[baseTransferIndex + transfer].frReqCount : pFrames[baseTransferIndex + transfer].frReqCount);
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;
pageOffset += trLen;
if (pageOffset >= kEHCIPageSize)
{
pageOffset -= kEHCIPageSize;
page++;
}
}
*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;
}
USBLog(7, "AppleUSBEHCI[%p]::CreateHSIsochTransfer - in TD (%p) setting _completion action (%p)", this, pNewITD, pNewITD->_completion.action);
pNewITD->_completion = command->GetUSLCompletion();
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;
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;
if (pEP->direction == kUSBOut)
{
completeSplitFlags = 0; if (reqCount > kUSBEHCIMaxSSOUTsection)
{
transactionCount = (reqCount + (kUSBEHCIMaxSSOUTsection-1)) / kUSBEHCIMaxSSOUTsection; transactionPosition = 1; startSplitFlags = pEP->startSplitFlags; }
else
{
startSplitFlags = pEP->startSplitFlags; transactionPosition = 0; transactionCount = 1; }
}
else
{
startSplitFlags = pEP->startSplitFlags; transactionPosition = 0; transactionCount = 0; completeSplitFlags = pEP->completeSplitFlags; 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)
{
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)
{
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: %Ld, pEP->firstAvailableFrame: %Ld. 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;
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 (!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 > currFrame)
{
currFrame = newCurrFrame;
}
}
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;
}
prevIsochLE = OSDynamicCast(IOUSBControllerIsochListElement, _logicalPeriodicList[pEP->inSlot]);
while (prevIsochLE)
{
prevSITD = OSDynamicCast(AppleEHCISplitIsochTransferDescriptor, prevIsochLE);
if (prevSITD)
{
if (pEP->direction == kUSBIn)
{
AppleEHCIIsochEndpoint *pPrevEP = OSDynamicCast(AppleEHCIIsochEndpoint, prevSITD->_pEndpoint);
if (pPrevEP)
{
if (pPrevEP->hiPtr == pEP->hiPtr)
{
if (pPrevEP->direction == kUSBOut)
{
linkAfter = prevSITD;
}
else if (pPrevEP->isochINSSFrame < pEP->isochINSSFrame)
{
linkAfter = prevSITD;
}
else if ((pPrevEP->isochINSSFrame == pEP->isochINSSFrame) && (prevSITD->_isDummySITD))
{
linkAfter = prevSITD;
}
}
}
}
else
{
UInt8 oldStart = FirstScheduledSSMicroFrame((AppleEHCIIsochEndpoint*)(prevSITD->_pEndpoint));
UInt8 myStart = FirstScheduledSSMicroFrame((AppleEHCIIsochEndpoint*)(pTD->_pEndpoint));
UInt8 oldEnd = LastScheduledSSMicroFrame((AppleEHCIIsochEndpoint*)(prevSITD->_pEndpoint));
UInt8 myEnd = LastScheduledSSMicroFrame((AppleEHCIIsochEndpoint*)(pTD->_pEndpoint));
if ((oldStart < myStart) || ((oldStart == myStart) && (oldEnd < myEnd)))
{
linkAfter = prevSITD;
}
else
{
}
}
}
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(USBToHostLong(_periodicList[pEP->inSlot]));
pTD->_logicalNext = _logicalPeriodicList[pEP->inSlot];
_logicalPeriodicList[pEP->inSlot] = pTD;
_periodicList[pEP->inSlot] = HostToUSBLong(pTD->GetPhysicalAddrWithType());
}
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 ((finFrame - startFrame) > 1)
USBError(1, "AppleUSBEHCI[%p]::AddIsocFramesToSchedule - end - startFrame(0x%Lx) finFrame(0x%Lx)", this, startFrame, finFrame);
USBLog(7, "AppleUSBEHCI[%p]::AddIsocFramesToSchedule - finished, currFrame: %Lx", this, GetFrameNumber() );
}
IOReturn
AppleUSBEHCI::UIMHubMaintenance(USBDeviceAddress highSpeedHub, UInt32 highSpeedPort, UInt32 command, UInt32 flags)
{
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::GetHubInfo(&_hsHubs, highSpeedHub, 0);
if (hiPtr)
{
USBLog(7, "AppleUSBEHCI[%p]::UIMHubMaintenance - adding hub which already exists (%d)", this, highSpeedHub);
AppleUSBEHCIHubInfo::DeleteHubInfoZero(&_hsHubs, highSpeedHub);
}
hiPtr = AppleUSBEHCIHubInfo::NewHubInfoZero(&_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::DeleteHubInfoZero(&_hsHubs, highSpeedHub); break;
default:
return kIOReturnBadArgument;
}
return kIOReturnSuccess;
}
#define kEHCIUIMScratchFirstActiveFrame 0
void
AppleUSBEHCI::ReturnOneTransaction(EHCIGeneralTransferDescriptor *transaction,
AppleEHCIQueueHead *pED,
AppleEHCIQueueHead *pEDBack,
IOReturn err)
{
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);
}
void
AppleUSBEHCI::CheckEDListForTimeouts(AppleEHCIQueueHead *head)
{
AppleEHCIQueueHead *pED = head;
AppleEHCIQueueHead *pEDBack = NULL, *pEDBack1 = NULL;
IOPhysicalAddress pTDPhys;
EHCIGeneralTransferDescriptor *pTD;
UInt32 noDataTimeout;
UInt32 completionTimeout;
UInt32 rem;
UInt32 curFrame = GetFrameNumber32();
for (; pED != 0; pED = (AppleEHCIQueueHead *)pED->_logicalNext)
{
USBLog(7, "AppleUSBEHCI[%p]::CheckEDListForTimeouts - checking ED [%p]", this, pED);
pED->print(7);
pEDBack = pEDBack1;
pEDBack1 = pED;
pTDPhys = USBToHostLong(pED->GetSharedLogical()->CurrqTDPtr) & kEHCIEDTDPtrMask;
pTD = pED->_qTD;
if (!pTD)
{
USBLog(6, "AppleUSBEHCI[%p]::CheckEDListForTimeouts - no TD", this);
continue;
}
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);
}
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);
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);
ReturnOneTransaction(pTD, pED, pEDBack, kIOUSBTransactionTimeout);
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;
continue;
}
if ((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) );
ReturnOneTransaction(pTD, pED, pEDBack, kIOUSBTransactionTimeout);
continue;
}
}
}
void
AppleUSBEHCI::UIMCheckForTimeouts(void)
{
AbsoluteTime currentTime;
AbsoluteTime lastRootHubChangeTime;
UInt64 elapsedTime = 0;
bool allPortsDisconnected = false;
UInt32 usbcmd;
UInt32 usbsts;
if ( isInactive() || !_controllerAvailable || (_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 and USBSTS not synched ON (#%d)", this, _asynchScheduleUnsynchCount);
}
}
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 and USBSTS not synched OFF (#%d)", this, _asynchScheduleUnsynchCount);
}
}
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 and USBSTS not synched ON (#%d)", this, _periodicScheduleUnsynchCount);
}
}
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 and USBSTS not synched ON (#%d)", this, _periodicScheduleUnsynchCount);
}
}
else
_periodicScheduleUnsynchCount = 0;
}
CheckEDListForTimeouts(_AsyncHead);
}
UInt8
AppleUSBEHCI::FirstScheduledSSMicroFrame(AppleEHCIIsochEndpoint *pEP)
{
UInt8 ssFlags = pEP->startSplitFlags;
UInt8 ret = 0;
if (!ssFlags)
return 0;
while ((ssFlags & 1) == 0)
{
ret++;
ssFlags >>= 1;
}
USBLog(6, "AppleUSBEHCI[%p]::FirstScheduledSSMicroFrame(%p): returning %d", this, pEP, ret);
return ret;
}
UInt8
AppleUSBEHCI::LastScheduledSSMicroFrame(AppleEHCIIsochEndpoint *pEP)
{
UInt8 ssFlags = pEP->startSplitFlags;
UInt8 ret = 7;
if (!ssFlags)
return 0;
while ((ssFlags & 0x80) == 0)
{
ret--;
ssFlags <<= 1;
}
USBLog(6, "AppleUSBEHCI[%p]::LastScheduledSSMicroFrame(%p): returning %d", this, pEP, ret);
return ret;
}
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)
{
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");
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:
linkAsyncEndpoint(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;
}
pLEBack = NULL;
for(i= 0; i < _greatestPeriod; i++)
{
pLE = _logicalPeriodicList[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 : _logicalPeriodicList[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");
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");
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:
linkAsyncEndpoint(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;
}
pLEBack = NULL;
for(i= 0; i < _greatestPeriod; i++)
{
pLE = _logicalPeriodicList[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 = _logicalPeriodicList[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");
return kIOReturnSuccess;
}