AppleUSBEHCI_PwrMgmt.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOService.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/platform/ApplePlatformExpert.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/IOUSBLog.h>
#include "AppleUSBEHCI.h"
enum {
kGossamerTypeGossamer = 1,
kGossamerTypeSilk,
kGossamerTypeWallstreet,
kGossamerTypeiMac,
kGossamerTypeYosemite,
kGossamerType101
};
#include "AppleUSBEHCI.h"
#define number_of_power_states 2
static IOPMPowerState ourPowerStates[number_of_power_states] = {
{1,0,0,0,0,0,0,0,0,0,0,0},
{1,IOPMDeviceUsable,IOPMPowerOn,IOPMPowerOn,0,0,0,0,0,0,0,0}
};
static IOPMPowerState ourPowerStatesKL[number_of_power_states] = {
{1,0,0,0,0,0,0,0,0,0,0,0},
{1, IOPMDeviceUsable, IOPMPowerOn, IOPMPowerOn | IOPMClockNormal, 0,0,0,0,0,0,0,0}
};
void
AppleUSBEHCI::initForPM (IOPCIDevice *provider)
{
_onCardBus = (0 != provider->metaCast("IOCardBusDevice"));
if ( !provider->getProperty("AAPL,clock-id") && !((getPlatform()->getChipSetType() == kChipSetTypeGossamer) && getPlatform()->getMachineType() == kGossamerTypeYosemite) )
{
bool hasSupport = false;
if (_errataBits & kErrataICH6PowerSequencing)
hasSupport = provider->hasPCIPowerManagement(kPCIPMCPMESupportFromD3Cold);
else
hasSupport = provider->hasPCIPowerManagement();
if (hasSupport)
{
if (_errataBits & kErrataICH6PowerSequencing)
hasSupport = (provider->enablePCIPowerManagement(kPCIPMCPMESupportFromD3Cold) == kIOReturnSuccess);
else
hasSupport = (provider->enablePCIPowerManagement() == kIOReturnSuccess);
}
if (hasSupport)
{
_hasPCIPwrMgmt = true;
setProperty("Card Type","Built-in");
}
else
{
USBLog(1, "AppleUSBEHCI[%p]::start EHCI controller will be unloaded across sleep",this);
_unloadUIMAcrossSleep = true;
setProperty("Card Type","PCI");
}
}
else
{
setProperty("Card Type","Built-in");
}
if ( _onCardBus )
{
setProperty("Card Type","CardBus");
_unloadUIMAcrossSleep = true;
}
usb_remote_wakeup = OSSymbol::withCString("usb_remote_wakeup");
registerService();
if ( provider->getProperty("AAPL,clock-id"))
{
USBLog(2, "AppleUSBEHCI[%p]:: registering controlling driver with clock", this);
registerPowerDriver(this,ourPowerStatesKL,number_of_power_states);
}
else
{
USBLog(2, "AppleUSBEHCI[%p]:: registering controlling driver without clock", this);
registerPowerDriver(this,ourPowerStates,number_of_power_states);
}
changePowerStateTo(1);
if (_errataBits & kErrataICH6PowerSequencing)
_powerDownNotifier = registerPrioritySleepWakeInterest(PowerDownHandler, this, 0);
}
unsigned long AppleUSBEHCI::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
{
if ( getProvider()->getProperty("AAPL,clock-id")) {
if ( ((domainState & IOPMPowerOn) && (domainState & IOPMClockNormal) ) ||
(domainState & kIOPMDoze) && (domainState & IOPMClockNormal) ) {
return 1;
}
else {
return 0;
}
}
else { if ( (domainState & IOPMPowerOn) ||
(domainState & kIOPMDoze) ) {
return 1;
}
else {
return 0;
}
}
}
unsigned long AppleUSBEHCI::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
{
return 1;
}
IOReturn
AppleUSBEHCI::setPowerState( unsigned long powerStateOrdinal, IOService* whatDevice )
{
IOReturn sleepRes;
static uint32_t * pHibernateState;
USBLog(5,"AppleUSBEHCI[%p]::setPowerState (%ld) bus %ld", this, powerStateOrdinal, _busNumber );
IOSleep(5);
if (_ehciBusState != kEHCIBusStateSuspended)
{
_workLoop->CloseGate();
}
else
{
sleepRes = _workLoop->wake(&_ehciBusState);
if(sleepRes != kIOReturnSuccess)
{
USBError(1, "AppleUSBEHCI[%p]::setPowerState - Can't wake workloop, error 0x%x", this, sleepRes);
}
else
{
USBLog(5, "AppleUSBEHCI[%p]::setPowerState - workLoop successfully awakened", this);
}
}
if ( powerStateOrdinal == kEHCISetPowerLevelSuspend )
{
USBLog(5, "AppleUSBEHCI::setPowerState - disabling interrupt before suspending bus");
_savedUSBIntr = _pEHCIRegisters->USBIntr; _pEHCIRegisters->USBIntr = 0;
if ( !pHibernateState )
{
OSData * data = OSDynamicCast(OSData, (IOService::getPMRootDomain())->getProperty(kIOHibernateStateKey));
if (data)
{
pHibernateState = (uint32_t *) data->getBytesNoCopy();
}
}
if ( _unloadUIMAcrossSleep )
{
USBLog(3,"AppleUSBEHCI[%p]::setPowerState - Unloading UIM for bus %d before going to sleep", this, (int)_busNumber );
if ( _rootHubDevice )
{
USBLog(2, "AppleUSBEHCI[%p]::setPowerState - Terminating root hub in setPowerState()", this);
_rootHubDevice->terminate(kIOServiceRequired | kIOServiceSynchronous);
_rootHubDevice->detachAll(gIOUSBPlane);
_rootHubDevice->release();
_rootHubDevice = NULL;
USBLog(2, "AppleUSBEHCI[%p]::setPowerState - Terminated root hub in setPowerState()", this);
}
SuspendUSBBus();
UIMFinalizeForPowerDown();
_savedPeriodicListBase = _pEHCIRegisters->PeriodicListBase;
_savedAsyncListAddr = _pEHCIRegisters->AsyncListAddr;
_ehciAvailable = false; }
else
{
USBLog(5, "AppleUSBEHCI[%p]::setPowerState - suspending the bus", this);
_remote_wakeup_occurred = false;
if (_idleSuspend)
{
USBLog(5, "AppleUSBEHCI[%p]::setPowerState - in _idleSuspend - restarting USB before suspending", this);
RestartUSBBus();
}
USBLog(7, "AppleUSBEHCI[%p]::setPowerState - about to suspend bus - showing queue", this);
printAsyncQueue(7);
SuspendUSBBus();
_savedPeriodicListBase = _pEHCIRegisters->PeriodicListBase;
_savedAsyncListAddr = _pEHCIRegisters->AsyncListAddr;
USBLog(7, "AppleUSBEHCI[%p]::setPowerState The bus is now suspended - showing queue", this);
printAsyncQueue(7);
}
_ehciAvailable = false;
_ehciBusState = kEHCIBusStateSuspended;
_idleSuspend = false;
}
if ( powerStateOrdinal == kEHCISetPowerLevelIdleSuspend )
{
USBLog(5, "AppleUSBEHCI[%p]::setPowerState - halting the bus due to inactivity", this);
_idleSuspend = true;
DisableAsyncSchedule();
DisablePeriodicSchedule();
StopUSBBus();
USBLog(5, "AppleUSBEHCI[%p]::setPowerState - The bus is now halted due to inactivity", this);
}
if ( powerStateOrdinal == kEHCISetPowerLevelRunning )
{
if ( _uimInitialized && pHibernateState && *pHibernateState && !_wakingFromHibernation && !_idleSuspend)
{
USBLog(1,"AppleUSBEHCI[%p]::setPowerState - Unloading UIM for bus %d after hibernate - _ehciAvailable[%s]",this, (int)_busNumber, _ehciAvailable ? "true" : "false" );
_wakingFromHibernation = true; UIMFinalizeForPowerDown();
_ehciAvailable = true; if ( _rootHubDevice )
{
USBLog(2, "+AppleUSBEHCI[%p]::setPowerState - Terminating root hub in setPowerState()", this);
_rootHubDevice->terminate(kIOServiceRequired | kIOServiceSynchronous);
_rootHubDevice->detachAll(gIOUSBPlane);
_rootHubDevice->release();
_rootHubDevice = NULL;
USBLog(2, "-AppleUSBEHCI[%p]::setPowerState - Terminated root hub in setPowerState()", this);
}
USBLog(2,"AppleUSBEHCI[%p]::setPowerState - setting _needToCreateRootHub", this);
_needToCreateRootHub = true;
goto done;
}
else if ( !_uimInitialized )
{
if ( isInactive() || (_onCardBus && _pcCardEjected) )
{
_ehciBusState = kEHCIBusStateRunning;
USBLog(3,"AppleUSBEHCI[%p]::setPowerState - isInactive (or pccardEjected) while setPowerState (%d,%d)",this, isInactive(), _pcCardEjected);
}
else
{
IOReturn err = kIOReturnSuccess;
USBLog(5, "AppleUSBEHCI[%p]::setPowerState - Re-loading UIM if necessary (%d)", this, _uimInitialized );
UIMInitializeForPowerUp();
_ehciBusState = kEHCIBusStateRunning;
_ehciAvailable = true;
if ( _rootHubDevice == NULL )
{
err = CreateRootHubDevice( _device, &_rootHubDevice );
if ( err != kIOReturnSuccess )
{
USBError(1,"AppleUSBEHCI[%p]::setPowerState - Could not create root hub device upon wakeup (%x)!", this, err);
}
else
{
_rootHubDevice->registerService(kIOServiceRequired | kIOServiceSynchronous);
}
}
}
}
else if (_idleSuspend)
{
USBLog(5, "AppleUSBEHCI[%p]::setPowerState - in _idleSuspend - restarting USB", this);
RestartUSBBus();
}
else
{
USBLog(5, "AppleUSBEHCI[%p]::setPowerState - setPowerState powering on USB", this);
if (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIPortChangeIntBit)
{
IOLog("USB caused wake event (EHCI)\n");
}
_remote_wakeup_occurred = true;
_ehciAvailable = true;
if (_savedUSBIntr)
_pEHCIRegisters->USBIntr = _savedUSBIntr; USBLog(5, "AppleUSBEHCI[%p]::setPowerState - after reenabling interrupts, USBIntr = %p", this, (void*)USBToHostLong(_pEHCIRegisters->USBIntr));
USBLog(7, "AppleUSBEHCI[%p]::setPowerState - about to resume bus - showing queue", this);
printAsyncQueue(7);
ResumeUSBBus();
USBLog(7, "AppleUSBEHCI[%p]::setPowerState - bus has been resumed - showing queue", this);
printAsyncQueue(7);
_ehciBusState = kEHCIBusStateRunning;
}
LastRootHubPortStatusChanged(true);
_idleSuspend = false;
}
done:
if (_ehciBusState == kEHCIBusStateSuspended)
{
sleepRes = _workLoop->sleep(&_ehciBusState);
if(sleepRes != kIOReturnSuccess)
{
USBError(1, "AppleUSBEHCI[%p]::setPowerState - Can't sleep workloop, error 0x%x", this, sleepRes);
}
else
{
USBLog(5, "AppleUSBEHCI[%p]::setPowerState - workLoop successfully slept", this);
}
}
else
{
_workLoop->OpenGate();
}
USBLog(5,"AppleUSBEHCI[%p]::setPowerState done", this );
return IOPMAckImplied;
}
IOReturn AppleUSBEHCI::callPlatformFunction(const OSSymbol *functionName,
bool waitForFunction,
void *param1, void *param2,
void *param3, void *param4)
{
IOLog("EHCIUIM -- callPlatformFunction unimplimented \n");
if (functionName == usb_remote_wakeup)
{
bool *wake;
wake = (bool *)param1;
if (_remote_wakeup_occurred)
{
*wake = true;
}
else
{
*wake = false;
}
return kIOReturnSuccess;
}
return kIOReturnBadArgument;
}
void
AppleUSBEHCI::ResumeUSBBus()
{
UInt8 numPorts;
int i;
bool enabledports = false;
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);
}
}
}
if (_savedPeriodicListBase && (_pEHCIRegisters->PeriodicListBase != _savedPeriodicListBase))
{
USBLog(4, "AppleUSBEHCI[%p]::ResumeUSBBus - restoring PeriodicListBase[from 0x%x to 0x%x]", this, (unsigned int)USBToHostLong(_pEHCIRegisters->PeriodicListBase), (unsigned int)USBToHostLong(_savedPeriodicListBase));
_pEHCIRegisters->PeriodicListBase = _savedPeriodicListBase;
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)
{
_pEHCIRegisters->USBCMD |= HostToUSBLong(kEHCICMDRunStop);
IOSync();
for (i=0; (i< 100) && (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIHCHaltedBit); i++)
IODelay(100);
if (i>1)
{
USBError(1, "AppleUSBEHCI[%p]::ResumeUSBBus - controller took (%d) turns to get going", this, i);
}
}
numPorts = USBToHostLong(_pEHCICapRegisters->HCSParams) & kEHCINumPortsMask;
USBLog(7, "AppleUSBEHCI[%p]::ResumeUSBBus - resuming %d ports", this, numPorts);
for (i=0; i < numPorts; i++)
{
UInt32 portStat;
portStat = USBToHostLong(_pEHCIRegisters->PortSC[i]);
if (portStat & kEHCIPortSC_Owner)
{
USBLog(4, "AppleUSBEHCI[%p]::ResumeUSBBus - port %d owned by OHCI", this, i+1);
}
else if (portStat & kEHCIPortSC_Enabled)
{
if ( !(_savedSuspendedPortBitmap & (1<<i)) || (portStat & kEHCIPortSC_Resume) )
{
portStat |= kEHCIPortSC_Resume;
_pEHCIRegisters->PortSC[i] = HostToUSBLong(portStat);
IOSync();
if (_errataBits & kErrataNECIncompleteWrite)
{
UInt32 newValue = 0, count = 0;
newValue = USBToHostLong(_pEHCIRegisters->PortSC[i]);
while ((count++ < 10) && !(newValue & kEHCIPortSC_Resume))
{
USBError(1, "EHCI driver: ResumeUSBBus - PortSC resume not sticking (on). Retrying.");
_pEHCIRegisters->PortSC[i] = HostToUSBLong(portStat);
IOSync();
newValue = USBToHostLong(_pEHCIRegisters->PortSC[i]);
}
}
if ( (portStat & kEHCIPortSC_Resume) && (_savedSuspendedPortBitmap & (1<<i)))
{
USBLog(4, "AppleUSBEHCI[%p]::ResumeUSBBus - port %d was suspended but resuming it because it generated a resume", this, i+1);
}
USBLog(4, "AppleUSBEHCI[%p]::ResumeUSBBus - port %d now resumed (%ld, %ld)", this, i+1, _savedSuspendedPortBitmap & (1<<i), portStat & kEHCIPortSC_Resume);
}
else
USBLog(4, "AppleUSBEHCI[%p]::ResumeUSBBus - port %d not resuming because it was previously suspended", this, i+1);
enabledports = true;
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::ResumeUSBBus - port %d not enabled", this, i);
}
}
if (enabledports)
{
USBLog(7, "AppleUSBEHCI[%p]::ResumeUSBBus Delaying 20 milliseconds in resume state", this);
IODelay(20000);
for (i=0; i < numPorts; i++)
{
UInt32 portStat;
portStat = USBToHostLong(_pEHCIRegisters->PortSC[i]);
if (portStat & kEHCIPortSC_Owner)
{
USBLog(7, "AppleUSBEHCI[%p]::ResumeUSBBus - port %d owned by OHCI", this, i+1);
}
else if (portStat & kEHCIPortSC_Enabled)
{
portStat &= ~kEHCIPortSC_Resume;
_pEHCIRegisters->PortSC[i] = HostToUSBLong(portStat);
IOSync();
#if 0
if (_errataBits & kErrataNECIncompleteWrite)
{
UInt32 newValue = 0, count = 0;
IODelay(2000); newValue = USBToHostLong(_pEHCIRegisters->PortSC[i]);
while ((count++ < 10) && (newValue & kEHCIPortSC_Resume))
{
USBError(1, "EHCI driver: ResumeUSBBus - PortSC resume not sticking (off). Retrying.");
_pEHCIRegisters->PortSC[i] = HostToUSBLong(portStat);
IOSync();
IODelay(2000); newValue = USBToHostLong(_pEHCIRegisters->PortSC[i]);
}
}
#endif
USBLog(7, "AppleUSBEHCI[%p]::ResumeUSBBus - port %d finished resume sequence", this, i+1);
enabledports = true;
}
else
{
USBLog(7, "AppleUSBEHCI[%p]::ResumeUSBBus - port %d not enabled", this, i+1);
}
}
IODelay(10000); }
if (_savedUSBCMD)
{
USBLog(7, "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;
_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));
}
_savedPeriodicListBase = _pEHCIRegisters->PeriodicListBase;
_savedAsyncListAddr = _pEHCIRegisters->AsyncListAddr;
GetNumberOfPorts( &numPorts );
USBLog(numPorts ? 4 : 1, "AppleUSBEHCI[%p]::SuspendUSBBus - suspending %d ports", this, numPorts);
for (i=0; i < numPorts; i++)
{
UInt32 portStat;
portStat = USBToHostLong(_pEHCIRegisters->PortSC[i]);
if (portStat & kEHCIPortSC_Owner)
{
USBLog(4, "AppleUSBEHCI[%p]::SuspendUSBBus - port %d owned by OHCI", this, i+1);
}
else if (portStat & kEHCIPortSC_Enabled)
{
if (portStat & kEHCIPortSC_Suspend)
{
_savedSuspendedPortBitmap |= (1<<i);
USBLog(4, "AppleUSBEHCI[%p]::SuspendUSBBus - port %d was already suspended", this, i+1);
}
else
{
EHCIRootHubPortSuspend(i+1, true);
}
}
else
{
USBLog(4, "AppleUSBEHCI[%p]::SuspendUSBBus - port %d not enabled", this, i+1);
}
}
usbcmd &= ~kEHCICMDRunStop;
_pEHCIRegisters->USBCMD = HostToUSBLong(usbcmd);
IOSync();
_ehciBusState = kEHCIBusStateOff;
USBLog(7, "AppleUSBEHCI[%p]::SuspendUSBBus - ports suspended, HC stop set, waiting for halted", this);
do
{
usbsts = USBToHostLong(_pEHCIRegisters->USBSTS);
} while (!(usbsts & kEHCIHCHaltedBit));
USBLog(5, "AppleUSBEHCI[%p]::SuspendUSBBus - HC halted", this);
}
void
AppleUSBEHCI::StopUSBBus()
{
UInt32 usbcmd;
usbcmd = USBToHostLong(_pEHCIRegisters->USBCMD);
usbcmd &= ~kEHCICMDRunStop;
_pEHCIRegisters->USBCMD = HostToUSBLong(usbcmd);
_ehciBusState = kEHCIBusStateOff;
USBLog(5, "AppleUSBEHCI[%p]::StopUSBBus - HC halted", this);
}
void
AppleUSBEHCI::RestartUSBBus()
{
UInt32 usbcmd, usbsts;
do
{
usbsts = USBToHostLong(_pEHCIRegisters->USBSTS);
} while (!(usbsts & kEHCIHCHaltedBit));
usbcmd = USBToHostLong(_pEHCIRegisters->USBCMD);
usbcmd |= kEHCICMDRunStop;
_pEHCIRegisters->USBCMD = HostToUSBLong(usbcmd);
_ehciBusState = kEHCIBusStateRunning;
USBLog(5, "AppleUSBEHCI[%p]::RestartUSBBus - HC restarted", this);
}
IOReturn
AppleUSBEHCI::PowerDownHandler(void *target, void *refCon, UInt32 messageType, IOService *service,
void *messageArgument, vm_size_t argSize )
{
AppleUSBEHCI * me = OSDynamicCast(AppleUSBEHCI, (OSObject *)target);
if (!me || !(me->_errataBits & kErrataICH6PowerSequencing))
return kIOReturnUnsupported;
USBLog(2, "AppleUSBEHCI[%p]::PowerDownHandler PowerDownHandler %p %p", me, (void*)messageType, messageArgument);
if (me->_ehciAvailable)
{
switch (messageType)
{
case kIOMessageSystemWillRestart:
case kIOMessageSystemWillPowerOff:
if (me->_ehciBusState == kEHCIBusStateRunning)
{
if ( me->_rootHubDevice )
{
me->_rootHubDevice->terminate(kIOServiceRequired | kIOServiceSynchronous);
me->_rootHubDevice->detachAll(gIOUSBPlane);
me->_rootHubDevice->release();
me->_rootHubDevice = NULL;
}
me->SuspendUSBBus();
}
me->_watchdogUSBTimer->cancelTimeout();
if (me->_uimInitialized)
{
me->UIMFinalizeForPowerDown();
}
break;
default:
break;
}
}
return kIOReturnSuccess;
}