AppleUSBEHCI_UIM.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include "AppleUSBEHCI.h"
#include <IOKit/IOMemoryDescriptor.h>
#include <IOKit/IOMemoryCursor.h>
#include <IOKit/usb/IOUSBLog.h>
#define super IOUSBControllerV2
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;
AppleEHCIQueueHead *pED;
USBLog(7, "%s[%p]::UIMCreateControlEndpoint(%d, %d, %d, %d @(%d, %d))\n", getName(), this,
functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort);
if (_rootHubFuncAddress == functionAddress)
{
return(kIOReturnSuccess);
}
if( (speed == kUSBDeviceSpeedLow) && (maxPacketSize > 8) )
{
if(functionAddress != 0)
{
USBError(1, "%s[%p]::UIMCreateControlEndpoint - incorrect max packet size (%d) for low speed", getName(), this, maxPacketSize);
return(kIOReturnBadArgument);
}
USBLog(3, "%s[%p]::UIMCreateControlEndpoint - changing low speed max packet from %d to 8 for dev 0", getName(), this, maxPacketSize);
maxPacketSize = 8;
}
pED = _AsyncHead;
pEHCIEndpointDescriptor = AddEmptyCBEndPoint(functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort, kEHCIEDDirectionTD, pED);
if(pED == NULL)
{
_AsyncHead = pEHCIEndpointDescriptor;
_pEHCIRegisters->AsyncListAddr = HostToUSBLong( pEHCIEndpointDescriptor->_sharedPhysical );
}
if (pEHCIEndpointDescriptor == NULL)
return(-1);
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;
UInt32 mySpeed = 0;
AppleEHCIQueueHead * pED;
EHCIGeneralTransferDescriptorPtr pTD;
USBLog(7, "%s[%p]::MakeEmptyEndPoint - Addr: %d, EPT#: %d, MPS: %d, speed: %d, hubAddr: %d, hubPort: %d, dir: %d", getName(), this,
functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort, direction);
if( (highSpeedHub == 0) && (speed != kUSBDeviceSpeedHigh) )
{
USBLog(1, "%s[%p]::MakeEmptyEndPoint - new endpoint NOT fixing up speed", getName(), this);
}
pED = FindControlBulkEndpoint(functionAddress, endpointNumber, NULL, direction);
if(pED != NULL)
{
USBLog(1, "%s[%p]::MakeEmptyEndPoint - old endpoint found, abusing %p", getName(), this, pED);
pED->GetSharedLogical()->flags = 0xffffffff;
}
pED = AllocateQH();
USBLog(7, "%s[%p]::MakeEmptyEndPoint - new endpoint %p", getName(), 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, "%s[%p]::MakeEmptyEndPoint - mySpeed %d", getName(), this, mySpeed);
myMaxPacketSize = ((UInt32) maxPacketSize) << kEHCIEDFlags_MPSPhase;
pED->direction = direction;
USBLog(7, "%s[%p]::MakeEmptyEndPoint - MPS = %d, setting flags to %p", getName(), this, maxPacketSize, myFunctionAddress | myEndPointNumber | myMaxPacketSize | mySpeed);
pED->GetSharedLogical()->flags = HostToUSBLong(myFunctionAddress | myEndPointNumber | myMaxPacketSize | mySpeed);
pED->GetSharedLogical()->splitFlags = HostToUSBLong( (1<< 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;
#warning Async problems adding first qTD
pTD = AllocateTD(); pTD->pShared->flags = 0; pTD->pShared->nextTD = HostToUSBLong(kEHCITermFlag);
pTD->pShared->altTD = HostToUSBLong(kEHCITermFlag);
pTD->command = NULL;
USBLog(7, "%s[%p]::MakeEmptyEndPoint - pointing NextqTDPtr to %lx", getName(), this, 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);
mySMask = (0x08 << kEHCIEDSplitFlags_SMaskPhase); if(speed != kUSBDeviceSpeedHigh)
{
mySMask |= (0xE0 << kEHCIEDSplitFlags_CMaskPhase); }
intED->GetSharedLogical()->splitFlags |= HostToUSBLong(mySMask);
return intED;
}
void
AppleUSBEHCI::linkAsyncEndpoint(AppleEHCIQueueHead *CBED, AppleEHCIQueueHead *pEDHead)
{
IOPhysicalAddress newHorizPtr;
if(pEDHead == NULL) {
CBED->GetSharedLogical()->flags |= HostToUSBLong(1 << kEHCIEDFlags_HPhase);
}
newHorizPtr = HostToUSBLong(CBED->GetPhysicalAddrWithType());
USBLog(7, "%s[%p]::linkAsynEndpoint pEDHead %p", getName(), this, pEDHead);
if(pEDHead == NULL)
{
CBED->GetSharedLogical()->nextQH = newHorizPtr;
CBED->_logicalNext = NULL;
}
else
{
CBED->GetSharedLogical()->nextQH = pEDHead->GetSharedLogical()->nextQH;
CBED->_logicalNext = pEDHead->_logicalNext;
pEDHead->_logicalNext = CBED;
pEDHead->GetSharedLogical()->nextQH = newHorizPtr;
}
}
AppleEHCIQueueHead *
AppleUSBEHCI::AddEmptyCBEndPoint(
UInt8 functionAddress,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed,
USBDeviceAddress highSpeedHub,
int highSpeedPort,
UInt8 direction,
AppleEHCIQueueHead * pED)
{
AppleEHCIQueueHead * CBED;
UInt32 cFlag;
UInt32 myDataToggleCntrl;
USBLog(7, "%s[%p]::AddEmptyCBEndPoint speed %d @(%d, %d)", getName(), 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, pED);
return CBED;
}
IOReturn
AppleUSBEHCI::UIMCreateControlTransfer(
short functionAddress,
short endpointNumber,
IOUSBCompletion completion,
void* CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
USBLog(1, "%s(%p)UIMCreateControlTransfer- calling the wrong method!", getName(), this);
return kIOReturnIPCError;
}
void
AppleUSBEHCI::printAsyncQueue()
{
AppleEHCIQueueHead *pED = _AsyncHead;
if (pED)
{
USBLog(7, "%s[%p]::printAsyncQueue", getName(), this);
while (pED)
{
pED = OSDynamicCast(AppleEHCIQueueHead, pED->_logicalNext);
}
}
else
{
USBLog(7, "%s[%p]::printAsyncQueue: NULL Async Queue", getName(), this);
}
}
void AppleUSBEHCI::printTD(EHCIGeneralTransferDescriptorPtr pTD)
{
#if 1
IOLog("print TD turned off\n");
#else
if(pTD == 0)
{
IOLog("Attempt to print null TD\n");
return;
}
USBLog(5, "%s[%p]::printED: ------pTD at %lx", getName(), this, (UInt32)pTD);
USBLog(5, "%s[%p]::printED: nextTD: %lx", getName(), this, USBToHostLong(pTD->pShared->nextTD));
USBLog(5, "%s[%p]::printED: altTD: %lx", getName(), this, USBToHostLong(pTD->pShared->altTD));
USBLog(5, "%s[%p]::printED: flags: %lx", getName(), this, USBToHostLong(pTD->pShared->flags));
USBLog(5, "%s[%p]::printED: BuffPtr0: %lx", getName(), this, USBToHostLong(pTD->pShared->BuffPtr[0]));
USBLog(5, "%s[%p]::printED: pEndpt: %lx", getName(), this, (UInt32)(pTD->pQH));
USBLog(5, "%s[%p]::printED: pPhys: %lx", getName(), this, (UInt32)(pTD->pPhysical));
USBLog(5, "%s[%p]::printED: pLogNxt: %lx", getName(), this, (UInt32)(pTD->pLogicalNext));
USBLog(5, "%s[%p]::printED: logBf: %lx", getName(), this, (UInt32)(pTD->logicalBuffer));
#endif
}
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, "%s[%p]::UIMCreateControlTransfer adr=%d:%d cbp=%lx:%lx br=%s cback=[%p:%p] dir=%d)",
getName(), this, functionAddress, endpointNumber, (UInt32)CBP, bufferSize,
bufferRounding ? "YES":"NO", completion.target, completion.parameter, direction);
pEDQueue = FindControlBulkEndpoint(functionAddress, endpointNumber, &pEDDummy, kEHCIEDDirectionTD);
USBLog(7, "%s[%p]::UIMCreateControlTransfer -- found endpoint at %p", getName(), this, pEDQueue);
if (pEDQueue == NULL)
{
USBLog(3, "%s[%p]::UIMCreateControlTransfer- Could not find endpoint!", getName(), this);
return kIOUSBEndpointNotFound;
}
status = allocateTDs(pEDQueue, command, CBP, bufferSize, direction, true);
if(status == kIOReturnSuccess)
{
USBLog(7, "%s[%p]::UIMCreateControlTransfer allocateTDS done - CMD = %p, STS = %p", getName(), this, USBToHostLong(_pEHCIRegisters->USBCMD), USBToHostLong(_pEHCIRegisters->USBSTS));
printAsyncQueue();
EnableAsyncSchedule();
}
else
{
USBError(1, "%s[%p]::UIMCreateControlTransfer - allocateTDs returned error %x", getName(), this, (UInt32)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, "%s[%p]::FindControlBulkEndpoint - pEDQueue is NULL", getName(), this);
return NULL;
}
do {
EDDirection = pEDQueue->direction;
if( ( (USBToHostLong(pEDQueue->GetSharedLogical()->flags) & kUniqueNumNoDirMask) == 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 bytesToSchedule;
bool needNewTD = false;
UInt32 maxTDLength;
if(controlTransaction)
{
myToggle = 0; if(direction != kEHCIEDDirectionTD)
{ myToggle |= kEHCITDFlags_DT; }
}
myDirection = (UInt32) direction << kEHCITDFlags_PIDPhase;
maxPacket = (USBToHostLong(pEDQueue->GetSharedLogical()->flags) & kEHCIEDFlags_MPS) >> kEHCIEDFlags_MPSPhase;
pTD1 = AllocateTD();
if (pTD1 == NULL)
{
USBError(1, "%s[%p]::allocateTDs can't allocate 1st new TD", getName(), this);
return kIOReturnNoMemory;
}
pTD = pTD1;
if (bufferSize != 0)
{
transferOffset = 0;
curTDsegment = 0;
bytesThisTD = 0;
while (transferOffset < bufferSize)
{
dmaStartAddr = CBP->getPhysicalSegment(transferOffset, &totalPhysLength);
USBLog(7, "%s[%p]::allocateTDs - getPhysicalSegment returned length of %d (out of %d) and start of %p", getName(), this, totalPhysLength, bufferSize, dmaStartAddr);
dmaStartOffset = (dmaStartAddr & (kEHCIPageSize-1));
bytesToSchedule = 0;
if ((curTDsegment == 0) || (dmaStartOffset == 0))
{
needNewTD = false;
if (totalPhysLength > bufferSize)
{
USBLog(1, "%s[%p]::allocateTDs - segment physical length > buffer size - very strange", getName(), this);
totalPhysLength = bufferSize;
}
maxTDLength = ((kEHCIPagesPerTD-curTDsegment) * kEHCIPageSize) - dmaStartOffset;
if (totalPhysLength > maxTDLength)
{
if ((curTDsegment == 0) && (dmaStartOffset != 0))
{
USBLog(7, "%s[%p]::allocateTDs - segment won't fit - using 4 pages for this TD", getName(), this);
bytesToSchedule = (kEHCIPagesPerTD-1) * kEHCIPageSize;
}
else
{
USBLog(7, "%s[%p]::allocateTDs - segment is larger than 1 TD - using %d pages for this TD", getName(), this, kEHCIPagesPerTD - curTDsegment);
bytesToSchedule = (kEHCIPagesPerTD - curTDsegment) * kEHCIPageSize;
}
}
else
bytesToSchedule = totalPhysLength;
bytesThisTD += bytesToSchedule;
transferOffset += bytesToSchedule;
if ( (transferOffset < bufferSize) && ((dmaStartOffset+bytesToSchedule) & kEHCIPageOffsetMask) )
{
USBLog(6, "%s[%p]::allocateTDs - non-last transfer didn't end at end of page (%d, %d)", getName(), this, dmaStartOffset+bytesToSchedule);
needNewTD = true;
}
while (bytesToSchedule)
{
pTD->pShared->BuffPtr[curTDsegment++] = HostToUSBLong(dmaStartAddr);
dmaStartAddr += (kEHCIPageSize - dmaStartOffset);
if (bytesToSchedule > (kEHCIPageSize - dmaStartOffset))
bytesToSchedule -= (kEHCIPageSize - dmaStartOffset);
else
bytesToSchedule = 0;
dmaStartOffset = 0;
}
if ( ((curTDsegment < kEHCIPagesPerTD) && (transferOffset < bufferSize)) && !needNewTD )
{
USBLog(7, "%s[%p]::allocateTDs - didn't fill up this TD (segment %d) - going back for more", getName(), this, curTDsegment);
continue;
}
}
flags = kEHCITDioc;
USBLog(7, "%s[%p]::allocateTDs - i have %d bytes in %d segments", getName(), this, bytesThisTD, curTDsegment);
for (segment = 0; segment < curTDsegment; segment++)
{
USBLog(7, "%s[%p]::allocateTDs - addr[%d]:%p", getName(), this, segment, USBToHostLong(pTD->pShared->BuffPtr[segment]));
}
flags |= (bytesThisTD << kEHCITDFlags_BytesPhase);
pTD->pShared->altTD = HostToUSBLong(pTD1->pPhysical); pTD->pType = (UInt32) kEHCIBulkTransferOutType;
flags |= myDirection | myToggle | kEHCITDStatus_Active | (3<<kEHCITDFlags_CerrPhase);
pTD->traceFlag = false;
pTD->pQH = pEDQueue;
USBLog(6, "%s[%p]::allocateTDs - putting command into TD (%p) on ED (%p)", getName(), this, pTD, pEDQueue);
pTD->command = command; if (transferOffset >= bufferSize)
{
myToggle = 0; pTD->lastTDofTransaction = true;
pTD->logicalBuffer = CBP;
pTD->pShared->flags = HostToUSBLong(flags);
}
else
{
pTD->lastTDofTransaction = false;
myToggle = 0; pTDnew = AllocateTD();
if (pTDnew == NULL)
{
status = kIOReturnNoMemory;
USBError(1, "%s[%p]::allocateTDs can't allocate new TD", getName(), this);
}
else
{
pTD->pShared->nextTD = HostToUSBLong(pTDnew->pPhysical);
pTD->pLogicalNext = pTDnew;
pTD->pShared->flags = HostToUSBLong(flags); pTD = pTDnew;
curTDsegment = 0;
bytesThisTD = 0;
USBLog(7, "%s[%p]::allocateTDs - got another TD - going to fill it up too (%d, %d)", getName(), this, transferOffset, bufferSize);
}
}
}
}
else
{
pTD->pShared->altTD = HostToUSBLong(pTD1->pPhysical); USBLog(6, "%s[%p]::allocateTDs - (no buffer)- putting command into TD (%p) on ED (%p)", getName(), this, pTD, pEDQueue);
pTD->command = command;
pTD->lastTDofTransaction = true;
pTD->logicalBuffer = CBP;
pTD->traceFlag = false;
pTD->pQH = pEDQueue;
flags = kEHCITDioc | 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->pQH = pTD1->pQH;
USBLog(7, "%s[%p]::allocateTDs - transfering command from TD (%p) to TD (%p)", getName(), this, pTD1, pTDLast);
pTDLast->command = pTD1->command;
pTDLast->lastTDofTransaction = pTD1->lastTDofTransaction;
pTDLast->traceFlag = pTD1->traceFlag;
pTDLast->pType = pTD1->pType;
pTDLast->pLogicalNext = pTD1->pLogicalNext;
pTDLast->logicalBuffer = pTD1->logicalBuffer;
pTD->pShared->nextTD = HostToUSBLong(pTD1->pPhysical);
pTD->pLogicalNext = pTD1;
pTD1->pShared->nextTD = HostToUSBLong(kEHCITermFlag);
pTD1->pShared->altTD = HostToUSBLong(kEHCITermFlag);
pTD1->pLogicalNext = 0;
USBLog(7, "%s[%p]::allocateTDs - zeroing out command in TD (%p)", getName(), this, pTD1);
pTD1->command = NULL;
pEDQueue->TailTD = pTD1;
pTDLast->pShared->flags = flags;
if (status)
{
USBLog(3, "%s[%p] CreateGeneralTransfer: returning status 0x%x", getName(), 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);
}
return kOHCIITDConditionDeviceNotResponding; }
if( (flags & kEHCITDStatus_PingState) != 0) {
return kOHCIITDConditionDeviceNotResponding;
}
USBLog(1, "mungeECHIStatus condition we're not expecting %x", flags);
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;
USBLog(7, "+%s[%p]::EHCIUIMDoDoneQueueProcessing", getName(), this);
while (pHCDoneTD != NULL)
{
IOReturn errStatus;
if(pHCDoneTD == stopAt)
{
USBLog(5, "%s[%p]::EHCIUIMDoDoneQueueProcessing stop at %p",getName(), 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, "%s[%p]::EHCIUIMDoDoneQueueProcessing - TD (%p) - got transferStatus %p with flags (%p)", getName(), this, pHCDoneTD, transferStatus, flags);
}
errStatus = TranslateStatusToUSBError(transferStatus);
accumErr = errStatus;
if (errStatus)
{
USBLog(4, "%s[%p]::EHCIUIMDoDoneQueueProcessing - got errror %p", getName(), this, errStatus);
}
}
if (pHCDoneTD->pType == kEHCIIsochronousType)
{
USBError (1, "%s[%p]::EHCIUIMDoDoneQueueProcessing we're not expecting this (pHCDoneTD->pType == kEHCIIsochronousType)", getName(), this);
}
else
{
bufferSizeRemaining += (flags & kEHCITDFlags_Bytes) >> kEHCITDFlags_BytesPhase;
if (pHCDoneTD->lastTDofTransaction)
{
if ( pHCDoneTD->command == NULL )
{
USBError (1, "%s[%p]::EHCIUIMDoDoneQueueProcessing pHCDoneTD->command is NULL (%p)", getName(), this, pHCDoneTD);
}
else
{
IOUSBCompletion completion = pHCDoneTD->command->GetUSLCompletion();
if(!safeAction || (safeAction == completion.action))
{
pHCDoneTD->lastTDofTransaction = 0;
Complete(completion, errStatus, bufferSizeRemaining);
bufferSizeRemaining = 0; accumErr = kIOReturnSuccess;
}
else
{ if(_pendingHead)
_pendingTail->pLogicalNext = pHCDoneTD;
else
_pendingHead = pHCDoneTD;
_pendingTail = pHCDoneTD;
}
}
}
pHCDoneTD->logicalBuffer = NULL;
USBLog(7, "%s[%p]::EHCIUIMDoDoneQueueProcessing - deallocating TD (%p)", getName(), this, pHCDoneTD);
DeallocateTD(pHCDoneTD);
}
pHCDoneTD = nextTD; }
USBLog(7, "-%s[%p]::EHCIUIMDoDoneQueueProcessing", getName(), this);
return(kIOReturnSuccess);
}
IOReturn
AppleUSBEHCI::scavengeIsocTransactions(IOUSBCompletionAction safeAction)
{
AppleEHCIIsochListElement *pDoneEl;
UInt32 cachedProducer;
UInt32 cachedConsumer;
AppleEHCIIsochEndpointPtr pEP;
AppleEHCIIsochListElement *prevEl;
AppleEHCIIsochListElement *nextEl;
IOInterruptState intState;
intState = IOSimpleLockLockDisableInterrupt( _wdhLock );
pDoneEl = (AppleEHCIIsochListElement*)_savedDoneQueueHead;
cachedProducer = _producerCount;
IOSimpleLockUnlockEnableInterrupt( _wdhLock, intState );
cachedConsumer = _consumerCount;
if (pDoneEl && (cachedConsumer != cachedProducer))
{
prevEl = NULL;
USBLog(7, "%s[%p]::scavengeIsocTransactions - before reversal, cachedConsumer = 0x%x", getName(), this, cachedConsumer);
while (true)
{
pDoneEl->_logicalNext = prevEl;
prevEl = pDoneEl;
cachedConsumer++;
if ( cachedProducer == cachedConsumer)
break;
pDoneEl = pDoneEl->doneQueueLink;
}
_consumerCount = cachedConsumer;
USBLog(7, "%s[%p]::scavengeIsocTransactions - after reversal, cachedConsumer = 0x%x", getName(), this, cachedConsumer);
while (pDoneEl)
{
nextEl = OSDynamicCast(AppleEHCIIsochListElement, pDoneEl->_logicalNext);
pDoneEl->_logicalNext = NULL;
USBLog(7, "%s[%p]::scavengeIsocTransactions - about to scavenge TD %p", getName(), this, pDoneEl);
scavengeAnIsocTD(pDoneEl, safeAction);
pDoneEl = nextEl;
}
}
pEP = _isochEPList;
while (pEP)
{
AddIsocFramesToSchedule(pEP);
pEP = pEP->nextEP;
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::scavengeAnIsocTD(AppleEHCIIsochListElement *pTD, IOUSBCompletionAction safeAction)
{
AppleEHCIIsochEndpointPtr pEP;
IOReturn ret;
pEP = pTD->myEndpoint;
if(pEP == NULL)
{
USBError(1, "%s[%p]::scavengeAnIsocEndPoint - could not find endpoint associated with iTD (%p)", getName(), this, pTD->myEndpoint);
}
else
{
if (!pTD->lowLatency)
ret = pTD->UpdateFrameList(); PutTDonDoneQueue(pEP, pTD);
}
if(pTD->completion.action != NULL)
{
ReturnIsocDoneQueue(pEP);
}
return(kIOReturnSuccess);
}
void
AppleUSBEHCI::PutTDonToDoList(AppleEHCIIsochEndpointPtr pED, AppleEHCIIsochListElement *pTD)
{
USBLog(7, "%s[%p]::PutTDonToDoList - pED (%p) pTD (%p) frameNumber(%Lx)", getName(), this, pED, pTD, pTD->frameNumber);
if(pED->toDoList == NULL)
{
pED->toDoList = pTD;
}
else
{
pED->toDoEnd->_logicalNext = pTD;
}
pED->toDoEnd = pTD;
pED->activeTDs++;
}
AppleEHCIIsochListElement *
AppleUSBEHCI::GetTDfromToDoList(AppleEHCIIsochEndpointPtr pED)
{
AppleEHCIIsochListElement *pTD;
pTD = pED->toDoList;
if (pTD)
{
if (pTD == pED->toDoEnd)
pED->toDoList = pED->toDoEnd = NULL;
else
pED->toDoList = OSDynamicCast(AppleEHCIIsochListElement, pTD->_logicalNext);
}
return pTD;
}
void
AppleUSBEHCI::PutTDonDoneQueue(AppleEHCIIsochEndpointPtr pED, AppleEHCIIsochListElement *pTD)
{
if(pED->doneQueue == NULL)
{
pED->doneQueue = pTD;
}
else
{
pED->doneEnd->_logicalNext = pTD;
}
pED->doneEnd = pTD;
}
AppleEHCIIsochListElement *
AppleUSBEHCI::GetTDfromDoneQueue(AppleEHCIIsochEndpointPtr pED)
{
AppleEHCIIsochListElement *pTD;
pTD = pED->doneQueue;
if (pTD)
{
if (pTD == pED->doneEnd)
pED->doneQueue = pED->doneEnd = NULL;
else
pED->doneQueue = OSDynamicCast(AppleEHCIIsochListElement, pTD->_logicalNext);
pED->activeTDs--;
}
return pTD;
}
IOReturn
AppleUSBEHCI::scavengeAnEndpointQueue(AppleEHCIListElement *pEDQueue, IOUSBCompletionAction safeAction)
{
EHCIGeneralTransferDescriptorPtr doneQueue = NULL, doneTail= NULL, qHead, qTD, qEnd;
UInt32 flags, count = 0;
Boolean TDisHalted, shortTransfer;
AppleEHCIQueueHead *pQH;
while( (pEDQueue != NULL) && (count++ < 150000) )
{
pQH = OSDynamicCast(AppleEHCIQueueHead, pEDQueue);
if(pQH)
{
qTD = qHead = pQH->qTD;
qEnd = pQH->TailTD;
TDisHalted = false;
shortTransfer = false;
while( (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->lastTDofTransaction)
{
USBLog(7, "%s[%p]::scavengeAnEndpointQueue - TD (%p) on ED (%p)", getName(), 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(TDisHalted)
{
flags = USBToHostLong(qTD->pShared->flags);
pQH->GetSharedLogical()->NextqTDPtr = HostToUSBLong( qTD->pPhysical);
if((flags & kEHCITDStatus_Active) != 0) {
break;
}
}
TDisHalted = false;
shortTransfer = false;
}
else
{
USBLog(7, "%s[%p]::scavengeAnEndpointQueue - looking past TD (%p) on ED (%p)", getName(), this, qTD, pQH);
qTD = qTD->pLogicalNext;
}
}
}
pEDQueue = pEDQueue->_logicalNext;
}
if(doneQueue != NULL)
{
EHCIUIMDoDoneQueueProcessing(doneQueue, kIOReturnSuccess, safeAction, NULL);
}
if(count > 1000)
{
USBLog(1, "%s[%p]::scavengeAnEndpointQueue looks like bad ed queue %lx", getName(), this, count);
}
return kIOReturnSuccess;
}
void
AppleUSBEHCI::scavengeCompletedTransactions(IOUSBCompletionAction safeAction)
{
AppleEHCIListElement **pEDQueue;
IOReturn err, err1;
int i;
safeAction = 0;
err = scavengeIsocTransactions(safeAction);
if(err != kIOReturnSuccess)
{
USBLog(1, "%s[%p]::scavengeCompletedTransactions err isoch list %x", getName(), this, err);
}
if ( _AsyncHead != NULL )
{
err = scavengeAnEndpointQueue(_AsyncHead, safeAction);
if(err != kIOReturnSuccess)
{
USBLog(1, "%s[%p]::scavengeCompletedTransactions err async queue %x", getName(), this, err);
}
}
if ( _logicalPeriodicList != NULL )
{
pEDQueue = _logicalPeriodicList;
for(i= 0; i<kEHCIPeriodicListEntries; i++)
{
if(*pEDQueue != NULL)
{
err1 = scavengeAnEndpointQueue(*pEDQueue, safeAction);
if(err1 != kIOReturnSuccess)
{
err = err1;
USBLog(1, "%s[%p]::scavengeCompletedTransactions err periodic queue %lx", getName(), this, err);
}
}
pEDQueue++;
}
}
}
IOReturn
AppleUSBEHCI::UIMCreateControlTransfer(
short functionAddress,
short endpointNumber,
IOUSBCommand* command,
void* CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
IOMemoryDescriptor * desc = NULL;
IODirection descDirection;
IOReturn status;
IOUSBCompletion completion = command->GetUSLCompletion();
USBLog(7, "%s[%p]::UIMCreateControlTransfer - CrntlTx: adr=%d:%d cbp=%lx:%lx br=%s cback=[%lx:%lx] dir=%d)", getName(), this,
functionAddress, endpointNumber, (UInt32)CBP, bufferSize,
bufferRounding?"YES":"NO", (UInt32)completion.target, (UInt32)completion.parameter, direction);
if (direction == kUSBOut)
descDirection = kIODirectionOut;
else if (direction == kUSBIn)
descDirection = kIODirectionIn;
else
descDirection = kIODirectionOut;
if(bufferSize != 0)
{
desc = IOMemoryDescriptor::withAddress(CBP, bufferSize, descDirection);
if(!desc)
{
USBError(1, "%s[%p]::UIMCreateControlTransfer - IOMemoryDescriptor::withAddress failed", getName(), this);
return kIOReturnNoMemory;
}
}
USBLog(7, "%s[%p]::UIMCreateControlTransfer - calling UIMCreateControlTransfer0 with mem desc", getName(), this);
status = UIMCreateControlTransfer(functionAddress, endpointNumber, command, desc, bufferRounding, bufferSize, direction);
if(desc)
desc->release();
return status;
}
IOReturn
AppleUSBEHCI::UIMCreateControlTransfer(
short functionAddress,
short endpointNumber,
IOUSBCompletion completion,
IOMemoryDescriptor* CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
USBLog(1, "%s[%p] UIMCreateControlTransfer- calling the wrong method!", getName(), this);
return kIOReturnIPCError;
}
IOReturn
AppleUSBEHCI::UIMCreateBulkEndpoint(
UInt8 functionAddress,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt8 maxPacketSize)
{
USBLog(1, "%s[%p] UIMCreateBulkEndpoint- calling the wrong method!", getName(), this);
return kIOReturnInternalError;
}
IOReturn
AppleUSBEHCI::UIMCreateBulkEndpoint(
UInt8 functionAddress,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt16 maxPacketSize,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
AppleEHCIQueueHead *pEHCIEndpointDescriptor;
AppleEHCIQueueHead *pED;
USBLog(7, "%s[%p]::UIMCreateBulkEndpoint(adr=%d:%d, max=%d, dir=%d)", getName(), this, functionAddress, endpointNumber, maxPacketSize, direction);
if( (direction != kUSBOut) && (direction != kUSBIn) )
{
USBLog(1, "%s[%p]::UIMCreateBulkEndpoint - wrong direction %d", getName(), this, direction);
return kIOReturnBadArgument;
}
if(highSpeedHub == 0)
speed = kUSBDeviceSpeedHigh;
else
speed = kUSBDeviceSpeedFull;
pED = _AsyncHead;
if ((speed == kUSBDeviceSpeedHigh) && (maxPacketSize != 512))
{
USBLog(1, "%s[%p]::UIMCreateBulkEndpoint - ERROR converting HS maxPacketSize from %d to 512", getName(), this, maxPacketSize);
maxPacketSize = 512;
}
pEHCIEndpointDescriptor = AddEmptyCBEndPoint(functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort, direction, pED);
if (pEHCIEndpointDescriptor == NULL)
return kIOReturnNoResources;
if(pED == NULL)
{
_AsyncHead = pEHCIEndpointDescriptor;
_pEHCIRegisters->AsyncListAddr = USBToHostLong( pEHCIEndpointDescriptor->_sharedPhysical );
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::UIMCreateBulkTransfer(IOUSBCommand* command)
{
AppleEHCIQueueHead *pEDQueue;
AppleEHCIQueueHead *pEDDummy;
IOReturn status;
IOMemoryDescriptor* buffer = command->GetBuffer();
short direction = command->GetDirection();
USBLog(7, "%s[%p]::UIMCreateBulkTransfer - adr=%d:%d cbp=%lx:%x cback=[%lx:%lx:%lx] dir=%d)", getName(), this,
command->GetAddress(), command->GetEndpoint(), (UInt32)buffer, (int)buffer->getLength(),
(UInt32)command->GetUSLCompletion().action, (UInt32)command->GetUSLCompletion().target, (UInt32)command->GetUSLCompletion().parameter, direction);
pEDQueue = FindControlBulkEndpoint(command->GetAddress(), command->GetEndpoint(), &pEDDummy, direction);
if (pEDQueue == NULL)
{
USBLog(3, "%s[%p]::UIMCreateControlTransfer- Could not find endpoint!", getName(), this);
return kIOUSBEndpointNotFound;
}
status = allocateTDs(pEDQueue, command, buffer, buffer->getLength(), direction, false );
if(status == kIOReturnSuccess)
EnableAsyncSchedule();
else
{
USBLog(1, "%s[%p]::UIMCreateControlTransfer- allocateTDs returned error %x", getName(), this, (UInt32)status);
}
return status;
}
IOReturn
AppleUSBEHCI::UIMCreateBulkTransfer(
short functionAddress,
short endpointNumber,
IOUSBCompletion completion,
IOMemoryDescriptor * CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
USBLog(1, "%s(%p)UIMCreateBulkTransfer- calling the wrong method!", getName(), 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,"%s[%p]::validatePollingRate HS pollingRate raw: %d", getName(), this, pollingRate);
if(pollingRate <= 3)
{
pollingRate = 1;
}
else
{
if(pollingRate > 16)
{
int count = 0;
USBLog(1,"%s[%p]::validatePollingRate: illegal HS polling rate (%d), cooking like FS", getName(), this, pollingRate);
while( (pollingRate >> count) != 1)
count++;
pollingRate = (1 << count);
USBLog(1,"%s[%p]::validatePollingRate: (illegal)new cooked polling rate (%d)", getName(), this, pollingRate);
}
else
{
pollingRate = 1 << (pollingRate - 4);
}
}
if(pollingRate > kEHCIMaxPoll)
{
pollingRate = kEHCIMaxPoll;
}
USBLog(5,"%s[%p]::validatePollingRate HS pollingRate cooked: %d", getName(), this, pollingRate);
}
else
{
int count = 0;
USBLog(5,"%s[%p]::validatePollingRate LS/FS pollingRate raw: %d", getName(), this, pollingRate);
while( (pollingRate >> count) != 1)
count++;
pollingRate = (1 << count);
if(pollingRate > 255)
{
USBLog(5,"%s[%p]::validatePollingRate - Oops LS/FS pollingRate too high: %d, setting to 128", getName(), this, pollingRate);
pollingRate = 128;
}
else if( (pollingRate < 8) && (speed == kUSBDeviceSpeedLow) )
{
USBLog(5,"%s[%p]::validatePollingRate Oops LS pollingRate too low: %d, setting to 8.", getName(), this, pollingRate);
pollingRate = 8;
}
else if(pollingRate == 0)
{
USBLog(5,"%s[%p]::validatePollingRate Oops HS pollingRate too low: %d, setting to 1.", getName(), this, pollingRate);
pollingRate = 1;
}
USBLog(5, "%s[%p]::validatePollingRate LS/FS pollingRate cooked: %d", getName(), 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 AppleEHCIListElement*
FindIntEDqueue(AppleEHCIListElement *start, UInt8 pollingRate)
{
AppleEHCIQueueHead *pQH;
AppleEHCIIsochListElement *pIsoch = OSDynamicCast(AppleEHCIIsochListElement, start);
if (pIsoch)
{
while (OSDynamicCast(AppleEHCIIsochListElement, start->_logicalNext))
{
pIsoch = OSDynamicCast(AppleEHCIIsochListElement, start->_logicalNext);
start = start->_logicalNext;
}
start = 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 = start->_logicalNext;
}
return start;
}
void AppleUSBEHCI::linkInterruptEndpoint(AppleEHCIQueueHead *pEHCIEndpointDescriptor)
{
short pollingRate;
UInt16 maxPacketSize;
int offset;
AppleEHCIListElement * pLE;
UInt32 newHorizPtr;
maxPacketSize = pEHCIEndpointDescriptor->maxPacketSize;
offset = pEHCIEndpointDescriptor->offset;
pollingRate = pEHCIEndpointDescriptor->pollM1+1;
newHorizPtr = HostToUSBLong( pEHCIEndpointDescriptor->GetPhysicalAddrWithType());
while( offset < kEHCIPeriodicListEntries)
{
pLE = FindIntEDqueue(_logicalPeriodicList[offset], pollingRate);
if(pLE == NULL)
{ if(pEHCIEndpointDescriptor->_logicalNext == NULL)
{
pEHCIEndpointDescriptor->_logicalNext = _logicalPeriodicList[offset];
pEHCIEndpointDescriptor->GetSharedLogical()->nextQH = _periodicList[offset];
}
else
{
USBError(1, "%s[%p]::linkInterruptEndpoint(%p) - _logicalNext is not NULL! (%p)", getName(), this, pEHCIEndpointDescriptor, pEHCIEndpointDescriptor->_logicalNext);
}
_logicalPeriodicList[offset] = pEHCIEndpointDescriptor;
_periodicList[offset] = newHorizPtr;
USBLog(7, "%s[%p]::linkInterruptEndpoint - inserted at top of list %d - next logical (%p) next physical (%p)", getName(), this, offset, pEHCIEndpointDescriptor->_logicalNext, USBToHostLong(pEHCIEndpointDescriptor->GetSharedLogical()->nextQH));
}
else if (pEHCIEndpointDescriptor != pLE)
{
if(pEHCIEndpointDescriptor->_logicalNext == NULL) {
pEHCIEndpointDescriptor->_logicalNext = pLE->_logicalNext;
pEHCIEndpointDescriptor->GetSharedLogical()->nextQH = pLE->GetPhysicalLink();
}
else
{
USBError(1, "%s[%p]::linkInterruptEndpoint(%p) - _logicalNext is not NULL! (%p)", getName(), this, pEHCIEndpointDescriptor, pEHCIEndpointDescriptor->_logicalNext);
}
pLE->_logicalNext = pEHCIEndpointDescriptor;
pLE->SetPhysicalLink(newHorizPtr);
USBLog(7, "%s[%p]::linkInterruptEndpoint - inserted into list %d - next logical (%p) next physical (%p)", getName(), this, offset, pEHCIEndpointDescriptor->_logicalNext, USBToHostLong(pEHCIEndpointDescriptor->GetSharedLogical()->nextQH));
}
else
{
USBLog(7, "%s[%p]::linkInterruptEndpoint - (%p) already linked into %d (%p)", getName(), 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, "%s[%p]::UIMCreateInterruptEndpoint - old version called with no split params");
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;
AppleEHCIListElement * pLE;
AppleUSBEHCIHubInfoPtr hiPtr;
if (_rootHubFuncAddress == functionAddress)
return kIOReturnSuccess;
USBLog(7, "%s[%p]::UIMCreateInterruptEndpoint (%d, %d, %s, %d, %d)", getName(), this,
functionAddress, endpointNumber, (speed == kUSBDeviceSpeedLow) ? "lo" : "full", maxPacketSize,
pollingRate);
if( (speed == kUSBDeviceSpeedLow) && (maxPacketSize > 8) )
{
USBLog (1, "%s[%p]::UIMCreateInterruptEndpoint - incorrect max packet size (%d) for low speed", getName(), this, maxPacketSize);
return kIOReturnBadArgument;
}
if(pollingRate == 0)
return(kIOReturnBadArgument);
pollingRate = validatePollingRate(pollingRate, speed, &offset, &availableBandwidth);
if (maxPacketSize > availableBandwidth)
{
USBLog (1, "%s[%p]::UIMCreateInterruptEndpoint - no bandwidth", getName(), this);
return kIOReturnNoBandwidth;
}
if (highSpeedHub)
{
hiPtr = GetHubInfo(highSpeedHub, 0);
if (!hiPtr)
{
hiPtr = NewHubInfo(highSpeedHub, 0);
if (!hiPtr)
return kIOReturnInternalError;
USBLog (1, "%s[%p]::UIMCreateInterruptEndpoint - setting new hub info(%p) bandwidth to 1024", getName(), this, hiPtr);
hiPtr->bandwidthAvailable = 1024;
}
if (hiPtr->flags & kUSBEHCIFlagsMuliTT)
{
hiPtr = GetHubInfo(highSpeedHub, highSpeedPort);
if (!hiPtr)
{
hiPtr = NewHubInfo(highSpeedHub, highSpeedPort);
if (!hiPtr)
return kIOReturnInternalError;
USBLog (1, "%s[%p]::UIMCreateInterruptEndpoint - setting new hub info(%p) bandwidth to 1024", getName(), this, hiPtr);
hiPtr->bandwidthAvailable = 1024;
}
}
if (maxPacketSize > hiPtr->bandwidthAvailable)
{
USBLog (1, "%s[%p]::UIMCreateInterruptEndpoint - split transaction - no bandwidth on hub or port (MPS %d, bw %d)", getName(), this, maxPacketSize, hiPtr->bandwidthAvailable);
return kIOReturnNoBandwidth;
}
hiPtr->bandwidthAvailable -= maxPacketSize;
USBLog(5, "%s[%p]::UIMCreateInterruptEndpoint - using offset %d with HS bandwidth of %d and hub/port bandwidth of %d", getName(), this, offset, availableBandwidth, hiPtr->bandwidthAvailable);
}
else
{
USBLog(5, "%s[%p]::UIMCreateInterruptEndpoint - using offset %d with HS bandwidth of %d", getName(), this, offset, availableBandwidth);
}
pEHCIEndpointDescriptor = MakeEmptyIntEndPoint(functionAddress, endpointNumber, maxPacketSize, speed, highSpeedHub, highSpeedPort, direction);
if (pEHCIEndpointDescriptor == NULL)
{
USBError(1, "%s[%p]::UIMCreateInterruptEndpoint - could not create empty endpoint", getName(), this);
return kIOReturnNoResources;
}
pEHCIEndpointDescriptor->pollM1 = pollingRate-1;
pEHCIEndpointDescriptor->offset = offset;
pEHCIEndpointDescriptor->maxPacketSize = maxPacketSize;
if(_greatestPeriod < pollingRate)
{
_greatestPeriod = pollingRate;
}
linkInterruptEndpoint(pEHCIEndpointDescriptor);
#if 0
UInt32 newHorizPtr;
newHorizPtr = HostToUSBLong( pEHCIEndpointDescriptor->GetPhysicalAddrWithType());
USBLog(5, "+%s[%p]::UIMCreateInterruptEndpoint - about to put new int ED %p (physical %p) into periodic list", getName(), this, pEHCIEndpointDescriptor, USBToHostLong(newHorizPtr));
while( offset < kEHCIPeriodicListEntries)
{
pLE = FindIntEDqueue(_logicalPeriodicList[offset], pollingRate);
if(pLE == NULL)
{ if(pEHCIEndpointDescriptor->_logicalNext == NULL) {
pEHCIEndpointDescriptor->_logicalNext = _logicalPeriodicList[offset];
pEHCIEndpointDescriptor->GetSharedLogical()->nextQH = _periodicList[offset];
}
_logicalPeriodicList[offset] = pEHCIEndpointDescriptor;
_periodicList[offset] = newHorizPtr;
USBLog(7, "%s[%p]::UIMCreateInterruptEndpoint - inserted at top of list %d - next logical (%p) next physical (%p)", getName(), this, offset, pEHCIEndpointDescriptor->_logicalNext, USBToHostLong(pEHCIEndpointDescriptor->GetSharedLogical()->nextQH));
}
else if (pEHCIEndpointDescriptor != pLE)
{
if(pEHCIEndpointDescriptor->_logicalNext == NULL) {
pEHCIEndpointDescriptor->_logicalNext = pLE->_logicalNext;
pEHCIEndpointDescriptor->GetSharedLogical()->nextQH = pLE->GetPhysicalLink();
}
pLE->_logicalNext = pEHCIEndpointDescriptor;
pLE->SetPhysicalLink(newHorizPtr);
USBLog(7, "%s[%p]::UIMCreateInterruptEndpoint - inserted into list %d - next logical (%p) next physical (%p)", getName(), this, offset, pEHCIEndpointDescriptor->_logicalNext, USBToHostLong(pEHCIEndpointDescriptor->GetSharedLogical()->nextQH));
}
else
{
USBLog(7, "%s[%p]::UIMCreateInterruptEndpoint - (%p) already linked into %d (%p)", getName(), this, pEHCIEndpointDescriptor, offset, pLE);
}
if (offset < kEHCIMaxPoll)
_periodicBandwidth[offset] -= maxPacketSize;
offset += pollingRate;
}
_periodicEDsInSchedule++;
#endif
USBLog(5, "-%s[%p]::UIMCreateInterruptEndpoint", getName(), this);
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::UIMCreateIsochEndpoint(
short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction)
{
USBError(1, "%s[%p]::UIMCreateIsochEndpoint -- old version called with no split params", getName(), this);
return kIOReturnBadArgument;
}
IOReturn
AppleUSBEHCI::UIMCreateIsochEndpoint(
short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
AppleEHCIIsochEndpointPtr pEP;
UInt32 curMaxPacketSize;
AppleUSBEHCIHubInfoPtr hiPtr;
UInt32 xtraRequest;
UInt16 *bandWidthAvailPtr;
UInt16 highSpeedBandWidth;
USBLog(7, "%s[%p]::UIMCreateIsochEndpoint(%d, %d, %d, %d, %d, %d)", getName(), this, functionAddress, endpointNumber, maxPacketSize, direction, highSpeedHub, highSpeedPort);
if (highSpeedHub == 0)
{
USBLog (1, "%s[%p]::UIMCreateIsochEndpoint - high speed", getName(), this);
}
if (highSpeedHub == 0)
{
highSpeedBandWidth = _isochBandwidthAvail;
bandWidthAvailPtr = &highSpeedBandWidth;
}
else
{
hiPtr = GetHubInfo(highSpeedHub, 0);
if (!hiPtr)
{
hiPtr = NewHubInfo(highSpeedHub, 0);
if (!hiPtr)
return kIOReturnInternalError;
USBLog (1, "%s[%p]::UIMCreateIsochEndpoint - setting new hub info(%p) bandwidth to 1024", getName(), this, hiPtr);
hiPtr->bandwidthAvailable = 1024;
}
if (hiPtr->flags & kUSBEHCIFlagsMuliTT)
{
hiPtr = GetHubInfo(highSpeedHub, highSpeedPort);
if (!hiPtr)
{
hiPtr = NewHubInfo(highSpeedHub, highSpeedPort);
if (!hiPtr)
return kIOReturnInternalError;
USBLog (1, "%s[%p]::UIMCreateIsochEndpoint - setting new hub info(%p) bandwidth to 1024", getName(), this, hiPtr);
hiPtr->bandwidthAvailable = 1024;
}
}
bandWidthAvailPtr = &hiPtr->bandwidthAvailable;
}
pEP = FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL);
if (pEP)
{
USBLog(6,"%s[%p]::UIMCreateIsochEndpoint endpoint already exists, changing maxPacketSize to %d",getName(), this, maxPacketSize);
curMaxPacketSize = pEP->maxPacketSize;
if (maxPacketSize == curMaxPacketSize)
{
USBLog(4, "%s[%p]::UIMCreateIsochEndpoint maxPacketSize (%d) the same, no change",getName(), this, maxPacketSize);
return kIOReturnSuccess;
}
if (maxPacketSize > curMaxPacketSize)
{
xtraRequest = maxPacketSize - curMaxPacketSize;
if (xtraRequest > *bandWidthAvailPtr)
{
USBLog(1,"%s[%p]::UIMCreateIsochEndpoint out of bandwidth, request (extra) = %d, available: %d",getName(), this, xtraRequest, *bandWidthAvailPtr);
return kIOReturnNoBandwidth;
}
*bandWidthAvailPtr -= xtraRequest;
USBLog(6, "%s[%p]::UIMCreateIsochEndpoint grabbing additional bandwidth: %d, new available: %d",getName(), this, xtraRequest, *bandWidthAvailPtr);
} else
{
xtraRequest = curMaxPacketSize - maxPacketSize;
*bandWidthAvailPtr += xtraRequest;
USBLog(6, "%s[%p]::UIMCreateIsochEndpoint returning some bandwidth: %d, new available: %d",getName(), this, xtraRequest, *bandWidthAvailPtr);
}
pEP->maxPacketSize = maxPacketSize;
if (highSpeedHub == 0)
{
_isochBandwidthAvail = highSpeedBandWidth;
if(maxPacketSize >1024)
{
pEP->mult = ((maxPacketSize-1)/1024)+1;
pEP->oneMPS = (maxPacketSize+2)/pEP->mult;
}
else
{
pEP->mult = 1;
pEP->oneMPS = maxPacketSize;
}
USBLog(5,"%s[%p]::UIMCreateIsochEndpoint high speed size %d, mult %d: %d",getName(), this, maxPacketSize, pEP->mult, pEP->oneMPS);
}
return kIOReturnSuccess;
}
if (maxPacketSize > *bandWidthAvailPtr)
{
USBLog(1,"%s[%p]::UIMCreateIsochEndpoint out of bandwidth, request (extra) = %d, available: %d",getName(), this, maxPacketSize, *bandWidthAvailPtr);
return kIOReturnNoBandwidth;
}
pEP = CreateIsochronousEndpoint(functionAddress, endpointNumber, direction, highSpeedHub, highSpeedPort);
if (pEP == NULL)
return kIOReturnNoMemory;
pEP->toDoList = NULL;
pEP->toDoEnd = NULL;
pEP->doneQueue = NULL;
pEP->doneEnd = NULL;
pEP->inSlot = kEHCIPeriodicListEntries+1;
*bandWidthAvailPtr -= maxPacketSize;
pEP->maxPacketSize = maxPacketSize;
USBLog(7, "%s[%p]::UIMCreateIsochEndpoint success. bandwidth used = %d, new available: %d",getName(), this, maxPacketSize, *bandWidthAvailPtr);
if (highSpeedHub == 0)
{
_isochBandwidthAvail = highSpeedBandWidth;
if(maxPacketSize >1024)
{
pEP->mult = ((maxPacketSize-1)/1024)+1;
pEP->oneMPS = (maxPacketSize+2)/pEP->mult;
}
else
{
pEP->mult = 1;
pEP->oneMPS = maxPacketSize;
}
USBLog(6,"%s[%p]::UIMCreateIsochEndpoint high speed 2 size %d, mult %d: %d",getName(), this, maxPacketSize, pEP->mult, pEP->oneMPS);
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::AbortIsochEP(AppleEHCIIsochEndpointPtr pEP)
{
UInt32 slot;
IOReturn err;
AppleEHCIIsochListElement *pTD;
USBLog(7, "%s[%p]::AbortIsochEP (%p)", getName(), this, pEP);
DisablePeriodicSchedule();
while (_filterInterruptActive)
;
err = scavengeIsocTransactions(NULL);
if (err)
{
USBLog(1, "%s[%p]::AbortIsochEP - err (%p) from scavengeIsocTransactions", getName(), this, err);
}
if ((_outSlot < kEHCIPeriodicListEntries) && (pEP->inSlot < kEHCIPeriodicListEntries))
{
slot = _outSlot;
while (slot != pEP->inSlot)
{
AppleEHCIListElement *thing;
AppleEHCIListElement *nextThing;
AppleEHCIListElement *prevThing;
thing = _logicalPeriodicList[slot];
prevThing = NULL;
while(thing != NULL)
{
nextThing = thing->_logicalNext;
pTD = OSDynamicCast(AppleEHCIIsochListElement, thing);
if(pTD)
{
if (pTD->myEndpoint == pEP)
{
if (prevThing)
{
prevThing->_logicalNext = thing->_logicalNext;
prevThing->SetPhysicalLink(thing->GetPhysicalLink());
}
else
{
_logicalPeriodicList[slot] = nextThing;
_periodicList[slot] = thing->GetPhysicalLink();
}
err = pTD->UpdateFrameList(); PutTDonDoneQueue(pEP, pTD);
break; }
}
else
{
break;
}
prevThing = thing;
thing = nextThing;
}
slot = (slot + 1) & (kEHCIPeriodicListEntries-1);
}
}
pTD = GetTDfromToDoList(pEP);
while (pTD)
{
err = pTD->UpdateFrameList();
PutTDonDoneQueue(pEP, pTD);
pTD = GetTDfromToDoList(pEP);
}
pEP->firstAvailableFrame = 0;
pEP->inSlot = kEHCIPeriodicListEntries + 1;
EnablePeriodicSchedule();
pEP->accumulatedStatus = kIOReturnAborted;
ReturnIsocDoneQueue(pEP);
pEP->accumulatedStatus = kIOReturnSuccess;
return kIOReturnSuccess;
}
void
AppleUSBEHCI::returnTransactions(AppleEHCIQueueHead *pED, EHCIGeneralTransferDescriptor *untilThisOne)
{
EHCIGeneralTransferDescriptorPtr doneQueue = NULL, doneTail= NULL;
bool removedSome = false;
USBLog(5, "%s[%p]::returnTransactions, pED(%p) until (%p)", getName(), this, pED, untilThisOne);
pED->print(5);
if (!(USBToHostLong(pED->GetSharedLogical()->qTDFlags) & kEHCITDStatus_Halted))
{
USBError(1, "%s[%p]::returnTransactions, pED (%p) NOT HALTED (qTDFlags = %p)", getName(), this, pED, USBToHostLong(pED->GetSharedLogical()->qTDFlags));
}
if ((pED->qTD != pED->TailTD) && (pED->qTD != untilThisOne)) {
USBLog(5, "%s[%p] returnTransactions: removing TDs", getName(), 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()->NextqTDPtr = HostToUSBLong(untilThisOne->pPhysical);
pED->qTD = untilThisOne;
}
USBLog(5, "%s[%p]::returnTransactions, pED->qTD (L:%p P:%p) pED->TailTD (L:%p P:%p)", getName(), this, pED->qTD, pED->qTD->pPhysical, pED->TailTD, pED->TailTD->pPhysical);
USBLog(5, "%s[%p]::returnTransactions: clearing ED bit, qTDFlags = %x", getName(), this, USBToHostLong(pED->GetSharedLogical()->qTDFlags));
if (removedSome)
pED->GetSharedLogical()->qTDFlags = 0; else
pED->GetSharedLogical()->qTDFlags &= HostToUSBLong(kEHCITDFlags_DT); if (doneQueue)
{
USBLog(5, "%s[%p]::returnTransactions: calling back the done queue (after ED is made active)", getName(), this);
EHCIUIMDoDoneQueueProcessing(doneQueue, kIOUSBTransactionReturned, NULL, NULL);
}
USBLog(5, "%s[%p]::returnTransactions: after bit clear, qTDFlags = %x", getName(), this, USBToHostLong(pED->GetSharedLogical()->qTDFlags));
}
void
AppleUSBEHCI::HaltAsyncEndpoint(AppleEHCIQueueHead *pED, AppleEHCIQueueHead *pEDBack)
{
if (!(USBToHostLong(pED->GetSharedLogical()->qTDFlags) & kEHCITDStatus_Halted))
{
USBLog(6, "%s[%p]::HaltAsyncEndpoint - unlinking, halting, and relinking (%p)", getName(), this, pED);
unlinkAsyncEndpoint(pED, pEDBack);
pED->GetSharedLogical()->qTDFlags |= HostToUSBLong(kEHCITDStatus_Halted);
linkAsyncEndpoint(pED, _AsyncHead);
}
}
void
AppleUSBEHCI::HaltInterruptEndpoint(AppleEHCIQueueHead *pED)
{
if (!(USBToHostLong(pED->GetSharedLogical()->qTDFlags) & kEHCITDStatus_Halted))
{
USBLog(6, "%s[%p]::HaltInterruptEndpoint - unlinking, halting, and relinking (%p)", getName(), this, pED);
unlinkIntEndpoint(pED);
pED->GetSharedLogical()->qTDFlags |= HostToUSBLong(kEHCITDStatus_Halted);
linkInterruptEndpoint(pED);
}
}
IOReturn
AppleUSBEHCI::HandleEndpointAbort(
short functionAddress,
short endpointNumber,
short direction,
bool clearToggle)
{
AppleEHCIQueueHead *pED;
AppleEHCIQueueHead *pEDQueueBack;
AppleEHCIIsochEndpointPtr piEP;
USBLog(5, "%s[%p] AppleUSBEHCI::HandleEndpointAbort: Addr: %d, Endpoint: %d,%d",getName(), this, functionAddress, endpointNumber, direction);
if (functionAddress == _rootHubFuncAddress)
{
if ( (endpointNumber != 1) && (endpointNumber != 0) )
{
USBLog(1, "%s[%p::HandleEndpointAbort: bad params - endpNumber: %d", getName(), this, endpointNumber );
return kIOReturnBadArgument;
}
USBLog(5, "%s[%p]::HandleEndpointAbort: Attempting operation on root hub", getName(), this);
return SimulateEDAbort( endpointNumber, direction);
}
piEP = FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL);
if (piEP)
{
return AbortIsochEP(piEP);
}
pED = FindControlBulkEndpoint (functionAddress, endpointNumber, &pEDQueueBack, direction);
if(pED != NULL)
{
HaltAsyncEndpoint(pED, pEDQueueBack);
returnTransactions(pED, NULL); if (clearToggle)
pED->GetSharedLogical()->qTDFlags &= HostToUSBLong(~kEHCITDFlags_DT); }
else
{
pED = FindInterruptEndpoint(functionAddress, endpointNumber, direction, &pEDQueueBack);
if(pED == NULL)
{
USBLog(1, "AppleUSBEHCI::HandleEndpointAbort, endpoint not found");
return kIOUSBEndpointNotFound;
}
#warning Aborting Int endpoints needs to be done properly.
HaltInterruptEndpoint(pED);
returnTransactions(pED, NULL);
}
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, "%s[%p]::UIMClearEndpointStall - endpoint %d:%d", getName(), this, functionAddress, endpointNumber);
return HandleEndpointAbort(functionAddress, endpointNumber, direction, true);
}
AppleEHCIQueueHead *
AppleUSBEHCI::FindInterruptEndpoint(short functionNumber, short endpointNumber, short direction, AppleEHCIQueueHead * *pEDBack)
{
UInt32 unique;
AppleEHCIQueueHead * pEDQueue;
AppleEHCIQueueHead * pEDQueueBack;
int i;
unique = (UInt32) ((((UInt32) endpointNumber) << kEHCIEDFlags_ENPhase) | ((UInt32) functionNumber));
pEDQueueBack = NULL;
for(i= 0; i < _greatestPeriod; i++)
{
pEDQueue = OSDynamicCast(AppleEHCIQueueHead, _logicalPeriodicList[i]);
while ( pEDQueue != NULL)
{
if( ( (USBToHostLong(pEDQueue->GetSharedLogical()->flags) & kUniqueNumNoDirMask) == unique) && ( pEDQueue->direction == (UInt8)direction) )
{
if (pEDBack)
*pEDBack = pEDQueueBack;
return pEDQueue;
} else
{
pEDQueueBack = pEDQueue;
pEDQueue = OSDynamicCast(AppleEHCIQueueHead, pEDQueue->_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, "%s[%p]::UIMCreateInterruptTransfer - adr=%d:%d cbp=%p:%lx br=%s cback=[%lx:%lx:%lx])", getName(), this,
command->GetAddress(), command->GetEndpoint(), command->GetBuffer(),
command->GetBuffer()->getLength(), command->GetBufferRounding()?"YES":"NO",
(UInt32)completion.action, (UInt32)completion.target,
(UInt32)completion.parameter);
if (_rootHubFuncAddress == command->GetAddress())
{
SimulateRootHubInt(command->GetEndpoint(), buffer, buffer->getLength(), completion);
return kIOReturnSuccess;
}
pEDQueue = FindInterruptEndpoint(command->GetAddress(), command->GetEndpoint(), direction, NULL);
if (!pEDQueue)
{
USBLog(1, "%s[%p]::UIMCreateInterruptTransfer - Endpoint not found", getName(), this);
return kIOUSBEndpointNotFound;
}
status = allocateTDs(pEDQueue, command, buffer, command->GetBuffer()->getLength(), direction, false );
if(status != kIOReturnSuccess)
{
USBLog(1, "%s[%p]::UIMCreateInterruptTransfer allocateTDs failed %x", getName(), this, status);
}
else
EnablePeriodicSchedule();
return status;
}
IOReturn
AppleUSBEHCI::UIMCreateInterruptTransfer(
short functionAddress,
short endpointNumber,
IOUSBCompletion completion,
IOMemoryDescriptor * CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
USBLog(1, "%s(%p)UIMCreateInterruptTransfer- calling the wrong method!", getName(), this);
return kIOReturnIPCError;
}
void
AppleUSBEHCI::unlinkIntEndpoint(AppleEHCIQueueHead * pED)
{
int i;
AppleEHCIQueueHead * pEDQueue;
int maxPacketSize;
Boolean foundED = false;
USBLog(7, "+%s[%p]::unlinkIntEndpoint(%p)", getName(), this, pED);
maxPacketSize = (USBToHostLong(pED->GetSharedLogical()->flags) & kEHCIEDFlags_MPS) >> kEHCIEDFlags_MPSPhase;
for(i= pED->offset; i < kEHCIPeriodicListEntries; i += pED->pollM1+1)
{
pEDQueue = OSDynamicCast(AppleEHCIQueueHead, _logicalPeriodicList[i]);
if(pED == pEDQueue)
{
_logicalPeriodicList[i] = pED->_logicalNext;
_periodicList[i] = pED->GetSharedLogical()->nextQH;
foundED = true;
USBLog(6, "%s[%p]::unlinkIntEndpoint- found ED at top of list %d, new logical=%p, new physical=%p", getName(), this, i, _logicalPeriodicList[i], USBToHostLong(_periodicList[i]));
}
else
{
while(pEDQueue != NULL)
{
if(pEDQueue->_logicalNext == pED)
{
pEDQueue->_logicalNext = pED->_logicalNext;
pEDQueue->GetSharedLogical()->nextQH = pED->GetSharedLogical()->nextQH;
foundED = true;
USBLog(6, "%s[%p]::unlinkIntEndpoint- found ED in list %d, new logical=%p, new physical=%p", getName(), this, i, pEDQueue->_logicalNext, USBToHostLong(pEDQueue->GetSharedLogical()->nextQH));
break;
}
pEDQueue = OSDynamicCast(AppleEHCIQueueHead, pEDQueue->_logicalNext);
}
if(pEDQueue == NULL)
{
USBLog(7, "%s[%p]::unlinkIntEndpoint endpoint not found in list %d", getName(), this, i);
}
}
if (i < kEHCIMaxPoll)
_periodicBandwidth[i] += maxPacketSize;
}
IOSleep(1); pED->_logicalNext = NULL;
if (foundED)
_periodicEDsInSchedule--;
USBLog(7, "-%s[%p]::unlinkIntEndpoint(%p)", getName(), this, pED);
}
void
AppleUSBEHCI::unlinkAsyncEndpoint(AppleEHCIQueueHead * pED, AppleEHCIQueueHead * pEDQueueBack)
{
UInt32 CMD, STS, count;
if( (pEDQueueBack == NULL) && (pED->_logicalNext == NULL) )
{
USBLog(7, "%s[%p]::unlinkAsyncEndpoint: removing sole endpoint %lx", getName(),this, (long)pED);
DisableAsyncSchedule();
printAsyncQueue();
_AsyncHead = NULL;
_pEHCIRegisters->AsyncListAddr = 0;
printAsyncQueue();
}
else
{
USBLog(7, "%s[%p]::unlinkAsyncEndpoint: removing endpoint from queue %lx", getName(),this, (long)pED);
if(_AsyncHead == pED)
{
if (pEDQueueBack)
{
USBError(1, "%s[%p]::unlinkAsyncEndpoint: ERROR - pEDQueueBack should be NULL at this point", getName(),this );
}
pEDQueueBack = OSDynamicCast(AppleEHCIQueueHead, pED->_logicalNext);
while (pEDQueueBack->_logicalNext)
pEDQueueBack = OSDynamicCast(AppleEHCIQueueHead, pEDQueueBack->_logicalNext);
printAsyncQueue();
_AsyncHead = OSDynamicCast(AppleEHCIQueueHead, pED->_logicalNext);
_pEHCIRegisters->AsyncListAddr = HostToUSBLong(pED->_logicalNext->_sharedPhysical);
pEDQueueBack->GetSharedLogical()->nextQH = HostToUSBLong(pED->_logicalNext->GetPhysicalAddrWithType());
pED = OSDynamicCast(AppleEHCIQueueHead , pED->_logicalNext);
pED->GetSharedLogical()->flags |= HostToUSBLong(kEHCIEDFlags_H);
printAsyncQueue();
}
else if(pEDQueueBack != NULL)
{
printAsyncQueue();
pEDQueueBack->GetSharedLogical()->nextQH = pED->GetSharedLogical()->nextQH;
pEDQueueBack->_logicalNext = pED->_logicalNext;
printAsyncQueue();
}
else
{
USBLog(7, "%s[%p]::unlinkAsyncEndpoint: ED not head, but pEDQueueBack not NULL", getName(),this);
}
CMD = USBToHostLong(_pEHCIRegisters->USBCMD);
_pEHCIRegisters->USBCMD = HostToUSBLong(CMD | kEHCICMDAsyncDoorbell);
STS = USBToHostLong(_pEHCIRegisters->USBSTS);
count = 0;
while((STS & kEHCIAAEIntBit) == 0)
{
IOSleep(1);
STS = USBToHostLong(_pEHCIRegisters->USBSTS);
count++;
if ( count > 10000)
{
break;
}
};
USBLog(5, "%s[%p]::unlinkAsyncEndpoint: delayed for %d", getName(),this, count);
_pEHCIRegisters->USBSTS = HostToUSBLong(kEHCIAAEIntBit);
}
}
IOReturn
AppleUSBEHCI::DeleteIsochEP(AppleEHCIIsochEndpointPtr pEP)
{
AppleEHCIIsochEndpointPtr curEP, prevEP;
USBLog(7, "%s[%p]::DeleteIsochEP (%p)", getName(), this, pEP);
if (pEP->activeTDs)
{
USBLog(6, "%s[%p]::DeleteIsochEP- there are still %d active TDs - aborting", getName(), this, pEP->activeTDs);
AbortIsochEP(pEP);
if (pEP->activeTDs)
{
USBLog(3, "%s[%p]::DeleteIsochEP- after abort there are STILL %d active TDs", getName(), this, 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;
}
if (pEP->highSpeedHub == 0)
{
_isochBandwidthAvail += pEP->maxPacketSize;
}
else
{
AppleUSBEHCIHubInfoPtr hiPtr;
hiPtr = GetHubInfo(pEP->highSpeedHub, pEP->highSpeedPort);
if (!hiPtr)
{
hiPtr = GetHubInfo(pEP->highSpeedHub, 0);
}
if (hiPtr)
{
USBLog(5, "%s[%p]::DeleteIsochEP - returning bandwidth (%d) - new bandwidth (%d)", getName(), this, pEP->maxPacketSize, hiPtr->bandwidthAvailable + pEP->maxPacketSize);
hiPtr->bandwidthAvailable += pEP->maxPacketSize;
}
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::UIMDeleteEndpoint(
short functionAddress,
short endpointNumber,
short direction)
{
AppleEHCIQueueHead *pED;
AppleEHCIQueueHead *pEDQueueBack;
AppleEHCIIsochEndpointPtr piEP;
USBLog(7, "%s[%p] AppleUSBEHCI::UIMDeleteEndpoint: Addr: %d, Endpoint: %d,%d",getName(), this, functionAddress,endpointNumber,direction);
if (functionAddress == _rootHubFuncAddress)
{
if ( (endpointNumber != 1) && (endpointNumber != 0) )
{
USBLog(1, "%s[%p] UIMDeleteEndpoint: bad params - endpNumber: %d", getName(), this, endpointNumber );
return kIOReturnBadArgument;
}
USBLog(5, "%s[%p] UIMDeleteEndpoint: Attempting operation on root hub", getName(), this);
return SimulateEDDelete( endpointNumber, direction);
}
piEP = 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;
AppleUSBEHCIHubInfoPtr hiPtr;
pED = FindInterruptEndpoint(functionAddress, endpointNumber, direction, &pEDQueueBack);
if(pED == NULL)
{
USBLog(2, "AppleUSBEHCI::UIMDeleteEndpoint, endpoint not found");
return kIOUSBEndpointNotFound;
}
USBLog(5, "%s[%p]::UIMDeleteEndpoint: deleting Int endpoint", getName(), this);
unlinkIntEndpoint(pED);
if (!_periodicEDsInSchedule)
{
USBLog(3, "%s[%p]::UIMDeleteEndpoint: $$$$$$ all EDs gone from periodic schedule, disabling", getName(), this, _periodicEDsInSchedule);
DisablePeriodicSchedule();
}
splitFlags = USBToHostLong(pED->GetSharedLogical()->splitFlags);
highSpeedHub = (splitFlags & kEHCIEDSplitFlags_HubAddr) >> kEHCIEDSplitFlags_HubAddrPhase;
highSpeedPort = (splitFlags & kEHCIEDSplitFlags_Port) >> kEHCIEDSplitFlags_PortPhase;
hiPtr = GetHubInfo(highSpeedHub, highSpeedPort);
if (!hiPtr)
{
hiPtr = GetHubInfo(highSpeedHub, 0);
}
if (hiPtr)
{
USBLog(5, "%s[%p]::UIMDeleteEndpoint - returning bandwidth (%d) - new bandwidth (%d)", getName(), this, pED->maxPacketSize, hiPtr->bandwidthAvailable + pED->maxPacketSize);
hiPtr->bandwidthAvailable += pED->maxPacketSize;
}
}
else
{
USBLog(5, "%s[%p] UIMDeleteEndpoint: deleting async endpoint", getName(), this);
unlinkAsyncEndpoint(pED, pEDQueueBack);
}
if(pED->qTD != pED->TailTD) {
USBLog(5, "%s[%p] UIMDeleteEndpoint: removing TDs", getName(), this);
EHCIUIMDoDoneQueueProcessing(pED->qTD, kIOUSBTransactionReturned, NULL, pED->TailTD);
pED->qTD = pED->TailTD;
pED->GetSharedLogical()->NextqTDPtr = HostToUSBLong(pED->qTD->pPhysical);
}
USBLog(5, "%s[%p] AppleUSBEHCI::UIMDeleteEndpoint: Deallocating %p",getName(), this, pED);
DeallocateED(pED);
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::CreateHSIsochTransfer( AppleEHCIIsochEndpointPtr pEP,
IOUSBIsocCompletion completion,
UInt64 frameNumberStart,
IOMemoryDescriptor *pBuffer,
UInt32 frameCount,
IOUSBIsocFrame *pFrames)
{
return CreateHSIsochTransfer(pEP, completion, frameNumberStart, pBuffer, frameCount, (IOUSBLowLatencyIsocFrame *)pFrames, 0, false);
}
IOReturn
AppleUSBEHCI::CreateHSIsochTransfer( AppleEHCIIsochEndpointPtr pEP,
IOUSBIsocCompletion completion,
UInt64 frameNumberStart,
IOMemoryDescriptor *pBuffer,
UInt32 frameCount,
IOUSBLowLatencyIsocFrame *pFrames,
UInt32 updateFrequency)
{
return CreateHSIsochTransfer(pEP, completion, frameNumberStart, pBuffer, frameCount, pFrames, updateFrequency, true);
}
IOReturn
AppleUSBEHCI::CreateHSIsochTransfer( AppleEHCIIsochEndpointPtr pEP,
IOUSBIsocCompletion completion,
UInt64 frameNumberStart,
IOMemoryDescriptor *pBuffer,
UInt32 frameCount,
IOUSBLowLatencyIsocFrame *pFrames,
UInt32 updateFrequency,
Boolean lowLatency)
{
UInt64 curFrameNumber = GetFrameNumber();
UInt64 maxOffset;
UInt32 bufferSize;
AppleEHCIIsochTransferDescriptor *pNewITD = NULL;
IOByteCount transferOffset;
unsigned i,j;
UInt32 *buffP, *TransactionP = 0;
UInt32 pageOffset;
UInt32 page;
UInt32 frames;
UInt32 trLen;
UInt64 frameDiff;
UInt32 diff32;
IOUSBIsocFrame *pHLFrames;
IOPhysicalAddress dmaStartAddr;
IOByteCount segLen;
if( (frameCount % 8) != 0 )
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer frameCount not whole frame: %d",getName(), this, frameCount);
return kIOReturnBadArgument;
}
maxOffset = _frameListSize;
if (frameNumberStart <= curFrameNumber)
{
if (frameNumberStart < (curFrameNumber - maxOffset))
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer request frame WAY too old. frameNumberStart: %ld, curFrameNumber: %ld. Returning 0x%x",getName(), this, (UInt32) frameNumberStart, (UInt32) curFrameNumber, kIOReturnIsoTooOld);
return kIOReturnIsoTooOld;
}
USBLog(5,"%s[%p]::UIMCreateIsochTransfer WARNING! curframe later than requested, expect some notSent errors! frameNumberStart: %ld, curFrameNumber: %ld. USBIsocFrame Ptr: %p, First ITD: %p",getName(), this, (UInt32) frameNumberStart, (UInt32) curFrameNumber, pFrames, pEP->toDoEnd);
} else
{ if (frameNumberStart > (curFrameNumber + maxOffset))
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer request frame too far ahead! frameNumberStart: %ld, curFrameNumber: %ld",getName(), this, (UInt32) frameNumberStart, (UInt32) curFrameNumber);
return kIOReturnIsoTooNew;
}
frameDiff = frameNumberStart - curFrameNumber;
diff32 = (UInt32)frameDiff;
if (diff32 < 2)
{
USBLog(5,"%s[%p]::UIMCreateIsochTransfer WARNING! - frameNumberStart less than 2 ms (is %ld)! frameNumberStart: %ld, curFrameNumber: %ld",getName(), this, (UInt32) diff32, (UInt32) frameNumberStart, (UInt32) curFrameNumber);
}
}
frames = 100;
transferOffset = 0;
pHLFrames = (IOUSBIsocFrame *)pFrames;
while(frameCount > 0)
{
bufferSize = 0;
for ( i = 0; i< 8; i++)
{
if(frameCount < i)
{
break;
}
if(lowLatency)
{
if (pFrames[i].frReqCount > kUSBMaxHSIsocFrameReqCount)
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer Isoch frame too big %d",getName(), this, pFrames[i].frReqCount);
return kIOReturnBadArgument;
}
bufferSize += pFrames[i].frReqCount;
}
else
{
if (pHLFrames[i].frReqCount > kUSBMaxHSIsocFrameReqCount)
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer Isoch frame too big %d",getName(), this, pHLFrames[i].frReqCount);
return kIOReturnBadArgument;
}
bufferSize += pHLFrames[i].frReqCount;
}
}
pNewITD = AllocateITD();
USBLog(7, "%s[%p]::UIMCreateIsochTransfer - new iTD %p", getName(), this, pNewITD);
if (pNewITD == NULL)
{
USBLog(1,"%s[%p]::UIMCreateIsochTransfer Could not allocate a new iTD",getName(), this);
return kIOReturnNoMemory;
}
pNewITD->lowLatency = lowLatency;
buffP = &pNewITD->GetSharedLogical()->bufferPage0;
dmaStartAddr = pBuffer->getPhysicalSegment(transferOffset, &segLen);
pageOffset = dmaStartAddr & kEHCIPageOffsetMask;
if(segLen > bufferSize)
{
segLen = bufferSize;
}
if(segLen > (kEHCIPageSize-pageOffset))
{
segLen = kEHCIPageSize-pageOffset;
}
*(buffP++) = HostToUSBLong( dmaStartAddr & kEHCIPageMask);
USBLog(7, "%s[%p]::CreateHSIocTransfer - getPhysicalSegment returned start of %p; length:%ld ; Buff Ptr0:%lx", getName(), this, dmaStartAddr, segLen, *(buffP-1));
transferOffset += segLen;
bufferSize -= segLen;
for(j=1; j<=6; j++)
{
if(bufferSize==0)
{
*(buffP++) = 0;
continue;
}
dmaStartAddr = pBuffer->getPhysicalSegment(transferOffset, &segLen);
*(buffP++) = HostToUSBLong( dmaStartAddr & kEHCIPageMask);
pageOffset = dmaStartAddr & kEHCIPageOffsetMask;
if(pageOffset != 0)
{
USBError(1, "%s[%p]::CreateHSIocTransfer - pageOffset not zero in %dth buff: %p", getName(), this, j, dmaStartAddr);
}
if(segLen > bufferSize)
{
segLen = bufferSize;
}
if(segLen > kEHCIPageSize)
{
segLen = kEHCIPageSize;
}
transferOffset += segLen;
bufferSize -= segLen;
USBLog(7, "%s[%p]::CreateHSIocTransfer - getPhysicalSegment returned start of %p; length:%ld ; Buff Ptr%d:%lx", getName(), this, dmaStartAddr, segLen, j, *(buffP-1));
}
page = 0;
TransactionP = &pNewITD->GetSharedLogical()->Transaction0;
if(lowLatency)
{
pNewITD->myFrames = (IOUSBIsocFrame *)pFrames; }
else
{
pNewITD->myFrames = pHLFrames; }
for ( i = 0; i< 8; i++)
{
if(frameCount < i)
{
break;
}
if(lowLatency)
{
trLen = (pFrames++)->frReqCount;
}
else
{
trLen = (pHLFrames++)->frReqCount;
}
*(TransactionP++) = HostToUSBLong(kEHCI_ITDStatus_Active | (trLen<< kEHCI_ITDTr_LenPhase) |
(pageOffset << kEHCI_ITDTr_OffsetPhase) | (page << kEHCI_ITDTr_PagePhase) );
pNewITD->completion.action = NULL;
pageOffset += trLen;
if(pageOffset > kEHCIPageSize)
{
pageOffset -= kEHCIPageSize;
page++;
}
};
if(frameCount > 8)
{
frameCount -= 8;
}
else
{
frameCount = 0;
}
if(frames-- == 0)
{
TransactionP[-1] |= HostToUSBLong(kEHCI_ITDTr_IOC);
frames = 100;
}
pNewITD->frameNumber = frameNumberStart++;
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->myEndpoint = pEP;
PutTDonToDoList(pEP, pNewITD);
}
TransactionP[-1] |= HostToUSBLong(kEHCI_ITDTr_IOC);
USBLog(3,"%s[%p]::UIMCreateIsochTransfer completion completion.action %p",getName(), this, completion.action);
pNewITD->completion = completion;
AddIsocFramesToSchedule(pEP);
EnablePeriodicSchedule();
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::CreateSplitIsochTransfer( AppleEHCIIsochEndpointPtr pEP,
IOUSBIsocCompletion completion,
UInt64 frameNumberStart,
IOMemoryDescriptor *pBuffer,
UInt32 frameCount,
IOUSBIsocFrame *pFrames,
UInt32 updateFrequency,
bool lowLatency)
{
AppleEHCISplitIsochTransferDescriptor *pNewSITD;
UInt64 maxOffset;
UInt64 curFrameNumber = GetFrameNumber();
UInt64 frameDiff;
UInt32 diff32;
IOByteCount transferOffset;
UInt32 frames;
IOUSBLowLatencyIsocFrame *pLLFrames;
UInt32 bufferSize;
UInt8 startSplitFlags;
UInt8 completeSplitFlags;
UInt8 transactionPosition;
UInt8 transactionCount;
UInt8 ioc = 0;
UInt32 i;
UInt32 pageOffset;
IOPhysicalAddress dmaStartAddr;
IOByteCount segLen;
USBLog(6, "%s[%p]::CreateSplitIsochTransfer - frameCount %d - frameNumberStart 0x%Lx - curFrameNumber 0x%Lx", getName(), this, frameCount, frameNumberStart, curFrameNumber);
USBLog(6, "%s[%p]::CreateSplitIsochTransfer - updateFrequency %d - lowLatency %d", getName(), this, updateFrequency, lowLatency);
maxOffset = _frameListSize;
if (frameNumberStart < pEP->firstAvailableFrame)
{
USBLog(3,"%s[%p]::CreateSplitIsochTransfer: no overlapping frames - EP (%p) frameNumberStart: %Ld, pEP->firstAvailableFrame: %Ld. Returning 0x%x",getName(), this, pEP, frameNumberStart, pEP->firstAvailableFrame, kIOReturnIsoTooOld);
return kIOReturnIsoTooOld;
}
pEP->firstAvailableFrame = frameNumberStart;
if (frameNumberStart <= curFrameNumber)
{
if (frameNumberStart < (curFrameNumber - maxOffset))
{
USBLog(3,"%s[%p]::CreateSplitIsochTransfer request frame WAY too old. frameNumberStart: %Ld, curFrameNumber: %Ld. Returning 0x%x",getName(), this, frameNumberStart, curFrameNumber, kIOReturnIsoTooOld);
return kIOReturnIsoTooOld;
}
USBLog(5,"%s[%p]::UIMCreateIsochTransfer WARNING! curframe later than requested, expect some notSent errors! frameNumberStart: %Ld, curFrameNumber: %Ld. USBIsocFrame Ptr: %p, First ITD: %p",getName(), this, frameNumberStart, curFrameNumber, pFrames, pEP->toDoEnd);
} else
{ if (frameNumberStart > (curFrameNumber + maxOffset))
{
USBLog(3,"%s[%p]::CreateSplitIsochTransfer request frame too far ahead! frameNumberStart: %Ld, curFrameNumber: %Ld",getName(), this, frameNumberStart, curFrameNumber);
return kIOReturnIsoTooNew;
}
frameDiff = frameNumberStart - curFrameNumber;
diff32 = (UInt32)frameDiff;
if (diff32 < 2)
{
USBLog(5,"%s[%p]::UIMCreateIsochTransfer WARNING! - frameNumberStart less than 2 ms (is %d)! frameNumberStart: %Ld, curFrameNumber: %Ld",getName(), this, diff32, frameNumberStart, curFrameNumber);
}
}
pLLFrames = (IOUSBLowLatencyIsocFrame *)pFrames;
bufferSize = 0;
for ( i = 0; i < frameCount; i++)
{
if (!lowLatency)
{
if (pFrames[i].frReqCount > kUSBMaxIsocFrameReqCount)
{
USBLog(3,"%s[%p]::CreateSplitIsochTransfer - Isoch frame (%d) too big %d",getName(), this, i + 1, pFrames[i].frReqCount);
return kIOReturnBadArgument;
}
bufferSize += pFrames[i].frReqCount;
} else
{
if (pLLFrames[i].frReqCount > kUSBMaxIsocFrameReqCount)
{
USBLog(3,"%s[%p]::CreateSplitIsochTransfer(LL) - Isoch frame (%d) too big %d",getName(), this, i + 1, pLLFrames[i].frReqCount);
return kIOReturnBadArgument;
}
bufferSize += pLLFrames[i].frReqCount;
pLLFrames[i].frStatus = (IOReturn) kUSBLowLatencyIsochTransferKey;
}
}
frames = 100;
transferOffset = 0;
for ( i = 0; i < frameCount; i++)
{
UInt16 reqCount, reqLeft;
pNewSITD = AllocateSITD();
if (lowLatency)
reqCount = pLLFrames[i].frReqCount;
else
reqCount = pFrames[i].frReqCount;
USBLog(7, "%s[%p]::CreateSplitIsochTransfer - new iTD %p size (%d)", getName(), this, pNewSITD, reqCount);
if (!pNewSITD)
{
USBLog(1,"%s[%p]::CreateSplitIsochTransfer Could not allocate a new iTD",getName(), this);
return kIOReturnNoMemory;
}
pEP->firstAvailableFrame++;
pNewSITD->lowLatency = lowLatency;
dmaStartAddr = pBuffer->getPhysicalSegment(transferOffset, &segLen);
pageOffset = dmaStartAddr & kEHCIPageOffsetMask;
if(segLen > reqCount)
{
segLen = reqCount;
}
if(segLen > (kEHCIPageSize-pageOffset))
{
segLen = kEHCIPageSize-pageOffset;
}
pNewSITD->GetSharedLogical()->buffPtr0 = HostToUSBLong(dmaStartAddr);
USBLog(7, "%s[%p]::CreateSplitIocTransfer - getPhysicalSegment returned start of %p; length %ld", getName(), this, dmaStartAddr, segLen);
transferOffset += segLen;
bufferSize -= segLen;
reqLeft = reqCount - segLen;
if(reqLeft==0)
{
pNewSITD->GetSharedLogical()->buffPtr1 = 0;
}
else
{
dmaStartAddr = pBuffer->getPhysicalSegment(transferOffset, &segLen);
pNewSITD->GetSharedLogical()->buffPtr1 = HostToUSBLong(dmaStartAddr & kEHCIPageMask);
if(segLen > reqLeft)
{
segLen = reqLeft;
}
if(segLen > kEHCIPageSize)
{
segLen = kEHCIPageSize;
}
USBLog(7, "%s[%p]::CreateSplitIocTransfer - getPhysicalSegment returned start of %p; length %ld", getName(), this, dmaStartAddr, segLen);
transferOffset += segLen;
bufferSize -= segLen;
}
pNewSITD->myFrames = pFrames;
pNewSITD->frameNumber = frameNumberStart + i;
pNewSITD->frameIndex = i;
if (pEP->direction == kUSBOut)
{
completeSplitFlags = 0; if (reqCount > 188)
{
transactionCount = (reqCount + 187) / 188; transactionPosition = 1; startSplitFlags = (2 << transactionCount) - 1; }
else
{
startSplitFlags = 2; transactionPosition = 0; transactionCount = 1; }
}
else
{
startSplitFlags = 1; transactionPosition = 0; transactionCount = 0; completeSplitFlags = 0xFC; }
if (i == (frameCount-1))
{
ioc = 1;
pNewSITD->completion = completion;
}
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)
);
pNewSITD->GetSharedLogical()->statFlags = HostToUSBLong(
(ioc << kEHCIsiTDStatIOCPhase)
| (reqCount << kEHCIsiTDStatLengthPhase)
| (kEHCIsiTDStatStatusActive)
);
pNewSITD->GetSharedLogical()->buffPtr1 |= HostToUSBLong(
(transactionPosition << kEHCIsiTDBuffPtr1TPPhase)
| (transactionCount)
);
pNewSITD->GetSharedLogical()->backPtr = HostToUSBLong(kEHCITermFlag);
pNewSITD->myEndpoint = pEP;
PutTDonToDoList(pEP, pNewSITD);
}
AddIsocFramesToSchedule(pEP);
EnablePeriodicSchedule();
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::UIMCreateIsochTransfer( short functionAddress,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameStart,
IOMemoryDescriptor *pBuffer,
UInt32 frameCount,
IOUSBIsocFrame *pFrames)
{
AppleEHCIIsochEndpointPtr pEP;
USBLog(7, "%s[%p]::UIMCreateIsochTransfer - adr=%d:%d cbp=%p:%lx (cback=[%lx:%lx:%lx])", getName(), this,
functionAddress, endpointNumber, pBuffer,
pBuffer->getLength(),
(UInt32)completion.action, (UInt32)completion.target,
(UInt32)completion.parameter);
if ( (frameCount == 0) || (frameCount > 200) )
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer bad frameCount: %d",getName(), this, frameCount);
return kIOReturnBadArgument;
}
pEP = FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL);
if(pEP == NULL)
{
USBLog(1, "%s[%p]::UIMCreateIsochTransfer - Endpoint not found", getName(), this);
return kIOUSBEndpointNotFound;
}
if (pEP->highSpeedHub)
return CreateSplitIsochTransfer(pEP, completion, frameStart, pBuffer, frameCount, pFrames);
else
return CreateHSIsochTransfer(pEP, completion, frameStart, pBuffer, frameCount, pFrames);
}
IOReturn
AppleUSBEHCI::UIMCreateIsochTransfer( short functionAddress,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameNumberStart,
IOMemoryDescriptor *pBuffer,
UInt32 frameCount,
IOUSBLowLatencyIsocFrame *pFrames,
UInt32 updateFrequency)
{
AppleEHCIIsochEndpointPtr pEP;
USBLog(7, "%s[%p]::UIMCreateIsochTransfer - adr=%d:%d cbp=%p:%lx (cback=[%lx:%lx:%lx])", getName(), this,
functionAddress, endpointNumber, pBuffer,
pBuffer->getLength(),
(UInt32)completion.action, (UInt32)completion.target,
(UInt32)completion.parameter);
if ( (frameCount == 0) || (frameCount > 200) )
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer bad frameCount: %d",getName(), this, frameCount);
return kIOReturnBadArgument;
}
pEP = FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL);
if(pEP == NULL)
{
USBLog(1, "%s[%p]::UIMCreateIsochTransfer - Endpoint not found", getName(), this);
return kIOUSBEndpointNotFound;
}
if (pEP->highSpeedHub)
return CreateSplitIsochTransfer(pEP, completion, frameNumberStart, pBuffer, frameCount, (IOUSBIsocFrame*)pFrames, updateFrequency, true);
else
return CreateHSIsochTransfer(pEP, completion, frameNumberStart, pBuffer, frameCount, pFrames, updateFrequency);
}
void
AppleUSBEHCI::AddIsocFramesToSchedule(AppleEHCIIsochEndpointPtr pEP)
{
UInt64 currFrame;
AppleEHCIIsochListElement *pTD;
UInt16 nextSlot;
pTD = GetTDfromToDoList(pEP);
if(pTD == NULL)
{
USBLog(7, "%s[%p]::AddIsocFramesToSchedule - no frames to add fn:%d EP:%d", getName(), this, pEP->functionAddress, pEP->endpointNumber);
return;
}
currFrame = GetFrameNumber();
USBLog(7, "%s[%p]::AddIsocFramesToSchedule - fn:%d EP:%d inSlot (0x%x), currFrame: 0x%Lx", getName(), this, pEP->functionAddress, pEP->endpointNumber, pEP->inSlot, currFrame);
while(pTD->frameNumber <= (currFrame+1)) {
IOReturn ret;
USBLog(5, "%s[%p]::AddIsocFramesToSchedule - ignoring TD(%p) because it is too old (%Lx) vs (%Lx) ", getName(), this, pTD, pTD->frameNumber, currFrame);
ret = pTD->UpdateFrameList(); PutTDonDoneQueue(pEP, pTD);
pTD = GetTDfromToDoList(pEP);
if(pTD == NULL)
{
ReturnIsocDoneQueue(pEP);
return;
}
}
currFrame = pTD->frameNumber;
pEP->inSlot = currFrame & (kEHCIPeriodicListEntries-1);
do
{
nextSlot = (pEP->inSlot + 1) & (kEHCIPeriodicListEntries-1);
if( nextSlot == _outSlot) {
USBLog(6, "%s[%p]::AddIsocFramesToSchedule - caught up nextSlot (0x%x) _outSlot (0x%x)", getName(), this, nextSlot, _outSlot);
break;
}
USBLog(6, "%s[%p]::AddIsocFramesToSchedule - checking TD(%p) FN(0x%Lx) against currFrame (0x%Lx)", getName(), this, pTD, pTD->frameNumber, currFrame);
if(currFrame == pTD->frameNumber)
{
if(_outSlot > kEHCIPeriodicListEntries)
{
_outSlot = pEP->inSlot;
}
USBLog(6, "%s[%p]::AddIsocFramesToSchedule - linking TD (%p) with frame (0x%Lx) into slot (0x%x) - curr next log (%p) phys (%p)", getName(),
this, pTD, pTD->frameNumber, pEP->inSlot, _logicalPeriodicList[pEP->inSlot], USBToHostLong(_periodicList[pEP->inSlot]));
pTD->SetPhysicalLink(_periodicList[pEP->inSlot]);
pTD->_logicalNext = _logicalPeriodicList[pEP->inSlot];
_logicalPeriodicList[pEP->inSlot] = pTD;
_periodicList[pEP->inSlot] = HostToUSBLong(pTD->GetPhysicalAddrWithType());
USBLog(6, "%s[%p]::AddIsocFramesToSchedule - _periodicList[%x]:%x", getName(), this, pEP->inSlot, USBToHostLong(_periodicList[pEP->inSlot]));
pTD = GetTDfromToDoList(pEP);
}
currFrame++;
pEP->inSlot = nextSlot;
USBLog(6, "%s[%p]::AddIsocFramesToSchedule - pEP->inSlot is now 0x%x", getName(), this, pEP->inSlot);
} while(pTD != NULL);
USBLog(7, "%s[%p]::AddIsocFramesToSchedule - finished, currFrame: %Lx", getName(), this, GetFrameNumber() );
}
void
AppleUSBEHCI::ReturnIsocDoneQueue(AppleEHCIIsochEndpointPtr pEP)
{
AppleEHCIIsochListElement *pTD = GetTDfromDoneQueue(pEP);
IOUSBIsocFrame *pFrames;
USBLog(7, "%s[%p]::ReturnIsocDoneQueue (%p)", getName(), this, pEP);
if (pTD)
{
pFrames = pTD->myFrames;
}
while(pTD)
{
if( pTD->completion.action != NULL)
{
IOUSBIsocCompletionAction pHandler;
pHandler = pTD->completion.action;
pTD->completion.action = NULL;
USBLog(7, "%s[%p]::ReturnIsocDoneQueue- calling handler(%p, %p, %p, %p)", getName(), this, pTD->completion.target, pTD->completion.parameter, pEP->accumulatedStatus, pFrames);
(*pHandler) (pTD->completion.target, pTD->completion.parameter, pEP->accumulatedStatus, pFrames);
if (pEP->accumulatedStatus != kIOReturnAborted)
pEP->accumulatedStatus = kIOReturnSuccess;
pTD->Deallocate(this);
pTD = GetTDfromDoneQueue(pEP);
if (pTD)
pFrames = pTD->myFrames;
}
else
{
pTD->Deallocate(this);
pTD = GetTDfromDoneQueue(pEP);
}
}
}
IOReturn
AppleUSBEHCI::UIMHubMaintenance(USBDeviceAddress highSpeedHub, UInt32 highSpeedPort, UInt32 command, UInt32 flags)
{
AppleUSBEHCIHubInfoPtr hiPtr;
switch (command)
{
case kUSBHSHubCommandAddHub:
USBLog(7, "%s[%p]::UIMHubMaintenance - adding hub %d with flags %x", getName(), this, highSpeedHub, flags);
hiPtr = GetHubInfo(highSpeedHub, 0);
if (hiPtr)
{
USBLog(7, "%s[%p]::UIMHubMaintenance - adding hub which already exists (%d)", getName(), this, highSpeedHub);
hiPtr->flags = flags;
}
else
{
hiPtr = NewHubInfo(highSpeedHub, 0);
if (!hiPtr)
return kIOReturnNoMemory;
USBLog(7, "%s[%p]::UIMHubMaintenance - done creating new hub (%p) for address (%d)", getName(), this, hiPtr, highSpeedHub);
hiPtr->flags = flags;
hiPtr->bandwidthAvailable = 1024;
}
break;
case kUSBHSHubCommandRemoveHub:
USBLog(7, "%s[%p]::UIMHubMaintenance - deleting hub %d", getName(), this, highSpeedHub);
DeleteHubInfo(highSpeedHub, 0xffff); break;
default:
return kIOReturnBadArgument;
}
return kIOReturnSuccess;
}
#define kEHCIUIMScratchFirstActiveFrame 0
void
AppleUSBEHCI::ReturnOneTransaction(
EHCIGeneralTransferDescriptor *transaction,
AppleEHCIQueueHead *pED,
AppleEHCIQueueHead *pEDBack,
IOReturn err)
{
HaltAsyncEndpoint(pED, pEDBack);
USBLog(6, "ReturnOneTransaction Enter with transaction %p",transaction);
while(transaction!= NULL)
{
if(transaction->lastTDofTransaction)
{
transaction = transaction->pLogicalNext;
break;
}
transaction = transaction->pLogicalNext;
USBLog(7, "ReturnOneTransaction next transaction %p",transaction);
}
USBLog(6, "ReturnOneTransaction going with transaction %p",transaction);
if(transaction == NULL)
{
USBLog(1, "%s[%p]::ReturnOneTransaction - returning all TDs on the queue", getName(), this);
}
else
{
}
returnTransactions(pED, transaction);
}
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, "%s[%p]::CheckEDListForTimeouts - checking ED [%p]", getName(), this, pED);
pED->print(7);
pEDBack = pEDBack1;
pEDBack1 = pED;
pTDPhys = USBToHostLong(pED->GetSharedLogical()->CurrqTDPtr) & kEHCIEDTDPtrMask;
pTD = pED->qTD;
if (!pTD)
{
USBLog(6, "%s[%p]::CheckEDListForTimeouts - no TD", getName(), this);
continue;
}
if (!pTD->command)
{
USBLog(7, "%s[%p]::CheckEDListForTimeouts - found a TD without a command - moving on", getName(), this);
continue;
}
if (pTD == pED->TailTD)
{
USBLog(1, "%s[%p]::CheckEDListForTimeouts - ED (%p) - TD is TAIL but there is a command - pTD (%p)", getName(), this, pED, pTD);
pED->print(5);
}
if(pTDPhys != pTD->pPhysical)
{
USBLog(5, "%s[%p]::CheckEDListForTimeouts - pED (%p) - mismatched logical and physical - TD (%p) will be scavenged later", getName(), this, pED, pTD);
pED->print(5);
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)
{
USBLog(2, "%s[%p]::CheckEDListForTimeout - Found a TD [%p] on QH [%p] past the completion deadline, timing out! (%x - %x)", getName(), this, pTD, pED, curFrame, firstActiveFrame);
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)
{
USBLog(2, "(%p)Found a transaction which hasn't moved in 5 seconds, timing out! (%x - %x)", pTD, curFrame, pTD->lastFrame);
ReturnOneTransaction(pTD, pED, pEDBack, kIOUSBTransactionTimeout);
continue;
}
}
}
void
AppleUSBEHCI::UIMCheckForTimeouts(void)
{
AbsoluteTime currentTime;
AbsoluteTime lastRootHubChangeTime;
UInt64 elapsedTime = 0;
bool allPortsDisconnected = false;
if ( isInactive() || (_onCardBus && _pcCardEjected) || !_ehciAvailable || (_ehciBusState != kEHCIBusStateRunning))
return;
CheckEDListForTimeouts(_AsyncHead);
if ( !_idleSuspend )
{
clock_get_uptime( ¤tTime );
SUB_ABSOLUTETIME(¤tTime, &_lastCheckedTime );
absolutetime_to_nanoseconds(currentTime, &elapsedTime);
elapsedTime /= 1000000000;
if ( elapsedTime >= kEHCICheckForRootHubConnectionsPeriod )
{
USBLog(6,"%s[%p] Time to check for root hub inactivity on bus %d", getName(), this, _busNumber);
clock_get_uptime( &_lastCheckedTime );
allPortsDisconnected = RootHubAreAllPortsDisconnected();
if ( allPortsDisconnected )
{
lastRootHubChangeTime = LastRootHubPortStatusChanged( false );
clock_get_uptime( ¤tTime );
SUB_ABSOLUTETIME(¤tTime, &lastRootHubChangeTime );
absolutetime_to_nanoseconds(currentTime, &elapsedTime);
elapsedTime /= 1000000000;
if ( elapsedTime >= kEHCICheckForRootHubInactivityPeriod )
{
USBLog(5,"%s[%p] Time to suspend the ports of bus %d", getName(), this, _busNumber);
setPowerState( kEHCISetPowerLevelIdleSuspend, this);
}
}
}
}
}
#if 0
void AppleUSBEHCI::printED(AppleEHCIQueueHead * pED)
{
if(pED == NULL)
{
USBLog(7, "%s[%p]::printED: Attempt to print null ED", getName(), this);
return;
}
USBLog(5, "%s[%p]::printED: ----------------pED at %p", getName(), this, pED);
USBLog(5, "%s[%p]::printED: nextQH: %p", getName(), this, USBToHostLong(pED->GetSharedLogical()->nextQH));
USBLog(5, "%s[%p]::printED: flags: %p", getName(), this, USBToHostLong(pED->GetSharedLogical()->flags));
USBLog(5, "%s[%p]::printED: slags: %p", getName(), this, USBToHostLong(pED->GetSharedLogical()->splitFlags));
USBLog(5, "%s[%p]::printED: CurrqTD: %p", getName(), this, USBToHostLong(pED->GetSharedLogical()->CurrqTDPtr));
USBLog(5, "%s[%p]::printED: NextqTD: %p", getName(), this, USBToHostLong(pED->GetSharedLogical()->NextqTDPtr));
USBLog(5, "%s[%p]::printED: AltqTD: %p", getName(), this, USBToHostLong(pED->GetSharedLogical()->AltqTDPtr));
USBLog(5, "%s[%p]::printED: TDFlags: %p", getName(), this, USBToHostLong(pED->GetSharedLogical()->qTDFlags));
USBLog(5, "%s[%p]::printED: BuffPtr[0]: %p", getName(), this, USBToHostLong(pED->GetSharedLogical()->BuffPtr[0]));
USBLog(5, "%s[%p]::printED: pLgNext: %p", getName(), this, pED->_logicalNext);
USBLog(5, "%s[%p]::printED: pEDSharedPhys: %p", getName(), this, pED->_sharedPhysical);
USBLog(5, "%s[%p]::printED: head qTD: %p", getName(), this, pED->qTD);
USBLog(5, "%s[%p]::printED: last qTD: %p", getName(), this, pED->TailTD);
if(pED->qTD != NULL)
{
USBLog(5, "%s[%p]::printED: head qTD physical: %p", getName(), this, pED->qTD->pPhysical);
}
USBLog(5, "%s[%p]::printED: -----------------------------", getName(), this);
}
#endif