#include <libkern/OSByteOrder.h>
#include <IOKit/IOMemoryCursor.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOFilterInterruptEventSource.h>
#include <IOKit/usb/USB.h>
#include <IOKit/usb/IOUSBLog.h>
#include <IOKit/pccard/IOPCCard.h>
#include "AppleUSBEHCI.h"
#include "AppleEHCIedMemoryBlock.h"
#include "AppleEHCItdMemoryBlock.h"
#include "AppleEHCIitdMemoryBlock.h"
#include "AppleEHCIsitdMemoryBlock.h"
#include "AppleUSBEHCIHubInfo.h"
#define super IOUSBControllerV2
#define self this
#define NUM_BUFFER_PAGES 9 // 54
#define NUM_TDS 255 // 1500
#define NUM_EDS 256 // 1500
#define NUM_ITDS 192 // 1300
OSDefineMetaClassAndStructors(AppleUSBEHCI, IOUSBControllerV2)
bool
AppleUSBEHCI::init(OSDictionary * propTable)
{
if (!super::init(propTable))
return false;
_ehciBusState = kEHCIBusStateOff;
_ehciAvailable = true;
_hasPCIPwrMgmt = false;
_intLock = IOLockAlloc();
if (!_intLock)
return(false);
_controllerSpeed = kUSBDeviceSpeedHigh; _wdhLock = IOSimpleLockAlloc();
if (!_wdhLock)
return(false);
_uimInitialized = false;
_producerCount = 1;
_consumerCount = 1;
return (true);
}
void
AppleUSBEHCI::free()
{
IOLockFree( _intLock );
IOSimpleLockFree( _wdhLock );
if (_processDoneQueueThread)
{
thread_call_cancel(_processDoneQueueThread);
thread_call_free(_processDoneQueueThread);
}
super::free();
}
void AppleUSBEHCI::showRegisters(char *s)
{
int i;
USBLog(3,"EHCIUIM -- showRegisters %s version: 0x%x", s, USBToHostWord(_pEHCICapRegisters->HCIVersion));
USBLog(3,"USBCMD: 0x%lx", USBToHostLong(_pEHCIRegisters->USBCMD));
USBLog(3,"USBSTS: 0x%lx", USBToHostLong(_pEHCIRegisters->USBSTS));
USBLog(3,"USBIntr: 0x%lx", USBToHostLong(_pEHCIRegisters->USBIntr));
USBLog(3,"FRIndex: 0x%lx", USBToHostLong(_pEHCIRegisters->FRIndex));
USBLog(3,"CTRLDSSeg: 0x%lx", USBToHostLong(_pEHCIRegisters->CTRLDSSegment));
USBLog(3,"PerListBase: 0x%lx", USBToHostLong(_pEHCIRegisters->PeriodicListBase));
USBLog(3,"AsyncListAd: 0x%lx", USBToHostLong(_pEHCIRegisters->AsyncListAddr));
USBLog(3,"ConfFlg: 0x%lx\n", USBToHostLong(_pEHCIRegisters->ConfigFlag));
for(i=0;i<5;i++)
{
UInt32 x;
x = USBToHostLong(_pEHCIRegisters->PortSC[i]);
if(x != 0x1000)
USBLog(3,"PortSC[%d]: 0x%lx", i+1, x);
}
}
bool
AppleUSBEHCI::start( IOService * provider )
{
USBLog(7, "+%s[%p]::start", getName(), this);
if( !super::start(provider))
return (false);
initForPM(_device);
_processDoneQueueThread = thread_call_allocate((thread_call_func_t)ProcessDoneQueueEntry, (thread_call_param_t)this);
if ( !_processDoneQueueThread )
{
USBError(1, "%s[%p] could not allocate thread callout function. Aborting start", getName(), this);
return false;
}
USBLog(7, "-%s[%p]::start", getName(), this);
return true;
}
IOReturn
AppleUSBEHCI::UIMInitialize(IOService * provider)
{
UInt32 CapLength, USBCmd;
IOReturn err = kIOReturnSuccess;
UInt32 lvalue;
int i;
USBLog(7, "%s[%p]::UIMInitialize", getName(), this);
_device = OSDynamicCast(IOPCIDevice, provider);
if(_device == NULL)
return kIOReturnBadArgument;
do {
if (!(_deviceBase = provider->mapDeviceMemoryWithIndex(0)))
{
USBError(1, "%s[%p]::UIMInitialize - unable to get device memory", getName(), this);
err = kIOReturnNoResources;
break;
}
USBLog(3, "%s: config @ %lx (%lx)\n", getName(),
(long)_deviceBase->getVirtualAddress(),
_deviceBase->getPhysicalAddress());
SetVendorInfo();
_filterInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this,
AppleUSBEHCI::InterruptHandler,
AppleUSBEHCI::PrimaryInterruptFilter,
_device );
if ( !_filterInterruptSource )
{
USBError(1,"%s[%p]: unable to get filterInterruptEventSource", getName(), this);
err = kIOReturnNoResources;
break;
}
err = _workLoop->addEventSource(_filterInterruptSource);
if ( err != kIOReturnSuccess )
{
USBError(1,"%s[%p]: unable to add filter event source: 0x%x", getName(), this, err);
err = kIOReturnNoResources;
break;
}
_errataBits = GetErrataBits(_vendorID, _deviceID, _revisionID);
USBLog(7, "%s[%p]::UIMInitialize - errata bits=%x", getName(), this, _errataBits);
_pageSize = PAGE_SIZE;
_pEHCICapRegisters = (EHCICapRegistersPtr) _deviceBase->getVirtualAddress();
lvalue = _device->configRead32(cwCommand);
_device->configWrite32(cwCommand, (lvalue & 0xffff0000) | (cwCommandEnableBusMaster | cwCommandEnableMemorySpace));
CapLength = _pEHCICapRegisters->CapLength;
_pEHCIRegisters = (EHCIRegistersPtr) ( ((UInt32)_pEHCICapRegisters) + CapLength);
_workLoop->enableAllInterrupts();
_rootHubFuncAddress = 1;
_pEHCIRegisters->USBCMD = 0; for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit); i++)
IOSleep(1);
if (i >= 100)
{
USBError(1, "%s[%p]::UIMInitialize - could not get chip to halt within 100 ms", getName(), this);
err = kIOReturnInternalError;
break;
}
_pEHCIRegisters->USBCMD = HostToUSBLong(kEHCICMDHCReset); for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBCMD) & kEHCICMDHCReset); i++)
IOSleep(1);
if (i >= 100)
{
USBError(1, "%s[%p]::UIMInitialize - could not get chip to come out of reset within 100 ms", getName(), this);
err = kIOReturnInternalError;
break;
}
_pEHCIRegisters->PeriodicListBase = 0; _pEHCIRegisters->AsyncListAddr = 0; _pEHCIRegisters->USBIntr = HostToUSBLong(kEHCICompleteIntBit | kEHCIErrorIntBit | kEHCIHostErrorIntBit | kEHCIFrListRolloverIntBit);
USBCmd = USBToHostLong(_pEHCIRegisters->USBCMD);
_frameListSize = (USBCmd & kEHCICMDFrameListSizeMask) >> kEHCICMDFrameListSizeOffset;
if (_frameListSize)
{
USBError(1, "%s[%p]::UIMInitialize - bad _frameListSize", getName(), this);
err = kIOReturnInternalError;
break;
}
_frameListSize = 1024;
USBCmd |= kEHCICMDRunStop;
_ehciBusState = kEHCIBusStateRunning;
USBCmd |= 8 << kEHCICMDIntThresholdOffset; _pEHCIRegisters->USBCMD = USBToHostLong(USBCmd);
_pEHCIRegisters->ConfigFlag = USBToHostLong(kEHCIPortRoutingBit); IOSync();
_isochBandwidthAvail = 5 *1024;
_outSlot = kEHCIPeriodicListEntries+1;
_frameNumber = 0;
if ((err = InterruptInitialize()))
continue;
_uimInitialized = true;
return kIOReturnSuccess;
} while (false);
USBError(1, "%s[%p]::UIMInitialize - Error occurred (0x%x)", getName(), this, err);
UIMFinalize();
if (_filterInterruptSource)
_filterInterruptSource->release();
return(err);
}
IOReturn
AppleUSBEHCI::AsyncInitialize (void)
{
_AsyncHead = NULL;
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::InterruptInitialize (void)
{
int i;
UInt32 termBit, *list;
AppleEHCIListElement **logical;
IOPhysicalAddress physPtr;
_periodicList = (UInt32 *)IOMallocContiguous(kEHCIPeriodicFrameListsize, kEHCIPageSize, &physPtr);
if(_periodicList == NULL)
{
return kIOReturnNoResources;
}
_pEHCIRegisters->PeriodicListBase = HostToUSBLong(physPtr);
_logicalPeriodicList = (AppleEHCIListElement **)IOMalloc(kEHCIPeriodicFrameListsize);
if(_logicalPeriodicList == NULL)
{
_periodicList = NULL;
return kIOReturnNoResources;
}
termBit = HostToUSBLong(kEHCITermFlag);
list = (UInt32 *)_periodicList;
logical = _logicalPeriodicList;
for(i= 0; i<kEHCIPeriodicListEntries; i++)
{
*(list++) = termBit;
*(logical++) = NULL;
}
for (i=0; i<kEHCIMaxPoll; i++)
_periodicBandwidth[i] = kEHCIMaxPeriodicBandwidth;
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::UIMFinalize(void)
{
int i;
IOReturn err = kIOReturnSuccess;
if ( _deviceBase )
USBLog (3, "%s[%p]: @ %lx (%lx)(shutting down HW)",getName(), this, (long)_deviceBase->getVirtualAddress(), _deviceBase->getPhysicalAddress());
if ( _workLoop )
_workLoop->disableAllInterrupts();
IOSleep(2);
if ( !isInactive() && _pEHCIRegisters && _device )
{
_pEHCIRegisters->USBIntr = 0x0;
IOSync();
_pEHCIRegisters->USBCMD = 0; for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit); i++)
IOSleep(1);
if (i >= 100)
{
USBError(1, "%s[%p]::UIMInitialize - could not get chip to halt within 100 ms", getName(), this);
err = kIOReturnInternalError;
goto ErrorExit;
}
_pEHCIRegisters->USBCMD = HostToUSBLong(kEHCICMDHCReset); for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBCMD) & kEHCICMDHCReset); i++)
IOSleep(1);
if (i >= 100)
{
USBError(1, "%s[%p]::UIMInitialize - could not get chip to come out of reset within 100 ms", getName(), this);
err = kIOReturnInternalError;
goto ErrorExit;
}
_device->configWrite32(cwCommand, cwCommandEnableMemorySpace);
_pEHCIRegisters->PeriodicListBase = 0; _pEHCIRegisters->AsyncListAddr = 0; IOSync();
}
if ( _periodicList )
IOFree( _periodicList, kEHCIPeriodicFrameListsize );
if ( _logicalPeriodicList )
IOFree( _logicalPeriodicList, kEHCIPeriodicFrameListsize );
if ( _filterInterruptSource && _workLoop )
{
_workLoop->removeEventSource(_filterInterruptSource);
_filterInterruptSource->release();
_filterInterruptSource = NULL;
}
ErrorExit:
_uimInitialized = false;
return err;
}
UInt32
AppleUSBEHCI::GetBandwidthAvailable()
{
USBLog(7, "%s[%p]::GetBandwidthAvailable -- returning %d", getName(), this, _isochBandwidthAvail);
return _isochBandwidthAvail;
}
UInt32
AppleUSBEHCI::GetFrameNumber32()
{
UInt32 temp1, temp2;
register UInt32 frindex;
do
{
temp1 = (UInt32)_frameNumber;
frindex = HostToUSBLong(_pEHCIRegisters->FRIndex);
IOSync();
temp2 = (UInt32)_frameNumber;
} while ((temp1 != temp2) || (frindex == 0) );
frindex = frindex >> 3;
USBLog(7, "%s[%p]::GetFrameNumber32 -- returning %d (0x%x)", getName(), this, (UInt32)(temp1+frindex), (UInt32)(temp1+frindex));
return (UInt32)(temp1 + frindex);
}
UInt64
AppleUSBEHCI::GetFrameNumber()
{
UInt64 temp1, temp2;
register UInt32 frindex;
do
{
temp1 = _frameNumber;
frindex = HostToUSBLong(_pEHCIRegisters->FRIndex);
IOSync();
temp2 = _frameNumber;
} while ( (temp1 != temp2) || (frindex == 0) );
frindex = frindex >> 3;
USBLog(7, "%s[%p]::GetFrameNumber -- returning %Ld (0x%Lx)", getName(), this, temp1+frindex, temp1+frindex);
return (temp1 + frindex);
}
UInt64
AppleUSBEHCI::GetMicroFrameNumber()
{
UInt64 temp1, temp2;
register UInt32 frindex;
do
{
temp1 = _frameNumber;
frindex = HostToUSBLong(_pEHCIRegisters->FRIndex);
IOSync();
temp2 = _frameNumber;
} while ( (temp1 != temp2) || (frindex == 0) );
temp1 = temp1 << 3;
USBLog(7, "%s[%p]::GetMicroFrameNumber -- returning %Ld (0x%Lx)", getName(), this, temp1+frindex, temp1+frindex);
return (temp1 + frindex);
}
void
AppleUSBEHCI::SetVendorInfo(void)
{
OSData *vendProp, *deviceProp, *revisionProp;
vendProp = OSDynamicCast(OSData, _device->getProperty( "vendor-id" ));
if (vendProp)
_vendorID = *((UInt32 *) vendProp->getBytesNoCopy());
deviceProp = OSDynamicCast(OSData, _device->getProperty( "device-id" ));
if (deviceProp)
_deviceID = *((UInt32 *) deviceProp->getBytesNoCopy());
revisionProp = OSDynamicCast(OSData, _device->getProperty( "revision-id" ));
if (revisionProp)
_revisionID = *((UInt32 *) revisionProp->getBytesNoCopy());
}
AppleEHCIQueueHead *
AppleUSBEHCI::AllocateQH(void)
{
AppleEHCIQueueHead *freeQH;
freeQH = _pFreeQH;
if (freeQH == NULL)
{
AppleEHCIedMemoryBlock *memBlock;
UInt32 numEDs, i;
memBlock = AppleEHCIedMemoryBlock::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();
_pLastFreeQH = AppleEHCIQueueHead::WithSharedMemory(memBlock->GetLogicalPtr(0), memBlock->GetPhysicalPtr(0));
_pFreeQH = _pLastFreeQH;
for (i=1; i < numEDs; i++)
{
freeQH = AppleEHCIQueueHead::WithSharedMemory(memBlock->GetLogicalPtr(i), memBlock->GetPhysicalPtr(i));
if (!freeQH)
{
USBLog(1, "%s[%p]::AllocateED - hmm. ran out of EDs in a memory block", getName(), this);
freeQH = _pFreeQH;
break;
}
freeQH->_logicalNext = _pFreeQH;
_pFreeQH = freeQH;
}
}
if (freeQH)
{
_pFreeQH = OSDynamicCast(AppleEHCIQueueHead, freeQH->_logicalNext);
freeQH->_logicalNext = NULL;
}
return freeQH;
}
IOReturn
AppleUSBEHCI::DeallocateTD (EHCIGeneralTransferDescriptorPtr pTD)
{
UInt32 physical;
physical = pTD->pPhysical;
pTD->pLogicalNext = NULL;
pTD->pPhysical = physical;
if (_pLastFreeTD)
{
_pLastFreeTD->pLogicalNext = pTD;
_pLastFreeTD = pTD;
}
else
{
_pLastFreeTD = pTD;
_pFreeTD = pTD;
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::DeallocateED (AppleEHCIQueueHead *pED)
{
USBLog(7, "%s[%p]::DeallocateED - deallocating %p", getName(), this, pED);
pED->_logicalNext = NULL;
if (_pLastFreeQH)
{
_pLastFreeQH->_logicalNext = pED;
_pLastFreeQH = pED;
}
else
{
_pLastFreeQH = pED;
_pFreeQH = pED;
}
return (kIOReturnSuccess);
}
EHCIGeneralTransferDescriptorPtr
AppleUSBEHCI::AllocateTD(void)
{
EHCIGeneralTransferDescriptorPtr freeTD;
freeTD = _pFreeTD;
if (freeTD == NULL)
{
AppleEHCItdMemoryBlock *memBlock;
UInt32 numTDs, i;
memBlock = AppleEHCItdMemoryBlock::NewMemoryBlock();
if (!memBlock)
{
USBError(1, "%s[%p]::AllocateTD - unable to allocate a new memory block!", getName(), this);
return NULL;
}
memBlock->SetNextBlock(_tdMBHead);
_tdMBHead = memBlock;
numTDs = memBlock->NumTDs();
_pLastFreeTD = memBlock->GetTD(0); for (i=0; i < numTDs; i++)
{
freeTD = memBlock->GetTD(i);
if (!freeTD)
{
USBError(1, "%s[%p]::AllocateTD - hmm. ran out of TDs in a memory block", getName(), this);
freeTD = _pFreeTD;
break;
}
freeTD->pLogicalNext = _pFreeTD;
_pFreeTD = freeTD;
}
}
if (freeTD)
{
_pFreeTD = freeTD->pLogicalNext;
freeTD->pLogicalNext = NULL;
freeTD->lastFrame = 0;
freeTD->lastRemaining = 0;
freeTD->command = NULL;
}
return freeTD;
}
AppleEHCIIsochTransferDescriptor *
AppleUSBEHCI::AllocateITD(void)
{
AppleEHCIIsochTransferDescriptor *freeITD;
freeITD = _pFreeITD;
if (freeITD == NULL)
{
AppleEHCIitdMemoryBlock *memBlock;
UInt32 numTDs, i;
memBlock = AppleEHCIitdMemoryBlock::NewMemoryBlock();
if (!memBlock)
{
USBError(1, "%s[%p]::AllocateITD - unable to allocate a new memory block!", getName(), this);
return NULL;
}
memBlock->SetNextBlock(_itdMBHead);
_itdMBHead = memBlock;
numTDs = memBlock->NumTDs();
_pLastFreeITD = AppleEHCIIsochTransferDescriptor::WithSharedMemory(memBlock->GetLogicalPtr(0), memBlock->GetPhysicalPtr(0));
_pFreeITD = _pLastFreeITD;
for (i=1; i < numTDs; i++)
{
freeITD = AppleEHCIIsochTransferDescriptor::WithSharedMemory(memBlock->GetLogicalPtr(i), memBlock->GetPhysicalPtr(i));
if (!freeITD)
{
USBError(1, "%s[%p]::AllocateTD - hmm. ran out of TDs in a memory block", getName(), this);
freeITD = _pFreeITD;
break;
}
freeITD->_logicalNext = _pFreeITD;
_pFreeITD = freeITD;
}
}
if (freeITD)
{
_pFreeITD = OSDynamicCast(AppleEHCIIsochTransferDescriptor, freeITD->_logicalNext);
freeITD->_logicalNext = NULL;
if (!_pFreeITD)
_pLastFreeITD = NULL;
}
USBLog(1, "%s[%p]::AllocateITD - returning %p", getName(), this, freeITD);
return freeITD;
}
IOReturn
AppleUSBEHCI::DeallocateITD (AppleEHCIIsochTransferDescriptor *pTD)
{
USBLog(7, "%s[%p]::DeallocateITD - deallocating %p", getName(), this, pTD);
pTD->_logicalNext = NULL;
if (_pLastFreeITD)
{
_pLastFreeITD->_logicalNext = pTD;
_pLastFreeITD = pTD;
}
else
{
_pLastFreeITD = pTD;
_pFreeITD = pTD;
}
return kIOReturnSuccess;
}
AppleEHCISplitIsochTransferDescriptor *
AppleUSBEHCI::AllocateSITD(void)
{
AppleEHCISplitIsochTransferDescriptor *freeSITD;
freeSITD = _pFreeSITD;
if (freeSITD == NULL)
{
AppleEHCIsitdMemoryBlock *memBlock;
UInt32 numTDs, i;
memBlock = AppleEHCIsitdMemoryBlock::NewMemoryBlock();
if (!memBlock)
{
USBError(1, "%s[%p]::AllocateTD - unable to allocate a new memory block!", getName(), this);
return NULL;
}
memBlock->SetNextBlock(_sitdMBHead);
_sitdMBHead = memBlock;
numTDs = memBlock->NumTDs();
USBLog(3, "%s[%p]::AllocateSITD - got new memory block (%p) with %d SITDs in it", getName(), this, memBlock, numTDs);
_pLastFreeSITD = AppleEHCISplitIsochTransferDescriptor::WithSharedMemory(memBlock->GetLogicalPtr(0), memBlock->GetPhysicalPtr(0));
_pFreeSITD = _pLastFreeSITD;
for (i=1; i < numTDs; i++)
{
freeSITD = AppleEHCISplitIsochTransferDescriptor::WithSharedMemory(memBlock->GetLogicalPtr(i), memBlock->GetPhysicalPtr(i));
if (!freeSITD)
{
USBError(1, "%s[%p]::AllocateTD - hmm. ran out of TDs in a memory block", getName(), this);
freeSITD = _pFreeSITD;
break;
}
freeSITD->_logicalNext = _pFreeSITD;
_pFreeSITD = freeSITD;
}
}
if (freeSITD)
{
_pFreeSITD = OSDynamicCast(AppleEHCISplitIsochTransferDescriptor, freeSITD->_logicalNext);
if (!_pFreeSITD)
_pLastFreeSITD = NULL;
freeSITD->_logicalNext = NULL;
}
USBLog(7, "%s[%p]::AllocateSITD - returning %p", getName(), this, freeSITD);
return freeSITD;
}
IOReturn
AppleUSBEHCI::DeallocateSITD (AppleEHCISplitIsochTransferDescriptor *pTD)
{
USBLog(7, "%s[%p]::DeallocateSITD - deallocating %p", getName(), this, pTD);
pTD->_logicalNext = NULL;
if (_pLastFreeSITD)
{
_pLastFreeSITD->_logicalNext = pTD;
_pLastFreeSITD = pTD;
}
else
{
_pLastFreeSITD = pTD;
_pFreeSITD = pTD;
}
return kIOReturnSuccess;
}
AppleEHCIIsochEndpointPtr
AppleUSBEHCI::AllocateIsochEP()
{
AppleEHCIIsochEndpointPtr pEP;
pEP = _freeIsochEPList;
if (!pEP)
{
pEP = (AppleEHCIIsochEndpointPtr)IOMalloc(sizeof(AppleEHCIIsochEndpointStruct));
if (pEP)
pEP->nextEP = NULL;
}
if (pEP)
{
_freeIsochEPList = pEP->nextEP;
}
return pEP;
}
IOReturn
AppleUSBEHCI::DeallocateIsochEP(AppleEHCIIsochEndpointPtr pEP)
{
pEP->nextEP = _freeIsochEPList;
_freeIsochEPList = pEP;
return kIOReturnSuccess;
}
void
AppleUSBEHCI::doCallback(EHCIGeneralTransferDescriptorPtr nextTD,
UInt32 transferStatus,
UInt32 bufferSizeRemaining)
{
USBError(1, "%s[%p]::doCallback unimemented *************", getName(), this);
}
IOReturn
AppleUSBEHCI::UIMInitializeForPowerUp(void)
{
UInt32 CapLength, USBCmd;
IOReturn err = kIOReturnSuccess;
UInt32 lvalue;
int i;
USBLog(5, "%s[%p]: initializing UIM for PowerUp @ %lx (%lx)", getName(), this,
(long)_deviceBase->getVirtualAddress(),
_deviceBase->getPhysicalAddress());
do {
lvalue = _device->configRead32(cwCommand);
_device->configWrite32(cwCommand, (lvalue & 0xffff0000) | (cwCommandEnableBusMaster | cwCommandEnableMemorySpace));
CapLength = _pEHCICapRegisters->CapLength;
_pEHCIRegisters = (EHCIRegistersPtr) ( ((UInt32)_pEHCICapRegisters) + CapLength);
_workLoop->enableAllInterrupts();
_rootHubFuncAddress = 1;
_pEHCIRegisters->USBCMD = 0; for ( i = 0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit); i++ )
IOSleep(1);
if ( i >= 100 )
{
USBError(1, "%s[%p]::UIMInitialize - could not get chip to halt within 100 ms", getName(), this);
err = kIOReturnInternalError;
break;
}
_pEHCIRegisters->USBCMD = HostToUSBLong(kEHCICMDHCReset);
for ( i = 0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBCMD) & kEHCICMDHCReset); i++ )
IOSleep(1);
if ( i >= 100 )
{
USBError(1, "%s[%p]::UIMInitialize - could not get chip to come out of reset within 100 ms", getName(), this);
err = kIOReturnInternalError;
break;
}
_pEHCIRegisters->USBIntr = HostToUSBLong(kEHCICompleteIntBit | kEHCIErrorIntBit | kEHCIHostErrorIntBit | kEHCIFrListRolloverIntBit);
USBCmd = USBToHostLong(_pEHCIRegisters->USBCMD);
_frameListSize = (USBCmd & kEHCICMDFrameListSizeMask) >> kEHCICMDFrameListSizeOffset;
if (_frameListSize)
{
USBError(1, "%s[%p]::UIMInitialize - bad _frameListSize", getName(), this);
err = kIOReturnInternalError;
break;
}
_frameListSize = 1024;
USBCmd |= kEHCICMDRunStop;
_ehciBusState = kEHCIBusStateRunning;
USBCmd |= 8 << kEHCICMDIntThresholdOffset; _pEHCIRegisters->USBCMD = USBToHostLong(USBCmd);
_pEHCIRegisters->ConfigFlag = USBToHostLong(kEHCIPortRoutingBit); IOSync();
_isochBandwidthAvail = 5 *1024;
_outSlot = kEHCIPeriodicListEntries+1;
_frameNumber = 0;
_uimInitialized = true;
_pEHCIRegisters->PeriodicListBase = _savedPeriodicListBase;
_pEHCIRegisters->AsyncListAddr = _savedAsyncListAddr;
return kIOReturnSuccess;
} while (false);
USBError(1, "%s[%p]::UIMInitializeForPowerUp - Error occurred (0x%x)", getName(), this, err);
UIMFinalize();
if (_filterInterruptSource)
_filterInterruptSource->release();
return err;
}
IOReturn
AppleUSBEHCI::UIMFinalizeForPowerDown(void)
{
int i;
IOReturn err;
if ( _deviceBase )
USBLog (3, "%s[%p]: @ %lx (%lx)(turning off HW)",getName(), this, (long)_deviceBase->getVirtualAddress(), _deviceBase->getPhysicalAddress());
if ( _workLoop )
_workLoop->disableAllInterrupts();
IOSleep(2);
if ( _pEHCIRegisters && _device )
{
_pEHCIRegisters->USBIntr = 0x0;
IOSync();
_savedPeriodicListBase = _pEHCIRegisters->PeriodicListBase;
_savedAsyncListAddr = _pEHCIRegisters->AsyncListAddr;
_pEHCIRegisters->USBCMD = 0; for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit); i++)
IOSleep(1);
if (i >= 100)
{
USBError(1, "%s[%p]::UIMInitializeForPowerUp - could not get chip to halt within 100 ms", getName(), this);
err = kIOReturnInternalError;
goto ErrorExit;
}
_pEHCIRegisters->USBCMD = HostToUSBLong(kEHCICMDHCReset); for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBCMD) & kEHCICMDHCReset); i++)
IOSleep(1);
if (i >= 100)
{
USBError(1, "%s[%p]::UIMInitializeForPowerUp - could not get chip to come out of reset within 100 ms", getName(), this);
err = kIOReturnInternalError;
goto ErrorExit;
}
_device->configWrite32(cwCommand, cwCommandEnableMemorySpace);
_pEHCIRegisters->PeriodicListBase = 0; _pEHCIRegisters->AsyncListAddr = 0; IOSync();
}
ErrorExit:
_uimInitialized = false;
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::EnableAsyncSchedule(void)
{
int i;
IOReturn stat = kIOReturnSuccess;
if (!(_pEHCIRegisters->USBCMD & HostToUSBLong(kEHCICMDAsyncEnable)))
{
for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSAsyncScheduleStatus); i++)
IOSleep(1);
if (i)
{
if (i >= 100)
{
USBLog(1, "%s[%p]::EnableAsyncSchedule: ERROR: USBCMD and USBSTS won't synchronize OFF", getName(), this);
stat = kIOReturnInternalError;
}
else
{
USBLog(7, "%s[%p]::EnableAsyncSchedule: had to wait %d ms for CMD and STS to synch up OFF", getName(), this, i);
}
}
if (!stat)
{
if (_errataBits & kErrataAgereEHCIAsyncSched)
{
_pEHCIRegisters->USBCMD &= HostToUSBLong(~kEHCICMDRunStop);
while (!(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit))
;
_pEHCIRegisters->USBCMD |= HostToUSBLong(kEHCICMDAsyncEnable | kEHCICMDRunStop);
}
else
{
_pEHCIRegisters->USBCMD |= HostToUSBLong(kEHCICMDAsyncEnable);
}
for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSAsyncScheduleStatus); i++)
IOSleep(1);
if (i)
{
if (i >= 100)
{
USBError(1, "%s[%p]::EnableAsyncSchedule: ERROR: USBCMD and USBSTS won't synchronize ON - cannot enable USB list processing", getName(), this);
stat = kIOReturnInternalError;
}
else
{
USBLog(7, "%s[%p]::EnableAsyncSchedule: had to wait %d ms for CMD and STS to synch up ON", getName(), this, i);
}
}
}
}
else
{
USBLog(7, "%s[%p]::EnableAsyncSchedule: schedule was already enabled", getName(), this);
}
if (stat)
{
USBLog(1, "%s[%p]::EnableAsyncSchedule: returning status %x", getName(), this, stat);
}
else
{
USBLog(7, "%s[%p]::EnableAsyncSchedule: schedule enabled cleanly", getName(), this);
}
return stat;
}
IOReturn
AppleUSBEHCI::DisableAsyncSchedule(void)
{
int i;
IOReturn stat = kIOReturnSuccess;
if (_pEHCIRegisters->USBCMD & HostToUSBLong(kEHCICMDAsyncEnable))
{
for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSAsyncScheduleStatus); i++)
IOSleep(1);
if (i)
{
if (i >= 100)
{
USBLog(1, "%s[%p]::DisableAsyncSchedule: ERROR: USBCMD and USBSTS won't synchronize ON", getName(), this);
stat = kIOReturnInternalError;
}
else
{
USBLog(7, "%s[%p]::DisableAsyncSchedule: had to wait %d ms for CMD and STS to synch up ON", getName(), this, i);
}
}
if (!stat)
{
_pEHCIRegisters->USBCMD &= HostToUSBLong(~kEHCICMDAsyncEnable);
for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSAsyncScheduleStatus); i++)
IOSleep(1);
if (i)
{
if (i >= 100)
{
USBLog(1, "%s[%p]::DisableAsyncSchedule: ERROR: USBCMD and USBSTS won't synchronize OFF", getName(), this);
stat = kIOReturnInternalError;
}
else
{
USBLog(7, "%s[%p]::DisableAsyncSchedule: had to wait %d ms for CMD and STS to synch up OFF", getName(), this, i);
}
}
}
}
else
{
USBLog(7, "%s[%p]::DisableAsyncSchedule: schedule was already disabled", getName(), this);
}
if (stat)
{
USBLog(1, "%s[%p]::DisableAsyncSchedule: returning status %x", getName(), this, stat);
}
else
{
USBLog(7, "%s[%p]::DisableAsyncSchedule: schedule disabled cleanly", getName(), this);
}
return stat;
}
IOReturn
AppleUSBEHCI::EnablePeriodicSchedule(void)
{
int i;
IOReturn stat = kIOReturnSuccess;
if (!(_pEHCIRegisters->USBCMD & HostToUSBLong(kEHCICMDPeriodicEnable)))
{
for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSPeriodicScheduleStatus); i++)
IOSleep(1);
if (i)
{
if (i >= 100)
{
USBLog(1, "%s[%p]::EnablePeriodicSchedule: ERROR: USBCMD and USBSTS won't synchronize OFF", getName(), this);
stat = kIOReturnInternalError;
}
else
{
USBLog(7, "%s[%p]::EnablePeriodicSchedule: had to wait %d ms for CMD and STS to synch up OFF", getName(), this, i);
}
}
if (!stat)
{
_pEHCIRegisters->USBCMD |= HostToUSBLong(kEHCICMDPeriodicEnable);
for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSPeriodicScheduleStatus); i++)
IOSleep(1);
if (i)
{
if (i >= 100)
{
USBLog(1, "%s[%p]::EnablePeriodicSchedule: ERROR: USBCMD and USBSTS won't synchronize ON", getName(), this);
stat = kIOReturnInternalError;
}
else
{
USBLog(7, "%s[%p]::EnablePeriodicSchedule: had to wait %d ms for CMD and STS to synch up ON", getName(), this, i);
}
}
}
}
else
{
USBLog(7, "%s[%p]::EnablePeriodicSchedule: schedule was already enabled", getName(), this);
}
if (stat)
{
USBLog(1, "%s[%p]::EnablePeriodicSchedule: returning status %x", getName(), this, stat);
}
else
{
USBLog(7, "%s[%p]::EnablePeriodicSchedule: schedule enabled cleanly", getName(), this);
}
return stat;
}
IOReturn
AppleUSBEHCI::DisablePeriodicSchedule(void)
{
int i;
IOReturn stat = kIOReturnSuccess;
if (_pEHCIRegisters->USBCMD & HostToUSBLong(kEHCICMDPeriodicEnable))
{
for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSPeriodicScheduleStatus); i++)
IOSleep(1);
if (i)
{
if (i >= 100)
{
USBLog(1, "%s[%p]::DisablePeriodicSchedule: ERROR: USBCMD and USBSTS won't synchronize ON", getName(), this);
stat = kIOReturnInternalError;
}
else
{
USBLog(7, "%s[%p]::DisablePeriodicSchedule: had to wait %d ms for CMD and STS to synch up ON", getName(), this, i);
}
}
if (!stat)
{
_pEHCIRegisters->USBCMD &= HostToUSBLong(~kEHCICMDPeriodicEnable);
for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSPeriodicScheduleStatus); i++)
IOSleep(1);
if (i)
{
if (i >= 100)
{
USBLog(1, "%s[%p]::DisablePeriodicSchedule: ERROR: USBCMD and USBSTS won't synchronize OFF", getName(), this);
stat = kIOReturnInternalError;
}
else
{
USBLog(7, "%s[%p]::DisablePeriodicSchedule: had to wait %d ms for CMD and STS to synch up OFF", getName(), this, i);
}
}
}
}
else
{
USBLog(7, "%s[%p]::DisablePeriodicSchedule: schedule was already disabled", getName(), this);
}
if (stat)
{
USBLog(1, "%s[%p]::DisablePeriodicSchedule: returning status %x", getName(), this, stat);
}
else
{
USBLog(7, "%s[%p]::DisablePeriodicSchedule: schedule disabled cleanly", getName(), this);
}
return stat;
}
AppleEHCIIsochEndpointPtr
AppleUSBEHCI::FindIsochronousEndpoint(
short functionAddress,
short endpointNumber,
short direction,
AppleEHCIIsochEndpointPtr *ppEPBack)
{
AppleEHCIIsochEndpointPtr pEP, pBack;
pEP = _isochEPList;
pBack = NULL;
while (pEP)
{
if ((pEP->functionAddress == functionAddress)
&& (pEP->endpointNumber == endpointNumber)
&& (pEP->direction == direction))
break;
pBack = pEP;
pEP = pEP->nextEP;
}
if (pEP && ppEPBack)
*ppEPBack = pBack;
return pEP;
}
AppleEHCIIsochEndpointPtr
AppleUSBEHCI::CreateIsochronousEndpoint(
short functionAddress,
short endpointNumber,
short direction,
USBDeviceAddress highSpeedHub,
int highSpeedPort)
{
AppleEHCIIsochEndpointPtr pEP;
pEP = AllocateIsochEP();
if (pEP)
{
pEP->toDoList = NULL;
pEP->toDoEnd = NULL;
pEP->doneQueue = NULL;
pEP->doneEnd = NULL;
pEP->deferredQueue = NULL;
pEP->deferredEnd = NULL;
pEP->firstAvailableFrame = 0;
pEP->accumulatedStatus = kIOReturnSuccess;
pEP->inSlot = 0;
pEP->activeTDs = 0;
pEP->functionAddress = functionAddress;
pEP->endpointNumber = endpointNumber;
pEP->direction = direction;
pEP->highSpeedHub = highSpeedHub;
pEP->highSpeedPort = highSpeedPort;
pEP->nextEP = _isochEPList;
_isochEPList = pEP;
}
return pEP;
}
IOReturn
AppleUSBEHCI::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;
}
}
USBLog(6, "%s[%p]::message type: 0x%x, isInactive = %d", getName(), this, type, isInactive());
return super::message( type, provider, argument );
}