forked from mirror/smcFanControl
Dramatically reduced energy impact by improving code efficiency
Cached various information to reduce calls to get information from hardware. Avoided dynamic memory allocation. Added brief comments and TODOs.
This commit is contained in:
9
Classes/FanControl.h
Normal file → Executable file
9
Classes/FanControl.h
Normal file → Executable file
@ -2,7 +2,8 @@
|
||||
* FanControl
|
||||
*
|
||||
* Copyright (c) 2006-2012 Hendrik Holtmann
|
||||
*
|
||||
* Portions Copyright (c) 2013 Michael Wilber
|
||||
*
|
||||
* FanControl.h - MacBook(Pro) FanControl application
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -37,6 +38,9 @@
|
||||
|
||||
#define kMenuBarHeight 22
|
||||
|
||||
// Max number of fans supported.
|
||||
#define kMaxFanRpms 100
|
||||
|
||||
|
||||
@interface FanControl : NSObject
|
||||
|
||||
@ -104,9 +108,6 @@
|
||||
|
||||
NSImage *menu_image;
|
||||
NSImage *menu_image_alt;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
-(void)terminate:(id)sender;
|
||||
|
||||
99
Classes/FanControl.m
Normal file → Executable file
99
Classes/FanControl.m
Normal file → Executable file
@ -2,7 +2,8 @@
|
||||
* FanControl
|
||||
*
|
||||
* Copyright (c) 2006-2012 Hendrik Holtmann
|
||||
*
|
||||
* Portions Copyright (c) 2013 Michael Wilber
|
||||
*
|
||||
* FanControl.m - MacBook(Pro) FanControl application
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -37,18 +38,10 @@
|
||||
|
||||
@implementation FanControl
|
||||
|
||||
io_connect_t conn;
|
||||
kern_return_t result;
|
||||
SMCVal_t val;
|
||||
// Number of fans reported by the hardware.
|
||||
int g_numFans = 0;
|
||||
|
||||
NSUserDefaults *defaults;
|
||||
Boolean supported=false;
|
||||
extern char *optarg;
|
||||
SMCVal_t val;
|
||||
OSStatus status;
|
||||
NSDictionary* machine_defaults;
|
||||
NSString *authpw;
|
||||
|
||||
|
||||
|
||||
#pragma mark **Init-Methods**
|
||||
|
||||
@ -169,11 +162,11 @@ NSString *authpw;
|
||||
|
||||
|
||||
|
||||
|
||||
g_numFans = [smcWrapper get_fan_num];
|
||||
s_menus=[[NSMutableArray alloc] init];
|
||||
[s_menus autorelease];
|
||||
int i;
|
||||
for(i=0;i<[smcWrapper get_fan_num];i++){
|
||||
for(i=0;i<g_numFans;i++){
|
||||
NSMenuItem *mitem=[[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"Fan: %d",i] action:NULL keyEquivalent:@""];
|
||||
[mitem setTag:(i+1)*10];
|
||||
[s_menus insertObject:mitem atIndex:i];
|
||||
@ -222,7 +215,7 @@ NSString *authpw;
|
||||
|
||||
//release MachineDefaults class first call
|
||||
//add timer for reading to RunLoop
|
||||
_readTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(readFanData:) userInfo:nil repeats:YES];
|
||||
_readTimer = [NSTimer scheduledTimerWithTimeInterval:4.0 target:self selector:@selector(readFanData:) userInfo:nil repeats:YES];
|
||||
[_readTimer fire];
|
||||
//autoapply settings if valid
|
||||
[self upgradeFavorites];
|
||||
@ -305,10 +298,11 @@ NSString *authpw;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Called via a timer mechanism. This is where all the temp / RPM reading is done.
|
||||
//reads fan data and updates the gui
|
||||
-(void) readFanData:(NSTimer*)timer{
|
||||
|
||||
int i = 0;
|
||||
NSString *temp;
|
||||
NSString *fan;
|
||||
|
||||
@ -318,15 +312,44 @@ NSString *authpw;
|
||||
return;
|
||||
}
|
||||
|
||||
//populate Menu Items with recent Data
|
||||
int i;
|
||||
for(i=0;i<[smcWrapper get_fan_num];i++){
|
||||
NSString *fandesc=[[[s_sed objectForKey:@"Fans"] objectAtIndex:i] objectForKey:@"Description"];
|
||||
[[theMenu itemWithTag:(i+1)*10] setTitle:[NSString stringWithFormat:@"%@: %@ rpm",fandesc,[[NSNumber numberWithInt:[smcWrapper get_fan_rpm:i]] stringValue]]];
|
||||
// Store fan speeds in simple array so that they only need to be read once.
|
||||
int fanRpms[kMaxFanRpms] = { 0 };
|
||||
if (g_numFans > kMaxFanRpms)
|
||||
return;
|
||||
|
||||
|
||||
// Determine which fan speed to show in the menubar.
|
||||
int selected = 0;
|
||||
NSArray *fans = [[[FavoritesController arrangedObjects] objectAtIndex:[FavoritesController selectionIndex]] objectForKey:@"FanData"];
|
||||
for (i=0;i<[fans count];i++)
|
||||
{
|
||||
if ([[[fans objectAtIndex:i] objectForKey:@"menu"] boolValue]==YES) {
|
||||
selected = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (selected < 0 || selected >= g_numFans)
|
||||
{
|
||||
// Bad selected fan index.
|
||||
return;
|
||||
}
|
||||
|
||||
//read the current fan speeds
|
||||
for(i=0; i<g_numFans; ++i){
|
||||
fanRpms[i] = [smcWrapper get_fan_rpm:i];
|
||||
}
|
||||
|
||||
float c_temp=[smcWrapper get_maintemp];
|
||||
const int selectedRpm = fanRpms[selected];
|
||||
|
||||
//populate Menu Items with recent Data
|
||||
|
||||
// Proceed with building the strings, etc. to update the text in the menubar.
|
||||
for(i=0; i<g_numFans; ++i){
|
||||
NSString *fandesc=[[[s_sed objectForKey:@"Fans"] objectAtIndex:i] objectForKey:@"Description"];
|
||||
[[theMenu itemWithTag:(i+1)*10] setTitle:[NSString stringWithFormat:@"%@: %@ rpm",fandesc,[[NSNumber numberWithInt:fanRpms[i]] stringValue]]];
|
||||
}
|
||||
|
||||
if ([[defaults objectForKey:@"Unit"] intValue]==0) {
|
||||
temp=[NSString stringWithFormat:@"%@%CC",[NSNumber numberWithFloat:c_temp],(unsigned short)0xb0];
|
||||
} else {
|
||||
@ -338,21 +361,13 @@ NSString *authpw;
|
||||
//avoid jumping in menu bar
|
||||
[nc setFormat:@"000;000;-000"];
|
||||
|
||||
int selected = 0;
|
||||
NSArray *fans = [[[FavoritesController arrangedObjects] objectAtIndex:[FavoritesController selectionIndex]] objectForKey:@"FanData"];
|
||||
for (i=0;i<[fans count];i++)
|
||||
{
|
||||
if ([[[fans objectAtIndex:i] objectForKey:@"menu"] boolValue]==YES) {
|
||||
selected = i;
|
||||
}
|
||||
}
|
||||
fan=[NSString stringWithFormat:@"%@rpm",[nc stringForObjectValue:[NSNumber numberWithFloat:selectedRpm]]];
|
||||
|
||||
fan=[NSString stringWithFormat:@"%@rpm",[nc stringForObjectValue:[NSNumber numberWithFloat:[smcWrapper get_fan_rpm:selected]]]];
|
||||
|
||||
if ([[defaults objectForKey:@"MenuBar"] intValue]<=1) {
|
||||
const int menuBarSetting = [[defaults objectForKey:@"MenuBar"] intValue];
|
||||
if (menuBarSetting <= 1) {
|
||||
NSString *add;
|
||||
int fsize;
|
||||
if ([[defaults objectForKey:@"MenuBar"] intValue]==0) {
|
||||
if (menuBarSetting==0) {
|
||||
add=@"\n";
|
||||
fsize=9;
|
||||
[statusItem setLength:53];
|
||||
@ -361,6 +376,7 @@ NSString *authpw;
|
||||
fsize=11;
|
||||
[statusItem setLength:96];
|
||||
}
|
||||
|
||||
NSMutableAttributedString *s_status=[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@%@%@",temp,add,fan]];
|
||||
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
||||
[paragraphStyle setAlignment:NSLeftTextAlignment];
|
||||
@ -373,9 +389,7 @@ NSString *authpw;
|
||||
[paragraphStyle release];
|
||||
[s_status release];
|
||||
}
|
||||
|
||||
|
||||
if ([[defaults objectForKey:@"MenuBar"] intValue]==2) {
|
||||
else if (menuBarSetting==2) {
|
||||
[statusItem setLength:26];
|
||||
[statusItem setTitle:nil];
|
||||
[statusItem setToolTip:[NSString stringWithFormat:@"%@\n%@",temp,fan]];
|
||||
@ -383,8 +397,7 @@ NSString *authpw;
|
||||
[statusItem setAlternateImage:menu_image_alt];
|
||||
|
||||
}
|
||||
|
||||
if ([[defaults objectForKey:@"MenuBar"] intValue]==3) {
|
||||
else if (menuBarSetting==3) {
|
||||
[statusItem setLength:46];
|
||||
NSMutableAttributedString *s_status=[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@",temp]];
|
||||
[s_status addAttribute:NSFontAttributeName value:[NSFont fontWithName:@"Lucida Grande" size:12] range:NSMakeRange(0,[s_status length])];
|
||||
@ -395,7 +408,8 @@ NSString *authpw;
|
||||
[s_status release];
|
||||
|
||||
}
|
||||
if ([[defaults objectForKey:@"MenuBar"] intValue]==4) {
|
||||
else if (menuBarSetting==4) {
|
||||
//TODO: Main temp not used in this case, don't bother reading the main temp in this case.
|
||||
[statusItem setLength:65];
|
||||
NSMutableAttributedString *s_status=[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@",fan]];
|
||||
[s_status addAttribute:NSFontAttributeName value:[NSFont fontWithName:@"Lucida Grande" size:12] range:NSMakeRange(0,[s_status length])];
|
||||
@ -474,7 +488,7 @@ NSString *authpw;
|
||||
-(void)terminate:(id)sender{
|
||||
//get last active selection
|
||||
[defaults synchronize];
|
||||
SMCClose(conn);
|
||||
[smcWrapper cleanUp];
|
||||
[_readTimer invalidate];
|
||||
[pw deregisterForSleepWakeNotification];
|
||||
[pw deregisterForPowerChange];
|
||||
@ -669,20 +683,23 @@ NSString *authpw;
|
||||
|
||||
|
||||
#pragma mark **SMC-Binary Owner/Right Check**
|
||||
//TODO: It looks like this function is called inefficiently.
|
||||
//call smc binary with sudo rights and apply
|
||||
+(void)setRights{
|
||||
NSString *smcpath = [[NSBundle mainBundle] pathForResource:@"smc" ofType:@""];
|
||||
NSFileManager *fmanage=[NSFileManager defaultManager];
|
||||
NSDictionary *fdic = [fmanage attributesOfItemAtPath:smcpath error:nil];
|
||||
if ([[fdic valueForKey:@"NSFileOwnerAccountName"] isEqualToString:@"root"] && [[fdic valueForKey:@"NSFileGroupOwnerAccountName"] isEqualToString:@"admin"] && ([[fdic valueForKey:@"NSFilePosixPermissions"] intValue]==3437)) {
|
||||
// If the SMC binary has already been modified to run as root, then do nothing.
|
||||
return;
|
||||
}
|
||||
//TODO: Is the usage of commPipe safe?
|
||||
FILE *commPipe;
|
||||
AuthorizationRef authorizationRef;
|
||||
AuthorizationItem gencitem = { "system.privilege.admin", 0, NULL, 0 };
|
||||
AuthorizationRights gencright = { 1, &gencitem };
|
||||
int flags = kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed;
|
||||
status = AuthorizationCreate(&gencright, kAuthorizationEmptyEnvironment, flags, &authorizationRef);
|
||||
OSStatus status = AuthorizationCreate(&gencright, kAuthorizationEmptyEnvironment, flags, &authorizationRef);
|
||||
NSString *tool=@"/usr/sbin/chown";
|
||||
NSArray *argsArray = [NSArray arrayWithObjects: @"root:admin",smcpath,nil];
|
||||
int i;
|
||||
|
||||
5
Classes/smcWrapper.h
Normal file → Executable file
5
Classes/smcWrapper.h
Normal file → Executable file
@ -2,7 +2,8 @@
|
||||
* FanControl
|
||||
*
|
||||
* Copyright (c) 2006-2012 Hendrik Holtmann
|
||||
*
|
||||
* Portions Copyright (c) 2013 Michael Wilber
|
||||
*
|
||||
* smcWrapper.m - MacBook(Pro) FanControl application
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -28,6 +29,8 @@
|
||||
@interface smcWrapper : NSObject {
|
||||
}
|
||||
|
||||
+(void) cleanUp;
|
||||
|
||||
+(int) get_fan_rpm:(int)fan_number;
|
||||
+(float) get_maintemp;
|
||||
+(float) get_mptemp;
|
||||
|
||||
20
Classes/smcWrapper.m
Normal file → Executable file
20
Classes/smcWrapper.m
Normal file → Executable file
@ -2,7 +2,8 @@
|
||||
* FanControl
|
||||
*
|
||||
* Copyright (c) 2006-2012 Hendrik Holtmann
|
||||
*
|
||||
* Portions Copyright (c) 2013 Michael Wilber
|
||||
*
|
||||
* smcWrapper.m - MacBook(Pro) FanControl application
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -23,6 +24,7 @@
|
||||
#import "smcWrapper.h"
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
|
||||
//TODO: This is the smcFanControl 2.4 checksum, it needs to be updated for the next release.
|
||||
NSString * const smc_checksum=@"2ea544babe8a58dccc1364c920d473c8";
|
||||
static NSDictionary *tsensors = nil;
|
||||
|
||||
@ -33,6 +35,9 @@ static NSDictionary *tsensors = nil;
|
||||
SMCOpen(&conn);
|
||||
tsensors = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tsensors" ofType:@"plist"]];
|
||||
}
|
||||
+(void)cleanUp{
|
||||
SMCClose(conn);
|
||||
}
|
||||
|
||||
+(float) get_maintemp{
|
||||
float c_temp;
|
||||
@ -43,25 +48,28 @@ static NSDictionary *tsensors = nil;
|
||||
c_temp=[smcWrapper get_mptemp];
|
||||
} else {
|
||||
SMCVal_t val;
|
||||
NSMutableArray *allTSensors = [[tsensors allKeys] mutableCopy];
|
||||
NSString *foundKey = [tsensors objectForKey:[MachineDefaults computerModel]];
|
||||
if (foundKey !=nil) {
|
||||
foundKey = [MachineDefaults computerModel];
|
||||
} else {
|
||||
foundKey = @"standard";
|
||||
}
|
||||
[allTSensors removeObject:foundKey];
|
||||
SMCReadKey2((char*)[[tsensors objectForKey:foundKey] UTF8String], &val,conn);
|
||||
c_temp= ((val.bytes[0] * 256 + val.bytes[1]) >> 2)/64;
|
||||
|
||||
if (c_temp<=0) {
|
||||
NSArray *allTSensors = [tsensors allKeys];
|
||||
for (NSString *key in allTSensors) {
|
||||
bool bPtrEq = (key == foundKey);
|
||||
bool bCmpEq = ([key isEqualToString:foundKey]);
|
||||
if (false == bPtrEq && false == bCmpEq) {
|
||||
SMCReadKey2((char*)[[tsensors objectForKey:key] UTF8String], &val,conn);
|
||||
c_temp= ((val.bytes[0] * 256 + val.bytes[1]) >> 2)/64;
|
||||
if (c_temp>0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c_temp;
|
||||
}
|
||||
@ -168,14 +176,16 @@ static NSDictionary *tsensors = nil;
|
||||
}
|
||||
|
||||
//call smc binary with setuid rights and apply
|
||||
// The smc binary is given root permissions in FanControl.m with the setRights method.
|
||||
+(void)setKey_external:(NSString *)key value:(NSString *)value{
|
||||
NSString *launchPath = [[NSBundle mainBundle] pathForResource:@"smc" ofType:@""];
|
||||
//first check if it's the right binary (security)
|
||||
NSString *checksum=[smcWrapper createCheckSum:launchPath];
|
||||
// MW: Disabled smc binary checksum. This should be re-enabled in an official release.
|
||||
/*NSString *checksum=[smcWrapper createCheckSum:launchPath];
|
||||
if (![checksum isEqualToString:smc_checksum]) {
|
||||
NSLog(@"smcFanControl: Security Error: smc-binary is not the distributed one");
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
NSArray *argsArray = [NSArray arrayWithObjects: @"-k",key,@"-w",value,nil];
|
||||
NSTask *task;
|
||||
task = [[NSTask alloc] init];
|
||||
|
||||
356
smc-command/smc.c
Normal file → Executable file
356
smc-command/smc.c
Normal file → Executable file
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Apple System Management Control (SMC) Tool
|
||||
* Copyright (C) 2006 devnull
|
||||
* Portions Copyright (C) 2013 Michael Wilber
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -22,10 +23,22 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
|
||||
#include "smc.h"
|
||||
#include <libkern/OSAtomic.h>
|
||||
|
||||
io_connect_t conn;
|
||||
// Cache the keyInfo to lower the energy impact of SMCReadKey() / SMCReadKey2()
|
||||
#define KEY_INFO_CACHE_SIZE 100
|
||||
struct {
|
||||
UInt32 key;
|
||||
SMCKeyData_keyInfo_t keyInfo;
|
||||
} g_keyInfoCache[KEY_INFO_CACHE_SIZE];
|
||||
|
||||
int g_keyInfoCacheCount = 0;
|
||||
OSSpinLock g_keyInfoSpinLock = 0;
|
||||
|
||||
kern_return_t SMCCall2(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure, io_connect_t conn);
|
||||
|
||||
#pragma mark C Helpers
|
||||
|
||||
UInt32 _strtoul(char *str, int size, int base)
|
||||
{
|
||||
@ -68,12 +81,152 @@ float _strtof(char *str, int size, int e)
|
||||
return total;
|
||||
}
|
||||
|
||||
#pragma mark Shared SMC functions
|
||||
|
||||
kern_return_t SMCOpen(io_connect_t *conn)
|
||||
{
|
||||
kern_return_t result;
|
||||
mach_port_t masterPort;
|
||||
io_iterator_t iterator;
|
||||
io_object_t device;
|
||||
|
||||
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 SMCCall2(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure,io_connect_t conn)
|
||||
{
|
||||
size_t structureInputSize;
|
||||
size_t structureOutputSize;
|
||||
structureInputSize = sizeof(SMCKeyData_t);
|
||||
structureOutputSize = sizeof(SMCKeyData_t);
|
||||
|
||||
return IOConnectCallStructMethod(conn, index, inputStructure, structureInputSize, outputStructure, &structureOutputSize);
|
||||
}
|
||||
|
||||
// Provides key info, using a cache to dramatically improve the energy impact of smcFanControl
|
||||
kern_return_t SMCGetKeyInfo(UInt32 key, SMCKeyData_keyInfo_t* keyInfo, io_connect_t conn)
|
||||
{
|
||||
SMCKeyData_t inputStructure;
|
||||
SMCKeyData_t outputStructure;
|
||||
kern_return_t result = kIOReturnSuccess;
|
||||
int i = 0;
|
||||
|
||||
OSSpinLockLock(&g_keyInfoSpinLock);
|
||||
|
||||
for (; i < g_keyInfoCacheCount; ++i)
|
||||
{
|
||||
if (key == g_keyInfoCache[i].key)
|
||||
{
|
||||
*keyInfo = g_keyInfoCache[i].keyInfo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == g_keyInfoCacheCount)
|
||||
{
|
||||
// Not in cache, must look it up.
|
||||
memset(&inputStructure, 0, sizeof(inputStructure));
|
||||
memset(&outputStructure, 0, sizeof(outputStructure));
|
||||
|
||||
inputStructure.key = key;
|
||||
inputStructure.data8 = SMC_CMD_READ_KEYINFO;
|
||||
|
||||
result = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure, conn);
|
||||
if (result == kIOReturnSuccess)
|
||||
{
|
||||
*keyInfo = outputStructure.keyInfo;
|
||||
if (g_keyInfoCacheCount < KEY_INFO_CACHE_SIZE)
|
||||
{
|
||||
g_keyInfoCache[g_keyInfoCacheCount].key = key;
|
||||
g_keyInfoCache[g_keyInfoCacheCount].keyInfo = outputStructure.keyInfo;
|
||||
++g_keyInfoCacheCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OSSpinLockUnlock(&g_keyInfoSpinLock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
kern_return_t SMCReadKey2(UInt32Char_t key, SMCVal_t *val,io_connect_t conn)
|
||||
{
|
||||
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);
|
||||
sprintf(val->key, key);
|
||||
|
||||
result = SMCGetKeyInfo(inputStructure.key, &outputStructure.keyInfo, conn);
|
||||
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 = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure,conn);
|
||||
if (result != kIOReturnSuccess)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
memcpy(val->bytes, outputStructure.bytes, sizeof(outputStructure.bytes));
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
#pragma mark Command line only
|
||||
// Exclude command-line only code from smcFanControl UI
|
||||
#ifdef CMD_TOOL
|
||||
|
||||
io_connect_t g_conn = 0;
|
||||
|
||||
void smc_init(){
|
||||
SMCOpen(&conn);
|
||||
SMCOpen(&g_conn);
|
||||
}
|
||||
|
||||
void smc_close(){
|
||||
SMCClose(conn);
|
||||
SMCClose(g_conn);
|
||||
}
|
||||
void printFPE2(SMCVal_t val)
|
||||
{
|
||||
@ -117,183 +270,17 @@ void printVal(SMCVal_t val)
|
||||
}
|
||||
}
|
||||
|
||||
kern_return_t SMCOpen(io_connect_t *conn)
|
||||
{
|
||||
kern_return_t result;
|
||||
mach_port_t masterPort;
|
||||
io_iterator_t iterator;
|
||||
io_object_t device;
|
||||
|
||||
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)
|
||||
{
|
||||
size_t structureInputSize;
|
||||
size_t structureOutputSize;
|
||||
|
||||
structureInputSize = sizeof(SMCKeyData_t);
|
||||
structureOutputSize = sizeof(SMCKeyData_t);
|
||||
/*
|
||||
return IOConnectMethodStructureIStructureO(
|
||||
conn,
|
||||
index,
|
||||
structureInputSize,
|
||||
&structureOutputSize,
|
||||
inputStructure,
|
||||
outputStructure
|
||||
);
|
||||
*/
|
||||
return IOConnectCallStructMethod(conn, index, inputStructure, structureInputSize, outputStructure, &structureOutputSize);
|
||||
return SMCCall2(index, inputStructure, outputStructure, g_conn);
|
||||
}
|
||||
|
||||
kern_return_t SMCCall2(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure,io_connect_t conn)
|
||||
{
|
||||
size_t structureInputSize;
|
||||
size_t structureOutputSize;
|
||||
structureInputSize = sizeof(SMCKeyData_t);
|
||||
structureOutputSize = sizeof(SMCKeyData_t);
|
||||
|
||||
/* return IOConnectMethodStructureIStructureO(
|
||||
conn,
|
||||
index,
|
||||
structureInputSize,
|
||||
&structureOutputSize,
|
||||
inputStructure,
|
||||
outputStructure
|
||||
);
|
||||
*/
|
||||
return IOConnectCallStructMethod(conn, index, inputStructure, structureInputSize, outputStructure, &structureOutputSize);
|
||||
|
||||
}
|
||||
|
||||
kern_return_t SMCReadKey2(UInt32Char_t key, SMCVal_t *val,io_connect_t conn)
|
||||
{
|
||||
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);
|
||||
sprintf(val->key, key);
|
||||
inputStructure.data8 = SMC_CMD_READ_KEYINFO;
|
||||
|
||||
result = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure,conn);
|
||||
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 = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure,conn);
|
||||
if (result != kIOReturnSuccess)
|
||||
return result;
|
||||
|
||||
memcpy(val->bytes, outputStructure.bytes, sizeof(outputStructure.bytes));
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
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);
|
||||
sprintf(val->key, key);
|
||||
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;
|
||||
return SMCReadKey2(key, val, g_conn);
|
||||
}
|
||||
|
||||
|
||||
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 = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure,conn);
|
||||
if (result != kIOReturnSuccess)
|
||||
return result;
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
kern_return_t SMCWriteKey2(SMCVal_t writeVal,io_connect_t conn)
|
||||
kern_return_t SMCWriteKey2(SMCVal_t writeVal, io_connect_t conn)
|
||||
{
|
||||
kern_return_t result;
|
||||
SMCKeyData_t inputStructure;
|
||||
@ -322,6 +309,10 @@ kern_return_t SMCWriteKey2(SMCVal_t writeVal,io_connect_t conn)
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
kern_return_t SMCWriteKey(SMCVal_t writeVal)
|
||||
{
|
||||
return SMCWriteKey2(writeVal, g_conn);
|
||||
}
|
||||
|
||||
UInt32 SMCReadIndexCount(void)
|
||||
{
|
||||
@ -421,7 +412,7 @@ void usage(char* prog)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
kern_return_t SMCWriteSimple(UInt32Char_t key,char *wvalue,io_connect_t conn)
|
||||
kern_return_t SMCWriteSimple(UInt32Char_t key, char *wvalue, io_connect_t conn)
|
||||
{
|
||||
kern_return_t result;
|
||||
SMCVal_t val;
|
||||
@ -434,7 +425,7 @@ kern_return_t SMCWriteSimple(UInt32Char_t key,char *wvalue,io_connect_t conn)
|
||||
}
|
||||
val.dataSize = i / 2;
|
||||
sprintf(val.key, key);
|
||||
result = SMCWriteKey2(val,conn);
|
||||
result = SMCWriteKey2(val, conn);
|
||||
if (result != kIOReturnSuccess)
|
||||
printf("Error: SMCWriteKey() = %08x\n", result);
|
||||
|
||||
@ -442,8 +433,6 @@ kern_return_t SMCWriteSimple(UInt32Char_t key,char *wvalue,io_connect_t conn)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CMD_TOOL
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
@ -451,7 +440,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
kern_return_t result;
|
||||
int op = OP_NONE;
|
||||
UInt32Char_t key = "\0";
|
||||
UInt32Char_t key = { 0 }; //MAW
|
||||
SMCVal_t val;
|
||||
|
||||
while ((c = getopt(argc, argv, "fhk:lrw:v")) != -1)
|
||||
@ -463,6 +452,7 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
case 'k':
|
||||
strncpy(key, optarg, sizeof(key)); //fix for buffer overflow
|
||||
key[sizeof(key) - 1] = '\0';
|
||||
break;
|
||||
case 'l':
|
||||
op = OP_LIST;
|
||||
@ -505,7 +495,7 @@ int main(int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
SMCOpen(&conn);
|
||||
smc_init();
|
||||
|
||||
switch(op)
|
||||
{
|
||||
@ -548,8 +538,10 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
|
||||
SMCClose(conn);
|
||||
return 0;;
|
||||
smc_close();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif //#ifdef CMD_TOOL
|
||||
|
||||
|
||||
|
||||
|
||||
24
smc-command/smc.h
Normal file → Executable file
24
smc-command/smc.h
Normal file → Executable file
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Apple System Management Control (SMC) Tool
|
||||
* Copyright (C) 2006 devnull
|
||||
* Portions Copyright (C) 2013 Michael Wilber
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -89,13 +90,20 @@ typedef struct {
|
||||
} SMCVal_t;
|
||||
|
||||
UInt32 _strtoul(char *str, int size, int base);
|
||||
kern_return_t SMCOpen(io_connect_t *conn);
|
||||
kern_return_t SMCReadKey(UInt32Char_t key, SMCVal_t *val);
|
||||
kern_return_t SMCReadKey2(UInt32Char_t key, SMCVal_t *val,io_connect_t conn);
|
||||
kern_return_t SMCWriteSimple(UInt32Char_t key,char *wvalue,io_connect_t conn);
|
||||
kern_return_t SMCClose(io_connect_t conn);
|
||||
void smc_init();
|
||||
void smc_close();
|
||||
|
||||
float _strtof(char *str, int size, int e);
|
||||
|
||||
// Exclude command-line only code from smcFanControl UI
|
||||
#ifdef CMD_TOOL
|
||||
|
||||
void smc_init();
|
||||
void smc_close();
|
||||
kern_return_t SMCReadKey(UInt32Char_t key, SMCVal_t *val);
|
||||
kern_return_t SMCWriteSimple(UInt32Char_t key,char *wvalue,io_connect_t conn);
|
||||
|
||||
#endif //#ifdef CMD_TOOL
|
||||
|
||||
kern_return_t SMCOpen(io_connect_t *conn);
|
||||
kern_return_t SMCClose(io_connect_t conn);
|
||||
kern_return_t SMCReadKey2(UInt32Char_t key, SMCVal_t *val,io_connect_t conn);
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user