#include "AppleThermal.h"
#define super IOService
OSDefineMetaClassAndStructors( AppleThermal, IOService )
bool
AppleThermal::findAndAttachI2C(IOService *provider)
{
const OSSymbol *i2cDriverName;
IOService *i2cCandidate;
i2cDriverName = OSSymbol::withCStringNoCopy("PPCI2CInterface.i2c-uni-n");
i2cCandidate = waitForService(resourceMatching(i2cDriverName));
interface = (PPCI2CInterface*)i2cCandidate->getProperty(i2cDriverName);
if (interface == NULL) {
#ifdef DEBUGMODE
IOLog("AppleThermal::findAndAttachI2C can't find the i2c in the registry\n");
#endif // DEBUGMODE
return false;
}
interface->retain();
return true;
}
bool
AppleThermal::detachFromI2C(IOService* )
{
if (interface) {
interface->release();
interface = 0;
}
return (true);
}
bool
AppleThermal::openI2C(UInt8 id)
{
if (interface != NULL) {
interface->openI2CBus(id);
interface->setStandardMode();
interface->setPollingMode(true);
return true;
}
return false;
}
void
AppleThermal::closeI2C()
{
if (interface != NULL)
interface->closeI2CBus();
}
bool
AppleThermal::writeI2C(SInt8 *data, UInt32 size)
{
bool success = false;
if (interface != NULL) {
success = interface->writeI2CBus((UInt8)kThermostatAddress, 0, (UInt8*)data, size);
#ifdef DEBUGMODE
if (!success)
IOLog("AppleThermal::writeI2C fails on %d of %d %d\n", size, data[0], data[1]);
#endif //DEBUGMODE
}
return success;
}
bool
AppleThermal::readI2C(SInt8 *data, UInt32 size)
{
bool success = false;
if (interface != NULL) {
success = interface->readI2CBus((UInt8)kThermostatAddress, 0, (UInt8*)data, size);
#ifdef DEBUGMODE
if (!success)
IOLog("AppleThermal::readI2C fails on %d of %d %d\n", size, data[0], data[1]);
#endif //DEBUGMODE
}
return success;
}
bool
AppleThermal::dataIsValid()
{
IOService *topProvider = NULL, *provider = getProvider();
while (provider != NULL) {
topProvider = provider;
provider = provider->getProvider();
#ifdef BEPARANOID
IOLog("AppleThermal::dataIsValid looking at %s\n", topProvider->getName());
#endif
}
if (topProvider != NULL) {
if (IODTMatchNubWithKeys(topProvider, "'PowerBook3,1'")) {
if ((thermalDesign == kThermalDesign_Pismo) ||
(thermalDesign == kThermalDesign_2000))
return true;
else {
#ifdef DEBUGMODE
IOLog("AppleThermal::dataIsValid machine type is supported but the data is not maching\n");
#endif //DEBUGMODE
}
}
else {
#ifdef DEBUGMODE
IOLog("AppleThermal::dataIsValid unsupported machine type\n");
#endif //DEBUGMODE
}
}
else {
#ifdef DEBUGMODE
IOLog("AppleThermal::dataIsValid can't read the machine name at the top of the tree\n");
#endif //DEBUGMODE
}
return false;
}
bool
AppleThermal::setThermostat(UInt32 id, SInt8 on, SInt8 off)
{
bool success = false;
if (openI2C(id)) {
SInt8 dataOn[3] = {3, on, 0}; SInt8 dataOff[3] = {2, off, 0}; SInt8 dataClr[2] = {1, 0};
success = writeI2C((SInt8*)&dataOn, sizeof(dataOn)); success &= writeI2C((SInt8*)&dataOff, sizeof(dataOff)); success &= writeI2C((SInt8*)&dataClr, sizeof(dataClr)); closeI2C();
}
return (success);
}
bool
AppleThermal::getThermostat(UInt32 id, SInt8 *on, SInt8 *off)
{
bool success = false;
if (openI2C(id)) {
SInt8 tmp, data[2]={0,0};
tmp = 3; success = writeI2C((SInt8*)&tmp, 1); success &= readI2C((SInt8*)&data, 2);
#ifdef BEPARANOID
IOLog("AppleThermal::getThermostat reads for ON %d %d\n", data[0], data[1]);
#endif
if ((on != NULL) && (success))
*on = data[0];
tmp = 2; success &= writeI2C((SInt8*)&tmp, 1); success &= readI2C((SInt8*)&data, 2);
#ifdef BEPARANOID
IOLog("AppleThermal::getThermostat reads for OFF %d %d\n", data[0], data[1]);
#endif
if ((off != NULL) && (success))
*off = data[0];
closeI2C();
}
return success;
}
bool
AppleThermal::retriveThermalProperty(IOService *provider)
{
OSData *t;
ThermalInfoPtr thisThermalInfo;
int i;
t = OSDynamicCast(OSData, provider->getProperty("thermal-info"));
if (t == NULL) {
#ifdef DEBUGMODE
IOLog( "AppleThermal::retriveThermalProperty missing property thermal-info in the registry.\n");
IOLog( " assuming that this hardware does not support it.\n");
#endif
return false;
}
thisThermalInfo = (ThermalInfoPtr)t->getBytesNoCopy();
if (thisThermalInfo == NULL) {
#ifdef DEBUGMODE
IOLog( "AppleThermal::retriveThermalProperty property thermal-info is present but empty.\n");
#endif
return false;
}
thermalDesign = thisThermalInfo->thermalDesign; numberFans = thisThermalInfo->numberFans; numberThermostats = thisThermalInfo->numberThermostats;
#ifdef BEPARANOID
IOLog( "AppleThermal::retriveThermalProperty number of fans: %d number of thermostats %d.\n", numberFans, numberThermostats);
#endif //BEPARANOID
tempRanges = (TempRangesPtr)IOMalloc(sizeof(TempRanges) * numberThermostats);
if (tempRanges == NULL) {
#ifdef DEBUGMODE
IOLog( "AppleThermal::retriveThermalProperty there is not memory to allocate the TempRanges.\n");
#endif
return false;
}
for (i = 0 ; i < numberThermostats; i++) {
#ifdef DOTEST
tempRanges[i].on = 10;
tempRanges[i].off = 0;
#else
tempRanges[i].on = thisThermalInfo->onOffTemperatures[i] >> 8;
tempRanges[i].off = thisThermalInfo->onOffTemperatures[i] & 0xFF;
#endif
#ifdef BEPARANOID
IOLog( "AppleThermal::retriveThermalProperty termostat %d on at %d off at %d.\n", i, tempRanges[i].on, tempRanges[i].off);
#endif //BEPARANOID
}
return true;
}
bool
AppleThermal::setSleepMode()
{
bool success = true;
int i;
for (i = 0 ; i < numberThermostats; i++) {
if (openI2C(i)) {
SInt8 dataSD[2] = {1, 0x01};
success = writeI2C((SInt8*)dataSD, sizeof(dataSD)); closeI2C();
if (!success) {
#ifdef DEBUGMODE
IOLog("AppleThermal::setSleepMode setThermostat(%d) in sleep fails !!\n", i);
#endif }
}
}
return success;
}
bool
AppleThermal::setThermostats()
{
int i;
for (i = 0 ; i < numberThermostats; i++) {
if (!setThermostat(i, tempRanges[i].on, tempRanges[i].off)) {
#ifdef DEBUGMODE
IOLog("AppleThermal::setThermostats setThermostat(%d, %d, %d) fails !!\n", i, tempRanges[i].on, tempRanges[i].off);
#endif // DEBUGMODE
return (false);
}
#ifdef BEPARANOID
SInt8 localON, localOFF;
getThermostat(i, &localON, &localOFF);
IOLog( "AppleThermal::setThermostats termostat %d set on at %d off at %d.\n", i, tempRanges[i].on, tempRanges[i].off);
IOLog( "AppleThermal::setThermostats termostat %d read on at %d off at %d.\n", i, localON, localOFF);
#endif //BEPARANOID
}
return true;
}
void
AppleThermal::free()
{
detachFromI2C(getProvider());
if (tempRanges) {
IOFree(tempRanges, sizeof(TempRanges) * numberThermostats);
tempRanges = NULL;
}
super::free();
}
bool
AppleThermal::start(IOService *provider)
{
if (!super::start(provider))
return false;
tempRanges = NULL;
if (!retriveThermalProperty(provider)) {
return false;
}
if (!dataIsValid())
return false;
if (!findAndAttachI2C(provider)) {
#ifdef DEBUGMODE
IOLog("AppleThermal::start if (!findAndAttachI2C(IOService *provider)) fails !!\n");
#endif // DEBUGMODE
return (false);
}
#if 0
openI2C(0);
int i;
for (i = 0; i <255 ; i++) {
SInt8 dataSD[2] = {1, 0x01};
if (interface->writeI2CBus((UInt8)i, 0, (UInt8*)dataSD, sizeof(dataSD)))
IOLog("AppleThermal::start interface->writeI2CBus(0x%02x, 0) succeeded!!\n",(UInt8)i);
}
closeI2C();
#endif
if (!setThermostats()) {
#ifdef DEBUGMODE
IOLog("AppleThermal::start setThermostats fails !!\n");
#endif // DEBUGMODE
return (false);
}
#ifdef SUPPORTS_POWER_MANAGER
PMinit(); provider->joinPMtree(this);
#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}
};
if (pm_vars != NULL)
registerPowerDriver(this, ourPowerStates, number_of_power_states);
wakingUpFromSleep = false;
return true;
#else // ! SUPPORTS_POWER_MANAGER
return false;
#endif SUPPORTS_POWER_MANAGER
}
UInt32
AppleThermal::readThermostatTemperature (UInt8 inID)
{
bool success = true;
SInt8 temperature[2];
if (openI2C(inID)) {
SInt8 registerToReadFrom = 0;
success &= writeI2C((SInt8*)®isterToReadFrom, sizeof(registerToReadFrom));
if (success) {
success &= readI2C((SInt8*)&temperature, 2);
}
}
if (success)
return (UInt32)temperature[0];
else
return 0;
}
bool
AppleThermal::readThermostatSettings (UInt8 id, SInt8 *lOn,SInt8 *lOff)
{
return getThermostat(id, lOn, lOff);
}
IOReturn
AppleThermal::setPowerState(unsigned long powerStateOrdinal, IOService* whatDevice)
{
#ifdef SUPPORTS_POWER_MANAGER
if (powerStateOrdinal == 0)
{
setSleepMode();
wakingUpFromSleep = true;
}
if ((powerStateOrdinal == 1) && (wakingUpFromSleep))
{
setThermostats();
wakingUpFromSleep = false;
}
#endif // SUPPORTS_POWER_MANAGER
return IOPMAckImplied;
}