#include <libkern/OSByteOrder.h>
extern "C" {
#include <kern/clock.h>
}
#include <IOKit/IOFilterInterruptEventSource.h>
#include <IOKit/IOMemoryCursor.h>
#include <IOKit/IOMessage.h>
#include <IOKit/pccard/IOPCCard.h>
#include <IOKit/usb/USB.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
#define NUM_BUFFER_PAGES 9 // 54
#define NUM_TDS 255 // 1500
#define NUM_EDS 256 // 1500
#define NUM_ITDS 192 // 1300
static int GetEDType(AppleOHCIEndpointDescriptorPtr pED);
extern void print_td(AppleOHCIGeneralTransferDescriptorPtr pTD);
extern void print_itd(AppleOHCIIsochTransferDescriptorPtr x);
OSDefineMetaClassAndStructors(AppleUSBOHCI, IOUSBController)
bool
AppleUSBOHCI::init(OSDictionary * propTable)
{
if (!super::init(propTable)) return false;
_ohciBusState = kOHCIBusStateOff;
_ohciAvailable = true;
_intLock = IOLockAlloc();
if (!_intLock)
return(false);
_wdhLock = IOSimpleLockAlloc();
if (!_wdhLock)
return(false);
_uimInitialized = false;
_producerCount = 1;
_consumerCount = 1;
return (true);
}
bool
AppleUSBOHCI::start( IOService * provider )
{
UInt32 ext1;
USBLog(5,"+%s[%p]::start", getName(), this);
if( !super::start(provider))
return false;
initForPM(_device);
clock_get_uptime(&_lastCheckedTime);
USBLog(5,"-%s[%p]::start", getName(), this);
return true;
}
void
AppleUSBOHCI::SetVendorInfo(void)
{
OSData *vendProp, *deviceProp, *revisionProp;
vendProp = (OSData *) _device->getProperty( "vendor-id" );
if (vendProp)
_vendorID = *((UInt32 *) vendProp->getBytesNoCopy());
deviceProp = (OSData *) _device->getProperty( "device-id" );
if (deviceProp)
_deviceID = *((UInt32 *) deviceProp->getBytesNoCopy());
revisionProp = (OSData *) _device->getProperty( "revision-id" );
if (revisionProp)
_revisionID = *((UInt32 *) revisionProp->getBytesNoCopy());
}
IOReturn
AppleUSBOHCI::UIMInitialize(IOService * provider)
{
IOReturn err = kIOReturnSuccess;
UInt32 lvalue;
IOPhysicalAddress hcDoneHead;
USBLog(5,"%s[%p]: initializing UIM", getName(), this);
_device = OSDynamicCast(IOPCIDevice, provider);
if(_device == NULL)
return kIOReturnBadArgument;
do {
if (!(_deviceBase = provider->mapDeviceMemoryWithIndex(0)))
{
USBError(1,"%s[%p]: unable to get device memory", getName(), this);
break;
}
USBLog(3, "%s: config @ %lx (%lx)", getName(),
(long)_deviceBase->getVirtualAddress(),
_deviceBase->getPhysicalAddress());
SetVendorInfo();
_filterInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this,
AppleUSBOHCI::InterruptHandler,
AppleUSBOHCI::PrimaryInterruptFilter,
provider );
if ( !_filterInterruptSource )
{
USBError(1,"%s[%p]: unable to get filterInterruptEventSource", getName(), this);
break;
}
err = _workLoop->addEventSource(_filterInterruptSource);
if ( err != kIOReturnSuccess )
{
USBError(1,"%s[%p]: unable to add filter event source: 0x%x", getName(), this, err);
break;
}
_genCursor = IONaturalMemoryCursor::withSpecification(PAGE_SIZE, PAGE_SIZE);
if(!_genCursor)
break;
_isoCursor = IONaturalMemoryCursor::withSpecification(kUSBMaxIsocFrameReqCount, kUSBMaxIsocFrameReqCount);
if(!_isoCursor)
break;
_errataBits = GetErrataBits(_vendorID, _deviceID, _revisionID);
if (_errataBits & kErrataLucentSuspendResume)
{
OSData *suspendProp;
UInt32 portBitmap = 0;
suspendProp = (OSData *) provider->getProperty( "AAPL,SuspendablePorts" );
if (suspendProp)
{
portBitmap = *((UInt32 *) suspendProp->getBytesNoCopy());
_disablePortsBitmap = (0xffffffff & (~portBitmap));
}
else
_disablePortsBitmap = (0xffffffff);
}
USBLog(5,"%s: errata bits=%lx", getName(), _errataBits);
_pageSize = PAGE_SIZE;
_pOHCIRegisters = (OHCIRegistersPtr) _deviceBase->getVirtualAddress();
#if (DEBUGGING_LEVEL > 2)
dumpRegs();
#endif
lvalue = _device->configRead32(cwCommand);
_device->configWrite32(cwCommand, (lvalue & 0xffff0000) | (cwCommandEnableBusMaster | cwCommandEnableMemorySpace));
hcDoneHead = USBToHostLong(_pOHCIRegisters->hcDoneHead);
if ( hcDoneHead != NULL )
{
USBError(1,"%s[%p]::UIMInitialize Non-NULL hcDoneHead: %p", getName(), this, hcDoneHead );
_pOHCIRegisters->hcCommandStatus = USBToHostLong(kOHCIHcCommandStatus_HCR); IOSleep(3);
}
_pOHCIRegisters->hcControlCurrentED = 0;
_pOHCIRegisters->hcControlHeadED = 0;
IOSync();
_pHCCA = (Ptr) IOMallocContiguous(kHCCAsize, kHCCAalignment, &_hccaPhysAddr);
if (!_pHCCA)
{
USBError(1,"%s[%p]: Unable to allocate memory (2)", getName(), this);
err = kIOReturnNoMemory;
break;
}
OSWriteLittleInt32(&_pOHCIRegisters->hcHCCA, 0, _hccaPhysAddr);
IOSync();
_pOHCIRegisters->hcInterruptStatus = USBToHostLong(kOHCIHcInterrupt_WDH);
IOSync();
_workLoop->enableAllInterrupts();
_rootHubFuncAddress = 1;
if ((err = IsochronousInitialize())) break;
if ((err = InterruptInitialize())) break;
if ((err = BulkInitialize())) break;
if ((err = ControlInitialize())) break;
UInt32 hcFSMPS; UInt32 hcFI; UInt32 hcPS;
hcFI = USBToHostLong(_pOHCIRegisters->hcFmInterval) & kOHCIHcFmInterval_FI;
hcFSMPS = ((((hcFI-kOHCIMax_OverHead) * 6)/7) << kOHCIHcFmInterval_FSMPSPhase);
hcPS = (hcFI * 9) / 10; _pOHCIRegisters->hcFmInterval = HostToUSBLong(hcFI | hcFSMPS);
_pOHCIRegisters->hcPeriodicStart = HostToUSBLong(hcPS);
IOSync();
if (_errataBits & kErrataNeedsPortPowerOff)
{
USBError(1, "%s[%p]::UIMInitialize error, turning off power to ports to clear", getName(), this);
OHCIRootHubPower(0 );
}
_pOHCIRegisters->hcControl = HostToUSBLong ((kOHCIFunctionalState_Reset << kOHCIHcControl_HCFSPhase));
IOSync();
_pOHCIRegisters->hcControl = HostToUSBLong ((kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase)
| kOHCIHcControl_CLE | kOHCIHcControl_BLE
| kOHCIHcControl_PLE | kOHCIHcControl_IE);
IOSync();
if (_errataBits & kErrataDisableOvercurrent)
_pOHCIRegisters->hcRhDescriptorA |= USBToHostLong(kOHCIHcRhDescriptorA_NOCP);
_pOHCIRegisters->hcRhStatus = HostToUSBLong(kOHCIHcRhStatus_OCIC | kOHCIHcRhStatus_DRWE); IOSync();
OHCIRootHubPower(1 );
_pOHCIRegisters->hcInterruptEnable = HostToUSBLong (kOHCIHcInterrupt_MIE | kOHCIDefaultInterrupts);
IOSync();
if (_errataBits & kErrataLSHSOpti)
OptiLSHSFix();
_uimInitialized = true;
return(kIOReturnSuccess);
} while (false);
USBError(1, "%s[%p]::UIMInitialize error(%x)", getName(), this, err);
UIMFinalize();
if (_filterInterruptSource)
{
_filterInterruptSource->release();
_filterInterruptSource = NULL;
}
return(err);
}
IOReturn
AppleUSBOHCI::UIMFinalize(void)
{
USBLog (3, "%s[%p]: @ %lx (%lx)(shutting down HW)",getName(),this,
(long)_deviceBase->getVirtualAddress(),
_deviceBase->getPhysicalAddress());
_workLoop->disableAllInterrupts();
if ( !isInactive() )
{
_pOHCIRegisters->hcInterruptDisable = HostToUSBLong(kOHCIHcInterrupt_MIE);
IOSync();
_pOHCIRegisters->hcControl = HostToUSBLong((kOHCIFunctionalState_Reset << kOHCIHcControl_HCFSPhase));
IOSync();
IOSleep(2);
_device->configWrite32(cwCommand, cwCommandEnableMemorySpace);
_pOHCIRegisters->hcHCCA = 0;
_pOHCIRegisters->hcControlHeadED = 0;
_pOHCIRegisters->hcControlCurrentED = 0;
_pOHCIRegisters->hcBulkHeadED = 0;
_pOHCIRegisters->hcBulkCurrentED = 0;
IOSync();
OHCIRootHubPower(0 );
_pOHCIRegisters->hcCommandStatus = HostToUSBLong(kOHCIHcCommandStatus_HCR); IOSync();
IOSleep(1); }
_pFreeITD = NULL;
_pLastFreeITD = NULL;
if (_itdMBHead)
{
AppleUSBOHCIitdMemoryBlock *curBlock = _itdMBHead;
AppleUSBOHCIitdMemoryBlock *nextBlock;
_itdMBHead = NULL;
while (curBlock)
{
nextBlock = curBlock->GetNextBlock();
curBlock->release();
curBlock = nextBlock;
}
}
_pFreeTD = NULL;
_pLastFreeTD = NULL;
if (_gtdMBHead)
{
AppleUSBOHCIgtdMemoryBlock *curBlock = _gtdMBHead;
AppleUSBOHCIgtdMemoryBlock *nextBlock;
_gtdMBHead = NULL;
while (curBlock)
{
nextBlock = curBlock->GetNextBlock();
curBlock->release();
curBlock = nextBlock;
}
}
_pFreeED = NULL;
_pLastFreeED = NULL;
if (_edMBHead)
{
AppleUSBOHCIedMemoryBlock *curBlock = _edMBHead;
AppleUSBOHCIedMemoryBlock *nextBlock;
_edMBHead = NULL;
while (curBlock)
{
nextBlock = curBlock->GetNextBlock();
curBlock->release();
curBlock = nextBlock;
}
}
IOFree ( _pHCCA, kHCCAsize );
if ( _filterInterruptSource )
{
_workLoop->removeEventSource(_filterInterruptSource);
_filterInterruptSource->release();
_filterInterruptSource = NULL;
}
if ( _genCursor )
{
_genCursor->release();
_genCursor = NULL;
}
if ( _isoCursor )
{
_isoCursor->release();
_isoCursor = NULL;
}
_uimInitialized = false;
return(kIOReturnSuccess);
}
void
AppleUSBOHCI::doCallback(AppleOHCIGeneralTransferDescriptorPtr nextTD,
UInt32 transferStatus,
UInt32 bufferSizeRemaining)
{
AppleOHCIGeneralTransferDescriptorPtr pCurrentTD, pTempTD;
AppleOHCIEndpointDescriptorPtr pED;
IOPhysicalAddress PhysAddr;
pED = nextTD->pEndpoint;
pED->pShared->flags |= HostToUSBWord(kOHCIEDControl_K); PhysAddr = (IOPhysicalAddress) USBToHostLong(pED->pShared->tdQueueHeadPtr) & kOHCIHeadPMask;
nextTD = AppleUSBOHCIgtdMemoryBlock::GetGTDFromPhysical(PhysAddr);
pCurrentTD = nextTD;
if(pCurrentTD == NULL)
{
USBLog(3, "%s[%p]::doCallback No transfer descriptors!", getName(), this);
return;
}
USBLog(5, "AppleUSBOHCI::doCallback: pCurrentTD = %p, pED->pLogicalTailP = %p", pCurrentTD, pED->pLogicalTailP);
while (pCurrentTD != pED->pLogicalTailP)
{
pED->pShared->tdQueueHeadPtr = pCurrentTD->pShared->nextTD | (pED->pShared->tdQueueHeadPtr & HostToUSBLong(~kOHCIHeadPointer_headP));
USBLog(5, "AppleUSBOHCI::doCallback- queueheadptr is now %p", pED->pShared->tdQueueHeadPtr);
bufferSizeRemaining += findBufferRemaining (pCurrentTD);
pCurrentTD->pShared->currentBufferPtr = NULL;
if (pCurrentTD->uimFlags & kUIMFlagsCallbackTD)
{
IOUSBCompletion completion;
if (transferStatus == kOHCIGTDConditionDataUnderrun)
{
USBLog(5, "AppleUSBOHCI::doCallback- found callback TD, setting queuehead to %p", pED->pShared->tdQueueHeadPtr & HostToUSBLong(~kOHCIHeadPointer_H));
pED->pShared->tdQueueHeadPtr = pED->pShared->tdQueueHeadPtr & HostToUSBLong(~kOHCIHeadPointer_H);
transferStatus = 0;
}
completion = pCurrentTD->command->GetUSLCompletion();
pCurrentTD->uimFlags &= ~kUIMFlagsCallbackTD;
DeallocateTD(pCurrentTD);
pED->pShared->flags &= ~HostToUSBWord(kOHCIEDControl_K); Complete(completion,
TranslateStatusToUSBError(transferStatus),
bufferSizeRemaining);
bufferSizeRemaining = 0;
return;
}
pTempTD = pCurrentTD->pLogicalNext;
DeallocateTD(pCurrentTD);
pCurrentTD = pTempTD;
}
}
UInt32
AppleUSBOHCI::findBufferRemaining (AppleOHCIGeneralTransferDescriptorPtr pCurrentTD)
{
UInt32 pageMask;
UInt32 bufferSizeRemaining;
pageMask = ~(_pageSize - 1);
if (pCurrentTD->pShared->currentBufferPtr == 0)
{
bufferSizeRemaining = 0;
}
else if ((USBToHostLong(pCurrentTD->pShared->bufferEnd) & (pageMask)) ==
(USBToHostLong(pCurrentTD->pShared->currentBufferPtr)& (pageMask)))
{
bufferSizeRemaining =
(USBToHostLong (pCurrentTD->pShared->bufferEnd) & ~pageMask) -
(USBToHostLong (pCurrentTD->pShared->currentBufferPtr) & ~pageMask) + 1;
}
else
{
bufferSizeRemaining =
((USBToHostLong(pCurrentTD->pShared->bufferEnd) & ~pageMask) + 1) +
(_pageSize - (USBToHostLong(pCurrentTD->pShared->currentBufferPtr) & ~pageMask));
}
return (bufferSizeRemaining);
}
IOReturn
AppleUSBOHCI::ControlInitialize(void)
{
AppleOHCIEndpointDescriptorPtr pED, pED2;
pED = AllocateED();
if ( pED == NULL )
return kIOReturnNoMemory;
pED->pShared->flags = HostToUSBLong (kOHCIEDControl_K);
pED->pShared->nextED = 0; _pControlTail = pED;
pED2 = AllocateED();
if ( pED2 == NULL )
return kIOReturnNoMemory;
pED2->pShared->flags = HostToUSBLong (kOHCIEDControl_K);
_pControlHead = pED2;
_pOHCIRegisters->hcControlHeadED = HostToUSBLong ((UInt32) pED2->pPhysical);
pED2->pShared->nextED = HostToUSBLong ((UInt32) pED->pPhysical);
pED2->pLogicalNext = pED;
return kIOReturnSuccess;
}
IOReturn
AppleUSBOHCI::BulkInitialize (void)
{
AppleOHCIEndpointDescriptorPtr pED, pED2;
pED = AllocateED();
if ( pED == NULL )
return kIOReturnNoMemory;
pED->pShared->flags = HostToUSBLong (kOHCIEDControl_K);
pED->pShared->nextED = NULL; _pBulkTail = pED;
pED2 = AllocateED();
if ( pED2 == NULL ) return kIOReturnNoMemory;
pED2->pShared->flags = HostToUSBLong (kOHCIEDControl_K);
_pBulkHead = pED2;
_pOHCIRegisters->hcBulkHeadED = HostToUSBLong ((UInt32) pED2->pPhysical);
pED2->pShared->nextED = HostToUSBLong ((UInt32) pED->pPhysical);
pED2->pLogicalNext = pED;
return kIOReturnSuccess;
}
IOReturn
AppleUSBOHCI::IsochronousInitialize(void)
{
AppleOHCIEndpointDescriptorPtr pED, pED2;
pED = AllocateED();
if ( pED == NULL )
return kIOReturnNoMemory;
pED->pShared->flags = HostToUSBLong (kOHCIEDControl_K);
pED->pShared->nextED = NULL; _pIsochTail = pED;
pED2 = AllocateED();
if ( pED2 == NULL )
return kIOReturnNoMemory;
pED2->pShared->flags = HostToUSBLong (kOHCIEDControl_K);
_pIsochHead = pED2;
pED2->pShared->nextED = HostToUSBLong ((UInt32) pED->pPhysical);
pED2->pLogicalNext = pED;
_isochBandwidthAvail = kUSBMaxIsocFrameReqCount;
return kIOReturnSuccess;
}
IOReturn
AppleUSBOHCI::InterruptInitialize (void)
{
UInt32 dummyControl;
int i, p, q, z;
AppleOHCIEndpointDescriptorPtr pED, pIsochHead;
dummyControl = kOHCIEDControl_K;
dummyControl |= 0; dummyControl = HostToUSBLong (dummyControl);
pIsochHead = (AppleOHCIEndpointDescriptorPtr) _pIsochHead;
for (i = 0; i < 63; i++)
{
pED = AllocateED();
if (pED == NULL)
{
return (kIOReturnNoMemory);
}
else
{
pED->pShared->flags = dummyControl;
pED->pShared->nextED = NULL; _pInterruptHead[i].pHead = pED;
_pInterruptHead[i].pHeadPhysical = pED->pPhysical;
_pInterruptHead[i].nodeBandwidth = 0;
}
if (i < 32)
((UInt32 *)_pHCCA)[i] = (UInt32) HostToUSBLong((UInt32) _pInterruptHead[i].pHeadPhysical);
}
p = 0;
q = 32;
for (i = 0; i < (32 +16 + 8 + 4 + 2); i++)
{
if (i < q/2+p)
z = i + q;
else
z = i + q/2;
if (i == p+q-1)
{
p = p + q;
q = q/2;
}
pED = _pInterruptHead[i].pHead;
pED->pShared->nextED = HostToUSBLong (_pInterruptHead[z].pHeadPhysical);
pED->pLogicalNext = _pInterruptHead[z].pHead;
_pInterruptHead[i].pTail = (AppleOHCIEndpointDescriptorPtr) pED->pLogicalNext;
}
i = 62;
pED = _pInterruptHead[i].pHead;
pED->pShared->nextED = HostToUSBLong (pIsochHead->pPhysical);
pED->pLogicalNext = _pIsochHead;
_pInterruptHead[i].pTail = (AppleOHCIEndpointDescriptorPtr) pED->pLogicalNext;
return kIOReturnSuccess;
}
AppleOHCIIsochTransferDescriptorPtr
AppleUSBOHCI::AllocateITD(void)
{
AppleOHCIIsochTransferDescriptorPtr freeITD;
freeITD = _pFreeITD;
if (freeITD == NULL)
{
AppleUSBOHCIitdMemoryBlock *memBlock;
UInt32 numTDs, i;
memBlock = AppleUSBOHCIitdMemoryBlock::NewMemoryBlock();
if (!memBlock)
{
USBLog(1, "%s[%p]::AllocateTD - unable to allocate a new memory block!", getName(), this);
return NULL;
}
memBlock->SetNextBlock(_itdMBHead);
_itdMBHead = memBlock;
numTDs = memBlock->NumITDs();
_pLastFreeITD = memBlock->GetITD(0);
_pFreeITD = _pLastFreeITD;
_pFreeITD->pPhysical = memBlock->GetSharedPhysicalPtr(0);
_pFreeITD->pShared = memBlock->GetSharedLogicalPtr(0);
USBLog(7, "%s[%p]::AllocateITD - _pFreeITD (%p), _pFreeITD->pPhysical(%p), _pFreeITD->pShared (%p), GetITDFromPhysical(%p)",
getName(), this, _pFreeITD, _pFreeITD->pPhysical, _pFreeITD->pShared, AppleUSBOHCIitdMemoryBlock::GetITDFromPhysical(_pFreeITD->pPhysical));
for (i=1; i < numTDs; i++)
{
freeITD = memBlock->GetITD(i);
if (!freeITD)
{
USBLog(1, "%s[%p]::AllocateTD - hmm. ran out of TDs in a memory block", getName(), this);
freeITD = _pFreeITD;
break;
}
freeITD->pLogicalNext = _pFreeITD;
freeITD->pPhysical = memBlock->GetSharedPhysicalPtr(i);
freeITD->pShared = memBlock->GetSharedLogicalPtr(i);
_pFreeITD = freeITD;
}
}
_pFreeITD = freeITD->pLogicalNext;
freeITD->pLogicalNext = NULL;
freeITD->uimFlags = 0;
return freeITD;
}
AppleOHCIGeneralTransferDescriptorPtr
AppleUSBOHCI::AllocateTD(void)
{
AppleOHCIGeneralTransferDescriptorPtr freeTD;
freeTD = _pFreeTD;
if (freeTD == NULL)
{
AppleUSBOHCIgtdMemoryBlock *memBlock;
UInt32 numTDs, i;
memBlock = AppleUSBOHCIgtdMemoryBlock::NewMemoryBlock();
if (!memBlock)
{
USBLog(1, "%s[%p]::AllocateTD - unable to allocate a new memory block!", getName(), this);
return NULL;
}
memBlock->SetNextBlock(_gtdMBHead);
_gtdMBHead = memBlock;
numTDs = memBlock->NumGTDs();
_pLastFreeTD = memBlock->GetGTD(0);
_pFreeTD = _pLastFreeTD;
_pFreeTD->pPhysical = memBlock->GetSharedPhysicalPtr(0);
_pFreeTD->pShared = memBlock->GetSharedLogicalPtr(0);
USBLog(7, "%s[%p]::AllocateTD - _pFreeTD (%p), _pFreeTD->pPhysical(%p), _pFreeTD->pShared (%p), GetGTDFromPhysical(%p)",
getName(), this, _pFreeTD, _pFreeTD->pPhysical, _pFreeTD->pShared, AppleUSBOHCIgtdMemoryBlock::GetGTDFromPhysical(_pFreeTD->pPhysical));
for (i=1; i < numTDs; i++)
{
freeTD = memBlock->GetGTD(i);
if (!freeTD)
{
USBLog(1, "%s[%p]::AllocateTD - hmm. ran out of TDs in a memory block", getName(), this);
freeTD = _pFreeTD;
break;
}
freeTD->pLogicalNext = _pFreeTD;
freeTD->pPhysical = memBlock->GetSharedPhysicalPtr(i);
freeTD->pShared = memBlock->GetSharedLogicalPtr(i);
_pFreeTD = freeTD;
}
}
_pFreeTD = freeTD->pLogicalNext;
freeTD->pLogicalNext = NULL;
freeTD->uimFlags = 0;
freeTD->lastFrame = 0; freeTD->lastRemaining = 0;
return freeTD;
}
AppleOHCIEndpointDescriptorPtr
AppleUSBOHCI::AllocateED(void)
{
AppleOHCIEndpointDescriptorPtr freeED;
freeED = _pFreeED;
if (freeED == NULL)
{
AppleUSBOHCIedMemoryBlock *memBlock;
UInt32 numEDs, i;
memBlock = AppleUSBOHCIedMemoryBlock::NewMemoryBlock();
if (!memBlock)
{
USBLog(1, "%s[%p]::AllocateED - unable to allocate a new memory block!", getName(), this);
return NULL;
}
memBlock->SetNextBlock(_edMBHead);
_edMBHead = memBlock;
numEDs = memBlock->NumEDs();
_pLastFreeED = memBlock->GetED(0);
_pFreeED = _pLastFreeED;
_pFreeED->pPhysical = memBlock->GetSharedPhysicalPtr(0);
_pFreeED->pShared = memBlock->GetSharedLogicalPtr(0);
USBLog(7, "%s[%p]::AllocateED - _pFreeED (%p), _pFreeED->pPhysical(%p), _pFreeED->pShared (%p)",
getName(), this, _pFreeED, _pFreeED->pPhysical, _pFreeED->pShared);
for (i=1; i < numEDs; i++)
{
freeED = memBlock->GetED(i);
if (!freeED)
{
USBLog(1, "%s[%p]::AllocateED - hmm. ran out of EDs in a memory block", getName(), this);
freeED = _pFreeED;
break;
}
freeED->pLogicalNext = _pFreeED;
freeED->pPhysical = memBlock->GetSharedPhysicalPtr(i);
freeED->pShared = memBlock->GetSharedLogicalPtr(i);
_pFreeED = freeED;
}
}
_pFreeED = freeED->pLogicalNext;
freeED->pLogicalNext = NULL;
return freeED;
}
IOReturn
AppleUSBOHCI::DeallocateITD (AppleOHCIIsochTransferDescriptorPtr pTD)
{
UInt32 physical;
physical = pTD->pPhysical;
pTD->pLogicalNext = NULL;
pTD->pPhysical = physical;
if (_pFreeITD)
{
_pLastFreeITD->pLogicalNext = pTD;
_pLastFreeITD = pTD;
}
else
{
_pLastFreeITD = pTD;
_pFreeITD = pTD;
}
return (kIOReturnSuccess);
}
IOReturn
AppleUSBOHCI::DeallocateTD (AppleOHCIGeneralTransferDescriptorPtr pTD)
{
UInt32 physical;
physical = pTD->pPhysical;
pTD->pLogicalNext = NULL;
pTD->pPhysical = physical;
if (_pFreeTD)
{
_pLastFreeTD->pLogicalNext = pTD;
_pLastFreeTD = pTD;
} else {
_pLastFreeTD = pTD;
_pFreeTD = pTD;
}
return (kIOReturnSuccess);
}
IOReturn
AppleUSBOHCI::DeallocateED (AppleOHCIEndpointDescriptorPtr pED)
{
UInt32 physical;
physical = pED->pPhysical;
pED->pPhysical = physical;
pED->pLogicalNext = NULL;
if (_pFreeED){
_pLastFreeED->pLogicalNext = pED;
_pLastFreeED = pED;
} else {
_pLastFreeED = pED;
_pFreeED = pED;
}
return (kIOReturnSuccess);
}
int
GetEDType(AppleOHCIEndpointDescriptorPtr pED)
{
return ((USBToHostLong(pED->pShared->flags) & kOHCIEDControl_F) >> kOHCIEDControl_FPhase);
}
IOReturn
AppleUSBOHCI::RemoveAllTDs (AppleOHCIEndpointDescriptorPtr pED)
{
RemoveTDs(pED);
if (GetEDType(pED) == kOHCIEDFormatGeneralTD) {
DeallocateTD(
(AppleOHCIGeneralTransferDescriptorPtr) pED->pLogicalTailP);
}
else
{
DeallocateITD(
(AppleOHCIIsochTransferDescriptorPtr) pED->pLogicalTailP);
}
pED->pLogicalTailP = NULL;
return (0);
}
IOReturn
AppleUSBOHCI::RemoveTDs(AppleOHCIEndpointDescriptorPtr pED)
{
AppleOHCIGeneralTransferDescriptorPtr pCurrentTD, lastTD;
UInt32 bufferSizeRemaining = 0;
AppleOHCIIsochTransferDescriptorPtr pITD, pITDLast;
if (GetEDType(pED) == kOHCIEDFormatGeneralTD)
{
pCurrentTD = (AppleOHCIGeneralTransferDescriptorPtr) (USBToHostLong(pED->pShared->tdQueueHeadPtr) & kOHCIHeadPMask);
pCurrentTD = AppleUSBOHCIgtdMemoryBlock::GetGTDFromPhysical((IOPhysicalAddress) pCurrentTD);
lastTD = (AppleOHCIGeneralTransferDescriptorPtr) pED->pLogicalTailP;
pED->pLogicalHeadP = pED->pLogicalTailP;
while (pCurrentTD != lastTD)
{
if (pCurrentTD == NULL)
return (-1);
pED->pShared->tdQueueHeadPtr = pCurrentTD->pShared->nextTD;
pED->pLogicalHeadP = pCurrentTD->pLogicalNext;
bufferSizeRemaining += findBufferRemaining(pCurrentTD);
if (pCurrentTD->uimFlags & kUIMFlagsCallbackTD)
{
IOUSBCompletion completion = pCurrentTD->command->GetUSLCompletion();
pCurrentTD->uimFlags &= ~kUIMFlagsCallbackTD;
Complete(completion, kIOReturnAborted, bufferSizeRemaining);
bufferSizeRemaining = 0;
}
DeallocateTD(pCurrentTD);
pCurrentTD = (AppleOHCIGeneralTransferDescriptorPtr) pED->pLogicalHeadP;
}
}
else
{
UInt32 phys;
phys = (USBToHostLong(pED->pShared->tdQueueHeadPtr) & kOHCIHeadPMask);
pITD = AppleUSBOHCIitdMemoryBlock::GetITDFromPhysical(phys);
pITDLast = (AppleOHCIIsochTransferDescriptorPtr)pED->pLogicalTailP;
while (pITD != pITDLast)
{
AppleOHCIIsochTransferDescriptorPtr pPrevITD;
if (pITD == NULL)
return (-1);
pED->pShared->tdQueueHeadPtr = pITD->pShared->nextTD;
pED->pLogicalHeadP = pITD->pLogicalNext;
ProcessCompletedITD (pITD, kIOReturnAborted);
pPrevITD = pITD;
pITD = pITD->pLogicalNext;
DeallocateITD(pPrevITD);
}
}
return (0);
}
void
AppleUSBOHCI::ProcessCompletedITD (AppleOHCIIsochTransferDescriptorPtr pITD, IOReturn status)
{
IOUSBIsocFrame * pFrames;
IOUSBLowLatencyIsocFrame * pLLFrames;
int i;
int frameCount;
IOReturn aggregateStatus = kIOReturnSuccess;
IOReturn frameStatus;
UInt32 itdConditionCode;
bool hadUnderrun = false;
UInt32 delta;
UInt32 curFrame;
AbsoluteTime timeStop, timeStart;
UInt64 timeElapsed;
pFrames = pITD->pIsocFrame;
pLLFrames = (IOUSBLowLatencyIsocFrame *) pITD->pIsocFrame;
frameCount = (USBToHostLong(pITD->pShared->flags) & kOHCIITDControl_FC) >> kOHCIITDControl_FCPhase;
itdConditionCode = (USBToHostLong(pITD->pShared->flags) & kOHCIITDControl_CC) >> kOHCIITDControl_CCPhase;
if (itdConditionCode == kOHCIITDConditionDataOverrun)
{
status = kIOReturnIsoTooOld;
USBLog(5,"%s[%p]::ProcessCompletedITD: Data Overrun in Isoch xfer. Entire TD (%p) was too late, will return kIOReturnIsoTooOld (0x%x)", getName(), this,pITD, status);
}
if ( (_filterInterruptCount != 0 ) &&
( (pITD->pType == kOHCIIsochronousInLowLatencyType) ||
(pITD->pType == kOHCIIsochronousOutLowLatencyType) ) )
{
clock_get_uptime (&timeStop);
timeStart = pLLFrames[pITD->frameNum].frTimeStamp;
SUB_ABSOLUTETIME(&timeStop, &timeStart);
absolutetime_to_nanoseconds(timeStop, &timeElapsed);
if ( _lowLatencyIsochTDsProcessed != 0 )
{
USBLog(6, "%s[%p]::ProcessCompletedITD: LowLatency isoch TD's proccessed: %d, framesUpdated: %d, framesError: %d", getName(), this, _lowLatencyIsochTDsProcessed, _framesUpdated, _framesError);
USBLog(7, "%s[%p]::ProcessCompletedITD: delay in microsecs before callback (from hw interrupt time): %ld", getName(), this, (UInt32) timeElapsed / 1000);
}
_lowLatencyIsochTDsProcessed = 0;
_framesUpdated = 0;
_framesError = 0;
}
for (i=0; i <= frameCount; i++)
{
if ( (pITD->pType == kOHCIIsochronousInLowLatencyType) || (pITD->pType == kOHCIIsochronousOutLowLatencyType) )
{
UInt16 offset = USBToHostWord(pITD->pShared->offset[i]);
if ( (_filterInterruptCount != 0 ) &&
( (pITD->pType == kOHCIIsochronousInLowLatencyType) ||
(pITD->pType == kOHCIIsochronousOutLowLatencyType) ) )
{
if ( (pLLFrames[pITD->frameNum + i].frStatus != (IOReturn) kUSBLowLatencyIsochTransferKey) )
{
USBLog(6,"%s[%p]::ProcessCompletedITD: frame processed at hw interrupt time: frame: %d, frTimeStamp.lo: 0x%x", getName(), this, i, pLLFrames[pITD->frameNum + i].frTimeStamp.lo);
}
}
if ( ((offset & kOHCIITDOffset_CC) >> kOHCIITDOffset_CCPhase) == kOHCIITDOffsetConditionNotAccessed)
{
USBLog(6,"%s[%p]::ProcessCompletedITD: Isoch frame not accessed. Frame in request(1 based) %d, IsocFramePtr: %p, ITD: %p, Frames in this TD: %d, Relative frame in TD: %d", getName(), this, pITD->frameNum + i + 1, pLLFrames, pITD, frameCount+1, i+1);
pLLFrames[pITD->frameNum + i].frActCount = 0;
pLLFrames[pITD->frameNum + i].frStatus = kOHCIITDConditionNotAccessedReturn;
}
else
{
pLLFrames[pITD->frameNum + i].frStatus = (offset & kOHCIITDPSW_CC) >> kOHCIITDPSW_CCPhase;
if ( (kIOReturnSuccess == pLLFrames[pITD->frameNum + i].frStatus) &&
( (pITD->pType == kOHCIIsochronousOutType) || (pITD->pType == kOHCIIsochronousOutLowLatencyType) ) )
pLLFrames[pITD->frameNum + i].frActCount = pLLFrames[pITD->frameNum + i].frReqCount;
else
pLLFrames[pITD->frameNum + i].frActCount = offset & kOHCIITDPSW_Size;
}
frameStatus = pLLFrames[pITD->frameNum + i].frStatus;
if ( frameStatus != kIOReturnSuccess )
{
pLLFrames[pITD->frameNum + i].frStatus = TranslateStatusToUSBError(frameStatus);
if ( pLLFrames[pITD->frameNum + i].frStatus == kIOReturnUnderrun )
hadUnderrun = true;
else
aggregateStatus = pLLFrames[pITD->frameNum + i].frStatus;
}
}
else
{
UInt16 offset = USBToHostWord(pITD->pShared->offset[i]);
if ( ((offset & kOHCIITDOffset_CC) >> kOHCIITDOffset_CCPhase) == kOHCIITDOffsetConditionNotAccessed)
{
USBLog(6,"%s[%p]::ProcessCompletedITD: Isoch frame not accessed. Frame in request(1 based) %d, IsocFramePtr: %p, ITD: %p, Frames in this TD: %d, Relative frame in TD: %d", getName(), this, pITD->frameNum + i + 1, pFrames, pITD, frameCount+1, i+1);
pFrames[pITD->frameNum + i].frActCount = 0;
pFrames[pITD->frameNum + i].frStatus = kOHCIITDConditionNotAccessedReturn;
}
else
{
pFrames[pITD->frameNum + i].frStatus = (offset & kOHCIITDPSW_CC) >> kOHCIITDPSW_CCPhase;
if ( (kIOReturnSuccess == pFrames[pITD->frameNum + i].frStatus) &&
( (pITD->pType == kOHCIIsochronousOutType) || (pITD->pType == kOHCIIsochronousOutLowLatencyType) ) )
pFrames[pITD->frameNum + i].frActCount = pFrames[pITD->frameNum + i].frReqCount;
else
pFrames[pITD->frameNum + i].frActCount = offset & kOHCIITDPSW_Size;
}
frameStatus = pFrames[pITD->frameNum + i].frStatus;
if ( frameStatus != kIOReturnSuccess )
{
pFrames[pITD->frameNum + i].frStatus = TranslateStatusToUSBError(frameStatus);
if ( pFrames[pITD->frameNum + i].frStatus == kIOReturnUnderrun )
hadUnderrun = true;
else
aggregateStatus = pFrames[pITD->frameNum + i].frStatus;
}
}
}
if (pITD->completion.action)
{
IOUSBIsocCompletionAction pHandler;
if ( (status == kIOReturnSuccess) && ( (aggregateStatus != kIOReturnSuccess) || hadUnderrun) )
{
if ( (aggregateStatus == kIOReturnSuccess) && hadUnderrun )
aggregateStatus = kIOReturnUnderrun;
USBLog(6, "%s[%p]::ProcessCompletedITD: Changing isoc completion error from success to 0x%x", getName(), this, aggregateStatus);
status = aggregateStatus;
}
pHandler = pITD->completion.action;
pITD->completion.action = NULL;
(*pHandler) (pITD->completion.target, pITD->completion.parameter, status, pFrames);
}
}
void
AppleUSBOHCI::UIMProcessDoneQueue(IOUSBCompletionAction safeAction)
{
UInt32 interruptStatus;
IOPhysicalAddress PhysAddr;
AppleOHCIGeneralTransferDescriptorPtr pHCDoneTD;
UInt32 cachedProducer;
IOPhysicalAddress cachedWriteDoneQueueHead;
IOInterruptState intState;
intState = IOSimpleLockLockDisableInterrupt( _wdhLock );
cachedWriteDoneQueueHead = _savedDoneQueueHead;
cachedProducer = _producerCount;
IOSimpleLockUnlockEnableInterrupt( _wdhLock, intState );
DoDoneQueueProcessing( cachedWriteDoneQueueHead, cachedProducer, safeAction);
return;
}
IOReturn
AppleUSBOHCI::DoDoneQueueProcessing(IOPhysicalAddress cachedWriteDoneQueueHead, UInt32 cachedProducer, IOUSBCompletionAction safeAction)
{
UInt32 control, transferStatus;
long bufferSizeRemaining;
AppleOHCIGeneralTransferDescriptorPtr pHCDoneTD, prevTD, nextTD;
IOPhysicalAddress physicalAddress;
UInt32 pageMask;
AppleOHCIEndpointDescriptorPtr tempED;
AppleOHCIIsochTransferDescriptorPtr pITD, testITD;
volatile UInt32 cachedConsumer;
UInt32 numTDs = 0;
if (cachedWriteDoneQueueHead == NULL)
return kIOReturnSuccess;
cachedConsumer = _consumerCount;
if ( cachedConsumer == cachedProducer)
{
USBLog(3, "%s[%p]::DoDoneQueueProcessing consumer (%d) == producer (%d) Filter count: %d", getName(), this, cachedConsumer, cachedProducer, _filterInterruptCount);
return kIOReturnSuccess;
}
pHCDoneTD = AppleUSBOHCIgtdMemoryBlock::GetGTDFromPhysical(cachedWriteDoneQueueHead);
if ( pHCDoneTD == NULL )
return kIOReturnSuccess;
prevTD = NULL;
while ( true )
{
pHCDoneTD->pLogicalNext = prevTD;
prevTD = pHCDoneTD;
numTDs++;
cachedConsumer++;
if ( cachedProducer == cachedConsumer)
break;
physicalAddress = USBToHostLong(pHCDoneTD->pShared->nextTD) & kOHCIHeadPMask;
nextTD = AppleUSBOHCIgtdMemoryBlock::GetGTDFromPhysical(physicalAddress);
if ( nextTD == NULL )
{
USBLog(5, "%s[%p]::DoDoneQueueProcessing nextTD = NULL. (%p, %d, %d, %d)", getName(), this, physicalAddress, _filterInterruptCount, cachedProducer, cachedConsumer);
break;
}
pHCDoneTD = nextTD;
}
pHCDoneTD = prevTD;
_consumerCount = cachedConsumer;
while (pHCDoneTD != NULL)
{
IOReturn errStatus;
nextTD = pHCDoneTD->pLogicalNext;
control = USBToHostLong(pHCDoneTD->pShared->ohciFlags);
transferStatus = (control & kOHCIGTDControl_CC) >> kOHCIGTDControl_CCPhase;
errStatus = TranslateStatusToUSBError(transferStatus);
if (_OptiOn && (pHCDoneTD->pType == kOHCIOptiLSBug))
{
tempED = (AppleOHCIEndpointDescriptorPtr) pHCDoneTD->pEndpoint;
pHCDoneTD->pShared->ohciFlags = pHCDoneTD->pShared->ohciFlags & HostToUSBLong(kOHCIGTDClearErrorMask);
tempED->pShared->tdQueueHeadPtr &= HostToUSBLong(kOHCIHeadPMask);
pHCDoneTD->pShared->nextTD = tempED->pShared->tdQueueTailPtr & HostToUSBLong(kOHCIHeadPMask);
tempED->pShared->tdQueueTailPtr = HostToUSBLong(pHCDoneTD->pPhysical);
_pOHCIRegisters->hcCommandStatus = HostToUSBLong (kOHCIHcCommandStatus_CLF);
}
else if ((transferStatus == kOHCIGTDConditionBufferUnderrun) &&
(pHCDoneTD->pType == kOHCIBulkTransferOutType) &&
(_errataBits & kErrataRetryBufferUnderruns))
{
tempED = (AppleOHCIEndpointDescriptorPtr) pHCDoneTD->pEndpoint;
pHCDoneTD->pShared->ohciFlags = pHCDoneTD->pShared->ohciFlags & HostToUSBLong(kOHCIGTDClearErrorMask);
pHCDoneTD->pShared->nextTD = tempED->pShared->tdQueueHeadPtr & HostToUSBLong(kOHCIHeadPMask);
pHCDoneTD->pLogicalNext = AppleUSBOHCIgtdMemoryBlock::GetGTDFromPhysical(USBToHostLong(tempED->pShared->tdQueueHeadPtr) & kOHCIHeadPMask);
tempED->pShared->tdQueueHeadPtr = USBToHostLong(pHCDoneTD->pPhysical) | (tempED->pShared->tdQueueHeadPtr & HostToUSBLong( kOHCIEDToggleBitMask));
_pOHCIRegisters->hcCommandStatus = HostToUSBLong(kOHCIHcCommandStatus_BLF);
}
else if ( (pHCDoneTD->pType == kOHCIIsochronousInType) || (pHCDoneTD->pType == kOHCIIsochronousOutType) || (pHCDoneTD->pType == kOHCIIsochronousInLowLatencyType) || (pHCDoneTD->pType == kOHCIIsochronousOutLowLatencyType) )
{
pITD = (AppleOHCIIsochTransferDescriptorPtr) pHCDoneTD;
ProcessCompletedITD(pITD, errStatus);
DeallocateITD(pITD);
}
else
{
bufferSizeRemaining = findBufferRemaining (pHCDoneTD);
if (pHCDoneTD->uimFlags & kUIMFlagsCallbackTD)
{
IOUSBCompletion completion = pHCDoneTD->command->GetUSLCompletion();
if(!safeAction || (safeAction == completion.action))
{
pHCDoneTD->uimFlags &= ~kUIMFlagsCallbackTD;
Complete(completion, errStatus, bufferSizeRemaining);
DeallocateTD(pHCDoneTD);
}
else {
if(_pendingHead)
_pendingTail->pLogicalNext = pHCDoneTD;
else
_pendingHead = pHCDoneTD;
_pendingTail = pHCDoneTD;
}
}
else
{
if (errStatus != kIOReturnSuccess)
{
USBLog(5, "AppleUSBOHCI::DoDoneQueueProcessing - processing a short packet");
doCallback(pHCDoneTD, transferStatus, bufferSizeRemaining);
}
DeallocateTD(pHCDoneTD);
}
}
pHCDoneTD = nextTD;
}
return(kIOReturnSuccess);
}
void
AppleUSBOHCI::finishPending()
{
while(_pendingHead)
{
AppleOHCIGeneralTransferDescriptorPtr next = _pendingHead->pLogicalNext;
long bufferSizeRemaining = findBufferRemaining (_pendingHead);
UInt32 transferStatus = (USBToHostLong(_pendingHead->pShared->ohciFlags) & kOHCIGTDControl_CC) >> kOHCIGTDControl_CCPhase;
if (_pendingHead->uimFlags & kUIMFlagsCallbackTD)
{
IOUSBCompletion completion = _pendingHead->command->GetUSLCompletion();
_pendingHead->uimFlags &= ~kUIMFlagsCallbackTD;
Complete(completion, TranslateStatusToUSBError(transferStatus), bufferSizeRemaining);
}
DeallocateTD(_pendingHead);
_pendingHead = next;
}
}
UInt32
AppleUSBOHCI::GetBandwidthAvailable()
{
return _isochBandwidthAvail;
}
UInt64
AppleUSBOHCI::GetFrameNumber()
{
UInt64 bigFrameNumber;
UInt16 framenumber16;
framenumber16 = USBToHostWord(*(UInt16*)(_pHCCA + 0x80));
bigFrameNumber = _frameNumber + framenumber16;
if (framenumber16 < 200)
if (_pOHCIRegisters->hcInterruptStatus & HostToUSBLong(kOHCIHcInterrupt_FNO))
bigFrameNumber += kOHCIFrameOverflowBit;
return bigFrameNumber;
}
UInt32
AppleUSBOHCI::GetFrameNumber32()
{
UInt16 framenumber16;
UInt32 largishFrameNumber;
framenumber16 = USBToHostWord(*(UInt16*)(_pHCCA + 0x80));
largishFrameNumber = ((UInt32)_frameNumber) + framenumber16;
if (framenumber16 < 200)
if (_pOHCIRegisters->hcInterruptStatus & HostToUSBLong(kOHCIHcInterrupt_FNO))
largishFrameNumber += kOHCIFrameOverflowBit;
return largishFrameNumber;
}
void
AppleUSBOHCI::dumpRegs(void)
{
UInt32 lvalue;
lvalue = _device->configRead32(cwVendorID);
USBLog(5,"OHCI: cwVendorID=%lx", lvalue);
lvalue = _device->configRead32(clClassCodeAndRevID);
USBLog(5,"OHCI: clClassCodeAndRevID=%lx", lvalue);
lvalue = _device->configRead32(clHeaderAndLatency);
USBLog(5,"OHCI: clHeaderAndLatency=%lx", lvalue);
lvalue = _device->configRead32(clBaseAddressZero);
USBLog(5,"OHCI: clBaseAddressZero=%lx", lvalue);
lvalue = _device->configRead32(clBaseAddressOne);
USBLog(5,"OHCI: clBaseAddressOne=%lx", lvalue);
lvalue = _device->configRead32(clExpansionRomAddr);
USBLog(5,"OHCI: clExpansionRomAddr=%lx", lvalue);
lvalue = _device->configRead32(clLatGntIntPinLine);
USBLog(5,"OHCI: clLatGntIntPinLine=%lx", lvalue);
lvalue = _device->configRead32(clLatGntIntPinLine+4);
USBLog(5,"OHCI: clLatGntIntPinLine+4=%lx", lvalue);
lvalue = _device->configRead32(cwCommand);
USBLog(5,"OHCI: cwCommand=%lx", lvalue & 0x0000ffff);
USBLog(5,"OHCI: cwStatus=%lx", lvalue & 0xffff0000);
lvalue = _device->configRead32(cwCommand);
_device->configWrite32(cwCommand, lvalue);
_device->configWrite32(cwCommand, (lvalue & 0xffff0000) |
(cwCommandEnableBusMaster |
cwCommandEnableMemorySpace));
lvalue = _device->configRead32(cwCommand);
USBLog(5,"OHCI: cwCommand=%lx", lvalue & 0x0000ffff);
USBLog(5,"OHCI: cwStatus=%lx", lvalue & 0xffff0000);
USBLog(5,"OHCI: HcRevision=%lx", USBToHostLong((_pOHCIRegisters)->hcRevision));
USBLog(5," HcControl=%lx", USBToHostLong((_pOHCIRegisters)->hcControl));
USBLog(5," HcFmInterval=%lx", USBToHostLong((_pOHCIRegisters)->hcFmInterval));
USBLog(5," hcRhDescriptorA=%lx", USBToHostLong((_pOHCIRegisters)->hcRhDescriptorA));
USBLog(5," hcRhDescriptorB=%lx", USBToHostLong((_pOHCIRegisters)->hcRhDescriptorB));
}
IOReturn
AppleUSBOHCI::TranslateStatusToUSBError(UInt32 status)
{
static const UInt32 statusToErrorMap[] = {
kIOReturnSuccess,
kIOUSBCRCErr,
kIOUSBBitstufErr,
kIOUSBDataToggleErr,
kIOUSBPipeStalled,
kIOReturnNotResponding,
kIOUSBPIDCheckErr,
kIOUSBWrongPIDErr,
kIOReturnOverrun,
kIOReturnUnderrun,
kIOUSBReserved1Err,
kIOUSBReserved2Err,
kIOUSBBufferOverrunErr,
kIOUSBBufferUnderrunErr,
kIOUSBNotSent1Err,
kIOUSBNotSent2Err
};
if (status > 15) return(kIOReturnInternalError);
return(statusToErrorMap[status]);
}
void
AppleUSBOHCI::ReturnTransactions(
AppleOHCIGeneralTransferDescriptorPtr transaction,
UInt32 tail)
{
UInt32 physicalAddress;
AppleOHCIGeneralTransferDescriptorPtr nextTransaction;
AppleOHCIIsochTransferDescriptorPtr isochTransaction = ( AppleOHCIIsochTransferDescriptorPtr) transaction;
AppleOHCIIsochTransferDescriptorPtr nextIsochTransaction = NULL;
USBLog(6, "%s[%p]::ReturnTransactions: (0x%x, 0x%x)", getName(), this, (UInt32) transaction->pPhysical, tail);
if ( (transaction->pType == kOHCIIsochronousInType) || (transaction->pType == kOHCIIsochronousOutType) || (transaction->pType == kOHCIIsochronousInLowLatencyType) || (transaction->pType == kOHCIIsochronousOutLowLatencyType))
{
while(isochTransaction->pPhysical != tail)
{
if (isochTransaction->completion.action != NULL)
{
ProcessCompletedITD(isochTransaction, kIOUSBTransactionReturned);
}
physicalAddress = USBToHostLong(isochTransaction->pShared->nextTD) & kOHCIHeadPMask;
nextIsochTransaction = AppleUSBOHCIitdMemoryBlock::GetITDFromPhysical (physicalAddress);
DeallocateITD(isochTransaction);
isochTransaction = nextIsochTransaction;
if(isochTransaction == NULL)
{
USBLog(1, "%s[%p]::ReturnTransactions: Isoc Return queue broken", getName(), this);
break;
}
}
}
else
{
while(transaction->pPhysical != tail)
{
if (transaction->uimFlags & kUIMFlagsCallbackTD)
{
IOUSBCompletion completion = transaction->command->GetUSLCompletion();
transaction->uimFlags &= ~kUIMFlagsCallbackTD;
Complete(completion, kIOUSBTransactionReturned, 0);
}
physicalAddress = USBToHostLong(transaction->pShared->nextTD) & kOHCIHeadPMask;
nextTransaction = AppleUSBOHCIgtdMemoryBlock::GetGTDFromPhysical(physicalAddress);
DeallocateTD(transaction);
transaction = nextTransaction;
if(transaction == NULL)
{
USBLog(1, "%s[%p]::ReturnTransactions: Return queue broken", getName(), this);
break;
}
}
}
}
void
AppleUSBOHCI::ReturnOneTransaction(
AppleOHCIGeneralTransferDescriptorPtr transaction,
AppleOHCIEndpointDescriptorPtr pED,
IOReturn err)
{
UInt32 physicalAddress;
AppleOHCIGeneralTransferDescriptorPtr nextTransaction;
UInt32 something;
UInt32 tail;
UInt32 bufferSizeRemaining = 0;
USBError(1, "+%s[%p]::ReturnOneTransaction(%p, %p, %x)", getName(), this, transaction, pED, err);
pED->pShared->flags |= HostToUSBLong (kOHCIEDControl_K);
IOSleep(1);
if (transaction->pPhysical == (USBToHostLong(pED->pShared->tdQueueHeadPtr) & kOHCIHeadPMask))
{
tail = USBToHostLong(pED->pShared->tdQueueTailPtr);
while(transaction->pPhysical != tail)
{
physicalAddress = HostToUSBLong(transaction->pShared->nextTD) & kOHCIHeadPMask;
nextTransaction = AppleUSBOHCIgtdMemoryBlock::GetGTDFromPhysical(physicalAddress);
pED->pShared->tdQueueHeadPtr = transaction->pShared->nextTD;
pED->pLogicalHeadP = nextTransaction;
bufferSizeRemaining += findBufferRemaining(transaction);
if (transaction->uimFlags & kUIMFlagsCallbackTD)
{
IOUSBCompletion completion = transaction->command->GetUSLCompletion();
transaction->uimFlags &= ~kUIMFlagsCallbackTD;
if (!(transaction->uimFlags & kUIMFlagsMultiTDTransaction))
{
USBLog(2, "%s(%p)::ReturnOneTransaction - found the end of a non-multi transaction(%p)!", getName(), this, transaction);
DeallocateTD(transaction);
Complete(completion, err, bufferSizeRemaining);
break;
}
else if (transaction->uimFlags & kUIMFlagsFinalTDinTransaction)
{
USBLog(2, "%s(%p)::ReturnOneTransaction - found the end of a MULTI transaction(%p)!", getName(), this, transaction);
DeallocateTD(transaction);
Complete(completion, err, bufferSizeRemaining);
break;
}
else
{
USBLog(2, "%s(%p)::ReturnOneTransaction - returning the non-end of a MULTI transaction(%p)!", getName(), this, transaction);
DeallocateTD(transaction);
Complete(completion, err, bufferSizeRemaining);
}
}
else
DeallocateTD(transaction);
transaction = nextTransaction;
if(transaction == NULL)
{
USBError(1, "ReturnOneTransaction: Return queue broken");
break;
}
}
}
else
{
USBLog(2, "%s[%p]::ReturnOneTransaction - transaction not at beginning!(%p, %p)", getName(), this, transaction->pPhysical, pED->pShared->tdQueueHeadPtr);
}
USBLog(2, "-%s[%p]::ReturnOneTransaction - done, new queue head (L%p, P%p) V%p", getName(), this, pED->pLogicalHeadP, pED->pShared->tdQueueHeadPtr, ((AppleOHCIGeneralTransferDescriptorPtr)pED->pLogicalHeadP)->pPhysical);
pED->pShared->flags &= ~HostToUSBLong(kOHCIEDControl_K); }
IOReturn
AppleUSBOHCI::message( UInt32 type, IOService * provider, void * argument )
{
cs_event_t pccardevent;
if ( type == kIOPCCardCSEventMessage)
{
pccardevent = (UInt32) argument;
if ( pccardevent == CS_EVENT_CARD_REMOVAL )
{
USBLog(5,"%s[%p]: Received kIOPCCardCSEventMessage Need to return all transactions",getName(),this);
_pcCardEjected = true;
IOSleep(5);
ReturnAllTransactionsInEndpoint(_pControlHead, _pControlTail);
ReturnAllTransactionsInEndpoint(_pBulkHead, _pBulkTail);
IOSleep(5);
}
}
USBLog(6, "%s[%p]::message type: 0x%x, isInactive = %d", getName(), this, type, isInactive());
return super::message( type, provider, argument );
}
void
AppleUSBOHCI::stop(IOService * provider)
{
USBLog(5, "%s[%p]::stop isInactive = %d", getName(), this, isInactive());
return super::stop(provider);
}
bool
AppleUSBOHCI::finalize(IOOptionBits options)
{
USBLog(5, "%s[%p]::finalize isInactive = %d", getName(), this, isInactive());
return super::finalize(options);
}
IOReturn
AppleUSBOHCI::UIMInitializeForPowerUp(void)
{
UInt32 commandRegister;
IOPhysicalAddress hcDoneHead;
USBLog(5, "%s[%p]: initializing UIM for PowerUp @ %lx (%lx)", getName(), this,
(long)_deviceBase->getVirtualAddress(),
_deviceBase->getPhysicalAddress());
#if (DEBUGGING_LEVEL > 2)
dumpRegs();
#endif
commandRegister = _device->configRead32(cwCommand);
_device->configWrite32(cwCommand, (commandRegister & 0xffff0000) | (cwCommandEnableBusMaster | cwCommandEnableMemorySpace));
hcDoneHead = USBToHostLong(_pOHCIRegisters->hcDoneHead);
if ( hcDoneHead != NULL )
{
USBError(1,"%s[%p]::UIMInitialize Non-NULL hcDoneHead: %p", getName(), this, hcDoneHead );
_pOHCIRegisters->hcCommandStatus = USBToHostLong(kOHCIHcCommandStatus_HCR); IOSleep(3);
}
_pOHCIRegisters->hcControlCurrentED = 0;
_pOHCIRegisters->hcControlHeadED = HostToUSBLong ((UInt32) _pControlHead->pPhysical);
_pOHCIRegisters->hcBulkHeadED = HostToUSBLong ((UInt32) _pBulkHead->pPhysical);
IOSync();
OSWriteLittleInt32(&_pOHCIRegisters->hcHCCA, 0, _hccaPhysAddr);
IOSync();
_pOHCIRegisters->hcInterruptStatus = USBToHostLong(kOHCIHcInterrupt_WDH);
IOSync();
_workLoop->enableAllInterrupts();
UInt32 hcFSMPS; UInt32 hcFI; UInt32 hcPS;
hcFI = USBToHostLong(_pOHCIRegisters->hcFmInterval) & kOHCIHcFmInterval_FI;
hcFSMPS = ((((hcFI-kOHCIMax_OverHead) * 6)/7) << kOHCIHcFmInterval_FSMPSPhase);
hcPS = (hcFI * 9) / 10; _pOHCIRegisters->hcFmInterval = HostToUSBLong(hcFI | hcFSMPS);
_pOHCIRegisters->hcPeriodicStart = HostToUSBLong(hcPS);
IOSync();
_pOHCIRegisters->hcControl = HostToUSBLong ((kOHCIFunctionalState_Reset << kOHCIHcControl_HCFSPhase));
IOSync();
_pOHCIRegisters->hcControl = HostToUSBLong ((kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase)
| kOHCIHcControl_CLE | kOHCIHcControl_BLE
| kOHCIHcControl_PLE | kOHCIHcControl_IE);
IOSync();
if (_errataBits & kErrataDisableOvercurrent)
_pOHCIRegisters->hcRhDescriptorA |= USBToHostLong(kOHCIHcRhDescriptorA_NOCP);
_pOHCIRegisters->hcRhStatus = HostToUSBLong(kOHCIHcRhStatus_OCIC | kOHCIHcRhStatus_DRWE);
OHCIRootHubPower(1 );
_pOHCIRegisters->hcInterruptEnable = HostToUSBLong (kOHCIHcInterrupt_MIE | kOHCIDefaultInterrupts);
IOSync();
_uimInitialized = true;
return kIOReturnSuccess;
}
IOReturn
AppleUSBOHCI::UIMFinalizeForPowerDown(void)
{
USBLog (3, "%s[%p]: @ %lx (%lx)(turning off HW)",getName(), this,
(long)_deviceBase->getVirtualAddress(),
_deviceBase->getPhysicalAddress());
#if (DEBUGGING_LEVEL > 2)
dumpRegs();
#endif
_workLoop->disableAllInterrupts();
_pOHCIRegisters->hcInterruptDisable = HostToUSBLong(kOHCIHcInterrupt_MIE);
IOSync();
_pOHCIRegisters->hcControl = HostToUSBLong((kOHCIFunctionalState_Reset << kOHCIHcControl_HCFSPhase));
IOSync();
IOSleep(2);
_device->configWrite32(cwCommand, cwCommandEnableMemorySpace);
_pOHCIRegisters->hcHCCA = 0;
_pOHCIRegisters->hcControlHeadED = 0;
_pOHCIRegisters->hcControlCurrentED = 0;
_pOHCIRegisters->hcBulkHeadED = 0;
_pOHCIRegisters->hcBulkCurrentED = 0;
IOSync();
OHCIRootHubPower(0 );
_uimInitialized = false;
_pOHCIRegisters->hcCommandStatus = HostToUSBLong(kOHCIHcCommandStatus_HCR); IOSync();
IOSleep(1);
return kIOReturnSuccess;
}
void
AppleUSBOHCI::free()
{
IOLockFree( _intLock );
IOSimpleLockFree( _wdhLock );
super::free();
}