/* Program to print out the value reported by the onboard temperature sensor in * PowerMac G4 (FW800) systems, and the associated fan speed. * * The IOKitGetPropertyAtGivenPathCopy function is taken from an e-mail message * to the darwin-development mailing list from Chad Jones (chadj@mail.apple.com) * on September 5, 2001. The message is available here: * http://lists.apple.com/archives/darwin-development/2001/Sep/05/ioregistryharddiskhardwa.001.txt * (user: archives, password: archives) * * Information on the Dallas Semiconductor 1775 part was obtained from the * publicly available specifications sheet available on the web. All knowledge * of the workings of this system is based on speculation on my part, not on * any information from Apple. To my knowledge the AppleCPUThermo and AppleFan * kernel extensions are closed-source Apple proprietary, so I have no knowledge * of their inner workings, only what I could gleam from information available * in the IO Registry. * * Author: Eric Carlson, carl0240@tc.umn.edu * * This software is supplied 'as is', with no warranty. * You are free to use and/or redistribute this source, modified or unmodified, * in any form. */ // build using: // gcc -o temp temp.c -O3 -Wall -g -framework IOKit -framework CoreFoundation #include #include #include #include CFDataRef IOKitGetPropertyAtGivenPathCopy(char* PathToLookUp, char* PropertyToLookup) { mach_port_t MasterPort; kern_return_t status; io_registry_entry_t IOKitEntry; CFStringRef PropertyToLookupCFString; CFMutableDictionaryRef DictionaryOfIOKitEntries; CFDataRef DataToReturn; if ((PropertyToLookup == NULL) || (PathToLookUp == NULL)) { return(NULL); //we fail if any of the passed in values are null. } //Below we are getting the master port used to communicate with IOKit. //first argument: Mach_Port_NULL indicating that we want to get the master port. //Second Argument: The variable where the master port will be stored in. //status must be kern_success or we must fail. We don't need to release the result. status = IOMasterPort(MACH_PORT_NULL,&MasterPort); if (status != KERN_SUCCESS) //if we get error here then we fail with null. { return(NULL); } //Now need to get the IORegistry entry we are going to lookup. This is very like getting the directory of the file //we want to lookup in Finder. //First Argument: The master port we need to lookup from. //Second Argument: The IOKit path to the entry we are interested in. //Note the result must be released with IOObjectRelease later IOKitEntry = IORegistryEntryFromPath(MasterPort,PathToLookUp); //if we get an error back then give up if (IOKitEntry == MACH_PORT_NULL) { return(NULL); } //Now we need to get a list of all the keys which are available from that entry. This is equivelent of doing 'ls' in terminal which //lists all the entries at the current level. The DictionaryOfIOKitEntries contains the result which we are interested //in. We then pull the information out of the dictionary next. //First Argument: The IOKit entry we are interested in. This is //very much like the directory in a file system we are interested int. //Second Argument: The CFDictioanry where the results will be stored after this call is made. //Third Argument: NULL since we want default CFAllocator (as usual) //Forth Argument: NULL since we don't want any special options in the lookup/conversion. status = IORegistryEntryCreateCFProperties(IOKitEntry,&DictionaryOfIOKitEntries,NULL,NULL); IOObjectRelease(IOKitEntry); //We are now done with IOKitEntry so release it. if (status != KERN_SUCCESS) //if we get error here then we fail with null. { return(NULL); } //Now need to convert the character string into a CFString for use in dictionary lookup. PropertyToLookupCFString = CFStringCreateWithCString(NULL, PropertyToLookup, kCFStringEncodingASCII); if (PropertyToLookupCFString == NULL) { return(NULL); //if we don't have a property to lookup then we fail. } //Now pull the property we are interested in out of the Dictioary. DataToReturn = CFDictionaryGetValue(DictionaryOfIOKitEntries,PropertyToLookupCFString); CFRetain(DataToReturn); //need the value for later so retain now CFRelease(DictionaryOfIOKitEntries); //done with dictionary so release. CFRelease(PropertyToLookupCFString); //done with CFString return(DataToReturn); } int main(int argc, char* argv[]) { //the path to the node with the temperature info as provided by the AppleCPUThermo kernel extension char *ioRegPathTemp = "IOService:/MacRISC2PE/uni-n/AppleUniN/i2c/PPCI2CInterface/temp-monitor/AppleCPUThermo"; char *propertyNameTemp = "temperature"; //the path to the node with the fan speed table as provided by the AppleFan kernel extension char *ioRegPathFan = "IOService:/MacRISC2PE/uni-n/AppleUniN/i2c/PPCI2CInterface/fan/AppleFan"; char *propertyNameFan = "default-params"; int tempNum; CFIndex i; SInt64 fanVal; float temp; CFNumberRef tempCFNum = (CFNumberRef) IOKitGetPropertyAtGivenPathCopy(ioRegPathTemp, propertyNameTemp); CFDictionaryRef fanCFDict = (CFDictionaryRef) IOKitGetPropertyAtGivenPathCopy(ioRegPathFan, propertyNameFan); CFArrayRef fanSpeedTempArray; if(tempCFNum == NULL || fanCFDict == NULL) { return 1; } //extract the array of temperature values from the CFDictionary we got out of the IO registry fanSpeedTempArray = (CFArrayRef) CFDictionaryGetValue(fanCFDict, (const void*)CFStringCreateWithCString(NULL, "fan-speed-table", kCFStringEncodingASCII)); //get the temperature number (later converted to degrees C) if(!CFNumberGetValue(tempCFNum, kCFNumberIntType, (void*) &tempNum)) { return 1; } //loop through the temperature/fan speed table to find the current fan speed based on the temp we got i = CFArrayGetCount(fanSpeedTempArray); do { i--; CFNumberGetValue(CFArrayGetValueAtIndex(fanSpeedTempArray, i), kCFNumberSInt64Type, (void*) &fanVal); } while( ( fanVal > tempNum) && (i > 0) ); //the value stored in the IO registry appears to be the raw value returned from the temperature sensor, // a Dallas Semiconductor 1775 (ds1775) part. According to spec, the data is returned in two's complement form, // with apparently 12 of the 16 bit positions used (the default is 12 for the chip, and this seems to be what it is set to). // // So, to convert to degrees C, divide by 2^4 and multiply by 0.0625 (the resolution) temp = (tempNum / 16.0) * 0.0625; //convert temp number to degrees C printf("%f\n", (temp*(9.0/5.0))+32.0); //output in degrees F printf("%d\n",(int)i); //print fan value return 0; }