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 <IOKit/usb/IOUSBRootHubDevice.h>
#include "AppleUSBOHCI.h"
#include "AppleUSBOHCIMemoryBlocks.h"
#define DEBUGGING_LEVEL 0 // 1 = low; 2 = high; 3 = extreme
#define super IOUSBControllerV3
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;
IOByteCount transferOffset;
UInt32 pageCount;
UInt32 altFlags; IOUSBCompletion completion = command->GetUSLCompletion();
IODMACommand *dmaCommand = command->GetDMACommand();
UInt64 offset;
IODMACommand::Segment32 segments32[2];
IODMACommand::Segment64 segments64[2];
UInt32 i;
flags |= (kOHCIGTDConditionNotAccessed << kOHCIGTDControl_CCPhase);
altFlags = flags & ~kOHCIGTDControl_R;
altFlags |= ( 0x7 << kOHCIGTDControl_DIPhase );
if ( (USBToHostLong(queue->pShared->tdQueueHeadPtr) & kOHCIHeadPointer_H) && !( (type == kOHCIControlSetupType) && ( ((USBToHostLong(queue->pShared->flags) & kOHCIEDControl_EN) >> kOHCIEDControl_ENPhase) == 0 )) )
{
USBLog(1, "AppleUSBOHCI[%p]::CreateGeneralTransfer - trying to queue to a stalled pipe", this);
status = kIOUSBPipeStalled;
}
else if (bufferSize != 0)
{
if (CBP)
{
if (!dmaCommand)
{
USBError(1, "AppleUSBOHCI[%p]::CreateGeneralTransfer - no dmaCommand", this);
status = kIOReturnInternalError;
}
else if (dmaCommand->getMemoryDescriptor() != CBP)
{
USBError(1, "AppleUSBOHCI[%p]::CreateGeneralTransfer - mismatched CBP (%p) and dmaCommand memory descriptor (%p)", this, CBP, dmaCommand->getMemoryDescriptor());
status = kIOReturnInternalError;
}
}
else
{
USBError(1, "AppleUSBOHCI[%p]::CreateGeneralTransfer - nonZero bufferSize and no CBP", this);
status = kIOReturnInternalError;
}
if (!status)
{
transferOffset = 0;
while (transferOffset < bufferSize)
{
offset = transferOffset;
if(_errataBits & kErrataOnlySinglePageTransfers)
pageCount = 1;
else
pageCount = 2;
USBLog(7, "AppleUSBOHCI[%p]::CreateGeneralTransfer - getting segments - offset (%Ld) pageCount (%d) transferOffset (%d) bufferSize (%d)", this, offset, (int)pageCount, (int)transferOffset, (int)bufferSize);
status = dmaCommand->gen64IOVMSegments(&offset, segments64, &pageCount);
if (status || ((pageCount != 1) && (pageCount != 2)))
{
USBError(1, "AppleUSBOHCI[%p]::CreateGeneralTransfer - could not generate segments - err (%p) pageCount (%d) offset (%Ld) transferOffset (%d) bufferSize (%d) getMemoryDescriptor (%p)", this, (void*)status, (int)pageCount, offset, (int)transferOffset, (int)bufferSize, dmaCommand->getMemoryDescriptor());
status = status ? status : kIOReturnInternalError;
return status;
}
if (pageCount == 2)
{
USBLog(7, "AppleUSBOHCI[%p]::CreateGeneralTransfer - after gen64IOVMSegments, offset (%Ld) pageCount (%d) segments64[0].fIOVMAddr (%p) segments64[0].fLength (%d) segments64[1].fIOVMAddr (%p) segments64[1].fLength (%d)", this, offset, (int)pageCount, (void*)segments64[0].fIOVMAddr, (int)segments64[0].fLength, (void*)segments64[1].fIOVMAddr, (int)segments64[1].fLength);
}
else
{
USBLog(7, "AppleUSBOHCI[%p]::CreateGeneralTransfer - after gen64IOVMSegments, offset (%Ld) pageCount (%d) segments64[0].fIOVMAddr (%p) segments64[0].fLength (%d)", this, offset, (int)pageCount, (void*)segments64[0].fIOVMAddr, (int)segments64[0].fLength);
}
for (i=0; i< pageCount; i++)
{
if (((UInt32)(segments64[i].fIOVMAddr >> 32) > 0) || ((UInt32)(segments64[i].fLength >> 32) > 0))
{
USBError(1, "AppleUSBOHCI[%p]::CreateGeneralTransfer - generated segments (%d) not 32 bit - offset (0x%Lx) length (0x%Lx) ", this, (int)i, segments64[0].fIOVMAddr, segments64[0].fLength);
return kIOReturnInternalError;
}
segments32[i].fIOVMAddr = (UInt32)segments64[i].fIOVMAddr;
segments32[i].fLength = (UInt32)segments64[i].fLength;
}
newOHCIGeneralTransferDescriptor = AllocateTD();
if (newOHCIGeneralTransferDescriptor == NULL)
{
status = kIOReturnNoMemory;
break;
}
if ((pageCount == 2) && (transferOffset + segments32[0].fLength >= bufferSize))
{
USBLog(6, "AppleUSBOHCI[%p]::CreateGeneralTransfer - bufferSize < Descriptor size - adjusting pageCount", this);
pageCount = 1;
}
if ((pageCount == 2) && ((((segments32[0].fIOVMAddr + segments32[0].fLength) & PAGE_MASK) != 0) || ((segments32[1].fIOVMAddr & PAGE_MASK) != 0)))
{
pageCount = 1; if (segments32[0].fLength % ((USBToHostLong(queue->pShared->flags) & kOHCIEDControl_MPS) >> kOHCIEDControl_MPSPhase) != 0)
{
USBError(1, "AppleUSBOHCI[%p] CreateGeneralTransfer: non-multiple MPS transfer required -- giving up!", this);
status = kIOReturnNoMemory;
break;
}
}
pOHCIGeneralTransferDescriptor = (AppleOHCIGeneralTransferDescriptorPtr)queue->pLogicalTailP;
OSWriteLittleInt32(&pOHCIGeneralTransferDescriptor->pShared->currentBufferPtr, 0, segments32[0].fIOVMAddr);
OSWriteLittleInt32(&pOHCIGeneralTransferDescriptor->pShared->nextTD, 0, newOHCIGeneralTransferDescriptor->pPhysical);
if (pageCount == 2)
{
if ((transferOffset + segments32[0].fLength + segments32[1].fLength) > bufferSize)
{
USBLog(6, "AppleUSBOHCI[%p]::CreateGeneralTransfer - bufferSize < Descriptor size - adjusting physical segment 1", this);
segments32[1].fLength = bufferSize - (transferOffset + segments32[0].fLength);
}
OSWriteLittleInt32(&pOHCIGeneralTransferDescriptor->pShared->bufferEnd, 0, segments32[1].fIOVMAddr + segments32[1].fLength - 1);
transferOffset += segments32[1].fLength;
USBLog(7, "AppleUSBOHCI[%p]::CreateGeneralTransfer - added length of segment 1, transferOffset now %d", this, (int)transferOffset);
}
else
{
if ((transferOffset + segments32[0].fLength) > bufferSize)
{
USBLog(6, "AppleUSBOHCI[%p]::CreateGeneralTransfer - bufferSize < Descriptor size - adjusting physical segment 0", this);
segments32[0].fLength = bufferSize - transferOffset;
}
OSWriteLittleInt32(&pOHCIGeneralTransferDescriptor->pShared->bufferEnd, 0, segments32[0].fIOVMAddr + segments32[0].fLength - 1);
}
pOHCIGeneralTransferDescriptor->pLogicalNext = newOHCIGeneralTransferDescriptor;
pOHCIGeneralTransferDescriptor->pEndpoint = queue;
pOHCIGeneralTransferDescriptor->pType = type;
pOHCIGeneralTransferDescriptor->command = command;
transferOffset += segments32[0].fLength;
USBLog(7, "AppleUSBOHCI[%p]::CreateGeneralTransfer - added length of segment 0, transferOffset now %d", this, (int)transferOffset);
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(1, "AppleUSBOHCI[%p] CreateGeneralTransfer: returning status 0x%x", this, status);
}
return (status);
}
IOReturn
AppleUSBOHCI::UIMCreateControlEndpoint(
UInt8 functionAddress,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
USBLog(5, "AppleUSBOHCI[%p]: UIMCreateControlEndpoint w/ HS ( Addr: %d:%d, max=%d, %s) calling thru", this, functionAddress, endpointNumber, maxPacketSize, (speed == kUSBDeviceSpeedLow) ? "lo" : "full");
return UIMCreateControlEndpoint( functionAddress, endpointNumber, maxPacketSize, speed );
}
IOReturn
AppleUSBOHCI::UIMCreateControlEndpoint(UInt8 functionAddress, UInt8 endpointNumber, UInt16 maxPacketSize, UInt8 speed)
{
AppleOHCIEndpointDescriptorPtr pOHCIEndpointDescriptor, pED;
USBLog(5, "AppleUSBOHCI[%p]: UIMCreateControlEndpoint( Addr: %d:%d, max=%d, %s)", this,
functionAddress, endpointNumber, maxPacketSize, (speed == kUSBDeviceSpeedLow) ? "lo" : "full");
if (_rootHubFuncAddress == functionAddress)
{
if ( (endpointNumber != 0) && (speed == kUSBDeviceSpeedLow))
{
USBLog(3,"AppleUSBOHCI[%p] UIMCreateControlEndpoint: Bad parameters endpoint: %d, speed: %s",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, "AppleUSBOHCI[%p] UIMCreateControlTransfer- calling the wrong method!", 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, "AppleUSBOHCI[%p]::UIMCreateControlTransfer: adr=%d:%d cbp=%lx:%lx br=%s cback=[%lx:%lx] dir=%d)", 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, "AppleUSBOHCI[%p] UIMCreateControlTransfer- Could not find endpoint (FN: %d, EP: %d)!", 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, "AppleUSBOHCI[%p]UIMCreateControlTransfer- calling the wrong method!", 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, "AppleUSBOHCI[%p]UIMCreateControlTransfer- calling the pointer method instead of the desc method!", this);
return kIOReturnIPCError;
}
IOReturn
AppleUSBOHCI::UIMCreateBulkEndpoint(
UInt8 functionAddress,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt16 maxPacketSize,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
USBLog(5,"AppleUSBOHCI[%p]: UIMCreateBulkEndpoint HS(Addr=%d:%d, max=%d, dir=%d, %s) calling thru", this,
functionAddress, endpointNumber, maxPacketSize, direction, (speed == kUSBDeviceSpeedLow) ? "lo" : "full");
return UIMCreateBulkEndpoint( functionAddress, endpointNumber, direction, speed, maxPacketSize);
}
IOReturn AppleUSBOHCI::UIMCreateBulkEndpoint(
UInt8 functionAddress,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt8 maxPacketSize)
{
AppleOHCIEndpointDescriptorPtr pOHCIEndpointDescriptor, pED;
USBLog(5,"AppleUSBOHCI[%p]: UIMCreateBulkEndpoint(Addr=%d:%d, max=%d, dir=%d, %s)", 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, "AppleUSBOHCI[%p]UIMCreateBulkTransfer- calling the wrong method!", 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, "AppleUSBOHCI[%p]::UIMCreateBulkTransfer: adr=%d:%d cbp=%lx:%lx br=%s cback=[%lx:%lx:%lx] dir=%d)",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, "AppleUSBOHCI[%p] UIMCreateBulkTransfer- Could not find endpoint!", 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,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
USBLog(5, "AppleUSBOHCI[%p]: UIMCreateInterruptEndpoint HS ( Addr: %d:%d, max=%d, dir=%d, rate=%d, %s) calling thru", this,
functionAddress, endpointNumber, maxPacketSize,direction,
pollingRate, (speed == kUSBDeviceSpeedLow) ? "lo" : "full");
return UIMCreateInterruptEndpoint( functionAddress, endpointNumber, direction, speed, maxPacketSize, pollingRate);
}
IOReturn
AppleUSBOHCI::UIMCreateInterruptEndpoint(
short functionAddress,
short endpointNumber,
UInt8 direction,
short speed,
UInt16 maxPacketSize,
short pollingRate)
{
AppleOHCIEndpointDescriptorPtr pOHCIEndpointDescriptor;
AppleOHCIEndpointDescriptorPtr pED, temp;
int offset;
short originalDirection = direction;
USBLog(5, "AppleUSBOHCI[%p]: UIMCreateInterruptEndpoint ( Addr: %d:%d, max=%d, dir=%d, rate=%d, %s)", this,
functionAddress, endpointNumber, maxPacketSize,direction,
pollingRate, (speed == kUSBDeviceSpeedLow) ? "lo" : "full");
if (_rootHubFuncAddress == functionAddress)
{
if ( (endpointNumber != 1) || ( speed != kUSBDeviceSpeedFull ) || (direction != kUSBIn) )
{
USBLog(3, "AppleUSBOHCI[%p]: UIMCreateInterruptEndpoint bad parameters: endpNumber %d, speed: %s, direction: %d", this, endpointNumber, (speed == kUSBDeviceSpeedLow) ? "lo" : "full", direction);
return kIOReturnBadArgument;
}
return RootHubStartTimer(pollingRate);
}
if (direction == kUSBOut)
direction = kOHCIEDDirectionOut;
else if (direction == kUSBIn)
direction = kOHCIEDDirectionIn;
else
direction = kOHCIEDDirectionTD;
pED = FindInterruptEndpoint(functionAddress, endpointNumber, direction, &temp);
if ( pED != NULL )
{
IOReturn ret;
USBLog(3, "AppleUSBOHCI[%p]: UIMCreateInterruptEndpoint endpoint already existed -- deleting it", this);
ret = UIMDeleteEndpoint(functionAddress, endpointNumber, originalDirection);
if ( ret != kIOReturnSuccess)
{
USBLog(3, "AppleUSBOHCI[%p]: UIMCreateInterruptEndpoint deleting endpoint returned 0x%x", this, ret);
return ret;
}
}
else
{
USBLog(3, "AppleUSBOHCI[%p]: UIMCreateInterruptEndpoint endpoint does NOT exist", this);
}
if (_OptiOn)
if (speed == kUSBDeviceSpeedFull)
if (pollingRate >= 8)
pollingRate = 7;
if (DetermineInterruptOffset(pollingRate, maxPacketSize, &offset) == false)
return(kIOReturnNoBandwidth);
USBLog(5, "AppleUSBOHCI[%p]: UIMCreateInterruptEndpoint: offset = %d", 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, "AppleUSBOHCI[%p]UIMCreateInterruptTransfer- calling the wrong method!", 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();
if (_rootHubFuncAddress == command->GetAddress())
{
IODMACommand *dmaCommand = command->GetDMACommand();
IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor*)dmaCommand->getMemoryDescriptor() : NULL;
if (memDesc)
{
USBLog(3, "AppleUSBOHCI[%p]::UIMCreateInterruptTransfer - root hub interrupt transfer - clearing unneeded memDesc (%p) from dmaCommand (%p)", this, memDesc, dmaCommand);
dmaCommand->clearMemoryDescriptor();
}
if (command->GetEndpoint() == 1)
{
status = RootHubQueueInterruptRead(buffer, command->GetReqCount(), completion);
}
else
{
Complete(completion, kIOUSBEndpointNotFound, command->GetReqCount());
status = kIOUSBEndpointNotFound;
}
return status;
}
USBLog(7, "AppleUSBOHCI[%p]::UIMCreateInterruptTransfer: adr=%d:%d cbp=%p:%lx br=%s cback=[%lx:%lx:%lx])", this,
command->GetAddress(), command->GetEndpoint(), command->GetBuffer(),
command->GetReqCount(), command->GetBufferRounding()?"YES":"NO",
(UInt32)completion.action, (UInt32)completion.target,
(UInt32)completion.parameter);
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, "AppleUSBOHCI[%p] UIMCreateInterruptTransfer- Could not find endpoint!", this);
status = kIOUSBEndpointNotFound;
}
return (status);
}
IOReturn
AppleUSBOHCI::UIMCreateIsochEndpoint(
short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
return UIMCreateIsochEndpoint( functionAddress, endpointNumber, maxPacketSize, direction);
}
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,"AppleUSBOHCI[%p]::UIMCreateIsochEndpoint endpoint already exists, changing maxPacketSize to %ld", this, maxPacketSize);
edFlags = USBToHostLong(pED->pShared->flags);
curMaxPacketSize = ( edFlags & kOHCIEDControl_MPS) >> kOHCIEDControl_MPSPhase;
if (maxPacketSize == curMaxPacketSize)
{
USBLog(2,"AppleUSBOHCI[%p]::UIMCreateIsochEndpoint maxPacketSize (%ld) the same, no change", this, maxPacketSize);
return kIOReturnSuccess;
}
if (maxPacketSize > curMaxPacketSize)
{
xtraRequest = maxPacketSize - curMaxPacketSize;
if (xtraRequest > _isochBandwidthAvail)
{
USBLog(2,"AppleUSBOHCI[%p]::UIMCreateIsochEndpoint out of bandwidth, request (extra) = %ld, available: %ld", this, xtraRequest, _isochBandwidthAvail);
return kIOReturnNoBandwidth;
}
_isochBandwidthAvail -= xtraRequest;
USBLog(2,"AppleUSBOHCI[%p]::UIMCreateIsochEndpoint grabbing additional bandwidth: %ld, new available: %ld", this, xtraRequest, _isochBandwidthAvail);
}
else
{
xtraRequest = curMaxPacketSize - maxPacketSize;
_isochBandwidthAvail += xtraRequest;
USBLog(2,"AppleUSBOHCI[%p]::UIMCreateIsochEndpoint returning some bandwidth: %ld, new available: %ld", this, xtraRequest, _isochBandwidthAvail);
}
edFlags &= ~kOHCIEDControl_MPS; edFlags |= (maxPacketSize << kOHCIEDControl_MPSPhase);
OSWriteLittleInt32(&pED->pShared->flags, 0, edFlags);
return kIOReturnSuccess;
}
if (maxPacketSize > _isochBandwidthAvail)
{
USBLog(3,"AppleUSBOHCI[%p]::UIMCreateIsochEndpoint out of bandwidth, request (extra) = %ld, available: %ld", 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,"AppleUSBOHCI[%p]::UIMCreateIsochEndpoint success. bandwidth used = %ld, new available: %ld", this, maxPacketSize, _isochBandwidthAvail);
return kIOReturnSuccess;
}
IOReturn
AppleUSBOHCI::UIMCreateIsochTransfer(short functionAddress,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameNumberStart,
IOMemoryDescriptor * pBuffer,
UInt32 frameCount,
IOUSBIsocFrame * pFrames)
{
USBError(1, "AppleUSBOHCI::UIMCreateIsochTransfer - old method");
return kIOReturnIPCError;
}
IOReturn
AppleUSBOHCI::UIMAbortEndpoint(short functionAddress,
short endpointNumber,
short direction)
{
AppleOHCIEndpointDescriptorPtr pED;
AppleOHCIEndpointDescriptorPtr pEDQueueBack;
UInt32 something, controlMask;
USBLog(5, "AppleUSBOHCI[%p] UIMAbortEndpoint: Addr: %d, Endpoint: %d,%d", this, functionAddress,endpointNumber,direction);
if (functionAddress == _rootHubFuncAddress)
{
if ( (endpointNumber != 1) && (endpointNumber != 0) )
{
USBLog(1, "AppleUSBOHCI[%p] UIMAbortEndpoint: bad params - endpNumber: %d", this, endpointNumber );
return kIOReturnBadArgument;
}
USBLog(5, "AppleUSBOHCI[%p] UIMAbortEndpoint: Attempting operation on root hub", 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, "AppleUSBOHCI[%p] UIMAbortEndpoint- Could not find endpoint!", this);
return (kIOUSBEndpointNotFound);
}
pED->pShared->flags |= HostToUSBLong(kOHCIEDControl_K);
IOSleep(2);
if (_writeDoneHeadInterrupt & kOHCIHcInterrupt_WDH)
{
_writeDoneHeadInterrupt = 0;
UIMProcessDoneQueue(NULL);
}
RemoveTDs(pED, false);
pED->pShared->flags &= ~HostToUSBLong(kOHCIEDControl_K); IOSync();
return (kIOReturnSuccess);
}
IOReturn
AppleUSBOHCI::UIMDeleteEndpoint(
short functionAddress,
short endpointNumber,
short direction)
{
AppleOHCIEndpointDescriptorPtr pED;
AppleOHCIEndpointDescriptorPtr pEDQueueBack;
UInt32 hcControl;
UInt32 something, controlMask;
USBLog(5, "AppleUSBOHCI[%p] UIMDeleteEndpoint: Addr: %d, Endpoint: %d,%d", this, functionAddress,endpointNumber,direction);
if (functionAddress == _rootHubFuncAddress)
{
if ( (endpointNumber != 1) && (endpointNumber != 0) )
{
USBLog(1, "AppleUSBOHCI[%p] UIMDeleteEndpoint: bad params - endpNumber: %d", this, endpointNumber );
return kIOReturnBadArgument;
}
USBLog(5, "AppleUSBOHCI[%p] UIMDeleteEndpoint: Attempting operation on root hub", 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, "AppleUSBOHCI[%p] UIMDeleteEndpoint- Could not find endpoint!", 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(2);
if (_writeDoneHeadInterrupt & kOHCIHcInterrupt_WDH)
{
_writeDoneHeadInterrupt = 0;
UIMProcessDoneQueue(NULL);
}
hcControl |= controlMask;
_pOHCIRegisters->hcControl = HostToUSBLong(hcControl);
USBLog(5, "AppleUSBOHCI[%p]::UIMDeleteEndpoint", this);
if (GetEDType(pED) == kOHCIEDFormatIsochronousTD)
{
UInt32 maxPacketSize = (USBToHostLong(pED->pShared->flags) & kOHCIEDControl_MPS) >> kOHCIEDControl_MPSPhase;
_isochBandwidthAvail += maxPacketSize;
USBLog(5, "AppleUSBOHCI[%p]::UIMDeleteEndpoint (Isoch) - bandwidth returned %ld, new available: %ld", 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, "+AppleUSBOHCI[%p]: clearing endpoint %d:%d stall", this, functionAddress, endpointNumber);
if (_rootHubFuncAddress == functionAddress)
{
if ( (endpointNumber != 1) && (endpointNumber != 0) )
{
USBLog(1, "AppleUSBOHCI[%p] UIMClearEndpointStall: bad params - endpNumber: %d", this, endpointNumber );
return kIOReturnBadArgument;
}
USBLog(5, "AppleUSBOHCI[%p] UIMClearEndpointStall: Attempting operation on root hub", 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, "AppleUSBOHCI[%p] UIMClearEndpointStall- Could not find endpoint!", 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, "-AppleUSBOHCI[%p]: clearing endpoint %d:%d stall", 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) & kOHCIUniqueNumNoDirMask) == 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,"AppleUSBOHCI[%p]::DetermineInterruptOffset pollingRate of 0 -- that's illegal!", 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, "AppleUSBOHCI[%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",
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, "AppleUSBOHCI[%p]\tTD(%p->%p) cc=%s fc=%ld sf=0x%lx c=0x%08lx bp0=%p, bend=%p, next=%p",
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->bufferEnd),
USBToHostLong(pTD->pShared->nextTD)
);
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, "AppleUSBOHCI[%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",
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":"full",
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, "AppleUSBOHCI[%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",
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, "AppleUSBOHCI[%p] Control List: h/w head = 0x%lx", this, USBToHostLong(_pOHCIRegisters->hcControlHeadED));
print_list(_pControlHead, _pControlTail);
}
void
AppleUSBOHCI::print_bulk_list()
{
USBLog(7, "AppleUSBOHCI[%p] Bulk List: h/w head = 0x%lx", this, USBToHostLong(_pOHCIRegisters->hcBulkHeadED));
print_list((AppleOHCIEndpointDescriptorPtr) _pBulkHead, (AppleOHCIEndpointDescriptorPtr) _pBulkTail);
}
void
AppleUSBOHCI::print_int_list()
{
int i;
UInt32 w0;
AppleOHCIEndpointDescriptorPtr pED;
USBLog(7, "AppleUSBOHCI[%p]Interrupt List:", 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)
{
UInt32 myFlags = USBToHostLong( pED->pShared->flags);
USBLog(2, "AppleUSBOHCI[%p]::Found a transaction past the completion deadline, timing out! (%p, 0x%lx - 0x%lx)", this, pTD, curFrame, firstActiveFrame);
USBError(1, "AppleUSBOHCI[%p]::Found a transaction past the completion deadline on bus 0x%lx, timing out! (Addr: %ld, EP: %ld)", this, _busNumber, ((myFlags & kOHCIEDControl_FA) >> kOHCIEDControl_FAPhase), ((myFlags & kOHCIEDControl_EN) >> kOHCIEDControl_ENPhase) );
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)
{
UInt32 myFlags = USBToHostLong( pED->pShared->flags);
USBLog(2, "AppleUSBOHCI[%p]::Found a transaction which hasn't moved in 5 seconds, timing out! (%p, 0x%lx - 0x%lx)", this, pTD, curFrame, pTD->lastFrame);
USBError(1, "AppleUSBOHCI[%p]::Found a transaction which hasn't moved in 5 seconds on bus 0x%lx, timing out! (Addr: %ld, EP: %ld)", this, _busNumber, ((myFlags & kOHCIEDControl_FA) >> kOHCIEDControl_FAPhase), ((myFlags & kOHCIEDControl_EN) >> kOHCIEDControl_ENPhase) );
ReturnOneTransaction(pTD, pED, kIOUSBTransactionTimeout);
continue;
}
}
}
void
AppleUSBOHCI::ReturnAllTransactionsInEndpoint(AppleOHCIEndpointDescriptorPtr head, AppleOHCIEndpointDescriptorPtr tail)
{
AppleOHCIEndpointDescriptorPtr pED = head;
AppleOHCIGeneralTransferDescriptorPtr pTD;
UInt32 rem;
if (head == NULL)
return;
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;
ReturnOneTransaction(pTD, pED, kIOReturnNotResponding);
}
}
void
AppleUSBOHCI::UIMCheckForTimeouts(void)
{
AbsoluteTime currentTime;
AbsoluteTime lastRootHubChangeTime;
UInt64 elapsedTime = 0;
bool allPortsDisconnected = false;
if ( isInactive() || (_onCardBus && _pcCardEjected) || !_controllerAvailable || (_myBusState != kUSBBusStateRunning))
{
USBLog(7,"AppleUSBOHCI[%p] UIMCheckForTimeouts for bus %ld -- not appropriate", this, _busNumber);
return;
}
CheckEDListForTimeouts(_pControlHead, _pControlTail);
CheckEDListForTimeouts(_pBulkHead, _pBulkTail);
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,"AppleUSBOHCI[%p] Watchdog detected dead controller (hcca #: %ld, hc #: %ld)", 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 = HostToUSBLong(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;
IOSync();
_pOHCIRegisters->hcControl = HostToUSBLong(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)
{
USBError(1, "AppleUSBOHCI::UIMCreateIsochTransfer(LL) - old method");
return kIOReturnIPCError;
}
IOReturn
AppleUSBOHCI::UIMCreateIsochTransfer(IOUSBIsocCommand *command)
{
UInt8 direction = command->GetDirection();
USBDeviceAddress functionAddress = command->GetAddress();
UInt8 endpointNumber = command->GetEndpoint();
IOUSBIsocCompletion completion = command->GetUSLCompletion();
UInt64 frameNumberStart = command->GetStartFrame();
IOMemoryDescriptor * pBuffer = command->GetBuffer();
UInt32 frameCount = command->GetNumFrames();
IOUSBIsocFrame * pFrames = command->GetFrameList();
IOUSBLowLatencyIsocFrame * pLLFrames = (IOUSBLowLatencyIsocFrame *)pFrames;
UInt32 updateFrequency = command->GetUpdateFrequency();
bool requestFromRosettaClient = command->GetIsRosettaClient();
bool lowLatency = command->GetLowLatency();
IODMACommand * dmaCommand = command->GetDMACommand();
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;
UInt32 tdType;
IOByteCount transferOffset;
bool useUpdateFrequency = true;
UInt64 offset;
IODMACommand::Segment64 segments64[2];
IODMACommand::Segment32 segments32[2];
UInt32 edFlags;
UInt32 maxPacketSize;
if ( (frameCount == 0) || (frameCount > 1000) )
{
USBLog(3,"AppleUSBOHCI[%p]::UIMCreateIsochTransfer bad frameCount: %ld", this, frameCount);
return kIOReturnBadArgument;
}
if (direction == kUSBOut)
{
direction = kOHCIEDDirectionOut;
tdType = lowLatency ? kOHCIIsochronousOutLowLatencyType : kOHCIIsochronousOutType;
}
else if (direction == kUSBIn)
{
direction = kOHCIEDDirectionIn;
tdType = lowLatency ? kOHCIIsochronousInLowLatencyType : kOHCIIsochronousInType;
}
else
return kIOReturnInternalError;
if (!dmaCommand)
{
USBError(1,"AppleUSBOHCI[%p]::UIMCreateIsochTransfer no dmaCommand", this);
return kIOReturnInternalError;
}
if (dmaCommand->getMemoryDescriptor() != pBuffer)
{
USBError(1,"AppleUSBOHCI[%p]::UIMCreateIsochTransfer - memory desc in dmaCommand (%p) different than IOMD (%p)", this, dmaCommand->getMemoryDescriptor(), pBuffer);
return kIOReturnInternalError;
}
pED = FindIsochronousEndpoint(functionAddress, endpointNumber, direction, NULL);
if (!pED)
{
USBLog(3,"AppleUSBOHCI[%p]::UIMCreateIsochTransfer endpoint (%d) not found. Returning 0x%x", this, endpointNumber, kIOUSBEndpointNotFound);
return kIOUSBEndpointNotFound;
}
edFlags = USBToHostLong(pED->pShared->flags);
maxPacketSize = ( edFlags & kOHCIEDControl_MPS) >> kOHCIEDControl_MPSPhase;
if ( lowLatency && (updateFrequency == 0))
useUpdateFrequency = false;
if (frameNumberStart <= curFrameNumber)
{
if (frameNumberStart < (curFrameNumber - maxOffset))
{
USBLog(3,"AppleUSBOHCI[%p]::UIMCreateIsochTransfer request frame WAY too old. frameNumberStart: %ld, curFrameNumber: %ld. Returning 0x%x", this, (UInt32) frameNumberStart, (UInt32) curFrameNumber, kIOReturnIsoTooOld);
return kIOReturnIsoTooOld;
}
USBLog(6,"AppleUSBOHCI[%p]::UIMCreateIsochTransfer WARNING! curframe later than requested, expect some notSent errors! frameNumberStart: %ld, curFrameNumber: %ld. USBIsocFrame Ptr: %p, First ITD: %p", this, (UInt32) frameNumberStart, (UInt32) curFrameNumber, pFrames, pED->pLogicalTailP);
} else
{
if (frameNumberStart > (curFrameNumber + maxOffset))
{
USBLog(3,"AppleUSBOHCI[%p]::UIMCreateIsochTransfer request frame too far ahead! frameNumberStart: %ld, curFrameNumber: %ld, Returning 0x%x", this, (UInt32) frameNumberStart, (UInt32) curFrameNumber, kIOReturnIsoTooNew);
return kIOReturnIsoTooNew;
}
frameDiff = frameNumberStart - curFrameNumber;
diff32 = (UInt32)frameDiff;
if (diff32 < 2)
{
USBLog(5,"AppleUSBOHCI[%p]::UIMCreateIsochTransfer WARNING! - frameNumberStart less than 2 ms (is %ld)! frameNumberStart: %ld, curFrameNumber: %ld", this, (UInt32) diff32, (UInt32) frameNumberStart, (UInt32) curFrameNumber);
}
}
for ( i = 0; i< frameCount; i++)
{
if ((lowLatency ? pLLFrames[i].frReqCount : pFrames[i].frReqCount) > maxPacketSize)
{
USBLog(3,"AppleUSBOHCI[%p]::UIMCreateIsochTransfer Isoch frame (%ld) too big %d", this, i + 1, (lowLatency ? pLLFrames[i].frReqCount : pFrames[i].frReqCount));
return kIOReturnBadArgument;
}
bufferSize += (lowLatency ? pLLFrames[i].frReqCount : pFrames[i].frReqCount);
if (lowLatency)
pLLFrames[i].frStatus = requestFromRosettaClient ? (IOReturn) OSSwapInt32(kUSBLowLatencyIsochTransferKey) : (IOReturn) kUSBLowLatencyIsochTransferKey;
else
pFrames[i].frStatus = requestFromRosettaClient ? (IOReturn) OSSwapInt32(kUSBLowLatencyIsochTransferKey) : (IOReturn) kUSBLowLatencyIsochTransferKey;
}
USBLog(7,"AppleUSBOHCI[%p]::UIMCreateIsochTransfer transfer %s, buffer: %p, length: %ld frames: %ld, updateFreq: %ld", this, (direction == kOHCIEDDirectionIn) ? "in" : "out", pBuffer, bufferSize, frameCount, updateFrequency);
pNewITD = AllocateITD();
USBLog(7, "AppleUSBOHCI[%p]::UIMCreateIsochTransfer - new iTD %p", this, pNewITD);
if (pNewITD == NULL)
{
USBLog(1,"AppleUSBOHCI[%p]::UIMCreateIsochTransfer Could not allocate a new iTD", this);
return kIOReturnNoMemory;
}
if (!bufferSize)
{
numSegs = 1;
segments32[0].fIOVMAddr = segments32[0].fLength = 0;
pageOffset = 0;
}
pTailITD = (AppleOHCIIsochTransferDescriptorPtr)pED->pLogicalTailP; OSWriteLittleInt32(&pTailITD->pShared->nextTD, 0, pNewITD->pPhysical); pTailITD->pLogicalNext = pNewITD;
needNewITD = false;
transferOffset = 0;
while (curFrameInRequest < frameCount)
{
UInt16 thisFrameRequest = (lowLatency ? pLLFrames[curFrameInRequest].frReqCount : pFrames[curFrameInRequest].frReqCount);
if (!needNewITD && bufferSize && (thisFrameRequest != 0) )
{
numSegs = 2;
offset = transferOffset;
USBLog(7, "AppleUSBOHCI[%p]::UIMCreateIsochTransfer - calling gen64IOVMSegments - transferOffset (%d) offset (%Ld) thisFrameRequest (%d)", this, (int)transferOffset, offset, thisFrameRequest);
status = dmaCommand->gen64IOVMSegments(&offset, segments64, &numSegs);
if (status)
{
USBError(1, "AppleUSBOHCI[%p]::UIMCreateIsochTransfer - curFrameInRequest[%d] frameCount[%d] - got status (%p) from gen64IOVMSegments", this, (int)curFrameInRequest, (int)frameCount, (void*)status);
return status;
}
if (numSegs == 2)
{
USBLog(7, "AppleUSBOHCI[%p]::UIMCreateIsochTransfer - curFrameInRequest[%d] frameCount[%d] - after gen64IOVMSegments, offset (%Ld) numSegs (%d) segments64[0].fIOVMAddr (0x%Lx) segments64[0].fLength (0x%Lx) segments64[1].fIOVMAddr (0x%Lx) segments64[1].fLength (0x%Lx)", this, (int)curFrameInRequest, (int)frameCount, offset, (int)numSegs, segments64[0].fIOVMAddr, segments64[0].fLength, segments64[1].fIOVMAddr, segments64[1].fLength);
}
else
{
USBLog(7, "AppleUSBOHCI[%p]::UIMCreateIsochTransfer - curFrameInRequest[%d] frameCount[%d] - after gen64IOVMSegments, offset (%Ld) numSegs (%d) segments64[0].fIOVMAddr (0x%Lx) segments64[0].fLength (0x%Lx)", this, (int)curFrameInRequest, (int)frameCount, offset, (int)numSegs, segments64[0].fIOVMAddr, segments64[0].fLength);
}
for (i=0; i< numSegs; i++)
{
if (((UInt32)(segments64[i].fIOVMAddr >> 32) > 0) || ((UInt32)(segments64[i].fLength >> 32) > 0))
{
USBError(1, "AppleUSBOHCI[%p]::UIMCreateIsochTransfer - generated segments (%d) not 32 bit - offset (0x%Lx) length (0x%Lx) ", this, (int)i, segments64[0].fIOVMAddr, segments64[0].fLength);
return kIOReturnInternalError;
}
segments32[i].fIOVMAddr = (UInt32)segments64[i].fIOVMAddr;
segments32[i].fLength = (UInt32)segments64[i].fLength;
}
if (segments32[0].fLength >= thisFrameRequest)
{
segments32[0].fLength = thisFrameRequest;
numSegs = 1;
}
else if ((numSegs == 2) && ((thisFrameRequest - segments32[0].fLength) < segments32[1].fLength))
{
segments32[1].fLength = thisFrameRequest - segments32[0].fLength;
}
pageOffset = segments32[0].fIOVMAddr & kOHCIPageOffsetMask;
USBLog(7, "AppleUSBOHCI[%p]::UIMCreateIsochTransfer - adding segment 0 length (%d) to transferOffset", this, (int)segments32[0].fLength);
transferOffset += segments32[0].fLength;
segmentEnd = (segments32[0].fIOVMAddr + segments32[0].fLength ) & kOHCIPageOffsetMask;
USBLog(8,"curFrameInRequest: %ld, curFrameInTD: %ld, pageOffset: 0x%lx, numSegs: %ld, seg[0].location: 0x%lx, seg[0].length: %ld", curFrameInRequest, curFrameInTD, pageOffset, numSegs, segments32[0].fIOVMAddr, segments32[0].fLength);
if(numSegs == 2)
{
USBLog(7, "AppleUSBOHCI[%p]::UIMCreateIsochTransfer - adding segment 1 length (%d) to transferOffset", this, (int)segments32[1].fLength);
transferOffset += segments32[1].fLength;
USBLog(8 ,"seg[1].location: 0x%lx, seg[1].length %ld", segments32[1].fIOVMAddr, segments32[1].fLength);
if ( (_errataBits & kErrataNECOHCIIsochWraparound) && ((segments32[0].fIOVMAddr & kOHCIPageMask) == (segments32[1].fIOVMAddr & kOHCIPageMask)) )
{
USBLog(3,"AppleUSBOHCI[%p]::UIMCreateIsochTransfer On an NEC controller and frame data wraps from end of buffer to beginning. Dropping data to avoid controller hang", this);
numSegs = 1;
}
}
if ( (segments32[numSegs-1].fIOVMAddr & kOHCIPageMask) != ((segments32[numSegs-1].fIOVMAddr + segments32[numSegs-1].fLength) & kOHCIPageMask))
{
multiPageSegment = true;
USBLog(8,"We have a segment that crosses a page boundary: start: %p, length: %p, end: %p, curFrameinTD: %d", (void*)segments32[numSegs-1].fIOVMAddr, (void*)segments32[numSegs-1].fLength, (void*)(segments32[numSegs-1].fIOVMAddr + segments32[numSegs-1].fLength), (int)curFrameInTD);
}
else
multiPageSegment = false;
}
if (curFrameInTD == 0)
{
physPageStart = segments32[0].fIOVMAddr & 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 ((segments32[0].fIOVMAddr & kOHCIPageMask) != physPageStart)
{
if ( (pageSelectMask && (((segments32[0].fIOVMAddr & kOHCIPageMask) != physPageEnd) || numSegs == 2)) )
{
needNewITD = true;
USBLog(8, "AppleUSBOHCI[%p]::UIMCreateIsochTransfer - got it! (%ld, 0x%lx, 0x%lx, %ld)", this, pageSelectMask, ((UInt32)segments32[0].fIOVMAddr) & kOHCIPageMask, physPageEnd, numSegs);
}
else if ( pageSelectMask && multiPageSegment )
{
needNewITD = true;
USBLog(8,"AppleUSBOHCI[%p]::UIMCreateIsochTransfer This frame spans 2 or more pages and we already used our page crossing ", this);
}
else if ( (prevFramesPage != (segments32[0].fIOVMAddr & kOHCIPageMask)) && (segmentEnd != 0) )
{
needNewITD = true;
USBLog(8,"AppleUSBOHCI[%p]::UIMCreateIsochTransfer This frame starts on a new page and the previous one did NOT end on a page boundary (%ld)", this, segmentEnd);
}
else
{
if (pageSelectMask == 0 )
{
USBLog(8,"Using our page crossing for this TD (0x%lx)", (UInt32)(segments32[numSegs-1].fIOVMAddr + segments32[numSegs-1].fIOVMAddr -1 ) & kOHCIPageMask);
}
pageSelectMask = kOHCIPageSize; physPageEnd = (segments32[numSegs-1].fIOVMAddr + segments32[numSegs-1].fLength) & kOHCIPageMask;
}
}
prevFramesPage = (segments32[numSegs-1].fIOVMAddr + segments32[numSegs-1].fLength) & kOHCIPageMask;
if ( (curFrameInTD > 7) || needNewITD || (lowLatency && useUpdateFrequency && (curFrameInTD >= updateFrequency)) )
{
needNewITD = true; itdFlags |= (curFrameInTD-1) << kOHCIITDControl_FCPhase;
OSWriteLittleInt32(&pTailITD->pShared->bufferEnd, 0, lastPhysical);
curFrameInTD = 0;
pNewITD = AllocateITD();
USBLog(7, "AppleUSBOHCI[%p]::UIMCreateIsochTransfer - new iTD %p (curFrameInRequest: %ld, curFrameInTD: %ld, needNewITD: %d, updateFrequency: %ld", this, pNewITD, curFrameInRequest, curFrameInTD, needNewITD, updateFrequency);
if (pNewITD == NULL)
{
status = kIOReturnNoMemory;
break;
}
itdFlags |= (kOHCIGTDConditionNotAccessed << kOHCIGTDControl_CCPhase);
OSWriteLittleInt32(&pTailITD->pShared->flags, 0, itdFlags);
pTailITD->completion.action = NULL;
pTailITD->requestFromRosettaClient = requestFromRosettaClient;
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 = segments32[numSegs-1].fIOVMAddr + segments32[numSegs-1].fLength - 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;
pTailITD->requestFromRosettaClient = requestFromRosettaClient;
pED->pLogicalTailP = pNewITD;
OSWriteLittleInt32(&pED->pShared->tdQueueTailPtr, 0, pNewITD->pPhysical);
}
return status;
}
IOReturn
AppleUSBOHCI::GetFrameNumberWithTime(UInt64* frameNumber, AbsoluteTime *theTime)
{
if (!_commandGate)
return kIOReturnUnsupported;
return _commandGate->runAction(GatedGetFrameNumberWithTime, frameNumber, theTime);
}
IOReturn
AppleUSBOHCI::GatedGetFrameNumberWithTime(OSObject *owner, void* arg0, void* arg1, void* arg2, void* arg3)
{
AppleUSBOHCI *me = (AppleUSBOHCI*)owner;
UInt64 *frameNumber = (UInt64*)arg0;
AbsoluteTime *theTime = (AbsoluteTime*)arg1;
*frameNumber = me->_anchorFrame;
*theTime = me->_anchorTime;
return kIOReturnSuccess;
}
IOReturn
AppleUSBOHCI::UIMEnableAddressEndpoints(USBDeviceAddress address, bool enable)
{
AppleOHCIEndpointDescriptorPtr pEDQueue;
UInt32 edFlags;
int i;
USBLog(2, "AppleUSBOHCI[%p]::UIMEnableAddressEndpoints(%d, %s)", this, (int)address, enable ? "true" : "false");
pEDQueue = _pControlHead;
while (pEDQueue != _pControlTail)
{
edFlags = USBToHostLong(pEDQueue->pShared->flags);
if ((edFlags & kOHCIEDControl_FA) == address)
{
USBLog(2, "AppleUSBOHCI[%p]::UIMEnableAddressEndpoints - found control ED[%p] which matches - %s", this, pEDQueue, enable ? "enabling" : "disabling");
if (enable)
{
if (!(edFlags & kOHCISkipped))
{
USBLog(2, "AppleUSBOHCI[%p]::UIMEnableAddressEndpoints - HMMM - it was NOT marked as skipped..", this);
}
edFlags &= ~kOHCISkipped;
}
else
{
if (edFlags & kOHCISkipped)
{
USBLog(2, "AppleUSBOHCI[%p]::UIMEnableAddressEndpoints - HMMM - it was already marked as skipped..", this);
}
edFlags |= kOHCISkipped;
}
pEDQueue->pShared->flags = HostToUSBLong(edFlags);
IOSync();
}
pEDQueue = (AppleOHCIEndpointDescriptorPtr) pEDQueue->pLogicalNext;
}
pEDQueue = _pBulkHead;
while (pEDQueue != _pBulkTail)
{
edFlags = USBToHostLong(pEDQueue->pShared->flags);
if ((edFlags & kOHCIEDControl_FA) == address)
{
USBLog(2, "AppleUSBOHCI[%p]::UIMEnableAddressEndpoints - found Bulk ED[%p] which matches - %s", this, pEDQueue, enable ? "enabling" : "disabling");
if (enable)
{
if (!(edFlags & kOHCISkipped))
{
USBLog(2, "AppleUSBOHCI[%p]::UIMEnableAddressEndpoints - HMMM - it was NOT marked as skipped..", this);
}
edFlags &= ~kOHCISkipped;
}
else
{
if (edFlags & kOHCISkipped)
{
USBLog(2, "AppleUSBOHCI[%p]::UIMEnableAddressEndpoints - HMMM - it was already marked as skipped..", this);
}
edFlags |= kOHCISkipped;
}
pEDQueue->pShared->flags = HostToUSBLong(edFlags);
IOSync();
}
pEDQueue = (AppleOHCIEndpointDescriptorPtr) pEDQueue->pLogicalNext;
}
for (i = 0; i < 63; i++)
{
pEDQueue = _pInterruptHead[i].pHead;
while (pEDQueue != _pInterruptHead[i].pTail)
{
edFlags = USBToHostLong(pEDQueue->pShared->flags);
if ((edFlags & kOHCIEDControl_FA) == address)
{
USBLog(2, "AppleUSBOHCI[%p]::UIMEnableAddressEndpoints - found Interrupt ED[%p] which matches - %s", this, pEDQueue, enable ? "enabling" : "disabling");
if (enable)
{
if (!(edFlags & kOHCISkipped))
{
USBLog(2, "AppleUSBOHCI[%p]::UIMEnableAddressEndpoints - HMMM - it was NOT marked as skipped..", this);
}
edFlags &= ~kOHCISkipped;
}
else
{
if (edFlags & kOHCISkipped)
{
USBLog(2, "AppleUSBOHCI[%p]::UIMEnableAddressEndpoints - HMMM - it was already marked as skipped..", this);
}
edFlags |= kOHCISkipped;
}
pEDQueue->pShared->flags = HostToUSBLong(edFlags);
IOSync();
}
pEDQueue = pEDQueue->pLogicalNext;
}
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBOHCI::UIMEnableAllEndpoints(bool enable)
{
AppleOHCIEndpointDescriptorPtr pEDQueue;
UInt32 edFlags;
int i;
USBLog(2, "AppleUSBOHCI[%p]::UIMEnableAllEndpoints(%s)", this, enable ? "true" : "false");
pEDQueue = _pControlHead;
while (pEDQueue != _pControlTail)
{
edFlags = USBToHostLong(pEDQueue->pShared->flags);
if ((edFlags & kOHCISkipped) && (edFlags & kOHCIEDControl_FA))
{
USBLog(2, "AppleUSBOHCI[%p]::UIMEnableAllEndpoints - found skipped Control ED[%p] for ADDR[%d] ", this, pEDQueue, (int)(edFlags & kOHCIEDControl_FA));
edFlags &= ~kOHCISkipped;
pEDQueue->pShared->flags = HostToUSBLong(edFlags);
IOSync();
}
pEDQueue = (AppleOHCIEndpointDescriptorPtr) pEDQueue->pLogicalNext;
}
pEDQueue = _pBulkHead;
while (pEDQueue != _pBulkTail)
{
edFlags = USBToHostLong(pEDQueue->pShared->flags);
if ((edFlags & kOHCISkipped) && (edFlags & kOHCIEDControl_FA))
{
USBLog(2, "AppleUSBOHCI[%p]::UIMEnableAllEndpoints - found skipped Bulk ED[%p] for ADDR[%d] ", this, pEDQueue, (int)(edFlags & kOHCIEDControl_FA));
edFlags &= ~kOHCISkipped;
pEDQueue->pShared->flags = HostToUSBLong(edFlags);
IOSync();
}
pEDQueue = (AppleOHCIEndpointDescriptorPtr) pEDQueue->pLogicalNext;
}
for (i = 0; i < 63; i++)
{
pEDQueue = _pInterruptHead[i].pHead;
while (pEDQueue != _pInterruptHead[i].pTail)
{
edFlags = USBToHostLong(pEDQueue->pShared->flags);
if ((edFlags & kOHCISkipped) && (edFlags & kOHCIEDControl_FA))
{
USBLog(2, "AppleUSBOHCI[%p]::UIMEnableAllEndpoints - found skipped Interrupt ED[%p] for ADDR[%d] ", this, pEDQueue, (int)(edFlags & kOHCIEDControl_FA));
edFlags &= ~kOHCISkipped;
pEDQueue->pShared->flags = HostToUSBLong(edFlags);
IOSync();
}
pEDQueue = pEDQueue->pLogicalNext;
}
}
return kIOReturnSuccess;
}