#include <TargetConditionals.h>
#include <libkern/OSByteOrder.h>
#include <IOKit/IOMemoryCursor.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/IOFilterInterruptEventSource.h>
#include <IOKit/usb/USB.h>
#include <IOKit/usb/IOUSBLog.h>
#include <IOKit/usb/IOUSBRootHubDevice.h>
#include "AppleUSBEHCI.h"
#include "AppleUSBEHCIDiagnostics.h"
#include "AppleEHCIedMemoryBlock.h"
#include "AppleEHCItdMemoryBlock.h"
#include "AppleEHCIitdMemoryBlock.h"
#include "AppleEHCIsitdMemoryBlock.h"
#include "USBTracepoints.h"
#define super IOUSBControllerV3
#define self this
#define NUM_BUFFER_PAGES 9 // 54
#define NUM_TDS 255 // 1500
#define NUM_EDS 256 // 1500
#define NUM_ITDS 192 // 1300
#if EHCI_USE_KPRINTF
#undef USBLog
#undef USBError
void kprintf(const char *format, ...)
__attribute__((format(printf, 1, 2)));
#define USBLog( LEVEL, FORMAT, ARGS... ) if ((LEVEL) <= EHCI_USE_KPRINTF) { kprintf( FORMAT "\n", ## ARGS ) ; }
#define USBError( LEVEL, FORMAT, ARGS... ) { kprintf( FORMAT "\n", ## ARGS ) ; }
#endif
OSDefineMetaClassAndStructors(AppleUSBEHCI, IOUSBControllerV3)
bool
AppleUSBEHCI::init(OSDictionary * propTable)
{
if (!super::init(propTable))
return false;
_myBusState = kUSBBusStateReset;
_hasPCIPwrMgmt = false;
_wdhLock = IOSimpleLockAlloc();
if (!_wdhLock)
goto ErrorExit;
_isochScheduleLock = IOSimpleLockAlloc();
if (!_isochScheduleLock)
goto ErrorExit;
_uimInitialized = false;
_controllerSpeed = kUSBDeviceSpeedHigh;
_producerCount = 1;
_consumerCount = 1;
return true;
ErrorExit:
if ( _wdhLock )
IOSimpleLockFree(_wdhLock);
if (_isochScheduleLock)
IOSimpleLockFree(_isochScheduleLock);
return false;
}
void
AppleUSBEHCI::stop( IOService * provider )
{
if (_controllerAvailable)
{
USBLog(5, "AppleUSBEHCI[%p]::stop - isInactive(%s) - USBCMD(%p) USBSTS(%p)", this, isInactive() ? "true" : "false", (void*)USBToHostLong(_pEHCIRegisters->USBCMD), (void*)USBToHostLong(_pEHCIRegisters->USBSTS));
}
else
{
USBLog(5, "AppleUSBEHCI[%p]::stop - isInactive(%s) - Unavailable Registers", this, isInactive() ? "true" : "false");
}
super::stop(provider);
}
bool
AppleUSBEHCI::willTerminate(IOService * provider, IOOptionBits options)
{
UInt32 sts;
if (_controllerAvailable)
{
sts = USBToHostLong(_pEHCIRegisters->USBSTS);
if (sts == kEHCIInvalidRegisterValue)
{
USBLog(2, "AppleUSBEHCI[%p]::willTerminate - controller no longer available", this);
_controllerAvailable = false;
}
}
if (_controllerAvailable)
{
USBLog(5, "AppleUSBEHCI[%p]::willTerminate - isInactive(%s) - USBCMD(%p) USBSTS(%p)", this, isInactive() ? "true" : "false", (void*)USBToHostLong(_pEHCIRegisters->USBCMD), (void*)USBToHostLong(_pEHCIRegisters->USBSTS));
}
else
{
USBLog(5, "AppleUSBEHCI[%p]::willTerminate - isInactive(%s) - Unavailable Registers", this, isInactive() ? "true" : "false");
}
return super::willTerminate(provider, options);
}
bool
AppleUSBEHCI::didTerminate( IOService * provider, IOOptionBits options, bool * defer )
{
if (_controllerAvailable)
{
USBLog(5, "AppleUSBEHCI[%p]::didTerminate - isInactive(%s) - USBCMD(%p) USBSTS(%p)", this, isInactive() ? "true" : "false", (void*)USBToHostLong(_pEHCIRegisters->USBCMD), (void*)USBToHostLong(_pEHCIRegisters->USBSTS));
}
else
{
USBLog(5, "AppleUSBEHCI[%p]::didTerminate - isInactive(%s) - Unavailable Registers", this, isInactive() ? "true" : "false");
}
return super::didTerminate(provider, options, defer);
}
bool
AppleUSBEHCI::finalize(IOOptionBits options)
{
USBLog(3, "AppleUSBEHCI[%p]::finalize - controlBulkTransactionsOut(%d) activeIsochTransfers(%d) activeInterruptTransfers(%d)", this, (int)_controlBulkTransactionsOut, (int)_activeIsochTransfers, (int)_activeInterruptTransfers);
return super::finalize(options);
}
void
AppleUSBEHCI::free()
{
if ( _wdhLock )
IOSimpleLockFree(_wdhLock);
if (_isochScheduleLock)
IOSimpleLockFree(_isochScheduleLock);
super::free();
}
void AppleUSBEHCI::showRegisters(UInt32 level, const char *s)
{
int i;
if (!_controllerAvailable)
return;
if (_pEHCIRegisters->USBCMD == kEHCIInvalidRegisterValue)
{
USBLog(level,"AppleUSBEHCI[%p]::showRegisters - called from %s - registers are not available", this, s);
_controllerAvailable = false;
return;
}
USBLog(level,"AppleUSBEHCI[%p]::showRegisters - called from %s - version: 0x%x", this, s, USBToHostWord(_pEHCICapRegisters->HCIVersion));
#define SHOW_PCI_REGS
#ifdef SHOW_PCI_REGS
USBLog(level,"PCI: kIOPCIConfigVendorID=0x%x", (uint32_t)_device->configRead32(kIOPCIConfigVendorID));
USBLog(level," kIOPCIConfigRevisionID=0x%x", (uint32_t)_device->configRead32(kIOPCIConfigRevisionID));
USBLog(level," kIOPCIConfigCacheLineSize=0x%x", (uint32_t)_device->configRead32(kIOPCIConfigCacheLineSize));
USBLog(level," kIOPCIConfigBaseAddress0=0x%x", (uint32_t)_device->configRead32(kIOPCIConfigBaseAddress0));
USBLog(level," kIOPCIConfigBaseAddress1=0x%x", (uint32_t)_device->configRead32(kIOPCIConfigBaseAddress1));
USBLog(level," kIOPCIConfigExpansionROMBase=0x%x", (uint32_t)_device->configRead32(kIOPCIConfigExpansionROMBase));
USBLog(level," kIOPCIConfigInterruptLine=0x%x", (uint32_t)_device->configRead32(kIOPCIConfigInterruptLine));
USBLog(level," kIOPCIConfigInterruptLine+4=0x%x", (uint32_t)_device->configRead32(kIOPCIConfigInterruptLine+4));
USBLog(level," kIOPCIConfigCommand=%p", (void*)_device->configRead16(kIOPCIConfigCommand));
USBLog(level," kIOPCIConfigStatus=%p", (void*)_device->configRead16(kIOPCIConfigStatus));
#endif
USBLog(level,"EHCI: USBCMD: %p", (void*)USBToHostLong(_pEHCIRegisters->USBCMD));
USBLog(level," USBSTS: %p", (void*)USBToHostLong(_pEHCIRegisters->USBSTS));
USBLog(level," USBIntr: %p", (void*)USBToHostLong(_pEHCIRegisters->USBIntr));
USBLog(level," FRIndex: %p", (void*)USBToHostLong(_pEHCIRegisters->FRIndex));
USBLog(level," CTRLDSSeg: %p", (void*)USBToHostLong(_pEHCIRegisters->CTRLDSSegment));
USBLog(level," PerListBase: %p", (void*)USBToHostLong(_pEHCIRegisters->PeriodicListBase));
USBLog(level," AsyncListAd: %p", (void*)USBToHostLong(_pEHCIRegisters->AsyncListAddr));
USBLog(level," ConfFlg: %p", (void*)USBToHostLong(_pEHCIRegisters->ConfigFlag));
for(i=0;i<_rootHubNumPorts;i++)
{
UInt32 x;
x = USBToHostLong(_pEHCIRegisters->PortSC[i]);
if (x != 0x1000)
{
USBLog(level," PortSC[%d]: 0x%x", i+1, (uint32_t)x);
}
}
}
bool
AppleUSBEHCI::start( IOService * provider )
{
USBLog(7, "AppleUSBEHCI[%p]::start", this);
if ( !super::start(provider))
return (false);
USBLog(7, "AppleUSBEHCI[%p]::start", this);
return true;
}
IOReturn
AppleUSBEHCI::UIMInitialize(IOService * provider)
{
UInt32 CapLength, USBCmd, hccparams, ist;
IOReturn err = kIOReturnSuccess;
UInt16 lvalue;
UInt8 bValue;
int i;
bool gotTimerThreads;
USBLog(7, "AppleUSBEHCI[%p]::UIMInitialize", this);
_device = OSDynamicCast(IOPCIDevice, provider);
if (_device == NULL)
return kIOReturnBadArgument;
do {
if (!(_deviceBase = _device->mapDeviceMemoryWithIndex(0)))
{
USBError(1, "AppleUSBEHCI[%p]::UIMInitialize - unable to get device memory", this);
err = kIOReturnNoResources;
break;
}
USBLog(3, "AppleUSBEHCI[%p]::UIMInitialize config @ %x (%x)\n", this,
(uint32_t)_deviceBase->getVirtualAddress(),
(uint32_t)_deviceBase->getPhysicalAddress());
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
setProperty("BAR", _deviceBase->getPhysicalAddress(), 32);
#endif
SetVendorInfo();
_filterInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this,
AppleUSBEHCI::InterruptHandler,
AppleUSBEHCI::PrimaryInterruptFilter,
_device );
if ( !_filterInterruptSource )
{
USBError(1,"AppleUSBEHCI[%p]: unable to get filterInterruptEventSource", this);
err = kIOReturnNoResources;
break;
}
err = _workLoop->addEventSource(_filterInterruptSource);
if ( err != kIOReturnSuccess )
{
USBError(1,"AppleUSBEHCI[%p]: unable to add filter event source: 0x%x", this, err);
err = kIOReturnNoResources;
break;
}
_errataBits = GetErrataBits(_vendorID, _deviceID, _revisionID);
setProperty("Errata", _errataBits, 32);
if ((_vendorID == 0x12d8) && (_deviceID == 0x400f))
{
UInt16 pwrMgmtDataReg = _device->configRead16(0x84);
if (pwrMgmtDataReg & 0x3)
{
USBError(1,"The USB EHCI driver found a controller at the wrong PCI Power State (0x%x) - fixing that issue.", (int)pwrMgmtDataReg);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
setProperty("Initial PMDR", pwrMgmtDataReg, 16);
#endif
}
_device->configWrite16(0x84, 0);
}
USBLog(7, "AppleUSBEHCI[%p]::UIMInitialize - errata bits=%p", this, (void*)_errataBits);
_pEHCICapRegisters = (EHCICapRegistersPtr) _deviceBase->getVirtualAddress();
_device->configWrite16(kIOPCIConfigCommand, kIOPCICommandMemorySpace);
err = AcquireOSOwnership();
if ( err != kIOReturnSuccess )
{
USBError(1,"AppleUSBEHCI[%p]: unable to obtain ownership: 0x%x", this, err);
break;
}
CheckForSharedXHCIController();
hccparams = USBToHostLong(_pEHCICapRegisters->HCCParams);
if (!(_errataBits & kErrataUse32bitEHCI) && (hccparams & kEHCI64Bit))
_is64bit = true;
else
_is64bit = false;
setProperty("64bit", _is64bit);
ist = (hccparams & kEHCIISTMask) >> kEHCIISTPhase;
if (!ist)
_istKeepAwayFrames = 1;
else
_istKeepAwayFrames = 2;
CapLength = _pEHCICapRegisters->CapLength;
_pEHCIRegisters = (EHCIRegistersPtr) ( ((uintptr_t)_pEHCICapRegisters) + CapLength);
_workLoop->enableAllInterrupts();
_rootHubFuncAddress = 1;
if (_is64bit)
_pEHCIRegisters->CTRLDSSegment = 0;
_pEHCIRegisters->USBCMD = 0; IOSync();
for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit); i++)
IOSleep(1);
if (i >= 100)
{
USBError(1, "AppleUSBEHCI[%p]::UIMInitialize - could not get chip to halt within 100 ms", this);
err = kIOReturnInternalError;
break;
}
_pEHCIRegisters->USBCMD = HostToUSBLong(kEHCICMDHCReset); IOSync();
for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBCMD) & kEHCICMDHCReset); i++)
IOSleep(1);
if (i >= 100)
{
USBError(1, "AppleUSBEHCI[%p]::UIMInitialize - could not get chip to come out of reset within 100 ms", this);
err = kIOReturnInternalError;
break;
}
_pEHCIRegisters->PeriodicListBase = 0; _pEHCIRegisters->AsyncListAddr = 0; IOSync();
USBCmd = USBToHostLong(_pEHCIRegisters->USBCMD);
_frameListSize = (USBCmd & kEHCICMDFrameListSizeMask) >> kEHCICMDFrameListSizeOffset;
if (_frameListSize)
{
USBError(1, "AppleUSBEHCI[%p]::UIMInitialize - bad _frameListSize", this);
err = kIOReturnInternalError;
break;
}
_frameListSize = 1024;
USBCmd &= ~kEHCICMDIntThresholdMask;
USBCmd |= 1 << kEHCICMDIntThresholdOffset;
_myBusState = kUSBBusStateRunning;
_pEHCIRegisters->USBCMD = USBToHostLong(USBCmd);
_pEHCIRegisters->ConfigFlag = HostToUSBLong(kEHCIPortRoutingBit); IOSync();
IOSleep(1);
if (_errataBits & kErrataNECIncompleteWrite)
{
UInt32 newValue = 0, count = 0;
newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag);
while ((count++ < 10) && (newValue != kEHCIPortRoutingBit))
{
USBError(1, "EHCI driver: UIMInitialize - ConfigFlag bit not sticking. Retrying.");
_pEHCIRegisters->ConfigFlag = HostToUSBLong(kEHCIPortRoutingBit);
IOSync();
newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag);
}
}
_outSlot = kEHCIPeriodicListEntries+1; _frameNumber = 0;
if (!_v3ExpansionData->_onThunderbolt)
_expansionData->_isochMaxBusStall = 25000;
_controllerThinkTime = 100;
if ((err = InterruptInitialize()))
continue;
CheckSleepCapability();
gotTimerThreads = true;
_rootHubNumPorts = USBToHostLong(_pEHCICapRegisters->HCSParams) & kEHCINumPortsMask;
for (i=0; i < _rootHubNumPorts; i++)
{
_rhResumePortTimerThread[i] = thread_call_allocate((thread_call_func_t)RHResumePortTimerEntry, (thread_call_param_t)this);
if (!_rhResumePortTimerThread[i])
{
gotTimerThreads = false;
break;
}
}
if (!gotTimerThreads)
continue;
_diagnostics = AppleUSBEHCIDiagnostics::createDiagnostics(this);
if( _diagnostics )
{
setProperty( "Statistics", _diagnostics );
}
_uimInitialized = true;
registerService(); return kIOReturnSuccess;
} while (false);
USBError(1, "AppleUSBEHCI[%p]::UIMInitialize - Error occurred (0x%x)", this, err);
UIMFinalize();
if (_filterInterruptSource)
_filterInterruptSource->release();
return(err);
}
bool
AppleUSBEHCI::XHCIControllerMatchingNotifcationHandler(void * refCon, IOService * newController)
{
#pragma unused(refCon)
_workLoop->CloseGate();
USBLog(3, "AppleUSBEHCI[%p]::XHCIControllerMatchingNotifcationHandler got matching notification from %p", this, newController);
if (newController && _xhciControllerArray)
{
_xhciControllerArray->setObject(newController);
}
_workLoop->Wakeup(_xhciController, true);
_workLoop->OpenGate();
return true;
}
void
AppleUSBEHCI::CheckForSharedXHCIController(void)
{
uint64_t seconds = 10;
const IORegistryPlane* acpiPlane;
IORegistryIterator* iter;
IORegistryEntry* entry;
UInt32 portnum = 0;
IOACPIPlatformDevice* acpiDevice;
IOService * xhciCandidate = NULL;
IORegistryEntry * xhciProvider = NULL;
const char * xhciProviderName = NULL;
OSDictionary * matchingDictionary = NULL;
OSIterator * xhciList = NULL;
UInt32 assertVal = 0; UInt32 xhciBitmap = 0; IONotifier * notifier = NULL;
bool done = false;
IOServiceMatchingNotificationHandler notificationHandler;
if ( !isInactive() )
{
_xhciController = NULL;
acpiDevice = CopyACPIDevice( _device );
if (acpiDevice == NULL)
{
USBLog(3, "AppleUSBEHCI[%p]::CheckForSharedXHCIController acpiDevice not found", this);
return;
}
IOReturn status = acpiDevice->evaluateInteger ( "XHCN", &assertVal );
acpiDevice->release();
acpiDevice = NULL;
if (status != kIOReturnSuccess)
{
USBLog(3, "AppleUSBEHCI[%p]::CheckForSharedXHCIController XHCN method not found", this);
return;
}
matchingDictionary = serviceMatching("AppleUSBXHCI");
if (!matchingDictionary)
{
USBLog(3, "AppleUSBEHCI[%p]::CheckForSharedXHCIController could not get matching dictionary (very unusual)", this);
return;
}
notificationHandler = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &AppleUSBEHCI::XHCIControllerMatchingNotifcationHandler);
_xhciControllerArray = OSArray::withCapacity(1);
if (!_xhciControllerArray)
{
USBError(1, "AppleUSBEHCI[%p]::CheckForSharedXHCIController failed to allocated array", this);
return;
}
notifier = addMatchingNotification( gIOMatchedNotification, matchingDictionary, notificationHandler, this);
if (!notifier)
{
USBError(1, "AppleUSBEHCI[%p]::CheckForSharedXHCIController could not set up matching notification", this);
return;
}
_workLoop->CloseGate();
do
{
int sleepResult = 0;
while (_xhciControllerArray->getCount() == 0)
{
sleepResult = _workLoop->SleepWithTimeout(_xhciController, kSecondScale * seconds);
if (sleepResult == THREAD_TIMED_OUT)
{
USBError(1, "AppleUSBEHCI[%p]::CheckForSharedXHCIController timed out waiting for muxed XHCI controller", this);
break;
}
}
xhciCandidate = (IOService *)_xhciControllerArray->getObject(0);
if (!xhciCandidate)
{
USBError(1, "AppleUSBEHCI[%p]::CheckForSharedXHCIController error getting XHCI controller", this);
break;
}
xhciCandidate->retain();
_xhciControllerArray->removeObject(0);
USBLog(3, "AppleUSBEHCI[%p]::CheckForSharedXHCIController found XHCI candidate %p", this, xhciCandidate);
if (!xhciCandidate->metaCast("AppleUSBXHCI"))
{
USBLog(3, "AppleUSBEHCI[%p]::CheckForSharedXHCIController %p is not AppleUSBXHCI\n", this, xhciCandidate);
continue;
}
xhciProvider = xhciCandidate->getParentEntry(gIOServicePlane);
xhciProviderName = xhciProvider->getName();
if (strncmp(xhciProviderName, "XHC", 3) == 0)
{
char myNum = xhciProviderName[3];
int val = myNum - '1';
if ((val >=0) && (val < 10))
{
xhciBitmap |= (1 << val);
}
}
if ((xhciBitmap & assertVal) == assertVal)
{
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
uint64_t ourObject = (uint64_t) xhciCandidate;
setProperty("xhci", ourObject, 64);
#endif
_xhciController = xhciCandidate; _xhciController->retain(); done = true;
}
xhciCandidate->release();
} while (!done);
_workLoop->OpenGate();
if (notifier)
{
notifier->remove();
notifier = NULL;
}
if (_xhciControllerArray)
{
_xhciControllerArray->flushCollection();
_xhciControllerArray->release();
_xhciControllerArray = NULL;
}
if (matchingDictionary)
{
matchingDictionary->release();
}
if ((xhciBitmap & assertVal) == 0)
{
USBError(1, "AppleUSBEHCI[%p]::CheckForSharedXHCIController - unable to find the correct XHCI xhciBitmap(0x%08x) assertVal(0x%08x)", this, (unsigned int)xhciBitmap, (unsigned int)assertVal);
}
}
}
IOReturn
AppleUSBEHCI::AcquireOSOwnership(void)
{
UInt32 hccparams = USBToHostLong(_pEHCICapRegisters->HCCParams & kEHCIEECPMask);
UInt32 eecp;
UInt32 data;
USBLog(2, "Attempting to get EHCI Controller from BIOS");
eecp = (hccparams & kEHCIEECPMask) >> kEHCIEECPPhase;
if (eecp < 0x40)
return kIOReturnSuccess;
data = _device->configRead32(eecp);
if ((data & 0xFF) == kEHCI_USBLEGSUP_ID)
{
USBLog(2, "Found USBLEGSUP_ID - value %p - writing OSOwned", (void*)data);
_device->configWrite32(eecp, data | kEHCI_USBLEGSUP_OSOwned);
for (int i = 0; i < 25; i++)
{
data = _device->configRead32(eecp);
if ((data & kEHCI_USBLEGSUP_BIOSOwned) == 0)
break;
IOSleep(10);
}
if ((_device->configRead32(eecp) & kEHCI_USBLEGSUP_BIOSOwned) != 0)
{
USBError(1, "EHCI controller unable to take control from BIOS");
return kIOReturnNoResources;
}
else
{
USBLog(2, "acquireOSOwnership done - value %p", (void*)_device->configRead32(eecp));
}
}
else
{
USBLog(2, "EHCI controller has wrong value in EECP register");
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::AsyncInitialize (void)
{
_AsyncHead = NULL;
_InactiveAsyncHead = NULL;
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::InterruptInitialize (void)
{
int i;
IOPhysicalAddress physPtr;
IOReturn status;
UInt64 offset = 0;
IODMACommand::Segment32 segments;
UInt32 numSegments = 1;
IODMACommand *dmaCommand = NULL;
_periodicListBuffer = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task, kIOMemoryUnshared | kIODirectionInOut, kEHCIPeriodicFrameListsize, kEHCIStructureAllocationPhysicalMask);
if (_periodicListBuffer == NULL)
{
USBError(1, "AppleUSBEHCI[%p]::InterruptInitialize - IOBufferMemoryDescriptor::inTaskWithPhysicalMask failed", this);
return kIOReturnNoMemory;
}
status = _periodicListBuffer->prepare();
if (status)
{
USBError(1, "AppleUSBEHCI[%p]::InterruptInitialize - could not prepare buffer err(%p)", this, (void*)status);
_periodicListBuffer->release();
_periodicListBuffer = NULL;
return status;
}
_periodicList = (USBPhysicalAddress32 *)_periodicListBuffer->getBytesNoCopy();
dmaCommand = IODMACommand::withSpecification(kIODMACommandOutputHost32, 32, PAGE_SIZE, (IODMACommand::MappingOptions)(IODMACommand::kMapped | IODMACommand::kIterateOnly));
if (!dmaCommand)
{
USBError(1, "AppleUSBEHCI[%p]::InterruptInitialize - could not get IODMACommand", this);
_periodicListBuffer->complete();
_periodicListBuffer->release();
_periodicListBuffer = NULL;
return kIOReturnNoMemory;
}
USBLog(6, "AppleUSBEHCI[%p]::InterruptInitialize - got IODMACommand %p", this, dmaCommand);
status = dmaCommand->setMemoryDescriptor(_periodicListBuffer);
if (status)
{
USBError(1, "AppleUSBEHCI[%p]::InterruptInitialize - setMemoryDescriptor returned err (%p)", this, (void*)status);
dmaCommand->release();
_periodicListBuffer->complete();
_periodicListBuffer->release();
_periodicListBuffer = NULL;
return status;
}
status = dmaCommand->gen32IOVMSegments(&offset, &segments, &numSegments);
if (status || (numSegments != 1) || (segments.fLength != PAGE_SIZE))
{
USBError(1, "AppleUSBEHCI[%p]::InterruptInitialize - could not generate segments err (%p) numSegments (%d) fLength (%d)", this, (void*)status, (int)numSegments, (int)segments.fLength);
status = status ? status : kIOReturnInternalError;
dmaCommand->clearMemoryDescriptor();
dmaCommand->release();
_periodicListBuffer->complete();
_periodicListBuffer->release();
_periodicListBuffer = NULL;
return status;
}
physPtr = segments.fIOVMAddr;
USBLog(7, "AppleUSBEHCI[%p]::InterruptInitialize - frame list pPhysical[%p] frames[%p]", this, (void*)physPtr, _periodicList);
_physPeriodicListBase = HostToUSBLong(physPtr);
IOSync();
dmaCommand->clearMemoryDescriptor();
dmaCommand->release();
_logicalPeriodicList = IONew(IOUSBControllerListElement *, kEHCIPeriodicListEntries);
if (_logicalPeriodicList == NULL)
{
_periodicListBuffer->complete();
_periodicListBuffer->release();
_periodicListBuffer = NULL;
return kIOReturnNoMemory;
}
for(i= 0; i<kEHCIPeriodicListEntries; i++)
{
AppleEHCIQueueHead *pQH = NULL;
if (i < kEHCIMaxPollingInterval)
{
pQH = MakeEmptyIntEndPoint(0, 0, 8, kUSBDeviceSpeedHigh, 0, 0, kUSBIn);
if (pQH == NULL)
{
USBError(1, "AppleUSBEHCI[%p]::InterruptInitialize - could not create empty endpoint", this);
return kIOReturnNoResources;
}
if (pQH->_qTD)
{
pQH->GetSharedLogical()->NextqTDPtr = HostToUSBLong(kEHCITermFlag);
DeallocateTD(pQH->_qTD);
pQH->_qTD = NULL;
pQH->_TailTD = NULL;
}
pQH->_maxPacketSize = 0;
pQH->_bInterval = 10; pQH->_pollingRate = kEHCIMaxPollingInterval * kEHCIuFramesPerFrame * 2; pQH->SetPhysicalLink(kEHCITermFlag);
_dummyIntQH[i] = pQH;
}
else
{
pQH = _dummyIntQH[i % kEHCIMaxPollingInterval];
}
SetPeriodicListEntry(i, pQH);
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::UIMFinalize(void)
{
int i;
IOReturn err = kIOReturnSuccess;
if ( _deviceBase )
{
USBLog (3, "AppleUSBEHCI[%p]: @ %x (%x)(shutting down HW)", this, (uint32_t)_deviceBase->getVirtualAddress(), (uint32_t)_deviceBase->getPhysicalAddress());
}
#if 0
if ( _workLoop )
_workLoop->disableAllInterrupts();
#endif
IOSleep(2);
if ( _powerDownNotifier ) {
_powerDownNotifier->remove();
_powerDownNotifier = NULL;
}
USBLog(1, "AppleUSBEHCI[%p]::UIMFinalize isInactive(%x) _pEHCIRegisters(%p) _device(%p)", this, isInactive(), _pEHCIRegisters, _device);
USBTrace( kUSBTEHCI, kTPEHCIUIMFinalize , (uintptr_t)this, isInactive(), (uintptr_t)_pEHCIRegisters, (uintptr_t)_device);
if ( !isInactive() && _pEHCIRegisters && _device )
{
_pEHCIRegisters->USBIntr = 0x0;
IOSync();
if (_is64bit)
_pEHCIRegisters->CTRLDSSegment = 0; _pEHCIRegisters->USBCMD = 0; IOSync();
for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit); i++)
IOSleep(1);
if (i >= 100)
{
USBError(1, "AppleUSBEHCI[%p]::UIMFinalize - could not get chip to halt within 100 ms", this);
err = kIOReturnInternalError;
goto ErrorExit;
}
_myBusState = kUSBBusStateReset;
_pEHCIRegisters->USBCMD = HostToUSBLong(kEHCICMDHCReset); IOSync();
for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBCMD) & kEHCICMDHCReset); i++)
IOSleep(1);
if (i >= 100)
{
USBError(1, "AppleUSBEHCI[%p]::UIMFinalize - could not get chip to come out of reset within 100 ms", this);
err = kIOReturnInternalError;
goto ErrorExit;
}
_pEHCIRegisters->ConfigFlag = 0;
IOSync();
if (_errataBits & kErrataNECIncompleteWrite)
{
UInt32 newValue = 0, count = 0;
newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag);
while ((count++ < 10) && (newValue != 0))
{
USBError(1, "EHCI driver: UIMFinalize - ConfigFlag bit not sticking. Retrying.");
_pEHCIRegisters->ConfigFlag = 0;
IOSync();
newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag);
}
}
_device->configWrite16(kIOPCIConfigCommand, kIOPCICommandMemorySpace);
_pEHCIRegisters->PeriodicListBase = 0; _pEHCIRegisters->AsyncListAddr = 0; IOSync();
}
if( _xhciController )
{
_xhciController->release();
_xhciController = NULL;
}
if (_tdMBHead)
{
AppleEHCItdMemoryBlock *curBlock = _tdMBHead;
AppleEHCItdMemoryBlock *nextBlock;
_tdMBHead = NULL;
while (curBlock)
{
nextBlock = curBlock->GetNextBlock();
curBlock->release();
curBlock = nextBlock;
}
}
if (_itdMBHead)
{
AppleEHCIitdMemoryBlock *curBlock = _itdMBHead;
AppleEHCIitdMemoryBlock *nextBlock;
_itdMBHead = NULL;
while (curBlock)
{
nextBlock = curBlock->GetNextBlock();
curBlock->release();
curBlock = nextBlock;
}
}
while (_pFreeQH)
{
AppleEHCIQueueHead* qh = _pFreeQH;
_pFreeQH = OSDynamicCast(AppleEHCIQueueHead, qh->_logicalNext);
USBLog(5, "AppleUSBEHCI[%p]::UIMFinalize - freeing QH[%p] - AsyncHead[%p] InactiveAsyncHead[%p]", this, qh, _AsyncHead, _InactiveAsyncHead);
qh->release();
}
for (i=0; i < kEHCIMaxPollingInterval; i++)
{
AppleEHCIQueueHead* qh = _dummyIntQH[i];
if (qh)
{
USBLog(5, "AppleUSBEHCI[%p]::UIMFinalize - freeing dummy QH[%p]", this, qh);
qh->release();
}
}
if (_edMBHead)
{
AppleEHCIedMemoryBlock *curBlock = _edMBHead;
AppleEHCIedMemoryBlock *nextBlock;
_edMBHead = NULL;
while (curBlock)
{
nextBlock = curBlock->GetNextBlock();
curBlock->release();
curBlock = nextBlock;
}
}
if ( _periodicListBuffer )
{
_periodicListBuffer->complete();
_periodicListBuffer->release();
_periodicListBuffer = NULL;
}
if ( _logicalPeriodicList )
{
IODelete( _logicalPeriodicList, IOUSBControllerListElement *, kEHCIPeriodicListEntries );
_logicalPeriodicList = NULL;
}
if( _diagnostics )
{
_diagnostics->release();
_diagnostics = NULL;
}
if ( _filterInterruptSource && _workLoop )
{
_workLoop->removeEventSource(_filterInterruptSource);
_filterInterruptSource->release();
_filterInterruptSource = NULL;
}
ErrorExit:
_uimInitialized = false;
return err;
}
UInt32
AppleUSBEHCI::GetBandwidthAvailable()
{
int bandwidthAvailable = kEHCIHSMaxPeriodicBytesPeruFrame;
int pollingInterval, microframe;
for ( pollingInterval = 0 ; pollingInterval < kEHCIMaxPollingInterval; pollingInterval++ )
for ( microframe = 0; microframe < kEHCIuFramesPerFrame ; microframe++ )
bandwidthAvailable = MIN((kEHCIHSMaxPeriodicBytesPeruFrame-_periodicBandwidthUsed[pollingInterval][microframe]), bandwidthAvailable);
USBLog(7, "AppleUSBEHCI[%p]::GetBandwidthAvailable -- returning %d", this, bandwidthAvailable);
return bandwidthAvailable;
}
UInt32
AppleUSBEHCI::GetFrameNumber32()
{
UInt32 temp1, temp2;
register UInt32 frindex;
UInt32 sts = USBToHostLong(_pEHCIRegisters->USBSTS);
if (sts == kEHCIInvalidRegisterValue)
{
USBLog(2, "AppleUSBEHCI[%p]::GetFrameNumber32: can't access register", this);
return 0;
}
if ( sts & kEHCIHCHaltedBit)
{
USBLog(1, "AppleUSBEHCI[%p]::GetFrameNumber32 called but controller is halted", this);
USBTrace( kUSBTEHCI, kTPEHCIGetFrameNumber32 , (uintptr_t)this, USBToHostLong(_pEHCIRegisters->USBSTS), kEHCIHCHaltedBit, 0);
return 0;
}
do
{
temp1 = (UInt32)_frameNumber;
frindex = USBToHostLong(_pEHCIRegisters->FRIndex);
IOSync();
temp2 = (UInt32)_frameNumber;
} while ((temp1 != temp2) || (frindex == 0) );
frindex = frindex >> 3;
USBLog(7, "AppleUSBEHCI[%p]::GetFrameNumber32 -- returning %d (%p)", this, (int)(temp1+frindex), (void*)(temp1+frindex));
return (UInt32)(temp1 + frindex);
}
UInt64
AppleUSBEHCI::GetFrameNumber()
{
UInt64 temp1, temp2;
register UInt32 frindex;
UInt32 sts = USBToHostLong(_pEHCIRegisters->USBSTS);
if (sts == kEHCIInvalidRegisterValue)
{
return 0;
}
if ( sts & kEHCIHCHaltedBit)
{
USBTrace( kUSBTEHCI, kTPEHCIGetFrameNumber , (uintptr_t)this, USBToHostLong(_pEHCIRegisters->USBSTS), kEHCIHCHaltedBit, 0);
return 0;
}
do
{
temp1 = _frameNumber;
frindex = HostToUSBLong(_pEHCIRegisters->FRIndex);
temp2 = _frameNumber;
} while ( (temp1 != temp2) || (frindex == 0) );
frindex = frindex >> 3;
return (temp1 + frindex);
}
UInt64
AppleUSBEHCI::GetMicroFrameNumber()
{
UInt64 temp1, temp2;
register UInt32 frindex;
do
{
temp1 = _frameNumber;
frindex = HostToUSBLong(_pEHCIRegisters->FRIndex);
temp2 = _frameNumber;
} while ( (temp1 != temp2) || (frindex == 0) );
temp1 = temp1 << 3;
USBLog(7, "AppleUSBEHCI[%p]::GetMicroFrameNumber -- returning %qd (0x%qx)", 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, "AppleUSBEHCI[%p]::AllocateED - unable to allocate a new memory block!", this);
USBTrace( kUSBTEHCI, kTPEHCIAllocateQH , (uintptr_t)this, (uintptr_t)memBlock, 0, 1);
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, "AppleUSBEHCI[%p]::AllocateED - hmm. ran out of EDs in a memory block", this);
USBTrace( kUSBTEHCI, kTPEHCIAllocateQH , (uintptr_t)this, 0, 0, 2 );
freeQH = _pFreeQH;
break;
}
freeQH->_logicalNext = _pFreeQH;
_pFreeQH = freeQH;
}
}
if (freeQH)
{
_pFreeQH = OSDynamicCast(AppleEHCIQueueHead, freeQH->_logicalNext);
if (!_pFreeQH)
_pLastFreeQH = NULL;
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, "AppleUSBEHCI[%p]::DeallocateED - AsyncListAddr(%08x) deallocating %08x and smashing physical link", this, (int)_pEHCIRegisters->AsyncListAddr, (int)pED->_sharedPhysical);
pED->_logicalNext = NULL;
pED->SetPhysicalLink(0xFEDCBA98);
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, "AppleUSBEHCI[%p]::AllocateTD - unable to allocate a new memory block!", 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, "AppleUSBEHCI[%p]::AllocateTD - hmm. ran out of TDs in a memory block", this);
freeTD = _pFreeTD;
break;
}
freeTD->pLogicalNext = _pFreeTD;
_pFreeTD = freeTD;
}
}
if (freeTD)
{
_pFreeTD = freeTD->pLogicalNext;
if (!_pFreeTD)
_pLastFreeTD = NULL;
freeTD->pLogicalNext = NULL;
freeTD->lastFrame = 0;
freeTD->lastRemaining = 0;
freeTD->command = NULL;
freeTD->callbackOnTD = false;
freeTD->multiXferTransaction = false;
freeTD->finalXferInTransaction = false;
freeTD->tdSize = 0;
}
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, "AppleUSBEHCI[%p]::AllocateITD - unable to allocate a new memory block!", 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, "AppleUSBEHCI[%p]::AllocateTD - hmm. ran out of TDs in a memory block", this);
freeITD = _pFreeITD;
break;
}
freeITD->_logicalNext = _pFreeITD;
_pFreeITD = freeITD;
}
}
if (freeITD)
{
_pFreeITD = OSDynamicCast(AppleEHCIIsochTransferDescriptor, freeITD->_logicalNext);
freeITD->_logicalNext = NULL;
if (!_pFreeITD)
_pLastFreeITD = NULL;
}
bzero(&freeITD->GetSharedLogical()->Transaction0, sizeof(EHCIIsochTransferDescriptorShared)-sizeof(USBPhysicalAddress32) );
USBLog(7, "AppleUSBEHCI[%p]::AllocateITD - returning %p", this, freeITD);
return freeITD;
}
IOReturn
AppleUSBEHCI::DeallocateITD (AppleEHCIIsochTransferDescriptor *pTD)
{
USBLog(7, "AppleUSBEHCI[%p]::DeallocateITD - deallocating %p", 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, "AppleUSBEHCI[%p]::AllocateTD - unable to allocate a new memory block!", this);
return NULL;
}
memBlock->SetNextBlock(_sitdMBHead);
_sitdMBHead = memBlock;
numTDs = memBlock->NumTDs();
USBLog(3, "AppleUSBEHCI[%p]::AllocateSITD - got new memory block (%p) with %d SITDs in it", this, memBlock, (int)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, "AppleUSBEHCI[%p]::AllocateTD - hmm. ran out of TDs in a memory block", this);
freeSITD = _pFreeSITD;
break;
}
freeSITD->_logicalNext = _pFreeSITD;
_pFreeSITD = freeSITD;
}
}
if (freeSITD)
{
_pFreeSITD = OSDynamicCast(AppleEHCISplitIsochTransferDescriptor, freeSITD->_logicalNext);
if (!_pFreeSITD)
_pLastFreeSITD = NULL;
freeSITD->_logicalNext = NULL;
freeSITD->_isDummySITD = false;
}
USBLog(7, "AppleUSBEHCI[%p]::AllocateSITD - returning %p", this, freeSITD);
return freeSITD;
}
IOReturn
AppleUSBEHCI::DeallocateSITD (AppleEHCISplitIsochTransferDescriptor *pTD)
{
USBLog(7, "AppleUSBEHCI[%p]::DeallocateSITD - deallocating %p", this, pTD);
pTD->_logicalNext = NULL;
if (pTD->_frameNumber == GetFrameNumber())
{
USBLog(7, "AppleUSBEHCI::DeallocateSITD - pTD(%p) is for the current frame (%qd) - delaying", pTD, pTD->_frameNumber);
if (_pLastDelayedSITD)
{
_pLastDelayedSITD->_logicalNext = pTD;
_pLastDelayedSITD = pTD;
}
else
{
_pLastDelayedSITD = pTD;
_pDelayedSITD = pTD;
}
}
else
{
if (_pLastFreeSITD)
{
_pLastFreeSITD->_logicalNext = pTD;
_pLastFreeSITD = pTD;
}
else
{
_pLastFreeSITD = pTD;
_pFreeSITD = pTD;
}
}
pTD = _pDelayedSITD;
if (pTD)
{
USBLog(7, "AppleUSBEHCI::DeallocateSITD - looking at _pDelayedSITD(%p)", pTD);
}
while (pTD && (pTD->_frameNumber < GetFrameNumber()))
{
AppleEHCISplitIsochTransferDescriptor *nextSITD = (AppleEHCISplitIsochTransferDescriptor *)pTD->_logicalNext;
USBLog(7, "AppleUSBEHCI::DeallocateSITD - pTD(%p) was delayed (frame %qd) and I am now freeing it", pTD, pTD->_frameNumber);
pTD->_logicalNext = NULL;
if (_pLastFreeSITD)
{
_pLastFreeSITD->_logicalNext = pTD;
_pLastFreeSITD = pTD;
}
else
{
_pLastFreeSITD = pTD;
_pFreeSITD = pTD;
}
pTD = nextSITD;
_pDelayedSITD = pTD;
if (!_pDelayedSITD)
_pLastDelayedSITD = NULL;
}
return kIOReturnSuccess;
}
void
AppleUSBEHCI::doCallback(EHCIGeneralTransferDescriptorPtr nextTD,
UInt32 transferStatus,
UInt32 bufferSizeRemaining)
{
#pragma unused (nextTD, transferStatus, bufferSizeRemaining)
USBError(1, "AppleUSBEHCI[%p]::doCallback unimemented *************", this);
}
IOReturn
AppleUSBEHCI::EnableAsyncSchedule(bool waitForON)
{
int i;
IOReturn stat = kIOReturnSuccess;
if (!_pEHCIRegisters->AsyncListAddr)
{
USBLog(1, "AppleUSBEHCI[%p]::EnableAsyncSchedule.. AsyncListAddr is NULL!! We shouldn't be doing this. USBCMD(0x%08x) USBSTS(0x%08x) PCIStatus(0x%04x)", this, USBToHostLong(_pEHCIRegisters->USBCMD), USBToHostLong(_pEHCIRegisters->USBSTS), _device->configRead16(kIOPCIConfigStatus));
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
panic("AppleUSBEHCI::EnableAsyncSchedule.. AsyncListAddr is NULL!! USBCMD(0x%08x) USBSTS(0x%08x) PCIStatus(0x%04x)\n", USBToHostLong(_pEHCIRegisters->USBCMD), USBToHostLong(_pEHCIRegisters->USBSTS), _device->configRead16(kIOPCIConfigStatus));
#endif
return kIOReturnInternalError;
}
if (!(_pEHCIRegisters->USBCMD & HostToUSBLong(kEHCICMDAsyncEnable)))
{
USBLog(7, "AppleUSBEHCI[%p]::EnableAsyncSchedule: enabling schedule", this);
if (_errataBits & kErrataAgereEHCIAsyncSched)
{
_pEHCIRegisters->USBCMD &= HostToUSBLong(~kEHCICMDRunStop);
while (!(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit))
;
_pEHCIRegisters->USBCMD |= HostToUSBLong(kEHCICMDAsyncEnable | kEHCICMDRunStop);
}
else
{
_pEHCIRegisters->USBCMD |= HostToUSBLong(kEHCICMDAsyncEnable);
}
if (waitForON) {
IOSync();
for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSAsyncScheduleStatus); i++)
IOSleep(1);
if (i)
{
if (i >= 100)
{
USBError(1, "AppleUSBEHCI[%p]::EnableAsyncSchedule: ERROR: USBCMD and USBSTS won't synchronize ON - cannot enable USB list processing", this);
stat = kIOReturnInternalError;
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::EnableAsyncSchedule: had to wait %d ms for CMD and STS to synch up ON", this, i);
}
}
}
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::EnableAsyncSchedule: schedule was already enabled", this);
}
if (stat)
{
USBLog(1, "AppleUSBEHCI[%p]::EnableAsyncSchedule: returning status %x", this, stat);
USBTrace( kUSBTEHCI, kTPEHCIEnableAsyncSchedule , (uintptr_t)this, stat, 0, 0);
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::EnableAsyncSchedule: schedule enabled cleanly", this);
}
return stat;
}
IOReturn
AppleUSBEHCI::DisableAsyncSchedule(bool waitForOFF)
{
int i;
IOReturn stat = kIOReturnSuccess;
if (isInactive() || !_controllerAvailable)
{
USBLog(2, "AppleUSBEHCI[%p]::DisableAsyncSchedule: I am inActive - nothing to do", this);
return kIOReturnSuccess;
}
if (_pEHCIRegisters->USBCMD & HostToUSBLong(kEHCICMDAsyncEnable))
{
USBLog(7, "AppleUSBEHCI[%p]::DisableAsyncSchedule: disabling schedule", this);
_pEHCIRegisters->USBCMD &= HostToUSBLong(~kEHCICMDAsyncEnable);
if (waitForOFF) {
IOSync();
for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSAsyncScheduleStatus); i++)
IOSleep(1);
if (i)
{
if (i >= 100)
{
USBLog(1, "AppleUSBEHCI[%p]::DisableAsyncSchedule: ERROR: USBCMD and USBSTS won't synchronize OFF", this);
USBTrace( kUSBTEHCI, kTPEHCIDisableAsyncSchedule , (uintptr_t)this, USBToHostLong(_pEHCIRegisters->USBCMD), USBToHostLong(_pEHCIRegisters->USBSTS), kIOReturnInternalError);
stat = kIOReturnInternalError;
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::DisableAsyncSchedule: had to wait %d ms for CMD and STS to synch up OFF", this, i);
}
}
}
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::DisableAsyncSchedule: schedule was already disabled", this);
}
if (stat)
{
USBLog(1, "AppleUSBEHCI[%p]::DisableAsyncSchedule: returning status %x", this, stat);
USBTrace( kUSBTEHCI, kTPEHCIDisableAsyncSchedule, (uintptr_t)this, stat, 0, 0);
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::DisableAsyncSchedule: schedule disabled cleanly", this);
}
return stat;
}
IOReturn
AppleUSBEHCI::EnablePeriodicSchedule(bool waitForON)
{
int i;
IOReturn stat = kIOReturnSuccess;
if (_inAbortIsochEP)
{
USBLog(2, "EnablePeriodicSchedule - not doing in AbortIsochEP");
return stat;
}
if (!(_pEHCIRegisters->USBCMD & HostToUSBLong(kEHCICMDPeriodicEnable)))
{
USBLog(7, "AppleUSBEHCI[%p]::EnablePeriodicSchedule: enabling schedule", this);
_pEHCIRegisters->USBCMD |= HostToUSBLong(kEHCICMDPeriodicEnable);
if (waitForON) {
IOSync();
for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSPeriodicScheduleStatus); i++)
IOSleep(1);
if (i)
{
if (i >= 100)
{
USBLog(1, "AppleUSBEHCI[%p]::EnablePeriodicSchedule: ERROR: USBCMD and USBSTS won't synchronize ON", this);
USBTrace( kUSBTEHCI, kTPEHCIEnablePeriodicSchedule , (uintptr_t)this, USBToHostLong(_pEHCIRegisters->USBCMD), USBToHostLong(_pEHCIRegisters->USBSTS), kIOReturnInternalError);
stat = kIOReturnInternalError;
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::EnablePeriodicSchedule: had to wait %d ms for CMD and STS to synch up ON", this, i);
}
}
}
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::EnablePeriodicSchedule: schedule was already enabled", this);
}
if (stat)
{
USBLog(1, "AppleUSBEHCI[%p]::EnablePeriodicSchedule: returning status %x", this, stat);
USBTrace( kUSBTEHCI, kTPEHCIEnablePeriodicSchedule , (uintptr_t)this, stat, 0, 0);
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::EnablePeriodicSchedule: schedule enabled cleanly", this);
}
return stat;
}
IOReturn
AppleUSBEHCI::DisablePeriodicSchedule(bool waitForOFF)
{
int i;
IOReturn stat = kIOReturnSuccess;
if (_pEHCIRegisters->USBCMD & HostToUSBLong(kEHCICMDPeriodicEnable))
{
USBLog(7, "AppleUSBEHCI[%p]::DisablePeriodicSchedule: disabling schedule", this);
_pEHCIRegisters->USBCMD &= HostToUSBLong(~kEHCICMDPeriodicEnable);
if (waitForOFF) {
IOSync();
for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSPeriodicScheduleStatus); i++)
IOSleep(1);
if (i)
{
if (i >= 100)
{
USBLog(1, "AppleUSBEHCI[%p]::DisablePeriodicSchedule: ERROR: USBCMD and USBSTS won't synchronize OFF", this);
USBTrace( kUSBTEHCI, kTPEHCIDisablePeriodicSchedule , (uintptr_t)this, USBToHostLong(_pEHCIRegisters->USBCMD), USBToHostLong(_pEHCIRegisters->USBSTS), kIOReturnInternalError );
stat = kIOReturnInternalError;
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::DisablePeriodicSchedule: had to wait %d ms for CMD and STS to synch up OFF", this, i);
}
}
}
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::DisablePeriodicSchedule: schedule was already disabled", this);
}
if (stat)
{
USBLog(1, "AppleUSBEHCI[%p]::DisablePeriodicSchedule: returning status %x", this, stat);
USBTrace( kUSBTEHCI, kTPEHCIDisablePeriodicSchedule , (uintptr_t)this, stat, 0, 0);
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::DisablePeriodicSchedule: schedule disabled cleanly", this);
}
return stat;
}
IOUSBControllerListElement *
AppleUSBEHCI::GetPeriodicListLogicalEntry(int offset)
{
return _logicalPeriodicList[offset];
}
USBPhysicalAddress32
AppleUSBEHCI::GetPeriodicListPhysicalEntry(int offset)
{
return USBToHostLong(_periodicList[offset]);
}
void
AppleUSBEHCI::SetPeriodicListEntry(int offset, IOUSBControllerListElement *pListElem)
{
_logicalPeriodicList[offset] = pListElem;
if (pListElem)
{
_periodicList[offset] = HostToUSBLong(pListElem->GetPhysicalAddrWithType());
}
else
{
_periodicList[offset] = HostToUSBLong(kEHCITermFlag);
}
IOSync();
}
IOReturn
AppleUSBEHCI::message( UInt32 type, IOService * provider, void * argument )
{
IOService * nub = NULL;
const IORegistryPlane * usbPlane = NULL;
IOUSBRootHubDevice * parentHub = NULL;
IOReturn returnValue = kIOReturnSuccess;
USBLog(6, "AppleUSBEHCI[%p]::message type: %p, isInactive = %d", this, (void*)type, isInactive());
returnValue = super::message( type, provider, argument );
switch (type)
{
case kIOUSBMessageHubPortDeviceDisconnected:
EHCIMuxedPortDeviceDisconnected((char*)argument);
break;
case kIOUSBMessageExpressCardCantWake:
nub = (IOService*)argument;
usbPlane = getPlane(kIOUSBPlane);
parentHub = OSDynamicCast(IOUSBRootHubDevice, nub->getParentEntry(usbPlane));
nub->retain();
USBLog(1, "AppleUSBEHCI[%p]::message - got kIOUSBMessageExpressCardCantWake from driver %s[%p] argument is %s[%p]", this, provider->getName(), provider, nub->getName(), nub);
USBTrace( kUSBTEHCI, kTPEHCIMessage , (uintptr_t)this, (uintptr_t)provider, (uintptr_t)nub, kIOUSBMessageExpressCardCantWake );
if ( parentHub == _rootHubDevice || (nub == _rootHubDevice && parentHub == NULL) )
{
USBLog(1, "AppleUSBEHCI[%p]::message - device is attached to my root hub!!", this);
USBTrace( kUSBTEHCI, kTPEHCIMessage , (uintptr_t)this, 0, 0, 0);
_badExpressCardAttached = true;
}
nub->release();
returnValue = kIOReturnSuccess; break;
}
return returnValue;
}
IOUSBControllerIsochEndpoint*
AppleUSBEHCI::AllocateIsochEP()
{
AppleEHCIIsochEndpoint *pEP;
pEP = new AppleEHCIIsochEndpoint;
if (pEP)
{
if (!pEP->init())
{
pEP->release();
pEP = NULL;
}
}
return pEP;
}
void
AppleUSBEHCI::ReturnIsochDoneQueue(IOUSBControllerIsochEndpoint* isochEP)
{
super::ReturnIsochDoneQueue(isochEP);
if (_activeIsochTransfers == 0)
{
_outSlot = kEHCIPeriodicListEntries + 1;
}
}
IODMACommand*
AppleUSBEHCI::GetNewDMACommand()
{
USBLog(7, "AppleUSBEHCI[%p]::GetNewDMACommand - creating %d bit IODMACommand", this, _is64bit ? 64 : 32);
return IODMACommand::withSpecification(kIODMACommandOutputHost64, _is64bit ? 64 : 32, 0);
}
IOReturn
AppleUSBEHCI::GetLowLatencyOptionsAndPhysicalMask(IOOptionBits *pOptionBits, mach_vm_address_t *pPhysicalMask)
{
super::GetLowLatencyOptionsAndPhysicalMask(pOptionBits, pPhysicalMask); if (_is64bit)
*pPhysicalMask = 0xFFFFFFFFFFFFF000ULL; return kIOReturnSuccess;
}