AppleUSBOHCI_UIM.cpp [plain text]
#include <libkern/OSByteOrder.h>
extern "C" {
#include <kern/clock.h>
}
#include <IOKit/IOMemoryDescriptor.h>
#include <IOKit/IOMemoryCursor.h>
#include <IOKit/usb/IOUSBLog.h>
#include "AppleUSBOHCI.h"
#include "AppleUSBOHCIMemoryBlocks.h"
#define DEBUGGING_LEVEL 0 // 1 = low; 2 = high; 3 = extreme
#define super IOUSBController
static inline OHCIEDFormat
GetEDType(AppleOHCIEndpointDescriptorPtr pED)
{
return ((USBToHostLong(pED->pShared->flags) & kOHCIEDControl_F) >> kOHCIEDControl_FPhase);
}
IOReturn
AppleUSBOHCI::CreateGeneralTransfer(
AppleOHCIEndpointDescriptorPtr queue,
IOUSBCommand* command,
IOMemoryDescriptor * CBP,
UInt32 bufferSize,
UInt32 flags,
UInt32 type,
UInt32 kickBits)
{
AppleOHCIGeneralTransferDescriptorPtr pOHCIGeneralTransferDescriptor,
newOHCIGeneralTransferDescriptor;
IOReturn status = kIOReturnSuccess;
IOPhysicalSegment physicalAddresses[2];
IOByteCount transferOffset;
UInt32 pageSize;
UInt32 pageCount;
UInt32 altFlags; IOUSBCompletion completion = command->GetUSLCompletion();
pageSize = _pageSize;
flags |= (kOHCIGTDConditionNotAccessed << kOHCIGTDControl_CCPhase);
altFlags = flags & ~kOHCIGTDControl_R;
altFlags |= ( 0x7 << kOHCIGTDControl_DIPhase );
if (USBToHostLong(queue->pShared->tdQueueHeadPtr) & kOHCIHeadPointer_H)
{
USBError(1, "%s[%p]::CreateGeneralTransfer - trying to queue to a stalled pipe", getName(), this);
status = kIOUSBPipeStalled;
}
else if (bufferSize != 0)
{
transferOffset = 0;
while (transferOffset < bufferSize)
{
if(_errataBits & kErrataOnlySinglePageTransfers)
pageCount = _genCursor->getPhysicalSegments(CBP, transferOffset, physicalAddresses, 1);
else
pageCount = _genCursor->getPhysicalSegments(CBP, transferOffset, physicalAddresses, 2);
newOHCIGeneralTransferDescriptor = AllocateTD();
if (newOHCIGeneralTransferDescriptor == NULL) {
status = kIOReturnNoMemory;
break;
}
if ((pageCount == 2) && ((((physicalAddresses[0].location + physicalAddresses[0].length) & (pageSize-1)) != 0)
|| ((physicalAddresses[1].location & (pageSize-1)) != 0)))
{
pageCount = 1; if (physicalAddresses[0].length % ((USBToHostLong(queue->pShared->flags) & kOHCIEDControl_MPS) >> kOHCIEDControl_MPSPhase) != 0)
{
USBError(1, "%s[%p] CreateGeneralTransfer: non-multiple MPS transfer required -- giving up!", getName(), this);
status = kIOReturnNoMemory;
break;
}
}
pOHCIGeneralTransferDescriptor = (AppleOHCIGeneralTransferDescriptorPtr)queue->pLogicalTailP;
OSWriteLittleInt32(&pOHCIGeneralTransferDescriptor->pShared->currentBufferPtr, 0, physicalAddresses[0].location);
OSWriteLittleInt32(&pOHCIGeneralTransferDescriptor->pShared->nextTD, 0, newOHCIGeneralTransferDescriptor->pPhysical);
if (pageCount == 2)
{
OSWriteLittleInt32(&pOHCIGeneralTransferDescriptor->pShared->bufferEnd, 0, physicalAddresses[1].location + physicalAddresses[1].length - 1);
transferOffset += physicalAddresses[1].length;
}
else
OSWriteLittleInt32(&pOHCIGeneralTransferDescriptor->pShared->bufferEnd, 0, physicalAddresses[0].location + physicalAddresses[0].length - 1);
pOHCIGeneralTransferDescriptor->pLogicalNext = newOHCIGeneralTransferDescriptor;
pOHCIGeneralTransferDescriptor->pEndpoint = queue;
pOHCIGeneralTransferDescriptor->pType = type;
pOHCIGeneralTransferDescriptor->command = command;
transferOffset += physicalAddresses[0].length;
if (transferOffset >= bufferSize)
{
pOHCIGeneralTransferDescriptor->pShared->ohciFlags = HostToUSBLong(flags);
pOHCIGeneralTransferDescriptor->uimFlags |= kUIMFlagsCallbackTD;
if (command->GetMultiTransferTransaction())
{
pOHCIGeneralTransferDescriptor->uimFlags |= kUIMFlagsMultiTDTransaction;
if (command->GetFinalTransferInTransaction())
pOHCIGeneralTransferDescriptor->uimFlags |= kUIMFlagsFinalTDinTransaction;
}
}
else
{
pOHCIGeneralTransferDescriptor->pShared->ohciFlags = HostToUSBLong(altFlags);
pOHCIGeneralTransferDescriptor->uimFlags &= ~kUIMFlagsCallbackTD; }
queue->pShared->tdQueueTailPtr = pOHCIGeneralTransferDescriptor->pShared->nextTD;
queue->pLogicalTailP = newOHCIGeneralTransferDescriptor;
OSWriteLittleInt32(&_pOHCIRegisters->hcCommandStatus, 0, kickBits);
}
}
else
{
newOHCIGeneralTransferDescriptor = AllocateTD();
if (newOHCIGeneralTransferDescriptor == NULL)
{
status = kIOReturnNoMemory;
}
else
{
pOHCIGeneralTransferDescriptor = (AppleOHCIGeneralTransferDescriptorPtr) queue->pLogicalTailP;
pOHCIGeneralTransferDescriptor->pShared->ohciFlags = HostToUSBLong(flags);
OSWriteLittleInt32(&pOHCIGeneralTransferDescriptor->pShared->nextTD, 0, newOHCIGeneralTransferDescriptor->pPhysical);
pOHCIGeneralTransferDescriptor->pLogicalNext = newOHCIGeneralTransferDescriptor;
pOHCIGeneralTransferDescriptor->pEndpoint = queue;
pOHCIGeneralTransferDescriptor->pType = type;
pOHCIGeneralTransferDescriptor->pShared->currentBufferPtr = 0;
pOHCIGeneralTransferDescriptor->pShared->bufferEnd = 0;
pOHCIGeneralTransferDescriptor->command = command;
pOHCIGeneralTransferDescriptor->uimFlags |= kUIMFlagsCallbackTD;
if (command->GetMultiTransferTransaction())
{
pOHCIGeneralTransferDescriptor->uimFlags |= kUIMFlagsMultiTDTransaction;
if (command->GetFinalTransferInTransaction())
pOHCIGeneralTransferDescriptor->uimFlags |= kUIMFlagsFinalTDinTransaction;
}
queue->pShared->tdQueueTailPtr = pOHCIGeneralTransferDescriptor->pShared->nextTD;
queue->pLogicalTailP = newOHCIGeneralTransferDescriptor;
OSWriteLittleInt32(&_pOHCIRegisters->hcCommandStatus, 0, kickBits);
}
}
#if (DEBUGGING_LEVEL > 2)
print_td(pOHCIGeneralTransferDescriptor);
#endif
if (status)
USBLog(5, "%s[%p] CreateGeneralTransfer: returning status 0x%x", getName(), this, status);
return (status);
}
IOReturn
AppleUSBOHCI::UIMCreateControlEndpoint(UInt8 functionAddress, UInt8 endpointNumber, UInt16 maxPacketSize, UInt8 speed)
{
AppleOHCIEndpointDescriptorPtr pOHCIEndpointDescriptor, pED;
USBLog(5, "%s[%p]: UIMCreateControlEndpoint( Addr: %d:%d, max=%d, %s)", getName(), this,
functionAddress, endpointNumber, maxPacketSize, (speed == kUSBDeviceSpeedLow) ? "lo" : "full");
if (_rootHubFuncAddress == functionAddress)
{
if ( (endpointNumber != 0) && (speed == kUSBDeviceSpeedLow))
{
USBLog(3,"%s[%p] UIMCreateControlEndpoint: Bad parameters endpoint: %d, speed: %s",getName(),this,endpointNumber, (speed == kUSBDeviceSpeedLow) ? "lo" : "full");
return kIOReturnBadArgument;
}
return SimulateControlEDCreate(maxPacketSize);
}
pED = _pControlHead;
if ((speed == kUSBDeviceSpeedFull) && _OptiOn)
pED = (AppleOHCIEndpointDescriptorPtr) _pBulkHead;
pOHCIEndpointDescriptor = AddEmptyEndPoint(functionAddress,
endpointNumber,
maxPacketSize,
speed,
kOHCIEDDirectionTD,
pED,
kOHCIEDFormatGeneralTD);
#if (DEBUGGING_LEVEL > 2)
if ((speed == kUSBDeviceSpeedFull) && _OptiOn)
print_bulk_list();
else
print_control_list();
#endif
if (pOHCIEndpointDescriptor == NULL)
return kIOReturnNoMemory;
return kIOReturnSuccess;
}
IOReturn
AppleUSBOHCI::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
AppleUSBOHCI::UIMCreateControlTransfer(
short functionAddress,
short endpointNumber,
IOUSBCommand* command,
IOMemoryDescriptor* CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction)
{
UInt32 myBufferRounding = 0;
UInt32 myDirection;
UInt32 myToggle;
AppleOHCIEndpointDescriptorPtr pEDQueue, pEDDummy;
IOReturn status;
IOUSBCompletion completion = command->GetUSLCompletion();
USBLog(7, "%s[%p]\tCrntlTx: 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)
{
direction = kOHCIGTDPIDOut;
}
else if (direction == kUSBIn)
{
direction = kOHCIGTDPIDIn;
}
else
{
direction = kOHCIGTDPIDSetup;
}
pEDQueue = FindControlEndpoint(functionAddress, endpointNumber, &pEDDummy);
if (pEDQueue == NULL)
{
USBLog(3, "%s[%p] UIMCreateControlTransfer- Could not find endpoint (FN: %d, EP: %d)!", getName(), this, functionAddress, endpointNumber);
return(kIOUSBEndpointNotFound);
}
if (bufferRounding)
myBufferRounding = kOHCIGTDControl_R;
myDirection = (UInt32) direction << kOHCIDirectionOffset;
myToggle = kOHCIBit25;
if (direction != 0)
{
myToggle |= kOHCIBit24;
}
status = CreateGeneralTransfer(pEDQueue, command, CBP, bufferSize, myBufferRounding | myDirection | myToggle, kOHCIControlSetupType, kOHCIHcCommandStatus_CLF);
return (status);
}
IOReturn
AppleUSBOHCI::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;
}
IOReturn
AppleUSBOHCI::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(1, "%s[%p]UIMCreateControlTransfer- calling the pointer method instead of the desc method!", getName(), this);
return kIOReturnIPCError;
}
IOReturn AppleUSBOHCI::UIMCreateBulkEndpoint(
UInt8 functionAddress,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt8 maxPacketSize)
{
AppleOHCIEndpointDescriptorPtr pOHCIEndpointDescriptor, pED;
USBLog(5,"%s[%p]: UIMCreateBulkEndpoint(Addr=%d:%d, max=%d, dir=%d, %s)", getName(), this,
functionAddress, endpointNumber, maxPacketSize, direction, (speed == kUSBDeviceSpeedLow) ? "lo" : "full");
if (direction == kUSBOut)
direction = kOHCIEDDirectionOut;
else if (direction == kUSBIn)
direction = kOHCIEDDirectionIn;
else
direction = kOHCIEDDirectionTD;
pED = (AppleOHCIEndpointDescriptorPtr) _pBulkHead;
pOHCIEndpointDescriptor = AddEmptyEndPoint (functionAddress,
endpointNumber,
maxPacketSize,
speed,
direction,
pED,
kOHCIEDFormatGeneralTD);
if (pOHCIEndpointDescriptor == NULL)
return(kIOReturnNoMemory);
return (kIOReturnSuccess);
}
IOReturn
AppleUSBOHCI::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;
}
IOReturn
AppleUSBOHCI::UIMCreateBulkTransfer(IOUSBCommand* command)
{
IOReturn status = kIOReturnSuccess;
UInt32 myBufferRounding = 0;
UInt32 TDDirection;
UInt32 kickBits;
AppleOHCIEndpointDescriptorPtr pEDQueue, pEDDummy;
IOUSBCompletion completion = command->GetUSLCompletion();
short direction = command->GetDirection();
IOMemoryDescriptor* buffer = command->GetBuffer();
USBLog(7, "%s[%p]\tBulkTx: adr=%d:%d cbp=%lx:%x br=%s cback=[%lx:%lx:%lx] dir=%d)",getName(),this,
command->GetAddress(), command->GetEndpoint(), (UInt32)buffer, command->GetReqCount(), command->GetBufferRounding() ?"YES":"NO",
(UInt32)completion.action, (UInt32)completion.target, (UInt32)completion.parameter, direction);
if (direction == kUSBOut)
direction = kOHCIEDDirectionOut;
else if (direction == kUSBIn)
direction = kOHCIEDDirectionIn;
else
direction = kOHCIEDDirectionTD;
pEDQueue = FindBulkEndpoint(command->GetAddress(), command->GetEndpoint(), direction, &pEDDummy);
if (!pEDQueue)
{
USBLog(3, "%s[%p] UIMCreateBulkTransfer- Could not find endpoint!", getName(), this);
return (kIOUSBEndpointNotFound);
}
if (command->GetBufferRounding())
myBufferRounding = kOHCIGTDControl_R;
TDDirection = (UInt32) direction << kOHCIDirectionOffset;
kickBits = kOHCIHcCommandStatus_BLF;
if ( _OptiOn)
kickBits |= kOHCIHcCommandStatus_CLF;
status = CreateGeneralTransfer(pEDQueue, command, buffer, command->GetReqCount(), myBufferRounding | TDDirection, kOHCIBulkTransferOutType, kickBits);
return (status);
}
IOReturn
AppleUSBOHCI::UIMCreateInterruptEndpoint(
short functionAddress,
short endpointNumber,
UInt8 direction,
short speed,
UInt16 maxPacketSize,
short pollingRate)
{
AppleOHCIEndpointDescriptorPtr pOHCIEndpointDescriptor;
AppleOHCIEndpointDescriptorPtr pED;
int offset;
USBLog(5, "%s[%p]: UIMCreateInterruptEndpoint ( Addr: %d:%d, max=%d, dir=%d, rate=%d, %s)", getName(), this,
functionAddress, endpointNumber, maxPacketSize,direction,
pollingRate, (speed == kUSBDeviceSpeedLow) ? "lo" : "full");
if (_rootHubFuncAddress == functionAddress)
{
if ( (endpointNumber != 1) || ( speed != kUSBDeviceSpeedFull ) || (direction != kUSBIn) )
{
USBLog(3, "%s[%p]: UIMCreateInterruptEndpoint bad parameters: endpNumber %d, speed: %s, direction: %d",getName(), this, endpointNumber, (speed == kUSBDeviceSpeedLow) ? "lo" : "full", direction);
return kIOReturnBadArgument;
}
return SimulateInterruptEDCreate(maxPacketSize, pollingRate);
}
if (direction == kUSBOut)
direction = kOHCIEDDirectionOut;
else if (direction == kUSBIn)
direction = kOHCIEDDirectionIn;
else
direction = kOHCIEDDirectionTD;
if (_OptiOn)
if (speed == kUSBDeviceSpeedFull)
if (pollingRate >= 8)
pollingRate = 7;
if (DetermineInterruptOffset(pollingRate, maxPacketSize, &offset) == false)
return(kIOReturnNoBandwidth);
USBLog(6, "%s[%p]: UIMCreateInterruptEndpoint: offset = %d", getName(), this, offset);
pED = (AppleOHCIEndpointDescriptorPtr) _pInterruptHead[offset].pHead;
pOHCIEndpointDescriptor = AddEmptyEndPoint (functionAddress, endpointNumber,
maxPacketSize, speed, direction, pED, kOHCIEDFormatGeneralTD);
if (NULL == pOHCIEndpointDescriptor)
return(-1);
_pInterruptHead[offset].nodeBandwidth += maxPacketSize;
#if (DEBUGGING_LEVEL > 2)
print_int_list();
#endif
return (kIOReturnSuccess);
}
IOReturn
AppleUSBOHCI::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;
}
IOReturn
AppleUSBOHCI::UIMCreateInterruptTransfer(IOUSBCommand* command)
{
IOReturn status = kIOReturnSuccess;
UInt32 myBufferRounding = 0;
UInt32 myDirection;
UInt32 myToggle;
AppleOHCIEndpointDescriptorPtr pEDQueue, temp;
IOUSBCompletion completion = command->GetUSLCompletion();
IOMemoryDescriptor* buffer = command->GetBuffer();
short direction = command->GetDirection();
USBLog(7, "%s[%p]\tIntTx: adr=%d:%d cbp=%p:%lx br=%s cback=[%lx:%lx:%lx])", getName(), this,
command->GetAddress(), command->GetEndpoint(), command->GetBuffer(),
command->GetReqCount(), command->GetBufferRounding()?"YES":"NO",
(UInt32)completion.action, (UInt32)completion.target,
(UInt32)completion.parameter);
if (_rootHubFuncAddress == command->GetAddress())
{
SimulateRootHubInt(command->GetEndpoint(), buffer, command->GetReqCount(), completion);
return(kIOReturnSuccess);
}
if (direction == kUSBOut)
direction = kOHCIEDDirectionOut;
else if (direction == kUSBIn)
direction = kOHCIEDDirectionIn;
else
direction = kOHCIEDDirectionTD;
pEDQueue = FindInterruptEndpoint(command->GetAddress(), command->GetEndpoint(), direction, &temp);
if (pEDQueue != NULL)
{
if (command->GetBufferRounding())
myBufferRounding = kOHCIGTDControl_R;
myToggle = 0;
myDirection = (UInt32) direction << kOHCIDirectionOffset;
status = CreateGeneralTransfer(pEDQueue, command, buffer, command->GetReqCount(), myBufferRounding | myDirection | myToggle, kOHCIInterruptInType, 0);
}
else
{
USBLog(3, "%s[%p] UIMCreateInterruptTransfer- Could not find endpoint!", getName(), this);
status = kIOUSBEndpointNotFound;
}
return (status);
}
IOReturn
AppleUSBOHCI::UIMCreateIsochEndpoint(
short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction)
{
AppleOHCIEndpointDescriptorPtr pOHCIEndpointDescriptor, pED;
UInt32 curMaxPacketSize;
UInt32 xtraRequest;
UInt32 edFlags;
if (direction == kUSBOut)
direction = kOHCIEDDirectionOut;
else if (direction == kUSBIn)
direction = kOHCIEDDirectionIn;
else
direction = kOHCIEDDirectionTD;
pED = FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL);
if (pED) {
USBLog(2,"%s[%p]::UIMCreateIsochEndpoint endpoint already exists, changing maxPacketSize to %d",getName(), this, maxPacketSize);
edFlags = USBToHostLong(pED->pShared->flags);
curMaxPacketSize = ( edFlags & kOHCIEDControl_MPS) >> kOHCIEDControl_MPSPhase;
if (maxPacketSize == curMaxPacketSize)
{
USBLog(2,"%s[%p]::UIMCreateIsochEndpoint maxPacketSize (%d) the same, no change",getName(), this, maxPacketSize);
return kIOReturnSuccess;
}
if (maxPacketSize > curMaxPacketSize)
{
xtraRequest = maxPacketSize - curMaxPacketSize;
if (xtraRequest > _isochBandwidthAvail)
{
USBLog(2,"%s[%p]::UIMCreateIsochEndpoint out of bandwidth, request (extra) = %d, available: %d",getName(), this, xtraRequest, _isochBandwidthAvail);
return kIOReturnNoBandwidth;
}
_isochBandwidthAvail -= xtraRequest;
USBLog(2,"%s[%p]::UIMCreateIsochEndpoint grabbing additional bandwidth: %d, new available: %d",getName(), this, xtraRequest, _isochBandwidthAvail);
} else
{
xtraRequest = curMaxPacketSize - maxPacketSize;
_isochBandwidthAvail += xtraRequest;
USBLog(2,"%s[%p]::UIMCreateIsochEndpoint returning some bandwidth: %d, new available: %d",getName(), this, xtraRequest, _isochBandwidthAvail);
}
edFlags &= ~kOHCIEDControl_MPS; edFlags |= (maxPacketSize << kOHCIEDControl_MPSPhase);
OSWriteLittleInt32(&pED->pShared->flags, 0, edFlags);
return kIOReturnSuccess;
}
if (maxPacketSize > _isochBandwidthAvail)
{
USBLog(3,"%s[%p]::UIMCreateIsochEndpoint out of bandwidth, request (extra) = %d, available: %d",getName(), this, maxPacketSize, _isochBandwidthAvail);
return kIOReturnNoBandwidth;
}
_isochBandwidthAvail -= maxPacketSize;
pED = _pIsochHead;
pOHCIEndpointDescriptor = AddEmptyEndPoint(functionAddress, endpointNumber,
maxPacketSize, kUSBDeviceSpeedFull, direction, pED, kOHCIEDFormatIsochronousTD);
if (pOHCIEndpointDescriptor == NULL) {
_isochBandwidthAvail += maxPacketSize;
return(kIOReturnNoMemory);
}
USBLog(5,"%s[%p]::UIMCreateIsochEndpoint success. bandwidth used = %d, new available: %d",getName(), this, maxPacketSize, _isochBandwidthAvail);
return kIOReturnSuccess;
}
IOReturn
AppleUSBOHCI::UIMCreateIsochTransfer(
short functionAddress,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameNumberStart,
IOMemoryDescriptor * pBuffer,
UInt32 frameCount,
IOUSBIsocFrame *pFrames)
{
IOReturn status = kIOReturnSuccess;
AppleOHCIIsochTransferDescriptorPtr pTailITD = NULL;
AppleOHCIIsochTransferDescriptorPtr pNewITD = NULL;
AppleOHCIIsochTransferDescriptorPtr pTempITD = NULL;
UInt32 i;
UInt32 curFrameInRequest = 0;
UInt32 bufferSize = 0;
UInt32 pageOffset = 0;
UInt32 prevFramesPage = 0;
UInt32 lastPhysical = 0;
UInt32 segmentEnd = 0;
AppleOHCIEndpointDescriptorPtr pED;
UInt32 curFrameInTD = 0;
UInt16 frameNumber = (UInt16) frameNumberStart;
UInt64 curFrameNumber = GetFrameNumber();
UInt64 frameDiff;
UInt64 maxOffset = (UInt64)(0x00007FF0);
UInt32 diff32;
UInt32 itdFlags = 0;
UInt32 numSegs = 0;
UInt32 physPageStart = 0;
UInt32 physPageEnd = 0;
UInt32 pageSelectMask = 0;
bool needNewITD;
bool multiPageSegment = false;
IOPhysicalSegment segs[2];
UInt32 tdType;
IOByteCount transferOffset;
if ( (frameCount == 0) || (frameCount > 1000) )
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer bad frameCount: %d",getName(), this, frameCount);
return kIOReturnBadArgument;
}
if (direction == kUSBOut) {
direction = kOHCIEDDirectionOut;
tdType = kOHCIIsochronousOutType;
}
else if (direction == kUSBIn) {
direction = kOHCIEDDirectionIn;
tdType = kOHCIIsochronousInType;
}
else
return kIOReturnInternalError;
pED = FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL);
if (!pED)
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer endpoint (%d) not found: 0x%x",getName(), this, endpointNumber, kIOUSBEndpointNotFound);
return kIOUSBEndpointNotFound;
}
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, pED->pLogicalTailP);
} 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);
}
}
for ( i = 0; i< frameCount; i++)
{
if (pFrames[i].frReqCount > kUSBMaxIsocFrameReqCount)
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer Isoch frame too big %d",getName(), this, pFrames[i].frReqCount);
return kIOReturnBadArgument;
}
bufferSize += pFrames[i].frReqCount;
}
USBLog(7,"%s[%p]::UIMCreateIsochTransfer transfer %s, buffer: %p, length: %d",getName(), this, (direction == kOHCIEDDirectionIn) ? "in" : "out", pBuffer, bufferSize);
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;
}
if (!bufferSize) {
numSegs = 1;
segs[0].location = segs[0].length = 0;
pageOffset = 0;
}
pTailITD = (AppleOHCIIsochTransferDescriptorPtr)pED->pLogicalTailP; OSWriteLittleInt32(&pTailITD->pShared->nextTD, 0, pNewITD->pPhysical); pTailITD->pLogicalNext = pNewITD;
needNewITD = false;
transferOffset = 0;
while (curFrameInRequest < frameCount)
{
if(!needNewITD && bufferSize)
{
numSegs = _isoCursor->getPhysicalSegments(pBuffer, transferOffset, segs, 2, pFrames[curFrameInRequest].frReqCount);
pageOffset = segs[0].location & kOHCIPageOffsetMask;
transferOffset += segs[0].length;
segmentEnd = (segs[0].location + segs[0].length ) & kOHCIPageOffsetMask;
USBLog(8,"curFrameInRequest: %d, curFrameInTD: %d, pageOffset: %x, numSegs: %d, seg[0].location: %p, seg[0].length: %d", curFrameInRequest, curFrameInTD, pageOffset, numSegs, segs[0].location, segs[0].length);
if(numSegs == 2)
{
transferOffset += segs[1].length;
USBLog(8 ,"seg[1].location: %p, seg[1].length %d",segs[1].location, segs[1].length);
}
if ( (segs[numSegs-1].location & kOHCIPageMask) != ((segs[numSegs-1].location + segs[numSegs-1].length) & kOHCIPageMask))
{
multiPageSegment = true;
USBLog(8,"We have a segment that crosses a page boundary: start: %p, length: %d, end: %p, curFrameinTD: %d", segs[numSegs-1].location, segs[numSegs-1].length,segs[numSegs-1].location + segs[numSegs-1].length, curFrameInTD);
}
else
multiPageSegment = false;
}
if (curFrameInTD == 0)
{
physPageStart = segs[0].location & kOHCIPageMask; pageSelectMask = 0; needNewITD = false;
itdFlags = (UInt16)(curFrameInRequest + frameNumber);
pTailITD->pIsocFrame = pFrames; pTailITD->frameNum = curFrameInRequest; pTailITD->pType = tdType; OSWriteLittleInt32(&pTailITD->pShared->bufferPage0, 0, physPageStart);
}
else if ((segs[0].location & kOHCIPageMask) != physPageStart)
{
if ( (pageSelectMask && (((segs[0].location & kOHCIPageMask) != physPageEnd) || numSegs == 2)) )
{
needNewITD = true;
USBLog(8, "%s[%p]::UIMCreateIsochTransfer - got it! (%d, %p, %p, %d)", getName(), this, pageSelectMask, segs[0].location & kOHCIPageMask, physPageEnd, numSegs);
}
else if ( pageSelectMask && multiPageSegment )
{
needNewITD = true;
USBLog(8,"%s[%p]::UIMCreateIsochTransfer This frame spans 2 or more pages and we already used our page crossing ",getName(), this);
}
else if ( (prevFramesPage != (segs[0].location & kOHCIPageMask)) && (segmentEnd != 0) )
{
needNewITD = true;
USBLog(8,"%s[%p]::UIMCreateIsochTransfer This frame starts on a new page and the previous one did NOT end on a page boundary (%d)",getName(), this, segmentEnd);
}
else
{
if (pageSelectMask == 0 )
USBLog(8,"Using our page crossing for this TD (%p)",(segs[numSegs-1].location + segs[numSegs-1].length -1 ) & kOHCIPageMask);
pageSelectMask = kOHCIPageSize; physPageEnd = (segs[numSegs-1].location + segs[numSegs-1].length) & kOHCIPageMask;
}
}
prevFramesPage = (segs[numSegs-1].location + segs[numSegs-1].length) & kOHCIPageMask;
if ((curFrameInTD > 7) || needNewITD)
{
needNewITD = true; itdFlags |= (curFrameInTD-1) << kOHCIITDControl_FCPhase;
OSWriteLittleInt32(&pTailITD->pShared->bufferEnd, 0, lastPhysical);
curFrameInTD = 0;
pNewITD = AllocateITD();
USBLog(7, "%s[%p]::UIMCreateIsochTransfer - new iTD %p", getName(), this, pNewITD);
if (pNewITD == NULL)
{
status = kIOReturnNoMemory;
break;
}
itdFlags |= (kOHCIGTDConditionNotAccessed << kOHCIGTDControl_CCPhase);
itdFlags |= ( 0x7 << kOHCIGTDControl_DIPhase );
OSWriteLittleInt32(&pTailITD->pShared->flags, 0, itdFlags);
pTailITD->completion.action = NULL;
pTailITD = pTailITD->pLogicalNext; OSWriteLittleInt32(&pTailITD->pShared->nextTD, 0, pNewITD->pPhysical); pTailITD->pLogicalNext = pNewITD;
continue; }
OSWriteLittleInt16(&pTailITD->pShared->offset[curFrameInTD], 0,
pageOffset | pageSelectMask | (kOHCIITDOffsetConditionNotAccessed << kOHCIITDOffset_CCPhase));
curFrameInRequest++;
curFrameInTD++;
lastPhysical = segs[numSegs-1].location + segs[numSegs-1].length - 1;
}
if (status != kIOReturnSuccess)
{
pNewITD = pTailITD->pLogicalNext; pTempITD = (AppleOHCIIsochTransferDescriptorPtr)pED->pLogicalTailP;
pTailITD = pTempITD->pLogicalNext; pTempITD->pLogicalNext = NULL; pTempITD->pShared->nextTD = NULL; while (pTailITD != pNewITD)
{
pTempITD = pTailITD;
pTailITD = pTailITD->pLogicalNext;
DeallocateITD(pTempITD);
}
}
else
{
itdFlags |= (curFrameInTD-1) << kOHCIITDControl_FCPhase;
OSWriteLittleInt32(&pTailITD->pShared->flags, 0, itdFlags);
OSWriteLittleInt32(&pTailITD->pShared->bufferEnd, 0, lastPhysical);
pTailITD->completion = completion;
pED->pLogicalTailP = pNewITD;
OSWriteLittleInt32(&pED->pShared->tdQueueTailPtr, 0, pNewITD->pPhysical);
}
return status;
}
IOReturn
AppleUSBOHCI::UIMAbortEndpoint(
short functionAddress,
short endpointNumber,
short direction)
{
AppleOHCIEndpointDescriptorPtr pED;
AppleOHCIEndpointDescriptorPtr pEDQueueBack;
UInt32 something, controlMask;
USBLog(5, "%s[%p] UIMAbortEndpoint: Addr: %d, Endpoint: %d,%d", getName(), this, functionAddress,endpointNumber,direction);
if (functionAddress == _rootHubFuncAddress)
{
if ( (endpointNumber != 1) && (endpointNumber != 0) )
{
USBLog(1, "%s[%p] UIMAbortEndpoint: bad params - endpNumber: %d", getName(), this, endpointNumber );
return kIOReturnBadArgument;
}
USBLog(5, "%s[%p] UIMAbortEndpoint: Attempting operation on root hub", getName(), this);
return SimulateEDAbort(endpointNumber, direction);
}
if (direction == kUSBOut)
direction = kOHCIEDDirectionOut;
else if (direction == kUSBIn)
direction = kOHCIEDDirectionIn;
else
direction = kOHCIEDDirectionTD;
pED = FindEndpoint (functionAddress, endpointNumber, direction, &pEDQueueBack, &controlMask);
if (!pED)
{
USBLog(3, "%s[%p] UIMAbortEndpoint- Could not find endpoint!", getName(), this);
return (kIOUSBEndpointNotFound);
}
pED->pShared->flags |= HostToUSBLong(kOHCIEDControl_K);
IOSleep(1);
RemoveTDs(pED);
pED->pShared->flags &= ~HostToUSBLong(kOHCIEDControl_K);
return (kIOReturnSuccess);
}
IOReturn
AppleUSBOHCI::UIMDeleteEndpoint(
short functionAddress,
short endpointNumber,
short direction)
{
AppleOHCIEndpointDescriptorPtr pED;
AppleOHCIEndpointDescriptorPtr pEDQueueBack;
UInt32 hcControl;
UInt32 something, controlMask;
USBLog(5, "%s[%p] 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);
}
if (direction == kUSBOut)
direction = kOHCIEDDirectionOut;
else if (direction == kUSBIn)
direction = kOHCIEDDirectionIn;
else
direction = kOHCIEDDirectionTD;
pED = FindEndpoint (functionAddress,
endpointNumber,
direction,
&pEDQueueBack,
&controlMask);
if (!pED)
{
USBLog(3, "%s[%p] UIMDeleteEndpoint- Could not find endpoint!", getName(), this);
return (kIOUSBEndpointNotFound);
}
pED->pShared->flags |= HostToUSBLong(kOHCIEDControl_K);
pEDQueueBack->pShared->nextED = pED->pShared->nextED;
pEDQueueBack->pLogicalNext = pED->pLogicalNext;
hcControl = USBToHostLong(_pOHCIRegisters->hcControl);
hcControl &= ~controlMask;
hcControl &= OHCIBitRange(0, 10);
_pOHCIRegisters->hcControl = HostToUSBLong(hcControl);
IOSleep(1);
hcControl |= controlMask;
_pOHCIRegisters->hcControl = HostToUSBLong(hcControl);
USBLog(5, "%s[%p]::UIMDeleteEndpoint", getName(), this);
if (GetEDType(pED) == kOHCIEDFormatIsochronousTD)
{
UInt32 maxPacketSize = (USBToHostLong(pED->pShared->flags) & kOHCIEDControl_MPS) >> kOHCIEDControl_MPSPhase;
_isochBandwidthAvail += maxPacketSize;
USBLog(5, "%s[%p]::UIMDeleteEndpoint (Isoch) - bandwidth returned %d, new available: %d", getName(), this, maxPacketSize, _isochBandwidthAvail);
}
RemoveAllTDs(pED);
pED->pShared->nextED = NULL;
DeallocateED(pED);
#if (DEBUGGING_LEVEL > 2)
print_bulk_list();
print_control_list();
#endif
return (kIOReturnSuccess);
}
IOReturn
AppleUSBOHCI::UIMClearEndpointStall(
short functionAddress,
short endpointNumber,
short direction)
{
AppleOHCIEndpointDescriptorPtr pEDQueueBack, pED;
AppleOHCIGeneralTransferDescriptorPtr transaction;
UInt32 tail, controlMask;
USBLog(5, "+%s[%p]: clearing endpoint %d:%d stall", getName(), this, functionAddress, endpointNumber);
if (_rootHubFuncAddress == functionAddress)
{
if ( (endpointNumber != 1) && (endpointNumber != 0) )
{
USBLog(1, "%s[%p] UIMClearEndpointStall: bad params - endpNumber: %d", getName(), this, endpointNumber );
return kIOReturnBadArgument;
}
USBLog(5, "%s[%p] UIMClearEndpointStall: Attempting operation on root hub", getName(), this);
return SimulateEDClearStall(endpointNumber, direction);
}
if (direction == kUSBOut)
direction = kOHCIEDDirectionOut;
else if (direction == kUSBIn)
direction = kOHCIEDDirectionIn;
else
direction = kOHCIEDDirectionTD;
transaction = NULL;
tail = NULL;
pED = FindEndpoint (functionAddress, endpointNumber, direction, &pEDQueueBack, &controlMask);
if (!pED)
{
USBLog(3, "%s[%p] UIMClearEndpointStall- Could not find endpoint!", getName(), this);
return (kIOUSBEndpointNotFound);
}
if (pED != NULL)
{
tail = USBToHostLong(pED->pShared->tdQueueTailPtr);
transaction = AppleUSBOHCIgtdMemoryBlock::GetGTDFromPhysical(USBToHostLong(pED->pShared->tdQueueHeadPtr) & kOHCIHeadPMask);
pED->pShared->tdQueueHeadPtr = pED->pShared->tdQueueTailPtr;
pED->pLogicalHeadP = pED->pLogicalTailP;
}
if (transaction != NULL)
{
ReturnTransactions(transaction, tail);
}
USBLog(5, "-%s[%p]: clearing endpoint %d:%d stall", getName(), this, functionAddress, endpointNumber);
return (kIOReturnSuccess);
}
AppleOHCIEndpointDescriptorPtr
AppleUSBOHCI::AddEmptyEndPoint(
UInt8 functionAddress,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed,
UInt8 direction,
AppleOHCIEndpointDescriptorPtr pED,
OHCIEDFormat format)
{
UInt32 myFunctionAddress,
myEndpointNumber,
myEndpointDirection,
myMaxPacketSize,
mySpeed,
myFormat;
AppleOHCIEndpointDescriptorPtr pOHCIEndpointDescriptor;
AppleOHCIGeneralTransferDescriptorPtr pOHCIGeneralTransferDescriptor;
AppleOHCIIsochTransferDescriptorPtr pITD;
pOHCIEndpointDescriptor = (AppleOHCIEndpointDescriptorPtr) AllocateED();
myFunctionAddress = ((UInt32) functionAddress) << kOHCIEDControl_FAPhase;
myEndpointNumber = ((UInt32) endpointNumber) << kOHCIEDControl_ENPhase;
myEndpointDirection = ((UInt32) direction) << kOHCIEDControl_DPhase;
if (speed == kUSBDeviceSpeedFull)
mySpeed = kOHCIEDSpeedFull << kOHCIEDControl_SPhase;
else
mySpeed = kOHCIEDSpeedLow << kOHCIEDControl_SPhase;
myMaxPacketSize = ((UInt32) maxPacketSize) << kOHCIEDControl_MPSPhase;
myFormat = ((UInt32) format) << kOHCIEDControl_FPhase;
pOHCIEndpointDescriptor->pShared->flags = HostToUSBLong(myFunctionAddress
| myEndpointNumber
| myEndpointDirection
| myMaxPacketSize
| mySpeed
| myFormat);
if (format == kOHCIEDFormatGeneralTD)
{
pOHCIGeneralTransferDescriptor = AllocateTD();
if (pOHCIGeneralTransferDescriptor == NULL)
{
return NULL;
}
pOHCIEndpointDescriptor->pShared->tdQueueTailPtr = HostToUSBLong( pOHCIGeneralTransferDescriptor->pPhysical);
pOHCIEndpointDescriptor->pShared->tdQueueHeadPtr = HostToUSBLong( pOHCIGeneralTransferDescriptor->pPhysical);
pOHCIEndpointDescriptor->pLogicalTailP = pOHCIGeneralTransferDescriptor;
pOHCIEndpointDescriptor->pLogicalHeadP = pOHCIGeneralTransferDescriptor;
}
else
{
pITD = AllocateITD();
if (pITD == NULL)
{
return NULL;
}
pOHCIEndpointDescriptor->pShared->tdQueueTailPtr = HostToUSBLong( pITD->pPhysical);
pOHCIEndpointDescriptor->pShared->tdQueueHeadPtr = HostToUSBLong( pITD->pPhysical);
pOHCIEndpointDescriptor->pLogicalTailP = pITD;
pOHCIEndpointDescriptor->pLogicalHeadP = pITD;
}
pOHCIEndpointDescriptor->pShared->nextED = pED->pShared->nextED;
pOHCIEndpointDescriptor->pLogicalNext = pED->pLogicalNext;
pED->pLogicalNext = pOHCIEndpointDescriptor;
pED->pShared->nextED = HostToUSBLong(pOHCIEndpointDescriptor->pPhysical);
return (pOHCIEndpointDescriptor);
}
AppleOHCIEndpointDescriptorPtr
AppleUSBOHCI::FindControlEndpoint (
short functionNumber,
short endpointNumber,
AppleOHCIEndpointDescriptorPtr *pEDBack)
{
UInt32 unique;
AppleOHCIEndpointDescriptorPtr pEDQueue;
AppleOHCIEndpointDescriptorPtr pEDQueueBack;
unique = (UInt32) ((((UInt32) endpointNumber) << kOHCIEndpointNumberOffset) | ((UInt32) functionNumber));
pEDQueueBack = _pControlHead;
pEDQueue = pEDQueueBack->pLogicalNext;
while (pEDQueue != _pControlTail)
{
if ((USBToHostLong(pEDQueue->pShared->flags) & kUniqueNumNoDirMask) == unique)
{
*pEDBack = pEDQueueBack;
return (pEDQueue);
}
else
{
pEDQueueBack = pEDQueue;
pEDQueue = (AppleOHCIEndpointDescriptorPtr) pEDQueue->pLogicalNext;
}
}
if (_OptiOn)
{
pEDQueue = FindBulkEndpoint (functionNumber, endpointNumber, kOHCIEDDirectionTD, &pEDQueueBack);
*pEDBack = pEDQueueBack;
return (pEDQueue);
}
return NULL;
}
AppleOHCIEndpointDescriptorPtr
AppleUSBOHCI::FindBulkEndpoint (
short functionNumber,
short endpointNumber,
short direction,
AppleOHCIEndpointDescriptorPtr *pEDBack)
{
UInt32 unique;
UInt32 myEndpointDirection;
AppleOHCIEndpointDescriptorPtr pEDQueue;
AppleOHCIEndpointDescriptorPtr pEDQueueBack;
myEndpointDirection = ((UInt32) direction) << kOHCIEndpointDirectionOffset;
unique = (UInt32) ((((UInt32) endpointNumber) << kOHCIEndpointNumberOffset)
| ((UInt32) functionNumber) | myEndpointDirection);
pEDQueueBack = (AppleOHCIEndpointDescriptorPtr) _pBulkHead;
pEDQueue = pEDQueueBack->pLogicalNext;
while ( pEDQueue != _pBulkTail )
{
if ((USBToHostLong(pEDQueue->pShared->flags) & kUniqueNumMask) == unique)
{
*pEDBack = pEDQueueBack;
return (pEDQueue);
}
else
{
pEDQueueBack = pEDQueue;
pEDQueue = pEDQueue->pLogicalNext;
}
}
return NULL;
}
AppleOHCIEndpointDescriptorPtr
AppleUSBOHCI::FindEndpoint (
short functionNumber,
short endpointNumber,
short direction,
AppleOHCIEndpointDescriptorPtr *pEDQueueBack,
UInt32 *controlMask)
{
AppleOHCIEndpointDescriptorPtr pED, pEDBack;
pED = FindControlEndpoint (functionNumber, endpointNumber, &pEDBack);
if (pED != NULL)
{
*pEDQueueBack = pEDBack;
*controlMask = kOHCIHcControl_CLE;
return (pED);
}
pED = FindBulkEndpoint(functionNumber, endpointNumber, direction, &pEDBack);
if (pED != NULL)
{
*pEDQueueBack = pEDBack;
*controlMask = kOHCIHcControl_BLE;
if(_OptiOn)
*controlMask = kOHCIHcControl_CLE;
return (pED);
}
pED = FindInterruptEndpoint(functionNumber, endpointNumber, direction,
&pEDBack);
if (pED != NULL)
{
*pEDQueueBack = pEDBack;
*controlMask = 0;
return (pED);
}
pED = FindIsochronousEndpoint(functionNumber, endpointNumber,
direction, &pEDBack);
*pEDQueueBack = pEDBack;
*controlMask = 0;
return (pED);
}
AppleOHCIEndpointDescriptorPtr
AppleUSBOHCI::FindIsochronousEndpoint(
short functionNumber,
short endpointNumber,
short direction,
AppleOHCIEndpointDescriptorPtr *pEDBack)
{
UInt32 myEndpointDirection;
UInt32 unique;
AppleOHCIEndpointDescriptorPtr pEDQueue, pEDQueueBack;
myEndpointDirection = ((UInt32) direction) << kOHCIEndpointDirectionOffset;
unique = (UInt32) ((((UInt32) endpointNumber) << kOHCIEndpointNumberOffset)
| ((UInt32) functionNumber) | myEndpointDirection);
pEDQueueBack = (AppleOHCIEndpointDescriptorPtr) _pIsochHead;
pEDQueue = pEDQueueBack->pLogicalNext;
while (pEDQueue != _pIsochTail )
{
if ((USBToHostLong(pEDQueue->pShared->flags) & kUniqueNumMask) == unique)
{
if(pEDBack)
*pEDBack = pEDQueueBack;
return (pEDQueue);
}
else
{
pEDQueueBack = pEDQueue;
pEDQueue = pEDQueue->pLogicalNext;
}
}
return NULL;
}
AppleOHCIEndpointDescriptorPtr
AppleUSBOHCI::FindInterruptEndpoint(
short functionNumber,
short endpointNumber,
short direction,
AppleOHCIEndpointDescriptorPtr *pEDBack)
{
UInt32 myEndpointDirection;
UInt32 unique;
AppleOHCIEndpointDescriptorPtr pEDQueue;
int i;
UInt32 temp;
myEndpointDirection = ((UInt32) direction) << kOHCIEndpointDirectionOffset;
unique = (UInt32) ((((UInt32) endpointNumber) << kOHCIEDControl_ENPhase)
| (((UInt32) functionNumber) << kOHCIEDControl_FAPhase)
| myEndpointDirection);
for (i = 0; i < 63; i++)
{
pEDQueue = _pInterruptHead[i].pHead;
*pEDBack = pEDQueue;
pEDQueue = pEDQueue->pLogicalNext;
while (pEDQueue != _pInterruptHead[i].pTail)
{
temp = (USBToHostLong(pEDQueue->pShared->flags)) & kUniqueNumMask;
if ( temp == unique)
{
return(pEDQueue);
}
*pEDBack = pEDQueue;
pEDQueue = pEDQueue->pLogicalNext;
}
}
return NULL;
}
bool AppleUSBOHCI::DetermineInterruptOffset(
UInt32 pollingRate,
UInt32 ,
int *offset)
{
int num;
num = USBToHostLong(_pOHCIRegisters->hcFmNumber) & kOHCIFmNumberMask;
if (pollingRate < 1)
{
USBError(1,"%s[%p]::DetermineInterruptOffset pollingRate of 0 -- that's illegal!", getName(), this);
return(false);
}
else if(pollingRate < 2)
*offset = 62;
else if(pollingRate < 4)
*offset = (num%2) + 60;
else if(pollingRate < 8)
*offset = (num%4) + 56;
else if(pollingRate < 16)
*offset = (num%8) + 48;
else if(pollingRate < 32)
*offset = (num%16) + 32;
else
*offset = (num%32) + 0;
return (true);
}
#if (DEBUGGING_LEVEL > 2)
static char *cc_errors[] = {
"NO ERROR",
"CRC",
"BIT STUFFING",
"DATA TOGGLE MISMATCH",
"STALL",
"DEVICE NOT RESPONDING",
"PID CHECK FAILURE",
"UNEXPECTED PID",
"DATA OVERRUN",
"DATA UNDERRUN",
"??",
"??",
"BUFFER OVERRUN",
"BUFFER UNDERRUN",
"NOT ACCESSED A",
"NOT ACCESSED B"
};
void
AppleUSBOHCI::print_td(AppleOHCIGeneralTransferDescriptorPtr pTD)
{
UInt32 w0, dir, err;
if (pTD == 0) return;
w0 = USBToHostLong(pTD->pShared->ohciFlags);
dir = (w0 & kOHCIGTDControl_DP) >> kOHCIGTDControl_DPPhase;
err = (w0 & kOHCIGTDControl_CC) >> kOHCIGTDControl_CCPhase;
USBLog(7, "%s[%p]\tTD(0x%08lx->0x%08lx) dir=%s cc=%s errc=%ld t=%ld rd=%s: c=0x%08lx cbp=0x%08lx, next=0x%08lx, bend=0x%08lx",
getName(), this,
(UInt32)pTD, pTD->pPhysical,
dir == 0 ? "SETUP" : (dir==2?"IN":"OUT"),
cc_errors[err],
(w0 & kOHCIGTDControl_EC) >> kOHCIGTDControl_ECPhase,
(w0 & kOHCIGTDControl_T) >> kOHCIGTDControl_TPhase,
(w0 & kOHCIGTDControl_R)?"yes":"no",
USBToHostLong(pTD->pShared->ohciFlags),
USBToHostLong(pTD->pShared->currentBufferPtr),
USBToHostLong(pTD->pShared->nextTD),
USBToHostLong(pTD->pShared->bufferEnd));
}
void
AppleUSBOHCI::print_itd(AppleOHCIIsochTransferDescriptorPtr pTD)
{
UInt32 w0, err;
int i;
if (pTD == 0) return;
w0 = USBToHostLong(pTD->pShared->flags);
err = (w0 & kOHCIITDControl_CC) >> kOHCIITDControl_CCPhase;
USBLog(5, "%s[%p]\tTD(0x%08lx->0x%08lx) cc=%s fc=%ld sf=0x%lx c=0x%08lx bp0=0x%08lx, next=0x%08lx, bend=0x%08lx",
getName(), this,
(UInt32)pTD, pTD->pPhysical,
cc_errors[err],
(w0 & kOHCIITDControl_FC) >> kOHCIITDControl_FCPhase,
(w0 & kOHCIITDControl_SF) >> kOHCIITDControl_SFPhase,
w0,
USBToHostLong(pTD->pShared->bufferPage0),
USBToHostLong(pTD->pShared->nextTD),
USBToHostLong(pTD->pShared->bufferEnd));
for(i=0; i<8; i++)
{
USBLog(5, "Offset/PSW %d = 0x%x", i, USBToHostWord(pTD->pShared->offset[i]));
}
USBLog(5, "frames = 0x%lx, FrameNumber %ld", (UInt32)pTD->pIsocFrame, pTD->frameNum);
}
void
AppleUSBOHCI::print_ed(AppleOHCIEndpointDescriptorPtr pED)
{
AppleOHCIGeneralTransferDescriptorPtr pTD;
UInt32 w0;
if (pED == 0) {
kprintf("Null ED\n");
return;
}
w0 = USBToHostLong(pED->pShared->flags);
if ((w0 & kOHCIEDControl_K) == 0 )
{
USBLog(7, "%s[%p] ED(0x%08lx->0x%08lx) %ld:%ld d=%ld s=%s sk=%s i=%s max=%ld : c=0x%08lx tail=0x%08lx, head=0x%08lx, next=0x%08lx",
getName(), this,
(UInt32)pED, (UInt32)pED->pPhysical,
(w0 & kOHCIEDControl_FA) >> kOHCIEDControl_FAPhase,
(w0 & kOHCIEDControl_EN) >> kOHCIEDControl_ENPhase,
(w0 & kOHCIEDControl_D) >> kOHCIEDControl_DPhase,
w0 & kOHCIEDControl_S?"low":"hi",
w0 & kOHCIEDControl_K?"yes":"no",
w0 & kOHCIEDControl_F?"yes":"no",
(w0 & kOHCIEDControl_MPS) >> kOHCIEDControl_MPSPhase,
USBToHostLong(pED->pShared->flags),
USBToHostLong(pED->pShared->tdQueueTailPtr),
USBToHostLong(pED->pShared->tdQueueHeadPtr),
USBToHostLong(pED->pShared->nextED));
pTD = AppleUSBOHCIgtdMemoryBlock::GetGTDFromPhysical(USBToHostLong(pED->pShared->tdQueueHeadPtr) & kOHCINextEndpointDescriptor_nextED);
while (pTD != 0)
{
print_td(pTD);
pTD = pTD->pLogicalNext;
}
}
}
void
AppleUSBOHCI::print_isoc_ed(AppleOHCIEndpointDescriptorPtr pED)
{
AppleOHCIIsochTransferDescriptorPtr pTD;
UInt32 w0;
if (pED == 0) {
kprintf("Null ED\n");
return;
}
w0 = USBToHostLong(pED->pShared->flags);
if ((w0 & kOHCIEDControl_K) == 0 )
{
USBLog(7, "%s[%p] ED(0x%08lx->0x%08lx) %ld:%ld d=%ld s=%s sk=%s i=%s max=%ld : c=0x%08lx tail=0x%08lx, head=0x%08lx, next=0x%08lx",
getName(), this,
(UInt32)pED, (UInt32)pED->pPhysical,
(w0 & kOHCIEDControl_FA) >> kOHCIEDControl_FAPhase,
(w0 & kOHCIEDControl_EN) >> kOHCIEDControl_ENPhase,
(w0 & kOHCIEDControl_D) >> kOHCIEDControl_DPhase,
w0 & kOHCIEDControl_S?"low":"hi",
w0 & kOHCIEDControl_K?"yes":"no",
w0 & kOHCIEDControl_F?"yes":"no",
(w0 & kOHCIEDControl_MPS) >> kOHCIEDControl_MPSPhase,
USBToHostLong(pED->pShared->flags),
USBToHostLong(pED->pShared->tdQueueTailPtr),
USBToHostLong(pED->pShared->tdQueueHeadPtr),
USBToHostLong(pED->pShared->nextED));
pTD = (AppleOHCIIsochTransferDescriptorPtr) pED->pLogicalHeadP;
while (pTD != 0)
{
print_itd(pTD);
pTD = pTD->pLogicalNext;
}
}
}
void
AppleUSBOHCI::print_list(AppleOHCIEndpointDescriptorPtr pListHead, AppleOHCIEndpointDescriptorPtr pListTail)
{
AppleOHCIEndpointDescriptorPtr pED, pEDTail;
pED = (AppleOHCIEndpointDescriptorPtr) pListHead;
pEDTail = (AppleOHCIEndpointDescriptorPtr) pListTail;
while (pED != pEDTail)
{
print_ed(pED);
pED = pED->pLogicalNext;
}
print_ed(pEDTail);
}
void
AppleUSBOHCI::print_control_list()
{
USBLog(7, "%s[%p] Control List: h/w head = 0x%lx", getName(), this, USBToHostLong(_pOHCIRegisters->hcControlHeadED));
print_list(_pControlHead, _pControlTail);
}
void
AppleUSBOHCI::print_bulk_list()
{
USBLog(7, "%s[%p] Bulk List: h/w head = 0x%lx", getName(), this, USBToHostLong(_pOHCIRegisters->hcBulkHeadED));
print_list((AppleOHCIEndpointDescriptorPtr) _pBulkHead, (AppleOHCIEndpointDescriptorPtr) _pBulkTail);
}
void
AppleUSBOHCI::print_int_list()
{
int i;
UInt32 w0;
AppleOHCIEndpointDescriptorPtr pED;
USBLog(7, "%s[%p]Interrupt List:", getName(), this);
for (i = 0; i < 63; i++)
{
pED = _pInterruptHead[i].pHead->pLogicalNext;
w0 = USBToHostLong(pED->pShared->flags);
if ((w0 & kOHCIEDControl_K) == 0 )
{
USBLog(7, "%d:", i);
print_ed(pED);
}
}
}
#endif
#define kOHCIUIMScratchFirstActiveFrame 0
void
AppleUSBOHCI::CheckEDListForTimeouts(AppleOHCIEndpointDescriptorPtr head, AppleOHCIEndpointDescriptorPtr tail)
{
AppleOHCIEndpointDescriptorPtr pED = head;
AppleOHCIGeneralTransferDescriptorPtr pTD;
UInt32 noDataTimeout;
UInt32 completionTimeout;
UInt32 rem;
UInt32 curFrame = GetFrameNumber32();
for (pED = pED->pLogicalNext; pED != tail; pED = pED->pLogicalNext)
{
pTD = (AppleOHCIGeneralTransferDescriptorPtr) (USBToHostLong(pED->pShared->tdQueueHeadPtr) & kOHCIHeadPMask);
pTD = AppleUSBOHCIgtdMemoryBlock::GetGTDFromPhysical((IOPhysicalAddress)pTD);
if (!pTD)
continue;
if (pTD == pED->pLogicalTailP)
continue;
if (!pTD->command)
continue;
noDataTimeout = pTD->command->GetNoDataTimeout();
completionTimeout = pTD->command->GetCompletionTimeout();
if (completionTimeout)
{
UInt32 firstActiveFrame = pTD->command->GetUIMScratch(kOHCIUIMScratchFirstActiveFrame);
if (!firstActiveFrame)
{
pTD->command->SetUIMScratch(kOHCIUIMScratchFirstActiveFrame, curFrame);
continue;
}
if ((curFrame - firstActiveFrame) >= completionTimeout)
{
USBLog(2, "(%p)Found a transaction past the completion deadline, timing out! (%x - %x)", pTD, curFrame, firstActiveFrame);
ReturnOneTransaction(pTD, pED, kIOUSBTransactionTimeout);
continue;
}
}
if (!noDataTimeout)
continue;
if (!pTD->lastFrame || (pTD->lastFrame > curFrame))
{
pTD->lastFrame = curFrame;
pTD->lastRemaining = findBufferRemaining(pTD);
continue;
}
rem = findBufferRemaining(pTD);
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, kIOUSBTransactionTimeout);
continue;
}
}
}
void
AppleUSBOHCI::UIMCheckForTimeouts(void)
{
AbsoluteTime currentTime;
AbsoluteTime lastRootHubChangeTime;
UInt64 elapsedTime = 0;
bool allPortsDisconnected = false;
if ( isInactive() || (_onCardBus && _pcCardEjected) || !_ohciAvailable || (_ohciBusState != kOHCIBusStateRunning))
return;
CheckEDListForTimeouts(_pControlHead, _pControlTail);
CheckEDListForTimeouts(_pBulkHead, _pBulkTail);
if ( !_idleSuspend )
{
clock_get_uptime( ¤tTime );
SUB_ABSOLUTETIME(¤tTime, &_lastCheckedTime );
absolutetime_to_nanoseconds(currentTime, &elapsedTime);
elapsedTime /= 1000000000;
if ( elapsedTime >= kOHCICheckForRootHubConnectionsPeriod )
{
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 >= kOHCICheckForRootHubInactivityPeriod )
{
USBLog(5,"%s[%p] Time to suspend the ports of bus %d", getName(), this, _busNumber);
setPowerState( kOHCISetPowerLevelIdleSuspend, this);
}
}
}
}
if ( _errataBits & kErrataNeedsWatchdogTimer )
{
UInt16 hccaFrameNumber, hcFrameNumber;
UInt32 fmInterval, hcca, bulkHead, controlHead, periodicStart, intEnable, fmNumber;
hcFrameNumber = (UInt16) USBToHostLong(_pOHCIRegisters->hcFmNumber); hccaFrameNumber = (UInt16) USBToHostLong(*(UInt32 *)(_pHCCA + 0x80));
if ( (hcFrameNumber > 5) && (hcFrameNumber > (hccaFrameNumber+5)) )
{
USBError(1,"%s[%p] Watchdog detected dead controller (hcca #: %d, hc #: %d)", getName(), this, (UInt32) hccaFrameNumber, (UInt32) hcFrameNumber);
fmInterval = _pOHCIRegisters->hcFmInterval;
hcca = _pOHCIRegisters->hcHCCA;
bulkHead = _pOHCIRegisters->hcBulkHeadED;
controlHead = _pOHCIRegisters->hcControlHeadED;
periodicStart = _pOHCIRegisters->hcPeriodicStart;
intEnable = _pOHCIRegisters->hcInterruptEnable;
fmNumber = _pOHCIRegisters->hcFmNumber;
_pOHCIRegisters->hcCommandStatus = USBToHostLong(kOHCIHcCommandStatus_HCR); IOSleep(3);
_pOHCIRegisters->hcFmNumber = fmNumber;
_pOHCIRegisters->hcInterruptEnable = intEnable;
_pOHCIRegisters->hcPeriodicStart = periodicStart;
_pOHCIRegisters->hcBulkHeadED = bulkHead;
_pOHCIRegisters->hcControlHeadED = controlHead;
_pOHCIRegisters->hcHCCA = hcca;
_pOHCIRegisters->hcFmInterval = fmInterval;
_pOHCIRegisters->hcControl = USBToHostLong ((kOHCIFunctionalState_Resume << kOHCIHcControl_HCFSPhase));
if (_errataBits & kErrataLucentSuspendResume)
{
IOSleep(35);
}
else
{
IOSleep(20);
}
_pOHCIRegisters->hcControl = HostToUSBLong(kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase);
IOSleep(3);
_pOHCIRegisters->hcControl = HostToUSBLong((kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase)
| kOHCIHcControl_CLE | (_OptiOn ? kOHCIHcControl_Zero : kOHCIHcControl_BLE)
| kOHCIHcControl_PLE | kOHCIHcControl_IE);
}
}
}
IOReturn
AppleUSBOHCI::UIMCreateIsochTransfer(
short functionAddress,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameNumberStart,
IOMemoryDescriptor * pBuffer,
UInt32 frameCount,
IOUSBLowLatencyIsocFrame *pFrames,
UInt32 updateFrequency)
{
IOReturn status = kIOReturnSuccess;
AppleOHCIIsochTransferDescriptorPtr pTailITD = NULL;
AppleOHCIIsochTransferDescriptorPtr pNewITD = NULL;
AppleOHCIIsochTransferDescriptorPtr pTempITD = NULL;
UInt32 i;
UInt32 curFrameInRequest = 0;
UInt32 bufferSize = 0;
UInt32 pageOffset = 0;
UInt32 segmentEnd = 0;
UInt32 lastPhysical = 0;
AppleOHCIEndpointDescriptorPtr pED;
UInt32 curFrameInTD = 0;
UInt16 frameNumber = (UInt16) frameNumberStart;
UInt64 curFrameNumber = GetFrameNumber();
UInt64 frameDiff;
UInt64 maxOffset = (UInt64)(0x00007FF0);
UInt32 diff32;
UInt32 itdFlags = 0;
UInt32 numSegs = 0;
UInt32 physPageStart = 0;
UInt32 prevFramesPage = 0;
UInt32 physPageEnd = 0;
UInt32 pageSelectMask = 0;
bool needNewITD;
bool multiPageSegment = false;
IOPhysicalSegment segs[2];
UInt32 tdType;
IOByteCount transferOffset;
bool useUpdateFrequency = true;
if ( (frameCount == 0) || (frameCount > 1000) )
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer(LL) bad frameCount: %d",getName(), this, frameCount);
return kIOReturnBadArgument;
}
if (direction == kUSBOut) {
direction = kOHCIEDDirectionOut;
tdType = kOHCIIsochronousOutLowLatencyType;
}
else if (direction == kUSBIn) {
direction = kOHCIEDDirectionIn;
tdType = kOHCIIsochronousInLowLatencyType;
}
else
return kIOReturnInternalError;
pED = FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL);
if (!pED)
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer(LL) endpoint (%d) not found. Returning 0x%x", getName(), this, endpointNumber, kIOUSBEndpointNotFound);
return kIOUSBEndpointNotFound;
}
if ( updateFrequency == 0 )
useUpdateFrequency = false;
if (frameNumberStart <= curFrameNumber)
{
if (frameNumberStart < (curFrameNumber - maxOffset))
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer(LL) request frame WAY too old. frameNumberStart: %ld, curFrameNumber: %ld. Returning 0x%x", getName(), this, (UInt32) frameNumberStart, (UInt32) curFrameNumber, kIOReturnIsoTooOld);
return kIOReturnIsoTooOld;
}
USBLog(6,"%s[%p]::UIMCreateIsochTransfer(LL) 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, pED->pLogicalTailP);
} else
{
if (frameNumberStart > (curFrameNumber + maxOffset))
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer(LL) request frame too far ahead! frameNumberStart: %ld, curFrameNumber: %ld, Returning 0x%x",getName(), this, (UInt32) frameNumberStart, (UInt32) curFrameNumber, kIOReturnIsoTooNew);
return kIOReturnIsoTooNew;
}
frameDiff = frameNumberStart - curFrameNumber;
diff32 = (UInt32)frameDiff;
if (diff32 < 2)
{
USBLog(5,"%s[%p]::UIMCreateIsochTransfer(LL) WARNING! - frameNumberStart less than 2 ms (is %ld)! frameNumberStart: %ld, curFrameNumber: %ld",getName(), this, (UInt32) diff32, (UInt32) frameNumberStart, (UInt32) curFrameNumber);
}
}
for ( i = 0; i< frameCount; i++)
{
if (pFrames[i].frReqCount > kUSBMaxIsocFrameReqCount)
{
USBLog(3,"%s[%p]::UIMCreateIsochTransfer(LL) Isoch frame (%d) too big %d",getName(), this, i + 1, pFrames[i].frReqCount);
return kIOReturnBadArgument;
}
bufferSize += pFrames[i].frReqCount;
pFrames[i].frStatus = (IOReturn) kUSBLowLatencyIsochTransferKey;
}
USBLog(7,"%s[%p]::UIMCreateIsochTransfer(LL) transfer %s, buffer: %p, length: %d frames: %d",getName(), this, (direction == kOHCIEDDirectionIn) ? "in" : "out", pBuffer, bufferSize, frameCount);
pNewITD = AllocateITD();
USBLog(7, "%s[%p]::UIMCreateIsochTransfer(LL) - new iTD %p", getName(), this, pNewITD);
if (pNewITD == NULL)
{
USBLog(1,"%s[%p]::UIMCreateIsochTransfer(LL) Could not allocate a new iTD",getName(), this);
return kIOReturnNoMemory;
}
if (!bufferSize)
{
numSegs = 1;
segs[0].location = segs[0].length = 0;
pageOffset = 0;
}
pTailITD = (AppleOHCIIsochTransferDescriptorPtr)pED->pLogicalTailP; OSWriteLittleInt32(&pTailITD->pShared->nextTD, 0, pNewITD->pPhysical); pTailITD->pLogicalNext = pNewITD;
needNewITD = false;
transferOffset = 0;
while (curFrameInRequest < frameCount)
{
if (!needNewITD && bufferSize)
{
numSegs = _isoCursor->getPhysicalSegments(pBuffer, transferOffset, segs, 2, pFrames[curFrameInRequest].frReqCount);
pageOffset = segs[0].location & kOHCIPageOffsetMask;
transferOffset += segs[0].length;
segmentEnd = (segs[0].location + segs[0].length ) & kOHCIPageOffsetMask;
USBLog(8,"curFrameInRequest: %d, curFrameInTD: %d, pageOffset: %x, numSegs: %d, seg[0].location: %p, seg[0].length: %d", curFrameInRequest, curFrameInTD, pageOffset, numSegs, segs[0].location, segs[0].length);
if(numSegs == 2)
{
transferOffset += segs[1].length;
USBLog(8 ,"seg[1].location: %p, seg[1].length %d",segs[1].location, segs[1].length);
}
if ( (segs[numSegs-1].location & kOHCIPageMask) != ((segs[numSegs-1].location + segs[numSegs-1].length) & kOHCIPageMask))
{
multiPageSegment = true;
USBLog(8,"We have a segment that crosses a page boundary: start: %p, length: %d, end: %p, curFrameinTD: %d", segs[numSegs-1].location, segs[numSegs-1].length,segs[numSegs-1].location + segs[numSegs-1].length, curFrameInTD);
}
else
multiPageSegment = false;
}
if (curFrameInTD == 0)
{
physPageStart = segs[0].location & kOHCIPageMask; pageSelectMask = 0; needNewITD = false;
itdFlags = (UInt16)(curFrameInRequest + frameNumber);
pTailITD->pIsocFrame = (IOUSBIsocFrame *) pFrames; pTailITD->frameNum = curFrameInRequest; pTailITD->pType = tdType; OSWriteLittleInt32(&pTailITD->pShared->bufferPage0, 0, physPageStart);
}
else if ((segs[0].location & kOHCIPageMask) != physPageStart)
{
if ( (pageSelectMask && (((segs[0].location & kOHCIPageMask) != physPageEnd) || numSegs == 2)) )
{
needNewITD = true;
USBLog(8, "%s[%p]::UIMCreateIsochTransfer - got it! (%d, %p, %p, %d)", getName(), this, pageSelectMask, segs[0].location & kOHCIPageMask, physPageEnd, numSegs);
}
else if ( pageSelectMask && multiPageSegment )
{
needNewITD = true;
USBLog(8,"%s[%p]::UIMCreateIsochTransfer This frame spans 2 or more pages and we already used our page crossing ",getName(), this);
}
else if ( (prevFramesPage != (segs[0].location & kOHCIPageMask)) && (segmentEnd != 0) )
{
needNewITD = true;
USBLog(8,"%s[%p]::UIMCreateIsochTransfer(LL) This frame starts on a new page and the previous one did NOT end on a page boundary (%d)",getName(), this, segmentEnd);
}
else
{
if (pageSelectMask == 0 )
USBLog(8,"Using our page crossing for this TD (%p)",(segs[numSegs-1].location + segs[numSegs-1].length -1 ) & kOHCIPageMask);
pageSelectMask = kOHCIPageSize; physPageEnd = (segs[numSegs-1].location + segs[numSegs-1].length) & kOHCIPageMask;
}
}
prevFramesPage = (segs[numSegs-1].location + segs[numSegs-1].length) & kOHCIPageMask;
if ( (curFrameInTD > 7) || needNewITD || (useUpdateFrequency && (curFrameInTD >= updateFrequency)) )
{
itdFlags |= (curFrameInTD-1) << kOHCIITDControl_FCPhase;
OSWriteLittleInt32(&pTailITD->pShared->bufferEnd, 0, lastPhysical);
pNewITD = AllocateITD();
USBLog(7, "%s[%p]::UIMCreateIsochTransfer(LL) - new iTD %p (curFrameInRequest: %d, curFrameInTD: %d, needNewITD: %d, updateFrequency: %d", getName(), this, pNewITD, curFrameInRequest, curFrameInTD, needNewITD, updateFrequency);
if (pNewITD == NULL)
{
curFrameInTD = 0;
needNewITD = true; status = kIOReturnNoMemory;
break;
}
itdFlags |= (kOHCIGTDConditionNotAccessed << kOHCIGTDControl_CCPhase);
if ( !(useUpdateFrequency && (curFrameInTD >= updateFrequency)) || !useUpdateFrequency )
{
USBLog(7, "%s[%p]::UIMCreateIsochTransfer(LL) - Seting DI bits to 111b (curFrameInRequest %d)", getName(), this, curFrameInRequest);
itdFlags |= ( 0x7 << kOHCIGTDControl_DIPhase );
}
curFrameInTD = 0;
needNewITD = true;
OSWriteLittleInt32(&pTailITD->pShared->flags, 0, itdFlags);
pTailITD->completion.action = NULL;
pTailITD = pTailITD->pLogicalNext; OSWriteLittleInt32(&pTailITD->pShared->nextTD, 0, pNewITD->pPhysical); pTailITD->pLogicalNext = pNewITD;
continue; }
OSWriteLittleInt16(&pTailITD->pShared->offset[curFrameInTD], 0,
pageOffset | pageSelectMask | (kOHCIITDOffsetConditionNotAccessed << kOHCIITDOffset_CCPhase) );
curFrameInRequest++;
curFrameInTD++;
lastPhysical = segs[numSegs-1].location + segs[numSegs-1].length - 1;
}
if (status != kIOReturnSuccess)
{
pNewITD = pTailITD->pLogicalNext; pTempITD = (AppleOHCIIsochTransferDescriptorPtr)pED->pLogicalTailP;
pTailITD = pTempITD->pLogicalNext; pTempITD->pLogicalNext = NULL; pTempITD->pShared->nextTD = NULL; while (pTailITD != pNewITD)
{
pTempITD = pTailITD;
pTailITD = pTailITD->pLogicalNext;
DeallocateITD(pTempITD);
}
}
else
{
itdFlags |= (curFrameInTD-1) << kOHCIITDControl_FCPhase;
OSWriteLittleInt32(&pTailITD->pShared->flags, 0, itdFlags);
OSWriteLittleInt32(&pTailITD->pShared->bufferEnd, 0, lastPhysical);
pTailITD->completion = completion;
pED->pLogicalTailP = pNewITD;
OSWriteLittleInt32(&pED->pShared->tdQueueTailPtr, 0, pNewITD->pPhysical);
}
return status;
}