#include <sys/cdefs.h>
__BEGIN_DECLS
#include <kern/thread_call.h>
__END_DECLS
#include <IOKit/IODeviceTreeSupport.h>
#include "AppleHWSensor.h"
static const OSSymbol *sSensorID;
static const OSSymbol *sLowThreshold;
static const OSSymbol *sHighThreshold;
static const OSSymbol *sPollingPeriod;
static const OSSymbol *sPollingPeriodNS;
static const OSSymbol *sCurrentValue;
static const OSSymbol *sGetSensorValue;
static const OSSymbol *sThreshold;
static const OSSymbol *sTempSensor;
static const OSSymbol *sSensorType;
static const OSSymbol *sForceUpdate;
OSDefineMetaClassAndStructors(IOHWSensor,IOHWMonitor)
#ifdef ENABLENOTIFY
static IORegistryEntry *objFromHandle(UInt32 search)
{
const OSSymbol *handleSym = NULL;
OSIterator *iter = NULL;
IORegistryEntry *found = NULL;
do {
IORegistryEntry *obj;
handleSym = OSSymbol::withCString("AAPL,phandle");
if(!handleSym)
break;
iter = IORegistryIterator::iterateOver(gIODTPlane, kIORegistryIterateRecursively);
if(!iter)
break;
while(obj = (IORegistryEntry *)iter->getNextObject())
{
OSData *han;
han = OSDynamicCast(OSData, obj->getProperty(handleSym));
if(han)
{
UInt32 *handle = (UInt32 *)han->getBytesNoCopy();
if(*handle == search)
{
found = obj;
break;
}
}
}
} while (false);
if(handleSym)
handleSym->release();
if(iter)
iter->release();
return found;
}
#endif
void IOHWSensor::timerCallback(void *self)
{
IOHWSensor * me = OSDynamicCast(IOHWSensor, (OSMetaClassBase *) self);
if (me)
{
me->updateCurrentValue();
me->setTimeout();
}
}
bool IOHWSensor::start(IOService *provider)
{
OSDictionary *dict;
bool doPolling;
IOReturn ret;
SInt32 val, retryCount;
if(!sSensorID)
sSensorID = OSSymbol::withCString("sensor-id");
if(!sLowThreshold)
sLowThreshold = OSSymbol::withCString("low-threshold");
if(!sHighThreshold)
sHighThreshold = OSSymbol::withCString("high-threshold");
if(!sThreshold)
sThreshold = OSSymbol::withCString("threshold-value");
if(!sPollingPeriod)
sPollingPeriod = OSSymbol::withCString("polling-period");
if(!sPollingPeriodNS)
sPollingPeriodNS = OSSymbol::withCString("polling-period-ns");
if(!sCurrentValue)
sCurrentValue = OSSymbol::withCString("current-value");
if(!sGetSensorValue)
sGetSensorValue = OSSymbol::withCString("getSensorValue");
if(!sTempSensor)
sTempSensor = OSSymbol::withCString("temp-sensor");
if(!sSensorType)
sSensorType = OSSymbol::withCString("sensor-type");
if(!sForceUpdate)
sForceUpdate = OSSymbol::withCString("force-update");
if ( !(IOHWMonitor::start(provider)) )
return false;
DLOG("IOHWSensor::start(%s) - entered\n", fDebugID);
fCalloutEntry = thread_call_allocate((thread_call_func_t) IOHWSensor::timerCallback,
(thread_call_param_t) this);
if (fCalloutEntry == NULL)
{
IOLog("IOHWSensor::start failed to allocate thread callout\n");
return(false);
}
fLowThreshold = kNoThreshold;
fHighThreshold = kNoThreshold;
DLOG("IOHWSensor::start(%s) - parsing sensor nub properties\n", fDebugID);
bool parseSuccess = FALSE;
OSNumber *num;
OSData *data;
doPolling = false;
do {
data = OSDynamicCast(OSData, provider->getProperty(sSensorID));
if (!data)
{
DLOG("IOHWSensor - no Sensor ID !!\n");
break;
}
fID = OSReadBigInt32(data->getBytesNoCopy(),0);
num = OSNumber::withNumber(fID, 32);
if (!num)
{
IOLog("IOHWSensor - can't set Sensor ID !!\n");
break;
}
setProperty(sSensorID, num);
num->release();
num = (OSNumber *)getProperty("version");
if (num->unsigned32BitValue() == 1)
{
fChannel = fID;
}
else if (num->unsigned32BitValue() == 2)
{
data = OSDynamicCast(OSData, provider->getProperty("reg"));
if (!data) break;
fChannel = OSReadBigInt32(data->getBytesNoCopy(),0);
}
else
{
IOLog("IOHWSensor - version 2 but no reg property !!\n");
break;
}
parseSuccess = TRUE;
fPollingPeriod = kNoPolling;
fPollingPeriodNS = kNoPolling;
data = OSDynamicCast(OSData, provider->getProperty(sPollingPeriod));
if(data)
{
unsigned int length = (data->getLength() / sizeof(UInt32));
if (length == 2)
{
fPollingPeriodNS = OSReadBigInt32(data->getBytesNoCopy(),4); num = OSNumber::withNumber(fPollingPeriodNS, 32);
if(num)
{
setPollingPeriodNS(num);
num->release();
}
}
fPollingPeriod = OSReadBigInt32(data->getBytesNoCopy(),0); num = OSNumber::withNumber(fPollingPeriod, 32);
if(num)
{
setPollingPeriod(num);
num->release();
}
doPolling = ((fPollingPeriod != kNoPolling) || (fPollingPeriodNS != kNoPolling));
}
} while (0);
if (parseSuccess == FALSE)
{
if (fCalloutEntry)
{
thread_call_cancel (fCalloutEntry);
thread_call_free (fCalloutEntry);
}
fCalloutEntry = NULL;
return(false);
}
#ifdef ENABLENOTIFY
do
{
IORegistryEntry *notify_ancestor = provider;
OSDictionary *dict;
char *buf;
while(!notify_ancestor->inPlane(gIODTPlane))
notify_ancestor = notify_ancestor->getParentEntry(gIOServicePlane);
dict = notify_ancestor->dictionaryWithProperties();
if(!dict)
break;
OSSerialize *serial = OSSerialize::withCapacity(1000);
if(!serial)
{
dict->release();
break;
}
dict->serialize(serial);
buf = serial->text();
while(*buf)
{
if(strncmp("<key>notify-", buf, 12)==0)
{
char notify[128];
char key[135]; int len;
buf += 12;
len = 0;
while ((*buf != '<') && (*buf != 0) && (len < 128))
notify[len++] = *buf++;
notify[len] = 0;
strcpy(key, "notify-");
strcat(key, notify);
OSData *obj = OSDynamicCast(OSData, dict->getObject(key));
if(obj)
{
UInt32 *ptr = (UInt32*)obj->getBytesNoCopy();
if((UInt32)ptr[1] == fID)
{
fNotifyObj = objFromHandle(ptr[0]);
strcpy(key, "AAPL,");
strcat(key, notify);
fNotifySym = OSSymbol::withCString(key);
}
}
}
buf++;
}
serial->release();
dict->release();
}
while (false);
#endif
DLOG("IOHWSensor::start(%s) - polling initial sensor value\n", fDebugID);
retryCount = 0;
do {
ret = callPlatformFunction(sGetSensorValue, FALSE, (void *)fChannel, &val, NULL, NULL);
if (ret == kIOReturnSuccess)
break;
IOSleep (250); retryCount++;
} while (retryCount < 10);
if(ret != kIOReturnSuccess)
{
IOLog("AppleHWSensor::start failed to read initial sensor value! Got error %08lx\n", (UInt32)ret);
if (fCalloutEntry)
{
thread_call_cancel (fCalloutEntry);
thread_call_free (fCalloutEntry);
}
fCalloutEntry = NULL;
return(false);
}
DLOG("IOHWSensor::start(%s) - messaging pmon\n", fDebugID);
dict = OSDictionary::withCapacity(3);
num = OSNumber::withNumber(fID, 32);
dict->setObject(sSensorID, num);
num->release();
num = OSNumber::withNumber(val, 32);
setProperty(sCurrentValue, num); dict->setObject(sCurrentValue, num);
num->release();
dict->setObject(sSensorType, sTempSensor);
if(fIOPMon)
messageClient(kRegisterSensor, fIOPMon, dict);
dict->release();
registerService();
fInited = true;
if (doPolling) setTimeout();
DLOG("IOHWSensor::start(%s) - done\n", fDebugID);
return true;
}
void IOHWSensor::stop(IOService *provider)
{
if (fCalloutEntry) {
thread_call_cancel (fCalloutEntry);
thread_call_free (fCalloutEntry);
}
fCalloutEntry = NULL;
}
IOReturn IOHWSensor::setProperties( OSObject * properties )
{
OSDictionary * dict = OSDynamicCast(OSDictionary, properties);
OSNumber *num, *sec, *nsec;
if(!dict)
return kIOReturnBadArgument;
num = OSDynamicCast(OSNumber, dict->getObject(sLowThreshold));
if(num)
setLowThreshold(num);
num = OSDynamicCast(OSNumber, dict->getObject(sHighThreshold));
if(num)
setHighThreshold(num);
sec = OSDynamicCast(OSNumber, dict->getObject(sPollingPeriod));
if(sec)
setPollingPeriod(sec);
nsec = OSDynamicCast(OSNumber, dict->getObject(sPollingPeriodNS));
if(nsec)
setPollingPeriodNS(nsec);
if ( sec || nsec )
setTimeout();
if(dict->getObject(sCurrentValue) || dict->getObject(sForceUpdate))
updateCurrentValue();
return kIOReturnSuccess;
}
SInt32 IOHWSensor::updateCurrentValue()
{
SInt32 val;
OSNumber *num;
IOReturn ret;
do {
ret = updateValue(sGetSensorValue, sCurrentValue);
if (num = (OSNumber *)getProperty(sCurrentValue))
break;
IOSleep (250); } while (1);
#ifdef ENABLENOTIFY
if(fNotifyObj && fNotifySym)
fNotifyObj->setProperty(fNotifySym, num);
#endif
val = num->unsigned32BitValue();
if(fLowThreshold != kNoThreshold && val <= fLowThreshold)
sendMessage(kLowThresholdHit, val, fLowThreshold);
if(fHighThreshold != kNoThreshold && val >= fHighThreshold)
sendMessage(kHighThresholdHit, val, fHighThreshold);
return val;
}
void IOHWSensor::sendMessage(UInt32 msg, SInt32 val, SInt32 threshold)
{
OSDictionary *dict;
OSNumber *num;
dict = OSDictionary::withCapacity(3);
num = OSNumber::withNumber(fID, 32);
dict->setObject(sSensorID, num);
num->release();
num = OSNumber::withNumber(val, 32);
dict->setObject(sCurrentValue, num);
num->release();
num = OSNumber::withNumber(threshold, 32);
dict->setObject(sThreshold, num);
num->release();
if(fIOPMon)
messageClient(msg, fIOPMon, dict);
dict->release();
}
void IOHWSensor::setLowThreshold(OSNumber *val)
{
fLowThreshold = (SInt32)val->unsigned32BitValue();
setProperty(sLowThreshold, val);
}
void IOHWSensor::setHighThreshold(OSNumber *val)
{
fHighThreshold = (SInt32)val->unsigned32BitValue();
setProperty(sHighThreshold, val);
}
void IOHWSensor::setPollingPeriod(OSNumber *val)
{
fPollingPeriod = val->unsigned32BitValue();
setProperty(sPollingPeriod, val);
}
void IOHWSensor::setPollingPeriodNS(OSNumber *val)
{
fPollingPeriodNS = val->unsigned32BitValue();
setProperty(sPollingPeriodNS, val);
}
void IOHWSensor::setTimeout()
{
AbsoluteTime interval, end;
if (!fCalloutEntry) return;
AbsoluteTime_to_scalar( &interval ) = 0;
AbsoluteTime_to_scalar( &end ) = 0;
thread_call_cancel((thread_call_t) fCalloutEntry);
if( (fPollingPeriod == kNoPolling) && (fPollingPeriodNS == kNoPolling) )
return;
if(fPollingPeriod != kNoPolling)
{
clock_interval_to_absolutetime_interval( fPollingPeriod , NSEC_PER_SEC, &interval ); }
if(fPollingPeriodNS != kNoPolling)
{
AbsoluteTime scratch;
AbsoluteTime_to_scalar( &scratch ) = 0;
clock_interval_to_absolutetime_interval( fPollingPeriodNS , 1, &scratch ); ADD_ABSOLUTETIME(&interval, &scratch); }
clock_absolutetime_interval_to_deadline(interval, &end);
thread_call_enter_delayed((thread_call_t) fCalloutEntry, end); }
IOReturn IOHWSensor::setPowerState(unsigned long whatState, IOService *policyMaker)
{
IOReturn status;
if (!fInited)
return IOPMAckImplied;
status = IOHWMonitor::setPowerState( whatState, policyMaker );
if ( fCalloutEntry )
{
if ( sleeping )
thread_call_cancel( fCalloutEntry );
else
setTimeout();
}
return status;
}