AppleUSBEHCI_PwrMgmt.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOService.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOHibernatePrivate.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/usb/IOUSBRootHubDevice.h>
#include <IOKit/usb/IOUSBHubPolicyMaker.h>
#include <IOKit/usb/IOUSBLog.h>
#include <libkern/libkern.h>
#include "AppleUSBEHCI.h"
#include "USBTracepoints.h"
static class AppleUSBEHCI_IOLockClass gEHCI_GlobalLock;
#define super IOUSBControllerV3
#define _controllerCanSleep _expansionData->_controllerCanSleep
enum {
kGossamerTypeGossamer = 1,
kGossamerTypeSilk,
kGossamerTypeWallstreet,
kGossamerTypeiMac,
kGossamerTypeYosemite,
kGossamerType101
};
#if EHCI_USE_KPRINTF
#define EHCIPWRMGMT_USE_KPRINTF EHCI_USE_KPRINTF
#else
#define EHCIPWRMGMT_USE_KPRINTF 0
#endif
#if EHCIPWRMGMT_USE_KPRINTF
#undef USBLog
#undef USBError
void kprintf(const char *format, ...) __attribute__((format(printf, 1, 2)));
#define USBLog( LEVEL, FORMAT, ARGS... ) if ((LEVEL) <= EHCIPWRMGMT_USE_KPRINTF) { kprintf( FORMAT "\n", ## ARGS ) ; }
#define USBError( LEVEL, FORMAT, ARGS... ) { kprintf( FORMAT "\n", ## ARGS ) ; }
#endif
extern UInt32 getPortSCForWriting(EHCIRegistersPtr _pEHCIRegisters, short port);
AppleUSBEHCI_IOLockClass::AppleUSBEHCI_IOLockClass()
{
lock = IOLockAlloc();
}
AppleUSBEHCI_IOLockClass::~AppleUSBEHCI_IOLockClass()
{
IOLockFree(lock);
}
void
AppleUSBEHCI::CheckSleepCapability(void)
{
USBLog(2, "AppleUSBEHCI[%p]::CheckSleepCapability - assuming that I can sleep", this);
_controllerCanSleep = true;
_hasPCIPwrMgmt = false;
if ( !_device->getProperty("AAPL,clock-id") && !((getPlatform()->getChipSetType() == kChipSetTypeGossamer) && getPlatform()->getMachineType() == kGossamerTypeYosemite) )
{
if (_device->getProperty("built-in"))
{
if (_device->hasPCIPowerManagement(kPCIPMCPMESupportFromD3Cold) && (_device->enablePCIPowerManagement(kPCIPMCSPowerStateD3) == kIOReturnSuccess))
{
_hasPCIPwrMgmt = true;
setProperty("Card Type","Built-in");
}
}
else
{
if (_device->hasPCIPowerManagement() && (_device->enablePCIPowerManagement() == kIOReturnSuccess))
{
_hasPCIPwrMgmt = true;
setProperty("Card Type","Built-in");
}
}
if (!_hasPCIPwrMgmt)
{
USBError(1, "AppleUSBEHCI[%p]::CheckSleepCapability - controller will be unloaded across sleep",this);
_controllerCanSleep = false;
setProperty("Card Type","PCI");
}
}
else
{
setProperty("Card Type","Built-in");
}
_ExpressCardPort = ExpressCardPort(_device);
_badExpressCardAttached = false;
}
void
AppleUSBEHCI::ResumeUSBBus()
{
int i;
bool enabledports = false;
USBTrace( kUSBTEHCI, kTPEHCIResumeUSBBus, (uintptr_t)this, 0, 0, 0);
if (USBToHostLong(_pEHCIRegisters->ConfigFlag) != kEHCIPortRoutingBit)
{
USBLog(5, "AppleUSBEHCI[%p]::ResumeUSBBus - restoring ConfigFlag[from 0x%x]", this, (unsigned int) USBToHostLong(_pEHCIRegisters->ConfigFlag));
_pEHCIRegisters->ConfigFlag = HostToUSBLong(kEHCIPortRoutingBit);
IOSync();
if (_errataBits & kErrataNECIncompleteWrite)
{
UInt32 newValue = 0, count = 0;
newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag);
while ((count++ < 10) && (newValue != kEHCIPortRoutingBit))
{
USBError(1, "EHCI driver: ResumeUSBBus - ConfigFlag bit not sticking. Retrying.");
_pEHCIRegisters->ConfigFlag = HostToUSBLong(kEHCIPortRoutingBit);
IOSync();
newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag);
}
}
}
_pEHCIRegisters->PeriodicListBase = _physPeriodicListBase;
IOSync();
if (_savedAsyncListAddr && (_pEHCIRegisters->AsyncListAddr != _savedAsyncListAddr))
{
USBLog(4, "AppleUSBEHCI[%p]::ResumeUSBBus - restoring AsyncListAddr[from 0x%x to 0x%x]", this, (unsigned int)USBToHostLong(_pEHCIRegisters->AsyncListAddr), (unsigned int)USBToHostLong(_savedAsyncListAddr));
_pEHCIRegisters->AsyncListAddr = _savedAsyncListAddr;
IOSync();
}
if (_is64bit)
_pEHCIRegisters->CTRLDSSegment = 0;
if (USBToHostLong(_savedUSBCMD) & kEHCICMDRunStop)
{
UInt32 USBCmd = USBToHostLong(_pEHCIRegisters->USBCMD);
USBCmd &= ~kEHCICMDIntThresholdMask;
USBCmd |= 1 << kEHCICMDIntThresholdOffset; USBCmd |= kEHCICMDRunStop;
USBLog(5, "AppleUSBEHCI[%p]::ResumeUSBBus - initial restart - USBCMD is <%p> will be <%p>", this, (void*)USBToHostLong(_pEHCIRegisters->USBCMD), (void*)USBCmd);
_pEHCIRegisters->USBCMD = HostToUSBLong(USBCmd);
IOSync();
for (i=0; (i< 100) && (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit); i++)
IODelay(100);
if (i>1)
{
USBLog(2, "AppleUSBEHCI[%p]::ResumeUSBBus - controller took (%d) turns to get going", this, i);
}
}
USBLog(7, "AppleUSBEHCI[%p]::ResumeUSBBus - resuming %d ports", this, _rootHubNumPorts);
for (i=0; i < _rootHubNumPorts; i++)
{
UInt32 portStat;
portStat = getPortSCForWriting(_pEHCIRegisters, i+1);
if (portStat & kEHCIPortSC_Owner)
{
USBLog(4, "AppleUSBEHCI[%p]::ResumeUSBBus - port %d owned by OHCI", this, i+1);
}
else if (portStat & kEHCIPortSC_Enabled)
{
if (_badExpressCardAttached && ((int)_ExpressCardPort == (i+1)))
{
portStat |= (kEHCIPortSC_WKCNNT_E|kEHCIPortSC_WKDSCNNT_E);
_pEHCIRegisters->PortSC[i] = USBToHostLong(portStat);
IOSync();
}
enabledports = true;
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::ResumeUSBBus - port %d not enabled", this, i);
}
}
if (_savedUSBCMD)
{
USBLog(5, "AppleUSBEHCI[%p]::ResumeUSBBus - USBCMD is <%p> will be <%p>", this, (void*)_pEHCIRegisters->USBCMD, (void*)_savedUSBCMD);
_pEHCIRegisters->USBCMD = _savedUSBCMD;
}
}
void
AppleUSBEHCI::SuspendUSBBus()
{
UInt8 numPorts;
int i;
UInt32 usbcmd, usbsts;
USBTrace_Start( kUSBTEHCI, kTPEHCISuspendUSBBus, (uintptr_t)this, 0, 0, 0);
_savedSuspendedPortBitmap = 0;
_savedUSBCMD = _pEHCIRegisters->USBCMD;
USBLog(7, "AppleUSBEHCI[%p]::SuspendUSBBus - got _savedUSBCMD <%p>", this, (void*)_savedUSBCMD);
usbcmd = USBToHostLong(_savedUSBCMD);
if (usbcmd & kEHCICMDAsyncEnable)
{
for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSAsyncScheduleStatus); i++)
IODelay(100);
if (i)
{
USBError(1, "AppleUSBEHCI[%p]::SuspendUSBBus - Async Schedule should have been on but was off for %d loops", this, i);
}
usbcmd &= ~kEHCICMDAsyncEnable;
}
if (usbcmd & kEHCICMDPeriodicEnable)
{
for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSPeriodicScheduleStatus); i++)
IODelay(100);
if (i)
{
USBError(1, "AppleUSBEHCI[%p]::SuspendUSBBus - Periodic Schedule should have been on but was off for %d loops", this, i);
}
usbcmd &= ~kEHCICMDPeriodicEnable;
}
_pEHCIRegisters->USBCMD = HostToUSBLong(usbcmd); IOSync();
for (i=0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSAsyncScheduleStatus); i++)
IODelay(1000);
if (i > 2)
{
USBError(1, "AppleUSBEHCI[%p]::SuspendUSBBus - Async Schedule took %d loops to turn off", this, i);
}
for (i=0; (i < 1000) && (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCISTSPeriodicScheduleStatus); i++)
IODelay(1000);
if (i > 2)
{
USBError(1, "AppleUSBEHCI[%p]::SuspendUSBBus - Periodic Schedule took %d loops to turn off CMD(%p) STS(%p)", this, i, (void*)USBToHostLong(_pEHCIRegisters->USBCMD), (void*)USBToHostLong(_pEHCIRegisters->USBSTS));
}
_savedAsyncListAddr = _pEHCIRegisters->AsyncListAddr;
GetNumberOfPorts( &numPorts );
USBLog(numPorts ? 4 : 1, "AppleUSBEHCI[%p]::SuspendUSBBus - bus 0x%x, suspending %d ports", this, (uint32_t)_busNumber, numPorts);
for (i=0; i < numPorts; i++)
{
UInt32 portStat;
portStat = getPortSCForWriting(_pEHCIRegisters, i+1);
if (portStat & kEHCIPortSC_Owner)
{
USBLog(4, "AppleUSBEHCI[%p]::SuspendUSBBus - port %d owned by OHCI", this, i+1);
}
else
{
if (_badExpressCardAttached && ((int)_ExpressCardPort == (i+1)))
{
USBLog(4, "AppleUSBEHCI[%p]::SuspendUSBBus - port %d had an ExpresCard in it", this, i+1);
portStat &= ~(kEHCIPortSC_WKCNNT_E|kEHCIPortSC_WKDSCNNT_E);
_pEHCIRegisters->PortSC[i] = USBToHostLong(portStat);
IOSync();
}
if (portStat & kEHCIPortSC_Enabled)
{
if (portStat & kEHCIPortSC_Suspend)
{
_savedSuspendedPortBitmap |= (1<<i);
USBLog(4, "AppleUSBEHCI[%p]::SuspendUSBBus - port %d was already suspended (as it should have been)", this, i+1);
}
else
{
USBError(1, "AppleUSBEHCI[%p]::SuspendUSBBus - port %d was NOT already suspended (as it should have been) PROBLEMS AHEAD", this, i+1);
}
}
else
{
USBLog(4, "AppleUSBEHCI[%p]::SuspendUSBBus - port %d not enabled", this, i+1);
}
}
}
usbcmd &= ~kEHCICMDRunStop;
_pEHCIRegisters->USBCMD = HostToUSBLong(usbcmd);
IOSync();
_myBusState = kUSBBusStateReset;
USBLog(5, "AppleUSBEHCI[%p]::SuspendUSBBus - ports suspended, HC stop set, waiting for halted - USBCMD(%p) USBSTS(%p)", this, (void*)USBToHostLong(_pEHCIRegisters->USBCMD), (void*)USBToHostLong(_pEHCIRegisters->USBSTS));
i=0;
do
{
if ((++i % 10000) == 0)
{
USBLog(1, "AppleUSBEHCI[%p]::SuspendUSBBus - HC not halting! USBCMD(%p) USBSTS(%p) i(%d)", this, (void*)USBToHostLong(_pEHCIRegisters->USBCMD), (void*)USBToHostLong(_pEHCIRegisters->USBSTS), (int)i);
USBTrace( kUSBTEHCI, kTPEHCISuspendUSBBus, (uintptr_t)this, USBToHostLong(_pEHCIRegisters->USBCMD), USBToHostLong(_pEHCIRegisters->USBSTS), (int)i);
}
usbsts = USBToHostLong(_pEHCIRegisters->USBSTS);
} while (!(usbsts & kEHCIHCHaltedBit));
USBLog(5, "AppleUSBEHCI[%p]::SuspendUSBBus - HC halted", this);
}
void
AppleUSBEHCI::StopUSBBus()
{
UInt32 usbcmd;
USBTrace( kUSBTEHCI, kTPEHCIStopUSBBus, (uintptr_t)this, 0, 0, 0);
usbcmd = USBToHostLong(_pEHCIRegisters->USBCMD);
usbcmd &= ~kEHCICMDRunStop;
_pEHCIRegisters->USBCMD = HostToUSBLong(usbcmd);
_myBusState = kUSBBusStateReset;
USBLog(5, "AppleUSBEHCI[%p]::StopUSBBus - HC halted", this);
}
void
AppleUSBEHCI::RestartUSBBus()
{
UInt32 usbcmd, usbsts;
USBTrace( kUSBTEHCI, kTPEHCIRestartUSBBus, (uintptr_t)this, 0, 0, 0);
do
{
usbsts = USBToHostLong(_pEHCIRegisters->USBSTS);
} while (!(usbsts & kEHCIHCHaltedBit));
usbcmd = USBToHostLong(_pEHCIRegisters->USBCMD);
usbcmd |= kEHCICMDRunStop;
_pEHCIRegisters->USBCMD = HostToUSBLong(usbcmd);
_myBusState = kUSBBusStateRunning;
USBLog(5, "AppleUSBEHCI[%p]::RestartUSBBus - HC restarted", this);
}
IOReturn
AppleUSBEHCI::SaveControllerStateForSleep(void)
{
showRegisters(7, "+SaveControllerStateForSleep");
USBLog(5, "AppleUSBEHCI[%p]::SaveControllerStateForSleep - suspending the bus", this);
if (_myBusState < kUSBBusStateRunning)
{
USBLog(5, "AppleUSBEHCI[%p]::SaveControllerStateForSleep - _myBusState < kUSBBusStateRunning - restarting USB before suspending", this);
RestartUSBBus();
}
USBLog(7, "AppleUSBEHCI[%p]::SaveControllerStateForSleep - about to suspend bus - showing queue", this);
printAsyncQueue(7, "SaveControllerStateForSleep");
SuspendUSBBus();
USBLog(7, "AppleUSBEHCI[%p]::SaveControllerStateForSleep The bus is now suspended - showing queue", this);
printAsyncQueue(7, "SaveControllerStateForSleep");
_myBusState = kUSBBusStateSuspended;
showRegisters(7, "-SaveControllerStateForSleep");
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::RestoreControllerStateFromSleep(void)
{
USBLog(5, "AppleUSBEHCI[%p]::RestoreControllerStateFromSleep - setPowerState powering on USB", this);
showRegisters(7, "+RestoreControllerStateFromSleep");
if ((USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIPortChangeIntBit) || (_errataBits & kErrataMissingPortChangeInt))
{
UInt32 port;
for (port=0; port < _rootHubNumPorts; port++)
{
UInt32 portSC = USBToHostLong(_pEHCIRegisters->PortSC[port]);
if (portSC & kEHCIPortSC_ConnectChange)
{
if (portSC & kEHCIPortSC_Enabled)
{
USBError(1, "USB (EHCI):Port %d on bus 0x%x - connect status changed but still enabled. clearing enable bit: portSC(%p)\n", (int)port+1, (uint32_t)_busNumber, (void*)portSC);
portSC = getPortSCForWriting(_pEHCIRegisters, port+1);
portSC &= ~kEHCIPortSC_Enabled;
_pEHCIRegisters->PortSC[port] = HostToUSBLong(portSC);
}
else
{
IOLog("USB (EHCI):Port %d on bus 0x%x connected or disconnected: portSC(%p)\n", (int)port+1, (uint32_t)_busNumber, (void*)portSC);
USBLog(5, "AppleUSBEHCI[%p]::RestoreControllerStateFromSleep Port %d on bus 0x%x - connected or disconnected, calling EnsureUsability()", this, (int)port+1, (uint32_t)_busNumber);
EnsureUsability();
}
}
else if (portSC & kEHCIPortSC_Resume)
{
USBLog(5, "AppleUSBEHCI[%p]::RestoreControllerStateFromSleep Port %d on bus 0x%x - has remote wakeup from some device", this, (int)port+1, (uint32_t)_busNumber);
if (_rootHubDevice && _rootHubDevice->GetPolicyMaker())
{
_rootHubDevice->GetPolicyMaker()->message(kIOUSBMessageRootHubWakeEvent, this, (void *)(uintptr_t) port);
}
else
{
IOLog("\tUSB (EHCI):Port %d on bus 0x%x has remote wakeup from some device\n", (int)port+1, (uint32_t)_busNumber);
}
if ((_errataBits & kErrataMissingPortChangeInt) && !_portChangeInterrupt && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIPortChangeIntBit))
{
USBLog(2, "AppleUSBEHCI[%p]::RestoreControllerStateFromSleep - reclaiming missing Port Change interrupt for port %d", this, (int)port+1);
_portChangeInterrupt = kEHCIPortChangeIntBit;
}
}
else if ((portSC & kEHCIPortSC_Enabled) && !(portSC & kEHCIPortSC_Suspend))
{
USBError(1, "USB (EHCI):Port %d on bus 0x%x - port enabled but not suspended. clearing enable bit: portSC(%p)\n", (int)port+1, (uint32_t)_busNumber, (void*)portSC);
portSC = getPortSCForWriting(_pEHCIRegisters, port+1);
portSC &= ~kEHCIPortSC_Enabled;
_pEHCIRegisters->PortSC[port] = HostToUSBLong(portSC);
}
}
}
USBLog(7, "AppleUSBEHCI[%p]::RestoreControllerStateFromSleep - about to resume bus - showing queue", this);
printAsyncQueue(7, "RestoreControllerStateFromSleep");
ResumeUSBBus();
USBLog(7, "AppleUSBEHCI[%p]::RestoreControllerStateFromSleep - bus has been resumed - showing queue", this);
printAsyncQueue(7, "RestoreControllerStateFromSleep");
_myBusState = kUSBBusStateRunning;
showRegisters(7, "-RestoreControllerStateFromSleep");
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::ResetControllerState(void)
{
int i;
USBTrace( kUSBTEHCI, kTPEHCIResetControllerState, (uintptr_t)this, 0, 0, 0);
USBLog(5, "AppleUSBEHCI[%p]::ResetControllerState - powering down USB - _pEHCIRegisters(%p) _pEHCICapRegisters(%p) PCIConfigCommand(%p)", this, _pEHCIRegisters, _pEHCICapRegisters, (void*)_device->configRead16(kIOPCIConfigCommand));
showRegisters(2, "+ResetControllerState");
_pEHCIRegisters->USBCMD = 0; IOSync();
_myBusState = kUSBBusStateReset;
for (i=0; (i < 100) && !(USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit); i++)
IOSleep(1);
if (i >= 100)
{
USBError(1, "AppleUSBEHCI[%p]::ResetControllerState - could not get chip to halt within 100 ms", this);
return kIOReturnInternalError;
}
if (_pEHCIRegisters->AsyncListAddr)
{
_savedAsyncListAddr = _pEHCIRegisters->AsyncListAddr;
USBLog(5, "AppleUSBEHCI[%p]::ResetControllerState - got _savedAsyncListAddr(%p)", this, (void*)_savedAsyncListAddr);
}
_pEHCIRegisters->PeriodicListBase = 0; _pEHCIRegisters->AsyncListAddr = 0; IOSync();
USBLog(5, "AppleUSBEHCI[%p]::ResetControllerState - reseting saved status for %d root hub ports", this, (int)_rootHubNumPorts);
for (i=0; i < _rootHubNumPorts; i++)
{
_rhPrevStatus[i] = 0;
}
_uimInitialized = false;
showRegisters(2, "-ResetControllerState");
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::RestartControllerFromReset(void)
{
int i;
UInt32 USBCmd;
USBTrace( kUSBTEHCI, kTPEHCIRestartControllerFromReset, (uintptr_t)this, 0, 0, 0);
USBLog(5, "AppleUSBEHCI[%p]::RestartControllerFromReset - restarting USB _uimInitialized(%s) _savedAsyncListAddr(%p)", this, _uimInitialized ? "yes" : "no", (void*)_savedAsyncListAddr);
if (!_uimInitialized)
{
_pEHCIRegisters->USBCMD = HostToUSBLong(kEHCICMDHCReset);
IOSync();
for ( i = 0; (i < 100) && (USBToHostLong(_pEHCIRegisters->USBCMD) & kEHCICMDHCReset); i++ )
IOSleep(1);
if ( i >= 100 )
{
USBError(1, "AppleUSBEHCI[%p]::RestartControllerFromReset - could not get chip to come out of reset within 100 ms", this);
return kIOReturnInternalError;
}
}
_pEHCIRegisters->PeriodicListBase = _physPeriodicListBase;
IOSync();
if (_pEHCIRegisters->AsyncListAddr != _savedAsyncListAddr)
{
USBLog(5, "AppleUSBEHCI[%p]::RestartControllerFromReset - restoring AsyncListAddr[from 0x%x to 0x%x]", this, (uint32_t)_pEHCIRegisters->AsyncListAddr, (uint32_t)_savedAsyncListAddr);
_pEHCIRegisters->AsyncListAddr = _savedAsyncListAddr;
IOSync();
}
USBCmd = USBToHostLong(_pEHCIRegisters->USBCMD);
_frameListSize = (USBCmd & kEHCICMDFrameListSizeMask) >> kEHCICMDFrameListSizeOffset;
if (_frameListSize)
{
USBError(1, "AppleUSBEHCI[%p]::RestartControllerFromReset - bad _frameListSize", this);
return kIOReturnInternalError;
}
_frameListSize = 1024;
USBCmd |= kEHCICMDRunStop;
_myBusState = kUSBBusStateRunning;
USBCmd &= ~kEHCICMDIntThresholdMask;
USBCmd |= 1 << kEHCICMDIntThresholdOffset; _pEHCIRegisters->USBCMD = HostToUSBLong(USBCmd);
_pEHCIRegisters->ConfigFlag = HostToUSBLong(kEHCIPortRoutingBit); IOSync();
if (_errataBits & kErrataNECIncompleteWrite)
{
UInt32 newValue = 0, count = 0;
newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag);
while ((count++ < 10) && (newValue != kEHCIPortRoutingBit))
{
USBError(1, "EHCI driver: RestartControllerFromReset - ConfigFlag bit not sticking. Retrying.");
_pEHCIRegisters->ConfigFlag = HostToUSBLong(kEHCIPortRoutingBit);
IOSync();
newValue = USBToHostLong(_pEHCIRegisters->ConfigFlag);
}
}
_savedUSBIntr = HostToUSBLong(kEHCICompleteIntBit | kEHCIErrorIntBit | kEHCIHostErrorIntBit | kEHCIFrListRolloverIntBit | kEHCIPortChangeIntBit);
_outSlot = kEHCIPeriodicListEntries+1;
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::DozeController(void)
{
USBTrace( kUSBTEHCI, kTPEHCIDozeController, (uintptr_t)this, 0, 0, 0);
DisableAsyncSchedule(true);
DisablePeriodicSchedule(true);
StopUSBBus();
if (_myPowerState == kUSBPowerStateOn)
{
_pEHCIRegisters->USBIntr = _pEHCIRegisters->USBIntr | HostToUSBLong(kEHCIPortChangeIntBit);
IOSync();
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::WakeControllerFromDoze(void)
{
int i;
UInt32 port;
bool somePortNeedsToResume = false;
USBTrace( kUSBTEHCI, kTPEHCIWakeControllerFromDoze, (uintptr_t)this, 0, 0, 0);
RestartUSBBus();
for (port = 0; port < _rootHubNumPorts; port++)
{
UInt32 portStatus = USBToHostLong(_pEHCIRegisters->PortSC[port]);
if (portStatus & kEHCIPortSC_Resume)
{
USBLog(5, "AppleUSBEHCI[%p]::WakeControllerFromDoze - port %d appears to be resuming from a remote wakeup", this, (int)port+1);
_rhPortBeingResumed[port] = true;
somePortNeedsToResume = true;
}
}
if ( somePortNeedsToResume )
{
IOSleep(20);
RHCompleteResumeOnAllPorts();
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::EnableInterruptsFromController(bool enable)
{
bool armSecondaryInterrupt = false;
USBTrace( kUSBTEHCI, kTPEHCIEnableInterrupts, (uintptr_t)this, enable, 0, 0);
if (enable)
{
if ((_errataBits & kErrataMissingPortChangeInt) && _portChangeInterrupt)
{
UInt32 sts = USBToHostLong(_pEHCIRegisters->USBSTS);
UInt32 intr = USBToHostLong(_pEHCIRegisters->USBIntr);
if (!(intr & kEHCIPortChangeIntBit)) {
if (!(sts & kEHCIPortChangeIntBit))
{
USBLog(2, "AppleUSBEHCI[%p]::EnableInterruptsFromController - arming for missed port change interrupt", this);
armSecondaryInterrupt = true;
}
else
{
USBLog(2, "AppleUSBEHCI[%p]::EnableInterruptsFromController - no need to rearm for port change interrupt since is will arm itself", this);
}
}
else
{
USBLog(2, "AppleUSBEHCI[%p]::EnableInterruptsFromController - Port Change int unexpectedly armed in USBIntr register", this);
}
}
USBLog(5, "AppleUSBEHCI[%p]::EnableInterruptsFromController - enabling interrupts, USBIntr(%p) _savedUSBIntr(%p)", this, (void*)_pEHCIRegisters->USBIntr, (void*)HostToUSBLong(_savedUSBIntr));
_pEHCIRegisters->USBIntr = _savedUSBIntr;
IOSync();
_savedUSBIntr = 0;
}
else
{
_savedUSBIntr = _pEHCIRegisters->USBIntr; _pEHCIRegisters->USBIntr = HostToUSBLong(kEHCIFrListRolloverIntBit); IOSync();
USBLog(5, "AppleUSBEHCI[%p]::EnableInterruptsFromController - interrupts disabled, _savedUSBIntr(%p)", this, (void*)_savedUSBIntr);
}
if (armSecondaryInterrupt && _filterInterruptSource)
_filterInterruptSource->signalInterrupt();
return kIOReturnSuccess;
}
IOReturn
AppleUSBEHCI::powerStateDidChangeTo ( IOPMPowerFlags capabilities, unsigned long stateNumber, IOService* whatDevice)
{
USBTrace( kUSBTEHCI, kTPEHCIPowerState, (uintptr_t)this, stateNumber, 0, 2);
USBLog(5, "AppleUSBEHCI[%p]::powerStateDidChangeTo - stateNumber(%d)", this, (int)stateNumber);
if ((_myPowerState == kUSBPowerStateSleep) && (stateNumber == kUSBPowerStateLowPower))
{
_savedUSBIntr = _savedUSBIntr | HostToUSBLong(kEHCIPortChangeIntBit);
USBLog(5, "AppleUSBEHCI[%p]::powerStateDidChangeTo - added port change bit to _savedUSBIntr - now (%p)", this, (void*)_savedUSBIntr);
}
return super::powerStateDidChangeTo(capabilities, stateNumber, whatDevice);
}
void
AppleUSBEHCI::powerChangeDone ( unsigned long fromState)
{
unsigned long newState = getPowerState();
USBTrace( kUSBTEHCI, kTPEHCIPowerState, (uintptr_t)this, fromState, newState, 1);
USBLog((fromState == newState) ? 7 : 4, "AppleUSBEHCI[%p]::powerChangeDone from state (%d) to state (%d) _controllerAvailable(%s)", this, (int)fromState, (int)newState, _controllerAvailable ? "true" : "false");
if (_wakingFromHibernation)
{
USBLog(2, "AppleUSBEHCI[%p]::powerChangeDone - _wakingFromHibernation - _savedAsyncListAddr(%p) AsyncListAddr(%p) _AsyncHead(%p)", this, (void*)USBToHostLong(_savedAsyncListAddr), (void*)_pEHCIRegisters->AsyncListAddr, _AsyncHead);
_savedAsyncListAddr = _pEHCIRegisters->AsyncListAddr;
if (_savedAsyncListAddr)
{
USBLog(1, "AppleUSBEHCI[%p]::powerChangeDone - _savedAsyncListAddr is NOT NULL (%p) - UNEXPECTED", this, (void*)_savedAsyncListAddr);
_savedAsyncListAddr = 0;
}
if (_AsyncHead) {
AppleEHCIQueueHead *pQH = _AsyncHead;
USBError(1, "AppleUSBEHCI[%p]::powerChangeDone - waking from hibernation with some queue heads on the queue. UNEXPECTED", this);
while (pQH)
{
UInt32 flags = USBToHostLong(pQH->GetSharedLogical()->flags);
USBLog(1, "AppleUSBEHCI[%p]::powerChangeDone - pQH(%p) ADDR(%d) EP(%d) DIR(%d) being throw away", this, pQH, (int)(flags & kEHCIEDFlags_FA), (int)((flags & kEHCIEDFlags_EN) >> kEHCIEDFlags_ENPhase), (int)pQH->_direction);
pQH = OSDynamicCast(AppleEHCIQueueHead, pQH->_logicalNext);
}
_AsyncHead = NULL;
}
}
if (_controllerAvailable)
showRegisters(7, "powerChangeDone");
super::powerChangeDone(fromState);
}