AppleMaxim1989.cpp [plain text]
#include "AppleMaxim1989.h"
#define super IOService
OSDefineMetaClassAndStructors(AppleMaxim1989, IOService)
bool AppleMaxim1989::init( OSDictionary *dict )
{
if (!super::init(dict)) return(false);
fGetSensorValueSym = NULL;
pmRootDomain = NULL;
fPlatformFuncArray = NULL;
fI2CReadBufferSize = 0;
fSleep = false;
return(true);
}
void AppleMaxim1989::free( void )
{
super::free();
}
bool AppleMaxim1989::start( IOService *nub )
{
IOService *parentDev;
UInt32 fullAddr;
OSData * regprop;
const char * drvName;
const OSSymbol *instantiatePFuncs = OSSymbol::withCString("InstantiatePlatformFunctions");
IOReturn retval;
DLOG("AppleMaxim1989::start - entered\n");
if (!super::start(nub)) return(false);
if (!fGetSensorValueSym)
fGetSensorValueSym = OSSymbol::withCString("getSensorValue");
if ((regprop = OSDynamicCast(OSData, nub->getProperty("reg"))) == NULL)
{
IOLog("AppleMaxim1989::start no reg property!\n");
return(false);
}
else
{
fullAddr = *((UInt32 *)regprop->getBytesNoCopy());
fI2CBus = (UInt8)((fullAddr >> 8) & 0x000000ff);
fI2CAddress = (UInt8)(fullAddr & 0x000000fe);
DLOG("AppleMaxim1989::start fI2CBus = %02x fI2CAddress = %02x\n",
fI2CBus, fI2CAddress);
}
if ((parentDev = OSDynamicCast(IOService, nub->getParentEntry(gIODTPlane))) != NULL)
{
DLOG("AppleMaxim1989::start got parentDev %s\n", parentDev->getName());
}
else
{
DLOG("AppleMaxim1989::start failed to get parentDev\n");
return(false);
}
drvName = parentDev->getName();
if (strcmp(drvName, "i2c") != 0)
{
IOLog("AppleMaxim1989::start warning: unexpected i2c device name %s\n", drvName);
}
if ((fI2C_iface = OSDynamicCast(IOService, parentDev->getChildEntry(gIOServicePlane))) != NULL &&
(fI2C_iface->metaCast("PPCI2CInterface") != NULL))
{
DLOG("AppleMaxim1989::start got fI2C_iface %s\n", fI2C_iface->getName());
}
else
{
DLOG("AppleMaxim1989::start failed to get fI2C_iface\n");
return(false);
}
if (!openI2C())
{
IOLog("AppleMaxim1989::start failed to open I2C bus!\n");
return(false);
}
else
{
bool success = false;
UInt8 deviceID;
do {
if (!setI2CCombinedMode())
{
IOLog("AppleMaxim1989::start failed to set bus mode!\n");
break;
}
if (!readI2C(kReadDeviceID, &deviceID, 1))
{
IOLog("AppleMaxim1989::start device at bus %x addr %x not responding!\n",
fI2CBus, fI2CAddress);
break;
}
success = true;
} while (0);
closeI2C();
if (!success)
return(false);
}
fPlatformFuncArray = NULL;
DLOG("AppleMaxim1989::start(%x) calling InstantiatePlatformFunctions\n", fI2CAddress);
retval = nub->getPlatform()->callPlatformFunction(instantiatePFuncs, false,
(void *)nub, (void *)&fPlatformFuncArray, (void *)0, (void *)0);
instantiatePFuncs->release();
DLOG("AppleMaxim1989::start(%x) InstantiatePlatformFunctions returned %ld, pfArray %sNULL\n",
fI2CAddress, retval, fPlatformFuncArray ? "NOT " : "");
if (retval == kIOReturnSuccess && (fPlatformFuncArray != NULL))
{
int i, funcCount;
UInt32 flags;
IOPlatformFunction *func;
bool doSleepWake = false;
funcCount = fPlatformFuncArray->getCount();
DLOG("AppleMaxim1989::start(%x) iterating platformFunc array, count = %ld\n",
fI2CAddress, funcCount);
for (i = 0; i < funcCount; i++)
{
if (func = OSDynamicCast(IOPlatformFunction, fPlatformFuncArray->getObject(i)))
{
flags = func->getCommandFlags();
DLOG("AppleMaxim1989::start(%x) got function, flags 0x%08lx, pHandle 0x%08lx\n",
fI2CAddress, flags, func->getCommandPHandle());
if (flags & kIOPFFlagOnInit)
{
bool funcResult = performFunction(func, (void *)1, (void *)0, (void *)0, (void *)0);
DLOG("AppleMaxim1989::start(%x) startup function %s\n", fI2CAddress,
funcResult ? "SUCCEEDED" : "FAILED");
}
if (flags & (kIOPFFlagOnSleep | kIOPFFlagOnWake))
doSleepWake = true;
}
else
{
DLOG("AppleMaxim1989::start(%x) not an IOPlatformFunction object\n",
fI2CAddress);
}
}
if (doSleepWake)
{
mach_timespec_t waitTimeout;
waitTimeout.tv_sec = 30;
waitTimeout.tv_nsec = 0;
pmRootDomain = OSDynamicCast(IOPMrootDomain,
waitForService(serviceMatching("IOPMrootDomain"), &waitTimeout));
if (pmRootDomain != NULL)
{
DLOG("AppleMaxim1989::start(%x) to acknowledge power changes\n", fI2CAddress);
pmRootDomain->registerInterestedDriver(this);
}
else
{
IOLog("AppleMaxim1989::start(%x) failed to register PM interest\n",
fI2CAddress);
}
}
}
registerService();
publishChildren(nub);
return(true);
}
void AppleMaxim1989::stop( IOService *nub )
{
UInt32 flags, i;
IOPlatformFunction *func;
DLOG("AppleMaxim1989::stop - entered\n");
for (i = 0; i < fPlatformFuncArray->getCount(); i++)
{
if (func = OSDynamicCast(IOPlatformFunction, fPlatformFuncArray->getObject(i)))
{
flags = func->getCommandFlags();
if (flags & kIOPFFlagOnTerm)
performFunction(func, (void *)1, (void *)0, (void *)0, (void *)0);
}
}
if (fGetSensorValueSym) { fGetSensorValueSym->release(); fGetSensorValueSym = NULL; }
if (fPlatformFuncArray) { fPlatformFuncArray->release(); fPlatformFuncArray = NULL; }
super::stop( nub );
}
bool AppleMaxim1989::performFunction(IOPlatformFunction *func, void *pfParam1 = 0,
void *pfParam2 = 0, void *pfParam3 = 0, void *pfParam4 = 0)
{
bool success = true; IOPlatformFunctionIterator *iter;
UInt8 scratchBuffer[READ_BUFFER_LEN], mode = kI2CUnspecifiedMode;
UInt8 *maskBytes, *valueBytes;
unsigned delayMS;
UInt32 cmd, cmdLen, result, param1, param2, param3, param4, param5,
param6, param7, param8, param9, param10;
DLOG ("AppleMaxim1989::performFunction(%x) - entered\n", fI2CAddress);
if (!func)
return false;
if (!(iter = func->getCommandIterator()))
return false;
while (iter->getNextCommand (&cmd, &cmdLen, ¶m1, ¶m2, ¶m3, ¶m4,
¶m5, ¶m6, ¶m7, ¶m8, ¶m9, ¶m10, &result)) {
if (result != kIOPFNoError) {
DLOG("AppleMaxim1989::performFunction(%x) error parsing platform function\n", fI2CAddress);
success = false;
goto PERFORM_FUNCTION_EXIT;
}
DLOG ("AppleMaxim1989::performFunction(%x) - 1)0x%lx, 2)0x%lx, 3)0x%lx, 4)0x%lx, 5)0x%lx,"
"6)0x%lx, 7)0x%lx, 8)0x%lx, 9)0x%lx, 10)0x%lx\n", fI2CAddress, param1, param2, param3,
param4, param5, param6, param7, param8, param9, param10);
switch (cmd)
{
case kCommandDelay:
delayMS = param1 / 1000;
if (delayMS != 0) IOSleep(delayMS);
DLOG("AppleMaxim1989::performFunction(%x) delay %u\n", fI2CAddress, delayMS);
break;
case kCommandReadI2CSubAddr:
if (param2 > READ_BUFFER_LEN)
{
IOLog("AppleMaxim1989::performFunction(%x) r-sub operation too big!\n", fI2CAddress);
success = false;
goto PERFORM_FUNCTION_EXIT;
}
if (!openI2C())
{
IOLog("AppleMaxim1989::performFunction(%x) r-sub failed to open I2C\n", fI2CAddress);
success = false;
goto PERFORM_FUNCTION_EXIT;
}
else
{
if (mode == kI2CUnspecifiedMode || mode == kI2CCombinedMode)
setI2CCombinedMode();
else if (mode == kI2CDumbMode)
setI2CDumbMode();
else if (mode == kI2CStandardMode)
setI2CStandardMode();
else if (mode == kI2CStandardSubMode)
setI2CStandardSubMode();
fI2CReadBufferSize = (UInt16) param2;
success = readI2C( (UInt8) param1, fI2CReadBuffer, fI2CReadBufferSize );
DLOG("AppleMaxim1989::performFunction(%x) r-sub %x len %x, got data", fI2CAddress, param1, param2);
#ifdef MAX1989_DEBUG
char bufDump[256], byteDump[8];
bufDump[0] = '\0';
for (UInt32 i = 0; i < param2; i++)
{
sprintf(byteDump, " %02X", fI2CReadBuffer[i]);
strcat(bufDump, byteDump);
}
#endif
DLOG("%s\n", bufDump);
closeI2C();
}
if (!success) goto PERFORM_FUNCTION_EXIT;
break;
case kCommandWriteI2CSubAddr:
if (!openI2C())
{
IOLog("AppleMaxim1989::performFunction(%x) w-sub failed to open I2C\n", fI2CAddress);
success = false;
goto PERFORM_FUNCTION_EXIT;
}
else
{
if (mode == kI2CUnspecifiedMode || mode == kI2CStandardSubMode)
setI2CStandardSubMode();
else if (mode == kI2CDumbMode)
setI2CDumbMode();
else if (mode == kI2CStandardMode)
setI2CStandardMode();
else if (mode == kI2CCombinedMode)
setI2CCombinedMode();
DLOG("AppleMaxim1989::performFunction(%x) w-sub %x len %x data", fI2CAddress, param1, param2);
#ifdef MAX1989_DEBUG
char bufDump[256], byteDump[8];
bufDump[0] = '\0';
for (UInt32 i = 0; i < param2; i++)
{
sprintf(byteDump, " %02X", ((UInt8 *)param3)[i]);
strcat(bufDump, byteDump);
}
#endif
DLOG("%s\n", bufDump);
success = writeI2C( (UInt8) param1, (UInt8 *) param3, (UInt16) param2 );
closeI2C();
}
if (!success) goto PERFORM_FUNCTION_EXIT;
break;
case kCommandI2CMode:
if ((param1 == kI2CDumbMode) ||
(param1 == kI2CStandardMode) ||
(param1 == kI2CStandardSubMode) ||
(param1 == kI2CCombinedMode))
mode = (UInt8) param1;
DLOG("AppleMaxim1989::performFunction(%x) mode %x\n", fI2CAddress, mode);
break;
case kCommandRMWI2CSubAddr:
if ((param2 > fI2CReadBufferSize) || (param3 > fI2CReadBufferSize) || (param4 > fI2CReadBufferSize) || (param3 > param2)) {
IOLog("AppleMaxim1989::performFunction(%x) invalid mw-sub cycle\n", fI2CAddress);
success = false;
goto PERFORM_FUNCTION_EXIT;
}
maskBytes = (UInt8 *) param5;
valueBytes = (UInt8 *) param6;
for (unsigned int index = 0; index < param2; index++)
{
scratchBuffer[index] = (valueBytes[index] & maskBytes[index]);
scratchBuffer[index] |= (fI2CReadBuffer[index] & ~maskBytes[index]);
}
if (!openI2C())
{
IOLog("AppleMaxim1989::performFunction(%x) mw-sub failed to open I2C\n", fI2CAddress);
success = false;
goto PERFORM_FUNCTION_EXIT;
}
else
{
if (mode == kI2CUnspecifiedMode || mode == kI2CCombinedMode)
setI2CCombinedMode();
else if (mode == kI2CDumbMode)
setI2CDumbMode();
else if (mode == kI2CStandardMode)
setI2CStandardMode();
else if (mode == kI2CStandardSubMode)
setI2CStandardSubMode();
DLOG("AppleMaxim1989::performFunction(%x) mw-sub %x len %x data", fI2CAddress, param1, param4);
#ifdef MAX1989_DEBUG
char bufDump[256], byteDump[8];
bufDump[0] = '\0';
for (UInt32 i = 0; i < param4; i++)
{
sprintf(byteDump, " %02X", scratchBuffer[i]);
strcat(bufDump, byteDump);
}
#endif
DLOG("%s\n", bufDump);
success = writeI2C( (UInt8) param1, scratchBuffer, (UInt16) param4 );
closeI2C();
}
if (!success) goto PERFORM_FUNCTION_EXIT;
break;
default:
DLOG ("AppleMaxim1989::performFunction - bad command %ld\n", cmd);
success = false;
goto PERFORM_FUNCTION_EXIT;
}
}
PERFORM_FUNCTION_EXIT:
iter->release();
DLOG ("AppleMaxim1989::performFunction - done - returning %s\n", success ? "TRUE" : "FALSE");
return(success);
}
IOReturn AppleMaxim1989::callPlatformFunction(const OSSymbol *functionName,
bool waitForFunction, void *param1, void *param2,
void *param3, void *param4)
{
UInt32 maximReg = (UInt32)param1;
SInt32 *temp_buf = (SInt32 *)param2;
DLOG("AppleMaxim1989::callPlatformFunction(%x) %s %s %08lx %08lx %08lx %08lx\n",
fI2CAddress, functionName->getCStringNoCopy(), waitForFunction ? "TRUE" : "FALSE",
(UInt32) param1, (UInt32) param2, (UInt32) param3, (UInt32) param4);
if (functionName->isEqualTo(fGetSensorValueSym) == true)
{
if (fSleep == true)
return(kIOReturnOffline);
if (temp_buf == NULL)
return(kIOReturnBadArgument);
return(getTemp(maximReg, temp_buf));
}
return(super::callPlatformFunction(functionName, waitForFunction,
param1, param2, param3, param4));
}
IOReturn AppleMaxim1989::publishChildren(IOService *nub)
{
OSIterator *childIterator = NULL;
IORegistryEntry *childEntry = NULL;
IOService *childNub = NULL;
childIterator = nub->getChildIterator(gIODTPlane);
if( childIterator != NULL )
{
while ( ( childEntry = (IORegistryEntry *)( childIterator->getNextObject() ) ) != NULL )
{
childNub = OSDynamicCast(IOService, OSMetaClass::allocClassWithName("IOService"));
childNub->init(childEntry, gIODTPlane);
childNub->attach(this);
childNub->registerService();
DLOG("AppleMaxim1989::publishChildren(0x%x) published child %s\n", fI2CAddress<<1, childEntry->getName());
}
childIterator->release();
}
return kIOReturnSuccess;
}
#pragma mark -
#pragma mark *** Read Temperature Channels ***
#pragma mark -
IOReturn AppleMaxim1989::getTemp( UInt32 maximReg, SInt32 * temp )
{
UInt8 integer;
if (!openI2C())
{
IOLog("AppleMaxim1989::getTemp error opening bus!\n");
goto failNoClose;
}
if (!setI2CCombinedMode())
{
IOLog("AppleMaxim1989::getTemp failed to set bus mode!\n");
goto failClose;
}
if (!readI2C( maximReg, &integer, 1 ))
{
IOLog("AppleMaxim1989::getTemp read temp failed!\n");
goto failClose;
}
closeI2C();
*temp = ( ( ( SInt8 ) ( integer << 1 ) ) << 15 );
return(kIOReturnSuccess);
failClose:
closeI2C();
failNoClose:
*temp = -1;
return(kIOReturnError);
}
#pragma mark -
#pragma mark *** Power Management ***
#pragma mark -
IOReturn AppleMaxim1989::powerStateWillChangeTo (IOPMPowerFlags theFlags, unsigned long, IOService*)
{
if ( ! (theFlags & IOPMPowerOn) ) {
DLOG("AppleMaxim1989::powerStateWillChangeTo - sleep\n");
doSleep();
} else {
DLOG("AppleMaxim1989::powerStateWillChangeTo - wake\n");
doWake();
}
return IOPMAckImplied;
}
void AppleMaxim1989::doSleep(void)
{
UInt32 flags, i;
IOPlatformFunction *func;
fSleep = true;
for (i = 0; i < fPlatformFuncArray->getCount(); i++)
{
if (func = OSDynamicCast(IOPlatformFunction, fPlatformFuncArray->getObject(i)))
{
flags = func->getCommandFlags();
if (flags & kIOPFFlagOnSleep)
performFunction(func, (void *)1, (void *)0, (void *)0, (void *)0);
}
}
}
void AppleMaxim1989::doWake(void)
{
UInt32 flags, i;
IOPlatformFunction *func;
for (i = 0; i < fPlatformFuncArray->getCount(); i++)
{
if (func = OSDynamicCast(IOPlatformFunction, fPlatformFuncArray->getObject(i)))
{
flags = func->getCommandFlags();
if (flags & kIOPFFlagOnWake)
performFunction(func, (void *)1, (void *)0, (void *)0, (void *)0);
}
}
fSleep = false;
}
#pragma mark -
#pragma mark *** I2C Helpers ***
#pragma mark -
bool AppleMaxim1989::openI2C( void )
{
UInt32 passBus;
IOReturn status;
DLOG("AppleMaxim1989::openI2C(%x) - entered\n", fI2CAddress);
if (fI2C_iface == NULL)
return false;
passBus = (UInt32) fI2CBus; if ((status = (fI2C_iface->callPlatformFunction(kOpenI2Cbus, false, (void *) passBus, NULL, NULL, NULL)))
!= kIOReturnSuccess)
{
IOLog("AppleMaxim1989::openI2C(%x) failed, status = %08lx\n", fI2CAddress, (UInt32) status);
return(false);
}
return(true);
}
void AppleMaxim1989::closeI2C( void )
{
IOReturn status;
DLOG("AppleMaxim1989::closeI2C(%x) - entered\n", fI2CAddress);
if (fI2C_iface == NULL) return;
if ((status = (fI2C_iface->callPlatformFunction(kCloseI2Cbus, false, NULL, NULL, NULL, NULL)))
!= kIOReturnSuccess)
{
IOLog("AppleMaxim1989::closeI2C(%x) failed, status = %08lx\n", fI2CAddress, (UInt32) status);
}
}
bool AppleMaxim1989::setI2CDumbMode( void )
{
IOReturn status = kIOReturnSuccess;
DLOG("AppleMaxim1989::setI2CDumbMode(%x) - entered\n", fI2CAddress);
if ((fI2C_iface == NULL) ||
(status = (fI2C_iface->callPlatformFunction(kSetDumbMode, false, NULL, NULL, NULL, NULL)))
!= kIOReturnSuccess)
{
IOLog("AppleMaxim1989::setI2CDumbMode(%x) failed, status = %08lx\n", fI2CAddress, (UInt32) status);
return(false);
}
return(true);
}
bool AppleMaxim1989::setI2CStandardMode( void )
{
IOReturn status = kIOReturnSuccess;
DLOG("AppleMaxim1989::setI2CStandardMode(%x) - entered\n", fI2CAddress);
if ((fI2C_iface == NULL) ||
(status = (fI2C_iface->callPlatformFunction(kSetStandardMode, false, NULL, NULL, NULL, NULL)))
!= kIOReturnSuccess)
{
IOLog("AppleMaxim1989::setI2CStandardMode(%x) failed, status = %08lx\n", fI2CAddress, (UInt32) status);
return(false);
}
return(true);
}
bool AppleMaxim1989::setI2CStandardSubMode( void )
{
IOReturn status = kIOReturnSuccess;
DLOG("AppleMaxim1989::setI2CStandardSubMode(%x) - entered\n", fI2CAddress);
if ((fI2C_iface == NULL) ||
(status = (fI2C_iface->callPlatformFunction(kSetStandardSubMode, false, NULL, NULL, NULL, NULL)))
!= kIOReturnSuccess)
{
IOLog("AppleMaxim1989::setI2CStandardSubMode(%x) failed, status = %08lx\n", fI2CAddress, (UInt32) status);
return(false);
}
return(true);
}
bool AppleMaxim1989::setI2CCombinedMode( void )
{
IOReturn status = kIOReturnSuccess;
DLOG("AppleMaxim1989::setI2CCombinedMode(%x) - entered\n", fI2CAddress);
if ((fI2C_iface == NULL) ||
(status = (fI2C_iface->callPlatformFunction(kSetCombinedMode, false, NULL, NULL, NULL, NULL)))
!= kIOReturnSuccess)
{
IOLog("AppleMaxim1989::setI2CCombinedMode(%x) failed, status = %08lx\n", fI2CAddress, (UInt32) status);
return(false);
}
return(true);
}
bool AppleMaxim1989::writeI2C(UInt8 subAddr, UInt8 *data, UInt16 size)
{
UInt32 passAddr, passSubAddr, passSize;
unsigned int retries = 0;
IOReturn status;
DLOG("AppleMaxim1989::writeI2C(%x) - entered\n", fI2CAddress);
if (fI2C_iface == NULL || data == NULL || size == 0)
return false;
passAddr = (UInt32) (fI2CAddress >> 1);
passSubAddr = (UInt32) subAddr;
passSize = (UInt32) size;
while ((retries < kNumRetries) &&
((status = (fI2C_iface->callPlatformFunction(kWriteI2Cbus, false, (void *) passAddr,
(void *) passSubAddr, (void *) data, (void *) passSize))) != kIOReturnSuccess))
{
IOLog("AppleMaxim1989::writeI2C(%x) transaction failed, status = %08lx\n", fI2CAddress, (UInt32) status);
retries++;
}
if (retries >= kNumRetries)
return(false);
else
return(true);
}
bool AppleMaxim1989::readI2C(UInt8 subAddr, UInt8 *data, UInt16 size)
{
UInt32 passAddr, passSubAddr, passSize;
unsigned int retries = 0;
IOReturn status;
DLOG("AppleMaxim1989::readI2C(%x) \n", fI2CAddress);
if (fI2C_iface == NULL || data == NULL || size == 0)
return false;
passAddr = (UInt32) (fI2CAddress >> 1);
passSubAddr = (UInt32) subAddr;
passSize = (UInt32) size;
while ((retries < kNumRetries) &&
((status = (fI2C_iface->callPlatformFunction(kReadI2Cbus, false, (void *) passAddr,
(void *) passSubAddr, (void *) data, (void *) passSize))) != kIOReturnSuccess))
{
IOLog("AppleMaxim1989::readI2C error (0x%08X) I2CAddr = 0x%02X, subAddr = 0x%02X\n", (unsigned int) status, fI2CAddress, subAddr);
retries++;
}
if (retries >= kNumRetries)
return(false);
else
return(true);
}