#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"
#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(OHCIEndpointDescriptorPtr pED);
extern void print_td(OHCIGeneralTransferDescriptorPtr pTD);
extern void print_itd(OHCIIsochTransferDescriptorPtr 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;
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);
continue;
}
IOSleep(20);
err = _workLoop->addEventSource(_filterInterruptSource);
if ( err != kIOReturnSuccess )
{
USBError(1,"%s[%p]: unable to add filter event source: 0x%x", getName(), this, err);
continue;
}
_genCursor = IONaturalMemoryCursor::withSpecification(PAGE_SIZE, PAGE_SIZE);
if(!_genCursor)
continue;
_isoCursor = IONaturalMemoryCursor::withSpecification(kUSBMaxIsocFrameReqCount, kUSBMaxIsocFrameReqCount);
if(!_isoCursor)
continue;
_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));
if ((err = AllocateMemory(NUM_TDS, NUM_EDS, NUM_ITDS)))
continue;
_pOHCIRegisters->hcControlCurrentED = 0;
_pOHCIRegisters->hcControlHeadED = 0;
_pOHCIRegisters->hcDoneHead = 0;
IOSync();
_pHCCA = (Ptr) IOMallocContiguous(kHCCAsize, kHCCAalignment, &_hccaPhysAddr);
if (!_pHCCA)
{
USBError(1,"%s[%p]: Unable to allocate memory (2)", getName(), this);
err = kIOReturnNoMemory;
continue;
}
OSWriteLittleInt32(&_pOHCIRegisters->hcHCCA, 0, _hccaPhysAddr);
IOSync();
_pOHCIRegisters->hcInterruptStatus = USBToHostLong(kOHCIHcInterrupt_WDH);
IOSync();
_workLoop->enableAllInterrupts();
_rootHubFuncAddress = 1;
if ((err = IsochronousInitialize())) continue;
if ((err = InterruptInitialize())) continue;
if ((err = BulkInitialize())) continue;
if ((err = ControlInitialize())) continue;
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 );
IOSync();
_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();
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->hcPeriodCurrentED = 0;
_pOHCIRegisters->hcControlHeadED = 0;
_pOHCIRegisters->hcControlCurrentED = 0;
_pOHCIRegisters->hcBulkHeadED = 0;
_pOHCIRegisters->hcBulkCurrentED = 0;
_pOHCIRegisters->hcDoneHead = 0;
IOSync();
OHCIRootHubPower(0 );
IOSync();
}
IOFree( _pDataAllocation, _dataAllocationSize );
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(OHCIGeneralTransferDescriptorPtr nextTD,
UInt32 transferStatus,
UInt32 bufferSizeRemaining)
{
OHCIGeneralTransferDescriptorPtr pCurrentTD, pTempTD;
OHCIEndpointDescriptorPtr pED;
IOPhysicalAddress PhysAddr;
pED = (OHCIEndpointDescriptorPtr) nextTD->pEndpoint;
pED->flags |= HostToUSBWord(kOHCIEDControl_K); PhysAddr = (IOPhysicalAddress) USBToHostLong(pED->tdQueueHeadPtr) & kOHCIHeadPMask;
nextTD = (OHCIGeneralTransferDescriptorPtr) GetLogicalAddress(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->tdQueueHeadPtr = pCurrentTD->nextTD | (pED->tdQueueHeadPtr & HostToUSBLong(~kOHCIHeadPointer_headP));
USBLog(5, "AppleUSBOHCI::doCallback- queueheadptr is now %p", pED->tdQueueHeadPtr);
bufferSizeRemaining += findBufferRemaining (pCurrentTD);
pCurrentTD->currentBufferPtr = NULL;
if (pCurrentTD->uimFlags & kUIMFlagsLastTD)
{
IOUSBCompletion completion;
if (transferStatus == kOHCIGTDConditionDataUnderrun)
{
USBLog(5, "AppleUSBOHCI::doCallback- found callback TD, setting queuehead to %p", pED->tdQueueHeadPtr & HostToUSBLong(~kOHCIHeadPointer_H));
pED->tdQueueHeadPtr = pED->tdQueueHeadPtr & HostToUSBLong(~kOHCIHeadPointer_H);
transferStatus = 0;
}
completion = pCurrentTD->command->GetUSLCompletion();
pCurrentTD->uimFlags &= ~kUIMFlagsLastTD;
DeallocateTD(pCurrentTD);
pED->flags &= ~HostToUSBWord(kOHCIEDControl_K); Complete(completion,
TranslateStatusToUSBError(transferStatus),
bufferSizeRemaining);
bufferSizeRemaining = 0;
return;
}
pTempTD = pCurrentTD->pLogicalNext;
DeallocateTD(pCurrentTD);
pCurrentTD = pTempTD;
}
}
UInt32
AppleUSBOHCI::findBufferRemaining (OHCIGeneralTransferDescriptorPtr pCurrentTD)
{
UInt32 pageMask;
UInt32 bufferSizeRemaining;
pageMask = ~(_pageSize - 1);
if (pCurrentTD->currentBufferPtr == 0)
{
bufferSizeRemaining = 0;
}
else if ((USBToHostLong(pCurrentTD->bufferEnd) & (pageMask)) ==
(USBToHostLong(pCurrentTD->currentBufferPtr)& (pageMask)))
{
bufferSizeRemaining =
(USBToHostLong (pCurrentTD->bufferEnd) & ~pageMask) -
(USBToHostLong (pCurrentTD->currentBufferPtr) & ~pageMask) + 1;
}
else
{
bufferSizeRemaining =
((USBToHostLong(pCurrentTD->bufferEnd) & ~pageMask) + 1) +
(_pageSize - (USBToHostLong(pCurrentTD->currentBufferPtr) & ~pageMask));
}
return (bufferSizeRemaining);
}
IOReturn
AppleUSBOHCI::ControlInitialize(void)
{
OHCIEndpointDescriptorPtr pED, pED2;
pED = AllocateED();
if ( pED == NULL )
return kIOReturnNoMemory;
pED->flags = HostToUSBLong (kOHCIEDControl_K);
pED->nextED = 0; _pControlTail = pED;
pED2 = AllocateED();
if ( pED2 == NULL )
return kIOReturnNoMemory;
pED2->flags = HostToUSBLong (kOHCIEDControl_K);
_pControlHead = pED2;
_pOHCIRegisters->hcControlHeadED = HostToUSBLong ((UInt32) pED2->pPhysical);
pED2->nextED = HostToUSBLong ((UInt32) pED->pPhysical);
pED2->pLogicalNext = pED;
return kIOReturnSuccess;
}
IOReturn
AppleUSBOHCI::BulkInitialize (void)
{
OHCIEndpointDescriptorPtr pED, pED2;
pED = AllocateED();
if ( pED == NULL )
return kIOReturnNoMemory;
pED->flags = HostToUSBLong (kOHCIEDControl_K);
pED->nextED = 0; _pBulkTail = pED;
pED2 = AllocateED();
if ( pED2 == NULL ) return kIOReturnNoMemory;
pED2->flags = HostToUSBLong (kOHCIEDControl_K);
_pBulkHead = pED2;
_pOHCIRegisters->hcBulkHeadED = HostToUSBLong ((UInt32) pED2->pPhysical);
pED2->nextED = HostToUSBLong ((UInt32) pED->pPhysical);
pED2->pLogicalNext = pED;
return kIOReturnSuccess;
}
IOReturn
AppleUSBOHCI::IsochronousInitialize(void)
{
OHCIEndpointDescriptorPtr pED, pED2;
pED = AllocateED();
if ( pED == NULL )
return kIOReturnNoMemory;
pED->flags = HostToUSBLong (kOHCIEDControl_K);
pED->nextED = 0; _pIsochTail = pED;
pED2 = AllocateED();
if ( pED2 == NULL )
return kIOReturnNoMemory;
pED2->flags = HostToUSBLong (kOHCIEDControl_K);
_pIsochHead = pED2;
pED2->nextED = HostToUSBLong ((UInt32) pED->pPhysical);
pED2->pLogicalNext = pED;
_isochBandwidthAvail = kUSBMaxIsocFrameReqCount;
return kIOReturnSuccess;
}
IOReturn
AppleUSBOHCI::InterruptInitialize (void)
{
UInt32 dummyControl;
int i, p, q, z;
OHCIEndpointDescriptorPtr pED, pIsochHead;
dummyControl = kOHCIEDControl_K;
dummyControl |= 0; dummyControl = HostToUSBLong (dummyControl);
pIsochHead = (OHCIEndpointDescriptorPtr) _pIsochHead;
for (i = 0; i < 63; i++)
{
pED = AllocateED();
if (pED == NULL)
{
return (kIOReturnNoMemory);
}
else
{
pED->flags = dummyControl;
pED->nextED = 0; _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->nextED = HostToUSBLong (_pInterruptHead[z].pHeadPhysical);
pED->pLogicalNext = _pInterruptHead[z].pHead;
_pInterruptHead[i].pTail = (OHCIEndpointDescriptorPtr) pED->pLogicalNext;
}
i = 62;
pED = _pInterruptHead[i].pHead;
pED->nextED = HostToUSBLong (pIsochHead->pPhysical);
pED->pLogicalNext = _pIsochHead;
_pInterruptHead[i].pTail = (OHCIEndpointDescriptorPtr) pED->pLogicalNext;
return kIOReturnSuccess;
}
UInt32
AppleUSBOHCI::GetLogicalAddress (UInt32 pPhysicalAddress)
{
OHCIPhysicalLogicalPtr pPhysicalLogical;
UInt32 LogicalAddress = NULL;
if (pPhysicalAddress == 0)
return(0);
pPhysicalLogical = _pPhysicalLogical;
while (pPhysicalLogical != NULL) {
if (pPhysicalAddress <= pPhysicalLogical->PhysicalEnd
&& pPhysicalAddress >= pPhysicalLogical->PhysicalStart)
{
LogicalAddress = pPhysicalLogical->LogicalStart +
(pPhysicalAddress - pPhysicalLogical->PhysicalStart);
pPhysicalLogical = NULL;
} else {
pPhysicalLogical = (OHCIPhysicalLogicalPtr) pPhysicalLogical->pNext;
}
}
return (LogicalAddress);
}
UInt32
AppleUSBOHCI::GetPhysicalAddress(UInt32 LogicalAddress, UInt32 count)
{
OHCIPhysicalLogicalPtr pPhysicalLogical;
UInt32 PhysicalAddress = NULL;
if (LogicalAddress == 0)
return(0);
pPhysicalLogical = _pPhysicalLogical;
while (pPhysicalLogical != NULL) {
if (LogicalAddress <= pPhysicalLogical->LogicalEnd
&& LogicalAddress >= pPhysicalLogical->LogicalStart)
{
PhysicalAddress = pPhysicalLogical->PhysicalStart
+ (LogicalAddress - pPhysicalLogical->LogicalStart);
pPhysicalLogical = NULL;
} else {
pPhysicalLogical = pPhysicalLogical->pNext;
}
}
if (PhysicalAddress == NULL)
PhysicalAddress = CreatePhysicalAddress(LogicalAddress, count);
return (PhysicalAddress);
}
UInt32
AppleUSBOHCI::CreatePhysicalAddress(UInt32 pLogicalAddress, UInt32 count)
{
OHCIPhysicalLogicalPtr pPhysicalLogical;
OHCIPhysicalLogicalPtr p;
pPhysicalLogical = _pPhysicalLogical;
p = (OHCIPhysicalLogicalPtr) IOMalloc(sizeof (OHCIPhysicalLogical));
p->LogicalStart = pLogicalAddress;
p->PhysicalStart = kvtophys((vm_offset_t)pLogicalAddress);
p->LogicalEnd = p->LogicalStart + count * _pageSize-1;
p->PhysicalEnd = p->PhysicalStart + count * _pageSize-1;
p->pNext = _pPhysicalLogical;
_pPhysicalLogical = p;
return (p->PhysicalStart);
}
IOReturn
AppleUSBOHCI::AllocateMemory (int num_of_TDs, int num_of_EDs, int num_of_ITDs)
{
Ptr p;
UInt32 physical;
UInt32 tdsPerPage, pagesTD,
edsPerPage, pagesED,
itdsPerPage, pagesITD;
OHCIEndpointDescriptorPtr FreeED, FreeEDCurrent;
OHCIGeneralTransferDescriptorPtr FreeTD, FreeTDCurrent;
OHCIIsochTransferDescriptorPtr FreeITD, FreeITDCurrent;
UInt32 i,j;
tdsPerPage = _pageSize / sizeof (OHCIGeneralTransferDescriptor);
pagesTD = (num_of_TDs + (tdsPerPage - 1)) / tdsPerPage;
edsPerPage = _pageSize / sizeof (OHCIEndpointDescriptor);
pagesED = (num_of_EDs + (edsPerPage - 1)) / edsPerPage;
itdsPerPage = _pageSize / sizeof (OHCIIsochTransferDescriptor);
pagesITD = (num_of_ITDs + (itdsPerPage - 1)) / itdsPerPage;
_dataAllocationSize = ( (pagesED + pagesTD + pagesITD + 1) * _pageSize);
p = (Ptr)IOMalloc(_dataAllocationSize);
if (!p)
return(kIOReturnNoMemory);
for(i=0; i<(pagesED + pagesTD + pagesITD + 1) * _pageSize/4; i++)
((UInt32 *)p)[i] = 0x12345678;
_pDataAllocation = p;
p = (Ptr) (((UInt32) p + (_pageSize - 1)) & ~(_pageSize - 1));
FreeED = (OHCIEndpointDescriptorPtr) p;
FreeEDCurrent = FreeED;
_pFreeED = FreeED;
for (i = 0 ; i < pagesED ; i++)
{
physical = kvtophys((UInt32)FreeEDCurrent);
for (j = 0; j < edsPerPage; j++)
{
FreeEDCurrent[j].pPhysical = physical + (j * sizeof (OHCIEndpointDescriptor));
FreeEDCurrent[j].pLogicalNext = (&FreeEDCurrent[j+1]);
}
if (i != (pagesED - 1))
{
FreeEDCurrent[j-1].pLogicalNext = (OHCIEndpointDescriptorPtr)((UInt32) FreeEDCurrent + _pageSize);
}
else
{
FreeEDCurrent[j-1].pLogicalNext = NULL;
_pLastFreeED = &FreeEDCurrent[j-1];
}
FreeEDCurrent = (OHCIEndpointDescriptorPtr) ((UInt32) FreeEDCurrent + _pageSize);
}
FreeTD = (OHCIGeneralTransferDescriptorPtr) FreeEDCurrent;
FreeTDCurrent = FreeTD;
_pFreeTD = FreeTD;
for (i = 0; i < pagesTD; i++)
{
physical = GetPhysicalAddress((UInt32) FreeTDCurrent, 1);
for (j = 0; j < tdsPerPage; j++)
{
FreeTDCurrent[j].pPhysical = physical + (j * sizeof (OHCIGeneralTransferDescriptor));
FreeTDCurrent[j].pLogicalNext = &(FreeTDCurrent[j+1]);
}
if (i != (pagesTD - 1))
{
FreeTDCurrent[j-1].pLogicalNext = (OHCIGeneralTransferDescriptorPtr)((UInt32) FreeTDCurrent + _pageSize);
}
else
{
FreeTDCurrent[j-1].pLogicalNext = NULL;
_pLastFreeTD = &FreeTDCurrent[j-1];
}
FreeTDCurrent = (OHCIGeneralTransferDescriptorPtr) ((UInt32) FreeTDCurrent + _pageSize);
}
FreeITD = (OHCIIsochTransferDescriptorPtr) FreeTDCurrent;
FreeITDCurrent = FreeITD;
_pFreeITD = FreeITD;
for (i = 0; i < pagesITD; i++)
{
physical = GetPhysicalAddress((UInt32) FreeITDCurrent, 1);
for (j = 0; j < itdsPerPage; j++)
{
FreeITDCurrent[j].pPhysical = physical + (j * sizeof (OHCIIsochTransferDescriptor));
FreeITDCurrent[j].pLogicalNext = (&FreeITDCurrent[j+1]);
}
if (i != (pagesITD - 1))
{
FreeITDCurrent[j-1].pLogicalNext = (OHCIIsochTransferDescriptorPtr)((UInt32) FreeITDCurrent + _pageSize);
}
else
{
FreeITDCurrent[j-1].pLogicalNext = NULL;
_pLastFreeITD = &FreeITDCurrent[j-1];
}
FreeITDCurrent = (OHCIIsochTransferDescriptorPtr) ((UInt32) FreeITDCurrent + _pageSize);
}
return (kIOReturnSuccess);
}
OHCIIsochTransferDescriptorPtr
AppleUSBOHCI::AllocateITD(void)
{
OHCIIsochTransferDescriptorPtr freeITD;
freeITD = _pFreeITD;
if (freeITD == NULL)
{
OHCIIsochTransferDescriptorPtr freeITDCurrent;
int j;
int itdsPerPage;
UInt32 physical;
USBLog(5,"%s[%p]: Out of Isoch TDs. Allocating some more", getName(), this);
UInt8 * p = (UInt8 *)IOMallocAligned(_pageSize, _pageSize);
if(p == NULL)
{
USBError(1, "%s[%p]: Could not create any more Isoch Transfer Descriptors!", getName(), this);
return NULL;
}
itdsPerPage = _pageSize / sizeof (OHCIIsochTransferDescriptor);
_pFreeITD = freeITDCurrent = (OHCIIsochTransferDescriptorPtr)p;
physical = GetPhysicalAddress((UInt32) freeITDCurrent, 1);
for (j = 0; j < itdsPerPage-1; j++)
{
freeITDCurrent[j].pPhysical = physical + (j * sizeof (OHCIIsochTransferDescriptor));
freeITDCurrent[j].pLogicalNext = &freeITDCurrent[j+1];
}
freeITDCurrent[j].pPhysical = physical + (j * sizeof (OHCIIsochTransferDescriptor));
freeITDCurrent[j].pLogicalNext = NULL;
_pLastFreeITD = &freeITDCurrent[j];
freeITD = _pFreeITD;
}
_pFreeITD = freeITD->pLogicalNext;
freeITD->pLogicalNext = NULL;
freeITD->uimFlags = 0;
return freeITD;
}
OHCIGeneralTransferDescriptorPtr
AppleUSBOHCI::AllocateTD(void)
{
OHCIGeneralTransferDescriptorPtr freeTD;
freeTD = _pFreeTD;
if (freeTD == NULL)
{
OHCIGeneralTransferDescriptorPtr freeTDCurrent;
int j;
int tdsPerPage;
UInt32 physical;
USBLog(3,"%s[%p]: Out of General TDs. Allocating some more", getName(), this);
UInt8 * p = (UInt8 *)IOMallocAligned(_pageSize, _pageSize);
if(p == NULL)
{
USBError(1, "%s[%p]: Could not create any more Transfer Descriptors!", getName(), this);
return NULL;
}
tdsPerPage = _pageSize / sizeof (OHCIGeneralTransferDescriptor);
_pFreeTD = freeTDCurrent = (OHCIGeneralTransferDescriptorPtr)p;
physical = GetPhysicalAddress((UInt32) freeTDCurrent, 1);
for (j = 0; j < tdsPerPage-1; j++)
{
freeTDCurrent[j].pPhysical = physical + (j * sizeof (OHCIGeneralTransferDescriptor));
freeTDCurrent[j].pLogicalNext = &freeTDCurrent[j+1];
}
freeTDCurrent[j].pPhysical = physical + (j * sizeof (OHCIGeneralTransferDescriptor));
freeTDCurrent[j].pLogicalNext = NULL;
_pLastFreeTD = &freeTDCurrent[j];
freeTD = _pFreeTD;
}
_pFreeTD = freeTD->pLogicalNext;
freeTD->pLogicalNext = NULL;
freeTD->uimFlags = 0;
freeTD->lastFrame = 0; freeTD->lastRemaining = 0;
return freeTD;
}
OHCIEndpointDescriptorPtr
AppleUSBOHCI::AllocateED(void)
{
OHCIEndpointDescriptorPtr freeED;
freeED = _pFreeED;
if (freeED == NULL)
{
int j;
int edsPerPage;
UInt32 physical;
OHCIEndpointDescriptorPtr FreeEDCurrent;
UInt8 * p = (UInt8 *)IOMallocAligned(_pageSize, _pageSize);
if(p == NULL)
{
USBError(1, "%s[%p]: Out of Endpoint Descriptors!", getName(), this);
return NULL;
}
edsPerPage = _pageSize / sizeof (OHCIEndpointDescriptor);
physical = kvtophys((vm_offset_t)p);
_pFreeED = FreeEDCurrent = (OHCIEndpointDescriptorPtr)p;
for (j = 0; j < edsPerPage-1; j++)
{
FreeEDCurrent[j].pPhysical =
physical + (j * sizeof (OHCIEndpointDescriptor));
FreeEDCurrent[j].pLogicalNext = (&FreeEDCurrent[j+1]);
}
FreeEDCurrent[j].pPhysical =
physical + (j * sizeof (OHCIEndpointDescriptor));
FreeEDCurrent[j].pLogicalNext = NULL;
_pLastFreeED = &FreeEDCurrent[j];
freeED = _pFreeED;
}
_pFreeED = (OHCIEndpointDescriptorPtr) freeED->pLogicalNext;
freeED->pLogicalNext = NULL;
return (freeED);
}
IOReturn
AppleUSBOHCI::DeallocateITD (OHCIIsochTransferDescriptorPtr 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 (OHCIGeneralTransferDescriptorPtr 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 (OHCIEndpointDescriptorPtr 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(OHCIEndpointDescriptorPtr pED)
{
return ((USBToHostLong(pED->flags) & kOHCIEDControl_F) >> kOHCIEDControl_FPhase);
}
IOReturn
AppleUSBOHCI::RemoveAllTDs (OHCIEndpointDescriptorPtr pED)
{
RemoveTDs(pED);
if (GetEDType(pED) == kOHCIEDFormatGeneralTD) {
DeallocateTD(
(OHCIGeneralTransferDescriptorPtr) pED->pLogicalTailP);
}
else
{
DeallocateITD(
(OHCIIsochTransferDescriptorPtr) pED->pLogicalTailP);
}
pED->pLogicalTailP = NULL;
return (0);
}
IOReturn
AppleUSBOHCI::RemoveTDs(OHCIEndpointDescriptorPtr pED)
{
OHCIGeneralTransferDescriptorPtr pCurrentTD, lastTD;
UInt32 bufferSizeRemaining = 0;
OHCIIsochTransferDescriptorPtr pITD, pITDLast;
if (GetEDType(pED) == kOHCIEDFormatGeneralTD)
{
pCurrentTD = (OHCIGeneralTransferDescriptorPtr) (USBToHostLong(pED->tdQueueHeadPtr) & kOHCIHeadPMask);
pCurrentTD = (OHCIGeneralTransferDescriptorPtr) GetLogicalAddress ((UInt32) pCurrentTD);
lastTD = (OHCIGeneralTransferDescriptorPtr) pED->pLogicalTailP;
pED->pLogicalHeadP = pED->pLogicalTailP;
while (pCurrentTD != lastTD)
{
if (pCurrentTD == NULL)
return (-1);
pED->tdQueueHeadPtr = pCurrentTD->nextTD;
pED->pLogicalHeadP = pCurrentTD->pLogicalNext;
bufferSizeRemaining += findBufferRemaining(pCurrentTD);
if (pCurrentTD->uimFlags & kUIMFlagsLastTD)
{
IOUSBCompletion completion = pCurrentTD->command->GetUSLCompletion();
pCurrentTD->uimFlags &= ~kUIMFlagsLastTD;
Complete(completion, kIOReturnAborted, bufferSizeRemaining);
bufferSizeRemaining = 0;
}
DeallocateTD(pCurrentTD);
pCurrentTD = (OHCIGeneralTransferDescriptorPtr) pED->pLogicalHeadP;
}
}
else
{
UInt32 phys;
phys = (USBToHostLong(pED->tdQueueHeadPtr) & kOHCIHeadPMask);
pITD = (OHCIIsochTransferDescriptorPtr) GetLogicalAddress(phys);
pITDLast = (OHCIIsochTransferDescriptorPtr)pED->pLogicalTailP;
while (pITD != pITDLast)
{
OHCIIsochTransferDescriptorPtr pPrevITD;
if (pITD == NULL)
return (-1);
pED->tdQueueHeadPtr = pITD->nextTD;
pED->pLogicalHeadP = pITD->pLogicalNext;
ProcessCompletedITD (pITD, kIOReturnAborted);
pPrevITD = pITD;
pITD = pITD->pLogicalNext;
DeallocateITD(pPrevITD);
}
}
return (0);
}
void
AppleUSBOHCI::ProcessCompletedITD (OHCIIsochTransferDescriptorPtr 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->flags) & kOHCIITDControl_FC) >> kOHCIITDControl_FCPhase;
itdConditionCode = (USBToHostLong(pITD->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->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->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;
OHCIGeneralTransferDescriptorPtr 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;
OHCIGeneralTransferDescriptorPtr pHCDoneTD, prevTD, nextTD;
IOPhysicalAddress physicalAddress;
UInt32 pageMask;
OHCIEndpointDescriptorPtr tempED;
OHCIIsochTransferDescriptorPtr 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 = (OHCIGeneralTransferDescriptorPtr) GetLogicalAddress(cachedWriteDoneQueueHead);
if ( pHCDoneTD == NULL )
return kIOReturnSuccess;
prevTD = NULL;
while ( true )
{
pHCDoneTD->pLogicalNext = prevTD;
prevTD = pHCDoneTD;
numTDs++;
cachedConsumer++;
if ( cachedProducer == cachedConsumer)
break;
physicalAddress = USBToHostLong(pHCDoneTD->nextTD) & kOHCIHeadPMask;
nextTD = (OHCIGeneralTransferDescriptorPtr) GetLogicalAddress(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;
#if 0
if ( (numTDs > 1) || (numTDs < 1) )
{
OHCIGeneralTransferDescriptorPtr testTD, nextTD;
IOUSBLowLatencyIsocFrame * pLLFrames;
int i;
int frameCount;
testTD = pHCDoneTD;
USBLog(3,"Processed %d (%d) TDs, # filtInterr: %ld, time Interval: %ld", numTDs, _lowLatencyIsochTDsProcessed, _filterInterruptCount, (UInt32) _timeElapsed );
while (testTD != NULL)
{
nextTD = testTD->pLogicalNext;
if ( (pHCDoneTD->pType == kOHCIIsochronousInLowLatencyType) || (pHCDoneTD->pType == kOHCIIsochronousOutLowLatencyType) )
{
testITD = (OHCIIsochTransferDescriptorPtr) testTD;
pLLFrames = (IOUSBLowLatencyIsocFrame *) testITD->pIsocFrame;
frameCount = (USBToHostLong(testITD->flags) & kOHCIITDControl_FC) >> kOHCIITDControl_FCPhase;
for (i=0; i <= frameCount; i++)
{
UInt16 offset = USBToHostWord(testITD->offset[i]);
if ( (_filterInterruptCount != 0 ))
{
if ( (pLLFrames[testITD->frameNum + i].frStatus != (IOReturn) kUSBLowLatencyIsochTransferKey) )
{
USBLog(3,"%s[%p]::MoreTD's(%p): frame processed at hw interrupt time: frame: %d, frTimeStamp.lo: 0x%x", getName(), this, testITD, i, pLLFrames[testITD->frameNum + i].frTimeStamp.lo);
}
}
}
}
testTD = nextTD;
}
}
#endif
while (pHCDoneTD != NULL)
{
IOReturn errStatus;
nextTD = pHCDoneTD->pLogicalNext;
control = USBToHostLong(pHCDoneTD->ohciFlags);
transferStatus = (control & kOHCIGTDControl_CC) >> kOHCIGTDControl_CCPhase;
errStatus = TranslateStatusToUSBError(transferStatus);
if (_OptiOn && (pHCDoneTD->pType == kOHCIOptiLSBug))
{
tempED = (OHCIEndpointDescriptorPtr) pHCDoneTD->pEndpoint;
pHCDoneTD->ohciFlags = pHCDoneTD->ohciFlags & HostToUSBLong(kOHCIGTDClearErrorMask);
tempED->tdQueueHeadPtr &= HostToUSBLong(kOHCIHeadPMask);
pHCDoneTD->nextTD = tempED->tdQueueTailPtr & HostToUSBLong(kOHCIHeadPMask);
tempED->tdQueueTailPtr = HostToUSBLong(pHCDoneTD->pPhysical);
_pOHCIRegisters->hcCommandStatus = HostToUSBLong (kOHCIHcCommandStatus_CLF);
}
else if ((transferStatus == kOHCIGTDConditionBufferUnderrun) &&
(pHCDoneTD->pType == kOHCIBulkTransferOutType) &&
(_errataBits & kErrataRetryBufferUnderruns))
{
tempED = (OHCIEndpointDescriptorPtr) pHCDoneTD->pEndpoint;
pHCDoneTD->ohciFlags = pHCDoneTD->ohciFlags & HostToUSBLong(kOHCIGTDClearErrorMask);
pHCDoneTD->nextTD = tempED->tdQueueHeadPtr & HostToUSBLong(kOHCIHeadPMask);
pHCDoneTD->pLogicalNext = (OHCIGeneralTransferDescriptorPtr) GetLogicalAddress (USBToHostLong(tempED->tdQueueHeadPtr) & kOHCIHeadPMask);
tempED->tdQueueHeadPtr = USBToHostLong(pHCDoneTD->pPhysical) | (tempED->tdQueueHeadPtr & HostToUSBLong( kOHCIEDToggleBitMask));
_pOHCIRegisters->hcCommandStatus = HostToUSBLong(kOHCIHcCommandStatus_BLF);
}
else if ( (pHCDoneTD->pType == kOHCIIsochronousInType) || (pHCDoneTD->pType == kOHCIIsochronousOutType) || (pHCDoneTD->pType == kOHCIIsochronousInLowLatencyType) || (pHCDoneTD->pType == kOHCIIsochronousOutLowLatencyType) )
{
pITD = (OHCIIsochTransferDescriptorPtr) pHCDoneTD;
ProcessCompletedITD(pITD, errStatus);
DeallocateITD(pITD);
}
else
{
bufferSizeRemaining = findBufferRemaining (pHCDoneTD);
if (pHCDoneTD->uimFlags & kUIMFlagsLastTD)
{
IOUSBCompletion completion = pHCDoneTD->command->GetUSLCompletion();
if(!safeAction || (safeAction == completion.action))
{
pHCDoneTD->uimFlags &= ~kUIMFlagsLastTD;
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)
{
OHCIGeneralTransferDescriptorPtr next = _pendingHead->pLogicalNext;
long bufferSizeRemaining = findBufferRemaining (_pendingHead);
UInt32 transferStatus = (USBToHostLong(_pendingHead->ohciFlags) & kOHCIGTDControl_CC) >> kOHCIGTDControl_CCPhase;
if (_pendingHead->uimFlags & kUIMFlagsLastTD)
{
IOUSBCompletion completion = _pendingHead->command->GetUSLCompletion();
_pendingHead->uimFlags &= ~kUIMFlagsLastTD;
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(
OHCIGeneralTransferDescriptor *transaction,
UInt32 tail)
{
UInt32 physicalAddress;
OHCIGeneralTransferDescriptor *nextTransaction;
OHCIIsochTransferDescriptorPtr isochTransaction = ( OHCIIsochTransferDescriptorPtr) transaction;
OHCIIsochTransferDescriptorPtr 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 = OSSwapInt32(isochTransaction->nextTD) & kOHCIHeadPMask;
nextIsochTransaction = (OHCIIsochTransferDescriptorPtr) GetLogicalAddress (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 & kUIMFlagsLastTD)
{
IOUSBCompletion completion = transaction->command->GetUSLCompletion();
transaction->uimFlags &= ~kUIMFlagsLastTD;
Complete(completion, kIOUSBTransactionReturned, 0);
}
physicalAddress = OSSwapInt32(transaction->nextTD) & kOHCIHeadPMask;
nextTransaction = (OHCIGeneralTransferDescriptorPtr) GetLogicalAddress (physicalAddress);
DeallocateTD(transaction);
transaction = nextTransaction;
if(transaction == NULL)
{
USBLog(1, "%s[%p]::ReturnTransactions: Return queue broken", getName(), this);
break;
}
}
}
}
void
AppleUSBOHCI::ReturnOneTransaction(
OHCIGeneralTransferDescriptor *transaction,
OHCIEndpointDescriptorPtr pED,
IOReturn err)
{
UInt32 physicalAddress;
OHCIGeneralTransferDescriptor *nextTransaction;
UInt32 something;
UInt32 tail;
UInt32 bufferSizeRemaining = 0;
USBError(1, "+%s[%p]::ReturnOneTransaction(%p, %p, %x)", getName(), this, transaction, pED, err);
pED->flags |= HostToUSBLong (kOHCIEDControl_K);
IOSleep(1);
if (transaction->pPhysical == (USBToHostLong(pED->tdQueueHeadPtr) & kOHCIHeadPMask))
{
tail = USBToHostLong(pED->tdQueueTailPtr);
while(transaction->pPhysical != tail)
{
physicalAddress = HostToUSBLong(transaction->nextTD) & kOHCIHeadPMask;
nextTransaction = (OHCIGeneralTransferDescriptorPtr) GetLogicalAddress (physicalAddress);
pED->tdQueueHeadPtr = transaction->nextTD;
pED->pLogicalHeadP = nextTransaction;
bufferSizeRemaining += findBufferRemaining(transaction);
if (transaction->uimFlags & kUIMFlagsLastTD)
{
IOUSBCompletion completion = transaction->command->GetUSLCompletion();
transaction->uimFlags &= ~kUIMFlagsLastTD;
DeallocateTD(transaction);
Complete(completion, err, bufferSizeRemaining);
USBLog(2, "%s(%p)::ReturnOneTransaction - found the end of the transaction(%p)!", getName(), this, transaction);
break;
}
DeallocateTD(transaction);
transaction = nextTransaction;
if(transaction == NULL)
{
USBLog(1, "ReturnOneTransaction: Return queue broken");
break;
}
}
}
else
{
USBLog(2, "%s[%p]::ReturnOneTransaction - transaction not at beginning!(%p, %p)", getName(), this, transaction->pPhysical, pED->tdQueueHeadPtr);
}
USBLog(2, "-%s[%p]::ReturnOneTransaction - done, new queue head (L%p, P%p) V%p", getName(), this, pED->pLogicalHeadP, pED->tdQueueHeadPtr, ((OHCIGeneralTransferDescriptor*)pED->pLogicalHeadP)->pPhysical);
pED->flags &= ~HostToUSBLong(kOHCIEDControl_K); }
IOReturn
AppleUSBOHCI::message( UInt32 type, IOService * provider, void * argument )
{
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;
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));
_pOHCIRegisters->hcControlCurrentED = 0;
_pOHCIRegisters->hcDoneHead = 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 );
IOSync();
_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->hcPeriodCurrentED = 0;
_pOHCIRegisters->hcControlHeadED = 0;
_pOHCIRegisters->hcControlCurrentED = 0;
_pOHCIRegisters->hcBulkHeadED = 0;
_pOHCIRegisters->hcBulkCurrentED = 0;
_pOHCIRegisters->hcDoneHead = 0;
IOSync();
OHCIRootHubPower(0 );
IOSync();
_uimInitialized = false;
return kIOReturnSuccess;
}
void
AppleUSBOHCI::free()
{
IOLockFree( _intLock );
IOSimpleLockFree( _wdhLock );
super::free();
}