AppleUSBUHCI_UIM.cpp [plain text]
#include <kern/clock.h>
#include <machine/limits.h>
#include <IOKit/usb/IOUSBRootHubDevice.h>
#include <IOKit/usb/IOUSBLog.h>
#include "AppleUSBUHCI.h"
#include "AppleUHCIListElement.h"
#include "USBTracepoints.h"
#pragma mark Control
IOReturn
AppleUSBUHCI::UIMCreateControlEndpoint(
UInt8 functionNumber,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
return UIMCreateControlEndpoint(functionNumber, endpointNumber, maxPacketSize, speed);
}
IOReturn
AppleUSBUHCI::UIMCreateControlEndpoint(UInt8 functionNumber,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed)
{
AppleUHCIQueueHead *pQH;
AppleUHCIQueueHead *prevQH;
AppleUHCITransferDescriptor *pTD;
if (functionNumber == _rootFunctionNumber)
{
return kIOReturnSuccess;
}
USBLog(3, "AppleUSBUHCI[%p]::UIMCreateControlEndpoint (f %d ep %d) max %d spd %d", this, functionNumber, endpointNumber, maxPacketSize, speed);
if (maxPacketSize == 0)
{
USBLog(1, "AppleUSBUHCI[%p]::UIMCreateControlEndpoint - maxPacketSize 0 is illegal (kIOReturnBadArgument)", this);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCreateControlEndpoint, functionNumber, endpointNumber, speed, kIOReturnBadArgument );
return kIOReturnBadArgument;
}
USBLog(5, "AppleUSBUHCI[%p]::UIMCreateControlEndpoint allocating endpoint", this);
pQH = AllocateQH(functionNumber, endpointNumber, kUSBNone, speed, maxPacketSize, kUSBControl);
if (pQH == NULL)
return kIOReturnNoMemory;
pTD = AllocateTD(pQH);
if (!pTD)
{
DeallocateQH(pQH);
return kIOReturnNoMemory;
}
pTD->GetSharedLogical()->ctrlStatus = 0; pQH->firstTD = pTD;
pQH->lastTD = pTD;
pQH->GetSharedLogical()->elink = HostToUSBLong(pTD->GetPhysicalAddrWithType());
if (speed == kUSBDeviceSpeedLow)
{
prevQH = _lsControlQHEnd;
} else
{
prevQH = _fsControlQHEnd;
}
USBLog(5, "AppleUSBUHCI[%p]::UIMCreateControlEndpoint linking qh %p into schedule after %p", this, pQH, prevQH);
pQH->_logicalNext = prevQH->_logicalNext;
pQH->SetPhysicalLink(prevQH->GetPhysicalLink());
IOSync();
prevQH->_logicalNext = pQH;
prevQH->SetPhysicalLink(pQH->GetPhysicalAddrWithType());
IOSync();
if (speed == kUSBDeviceSpeedLow)
{
_lsControlQHEnd = pQH;
} else
{
_fsControlQHEnd = pQH;
}
USBLog(3, "AppleUSBUHCI[%p]::UIMCreateControlEndpoint done pQH %p FN %d EP %d MPS %d", this, pQH, pQH->functionNumber, pQH->endpointNumber, pQH->maxPacketSize);
return kIOReturnSuccess;
}
IOReturn
AppleUSBUHCI::UIMCreateControlTransfer(short functionNumber,
short endpointNumber,
IOUSBCommand* command,
IOMemoryDescriptor *CBP,
bool bufferRounding, UInt32 bufferSize,
short direction)
{
AppleUHCIQueueHead *pQH;
AppleUHCITransferDescriptor *td, *last_td;
IOReturn status;
USBLog(7, "AppleUSBUHCI[%p]::UIMCreateControlTransfer (f %d ep %d dir %d) size %d", this, functionNumber, endpointNumber, direction, (int)bufferSize);
pQH = FindQueueHead(functionNumber, endpointNumber, kUSBAnyDirn, kUSBControl);
if (pQH == NULL)
{
USBLog(2, "AppleUSBUHCI[%p]::UIMCreateControlTransfer - queue head not found - FN(%d) EN(%d)", this, functionNumber, endpointNumber);
return kIOUSBEndpointNotFound;
}
if (pQH->stalled)
{
if (endpointNumber == 0)
{
USBError(1, "AppleUSBUHCI[%p]::UIMCreateControlTransfer - address %d endpoint 0 is incorrectly marked as stalled!", this, functionNumber);
}
else
{
USBLog(2, "AppleUSBUHCI[%p]::UIMCreateControlTransfer - Control pipe for ep %d stalled", this, endpointNumber);
return kIOUSBPipeStalled;
}
}
USBLog(7, "AppleUSBUHCI[%p]::UIMCreateControlTransfer - allocating TD chain with CBP %p", this, CBP);
status = AllocTDChain(pQH, command, CBP, bufferSize, direction, true);
if (status != kIOReturnSuccess)
{
USBLog(2, "AppleUSBUHCI[%p]::UIMCreateControlTransfer - returning status %p", this, (void*)status);
}
USBLog(7, "AppleUSBUHCI[%p]::UIMCreateControlTransfer - pQH[%p] firstTD[%p] lastTD[%p] status[%p]", this, pQH, pQH->firstTD, pQH->lastTD, (void*)status);
return status;
}
#pragma mark Bulk
IOReturn
AppleUSBUHCI::UIMCreateBulkEndpoint(UInt8 functionNumber,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt16 maxPacketSize,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
return UIMCreateBulkEndpoint(functionNumber, endpointNumber, direction, speed, maxPacketSize);
}
IOReturn
AppleUSBUHCI::UIMCreateBulkEndpoint(UInt8 functionNumber, UInt8 endpointNumber, UInt8 direction, UInt8 speed, UInt8 maxPacketSize)
{
AppleUHCITransferDescriptor *pTD;
AppleUHCIQueueHead *pQH;
AppleUHCIQueueHead *prevQH;
USBLog(5, "AppleUSBUHCI[%p]::UIMCreateBulkEndpoint (fn %d ep %d dir %d) speed %d mp %d", this, functionNumber, endpointNumber, direction, speed, maxPacketSize);
if (maxPacketSize == 0)
{
USBLog(1, "AppleUSBUHCI[%p]::UIMCreateBulkEndpoint - maxPacketSize 0 is illegal (kIOReturnBadArgument)", this);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCreateBulkEndpoint, functionNumber, endpointNumber, direction, kIOReturnBadArgument );
return kIOReturnBadArgument;
}
pQH = AllocateQH(functionNumber, endpointNumber, direction, speed, maxPacketSize, kUSBBulk);
if (pQH == NULL)
{
return kIOReturnNoMemory;
}
USBLog(7, "AppleUSBUHCI[%p]::UIMCreateBulkEndpoint allocating dummy TD", this);
pTD = AllocateTD(pQH);
if (!pTD)
{
DeallocateQH(pQH);
return kIOReturnNoMemory;
}
pTD->GetSharedLogical()->ctrlStatus = 0; pQH->firstTD = pTD;
pQH->lastTD = pTD;
pQH->GetSharedLogical()->elink = HostToUSBLong(pTD->GetPhysicalAddrWithType());
prevQH = _bulkQHEnd;
pQH->_logicalNext = prevQH->_logicalNext;
pQH->SetPhysicalLink(prevQH->GetPhysicalLink());
IOSync();
prevQH->_logicalNext = pQH;
prevQH->SetPhysicalLink(pQH->GetPhysicalAddrWithType());
IOSync();
_bulkQHEnd = pQH;
return kIOReturnSuccess;
}
IOReturn
AppleUSBUHCI::UIMCreateBulkTransfer(IOUSBCommand* command)
{
AppleUHCIQueueHead *pQH = NULL;
IOMemoryDescriptor *mp = NULL;
IOReturn status = 0xDEADBEEF;
USBLog(7, "AppleUSBUHCI[%p]::UIMCreateBulkTransfer (%d, %d, %d) size %d", this, command->GetAddress(), command->GetEndpoint(), command->GetDirection(), (int)command->GetReqCount());
pQH = FindQueueHead(command->GetAddress(), command->GetEndpoint(), command->GetDirection(), kUSBBulk);
if (pQH == NULL)
{
USBLog(2, "AppleUSBUHCI[%p]::UIMCreateBulkTransfer - endpoint (fn %d, ep %d, dir %d) not found", this, command->GetAddress(), command->GetEndpoint(), command->GetDirection() );
return kIOUSBEndpointNotFound;
}
if (pQH->stalled)
{
USBLog(4, "AppleUSBUHCI[%p]::UIMCreateBulkTransfer - Bulk pipe stalled", this);
return kIOUSBPipeStalled;
}
mp = command->GetBuffer();
USBLog(7, "AppleUSBUHCI[%p]::UIMCreateBulkTransfer - allocating TD chain with mp %p", this, mp);
status = AllocTDChain(pQH, command, mp, command->GetReqCount(), command->GetDirection(), false);
if (status != kIOReturnSuccess)
{
USBLog(4, "AppleUSBUHCI[%p]::UIMCreateBulkTransfer - AllocTDChain returns %d", this, status);
return status;
}
return kIOReturnSuccess;
}
#pragma mark Interrupt
IOReturn
AppleUSBUHCI::UIMCreateInterruptEndpoint(
short functionNumber,
short endpointNumber,
UInt8 direction,
short speed,
UInt16 maxPacketSize,
short pollingRate,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
return UIMCreateInterruptEndpoint(functionNumber, endpointNumber, direction, speed, maxPacketSize, pollingRate);
}
IOReturn
AppleUSBUHCI::UIMCreateInterruptEndpoint(short functionNumber,
short endpointNumber,
UInt8 direction,
short speed,
UInt16 maxPacketSize,
short pollingRate)
{
AppleUHCIQueueHead *pQH, *prevQH;
AppleUHCITransferDescriptor *pTD;
int i;
USBLog(3, "AppleUSBUHCI[%p]::UIMCreateInterruptEndpoint (fn %d, ep %d, dir %d) spd %d pkt %d rate %d", this, functionNumber, endpointNumber, direction, speed, maxPacketSize, pollingRate );
if (functionNumber == _rootFunctionNumber)
{
if (endpointNumber != 0 && endpointNumber != 1)
{
USBLog(1, "AppleUSBUHCI[%p]::UIMCreateInterruptEndpoint - maxPacketSize 0 is illegal (kIOReturnBadArgument)", this);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCreateInterruptEndpoint, functionNumber, endpointNumber, direction, kIOReturnBadArgument );
return kIOReturnBadArgument;
}
return RootHubStartTimer32(pollingRate);
}
pQH = FindQueueHead(functionNumber, endpointNumber, direction, kUSBInterrupt);
if ( pQH != NULL )
{
IOReturn ret;
USBLog(2, "AppleUSBUHCI[%p]::UIMCreateInterruptEndpoint endpoint already existed -- deleting it", this);
ret = UIMDeleteEndpoint(functionNumber, endpointNumber, direction);
if ( ret != kIOReturnSuccess)
{
USBLog(1, "AppleUSBUHCI[%p]::UIMCreateInterruptEndpoint deleting endpoint returned %p", this, (void*)ret);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCreateInterruptEndpoint, functionNumber, endpointNumber, direction, ret );
return ret;
}
}
for (i=kUHCI_NINTR_QHS-1; i>=0; i--)
{
if ((1 << i) <= pollingRate)
{
break;
}
}
if (i<0)
{
i = 0;
}
USBLog(5, "AppleUSBUHCI[%p]::UIMCreateInterruptEndpoint - we will use interrupt queue %d, which corresponds to a rate of %d", this, i, (1 << i));
USBLog(7, "AppleUSBUHCI[%p]::UIMCreateInterruptEndpoint allocating endpoint", this);
pQH = AllocateQH(functionNumber, endpointNumber, direction, speed, maxPacketSize, kUSBInterrupt);
if (pQH == NULL)
return kIOReturnNoMemory;
USBLog(7, "AppleUSBUHCI[%p]::UIMCreateInterruptEndpoint allocating dummy TD", this);
pTD = AllocateTD(pQH);
if (!pTD)
{
DeallocateQH(pQH);
return kIOReturnNoMemory;
}
pTD->GetSharedLogical()->ctrlStatus = 0; pQH->firstTD = pTD;
pQH->lastTD = pTD;
pQH->GetSharedLogical()->elink = HostToUSBLong(pTD->GetPhysicalAddrWithType());
pQH->interruptSlot = i;
prevQH = _intrQH[pQH->interruptSlot];
pQH->_logicalNext = prevQH->_logicalNext;
pQH->SetPhysicalLink(prevQH->GetPhysicalLink());
IOSync();
prevQH->_logicalNext = pQH;
prevQH->SetPhysicalLink(pQH->GetPhysicalAddrWithType());
USBLog(3, "AppleUSBUHCI[%p]::UIMCreateInterruptEndpoint done pQH[%p]", this, pQH);
return kIOReturnSuccess;
}
IOReturn
AppleUSBUHCI::UIMCreateInterruptTransfer(IOUSBCommand* command)
{
AppleUHCIQueueHead *pQH;
IOReturn status;
IOMemoryDescriptor *mp;
IOByteCount len;
if (command->GetAddress() == _rootFunctionNumber)
{
IODMACommand *dmaCommand = command->GetDMACommand();
IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor*)dmaCommand->getMemoryDescriptor() : NULL;
if (memDesc)
{
USBLog(3, "AppleUSBUHCI[%p]::UIMCreateInterruptTransfer - root hub interrupt transfer - clearing unneeded memDesc (%p) from dmaCommand (%p)", this, memDesc, dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
if (command->GetEndpoint() == 1)
{
status = RootHubQueueInterruptRead(command->GetBuffer(), command->GetReqCount(), command->GetUSLCompletion());
}
else
{
Complete(command->GetUSLCompletion(), kIOUSBEndpointNotFound, command->GetReqCount());
status = kIOUSBEndpointNotFound;
}
return status;
}
USBLog(7, "AppleUSBUHCI[%p]::UIMCreateInterruptTransfer - adr=(%d,%d) len %d rounding %d", this, command->GetAddress(), command->GetEndpoint(), (int)command->GetReqCount(), command->GetBufferRounding());
pQH = FindQueueHead(command->GetAddress(), command->GetEndpoint(), command->GetDirection(), kUSBInterrupt);
if (pQH == NULL)
{
USBLog(1, "AppleUSBUHCI[%p]::UIMCreateInterruptTransfer - QH not found", this);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCreateInterruptTransfer, command->GetAddress(), command->GetEndpoint(), command->GetDirection(), kIOUSBEndpointNotFound );
return kIOUSBEndpointNotFound;
}
if (pQH->stalled)
{
USBLog(1, "AppleUSBUHCI[%p]::UIMCreateInterruptTransfer - Interrupt pipe stalled", this);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCreateInterruptTransfer, command->GetAddress(), command->GetEndpoint(), command->GetDirection(), kIOUSBPipeStalled );
return kIOUSBPipeStalled;
}
mp = command->GetBuffer();
len = command->GetReqCount();
#define INTERRUPT_TRANSFERS_ONE_PACKET 0
#if INTERRUPT_TRANSFERS_ONE_PACKET
if ((int)len > ep->maxPacketSize)
{
len = ep->maxPacketSize;
}
#endif
USBLog(7, "AppleUSBUHCI[%p]::UIMCreateInterruptTransfer - allocating TD chain with mp %p", this, mp);
status = AllocTDChain(pQH, command, mp, len, command->GetDirection(), false);
if (status != kIOReturnSuccess)
{
return status;
}
USBLog(7, "AppleUSBUHCI[%p]::UIMCreateInterruptTransfer - done", this);
return kIOReturnSuccess;
}
#pragma mark Isochronous
IOReturn
AppleUSBUHCI::UIMCreateIsochEndpoint(short functionNumber,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
return UIMCreateIsochEndpoint(functionNumber, endpointNumber, maxPacketSize, direction);
}
IOReturn
AppleUSBUHCI::UIMCreateIsochEndpoint(short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction)
{
IOUSBControllerIsochEndpoint* pEP;
UInt32 curMaxPacketSize;
UInt32 xtraRequest;
IOReturn res;
USBLog(7, "AppleUSBUHCI[%p]::UIMCreateIsochEndpoint(%d, %d, %d, %d)", this, functionAddress, endpointNumber, (uint32_t)maxPacketSize, direction);
pEP = FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL);
if (pEP)
{
USBLog(6,"AppleUSBUHCI[%p]::UIMCreateIsochEndpoint endpoint already exists, attempting to change maxPacketSize to %d", this, (uint32_t)maxPacketSize);
curMaxPacketSize = pEP->maxPacketSize;
if (maxPacketSize == curMaxPacketSize)
{
USBLog(4, "AppleUSBUHCI[%p]::UIMCreateIsochEndpoint maxPacketSize (%d) the same, no change", this, (uint32_t)maxPacketSize);
return kIOReturnSuccess;
}
if (maxPacketSize > curMaxPacketSize)
{
xtraRequest = maxPacketSize - curMaxPacketSize;
if (xtraRequest > _isocBandwidth)
{
USBLog(1,"AppleUSBUHCI[%p]::UIMCreateIsochEndpoint out of bandwidth, request (extra) = %d, available: %d", this, (uint32_t)xtraRequest, (uint32_t)_isocBandwidth);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCreateIsochEndpoint, (uint32_t)xtraRequest, (uint32_t)_isocBandwidth, kIOReturnNoBandwidth, 1 );
return kIOReturnNoBandwidth;
}
_isocBandwidth -= xtraRequest;
USBLog(5, "AppleUSBUHCI[%p]::UIMCreateIsochEndpoint grabbing additional bandwidth: %d, new available: %d", this, (uint32_t)xtraRequest, (uint32_t)_isocBandwidth);
} else
{
xtraRequest = curMaxPacketSize - maxPacketSize;
_isocBandwidth += xtraRequest;
USBLog(5, "AppleUSBUHCI[%p]::UIMCreateIsochEndpoint returning some bandwidth: %d, new available: %d", this, (uint32_t)xtraRequest, (uint32_t)_isocBandwidth);
}
pEP->maxPacketSize = maxPacketSize;
USBLog(6,"AppleUSBUHCI[%p]::UIMCreateIsochEndpoint new size %d", this, (uint32_t)maxPacketSize);
return kIOReturnSuccess;
}
else
{
USBLog(7,"AppleUSBUHCI[%p]::UIMCreateIsochEndpoint no endpoint", this);
}
if (maxPacketSize > _isocBandwidth)
{
USBLog(1,"AppleUSBUHCI[%p]::UIMCreateIsochEndpoint out of bandwidth, request (extra) = %d, available: %d", this, (uint32_t)maxPacketSize, (uint32_t)_isocBandwidth);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCreateIsochEndpoint, (uint32_t)maxPacketSize, (uint32_t)_isocBandwidth, kIOReturnNoBandwidth, 2 );
return kIOReturnNoBandwidth;
}
pEP = CreateIsochronousEndpoint(functionAddress, endpointNumber, direction);
if (pEP == NULL)
return kIOReturnNoMemory;
pEP->maxPacketSize = maxPacketSize;
USBLog(5,"AppleUSBUHCI[%p]::UIMCreateIsochEndpoint 2 size %d", this, (uint32_t)maxPacketSize);
pEP->inSlot = kUHCI_NVFRAMES+1;
_isocBandwidth -= maxPacketSize;
USBLog(6, "AppleUSBUHCI[%p]::UIMCreateIsochEndpoint success. bandwidth used = %d, new available: %d", this, (uint32_t)maxPacketSize, (uint32_t)_isocBandwidth);
return kIOReturnSuccess;
}
IOReturn
AppleUSBUHCI::DeleteIsochEP(IOUSBControllerIsochEndpoint* pEP)
{
IOUSBControllerIsochEndpoint *curEP, *prevEP;
UInt32 currentMaxPacketSize;
USBLog(7, "AppleUSBUHCI[%p]::DeleteIsochEP (%p)", this, pEP);
if (pEP->activeTDs)
{
USBLog(6, "AppleUSBUHCI[%p]::DeleteIsochEP- there are still %d active TDs - aborting", this, (uint32_t)pEP->activeTDs);
AbortIsochEP(pEP);
if (pEP->activeTDs)
{
USBError(1, "AppleUSBUHCI[%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;
_isocBandwidth += currentMaxPacketSize;
USBLog(4, "AppleUSBUHCI[%p]::DeleteIsochEP returned bandwidth %d, new available: %d", this, (uint32_t)currentMaxPacketSize, (uint32_t)_isocBandwidth);
DeallocateIsochEP(pEP);
return kIOReturnSuccess;
}
IOReturn
AppleUSBUHCI::CreateIsochTransfer(IOUSBControllerIsochEndpoint* pEP, IOUSBIsocCommand *command)
{
AppleUHCIIsochTransferDescriptor *pNewITD=NULL;
UInt64 maxOffset;
UInt64 curFrameNumber = GetFrameNumber();
UInt64 frameDiff;
UInt32 diff32;
IOByteCount transferOffset;
UInt32 bufferSize;
UInt32 ioc = 0;
UInt32 i;
UInt32 pageOffset;
IOPhysicalAddress dmaStartAddr;
IOByteCount segLen;
UInt32 myStatFlags;
UInt32 myDirection;
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();
IOMemoryDescriptor * pBuffer = command->GetBuffer(); UInt64 offset;
IODMACommand::Segment64 segments64;
UInt32 numSegments;
IOReturn status;
USBLog(7, "AppleUSBUHCI[%p]::CreateIsochTransfer - frameCount %d - frameNumberStart %Ld - curFrameNumber %Ld", this, (uint32_t)frameCount, frameNumberStart, curFrameNumber);
USBLog(7, "AppleUSBUHCI[%p]::CreateIsochTransfer - updateFrequency %d - lowLatency %d", this, (uint32_t)updateFrequency, lowLatency);
if (!pEP)
{
USBError(1, "AppleUSBUHCI[%p]::CreateIsochTransfer - no endpoint", this);
return kIOReturnBadArgument;
}
maxOffset = kUHCI_NVFRAMES;
if (frameNumberStart < pEP->firstAvailableFrame)
{
USBLog(3,"AppleUSBUHCI[%p]::CreateIsochTransfer: no overlapping frames - EP (%p) frameNumberStart: %Ld, pEP->firstAvailableFrame: %Ld. Returning 0x%x", this, pEP, frameNumberStart, pEP->firstAvailableFrame, kIOReturnIsoTooOld);
return kIOReturnIsoTooOld;
}
pEP->firstAvailableFrame = frameNumberStart;
switch (pEP->direction)
{
case kUSBIn:
myDirection = kUHCI_TD_PID_IN;
break;
case kUSBOut:
myDirection = kUHCI_TD_PID_OUT;
break;
default:
USBLog(3,"AppleUSBUHCI[%p]::CreateIsochTransfer: bad direction(%d) in pEP[%p]", this, pEP->direction, pEP);
return kIOReturnBadArgument;
}
if (frameNumberStart <= curFrameNumber)
{
if (frameNumberStart < (curFrameNumber - maxOffset))
{
USBLog(3,"AppleUSBUHCI[%p]::CreateIsochTransfer request frame WAY too old. frameNumberStart: %Ld, curFrameNumber: %Ld. Returning 0x%x", this, frameNumberStart, curFrameNumber, kIOReturnIsoTooOld);
return kIOReturnIsoTooOld;
}
USBLog(5,"AppleUSBUHCI[%p]::CreateIsochTransfer WARNING! curframe later than requested, expect some notSent errors! frameNumberStart: %Ld, curFrameNumber: %Ld. USBIsocFrame Ptr: %p, First ITD: %p", this, frameNumberStart, curFrameNumber, pFrames, pEP->toDoEnd);
} else
{ if (frameNumberStart > (curFrameNumber + maxOffset))
{
USBLog(3,"AppleUSBUHCI[%p]::CreateIsochTransfer request frame too far ahead! frameNumberStart: %Ld, curFrameNumber: %Ld", this, frameNumberStart, curFrameNumber);
return kIOReturnIsoTooNew;
}
frameDiff = frameNumberStart - curFrameNumber;
diff32 = (UInt32)frameDiff;
if (diff32 < 2)
{
USBLog(5,"AppleUSBUHCI[%p]::CreateIsochTransfer WARNING! - frameNumberStart less than 2 ms (is %d)! frameNumberStart: %Ld, curFrameNumber: %Ld", this, (uint32_t)diff32, frameNumberStart, curFrameNumber);
}
}
pLLFrames = (IOUSBLowLatencyIsocFrame *)pFrames;
bufferSize = 0;
for ( i = 0; i < frameCount; i++)
{
if (!lowLatency)
{
if (pFrames[i].frReqCount > pEP->maxPacketSize)
{
USBLog(1,"AppleUSBUHCI[%p]::CreateIsochTransfer - Isoch frame (%d) too big (%d) MPS (%d)", this, (uint32_t)(i + 1), pFrames[i].frReqCount, (uint32_t)pEP->maxPacketSize);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCreateIsochTransfer, (uint32_t)(i + 1), pFrames[i].frReqCount, (uint32_t)pEP->maxPacketSize, 1 );
return kIOReturnBadArgument;
}
bufferSize += pFrames[i].frReqCount;
} else
{
if (pLLFrames[i].frReqCount > pEP->maxPacketSize)
{
USBLog(1,"AppleUSBUHCI[%p]::CreateIsochTransfer(LL) - Isoch frame (%d) too big (%d) MPS (%d)", this, (uint32_t)(i + 1), pLLFrames[i].frReqCount, (uint32_t)pEP->maxPacketSize);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCreateIsochTransfer, (uint32_t)(i + 1), pLLFrames[i].frReqCount, (uint32_t)pEP->maxPacketSize, 2 );
return kIOReturnBadArgument;
}
bufferSize += pLLFrames[i].frReqCount;
pLLFrames[i].frStatus = command->GetIsRosettaClient() ? (IOReturn) OSSwapInt32(kUSBLowLatencyIsochTransferKey) : (IOReturn) kUSBLowLatencyIsochTransferKey;
}
}
transferOffset = 0;
for ( i = 0; i < frameCount; i++)
{
UInt16 reqCount;
UInt32 token, ctrlStatus;
pNewITD = AllocateITD();
if (lowLatency)
reqCount = pLLFrames[i].frReqCount;
else
reqCount = pFrames[i].frReqCount;
USBLog(7, "AppleUSBUHCI[%p]::CreateIsochTransfer - new iTD %p size (%d)", this, pNewITD, reqCount);
if (!pNewITD)
{
USBLog(1,"AppleUSBUHCI[%p]::CreateIsochTransfer Could not allocate a new iTD", this);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCreateIsochTransfer, (uintptr_t)this, (uintptr_t)pNewITD, reqCount, 3 );
return kIOReturnNoMemory;
}
pEP->firstAvailableFrame++;
pNewITD->_lowLatency = lowLatency;
offset = transferOffset;
numSegments = 1;
status = dmaCommand->gen64IOVMSegments(&offset, &segments64, &numSegments);
if (status || (numSegments != 1) || ((UInt32)(segments64.fIOVMAddr >> 32) > 0) || ((UInt32)(segments64.fLength >> 32) > 0))
{
USBError(1, "AppleUSBUHCI[%p]::CreateIsochTransfer - could not generate segments err (%p) numSegments (%d) fIOVMAddr (0x%Lx) fLength (0x%Lx)", this, (void*)status, (int)numSegments, segments64.fIOVMAddr, segments64.fLength);
status = status ? status : kIOReturnInternalError;
dmaStartAddr = 0;
segLen = 0;
}
else
{
dmaStartAddr = (IOPhysicalAddress)segments64.fIOVMAddr;
segLen = (UInt32)segments64.fLength;
}
if (segLen > reqCount)
{
segLen = reqCount;
}
if (segLen < reqCount)
{
UHCIAlignmentBuffer *bp = GetIsochAlignmentBuffer();
if (!bp)
{
USBLog(1, "AppleUSBUHCI[%p]:CreateIsochTransfer - could not get the alignment buffer I needed", this);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCreateIsochTransfer, (uintptr_t)this, command->GetAddress(), command->GetEndpoint(), 4 );
USBError(1,"The USB UHCI driver could not get the resources it needed. Transfers will be affected (%d:%d)", command->GetAddress(), command->GetEndpoint());
reqCount = segLen;
break;
}
USBLog(6, "AppleUSBUHCI[%p]:CreateIsochTransfer - using alignment buffer %p at pPhysical %p instead of %p direction %s EP %d", this, (void*)bp->vaddr, (void*)bp->paddr, (void*)dmaStartAddr, (pEP->direction == kUSBOut) ? "OUT" : "IN", pEP->endpointNumber);
pNewITD->alignBuffer = bp;
dmaStartAddr = bp->paddr;
if (pEP->direction == kUSBOut)
{
pBuffer->readBytes(transferOffset, (void *)bp->vaddr, reqCount);
}
bp->userBuffer = pBuffer;
bp->userOffset = transferOffset;
bp->dmaCommand = OSDynamicCast(AppleUSBUHCIDMACommand, dmaCommand);
bp->actCount = 0;
}
transferOffset += reqCount;
bufferSize -= reqCount;
pNewITD->_pFrames = pFrames;
pNewITD->_frameNumber = frameNumberStart + i;
pNewITD->_frameIndex = i;
if (i == (frameCount-1))
{
ioc = kUHCI_TD_IOC;
pNewITD->_completion = command->GetUSLCompletion();
}
else if (lowLatency)
{
if (!updateFrequency)
ioc = (((i+1) % 8) == 0) ? (UInt32)kUHCI_TD_IOC : 0;
else
ioc = (((i+1) % updateFrequency) == 0) ? (UInt32)kUHCI_TD_IOC : 0;
}
else
ioc = 0;
pNewITD->GetSharedLogical()->buffer = HostToUSBLong(dmaStartAddr);
pNewITD->SetPhysicalLink(kUHCI_QH_T);
pNewITD->_lowLatency = lowLatency;
token = myDirection | UHCI_TD_SET_MAXLEN(reqCount) | UHCI_TD_SET_ENDPT(pEP->endpointNumber) | UHCI_TD_SET_ADDR(pEP->functionAddress);
pNewITD->GetSharedLogical()->token = HostToUSBLong(token);
ctrlStatus = kUHCI_TD_ACTIVE | kUHCI_TD_ISO | UHCI_TD_SET_ACTLEN(0) | ioc;
pNewITD->GetSharedLogical()->ctrlStatus = HostToUSBLong(ctrlStatus);
pNewITD->_pEndpoint = pEP;
pNewITD->_requestFromRosettaClient = command->GetIsRosettaClient();
PutTDonToDoList(pEP, pNewITD);
}
USBLog(7, "AppleUSBUHCI[%p]::CreateIsochTransfer - calling AddIsochFramesToSchedule", this);
AddIsochFramesToSchedule(pEP);
return kIOReturnSuccess;
}
IOReturn
AppleUSBUHCI::UIMCreateIsochTransfer(short functionNumber,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameStart,
IOMemoryDescriptor *pBuffer,
UInt32 frameCount,
IOUSBIsocFrame *pFrames)
{
USBError(1, "AppleUSBUHCI::UIMCreateIsochTransfer(LL) - old method");
return kIOReturnIPCError;
}
IOReturn
AppleUSBUHCI::UIMCreateIsochTransfer(short functionNumber,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameStart,
IOMemoryDescriptor *pBuffer,
UInt32 frameCount,
IOUSBLowLatencyIsocFrame *pFrames,
UInt32 updateFrequency)
{
USBError(1, "AppleUSBUHCI::UIMCreateIsochTransfer(LL) - old method");
return kIOReturnIPCError;
}
IOReturn
AppleUSBUHCI::UIMCreateIsochTransfer(IOUSBIsocCommand * command)
{
IOReturn err;
IOUSBControllerIsochEndpoint * pEP;
UInt64 maxOffset;
UInt64 curFrameNumber = GetFrameNumber();
UInt64 frameDiff;
UInt32 diff32;
USBLog(7, "AppleUSBUHCI[%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,"AppleUSBUHCI[%p]::UIMCreateIsochTransfer bad frameCount: %d", this, (uint32_t)command->GetNumFrames());
return kIOReturnBadArgument;
}
pEP = FindIsochronousEndpoint(command->GetAddress(), command->GetEndpoint(), command->GetDirection(), NULL);
if(pEP == NULL)
{
USBLog(1, "AppleUSBUHCI[%p]::UIMCreateIsochTransfer - Endpoint not found", this);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCreateIsochTransfer, (uintptr_t)this, command->GetAddress(), command->GetEndpoint(), 5 );
return kIOUSBEndpointNotFound;
}
return CreateIsochTransfer(pEP, command);
}
#pragma mark Endpoints
IOReturn
AppleUSBUHCI::HandleEndpointAbort(short functionAddress, short endpointNumber, short direction, bool clearToggle)
{
AppleUHCIQueueHead *pQH, *pQHPrev;
UInt32 link = 0;
IOUSBControllerIsochEndpoint *pIsochEP;
AppleUHCITransferDescriptor *savedFirstTD = NULL;
AppleUHCITransferDescriptor *savedLastTD = NULL;
USBLog(4, "AppleUSBUHCI[%p]::HandleEndpointAbort: Addr: %d, Endpoint: %d,%d", this, functionAddress, endpointNumber, direction);
if (functionAddress == _rootFunctionNumber)
{
if ( (endpointNumber != 1) && (endpointNumber != 0) )
{
USBLog(1, "AppleUSBUHCI[%p]::HandleEndpointAbort: bad params - endpNumber: %d", this, endpointNumber );
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMHandleEndpointAbort, (uintptr_t)this, endpointNumber, direction, kIOReturnBadArgument );
return kIOReturnBadArgument;
}
USBLog(5, "AppleUSBUHCI[%p]::HandleEndpointAbort: Attempting operation on root hub", this);
return RHAbortEndpoint(endpointNumber, direction);
}
pIsochEP = FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL);
if (pIsochEP)
{
return AbortIsochEP(pIsochEP);
}
if (pQH = FindQueueHead(functionAddress, endpointNumber, direction, kUSBControl, &pQHPrev), pQH)
{
USBLog(5, "AppleUSBUHCI[%p]::HandleEndpointAbort - Found control queue head %p prev %p", this, pQH, pQHPrev);
}
else if (pQH = FindQueueHead(functionAddress, endpointNumber, direction, kUSBInterrupt, &pQHPrev), pQH)
{
USBLog(5, "AppleUSBUHCI[%p]::HandleEndpointAbort - Found interrupt queue head %p prev %p", this, pQH, pQHPrev);
}
else if (pQH = FindQueueHead(functionAddress, endpointNumber, direction, kUSBBulk, &pQHPrev), pQH)
{
USBLog(5, "AppleUSBUHCI[%p]::HandleEndpointAbort - Found bulk queue head %p prev %p", this, pQH, pQHPrev);
}
if (pQH == NULL)
{
USBLog(1, "AppleUSBUHCI[%p]::HandleEndpointAbort - endpoint not found", this);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMHandleEndpointAbort, (uintptr_t)this, endpointNumber, direction, kIOUSBEndpointNotFound );
return kIOUSBEndpointNotFound;
}
if(pQH->firstTD != pQH->lastTD) {
UInt32 nextToggle = 0;
if (pQHPrev)
{
link = pQHPrev->GetPhysicalLink(); pQHPrev->SetPhysicalLink(pQH->GetPhysicalLink()); IOSleep(1); }
USBLog(4, "AppleUSBUHCI[%p]::HandleEndpointAbort: removing TDs", this);
savedFirstTD = pQH->firstTD;
savedLastTD = pQH->lastTD;
pQH->firstTD = pQH->lastTD;
if (!clearToggle)
{
nextToggle = USBToHostLong(savedFirstTD->GetSharedLogical()->token) & kUHCI_TD_D;
}
if (nextToggle != 0)
{
USBLog(6, "AppleUSBUHCI[%p]::HandleEndpointAbort Preserving a data toggle of 1 in response to an Abort()!", this);
}
pQH->firstTD->GetSharedLogical()->token = HostToUSBLong(nextToggle);
pQH->GetSharedLogical()->elink = HostToUSBLong(pQH->firstTD->GetPhysicalAddrWithType());
IOSync();
if (pQHPrev)
pQHPrev->SetPhysicalLink(link); }
else
{
if ( (USBToHostLong(pQH->firstTD->GetSharedLogical()->token) & kUHCI_TD_D) && !clearToggle )
{
USBLog(6, "AppleUSBUHCI[%p]::HandleEndpointAbort Preserving a data toggle of 1 in response to an Abort()!", this);
}
if (clearToggle)
pQH->firstTD->GetSharedLogical()->token = 0;
pQH->GetSharedLogical()->elink = HostToUSBLong(pQH->firstTD->GetPhysicalAddrWithType());
IOSync();
}
pQH->stalled = false;
USBLog(4, "AppleUSBUHCI[%p]::HandleEndpointAbort: Addr: %d, Endpoint: %d,%d - calling DoDoneQueue", this, functionAddress, endpointNumber, direction);
UHCIUIMDoDoneQueueProcessing(savedFirstTD, kIOUSBTransactionReturned, savedLastTD);
return kIOReturnSuccess;
}
IOReturn
AppleUSBUHCI::UIMAbortEndpoint(short functionAddress, short endpointNumber, short direction)
{
USBLog(3, "AppleUSBUHCI[%p]::UIMAbortEndpoint - endpoint %d:%d,%d", this, functionAddress, endpointNumber, direction);
return HandleEndpointAbort(functionAddress, endpointNumber, direction, false);
}
IOReturn
AppleUSBUHCI::UIMClearEndpointStall(short functionAddress, short endpointNumber, short direction)
{
USBLog(5, "AppleUSBUHCI[%p]::UIMClearEndpointStall - endpoint %d:%d,%d", this, functionAddress, endpointNumber, direction);
return HandleEndpointAbort(functionAddress, endpointNumber, direction, true);
}
IOReturn
AppleUSBUHCI::UIMDeleteEndpoint(short functionNumber, short endpointNumber, short direction)
{
AppleUHCIQueueHead *pQH;
IOUSBControllerIsochEndpoint* pIsochEP;
int i;
AppleUHCIQueueHead *pQHPrev = NULL;
IOReturn err;
USBLog(3, "AppleUSBUHCI[%p]::UIMDeleteEndpoint %d %d %d", this, functionNumber, endpointNumber, direction);
if (functionNumber == _rootFunctionNumber)
{
if (endpointNumber != 0 && endpointNumber != 1)
{
USBLog(1, "AppleUSBUHCI[%p]::UIMDeleteEndpoint - not ep 0 or ep 1 [%d](kIOReturnBadArgument)", this, endpointNumber);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMDeleteEndpoint, (uintptr_t)this, endpointNumber, direction, kIOReturnBadArgument );
return kIOReturnBadArgument;
}
return RHDeleteEndpoint(endpointNumber, direction);
}
pIsochEP = FindIsochronousEndpoint(functionNumber, endpointNumber, direction, NULL);
if (pIsochEP)
return DeleteIsochEP(pIsochEP);
if (pQH = FindQueueHead(functionNumber, endpointNumber, direction, kUSBControl, &pQHPrev), pQH)
{
USBLog(7, "AppleUSBUHCI[%p]::UIMDeleteEndpoint - Found control queue head %p prev %p", this, pQH, pQHPrev);
}
else if (pQH = FindQueueHead(functionNumber, endpointNumber, direction, kUSBInterrupt, &pQHPrev), pQH)
{
USBLog(7, "AppleUSBUHCI[%p]::UIMDeleteEndpoint - Found interrupt queue head %p prev %p", this, pQH, pQHPrev);
}
else if (pQH = FindQueueHead(functionNumber, endpointNumber, direction, kUSBBulk, &pQHPrev), pQH)
{
USBLog(7, "AppleUSBUHCI[%p]::UIMDeleteEndpoint - Found bulk queue head %p prev %p", this, pQH, pQHPrev);
}
if (pQH == NULL)
{
USBLog(1, "AppleUSBUHCI[%p]::UIMDeleteEndpoint - endpoint not found", this);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMDeleteEndpoint, (uintptr_t)this, endpointNumber, direction, kIOUSBEndpointNotFound );
return kIOUSBEndpointNotFound;
}
err = UnlinkQueueHead(pQH, pQHPrev);
if (err)
{
USBLog(1, "AppleUSBUHCI[%p]::UIMDeleteEndpoint - err %p unlinking endpoint", this, (void*)err);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMDeleteEndpoint, (uintptr_t)this, err, 0, 0);
}
if(pQH->firstTD != pQH->lastTD) {
USBLog(5, "AppleUSBUHCI[%p]::UIMDeleteEndpoint: removing TDs", this);
UHCIUIMDoDoneQueueProcessing(pQH->firstTD, kIOUSBTransactionReturned, pQH->lastTD);
pQH->firstTD = pQH->lastTD;
}
if ( pQH->firstTD != NULL )
{
USBLog(7, "AppleUSBUHCI[%p]::UIMDeleteEndpoint - deallocating the dummy TD", this);
DeallocateTD(pQH->firstTD);
pQH->firstTD = NULL;
}
USBLog(7, "AppleUSBUHCI[%p]::UIMDeleteEndpoint: Deallocating %p", this, pQH);
DeallocateQH(pQH);
return kIOReturnSuccess;
}
AppleUHCIQueueHead *
AppleUSBUHCI::FindQueueHead(short functionNumber, short endpointNumber, UInt8 direction, UInt8 type, AppleUHCIQueueHead **ppQHPrev)
{
AppleUHCIQueueHead *pQH, *firstQH, *lastQH, *prevQH = NULL;
USBLog(7, "AppleUSBUHCI[%p]::FindQueueHead(%d, %d, %d, %d)", this, functionNumber, endpointNumber, direction, type);
pQH = _disabledQHList;
while (pQH)
{
if ((pQH->functionNumber == functionNumber) && (pQH->endpointNumber == endpointNumber) && ((direction == kUSBAnyDirn) || (pQH->direction == direction)) && (pQH->type == type))
{
USBLog(2, "AppleUSBUHCI[%p]::FindQueueHead - found Queue Head[%p] on the DISABLED list - returning NULL", this, pQH);
return NULL;
#if 0
if (ppQHPrev)
*ppQHPrev = prevQH;
return pQH;
#endif
}
prevQH = pQH;
pQH = OSDynamicCast(AppleUHCIQueueHead, pQH->_logicalNext);
}
switch (type)
{
case kUSBInterrupt:
firstQH = _intrQH[kUHCI_NINTR_QHS-1];
lastQH = _lsControlQHStart;
break;
case kUSBControl:
firstQH = _lsControlQHStart;
lastQH = _bulkQHStart;
break;
case kUSBBulk:
firstQH = _bulkQHStart;
lastQH = _lastQH;
break;
default:
firstQH = lastQH = NULL;
}
pQH = firstQH;
while (pQH && (pQH != lastQH))
{
USBLog(7, "AppleUSBUHCI[%p]::FindQueueHead - looking at queue head %p (%d, %d, %d, %d)", this, pQH, pQH->functionNumber, pQH->endpointNumber, pQH->direction, pQH->type);
if ((pQH->functionNumber == functionNumber) && (pQH->endpointNumber == endpointNumber) && ((direction == kUSBAnyDirn) || (pQH->direction == direction)) && (pQH->type == type))
{
USBLog(7, "AppleUSBUHCI[%p]::FindQueueHead - found Queue Head %p", this, pQH);
if (ppQHPrev)
*ppQHPrev = prevQH;
return pQH;
}
prevQH = pQH;
pQH = OSDynamicCast(AppleUHCIQueueHead, pQH->_logicalNext);
}
USBLog(7, "AppleUSBUHCI[%p]::FindQueueHead - endpoint not found", this);
return NULL;
}
IOReturn
AppleUSBUHCI::UnlinkQueueHead(AppleUHCIQueueHead *pQH, AppleUHCIQueueHead *pQHBack)
{
if (!pQH || !pQHBack)
{
USBLog(1, "AppleUSBUHCI[%p]::UnlinkQueueHead - invalid params (%p, %p)", this, pQH, pQHBack);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMUnlinkQueueHead, (uintptr_t)this, (uintptr_t)pQH, (uintptr_t)pQHBack, kIOReturnBadArgument );
return kIOReturnBadArgument;
}
USBLog(7, "AppleUSBUHCI[%p]::UnlinkQueueHead(%p, %p)", this, pQH, pQHBack);
if (pQH == _lsControlQHEnd)
_lsControlQHEnd = pQHBack;
else if (pQH == _fsControlQHEnd)
_fsControlQHEnd = pQHBack;
else if (pQH == _bulkQHEnd)
_bulkQHEnd = pQHBack;
pQHBack->SetPhysicalLink(pQH->GetPhysicalLink());
pQHBack->_logicalNext = pQH->_logicalNext;
IOSleep(1);
return kIOReturnSuccess;
}
#pragma mark Transaction starting and completing
#define kUHCIUIMScratchFirstActiveFrame 0
void
AppleUSBUHCI::UIMCheckForTimeouts(void)
{
AbsoluteTime currentTime, t;
UInt64 elapsedTime;
UInt64 frameNumber;
UInt16 status, cmd, intr;
AppleUHCIQueueHead *pQH = NULL, *pQHBack = NULL, *pQHBack1 = NULL;
AppleUHCITransferDescriptor *pTD = NULL;
IOPhysicalAddress pTDPhys;
UInt32 noDataTimeout;
UInt32 completionTimeout;
UInt32 curFrame;
UInt32 rem;
bool logging = false;
int loopCount = 0;
uint64_t tempTime;
if (isInactive() || (_myBusState != kUSBBusStateRunning) || _wakingFromHibernation)
{
return;
}
USBLog(7, "AppleUSBUHCI[%p]::UIMCheckForTimeouts - calling ProcessCompletedTransactions", this);
ProcessCompletedTransactions();
tempTime = mach_absolute_time();
currentTime = *(AbsoluteTime*)&tempTime;
status = ioRead16(kUHCI_STS);
cmd = ioRead16(kUHCI_CMD);
intr = ioRead16(kUHCI_INTR);
if (status & kUHCI_STS_HCH)
{
ioWrite16(kUHCI_STS, kUHCI_STS_HCH);
USBError(1, "AppleUSBUHCI[%p]::UIMCheckForTimeouts - Host controller halted, resetting", this);
Reset(true);
Run(true);
}
frameNumber = GetFrameNumber();
_lastTimeoutFrameNumber = frameNumber;
_lastFrameNumberTime = currentTime;
for (pQH = _lsControlQHStart; pQH && (loopCount++ < 100); pQH = OSDynamicCast(AppleUHCIQueueHead, pQH->_logicalNext))
{
if (pQH == pQH->_logicalNext)
{
USBError(1,"AppleUSBUHCI[%p]::UIMCheckForTimeouts pQH (%p) linked to itself", this, pQH);
}
pQHBack = pQHBack1;
pQHBack1 = pQH;
if (pQH->type == kQHTypeDummy)
continue;
logging = true;
USBLog(7, "AppleUSBUHCI[%p]::UIMCheckForTimeouts - checking QH [%p]", this, pQH);
pQH->print(7);
pTDPhys = USBToHostLong(pQH->GetSharedLogical()->elink);
pTD = pQH->firstTD;
if (!pTD)
{
USBLog(3, "AppleUSBUHCI[%p]::UIMCheckForTimeouts - no TD", this);
continue;
}
if (!pTD->command)
{
USBLog(7, "AppleUSBUHCI[%p]::UIMCheckForTimeouts - found a TD without a command - moving on", this);
continue;
}
if (pTD == pQH->lastTD)
{
USBLog(1, "AppleUSBUHCI[%p]::UIMCheckForTimeouts - ED (%p) - TD is TAIL but there is a command - pTD (%p)", this, pQH, pTD);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCheckForTimeouts, (uintptr_t)this, (uintptr_t)pQH, (uintptr_t)pTD, 1 );
pQH->print(1);
}
if(pTDPhys != pTD->GetPhysicalAddrWithType())
{
USBLog(6, "AppleUSBUHCI[%p]::UIMCheckForTimeouts - pED (%p) - mismatched logical and physical - TD (%p) will be scavenged later", this, pQH, pTD);
pQH->print(7);
pTD->print(7);
continue;
}
noDataTimeout = pTD->command->GetNoDataTimeout();
completionTimeout = pTD->command->GetCompletionTimeout();
curFrame = GetFrameNumber32();
if (completionTimeout)
{
UInt32 firstActiveFrame = pTD->command->GetUIMScratch(kUHCIUIMScratchFirstActiveFrame);
if (!firstActiveFrame)
{
pTD->command->SetUIMScratch(kUHCIUIMScratchFirstActiveFrame, curFrame);
continue;
}
if ((curFrame - firstActiveFrame) >= completionTimeout)
{
USBLog(2, "AppleUSBUHCI[%p]::UIMCheckForTimeouts - Found a TD [%p] on QH [%p] past the completion deadline, timing out! (0x%x - 0x%x)", this, pTD, pQH, (uint32_t)curFrame, (uint32_t)firstActiveFrame);
USBError(1, "AppleUSBUHCI[%p]::Found a transaction past the completion deadline on bus 0x%x, timing out! (Addr: %d, EP: %d)", this, (uint32_t) _busNumber, pQH->functionNumber, pQH->endpointNumber );
pQH->print(2);
ReturnOneTransaction(pTD, pQH, pQHBack, kIOUSBTransactionTimeout);
continue;
}
}
if (!noDataTimeout)
continue;
if (!pTD->lastFrame || (pTD->lastFrame > curFrame))
{
pTD->lastFrame = curFrame;
pTD->lastRemaining = findBufferRemaining(pQH);
continue;
}
rem = findBufferRemaining(pQH);
if (pTD->lastRemaining != rem)
{
pTD->lastRemaining = rem;
continue;
}
if ((curFrame - pTD->lastFrame) >= noDataTimeout)
{
USBLog(2, "AppleUSBUHCI[%p]UIMCheckForTimeouts: Found a transaction (%p) which hasn't moved in 5 seconds, timing out! (0x%x - 0x%x)(CMD:%p STS:%p INTR:%p PORTSC1:%p PORTSC2:%p FRBASEADDR:%p ConfigCMD:%p)", this, pTD, (uint32_t)curFrame, (uint32_t)pTD->lastFrame, (void*)ioRead16(kUHCI_CMD), (void*)ioRead16(kUHCI_STS), (void*)ioRead16(kUHCI_INTR), (void*)ioRead16(kUHCI_PORTSC1), (void*)ioRead16(kUHCI_PORTSC2), (void*)ioRead32(kUHCI_FRBASEADDR), (void*)_device->configRead16(kIOPCIConfigCommand));
USBError(1, "AppleUSBUHCI[%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, pQH->functionNumber, pQH->endpointNumber );
pQH->print(2);
pTD->print(2);
ReturnOneTransaction(pTD, pQH, pQHBack, kIOUSBTransactionTimeout);
continue;
}
}
if (loopCount > 99)
{
USBLog(1,"AppleUSBUHCI[%p]::UIMCheckForTimeouts Too many loops around", this);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMCheckForTimeouts, (uintptr_t)this, loopCount, 0, 2 );
}
if (logging)
{
USBLog(7, "AppleUSBUHCI[%p]::UIMCheckForTimeouts - done", this);
}
}
void
AppleUSBUHCI::ReturnOneTransaction(AppleUHCITransferDescriptor *pTD,
AppleUHCIQueueHead *pQH,
AppleUHCIQueueHead *pQHBack,
IOReturn err)
{
AppleUHCITransferDescriptor *pTDFirst = pTD;
pQHBack->SetPhysicalLink(pQH->GetPhysicalLink());
IOSleep(1);
while(pTD != NULL)
{
if (pTD->callbackOnTD)
{
if (!pTD->multiXferTransaction)
{
USBLog(2, "AppleUSBUHCI[%p]::ReturnOneTransaction - found the end of a non-multi transaction(%p)!", this, pTD);
break;
}
else if (pTD->finalXferInTransaction)
{
USBLog(2, "AppleUSBUHCI[%p]::ReturnOneTransaction - found the end of a MULTI transaction(%p)!", this, pTD);
break;
}
else
{
USBLog(2, "AppleUSBUHCI[%p]::ReturnOneTransaction - returning the non-end of a MULTI transaction(%p)!", this, pTD);
}
}
pTD = OSDynamicCast(AppleUHCITransferDescriptor, pTD->_logicalNext);
}
if(pTD == NULL)
{
USBLog(1, "AppleUSBUHCI[%p]::ReturnOneTransaction - got to the end with no callback", this);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMReturnOneTransaction, (uintptr_t)this, (uintptr_t)pTD, 0, 0 );
}
else
{
pTD = OSDynamicCast(AppleUHCITransferDescriptor, pTD->_logicalNext);
pQH->GetSharedLogical()->elink = HostToUSBLong(pTD->GetPhysicalAddrWithType());
IOSync();
pQH->firstTD = pTD;
pQHBack->SetPhysicalLink(pQH->GetPhysicalAddrWithType()); }
USBLog(5, "AppleUSBUHCI[%p]::ReturnOneTransaction - returning transactions from (%p) to, but not including(%p)", this, pTDFirst, pTD);
UHCIUIMDoDoneQueueProcessing(pTDFirst, err, pTD);
}
UInt32
AppleUSBUHCI::findBufferRemaining(AppleUHCIQueueHead *pQH)
{
UInt32 ctrlStatus, token, bufferSizeRemaining = 0;
AppleUHCITransferDescriptor *pTD = pQH->firstTD;
while (pTD && (pTD != pQH->lastTD))
{
ctrlStatus = USBToHostLong(pTD->GetSharedLogical()->ctrlStatus);
token = USBToHostLong(pTD->GetSharedLogical()->token);
bufferSizeRemaining += (UHCI_TD_GET_MAXLEN(token) - UHCI_TD_GET_ACTLEN(ctrlStatus));
if (pTD->callbackOnTD)
break;
pTD = OSDynamicCast(AppleUHCITransferDescriptor, pTD->_logicalNext);
}
return bufferSizeRemaining;
}
IOReturn
AppleUSBUHCI::TDToUSBError(UInt32 status)
{
IOReturn result;
status &= kUHCI_TD_ERROR_MASK;
if (status == 0)
{
result = kIOReturnSuccess;
} else if (status & kUHCI_TD_CRCTO)
{
result = kIOReturnNotResponding;
} else if (status & kUHCI_TD_BABBLE)
{
result = kIOReturnOverrun;
} else if (status & kUHCI_TD_STALLED)
{
result = kIOUSBPipeStalled;
} else if (status & kUHCI_TD_DBUF)
{
result = kIOReturnOverrun;
} else if (status & kUHCI_TD_CRCTO)
{
result = kIOUSBCRCErr;
} else if (status & kUHCI_TD_BITSTUFF)
{
result = kIOUSBBitstufErr;
} else
{
result = kIOUSBTransactionReturned;
}
return result;
}
#pragma mark Transaction descriptors
IOReturn
AppleUSBUHCI::AllocTDChain(AppleUHCIQueueHead* pQH, IOUSBCommand *command, IOMemoryDescriptor* CBP, UInt32 bufferSize, UInt16 direction, Boolean controlTransaction)
{
AppleUHCITransferDescriptor *pTD1, *pTD, *pTDnew, *pTDLast;
UInt32 myToggle = 0;
UInt32 myDirection = 0;
IOByteCount transferOffset;
UInt32 token;
UInt32 ctrlStatus;
IOReturn status = kIOReturnSuccess;
UInt32 maxPacket;
UInt32 totalPhysLength;
IOPhysicalAddress dmaStartAddr;
UInt32 bytesToSchedule;
IODMACommand *dmaCommand = NULL;
UInt64 offset;
IODMACommand::Segment64 segments64;
UInt32 numSegments;
if(controlTransaction)
{
if(direction != kUSBNone)
{ myToggle = kUHCI_TD_D; }
}
else
{
myToggle = USBToHostLong(pQH->lastTD->GetSharedLogical()->token) & kUHCI_TD_D;
}
switch (direction)
{
case kUSBIn:
myDirection = kUHCI_TD_PID_IN;
break;
case kUSBOut:
myDirection = kUHCI_TD_PID_OUT;
break;
default:
myDirection = kUHCI_TD_PID_SETUP;
}
maxPacket = pQH->maxPacketSize;
if ((bufferSize > 0) && (maxPacket == 0))
{
USBError(1, "AppleUSBUHCI[%p]::AllocTDChain - buffserSize %d with maxPacket %d", this, (int)bufferSize, (int)maxPacket);
return kIOReturnNoResources;
}
pTD1 = AllocateTD(pQH);
if (pTD1 == NULL)
{
USBError(1, "AppleUSBUHCI[%p]::AllocTDChain - can't allocate 1st new TD", this);
return kIOReturnNoMemory;
}
pTD = pTD1;
ctrlStatus = kUHCI_TD_ACTIVE | UHCI_TD_SET_ERRCNT(3) | UHCI_TD_SET_ACTLEN(0);
if (direction == kUSBIn)
ctrlStatus |= kUHCI_TD_SPD;
if (pQH->speed == kUSBDeviceSpeedLow)
ctrlStatus |= kUHCI_TD_LS;
if (CBP && bufferSize)
{
dmaCommand = command->GetDMACommand();
if (!dmaCommand)
{
USBError(1, "AppleUSBUHCI[%p]::AllocTDChain - no dmaCommand", this);
DeallocateTD(pTD1);
return kIOReturnInternalError;
}
if (dmaCommand->getMemoryDescriptor() != CBP)
{
USBError(1, "AppleUSBUHCI[%p]::AllocTDChain - mismatched CBP (%p) and dmaCommand memory descriptor (%p)", this, CBP, dmaCommand->getMemoryDescriptor());
DeallocateTD(pTD);
return kIOReturnInternalError;
}
}
if (bufferSize != 0)
{
transferOffset = 0;
while (transferOffset < bufferSize)
{
offset = transferOffset;
numSegments = 1;
status = dmaCommand->gen64IOVMSegments(&offset, &segments64, &numSegments);
if (status || (numSegments != 1))
{
USBError(1, "AppleUSBUHCI[%p]::AllocTDChain - could not generate segments err (%p) offset (%d) transferOffset (%d) bufferSize (%d) getMemoryDescriptor (%p)", this, (void*)status, (int)offset, (int)transferOffset, (int)bufferSize, dmaCommand->getMemoryDescriptor());
status = status ? status : kIOReturnInternalError;
return status;
}
if (((UInt32)(segments64.fIOVMAddr >> 32) > 0) || ((UInt32)(segments64.fLength >> 32) > 0))
{
USBError(1, "AppleUSBUHCI[%p]::AllocTDChain - generated segment not 32 bit - offset (0x%Lx) length (0x%Lx) ", this, segments64.fIOVMAddr, segments64.fLength);
return kIOReturnInternalError;
}
dmaStartAddr = (IOPhysicalAddress)segments64.fIOVMAddr;
totalPhysLength = (UInt32)segments64.fLength;
USBLog(7, "AppleUSBUHCI[%p]::AllocTDChain - gen64IOVMSegments returned length of %d (out of %d) and start of 0x%x", this, (uint32_t)totalPhysLength, (uint32_t)bufferSize, (uint32_t)dmaStartAddr);
bytesToSchedule = 0;
if ((bufferSize-transferOffset) > maxPacket)
{
bytesToSchedule = maxPacket;
}
else
{
bytesToSchedule = (bufferSize-transferOffset);
}
if (totalPhysLength < bytesToSchedule)
{
UHCIAlignmentBuffer *bp;
bp = GetCBIAlignmentBuffer();
if (!bp)
{
USBError(1, "AppleUSBUHCI[%p]:AllocTDChain - could not get the alignment buffer I needed", this);
return kIOReturnNoResources;
}
USBLog(1, "AppleUSBUHCI[%p]:AllocTDChain - pTD (%p) using UHCIAlignmentBuffer (%p) paddr (%p) instead of CBP (%p) dmaStartAddr (%p) totalPhysLength (%d) bytesToSchedule (%d)", this, pTD, bp, (void*)bp->paddr, CBP, (void*)dmaStartAddr, (int)totalPhysLength, (int)bytesToSchedule);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMAllocateTDChain, (uintptr_t)this, (uintptr_t)pTD, (uintptr_t)bp, 1);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMAllocateTDChain, (uintptr_t)this, bp->paddr, (uintptr_t)CBP, 2);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMAllocateTDChain, (uintptr_t)this, dmaStartAddr, totalPhysLength, bytesToSchedule);
pTD->alignBuffer = bp;
dmaStartAddr = bp->paddr;
if (direction != kUSBIn)
{
CBP->readBytes(transferOffset, (void *)bp->vaddr, bytesToSchedule);
}
bp->userBuffer = CBP;
bp->userOffset = transferOffset;
bp->actCount = 0;
}
transferOffset += bytesToSchedule;
pTD->direction = direction;
pTD->GetSharedLogical()->buffer = HostToUSBLong(dmaStartAddr);
token = myDirection | myToggle | UHCI_TD_SET_MAXLEN(bytesToSchedule) | UHCI_TD_SET_ENDPT(pQH->endpointNumber) | UHCI_TD_SET_ADDR(pQH->functionNumber);
pTD->GetSharedLogical()->token = HostToUSBLong(token);
myToggle = myToggle ? 0 : (int)kUHCI_TD_D;
USBLog(7, "AppleUSBUHCI[%p]::AllocTDChain - putting command into TD (%p) on QH (%p)", this, pTD, pQH);
pTD->command = command; if (transferOffset >= bufferSize)
{
ctrlStatus |= kUHCI_TD_IOC;
pTD->callbackOnTD = true;
pTD->logicalBuffer = CBP;
pTD->GetSharedLogical()->ctrlStatus = HostToUSBLong(ctrlStatus & ~kUHCI_TD_SPD); pTD->multiXferTransaction = command->GetMultiTransferTransaction();
pTD->finalXferInTransaction = command->GetFinalTransferInTransaction();
}
else
{
pTD->callbackOnTD = false;
pTDnew = AllocateTD(pQH);
if (pTDnew == NULL)
{
status = kIOReturnNoMemory;
USBError(1, "AppleUSBUHCI[%p]::AllocTDChain can't allocate new TD", this);
}
else
{
pTD->SetPhysicalLink(pTDnew->GetPhysicalAddrWithType());
pTD->_logicalNext = pTDnew; pTD->GetSharedLogical()->ctrlStatus = HostToUSBLong(ctrlStatus);
pTD = pTDnew;
USBLog(7, "AppleUSBUHCI[%p]::AllocTDChain - got another TD - going to fill it up too (%d, %d)", this, (uint32_t)transferOffset, (uint32_t)bufferSize);
}
}
}
}
else
{
USBLog(7, "AppleUSBUHCI[%p]::AllocTDChain - (no buffer)- putting command into TD (%p) on QH (%p)", this, pTD, pQH);
pTD->command = command; ctrlStatus |= kUHCI_TD_IOC;
pTD->callbackOnTD = true;
pTD->multiXferTransaction = command->GetMultiTransferTransaction();
pTD->finalXferInTransaction = command->GetFinalTransferInTransaction();
pTD->logicalBuffer = CBP;
token = myDirection | myToggle | UHCI_TD_SET_MAXLEN(0) | UHCI_TD_SET_ENDPT(pQH->endpointNumber) | UHCI_TD_SET_ADDR(pQH->functionNumber);
pTD->GetSharedLogical()->token = HostToUSBLong(token);
pTD->GetSharedLogical()->ctrlStatus = HostToUSBLong(ctrlStatus);
myToggle = myToggle ? 0 : (int)kUHCI_TD_D;
}
pTDLast = pQH->lastTD;
pTD->SetPhysicalLink(pTD1->GetPhysicalAddrWithType());
pTD->_logicalNext = pTD1;
ctrlStatus = pTD1->GetSharedLogical()->ctrlStatus;
pTD1->GetSharedLogical()->ctrlStatus = 0;
pTDLast->SetPhysicalLink(pTD1->GetPhysicalLink());
pTDLast->GetSharedLogical()->ctrlStatus = pTD1->GetSharedLogical()->ctrlStatus;
pTDLast->GetSharedLogical()->token = pTD1->GetSharedLogical()->token;
pTDLast->GetSharedLogical()->buffer = pTD1->GetSharedLogical()->buffer;
USBLog(7, "AppleUSBUHCI[%p]::AllocTDChain - 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->_logicalNext = pTD1->_logicalNext;
pTDLast->logicalBuffer = pTD1->logicalBuffer;
if (pTD1->alignBuffer)
{
USBLog(1, "AppleUSBUHCI[%p]::AllocTDChain - moving alignBuffer from TD (%p) to TD (%p)", this, pTD1, pTDLast);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMAllocateTDChain, (uintptr_t)this, (uintptr_t)pTD1, (uintptr_t)pTDLast, 3);
}
pTDLast->alignBuffer = pTD1->alignBuffer;
pTD->SetPhysicalLink(pTD1->GetPhysicalAddrWithType());
pTD->_logicalNext = pTD1;
pTD1->SetPhysicalLink(kUHCI_TD_T);
pTD1->GetSharedLogical()->token = HostToUSBLong(myToggle); pTD1->GetSharedLogical()->buffer = 0; pTD1->_logicalNext = NULL;
pTD1->alignBuffer = NULL;
USBLog(7, "AppleUSBUHCI[%p]::AllocTDChain - zeroing out command in TD (%p)", this, pTD1);
pTD1->command = NULL;
pQH->lastTD = pTD1;
pTDLast->GetSharedLogical()->ctrlStatus = ctrlStatus;
USBLog(7, "AllocTDChain - TD list for QH %p firstTD %p lastTD %p ================================================", pQH, pQH->firstTD, pQH->lastTD);
pTD = pQH->firstTD;
while (pTD)
{
pTD->print(7);
pTD = (AppleUHCITransferDescriptor*)pTD->_logicalNext;
}
USBLog(7, "AllocTDChain - end of chain =========================================================");
if (status)
{
USBLog(2, "AppleUSBUHCI[%p]::AllocTDChain: returning status 0x%x", this, status);
}
if ((pQH->type == kUSBControl) || (pQH->type == kUSBBulk))
{
if (!_controlBulkTransactionsOut)
{
UInt32 link;
link = _lastQH->GetPhysicalLink();
USBLog(7, "AppleUSBUHCI[%p]::AllocTDChain - first transaction - unblocking list (%p to %p)", this, (void*)link, (void*)(link & ~kUHCI_QH_T));
_lastQH->SetPhysicalLink(link & ~kUHCI_QH_T);
}
_controlBulkTransactionsOut++;
USBLog(7, "AppleUSBUHCI[%p]::AllocTDChain - _controlBulkTransactionsOut(%p)", this, (void*)_controlBulkTransactionsOut);
}
return status;
}
void
AppleUSBUHCI::AddIsochFramesToSchedule(IOUSBControllerIsochEndpoint* pEP)
{
UInt64 currFrame, startFrame, finFrame;
IOUSBControllerIsochListElement *pTD = NULL;
UInt16 nextSlot, firstOutSlot;
uint64_t currentTime;
if(pEP->toDoList == NULL)
{
USBLog(7, "AppleUSBUHCI[%p]::AddIsochFramesToSchedule - no frames to add fn:%d EP:%d", this, pEP->functionAddress, pEP->endpointNumber);
return;
}
if(pEP->aborting)
{
USBLog(1, "AppleUSBUHCI[%p]::AddIsochFramesToSchedule - EP (%p) is aborting - not adding", this, pEP);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMAddIsochFramesToSchedule, (uintptr_t)this, pEP->functionAddress, pEP->endpointNumber, 1);
return;
}
if (!IOSimpleLockTryLock(_isochScheduleLock))
{
USBError(1, "AppleUSBUHCI[%p]::AddIsochFramesToSchedule - could not obtain scheduling lock", this);
return;
}
currFrame = GetFrameNumber();
startFrame = currFrame;
currentTime = mach_absolute_time();
while(pEP->toDoList->_frameNumber <= (currFrame+1)) {
IOReturn ret;
UInt64 newCurrFrame;
pTD = GetTDfromToDoList(pEP);
ret = pTD->UpdateFrameList(*(AbsoluteTime *)¤tTime); if (pEP->scheduledTDs > 0)
PutTDonDeferredQueue(pEP, pTD);
else
{
PutTDonDoneQueue(pEP, pTD, true);
}
if(pEP->toDoList == NULL)
{
IOSimpleLockUnlock(_isochScheduleLock);
USBLog(7, "AppleUSBUHCI[%p]::AddIsochFramesToSchedule - calling the ReturnIsocDoneQueue on a separate thread", this);
thread_call_enter1(_returnIsochDoneQueueThread, (thread_call_param_t) pEP);
return;
}
newCurrFrame = GetFrameNumber();
if (newCurrFrame > currFrame)
{
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMAddIsochFramesToSchedule, (uintptr_t)this, currFrame, newCurrFrame, 2);
currFrame = newCurrFrame;
}
}
firstOutSlot = (currFrame+1) & kUHCI_NVFRAMES_MASK;
currFrame = pEP->toDoList->_frameNumber;
pEP->inSlot = currFrame & kUHCI_NVFRAMES_MASK;
do
{
nextSlot = (pEP->inSlot + 1) & kUHCI_NVFRAMES_MASK;
if (pEP->inSlot == _outSlot)
{
break;
}
if( nextSlot == _outSlot) {
break;
}
pTD = GetTDfromToDoList(pEP);
if(currFrame == pTD->_frameNumber)
{
if(_outSlot > kUHCI_NVFRAMES)
{
_outSlot = firstOutSlot;
}
pTD->print(7);
pTD->SetPhysicalLink(USBToHostLong(_frameList[pEP->inSlot]));
pTD->_logicalNext = _logicalFrameList[pEP->inSlot];
_logicalFrameList[pEP->inSlot] = pTD;
_frameList[pEP->inSlot] = HostToUSBLong(pTD->GetPhysicalAddrWithType());
OSIncrementAtomic( &(pEP->scheduledTDs) );
}
currFrame++;
pEP->inSlot = nextSlot;
} while(pEP->toDoList != NULL);
finFrame = GetFrameNumber();
IOSimpleLockUnlock(_isochScheduleLock);
if ((finFrame - startFrame) > 1)
USBError(1, "AppleUSBUHCI[%p]::AddIsochFramesToSchedule - end - startFrame(0x%Ld) finFrame(0x%Ld)", this, startFrame, finFrame);
USBLog(7, "AppleUSBUHCI[%p]::AddIsochFramesToSchedule - finished, currFrame: %Ld", this, GetFrameNumber() );
}
IOReturn
AppleUSBUHCI::AbortIsochEP(IOUSBControllerIsochEndpoint* 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, "+AppleUSBUHCI[%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, (uint32_t)_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, "+AppleUSBUHCI[%p]::AbortIsochEP (%p)", this, pEP);
_inAbortIsochEP = true;
pEP->aborting = true;
timeStamp = mach_absolute_time();
while (_filterInterruptActive)
;
err = scavengeIsochTransactions();
if (err)
{
USBLog(1, "AppleUSBUHCI[%p]::AbortIsochEP - err (0x%x) from scavengeIsochTransactions", this, err);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMAbortIsochEP, (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, "+AppleUSBUHCI[%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, (uint32_t)_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 < kUHCI_NVFRAMES) && (pEP->inSlot < kUHCI_NVFRAMES))
{
bool stopAdvancing = false;
IOUSBControllerIsochListElement *activeTD = NULL;
slot = _outSlot;
while (slot != pEP->inSlot)
{
IOUSBControllerListElement *thing;
IOUSBControllerListElement *nextThing;
IOUSBControllerListElement *prevThing;
UInt32 nextSlot;
nextSlot = (slot+1) & kUHCI_NVFRAMES_MASK;
thing = _logicalFrameList[slot];
prevThing = NULL;
if (thing == NULL && (nextSlot != pEP->inSlot))
_outSlot = nextSlot;
while (thing != NULL)
{
nextThing = thing->_logicalNext;
pTD = OSDynamicCast(IOUSBControllerIsochListElement, thing);
if(pTD)
{
if (pTD->_pEndpoint == pEP)
{
UInt16 frSlot = (ReadFrameNumber() & kUHCI_NVFRAMES_MASK);
if (prevThing)
{
prevThing->_logicalNext = thing->_logicalNext;
prevThing->SetPhysicalLink(thing->GetPhysicalLink());
thing = prevThing; }
else
{
_logicalFrameList[slot] = nextThing;
_frameList[slot] = HostToUSBLong(thing->GetPhysicalLink());
thing = NULL; if (nextThing == NULL)
{
if (!stopAdvancing)
{
USBLog(5, "AppleUSBUHCI[%p]::AbortIsochEP(%p) - advancing _outslot from 0x%x to 0x%x", this, pEP, _outSlot, (uint32_t)nextSlot);
_outSlot = nextSlot;
}
else
{
USBLog(5, "AppleUSBUHCI[%p]::AbortIsochEP(%p) - would have advanced _outslot from 0x%x to 0x%x", this, pEP, _outSlot, (uint32_t)nextSlot);
}
}
}
if (frSlot == slot)
{
if (activeTD)
{
activeTD->UpdateFrameList(*(AbsoluteTime *)&timeStamp);
}
activeTD = pTD;
}
else
{
err = pTD->UpdateFrameList(*(AbsoluteTime *)&timeStamp);
}
OSDecrementAtomic( &(pEP->scheduledTDs));
PutTDonDoneQueue(pEP, pTD, true );
}
else if (pTD->_pEndpoint == NULL)
{
USBLog(1, "AppleUSBUHCI[%p]::AbortIsochEP (%p) - NULL endpoint in pTD %p", this, pEP, pTD);
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMAbortIsochEP, (uintptr_t)this, (uintptr_t)pEP, (uintptr_t)pTD, 2);
}
else
{
stopAdvancing = true;
USBLog(7, "AppleUSBUHCI[%p]::AbortIsochEP (%p) - a different EP in play (%p) - stop advancing", this, pEP, pTD->_pEndpoint);
}
}
else
{
break;
}
prevThing = thing;
thing = nextThing;
}
slot = nextSlot;
}
if (activeTD)
{
IODelay(1000);
activeTD->UpdateFrameList(*(AbsoluteTime *)&timeStamp);
}
}
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 = kUHCI_NVFRAMES + 1;
}
_inAbortIsochEP = false;
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, "+AppleUSBUHCI[%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, (uint32_t)_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( kUSBTUHCIUIM, kTPUHCIUIMAbortIsochEP, (uintptr_t)this, (uintptr_t)pEP, (uint32_t)_outSlot, 3 );
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMAbortIsochEP, (uint32_t)pEP->inSlot, (uint32_t)pEP->activeTDs, (uint32_t)pEP->onToDoList, 4 );
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMAbortIsochEP, (uintptr_t)pEP->toDoList, (uint32_t)pEP->deferredTDs, (uintptr_t)pEP->deferredQueue, 5 );
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMAbortIsochEP, (uint32_t)pEP->scheduledTDs, (uint32_t)pEP->onProducerQ, (uint32_t)_consumerCount, 6 );
USBTrace( kUSBTUHCIUIM, kTPUHCIUIMAbortIsochEP, (uint32_t)_producerCount, (uint32_t)pEP->onReversedList, (uint32_t)pEP->onDoneQueue, (uintptr_t)pEP->doneQueue );
}
else
{
USBLog(6, "-AppleUSBUHCI[%p]::AbortIsochEP[%p] - done - all clean - _outSlot (0x%x), pEP->inSlot (0x%x)", this, pEP, _outSlot, pEP->inSlot);
}
pEP->aborting = false;
USBLog(7, "-AppleUSBUHCI[%p]::AbortIsochEP (%p)", this, pEP);
return kIOReturnSuccess;
}
#pragma mark Disabled Endpoints
IOReturn
AppleUSBUHCI::UIMEnableAddressEndpoints(USBDeviceAddress address, bool enable)
{
UInt32 slot;
IOReturn err;
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAddressEndpoints(%d, %s)", this, (int)address, enable ? "true" : "false");
if (enable)
{
AppleUHCIQueueHead *pQH = _disabledQHList;
AppleUHCIQueueHead *pPrevQH = NULL;
AppleUHCIQueueHead *pPrevQHLive = NULL;
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAddressEndpoints- looking for QHs for address (%d) in the disabled queue", this, address);
while (pQH)
{
if (pQH->functionNumber == address)
{
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAddressEndpoints- found QH[%p] which matches", this, pQH);
if (pPrevQH)
pPrevQH->_logicalNext = pQH->_logicalNext;
else
_disabledQHList = OSDynamicCast(AppleUHCIQueueHead, pQH->_logicalNext);
pQH->_logicalNext = NULL;
switch (pQH->type)
{
case kUSBControl:
if (pQH->speed == kUSBDeviceSpeedLow)
{
pPrevQHLive = _lsControlQHEnd;
} else
{
pPrevQHLive = _fsControlQHEnd;
}
pQH->_logicalNext = pPrevQHLive->_logicalNext;
pQH->SetPhysicalLink(pPrevQHLive->GetPhysicalLink());
IOSync();
pPrevQHLive->_logicalNext = pQH;
pPrevQHLive->SetPhysicalLink(pQH->GetPhysicalAddrWithType());
IOSync();
if (pQH->speed == kUSBDeviceSpeedLow)
{
_lsControlQHEnd = pQH;
} else
{
_fsControlQHEnd = pQH;
}
break;
case kUSBBulk:
pPrevQHLive = _bulkQHEnd;
pQH->_logicalNext = pPrevQHLive->_logicalNext;
pQH->SetPhysicalLink(pPrevQHLive->GetPhysicalLink());
IOSync();
pPrevQHLive->_logicalNext = pQH;
pPrevQHLive->SetPhysicalLink(pQH->GetPhysicalAddrWithType());
IOSync();
_bulkQHEnd = pQH;
break;
case kUSBInterrupt:
pPrevQHLive = _intrQH[pQH->interruptSlot];
pQH->_logicalNext = pPrevQHLive->_logicalNext;
pQH->SetPhysicalLink(pPrevQHLive->GetPhysicalLink());
IOSync();
pPrevQHLive->_logicalNext = pQH;
pPrevQHLive->SetPhysicalLink(pQH->GetPhysicalAddrWithType());
break;
default:
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAddressEndpoints- found QH[%p] with unknown type(%d)", this, pQH, pQH->type);
break;
}
if (pPrevQH)
pQH = OSDynamicCast(AppleUHCIQueueHead, pPrevQH->_logicalNext);
else
pQH = _disabledQHList;
}
else
{
pPrevQH = pQH;
pQH = OSDynamicCast(AppleUHCIQueueHead, pQH->_logicalNext);
}
}
return kIOReturnSuccess;
}
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAddressEndpoints- looking for endpoints for device address(%d) to disable", this, address);
for (slot=0; slot < kUHCI_NVFRAMES; slot++)
{
IOUSBControllerListElement *pLE;
IOUSBControllerListElement *pPrevLE = NULL;
pLE = _logicalFrameList[slot];
while (pLE)
{
AppleUHCIIsochTransferDescriptor *pITD = OSDynamicCast(AppleUHCIIsochTransferDescriptor, pLE);
AppleUHCIQueueHead *pQH = OSDynamicCast(AppleUHCIQueueHead, pLE);
if (pQH && (pQH->type != kQHTypeDummy) && (pQH->functionNumber == address))
{
AppleUHCIQueueHead *pPrevQH = OSDynamicCast(AppleUHCIQueueHead, pPrevLE);
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAddressEndpoints- found pQH[%p] which matches (pPrevQH[%p])", this, pQH, pPrevQH);
if (!pPrevQH)
{
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAddressEndpoints- unexpected NULL pPrevQH", this);
}
else
{
err = UnlinkQueueHead(pQH, pPrevQH);
if (err)
{
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAddressEndpoints- err[%p] unlinking queue head", this, (void*)err);
}
else
{
pLE = pPrevLE;
pQH->_logicalNext = _disabledQHList;
_disabledQHList = pQH;
}
}
}
if (pITD && (UHCI_TD_GET_ADDR(USBToHostLong(pITD->GetSharedLogical()->token))))
{
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAddressEndpoints- found pITD[%p] which matches", this, pITD);
}
pPrevLE = pLE;
pLE = pLE->_logicalNext;
}
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBUHCI::UIMEnableAllEndpoints(bool enable)
{
UInt32 slot;
IOReturn err;
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAllEndpoints(%s)", this, enable ? "true" : "false");
if (enable)
{
AppleUHCIQueueHead *pQH = _disabledQHList;
AppleUHCIQueueHead *pPrevQH = NULL;
AppleUHCIQueueHead *pPrevQHLive = NULL;
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAllEndpoints- looking for QHs in the disabled queue", this);
while (pQH)
{
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAllEndpoints- found QH[%p] which matches", this, pQH);
_disabledQHList = OSDynamicCast(AppleUHCIQueueHead, pQH->_logicalNext);
pQH->_logicalNext = NULL;
switch (pQH->type)
{
case kUSBControl:
if (pQH->speed == kUSBDeviceSpeedLow)
{
pPrevQHLive = _lsControlQHEnd;
} else
{
pPrevQHLive = _fsControlQHEnd;
}
pQH->_logicalNext = pPrevQHLive->_logicalNext;
pQH->SetPhysicalLink(pPrevQHLive->GetPhysicalLink());
IOSync();
pPrevQHLive->_logicalNext = pQH;
pPrevQHLive->SetPhysicalLink(pQH->GetPhysicalAddrWithType());
IOSync();
if (pQH->speed == kUSBDeviceSpeedLow)
{
_lsControlQHEnd = pQH;
} else
{
_fsControlQHEnd = pQH;
}
break;
case kUSBBulk:
pPrevQHLive = _bulkQHEnd;
pQH->_logicalNext = pPrevQHLive->_logicalNext;
pQH->SetPhysicalLink(pPrevQHLive->GetPhysicalLink());
IOSync();
pPrevQHLive->_logicalNext = pQH;
pPrevQHLive->SetPhysicalLink(pQH->GetPhysicalAddrWithType());
IOSync();
_bulkQHEnd = pQH;
break;
case kUSBInterrupt:
pPrevQHLive = _intrQH[pQH->interruptSlot];
pQH->_logicalNext = pPrevQHLive->_logicalNext;
pQH->SetPhysicalLink(pPrevQHLive->GetPhysicalLink());
IOSync();
pPrevQHLive->_logicalNext = pQH;
pPrevQHLive->SetPhysicalLink(pQH->GetPhysicalAddrWithType());
break;
default:
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAllEndpoints- found QH[%p] with unknown type(%d)", this, pQH, pQH->type);
break;
}
pQH = _disabledQHList;
}
return kIOReturnSuccess;
}
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAllEndpoints- looking for endpoints for to disable", this);
for (slot=0; slot < kUHCI_NVFRAMES; slot++)
{
IOUSBControllerListElement *pLE;
IOUSBControllerListElement *pPrevLE = NULL;
pLE = _logicalFrameList[slot];
while (pLE)
{
AppleUHCIIsochTransferDescriptor *pITD = OSDynamicCast(AppleUHCIIsochTransferDescriptor, pLE);
AppleUHCIQueueHead *pQH = OSDynamicCast(AppleUHCIQueueHead, pLE);
if (pQH && (pQH->type != kQHTypeDummy))
{
AppleUHCIQueueHead *pPrevQH = OSDynamicCast(AppleUHCIQueueHead, pPrevLE);
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAllEndpoints- found pQH[%p] which matches (pPrevQH[%p])", this, pQH, pPrevQH);
if (!pPrevQH)
{
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAllEndpoints- unexpected NULL pPrevQH", this);
}
else
{
err = UnlinkQueueHead(pQH, pPrevQH);
if (err)
{
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAllEndpoints- err[%p] unlinking queue head", this, (void*)err);
}
else
{
pLE = pPrevLE;
pQH->_logicalNext = _disabledQHList;
_disabledQHList = pQH;
}
}
}
if (pITD && (UHCI_TD_GET_ADDR(USBToHostLong(pITD->GetSharedLogical()->token))))
{
USBLog(2, "AppleUSBUHCI[%p]::UIMEnableAllEndpoints- found pITD[%p] which matches", this, pITD);
}
pPrevLE = pLE;
pLE = pLE->_logicalNext;
}
}
return kIOReturnSuccess;
}