Created
November 10, 2012 01:13
-
-
Save edvakf/4049362 to your computer and use it in GitHub Desktop.
SMC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Apple System Management Control (SMC) Tool | |
* Copyright (C) 2006 devnull | |
* | |
* This program is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU General Public License | |
* as published by the Free Software Foundation; either version 2 | |
* of the License, or (at your option) any later version. | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* You should have received a copy of the GNU General Public License | |
* along with this program; if not, write to the Free Software | |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
*/ | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <IOKit/IOKitLib.h> | |
#include "smc.h" | |
static io_connect_t conn; | |
UInt32 _strtoul(char *str, int size, int base) | |
{ | |
UInt32 total = 0; | |
int i; | |
for (i = 0; i < size; i++) | |
{ | |
if (base == 16) | |
total += str[i] << (size - 1 - i) * 8; | |
else | |
total += (unsigned char) (str[i] << (size - 1 - i) * 8); | |
} | |
return total; | |
} | |
void _ultostr(char *str, UInt32 val) | |
{ | |
str[0] = '\0'; | |
sprintf(str, "%c%c%c%c", | |
(unsigned int) val >> 24, | |
(unsigned int) val >> 16, | |
(unsigned int) val >> 8, | |
(unsigned int) val); | |
} | |
float _strtof(char *str, int size, int e) | |
{ | |
float total = 0; | |
int i; | |
for (i = 0; i < size; i++) | |
{ | |
if (i == (size - 1)) | |
total += (str[i] & 0xff) >> e; | |
else | |
total += str[i] << (size - 1 - i) * (8 - e); | |
} | |
return total; | |
} | |
void printFPE2(SMCVal_t val) | |
{ | |
/* FIXME: This decode is incomplete, last 2 bits are dropped */ | |
printf("%.0f ", _strtof(val.bytes, val.dataSize, 2)); | |
} | |
void printUInt(SMCVal_t val) | |
{ | |
printf("%u ", (unsigned int) _strtoul(val.bytes, val.dataSize, 10)); | |
} | |
void printBytesHex(SMCVal_t val) | |
{ | |
int i; | |
printf("(bytes"); | |
for (i = 0; i < val.dataSize; i++) | |
printf(" %02x", (unsigned char) val.bytes[i]); | |
printf(")\n"); | |
} | |
void printVal(SMCVal_t val) | |
{ | |
printf(" %-4s [%-4s] ", val.key, val.dataType); | |
if (val.dataSize > 0) | |
{ | |
if ((strcmp(val.dataType, DATATYPE_UINT8) == 0) || | |
(strcmp(val.dataType, DATATYPE_UINT16) == 0) || | |
(strcmp(val.dataType, DATATYPE_UINT32) == 0)) | |
printUInt(val); | |
else if (strcmp(val.dataType, DATATYPE_FPE2) == 0) | |
printFPE2(val); | |
printBytesHex(val); | |
} | |
else | |
{ | |
printf("no data\n"); | |
} | |
} | |
kern_return_t SMCOpen(io_connect_t *conn) | |
{ | |
kern_return_t result; | |
mach_port_t masterPort; | |
io_iterator_t iterator; | |
io_object_t device; | |
result = IOMasterPort(MACH_PORT_NULL, &masterPort); | |
CFMutableDictionaryRef matchingDictionary = IOServiceMatching("AppleSMC"); | |
result = IOServiceGetMatchingServices(masterPort, matchingDictionary, &iterator); | |
if (result != kIOReturnSuccess) | |
{ | |
printf("Error: IOServiceGetMatchingServices() = %08x\n", result); | |
return 1; | |
} | |
device = IOIteratorNext(iterator); | |
IOObjectRelease(iterator); | |
if (device == 0) | |
{ | |
printf("Error: no SMC found\n"); | |
return 1; | |
} | |
result = IOServiceOpen(device, mach_task_self(), 0, conn); | |
IOObjectRelease(device); | |
if (result != kIOReturnSuccess) | |
{ | |
printf("Error: IOServiceOpen() = %08x\n", result); | |
return 1; | |
} | |
return kIOReturnSuccess; | |
} | |
kern_return_t SMCClose(io_connect_t conn) | |
{ | |
return IOServiceClose(conn); | |
} | |
kern_return_t SMCCall(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure) | |
{ | |
#if __LP64__ | |
size_t structureInputSize; | |
size_t structureOutputSize; | |
#else | |
IOItemCount structureInputSize; | |
IOByteCount structureOutputSize; | |
#endif | |
structureInputSize = sizeof(SMCKeyData_t); | |
structureOutputSize = sizeof(SMCKeyData_t); | |
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 | |
return IOConnectCallStructMethod( | |
conn, | |
index, | |
inputStructure, | |
structureInputSize, | |
outputStructure, | |
&structureOutputSize | |
); | |
#else | |
return IOConnectMethodStructureIStructureO( | |
conn, | |
index, | |
structureInputSize, | |
&structureOutputSize, | |
inputStructure, | |
outputStructure | |
); | |
#endif | |
} | |
kern_return_t SMCReadKey(UInt32Char_t key, SMCVal_t *val) | |
{ | |
kern_return_t result; | |
SMCKeyData_t inputStructure; | |
SMCKeyData_t outputStructure; | |
memset(&inputStructure, 0, sizeof(SMCKeyData_t)); | |
memset(&outputStructure, 0, sizeof(SMCKeyData_t)); | |
memset(val, 0, sizeof(SMCVal_t)); | |
inputStructure.key = _strtoul(key, 4, 16); | |
inputStructure.data8 = SMC_CMD_READ_KEYINFO; | |
result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure); | |
if (result != kIOReturnSuccess) | |
return result; | |
val->dataSize = outputStructure.keyInfo.dataSize; | |
_ultostr(val->dataType, outputStructure.keyInfo.dataType); | |
inputStructure.keyInfo.dataSize = val->dataSize; | |
inputStructure.data8 = SMC_CMD_READ_BYTES; | |
result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure); | |
if (result != kIOReturnSuccess) | |
return result; | |
memcpy(val->bytes, outputStructure.bytes, sizeof(outputStructure.bytes)); | |
return kIOReturnSuccess; | |
} | |
kern_return_t SMCWriteKey(SMCVal_t writeVal) | |
{ | |
kern_return_t result; | |
SMCKeyData_t inputStructure; | |
SMCKeyData_t outputStructure; | |
SMCVal_t readVal; | |
result = SMCReadKey(writeVal.key, &readVal); | |
if (result != kIOReturnSuccess) | |
return result; | |
if (readVal.dataSize != writeVal.dataSize) | |
return kIOReturnError; | |
memset(&inputStructure, 0, sizeof(SMCKeyData_t)); | |
memset(&outputStructure, 0, sizeof(SMCKeyData_t)); | |
inputStructure.key = _strtoul(writeVal.key, 4, 16); | |
inputStructure.data8 = SMC_CMD_WRITE_BYTES; | |
inputStructure.keyInfo.dataSize = writeVal.dataSize; | |
memcpy(inputStructure.bytes, writeVal.bytes, sizeof(writeVal.bytes)); | |
result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure); | |
if (result != kIOReturnSuccess) | |
return result; | |
return kIOReturnSuccess; | |
} | |
UInt32 SMCReadIndexCount(void) | |
{ | |
SMCVal_t val; | |
SMCReadKey("#KEY", &val); | |
return _strtoul(val.bytes, val.dataSize, 10); | |
} | |
kern_return_t SMCPrintAll(void) | |
{ | |
kern_return_t result; | |
SMCKeyData_t inputStructure; | |
SMCKeyData_t outputStructure; | |
int totalKeys, i; | |
UInt32Char_t key; | |
SMCVal_t val; | |
totalKeys = SMCReadIndexCount(); | |
for (i = 0; i < totalKeys; i++) | |
{ | |
memset(&inputStructure, 0, sizeof(SMCKeyData_t)); | |
memset(&outputStructure, 0, sizeof(SMCKeyData_t)); | |
memset(&val, 0, sizeof(SMCVal_t)); | |
inputStructure.data8 = SMC_CMD_READ_INDEX; | |
inputStructure.data32 = i; | |
result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure); | |
if (result != kIOReturnSuccess) | |
continue; | |
_ultostr(key, outputStructure.key); | |
result = SMCReadKey(key, &val); | |
printVal(val); | |
} | |
return kIOReturnSuccess; | |
} | |
kern_return_t SMCPrintFans(void) | |
{ | |
kern_return_t result; | |
SMCVal_t val; | |
UInt32Char_t key; | |
int totalFans, i; | |
result = SMCReadKey("FNum", &val); | |
if (result != kIOReturnSuccess) | |
return kIOReturnError; | |
totalFans = _strtoul(val.bytes, val.dataSize, 10); | |
printf("Total fans in system: %d\n", totalFans); | |
for (i = 0; i < totalFans; i++) | |
{ | |
printf("\nFan #%d:\n", i); | |
sprintf(key, "F%dAc", i); | |
SMCReadKey(key, &val); | |
printf(" Actual speed : %.0f\n", _strtof(val.bytes, val.dataSize, 2)); | |
sprintf(key, "F%dMn", i); | |
SMCReadKey(key, &val); | |
printf(" Minimum speed: %.0f\n", _strtof(val.bytes, val.dataSize, 2)); | |
sprintf(key, "F%dMx", i); | |
SMCReadKey(key, &val); | |
printf(" Maximum speed: %.0f\n", _strtof(val.bytes, val.dataSize, 2)); | |
sprintf(key, "F%dSf", i); | |
SMCReadKey(key, &val); | |
printf(" Safe speed : %.0f\n", _strtof(val.bytes, val.dataSize, 2)); | |
sprintf(key, "F%dTg", i); | |
SMCReadKey(key, &val); | |
printf(" Target speed : %.0f\n", _strtof(val.bytes, val.dataSize, 2)); | |
SMCReadKey("FS! ", &val); | |
if ((_strtoul(val.bytes, 2, 16) & (1 << i)) == 0) | |
printf(" Mode : auto\n"); | |
else | |
printf(" Mode : forced\n"); | |
double temp; | |
temp = SMCGetTemperature(SMC_KEY_CPU_TEMP); | |
printf(" Temp = %g\n", temp); | |
temp = SMCGetTemperature("TB0T"); | |
printf(" Temp TB0T = %g\n", temp); | |
temp = SMCGetTemperature("TC0D"); | |
printf(" Temp TC0D = %g\n", temp); | |
temp = SMCGetTemperature("TC0P"); | |
printf(" Temp TC0P = %g\n", temp); | |
temp = SMCGetTemperature("TM0P"); | |
printf(" Temp TM0P = %g\n", temp); | |
temp = SMCGetTemperature("TN0P"); | |
printf(" Temp TN0P = %g\n", temp); | |
temp = SMCGetTemperature("Th0H"); | |
printf(" Temp Th0H = %g\n", temp); | |
temp = SMCGetTemperature("Ts0P"); | |
printf(" Temp Ts0P = %g\n", temp); | |
temp = SMCGetTemperature("TN1P"); | |
printf(" Temp TN1P = %g\n", temp); | |
temp = SMCGetTemperature("Th1H"); | |
printf(" Temp Th1H = %g\n", temp); | |
} | |
return kIOReturnSuccess; | |
} | |
void usage(char* prog) | |
{ | |
printf("Apple System Management Control (SMC) tool %s\n", VERSION); | |
printf("Usage:\n"); | |
printf("%s [options]\n", prog); | |
printf(" -f : fan info decoded\n"); | |
printf(" -h : help\n"); | |
printf(" -k <key> : key to manipulate\n"); | |
printf(" -l : list all keys and values\n"); | |
printf(" -r : read the value of a key\n"); | |
printf(" -w <value> : write the specified value to a key\n"); | |
printf(" -v : version\n"); | |
printf("\n"); | |
} | |
double SMCGetTemperature(char *key) | |
{ | |
SMCVal_t val; | |
kern_return_t result; | |
result = SMCReadKey(key, &val); | |
if (result == kIOReturnSuccess) { | |
// read succeeded - check returned value | |
if (val.dataSize > 0) { | |
if (strcmp(val.dataType, DATATYPE_SP78) == 0) { | |
// convert fp78 value to temperature | |
int intValue = (val.bytes[0] * 256 + val.bytes[1]) >> 2; | |
return intValue / 64.0; | |
} | |
} | |
} | |
// read failed | |
return 0.0; | |
} | |
kern_return_t SMCSetFanRpm(char *key, int rpm) | |
{ | |
SMCVal_t val; | |
strcpy(val.key, key); | |
val.bytes[0] = (rpm << 2) / 256; | |
val.bytes[1] = (rpm << 2) % 256; | |
val.dataSize = 2; | |
return SMCWriteKey(val); | |
} | |
int SMCGetFanRpm(char *key) | |
{ | |
SMCVal_t val; | |
kern_return_t result; | |
result = SMCReadKey(key, &val); | |
if (result == kIOReturnSuccess) { | |
// read succeeded - check returned value | |
if (val.dataSize > 0) { | |
if (strcmp(val.dataType, DATATYPE_FPE2) == 0) { | |
// convert FPE2 value to int value | |
return (int)_strtof(val.bytes, val.dataSize, 2); | |
} | |
} | |
} | |
// read failed | |
return -1; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
int c; | |
extern char *optarg; | |
extern int optind, optopt, opterr; | |
kern_return_t result; | |
int op = OP_NONE; | |
UInt32Char_t key = "\0"; | |
SMCVal_t val; | |
while ((c = getopt(argc, argv, "fhk:lrw:v")) != -1) | |
{ | |
switch(c) | |
{ | |
case 'f': | |
op = OP_READ_FAN; | |
break; | |
case 'k': | |
if (strlen(optarg) > sizeof(UInt32Char_t)) { | |
memcpy(key, optarg, sizeof(UInt32Char_t)); | |
} else { | |
memcpy(key, optarg, strlen(optarg)); | |
} | |
break; | |
case 'l': | |
op = OP_LIST; | |
break; | |
case 'r': | |
op = OP_READ; | |
break; | |
case 'v': | |
printf("%s\n", VERSION); | |
return 0; | |
break; | |
case 'w': | |
op = OP_WRITE; | |
{ | |
int i; | |
char c[3]; | |
for (i = 0; i < strlen(optarg); i++) | |
{ | |
sprintf(c, "%c%c", optarg[i * 2], optarg[(i * 2) + 1]); | |
val.bytes[i] = (int) strtol(c, NULL, 16); | |
} | |
val.dataSize = i / 2; | |
if ((val.dataSize * 2) != strlen(optarg)) | |
{ | |
printf("Error: value is not valid\n"); | |
return 1; | |
} | |
} | |
break; | |
case 'h': | |
case '?': | |
op = OP_NONE; | |
break; | |
} | |
} | |
if (op == OP_NONE) | |
{ | |
usage(argv[0]); | |
return 1; | |
} | |
SMCOpen(&conn); | |
switch(op) | |
{ | |
case OP_LIST: | |
result = SMCPrintAll(); | |
if (result != kIOReturnSuccess) | |
printf("Error: SMCPrintAll() = %08x\n", result); | |
break; | |
case OP_READ: | |
if (strlen(key) > 0) | |
{ | |
result = SMCReadKey(key, &val); | |
if (result != kIOReturnSuccess) | |
printf("Error: SMCReadKey() = %08x\n", result); | |
else | |
printVal(val); | |
} | |
else | |
{ | |
printf("Error: specify a key to read\n"); | |
} | |
break; | |
case OP_READ_FAN: | |
result = SMCPrintFans(); | |
if (result != kIOReturnSuccess) | |
printf("Error: SMCPrintFans() = %08x\n", result); | |
break; | |
case OP_WRITE: | |
if (strlen(key) > 0) | |
{ | |
memcpy(val.key, key, strlen(key)); | |
result = SMCWriteKey(val); | |
if (result != kIOReturnSuccess) | |
printf("Error: SMCWriteKey() = %08x\n", result); | |
} | |
else | |
{ | |
printf("Error: specify a key to write\n"); | |
} | |
break; | |
} | |
SMCClose(conn); | |
return 0;; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Apple System Management Control (SMC) Tool | |
* Copyright (C) 2006 devnull | |
* | |
* This program is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU General Public License | |
* as published by the Free Software Foundation; either version 2 | |
* of the License, or (at your option) any later version. | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* You should have received a copy of the GNU General Public License | |
* along with this program; if not, write to the Free Software | |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
*/ | |
#ifndef __SMC_H__ | |
#define __SMC_H__ | |
#endif | |
#define VERSION "0.01_2" | |
#define OP_NONE 0 | |
#define OP_LIST 1 | |
#define OP_READ 2 | |
#define OP_READ_FAN 3 | |
#define OP_WRITE 4 | |
#define KERNEL_INDEX_SMC 2 | |
#define SMC_CMD_READ_BYTES 5 | |
#define SMC_CMD_WRITE_BYTES 6 | |
#define SMC_CMD_READ_INDEX 8 | |
#define SMC_CMD_READ_KEYINFO 9 | |
#define SMC_CMD_READ_PLIMIT 11 | |
#define SMC_CMD_READ_VERS 12 | |
#define DATATYPE_FPE2 "fpe2" | |
#define DATATYPE_UINT8 "ui8 " | |
#define DATATYPE_UINT16 "ui16" | |
#define DATATYPE_UINT32 "ui32" | |
#define DATATYPE_SP78 "sp78" | |
// key values | |
#define SMC_KEY_CPU_TEMP "TC0D" | |
#define SMC_KEY_FAN0_RPM_MIN "F0Mn" | |
#define SMC_KEY_FAN1_RPM_MIN "F1Mn" | |
#define SMC_KEY_FAN0_RPM_CUR "F0Ac" | |
#define SMC_KEY_FAN1_RPM_CUR "F1Ac" | |
typedef struct { | |
char major; | |
char minor; | |
char build; | |
char reserved[1]; | |
UInt16 release; | |
} SMCKeyData_vers_t; | |
typedef struct { | |
UInt16 version; | |
UInt16 length; | |
UInt32 cpuPLimit; | |
UInt32 gpuPLimit; | |
UInt32 memPLimit; | |
} SMCKeyData_pLimitData_t; | |
typedef struct { | |
UInt32 dataSize; | |
UInt32 dataType; | |
char dataAttributes; | |
} SMCKeyData_keyInfo_t; | |
typedef char SMCBytes_t[32]; | |
typedef struct { | |
UInt32 key; | |
SMCKeyData_vers_t vers; | |
SMCKeyData_pLimitData_t pLimitData; | |
SMCKeyData_keyInfo_t keyInfo; | |
char result; | |
char status; | |
char data8; | |
UInt32 data32; | |
SMCBytes_t bytes; | |
} SMCKeyData_t; | |
typedef char UInt32Char_t[5]; | |
typedef struct { | |
UInt32Char_t key; | |
UInt32 dataSize; | |
UInt32Char_t dataType; | |
SMCBytes_t bytes; | |
} SMCVal_t; | |
// prototypes | |
double SMCGetTemperature(char *key); | |
kern_return_t SMCSetFanRpm(char *key, int rpm); | |
int SMCGetFanRpm(char *key); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Redistribution of source code included in "ClamNF.app v5.5.5 for Mac OS X 10.5.8 (12/5/2011)" found here http://www.geocities.jp/freeggggroup/nf/
build with command:
usage: