Portable_PlatformMonitor.cpp [plain text]
#include "Portable_PlatformMonitor.h"
static const OSSymbol *gIOPMonPowerStateKey;
static const OSSymbol *gIOPMonClamshellStateKey;
static const OSSymbol *gIOPMonCPUActionKey;
static const OSSymbol *gIOPMonGPUActionKey;
static const OSSymbol *gIOPMonState0;
static const OSSymbol *gIOPMonState1;
static const OSSymbol *gIOPMonState2;
static const OSSymbol *gIOPMonState3;
static const OSSymbol *gIOPMonFull;
static const OSSymbol *gIOPMonReduced;
static const OSSymbol *gIOPMonSlow;
static const OSSymbol *gIOClamshellStateOpen;
static const OSSymbol *gIOClamshellStateClosed;
static Portable_PlatformMonitor *gIOPMon;
static IOService *provider;
static ConSensorInfo conSensorArray[kMaxConSensors];
static ConSensorInfo subSensorArray[kMaxSensorIndex];
ThresholdInfo thermalThresholdInfoArray[kMaxSensorIndex][kNumClamshellStates][kMaxThermalStates];
LimitsInfo *thermalLimits = NULL;
IORecursiveLock *setSpeedLock;
static LimitsInfo limits_Q72[5] =
{ { 0, 63, 1, kThrottleCPU, kNoSpecialState, }, { 1, 83, 1, kThrottleCPU, kNoSpecialState, }, { 2, 92, 1, kThrottleCPU, kNoSpecialState, }, { 3, 73, 5, kThrottleCPU, kNoSpecialState, }, { -1, 0, 0, 0, 0, } };
static LimitsInfo limits_Q54A[6] =
{ { 0, 54, 2, kThrottleCPU, kNoSpecialState, }, { 0, 59, 2, kThrottleCPU, kClamshellClosedState, }, { 1, 79, 4, kThrottleCPU, kNoSpecialState, }, { 2, 103, 4, kThrottleCPU, kNoSpecialState, }, { 3, 42, 2, kThrottleCPU, kNoSpecialState, }, { -1, 0, 0, 0, 0, } };
static LimitsInfo limits_Q16A[5] =
{ { 0, 76, 2, kThrottleCPU, kNoSpecialState, }, { 1, 75, 2, kThrottleCPU, kNoSpecialState, }, { 2, 82, 2, kThrottleCPU, kNoSpecialState, }, { 3, 42, 5, kThrottleCPU, kNoSpecialState, }, { -1, 0, 0, 0, 0, } };
static LimitsInfo limits_Q41A[5] =
{ { 0, 68, 2, kThrottleCPU, kNoSpecialState, }, { 1, 68, 2, kThrottleCPU, kNoSpecialState, }, { 2, 68, 2, kThrottleCPU, kNoSpecialState, }, { 3, 50, 5, kThrottleCPU, kNoSpecialState, }, { -1, 0, 0, 0, 0, } };
static LimitsInfo limits_Q79[5] =
{ { 0, 63, 1, kThrottleCPU, kNoSpecialState, }, { 1, 83, 1, kThrottleCPU, kNoSpecialState, }, { 2, 92, 1, kThrottleCPU, kNoSpecialState, }, { 3, 73, 5, kThrottleCPU, kNoSpecialState, }, { -1, 0, 0, 0, 0, } };
static LimitsInfo limits_P99[5] =
{ { 0, 73, 5, kThrottleCPU, kNoSpecialState, }, { 1, 73, 5, kThrottleCPU, kNoSpecialState, }, { 2, 73, 5, kThrottleCPU, kNoSpecialState, }, { 4, 73, 5, kThrottleCPU, kNoSpecialState, }, { -1, 0, 0, 0, 0, } };
static LimitsInfo limits_Q54[5] =
{ { 0, 53, 2, kThrottleCPU, kNoSpecialState, }, { 1, 79, 4, kThrottleCPU, kNoSpecialState, }, { 2, 103, 4, kThrottleCPU, kNoSpecialState, }, { 3, 73, 5, kThrottleCPU, kNoSpecialState, }, { -1, 0, 0, 0, 0, } };
static LimitsInfo limits_P72D[5] =
{ { 0, 63, 1, kThrottleCPU, kNoSpecialState, }, { 1, 83, 1, kThrottleCPU, kNoSpecialState, }, { 2, 92, 1, kThrottleCPU, kNoSpecialState, }, { 3, 73, 5, kThrottleCPU, kNoSpecialState, }, { -1, 0, 0, 0, 0, } };
static LimitsInfo limits_Q16[5] =
{ { 0, 76, 2, kThrottleCPU, kNoSpecialState, }, { 1, 75, 2, kThrottleCPU, kNoSpecialState, }, { 2, 82, 2, kThrottleCPU, kNoSpecialState, }, { 3, 50, 5, kThrottleCPU, kNoSpecialState, }, { -1, 0, 0, 0, 0, } };
static LimitsInfo limits_Q41[5] =
{ { 0, 68, 2, kThrottleCPU, kNoSpecialState, }, { 1, 68, 2, kThrottleCPU, kNoSpecialState, }, { 2, 68, 2, kThrottleCPU, kNoSpecialState, }, { 3, 50, 5, kThrottleCPU, kNoSpecialState, }, { -1, 0, 0, 0, 0, } };
static LimitsInfo limits_P84[4] =
{ { 0, 100, 5, kThrottleCPU, kNoSpecialState, }, { 1, 100, 5, kThrottleCPU, kNoSpecialState, }, { 2, 73, 5, kThrottleCPU, kNoSpecialState, }, { -1, 0, 0, 0, 0, } };
#ifndef sub_iokit_graphics
# define sub_iokit_graphics err_sub(5)
#endif
#ifndef kIOFBLowPowerAggressiveness
# define kIOFBLowPowerAggressiveness iokit_family_err(sub_iokit_graphics,1)
#endif
#define super IOPlatformMonitor
OSDefineMetaClassAndStructors(Portable_PlatformMonitor, IOPlatformMonitor)
bool Portable_PlatformMonitor::start ( IOService * nub )
{
UInt32 i;
IORegistryEntry *cpuEntry, *powerPCEntry;
OSIterator *childIterator;
OSData *cpuSpeedData;
UInt32 newCPUSpeed, newNum;
bool needs2003Fixes;
if (!initSymbols())
return false;
provider = nub;
debug_msg("Portable_PlatformMonitor::start - starting\n");
macRISC2PE = OSDynamicCast(MacRISC2PE, getPlatform());
goingToSleep = false;
machineModel = macRISC2PE->pMonPlatformNumber;
switch (machineModel)
{
case kPB51MachineModel: thermalLimits = limits_P84; break;
case kPB61MachineModel: thermalLimits = limits_P99; break;
case kPB52MachineModel: thermalLimits = limits_Q16; break;
case kPB53MachineModel: thermalLimits = limits_Q41; break;
case kPB62MachineModel: thermalLimits = limits_Q54; break;
case kPB63MachineModel: thermalLimits = limits_P72D; break;
case kPB64MachineModel: thermalLimits = limits_Q54A; break;
case kPB65MachineModel: thermalLimits = limits_Q72; break;
case kPB54MachineModel: thermalLimits = limits_Q16A; break;
case kPB55MachineModel: thermalLimits = limits_Q41A; break;
case kPB66MachineModel: thermalLimits = limits_Q79; break;
case kPB56MachineModel: thermalLimits = limits_Q16A; break; case kPB57MachineModel: thermalLimits = limits_Q41A; break;
default: thermalLimits = NULL;
}
createThermalThresholdArray(thermalLimits);
machineUtilizes65W = (( machineModel == kPB52MachineModel ) || ( machineModel == kPB53MachineModel ) || ( machineModel == kPB54MachineModel ) || ( machineModel == kPB55MachineModel ) || ( machineModel == kPB56MachineModel ) || ( machineModel == kPB57MachineModel ));
machineReducesOnNoBattery = (( machineModel == kPB51MachineModel ) || ( machineModel == kPB52MachineModel ) || ( machineModel == kPB53MachineModel ) || ( machineModel == kPB54MachineModel ) || ( machineModel == kPB55MachineModel ) || ( machineModel == kPB56MachineModel ) || ( machineModel == kPB57MachineModel ) || ( machineModel == kPB61MachineModel ) ||
( machineModel == kPB62MachineModel ) || ( machineModel == kPB64MachineModel ));
needs2003Fixes = (( machineModel == kPB52MachineModel ) || ( machineModel == kPB53MachineModel ) || ( machineModel == kPB62MachineModel ) || ( machineModel == kPB63MachineModel ));
if (needs2003Fixes)
macRISC2PE->processorSpeedChangeFlags |= kBusSlewBasedSpeedChange;
useBusSlewing = ((macRISC2PE->processorSpeedChangeFlags & kBusSlewBasedSpeedChange) != 0);
if (useBusSlewing)
macRISC2PE->processorSpeedChangeFlags &= ~kProcessorBasedSpeedChange;
if (machineModel == kPB51MachineModel) {
initialPowerState = kPowerState0; initialCPUPowerState = kCPUPowerState0;
}
else {
initialPowerState = kPowerState1; initialCPUPowerState = kCPUPowerState1;
}
if (machineModel == kPB61MachineModel)
wakingPowerState = kPowerState1; else
wakingPowerState = kPowerState0;
whichCPUSpeedController = ( useBusSlewing ? kSlewController : kCPUController );
initPlatformState ();
commandGateCaller = &iopmonCommandGateCaller;
cpuEntry = fromPath("/cpus", gIODTPlane);
if (cpuEntry != 0) {
if ((childIterator = cpuEntry->getChildIterator (gIODTPlane)) != NULL) {
while ((powerPCEntry = (IORegistryEntry *)(childIterator->getNextObject ())) != NULL) {
if (!strncmp ("PowerPC", powerPCEntry->getName(gIODTPlane), strlen ("PowerPC"))) {
cpuSpeedData = OSDynamicCast( OSData, powerPCEntry->getProperty( "max-clock-frequency" ));
if (cpuSpeedData) {
newCPUSpeed = *(UInt32 *) cpuSpeedData->getBytesNoCopy();
if (newCPUSpeed != gPEClockFrequencyInfo.cpu_clock_rate_hz)
{
newNum = newCPUSpeed / (gPEClockFrequencyInfo.cpu_clock_rate_hz /
gPEClockFrequencyInfo.bus_to_cpu_rate_num);
gPEClockFrequencyInfo.bus_to_cpu_rate_num = newNum; gPEClockFrequencyInfo.cpu_clock_rate_hz = newCPUSpeed; }
}
break;
}
}
}
}
conSensorArray[kPowerSensor].conSensorType = kIOPMonPowerSensor; conSensorArray[kPowerSensor].conSensor = this; conSensorArray[kPowerSensor].numStates = kMaxPowerStates;
conSensorArray[kPowerSensor].sensorValid = true;
conSensorArray[kPowerSensor].registered = true;
conSensorArray[kThermalSensor].conSensorType = kIOPMonThermalSensor; conSensorArray[kThermalSensor].conSensor = this;
conSensorArray[kThermalSensor].numStates = kMaxThermalStates;
conSensorArray[kThermalSensor].sensorValid = true;
conSensorArray[kThermalSensor].registered = true;
conSensorArray[kClamshellSensor].conSensorType = kIOPMonClamshellSensor; conSensorArray[kClamshellSensor].numStates = kNumClamshellStates;
conSensorArray[kClamshellSensor].sensorValid = true;
conSensorArray[kClamshellSensor].registered = false;
conSensorArray[kCPUController].conSensorType = kIOPMonCPUController; conSensorArray[kCPUController].registered = false;
conSensorArray[kGPUController].conSensorType = kIOPMonGPUController; conSensorArray[kGPUController].state = kGPUPowerState0;
conSensorArray[kGPUController].registered = true;
conSensorArray[kSlewController].conSensorType = kIOPMonSlewController; conSensorArray[kSlewController].registered = false;
for (i = 0; i < kMaxSensorIndex; i++) {
subSensorArray[i].conSensorType = kIOPMonThermalSensor;
subSensorArray[i].conSensorParent = kThermalSensor; subSensorArray[i].numStates = kMaxThermalStates;
subSensorArray[i].sensorValid = true;
subSensorArray[i].registered = false;
}
if (!(dictPowerLow = OSDictionary::withCapacity (3))) return false;
if (!(dictPowerHigh = OSDictionary::withCapacity (3))) return false;
if (!(dictClamshellOpen = OSDictionary::withCapacity (2))) return false;
if (!(dictClamshellClosed = OSDictionary::withCapacity (2))) return false;
dictPowerLow->setObject (gIOPMonCPUIDKey, OSNumber::withNumber ((unsigned long long)0, 32));
dictPowerLow->setObject (gIOPMonCurrentValueKey, OSNumber::withNumber ((unsigned long long)kPowerState1, 32));
dictPowerLow->setObject (gIOPMonTypeKey, gIOPMonTypePowerSens);
dictPowerHigh->setObject (gIOPMonCPUIDKey, OSNumber::withNumber ((unsigned long long)0, 32));
dictPowerHigh->setObject (gIOPMonCurrentValueKey, OSNumber::withNumber ((unsigned long long)kPowerState0, 32));
dictPowerHigh->setObject (gIOPMonTypeKey, gIOPMonTypePowerSens);
dictClamshellOpen->setObject (gIOPMonCurrentValueKey, OSNumber::withNumber ((unsigned long long)kClamshellStateOpen, 32));
dictClamshellOpen->setObject (gIOPMonTypeKey, gIOPMonTypeClamshellSens);
dictClamshellClosed->setObject (gIOPMonCurrentValueKey, OSNumber::withNumber ((unsigned long long)kClamshellStateClosed, 32));
dictClamshellClosed->setObject (gIOPMonTypeKey, gIOPMonTypeClamshellSens);
if (!gIOPMonPowerStateKey) gIOPMonPowerStateKey = OSSymbol::withCString (kIOPMonPowerStateKey);
if (!gIOPMonClamshellStateKey) gIOPMonClamshellStateKey = OSSymbol::withCString (kIOPMonClamshellStateKey);
if (!gIOPMonCPUActionKey) gIOPMonCPUActionKey = OSSymbol::withCString (kIOPMonCPUActionKey);
if (!gIOPMonGPUActionKey) gIOPMonGPUActionKey = OSSymbol::withCString (kIOPMonGPUActionKey);
if (!gIOPMonState0) gIOPMonState0 = OSSymbol::withCString (kIOPMonState0);
if (!gIOPMonState1) gIOPMonState1 = OSSymbol::withCString (kIOPMonState1);
if (!gIOPMonState2) gIOPMonState2 = OSSymbol::withCString (kIOPMonState2);
if (!gIOPMonState3) gIOPMonState3 = OSSymbol::withCString (kIOPMonState3);
if (!gIOClamshellStateOpen) gIOClamshellStateOpen = OSSymbol::withCString (kIOClamshellStateOpen);
if (!gIOClamshellStateClosed) gIOClamshellStateClosed = OSSymbol::withCString (kIOClamshellStateClosed);
if (!gIOPMonFull) gIOPMonFull = OSSymbol::withCString (kIOPMonFull);
if (!gIOPMonReduced) gIOPMonReduced = OSSymbol::withCString (kIOPMonReduced);
if (!gIOPMonSlow) gIOPMonSlow = OSSymbol::withCString (kIOPMonSlow);
lastPowerState = kMaxPowerStates;
lastClamshellState = kNumClamshellStates;
setSpeedLock = IORecursiveLockAlloc();
updateIOPMonStateInfo(kIOPMonPowerSensor, currentPowerState);
updateIOPMonStateInfo(kIOPMonClamshellSensor, currentClamshellState);
provider->setProperty (gIOPMonCPUActionKey, (OSObject *)gIOPMonReduced);
provider->setProperty (gIOPMonGPUActionKey, (OSObject *)gIOPMonFull);
publishResource ("IOPlatformMonitor", this);
if (super::start (nub))
{
conSensorArray[kGPUController].conSensor = pmRootDomain;
gIOPMon = this;
return true;
}
else
return false;
}
void Portable_PlatformMonitor::createThermalThresholdArray(LimitsInfo *curThermalLimits)
{
LimitsInfo *workLimits;
UInt32 whichClamshell;
ThresholdInfo *workThreshold;
workLimits = curThermalLimits;
while ( workLimits->sensorID >= 0 )
{
whichClamshell = ((( workLimits->machineState && kClamshellClosedState ) != 0 ) ? 1 : 0 );
workThreshold = &thermalThresholdInfoArray[workLimits->sensorID][whichClamshell][0];
workThreshold->thresholdLow = TEMP_SENSOR_FMT(0);
workThreshold->thresholdHigh = TEMP_SENSOR_FMT(workLimits->sensorThreshold);
workThreshold->thresholdAction = 0;
workThreshold++;
workThreshold->thresholdLow = TEMP_SENSOR_FMT(workLimits->sensorThreshold - workLimits->sensorHysteresis);
workThreshold->thresholdHigh = TEMP_SENSOR_FMT(127);
workThreshold->thresholdAction = workLimits->sensorEffect;
if ( whichClamshell == 0 )
{
workThreshold = &thermalThresholdInfoArray[workLimits->sensorID][1][0];
workThreshold->thresholdLow = TEMP_SENSOR_FMT(0);
workThreshold->thresholdHigh = TEMP_SENSOR_FMT(workLimits->sensorThreshold);
workThreshold->thresholdAction = 0;
workThreshold++;
workThreshold->thresholdLow = TEMP_SENSOR_FMT(workLimits->sensorThreshold - workLimits->sensorHysteresis);
workThreshold->thresholdHigh = TEMP_SENSOR_FMT(127);
workThreshold->thresholdAction = workLimits->sensorEffect;
}
workLimits++;
}
}
IOReturn Portable_PlatformMonitor::powerStateWillChangeTo (IOPMPowerFlags theFlags, unsigned long, IOService*)
{
if ( ! (theFlags & IOPMPowerOn) ) {
IORecursiveLockLock(setSpeedLock);
setCPUSpeed(true); goingToSleep = true;
IORecursiveLockUnlock(setSpeedLock);
}
return IOPMAckImplied;
}
IOReturn Portable_PlatformMonitor::powerStateDidChangeTo (IOPMPowerFlags theFlags, unsigned long, IOService*)
{
if (theFlags & IOPMPowerOn) {
goingToSleep = false;
debug_msg ("Portable_PlatformMonitor::powerStateDidChangeTo - wake\n");
conSensorArray[whichCPUSpeedController].state = wakingPowerState;
restorePlatformState();
}
return IOPMAckImplied;
}
IOReturn Portable_PlatformMonitor::setAggressiveness(unsigned long selector, unsigned long newLevel)
{
IOPMonEventData event;
IOReturn result;
if (goingToSleep)
return kIOReturnError;
result = super::setAggressiveness(selector, newLevel);
if (selector == kPMSetProcessorSpeed)
{
if ((newLevel != currentPowerState) && (newLevel < 2)) {
event.event = kIOPMonMessageStateChanged; event.conSensor = this;
event.eventDict = (newLevel == 0) ? dictPowerHigh : dictPowerLow;
handleEvent (&event); }
}
return result;
}
bool Portable_PlatformMonitor::setCPUSpeed( bool setPowerHigh )
{
IOService *serv;
UInt32 newSpeed;
UInt32 goSlowOffset = 0;
OSObject *newProperty;
IORecursiveLockLock(setSpeedLock);
if (goingToSleep)
{
IORecursiveLockUnlock(setSpeedLock); return false; }
if ( setPowerHigh )
{
newSpeed = kCPUPowerState0;
newProperty = (OSObject *)gIOPMonFull;
}
else
{
newSpeed = kCPUPowerState1;
goSlowOffset = 1;
newProperty = (OSObject *)gIOPMonReduced;
}
if (!conSensorArray[whichCPUSpeedController].registered)
{
IORecursiveLockUnlock(setSpeedLock); return false;
}
if ((conSensorArray[whichCPUSpeedController].state != newSpeed) && (serv = conSensorArray[whichCPUSpeedController].conSensor))
{
if ( whichCPUSpeedController == kSlewController )
slewBusSpeed ((UInt32) 0 + goSlowOffset); else
serv->setAggressiveness (kPMSetProcessorSpeed, 2 + goSlowOffset);
conSensorArray[whichCPUSpeedController].state = newSpeed;
provider->setProperty (gIOPMonCPUActionKey, newProperty);
}
IORecursiveLockUnlock(setSpeedLock);
return true;
}
void Portable_PlatformMonitor::slewBusSpeed (UInt32 newLevel)
{
OSDictionary *dict;
const OSObject *target_value[1];
const OSSymbol *key[1];
key[0] = OSSymbol::withCString(kIOPMonSlewActionKey);
if (conSensorArray[kSlewController].registered == true)
{
if (newLevel == 0)
{ target_value[0] = OSNumber::withNumber((unsigned long long) 0, 32);
dict = OSDictionary::withObjects(target_value, key, (unsigned int) 1, (unsigned int) 0);
}
else
{
target_value[0] = OSNumber::withNumber((unsigned long long) 1, 32);
dict = OSDictionary::withObjects(target_value, key, 1, 0);
}
conSensorArray[kSlewController].conSensor->setProperties(dict);
}
key[0]->release();
target_value[0]->release();
dict->release();
}
bool Portable_PlatformMonitor::setGPUSpeed( UInt32 newGPUSpeed )
{
IOService *serv;
OSObject *newProperty;
UInt32 newAggressiveness;
return true;
switch (newGPUSpeed)
{
case kGPUPowerState0: newProperty = (OSObject *)gIOPMonFull; newAggressiveness = 0; break;
case kGPUPowerState1: newProperty = (OSObject *)gIOPMonReduced; newAggressiveness = 1; break;
case kGPUPowerState2: newProperty = (OSObject *)gIOPMonSlow; newAggressiveness = 2; break;
default: return false; }
if (!conSensorArray[kGPUController].registered) return false;
if ((conSensorArray[kGPUController].state != newGPUSpeed) && (serv = conSensorArray[kGPUController].conSensor))
{
conSensorArray[kGPUController].state = newGPUSpeed;
serv->setAggressiveness (kIOFBLowPowerAggressiveness, newAggressiveness);
provider->setProperty (gIOPMonGPUActionKey, (OSObject *)newProperty);
}
return true;
}
void Portable_PlatformMonitor::applyPowerSettings(UInt32 actionToTake)
{
bool cpuFullSpeed;
bool gpuFullSpeed;
if (currentPowerState == kPowerState0)
cpuFullSpeed = ((actionToTake && kThrottleCPU) == 0);
else
cpuFullSpeed = false;
setCPUSpeed(cpuFullSpeed);
gpuFullSpeed = ((actionToTake && kThrottleCPU) == 0);
setGPUSpeed(gpuFullSpeed);
}
void Portable_PlatformMonitor::setSensorThermalThresholds(UInt32 sensorID, ThermalValue lowTemp, ThermalValue highTemp)
{
OSNumber *threshLow, *threshHigh;
threshLow = (OSNumber *)subSensorArray[sensorID].threshDict->getObject (gIOPMonLowThresholdKey);
threshLow->setValue((long long)lowTemp);
threshHigh = (OSNumber *)subSensorArray[sensorID].threshDict->getObject (gIOPMonHighThresholdKey);
threshHigh->setValue((long long)highTemp);
subSensorArray[sensorID].conSensor->setProperties (subSensorArray[sensorID].threshDict);
}
void Portable_PlatformMonitor::resetThermalSensorThresholds(void)
{
UInt32 subsi;
OSNumber *num;
ConSensorInfo *csInfo;
UInt32 value;
UInt32 myThermalState;
for (subsi = 0; subsi < kMaxSensorIndex; subsi++)
{
csInfo = &subSensorArray[subsi];
if (csInfo->registered)
{
if (num = OSDynamicCast (OSNumber, csInfo->dict->getObject(gIOPMonCurrentValueKey)))
{
value = num->unsigned32BitValue();
csInfo->state = kThermalState0;
myThermalState = lookupThermalStateFromValue (subsi, value);
subSensorArray[subsi].state = myThermalState;
setSensorThermalThresholds(subsi, thermalThresholdInfoArray[subsi][currentClamshellState][myThermalState].thresholdLow,
thermalThresholdInfoArray[subsi][currentClamshellState][myThermalState].thresholdHigh);
}
}
}
}
IOReturn Portable_PlatformMonitor::monitorPower (OSDictionary *dict, IOService *provider)
{
UInt32 type, index, subIndex, value;
OSNumber *num;
IOPMonEventData event;
bool clamshellChanged;
UInt32 adapterWatts;
bool mayNeedToRunSlow = false;
if (lookupConSensorInfo (dict, provider, &type, &index, &subIndex))
{
if (num = OSDynamicCast (OSNumber, dict->getObject(gIOPMonCurrentValueKey)))
{
value = num->unsigned32BitValue();
value &= ~kIOPMForceLowSpeed;
if ( machineReducesOnNoBattery )
{
if ( machineUtilizes65W )
{
adapterWatts = (value & 0xFF000000) >> 24;
if ( adapterWatts == 0 )
mayNeedToRunSlow = !((value & (kIOPMACInstalled | kIOPMACnoChargeCapability)) == (kIOPMACInstalled | kIOPMACnoChargeCapability));
else
if ( adapterWatts < 0x41 ) mayNeedToRunSlow = true;
}
else
mayNeedToRunSlow = true;
if (mayNeedToRunSlow)
{
if ((value & (kIOPMACInstalled | kIOPMACnoChargeCapability)) == (kIOPMACInstalled | kIOPMACnoChargeCapability))
value |= kIOPMForceLowSpeed;
else if ((value & (kIOPMRawLowBattery | kIOPMBatteryDepleted)) != 0)
value |= kIOPMForceLowSpeed;
else if ((value & kIOPMBatteryInstalled) == 0)
value |= kIOPMForceLowSpeed;
}
}
num->setValue((long long)value);
if ((value & kIOPMClosedClamshell) != 0)
clamshellChanged = (currentClamshellState == kClamshellStateOpen);
else
clamshellChanged = (currentClamshellState != kClamshellStateOpen);
if (clamshellChanged)
{
event.event = kIOPMonMessageStateChanged;
event.conSensor = this;
event.eventDict = (currentClamshellState == kClamshellStateOpen) ? dictClamshellClosed : dictClamshellOpen;
handleEvent (&event);
return kIOReturnSuccess;
}
}
}
return kIOReturnBadArgument;
}
void Portable_PlatformMonitor::updateIOPMonStateInfo (UInt32 type, UInt32 state)
{
const OSSymbol *stateKey, *stateValue;
stateKey = stateValue = NULL;
if (type == kIOPMonPowerSensor)
{
stateKey = gIOPMonPowerStateKey;
switch (state)
{
case kThermalState0: stateValue = gIOPMonState0; break;
case kThermalState1: stateValue = gIOPMonState1; break;
}
}
else if (type == kIOPMonClamshellSensor)
{
stateKey = gIOPMonClamshellStateKey;
if (state == kClamshellStateOpen)
stateValue = gIOClamshellStateOpen;
else if (state == kClamshellStateClosed)
stateValue = gIOClamshellStateClosed;
}
if (stateKey && stateValue)
provider->setProperty (stateKey, (OSObject *)stateValue);
return;
}
bool Portable_PlatformMonitor::initPlatformState ()
{
currentPowerState = initialPowerState; currentClamshellState = kClamshellStateOpen;
return true;
}
void Portable_PlatformMonitor::savePlatformState ()
{
return;
}
void Portable_PlatformMonitor::restorePlatformState ()
{
lastPowerState = kMaxPowerStates;
lastClamshellState = kNumClamshellStates;
resetThermalSensorThresholds();
adjustPlatformState();
}
bool Portable_PlatformMonitor::adjustPlatformState ()
{
bool result = true;
bool reevaluateThermalLevels = false;
UInt32 actionToTake = 0;
UInt32 subSensor;
if (lastPowerState != currentPowerState)
{
lastPowerState = currentPowerState;
updateIOPMonStateInfo(kIOPMonPowerSensor, currentPowerState);
}
if (lastClamshellState != currentClamshellState)
{
lastClamshellState = currentClamshellState;
updateIOPMonStateInfo(kIOPMonClamshellSensor, currentClamshellState);
reevaluateThermalLevels = true;
}
if ( reevaluateThermalLevels )
resetThermalSensorThresholds();
for (subSensor = 0; subSensor < kMaxSensorIndex; subSensor++)
if (subSensorArray[subSensor].registered)
actionToTake |= thermalThresholdInfoArray[subSensor][currentClamshellState][subSensorArray[subSensor].state].thresholdAction;
applyPowerSettings(actionToTake);
return result;
}
IOReturn Portable_PlatformMonitor::registerConSensor (OSDictionary *dict, IOService *conSensor)
{
UInt32 csi, subsi, type, initialState, initialValue;
ConSensorInfo *csInfo;
OSObject *obj;
if (!lookupConSensorInfo (dict, conSensor, &type, &csi, &subsi))
return kIOReturnBadArgument;
if (subsi < kMaxSensorIndex) csInfo = &subSensorArray[subsi];
else
csInfo = &conSensorArray[csi];
csInfo->conSensor = conSensor;
csInfo->dict = dict;
dict->retain ();
initialState = initialValue = 0;
switch (csInfo->conSensorType)
{
case kIOPMonThermalSensor:
if (!csInfo->sensorValid)
return kIOReturnUnsupported;
if (!(csInfo->threshDict = OSDictionary::withCapacity(3)))
return kIOReturnNoMemory;
csInfo->threshDict->setObject (gIOPMonIDKey, OSNumber::withNumber (subsi, 32));
csInfo->threshDict->setObject (gIOPMonLowThresholdKey,
OSNumber::withNumber (thermalThresholdInfoArray[subsi][currentClamshellState][initialState].thresholdLow, 32));
csInfo->threshDict->setObject (gIOPMonHighThresholdKey,
OSNumber::withNumber (thermalThresholdInfoArray[subsi][currentClamshellState][initialState].thresholdHigh, 32));
conSensor->setProperties (csInfo->threshDict);
csInfo->registered = true;
break;
case kIOPMonPowerSensor:
initialState = initialPowerState; break;
case kIOPMonClamshellSensor:
if (!retrieveCurrentValue (dict, &initialValue))
return kIOReturnBadArgument;
csInfo->registered = true;
break;
case kIOPMonCPUController:
initialState = initialCPUPowerState; csInfo->registered = true;
break;
case kIOPMonGPUController:
initialState = kGPUPowerState0; break;
case kIOPMonSlewController:
obj = csInfo->dict->getObject ("current-value");
initialValue = (OSDynamicCast (OSNumber, obj))->unsigned32BitValue();
initialState = initialValue;
csInfo->registered = true;
break;
default:
break;
}
csInfo->value = initialValue;
csInfo->state = initialState;
return kIOReturnSuccess;
}
bool Portable_PlatformMonitor::unregisterSensor (UInt32 sensorID)
{
if (sensorID >= kMaxSensors)
return false;
conSensorArray[sensorID].conSensor = NULL;
return true;
}
bool Portable_PlatformMonitor::lookupConSensorInfo (OSDictionary *dict, IOService *conSensor,
UInt32 *type, UInt32 *index, UInt32 *subIndex)
{
OSSymbol *typeString;
UInt32 tempType;
OSObject *obj, *obj2;
*index = kMaxConSensors; *subIndex = kMaxSensorIndex;
*type = tempType = kIOPMonUnknownSensor; obj = dict->getObject (gIOPMonTypeKey);
obj2 = dict->getObject (gIOPMonConTypeKey);
if ((obj && (typeString = OSDynamicCast (OSSymbol, obj))) || (obj2 && (typeString = OSDynamicCast (OSSymbol, obj2))))
{
if (typeString->isEqualTo (gIOPMonTypePowerSens))
tempType = kIOPMonPowerSensor;
else if (typeString->isEqualTo (gIOPMonTypeThermalSens))
tempType = kIOPMonThermalSensor;
else if (typeString->isEqualTo (gIOPMonTypeClamshellSens))
tempType = kIOPMonClamshellSensor;
else if (typeString->isEqualTo (gIOPMonTypeCPUCon))
tempType = kIOPMonCPUController;
else if (typeString->isEqualTo (gIOPMonTypeGPUCon))
tempType = kIOPMonGPUController;
else if (typeString->isEqualTo (gIOPMonTypeSlewCon))
tempType = kIOPMonSlewController;
else if (typeString->isEqualTo (gIOPMonTypeFanCon))
tempType = kIOPMonFanController;
}
if (retrieveSensorIndex (dict, subIndex))
{
if (*subIndex >= kMaxSensorIndex)
return false;
*type = (tempType == kIOPMonUnknownSensor) ? subSensorArray[*subIndex].conSensorType : tempType;
return true;
}
for (*index = 0; *index < kMaxConSensors; (*index)++)
{
if (conSensorArray[*index].conSensorType == tempType)
{
*type = tempType;
break;
}
}
return (*index < kMaxConSensors);
}
UInt32 Portable_PlatformMonitor::lookupThermalStateFromValue (UInt32 sensorIndex, ThermalValue value)
{
UInt32 i;
UInt32 curSensorState;
curSensorState = subSensorArray[sensorIndex].state;
if (curSensorState != kMaxThermalStates)
{
if (value > thermalThresholdInfoArray[sensorIndex][currentClamshellState][curSensorState].thresholdLow &&
value < thermalThresholdInfoArray[sensorIndex][currentClamshellState][curSensorState].thresholdHigh)
return curSensorState;
}
if (value > thermalThresholdInfoArray[sensorIndex][currentClamshellState][0].thresholdLow)
{
for (i = 0 ; i < subSensorArray[sensorIndex].numStates; i++)
if (value > thermalThresholdInfoArray[sensorIndex][currentClamshellState][i].thresholdLow &&
value < thermalThresholdInfoArray[sensorIndex][currentClamshellState][i].thresholdHigh)
return i;
return kMaxThermalStates;
}
return kThermalState0;
}
bool Portable_PlatformMonitor::handlePowerEvent (IOPMonEventData *eventData)
{
UInt32 nextPowerState;
bool result;
debug_msg ("Portable_PlatformMonitor::handlePowerEvent - START\n");
if (!(retrieveCurrentValue (eventData->eventDict, &nextPowerState)))
return false;
result = true;
if (currentPowerState != nextPowerState)
{
currentPowerState = nextPowerState;
result = adjustPlatformState ();
}
return result;
}
bool Portable_PlatformMonitor::handleThermalEvent (IOPMonEventData *eventData)
{
UInt32 type, csi, subsi, myThermalState;
ThermalValue value;
bool result = true;
debug_msg ("Portable_PlatformMonitor::handleThermalEvent - START\n");
if (!(retrieveCurrentValue (eventData->eventDict, &value)))
return false;
switch (eventData->event)
{
case kIOPMonMessageLowThresholdHit:
case kIOPMonMessageHighThresholdHit:
if (lookupConSensorInfo (eventData->eventDict, eventData->conSensor, &type, &csi, &subsi) && subSensorArray[subsi].registered)
{
myThermalState = lookupThermalStateFromValue (subsi, value);
if (myThermalState >= kMaxThermalStates)
result = false;
}
else
result = false;
break;
default:
result = false;
break;
}
if (result)
{
if (myThermalState != subSensorArray[subsi].state)
{
subSensorArray[subsi].state = myThermalState;
if (!subSensorArray[subsi].registered)
return false;
setSensorThermalThresholds(subsi, thermalThresholdInfoArray[subsi][currentClamshellState][myThermalState].thresholdLow,
thermalThresholdInfoArray[subsi][currentClamshellState][myThermalState].thresholdHigh);
}
result = adjustPlatformState ();
}
return result;
}
bool Portable_PlatformMonitor::handleClamshellEvent (IOPMonEventData *eventData)
{
UInt32 nextClamshellState;
bool result = true;
if (!(retrieveCurrentValue (eventData->eventDict, &nextClamshellState))) return false;
if (currentClamshellState != nextClamshellState)
{
currentClamshellState = nextClamshellState;
result = adjustPlatformState ();
}
return result;
}
IOReturn Portable_PlatformMonitor::iopmonCommandGateCaller(OSObject *object, void *arg0, void *arg1, void *arg2, void *arg3)
{
Portable_PlatformMonitor *me;
IOPMonCommandThreadSet *commandSet;
UInt32 type, conSensorID, subSensorID;
bool result;
if (((commandSet = (IOPMonCommandThreadSet *)arg0) == NULL) ||
((me = OSDynamicCast(Portable_PlatformMonitor, commandSet->me)) == NULL))
return kIOReturnError;
result = true;
switch (commandSet->command) {
case kIOPMonCommandHandleEvent:
if (!(commandSet->eventData.eventDict))
{
IOLog ("Portable_PlatformMonitor::iopmonCommandGateCaller - bad dictionary\n");
return kIOReturnBadArgument;
}
if (!(commandSet->eventData.conSensor))
{
IOLog ("Portable_PlatformMonitor::iopmonCommandGateCaller - bad conSensor\n");
return kIOReturnBadArgument;
}
if (!me->lookupConSensorInfo (commandSet->eventData.eventDict, commandSet->eventData.conSensor, &type, &conSensorID, &subSensorID))
{
IOLog ("Portable_PlatformMonitor::iopmonCommandGateCaller - bad sensor info lookup\n");
return kIOReturnBadArgument;
}
switch (type) {
case kIOPMonPowerSensor: result = me->handlePowerEvent (&commandSet->eventData);
break;
case kIOPMonThermalSensor: result = me->handleThermalEvent (&commandSet->eventData);
break;
case kIOPMonClamshellSensor: result = me->handleClamshellEvent (&commandSet->eventData);
break;
default:
IOLog ("Portable_PlatformMonitor::iopmonCommandGateCaller - bad sensorType(%ld), sensorID(%ld), subsi(%ld)\n",
type, conSensorID, subSensorID);
result = false;
break;
}
break;
case kIOPMonCommandSaveState:
me->savePlatformState ();
break;
case kIOPMonCommandRestoreState:
me->restorePlatformState ();
break;
default:
IOLog ("Portable_PlatformMonitor::iopmonCommandGateCaller - bad command %ld\n", commandSet->command);
result = false;
break;
}
return result ? kIOReturnSuccess : kIOReturnError;
}