AppleUSBEHCI_PwrMgmt.orig.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/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) )
{
if (provider->hasPCIPowerManagement() && (provider->enablePCIPowerManagement() == kIOReturnSuccess))
{
_hasPCIPwrMgmt = true;
setProperty("Card Type","Built-in");
}
else
{
USBLog(1, "%s[%p]::start EHCI controller will be unloaded across sleep",getName(),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, "%s(%p):: registering controlling driver with clock", getName(), this);
registerPowerDriver(this,ourPowerStatesKL,number_of_power_states);
}
else
{
USBLog(2, "%s(%p):: registering controlling driver without clock", getName(), this);
registerPowerDriver(this,ourPowerStates,number_of_power_states);
}
changePowerStateTo(1);
}
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;
USBLog(4,"%s[%p]::setPowerState (%ld) bus %d", getName(), this, powerStateOrdinal, _busNumber );
IOSleep(5);
if (_ehciBusState != kEHCIBusStateSuspended)
{
_workLoop->CloseGate();
}
else
{
sleepRes = _workLoop->wake(&_ehciBusState);
if(sleepRes != kIOReturnSuccess)
{
USBError(1, "%s[%p] setPowerState - Can't wake workloop, error 0x%x", getName(), this, sleepRes);
}
else
{
USBLog(5, "%s[%p :setPowerState - workLoop successfully awakened", getName(), this);
}
}
if ( powerStateOrdinal == kEHCISetPowerLevelSuspend )
{
if ( _unloadUIMAcrossSleep )
{
USBLog(3,"%s[%p] Unloading UIM for bus %d before going to sleep",getName(),this, _busNumber );
if ( _rootHubDevice )
{
USBLog(2, "%s[%p] Terminating root hub in setPowerState()", getName(), this);
_rootHubDevice->terminate(kIOServiceRequired | kIOServiceSynchronous);
_rootHubDevice->detachAll(gIOUSBPlane);
_rootHubDevice->release();
_rootHubDevice = NULL;
USBLog(2, "%s[%p] Terminated root hub in setPowerState()", getName(), this);
}
SuspendUSBBus();
UIMFinalizeForPowerDown();
_ehciAvailable = false; }
else
{
USBLog(2, "%s[%p] suspending the bus", getName(), this);
_remote_wakeup_occurred = false;
if (_idleSuspend)
{
USBLog(5, "%s[%p]::setPowerState - in _idleSuspend - restarting USB before suspending", getName(), this);
RestartUSBBus();
}
SuspendUSBBus();
USBLog(2, "%s[%p] The bus is now suspended", getName(), this);
}
_ehciBusState = kEHCIBusStateSuspended;
_idleSuspend = false;
if (_hasPCIPwrMgmt)
{
_savedUSBIntr = _pEHCIRegisters->USBIntr; _pEHCIRegisters->USBIntr = 0; _ehciAvailable = false; }
}
if ( powerStateOrdinal == kEHCISetPowerLevelIdleSuspend )
{
USBLog(2, "%s[%p] halting the bus due to inactivity", getName(), this);
_idleSuspend = true;
StopUSBBus();
USBLog(2, "%s[%p] The bus is now halted due to inactivity", getName(), this);
}
if ( powerStateOrdinal == kEHCISetPowerLevelRunning )
{
if ( !_uimInitialized )
{
if ( isInactive() || (_onCardBus && _pcCardEjected) )
{
_ehciBusState = kEHCIBusStateRunning;
USBLog(3,"%s[%p] isInactive (or pccardEjected) while setPowerState (%d,%d)",getName(),this, isInactive(), _pcCardEjected);
}
else
{
IOReturn err = kIOReturnSuccess;
USBLog(5, "%s[%p]: Re-loading UIM if necessary (%d)", getName(), this, _uimInitialized );
UIMInitializeForPowerUp();
_ehciBusState = kEHCIBusStateRunning;
_ehciAvailable = true; if ( _rootHubDevice == NULL )
{
err = CreateRootHubDevice( _device, &_rootHubDevice );
if ( err != kIOReturnSuccess )
{
USBError(1,"%s[%p] Could not create root hub device upon wakeup (%x)!",getName(), this, err);
}
else
{
_rootHubDevice->registerService(kIOServiceRequired | kIOServiceSynchronous);
}
}
}
}
else if (_idleSuspend)
{
USBLog(1, "%s[%p]::setPowerState - in _idleSuspend - restarting USB", getName(), this);
RestartUSBBus();
}
else
{
USBLog(2, "%s[%p] setPowerState powering on USB", getName(), this);
if (USBToHostLong(_pEHCIRegisters->USBSTS) & kEHCIPortChangeIntBit)
{
IOLog("USB caused wake event (EHCI)\n");
}
_remote_wakeup_occurred = true;
if (_hasPCIPwrMgmt)
{
_ehciAvailable = true; if (_savedUSBIntr)
_pEHCIRegisters->USBIntr = _savedUSBIntr; USBLog(4, "%s[%p]::setPowerState - after reenabling interrupts, USBIntr = %p", getName(), this, USBToHostLong(_pEHCIRegisters->USBIntr));
}
ResumeUSBBus();
_ehciBusState = kEHCIBusStateRunning;
}
LastRootHubPortStatusChanged(true);
_idleSuspend = false;
}
if (_ehciBusState == kEHCIBusStateSuspended)
{
sleepRes = _workLoop->sleep(&_ehciBusState);
if(sleepRes != kIOReturnSuccess)
{
USBError(1, "%s[%p] setPowerState - Can't sleep workloop, error 0x%x", getName(), this, sleepRes);
}
else
{
USBLog(5, "%s[%p :setPowerState - workLoop successfully slept", getName(), this);
}
}
else
{
_workLoop->OpenGate();
}
USBLog(4,"%s[%p]::setPowerState done", getName(), 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;
numPorts = USBToHostLong(_pEHCICapRegisters->HCSParams) & kEHCINumPortsMask;
USBLog(7, "%s[%p]::ResumeUSBBus - resuming %d ports", getName(), this, numPorts);
for (i=0; i < numPorts; i++)
{
UInt32 portStat;
portStat = USBToHostLong(_pEHCIRegisters->PortSC[i]);
if (portStat & kEHCIPortSC_Owner)
{
USBLog(7, "%s[%p]::ResumeUSBBus - port %d owned by OHCI", getName(), this, i);
}
else if (portStat & kEHCIPortSC_Enabled)
{
portStat |= kEHCIPortSC_Resume;
_pEHCIRegisters->PortSC[i] = HostToUSBLong(portStat);
USBLog(7, "%s[%p]::ResumeUSBBus - port %d now resumed", getName(), this, i);
enabledports = true;
}
else
{
USBLog(7, "%s[%p]::ResumeUSBBus - port %d not enabled", getName(), this, i);
}
}
if (enabledports)
{
USBLog(2, "%s[%p]::ResumeUSBBus Delaying 20 milliseconds in resume state", getName(), this);
IODelay(20000);
for (i=0; i < numPorts; i++)
{
UInt32 portStat;
portStat = USBToHostLong(_pEHCIRegisters->PortSC[i]);
if (portStat & kEHCIPortSC_Owner)
{
USBLog(7, "%s[%p]::ResumeUSBBus - port %d owned by OHCI", getName(), this, i);
}
else if (portStat & kEHCIPortSC_Enabled)
{
portStat &= ~kEHCIPortSC_Resume;
_pEHCIRegisters->PortSC[i] = HostToUSBLong(portStat);
USBLog(7, "%s[%p]::ResumeUSBBus - port %d now resumed", getName(), this, i);
enabledports = true;
}
else
{
USBLog(7, "%s[%p]::ResumeUSBBus - port %d not enabled", getName(), this, i);
}
}
}
if (_savedUSBCMD)
{
USBLog(7, "%s[%p]::ResumeUSBBus - USBCMD is <%x> will be <%x>", getName(), this, _pEHCIRegisters->USBCMD, _savedUSBCMD);
_pEHCIRegisters->USBCMD = _savedUSBCMD;
}
}
void
AppleUSBEHCI::SuspendUSBBus()
{
UInt8 numPorts;
int i;
UInt32 usbcmd, usbsts;
_savedUSBCMD = _pEHCIRegisters->USBCMD;
USBLog(7, "%s[%p]::SuspendUSBBus - got _savedUSBCMD <%x>", getName(), this, _savedUSBCMD);
usbcmd = USBToHostLong(_savedUSBCMD);
usbcmd &= ~kEHCICMDAsyncEnable;
usbcmd &= ~kEHCICMDPeriodicEnable;
_pEHCIRegisters->USBCMD = HostToUSBLong(usbcmd);
GetNumberOfPorts( &numPorts );
USBLog(7, "%s[%p]::SuspendUSBBus - suspending %d ports", getName(), this, numPorts);
for (i=0; i < numPorts; i++)
{
UInt32 portStat;
portStat = USBToHostLong(_pEHCIRegisters->PortSC[i]);
if (portStat & kEHCIPortSC_Owner)
{
USBLog(7, "%s[%p]::SuspendUSBBus - port %d owned by OHCI", getName(), this, i);
}
else if (portStat & kEHCIPortSC_Enabled)
{
portStat |= kEHCIPortSC_Suspend;
_pEHCIRegisters->PortSC[i] = HostToUSBLong(portStat);
USBLog(7, "%s[%p]::SuspendUSBBus - port %d now suspended", getName(), this, i);
}
else
{
USBLog(7, "%s[%p]::SuspendUSBBus - port %d not enabled", getName(), this, i);
}
}
usbcmd &= ~kEHCICMDRunStop;
_pEHCIRegisters->USBCMD = HostToUSBLong(usbcmd);
_ehciBusState = kEHCIBusStateOff;
USBLog(7, "%s[%p]::SuspendUSBBus - ports suspended, HC stop set, waiting for halted", getName(), this);
do
{
usbsts = USBToHostLong(_pEHCIRegisters->USBSTS);
} while (!(usbsts & kEHCIHCHaltedBit));
USBLog(3, "%s[%p]::SuspendUSBBus - HC halted", getName(), this);
}
void
AppleUSBEHCI::StopUSBBus()
{
UInt32 usbcmd;
usbcmd = USBToHostLong(_pEHCIRegisters->USBCMD);
usbcmd &= ~kEHCICMDRunStop;
_pEHCIRegisters->USBCMD = HostToUSBLong(usbcmd);
_ehciBusState = kEHCIBusStateOff;
USBLog(1, "%s[%p]::StopUSBBus - HC halted", getName(), 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(1, "%s[%p]::RestartUSBBus - HC restarted", getName(), this);
}