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
|
* FanControl
|
||||||
*
|
*
|
||||||
* Copyright (c) 2006-2012 Hendrik Holtmann
|
* Copyright (c) 2006-2012 Hendrik Holtmann
|
||||||
*
|
* Portions Copyright (c) 2013 Michael Wilber
|
||||||
|
*
|
||||||
* FanControl.h - MacBook(Pro) FanControl application
|
* FanControl.h - MacBook(Pro) FanControl application
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@ -37,6 +38,9 @@
|
|||||||
|
|
||||||
#define kMenuBarHeight 22
|
#define kMenuBarHeight 22
|
||||||
|
|
||||||
|
// Max number of fans supported.
|
||||||
|
#define kMaxFanRpms 100
|
||||||
|
|
||||||
|
|
||||||
@interface FanControl : NSObject
|
@interface FanControl : NSObject
|
||||||
|
|
||||||
@ -104,9 +108,6 @@
|
|||||||
|
|
||||||
NSImage *menu_image;
|
NSImage *menu_image;
|
||||||
NSImage *menu_image_alt;
|
NSImage *menu_image_alt;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)terminate:(id)sender;
|
-(void)terminate:(id)sender;
|
||||||
|
|||||||
111
Classes/FanControl.m
Normal file → Executable file
111
Classes/FanControl.m
Normal file → Executable file
@ -2,7 +2,8 @@
|
|||||||
* FanControl
|
* FanControl
|
||||||
*
|
*
|
||||||
* Copyright (c) 2006-2012 Hendrik Holtmann
|
* Copyright (c) 2006-2012 Hendrik Holtmann
|
||||||
*
|
* Portions Copyright (c) 2013 Michael Wilber
|
||||||
|
*
|
||||||
* FanControl.m - MacBook(Pro) FanControl application
|
* FanControl.m - MacBook(Pro) FanControl application
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@ -37,18 +38,10 @@
|
|||||||
|
|
||||||
@implementation FanControl
|
@implementation FanControl
|
||||||
|
|
||||||
io_connect_t conn;
|
// Number of fans reported by the hardware.
|
||||||
kern_return_t result;
|
int g_numFans = 0;
|
||||||
SMCVal_t val;
|
|
||||||
NSUserDefaults *defaults;
|
NSUserDefaults *defaults;
|
||||||
Boolean supported=false;
|
|
||||||
extern char *optarg;
|
|
||||||
SMCVal_t val;
|
|
||||||
OSStatus status;
|
|
||||||
NSDictionary* machine_defaults;
|
|
||||||
NSString *authpw;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark **Init-Methods**
|
#pragma mark **Init-Methods**
|
||||||
|
|
||||||
@ -100,7 +93,7 @@ NSString *authpw;
|
|||||||
}
|
}
|
||||||
|
|
||||||
-(void) awakeFromNib {
|
-(void) awakeFromNib {
|
||||||
|
|
||||||
s_sed = nil;
|
s_sed = nil;
|
||||||
pw=[[Power alloc] init];
|
pw=[[Power alloc] init];
|
||||||
[pw setDelegate:self];
|
[pw setDelegate:self];
|
||||||
@ -169,11 +162,11 @@ NSString *authpw;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
g_numFans = [smcWrapper get_fan_num];
|
||||||
s_menus=[[NSMutableArray alloc] init];
|
s_menus=[[NSMutableArray alloc] init];
|
||||||
[s_menus autorelease];
|
[s_menus autorelease];
|
||||||
int i;
|
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:@""];
|
NSMenuItem *mitem=[[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"Fan: %d",i] action:NULL keyEquivalent:@""];
|
||||||
[mitem setTag:(i+1)*10];
|
[mitem setTag:(i+1)*10];
|
||||||
[s_menus insertObject:mitem atIndex:i];
|
[s_menus insertObject:mitem atIndex:i];
|
||||||
@ -222,7 +215,7 @@ NSString *authpw;
|
|||||||
|
|
||||||
//release MachineDefaults class first call
|
//release MachineDefaults class first call
|
||||||
//add timer for reading to RunLoop
|
//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];
|
[_readTimer fire];
|
||||||
//autoapply settings if valid
|
//autoapply settings if valid
|
||||||
[self upgradeFavorites];
|
[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
|
//reads fan data and updates the gui
|
||||||
-(void) readFanData:(NSTimer*)timer{
|
-(void) readFanData:(NSTimer*)timer{
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
NSString *temp;
|
NSString *temp;
|
||||||
NSString *fan;
|
NSString *fan;
|
||||||
|
|
||||||
@ -317,16 +311,45 @@ NSString *authpw;
|
|||||||
if (s_sed==nil) {
|
if (s_sed==nil) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//populate Menu Items with recent Data
|
// Store fan speeds in simple array so that they only need to be read once.
|
||||||
int i;
|
int fanRpms[kMaxFanRpms] = { 0 };
|
||||||
for(i=0;i<[smcWrapper get_fan_num];i++){
|
if (g_numFans > kMaxFanRpms)
|
||||||
NSString *fandesc=[[[s_sed objectForKey:@"Fans"] objectAtIndex:i] objectForKey:@"Description"];
|
return;
|
||||||
[[theMenu itemWithTag:(i+1)*10] setTitle:[NSString stringWithFormat:@"%@: %@ rpm",fandesc,[[NSNumber numberWithInt:[smcWrapper get_fan_rpm:i]] stringValue]]];
|
|
||||||
|
|
||||||
|
// 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];
|
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) {
|
if ([[defaults objectForKey:@"Unit"] intValue]==0) {
|
||||||
temp=[NSString stringWithFormat:@"%@%CC",[NSNumber numberWithFloat:c_temp],(unsigned short)0xb0];
|
temp=[NSString stringWithFormat:@"%@%CC",[NSNumber numberWithFloat:c_temp],(unsigned short)0xb0];
|
||||||
} else {
|
} else {
|
||||||
@ -338,21 +361,13 @@ NSString *authpw;
|
|||||||
//avoid jumping in menu bar
|
//avoid jumping in menu bar
|
||||||
[nc setFormat:@"000;000;-000"];
|
[nc setFormat:@"000;000;-000"];
|
||||||
|
|
||||||
int selected = 0;
|
fan=[NSString stringWithFormat:@"%@rpm",[nc stringForObjectValue:[NSNumber numberWithFloat:selectedRpm]]];
|
||||||
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:[smcWrapper get_fan_rpm:selected]]]];
|
|
||||||
|
|
||||||
if ([[defaults objectForKey:@"MenuBar"] intValue]<=1) {
|
const int menuBarSetting = [[defaults objectForKey:@"MenuBar"] intValue];
|
||||||
|
if (menuBarSetting <= 1) {
|
||||||
NSString *add;
|
NSString *add;
|
||||||
int fsize;
|
int fsize;
|
||||||
if ([[defaults objectForKey:@"MenuBar"] intValue]==0) {
|
if (menuBarSetting==0) {
|
||||||
add=@"\n";
|
add=@"\n";
|
||||||
fsize=9;
|
fsize=9;
|
||||||
[statusItem setLength:53];
|
[statusItem setLength:53];
|
||||||
@ -361,6 +376,7 @@ NSString *authpw;
|
|||||||
fsize=11;
|
fsize=11;
|
||||||
[statusItem setLength:96];
|
[statusItem setLength:96];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSMutableAttributedString *s_status=[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@%@%@",temp,add,fan]];
|
NSMutableAttributedString *s_status=[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@%@%@",temp,add,fan]];
|
||||||
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
||||||
[paragraphStyle setAlignment:NSLeftTextAlignment];
|
[paragraphStyle setAlignment:NSLeftTextAlignment];
|
||||||
@ -373,9 +389,7 @@ NSString *authpw;
|
|||||||
[paragraphStyle release];
|
[paragraphStyle release];
|
||||||
[s_status release];
|
[s_status release];
|
||||||
}
|
}
|
||||||
|
else if (menuBarSetting==2) {
|
||||||
|
|
||||||
if ([[defaults objectForKey:@"MenuBar"] intValue]==2) {
|
|
||||||
[statusItem setLength:26];
|
[statusItem setLength:26];
|
||||||
[statusItem setTitle:nil];
|
[statusItem setTitle:nil];
|
||||||
[statusItem setToolTip:[NSString stringWithFormat:@"%@\n%@",temp,fan]];
|
[statusItem setToolTip:[NSString stringWithFormat:@"%@\n%@",temp,fan]];
|
||||||
@ -383,8 +397,7 @@ NSString *authpw;
|
|||||||
[statusItem setAlternateImage:menu_image_alt];
|
[statusItem setAlternateImage:menu_image_alt];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else if (menuBarSetting==3) {
|
||||||
if ([[defaults objectForKey:@"MenuBar"] intValue]==3) {
|
|
||||||
[statusItem setLength:46];
|
[statusItem setLength:46];
|
||||||
NSMutableAttributedString *s_status=[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@",temp]];
|
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])];
|
[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];
|
[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];
|
[statusItem setLength:65];
|
||||||
NSMutableAttributedString *s_status=[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@",fan]];
|
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])];
|
[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{
|
-(void)terminate:(id)sender{
|
||||||
//get last active selection
|
//get last active selection
|
||||||
[defaults synchronize];
|
[defaults synchronize];
|
||||||
SMCClose(conn);
|
[smcWrapper cleanUp];
|
||||||
[_readTimer invalidate];
|
[_readTimer invalidate];
|
||||||
[pw deregisterForSleepWakeNotification];
|
[pw deregisterForSleepWakeNotification];
|
||||||
[pw deregisterForPowerChange];
|
[pw deregisterForPowerChange];
|
||||||
@ -669,20 +683,23 @@ NSString *authpw;
|
|||||||
|
|
||||||
|
|
||||||
#pragma mark **SMC-Binary Owner/Right Check**
|
#pragma mark **SMC-Binary Owner/Right Check**
|
||||||
|
//TODO: It looks like this function is called inefficiently.
|
||||||
//call smc binary with sudo rights and apply
|
//call smc binary with sudo rights and apply
|
||||||
+(void)setRights{
|
+(void)setRights{
|
||||||
NSString *smcpath = [[NSBundle mainBundle] pathForResource:@"smc" ofType:@""];
|
NSString *smcpath = [[NSBundle mainBundle] pathForResource:@"smc" ofType:@""];
|
||||||
NSFileManager *fmanage=[NSFileManager defaultManager];
|
NSFileManager *fmanage=[NSFileManager defaultManager];
|
||||||
NSDictionary *fdic = [fmanage attributesOfItemAtPath:smcpath error:nil];
|
NSDictionary *fdic = [fmanage attributesOfItemAtPath:smcpath error:nil];
|
||||||
if ([[fdic valueForKey:@"NSFileOwnerAccountName"] isEqualToString:@"root"] && [[fdic valueForKey:@"NSFileGroupOwnerAccountName"] isEqualToString:@"admin"] && ([[fdic valueForKey:@"NSFilePosixPermissions"] intValue]==3437)) {
|
if ([[fdic valueForKey:@"NSFileOwnerAccountName"] isEqualToString:@"root"] && [[fdic valueForKey:@"NSFileGroupOwnerAccountName"] isEqualToString:@"admin"] && ([[fdic valueForKey:@"NSFilePosixPermissions"] intValue]==3437)) {
|
||||||
return;
|
// 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;
|
FILE *commPipe;
|
||||||
AuthorizationRef authorizationRef;
|
AuthorizationRef authorizationRef;
|
||||||
AuthorizationItem gencitem = { "system.privilege.admin", 0, NULL, 0 };
|
AuthorizationItem gencitem = { "system.privilege.admin", 0, NULL, 0 };
|
||||||
AuthorizationRights gencright = { 1, &gencitem };
|
AuthorizationRights gencright = { 1, &gencitem };
|
||||||
int flags = kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed;
|
int flags = kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed;
|
||||||
status = AuthorizationCreate(&gencright, kAuthorizationEmptyEnvironment, flags, &authorizationRef);
|
OSStatus status = AuthorizationCreate(&gencright, kAuthorizationEmptyEnvironment, flags, &authorizationRef);
|
||||||
NSString *tool=@"/usr/sbin/chown";
|
NSString *tool=@"/usr/sbin/chown";
|
||||||
NSArray *argsArray = [NSArray arrayWithObjects: @"root:admin",smcpath,nil];
|
NSArray *argsArray = [NSArray arrayWithObjects: @"root:admin",smcpath,nil];
|
||||||
int i;
|
int i;
|
||||||
|
|||||||
5
Classes/smcWrapper.h
Normal file → Executable file
5
Classes/smcWrapper.h
Normal file → Executable file
@ -2,7 +2,8 @@
|
|||||||
* FanControl
|
* FanControl
|
||||||
*
|
*
|
||||||
* Copyright (c) 2006-2012 Hendrik Holtmann
|
* Copyright (c) 2006-2012 Hendrik Holtmann
|
||||||
*
|
* Portions Copyright (c) 2013 Michael Wilber
|
||||||
|
*
|
||||||
* smcWrapper.m - MacBook(Pro) FanControl application
|
* smcWrapper.m - MacBook(Pro) FanControl application
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@ -28,6 +29,8 @@
|
|||||||
@interface smcWrapper : NSObject {
|
@interface smcWrapper : NSObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+(void) cleanUp;
|
||||||
|
|
||||||
+(int) get_fan_rpm:(int)fan_number;
|
+(int) get_fan_rpm:(int)fan_number;
|
||||||
+(float) get_maintemp;
|
+(float) get_maintemp;
|
||||||
+(float) get_mptemp;
|
+(float) get_mptemp;
|
||||||
|
|||||||
26
Classes/smcWrapper.m
Normal file → Executable file
26
Classes/smcWrapper.m
Normal file → Executable file
@ -2,7 +2,8 @@
|
|||||||
* FanControl
|
* FanControl
|
||||||
*
|
*
|
||||||
* Copyright (c) 2006-2012 Hendrik Holtmann
|
* Copyright (c) 2006-2012 Hendrik Holtmann
|
||||||
*
|
* Portions Copyright (c) 2013 Michael Wilber
|
||||||
|
*
|
||||||
* smcWrapper.m - MacBook(Pro) FanControl application
|
* smcWrapper.m - MacBook(Pro) FanControl application
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@ -23,6 +24,7 @@
|
|||||||
#import "smcWrapper.h"
|
#import "smcWrapper.h"
|
||||||
#import <CommonCrypto/CommonDigest.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";
|
NSString * const smc_checksum=@"2ea544babe8a58dccc1364c920d473c8";
|
||||||
static NSDictionary *tsensors = nil;
|
static NSDictionary *tsensors = nil;
|
||||||
|
|
||||||
@ -33,6 +35,9 @@ static NSDictionary *tsensors = nil;
|
|||||||
SMCOpen(&conn);
|
SMCOpen(&conn);
|
||||||
tsensors = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tsensors" ofType:@"plist"]];
|
tsensors = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tsensors" ofType:@"plist"]];
|
||||||
}
|
}
|
||||||
|
+(void)cleanUp{
|
||||||
|
SMCClose(conn);
|
||||||
|
}
|
||||||
|
|
||||||
+(float) get_maintemp{
|
+(float) get_maintemp{
|
||||||
float c_temp;
|
float c_temp;
|
||||||
@ -43,22 +48,25 @@ static NSDictionary *tsensors = nil;
|
|||||||
c_temp=[smcWrapper get_mptemp];
|
c_temp=[smcWrapper get_mptemp];
|
||||||
} else {
|
} else {
|
||||||
SMCVal_t val;
|
SMCVal_t val;
|
||||||
NSMutableArray *allTSensors = [[tsensors allKeys] mutableCopy];
|
|
||||||
NSString *foundKey = [tsensors objectForKey:[MachineDefaults computerModel]];
|
NSString *foundKey = [tsensors objectForKey:[MachineDefaults computerModel]];
|
||||||
if (foundKey !=nil) {
|
if (foundKey !=nil) {
|
||||||
foundKey = [MachineDefaults computerModel];
|
foundKey = [MachineDefaults computerModel];
|
||||||
} else {
|
} else {
|
||||||
foundKey = @"standard";
|
foundKey = @"standard";
|
||||||
}
|
}
|
||||||
[allTSensors removeObject:foundKey];
|
|
||||||
SMCReadKey2((char*)[[tsensors objectForKey:foundKey] UTF8String], &val,conn);
|
SMCReadKey2((char*)[[tsensors objectForKey:foundKey] UTF8String], &val,conn);
|
||||||
c_temp= ((val.bytes[0] * 256 + val.bytes[1]) >> 2)/64;
|
c_temp= ((val.bytes[0] * 256 + val.bytes[1]) >> 2)/64;
|
||||||
|
|
||||||
if (c_temp<=0) {
|
if (c_temp<=0) {
|
||||||
|
NSArray *allTSensors = [tsensors allKeys];
|
||||||
for (NSString *key in allTSensors) {
|
for (NSString *key in allTSensors) {
|
||||||
SMCReadKey2((char*)[[tsensors objectForKey:key] UTF8String], &val,conn);
|
bool bPtrEq = (key == foundKey);
|
||||||
c_temp= ((val.bytes[0] * 256 + val.bytes[1]) >> 2)/64;
|
bool bCmpEq = ([key isEqualToString:foundKey]);
|
||||||
if (c_temp>0) break;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,14 +176,16 @@ static NSDictionary *tsensors = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
//call smc binary with setuid rights and apply
|
//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{
|
+(void)setKey_external:(NSString *)key value:(NSString *)value{
|
||||||
NSString *launchPath = [[NSBundle mainBundle] pathForResource:@"smc" ofType:@""];
|
NSString *launchPath = [[NSBundle mainBundle] pathForResource:@"smc" ofType:@""];
|
||||||
//first check if it's the right binary (security)
|
//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]) {
|
if (![checksum isEqualToString:smc_checksum]) {
|
||||||
NSLog(@"smcFanControl: Security Error: smc-binary is not the distributed one");
|
NSLog(@"smcFanControl: Security Error: smc-binary is not the distributed one");
|
||||||
return;
|
return;
|
||||||
}
|
}*/
|
||||||
NSArray *argsArray = [NSArray arrayWithObjects: @"-k",key,@"-w",value,nil];
|
NSArray *argsArray = [NSArray arrayWithObjects: @"-k",key,@"-w",value,nil];
|
||||||
NSTask *task;
|
NSTask *task;
|
||||||
task = [[NSTask alloc] init];
|
task = [[NSTask alloc] init];
|
||||||
|
|||||||
620
smc-command/smc.c
Normal file → Executable file
620
smc-command/smc.c
Normal file → Executable file
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Apple System Management Control (SMC) Tool
|
* Apple System Management Control (SMC) Tool
|
||||||
* Copyright (C) 2006 devnull
|
* Copyright (C) 2006 devnull
|
||||||
|
* Portions Copyright (C) 2013 Michael Wilber
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -22,10 +23,22 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <IOKit/IOKitLib.h>
|
#include <IOKit/IOKitLib.h>
|
||||||
|
|
||||||
#include "smc.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)
|
UInt32 _strtoul(char *str, int size, int base)
|
||||||
{
|
{
|
||||||
@ -68,17 +81,157 @@ float _strtof(char *str, int size, int e)
|
|||||||
return total;
|
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(){
|
void smc_init(){
|
||||||
SMCOpen(&conn);
|
SMCOpen(&g_conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void smc_close(){
|
void smc_close(){
|
||||||
SMCClose(conn);
|
SMCClose(g_conn);
|
||||||
}
|
}
|
||||||
void printFPE2(SMCVal_t val)
|
void printFPE2(SMCVal_t val)
|
||||||
{
|
{
|
||||||
/* FIXME: This decode is incomplete, last 2 bits are dropped */
|
/* FIXME: This decode is incomplete, last 2 bits are dropped */
|
||||||
|
|
||||||
printf("%.0f ", _strtof(val.bytes, val.dataSize, 2));
|
printf("%.0f ", _strtof(val.bytes, val.dataSize, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +243,7 @@ void printUInt(SMCVal_t val)
|
|||||||
void printBytesHex(SMCVal_t val)
|
void printBytesHex(SMCVal_t val)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
printf("(bytes");
|
printf("(bytes");
|
||||||
for (i = 0; i < val.dataSize; i++)
|
for (i = 0; i < val.dataSize; i++)
|
||||||
printf(" %02x", (unsigned char) val.bytes[i]);
|
printf(" %02x", (unsigned char) val.bytes[i]);
|
||||||
@ -108,225 +261,63 @@ void printVal(SMCVal_t val)
|
|||||||
printUInt(val);
|
printUInt(val);
|
||||||
else if (strcmp(val.dataType, DATATYPE_FPE2) == 0)
|
else if (strcmp(val.dataType, DATATYPE_FPE2) == 0)
|
||||||
printFPE2(val);
|
printFPE2(val);
|
||||||
|
|
||||||
printBytesHex(val);
|
printBytesHex(val);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("no data\n");
|
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;
|
|
||||||
|
|
||||||
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)
|
kern_return_t SMCCall(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure)
|
||||||
{
|
{
|
||||||
size_t structureInputSize;
|
return SMCCall2(index, inputStructure, outputStructure, g_conn);
|
||||||
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 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 SMCReadKey(UInt32Char_t key, SMCVal_t *val)
|
||||||
|
{
|
||||||
|
return SMCReadKey2(key, val, g_conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_return_t SMCWriteKey2(SMCVal_t writeVal, io_connect_t conn)
|
||||||
{
|
{
|
||||||
kern_return_t result;
|
kern_return_t result;
|
||||||
SMCKeyData_t inputStructure;
|
SMCKeyData_t inputStructure;
|
||||||
SMCKeyData_t outputStructure;
|
SMCKeyData_t outputStructure;
|
||||||
|
|
||||||
|
SMCVal_t readVal;
|
||||||
|
|
||||||
|
result = SMCReadKey2(writeVal.key, &readVal,conn);
|
||||||
|
if (result != kIOReturnSuccess)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (readVal.dataSize != writeVal.dataSize)
|
||||||
|
return kIOReturnError;
|
||||||
|
|
||||||
memset(&inputStructure, 0, sizeof(SMCKeyData_t));
|
memset(&inputStructure, 0, sizeof(SMCKeyData_t));
|
||||||
memset(&outputStructure, 0, sizeof(SMCKeyData_t));
|
memset(&outputStructure, 0, sizeof(SMCKeyData_t));
|
||||||
memset(val, 0, sizeof(SMCVal_t));
|
|
||||||
|
inputStructure.key = _strtoul(writeVal.key, 4, 16);
|
||||||
inputStructure.key = _strtoul(key, 4, 16);
|
inputStructure.data8 = SMC_CMD_WRITE_BYTES;
|
||||||
sprintf(val->key, key);
|
inputStructure.keyInfo.dataSize = writeVal.dataSize;
|
||||||
inputStructure.data8 = SMC_CMD_READ_KEYINFO;
|
memcpy(inputStructure.bytes, writeVal.bytes, sizeof(writeVal.bytes));
|
||||||
|
result = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure,conn);
|
||||||
result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure);
|
|
||||||
if (result != kIOReturnSuccess)
|
if (result != kIOReturnSuccess)
|
||||||
return result;
|
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 kIOReturnSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
kern_return_t SMCWriteKey(SMCVal_t writeVal)
|
kern_return_t SMCWriteKey(SMCVal_t writeVal)
|
||||||
{
|
{
|
||||||
kern_return_t result;
|
return SMCWriteKey2(writeVal, g_conn);
|
||||||
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 result;
|
|
||||||
SMCKeyData_t inputStructure;
|
|
||||||
SMCKeyData_t outputStructure;
|
|
||||||
|
|
||||||
SMCVal_t readVal;
|
|
||||||
|
|
||||||
result = SMCReadKey2(writeVal.key, &readVal,conn);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
UInt32 SMCReadIndexCount(void)
|
UInt32 SMCReadIndexCount(void)
|
||||||
{
|
{
|
||||||
SMCVal_t val;
|
SMCVal_t val;
|
||||||
|
|
||||||
SMCReadKey("#KEY", &val);
|
SMCReadKey("#KEY", &val);
|
||||||
return _strtoul(val.bytes, val.dataSize, 10);
|
return _strtoul(val.bytes, val.dataSize, 10);
|
||||||
}
|
}
|
||||||
@ -336,31 +327,31 @@ kern_return_t SMCPrintAll(void)
|
|||||||
kern_return_t result;
|
kern_return_t result;
|
||||||
SMCKeyData_t inputStructure;
|
SMCKeyData_t inputStructure;
|
||||||
SMCKeyData_t outputStructure;
|
SMCKeyData_t outputStructure;
|
||||||
|
|
||||||
int totalKeys, i;
|
int totalKeys, i;
|
||||||
UInt32Char_t key;
|
UInt32Char_t key;
|
||||||
SMCVal_t val;
|
SMCVal_t val;
|
||||||
|
|
||||||
totalKeys = SMCReadIndexCount();
|
totalKeys = SMCReadIndexCount();
|
||||||
for (i = 0; i < totalKeys; i++)
|
for (i = 0; i < totalKeys; i++)
|
||||||
{
|
{
|
||||||
memset(&inputStructure, 0, sizeof(SMCKeyData_t));
|
memset(&inputStructure, 0, sizeof(SMCKeyData_t));
|
||||||
memset(&outputStructure, 0, sizeof(SMCKeyData_t));
|
memset(&outputStructure, 0, sizeof(SMCKeyData_t));
|
||||||
memset(&val, 0, sizeof(SMCVal_t));
|
memset(&val, 0, sizeof(SMCVal_t));
|
||||||
|
|
||||||
inputStructure.data8 = SMC_CMD_READ_INDEX;
|
inputStructure.data8 = SMC_CMD_READ_INDEX;
|
||||||
inputStructure.data32 = i;
|
inputStructure.data32 = i;
|
||||||
|
|
||||||
result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure);
|
result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure);
|
||||||
if (result != kIOReturnSuccess)
|
if (result != kIOReturnSuccess)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_ultostr(key, outputStructure.key);
|
_ultostr(key, outputStructure.key);
|
||||||
|
|
||||||
SMCReadKey(key, &val);
|
SMCReadKey(key, &val);
|
||||||
printVal(val);
|
printVal(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
return kIOReturnSuccess;
|
return kIOReturnSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,112 +361,111 @@ kern_return_t SMCPrintFans(void)
|
|||||||
SMCVal_t val;
|
SMCVal_t val;
|
||||||
UInt32Char_t key;
|
UInt32Char_t key;
|
||||||
int totalFans, i;
|
int totalFans, i;
|
||||||
|
|
||||||
result = SMCReadKey("FNum", &val);
|
result = SMCReadKey("FNum", &val);
|
||||||
if (result != kIOReturnSuccess)
|
if (result != kIOReturnSuccess)
|
||||||
return kIOReturnError;
|
return kIOReturnError;
|
||||||
|
|
||||||
totalFans = _strtoul(val.bytes, val.dataSize, 10);
|
totalFans = _strtoul(val.bytes, val.dataSize, 10);
|
||||||
printf("Total fans in system: %d\n", totalFans);
|
printf("Total fans in system: %d\n", totalFans);
|
||||||
|
|
||||||
for (i = 0; i < totalFans; i++)
|
for (i = 0; i < totalFans; i++)
|
||||||
{
|
{
|
||||||
printf("\nFan #%d:\n", i);
|
printf("\nFan #%d:\n", i);
|
||||||
sprintf(key, "F%dAc", i);
|
sprintf(key, "F%dAc", i);
|
||||||
SMCReadKey(key, &val);
|
SMCReadKey(key, &val);
|
||||||
printf(" Actual speed : %.0f\n", _strtof(val.bytes, val.dataSize, 2));
|
printf(" Actual speed : %.0f\n", _strtof(val.bytes, val.dataSize, 2));
|
||||||
sprintf(key, "F%dMn", i);
|
sprintf(key, "F%dMn", i);
|
||||||
SMCReadKey(key, &val);
|
SMCReadKey(key, &val);
|
||||||
printf(" Minimum speed: %.0f\n", _strtof(val.bytes, val.dataSize, 2));
|
printf(" Minimum speed: %.0f\n", _strtof(val.bytes, val.dataSize, 2));
|
||||||
sprintf(key, "F%dMx", i);
|
sprintf(key, "F%dMx", i);
|
||||||
SMCReadKey(key, &val);
|
SMCReadKey(key, &val);
|
||||||
printf(" Maximum speed: %.0f\n", _strtof(val.bytes, val.dataSize, 2));
|
printf(" Maximum speed: %.0f\n", _strtof(val.bytes, val.dataSize, 2));
|
||||||
sprintf(key, "F%dSf", i);
|
sprintf(key, "F%dSf", i);
|
||||||
SMCReadKey(key, &val);
|
SMCReadKey(key, &val);
|
||||||
printf(" Safe speed : %.0f\n", _strtof(val.bytes, val.dataSize, 2));
|
printf(" Safe speed : %.0f\n", _strtof(val.bytes, val.dataSize, 2));
|
||||||
sprintf(key, "F%dTg", i);
|
sprintf(key, "F%dTg", i);
|
||||||
SMCReadKey(key, &val);
|
SMCReadKey(key, &val);
|
||||||
printf(" Target speed : %.0f\n", _strtof(val.bytes, val.dataSize, 2));
|
printf(" Target speed : %.0f\n", _strtof(val.bytes, val.dataSize, 2));
|
||||||
SMCReadKey("FS! ", &val);
|
SMCReadKey("FS! ", &val);
|
||||||
if ((_strtoul(val.bytes, 2, 16) & (1 << i)) == 0)
|
if ((_strtoul(val.bytes, 2, 16) & (1 << i)) == 0)
|
||||||
printf(" Mode : auto\n");
|
printf(" Mode : auto\n");
|
||||||
else
|
else
|
||||||
printf(" Mode : forced\n");
|
printf(" Mode : forced\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return kIOReturnSuccess;
|
return kIOReturnSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
void usage(char* prog)
|
void usage(char* prog)
|
||||||
{
|
{
|
||||||
printf("Apple System Management Control (SMC) tool %s\n", VERSION);
|
printf("Apple System Management Control (SMC) tool %s\n", VERSION);
|
||||||
printf("Usage:\n");
|
printf("Usage:\n");
|
||||||
printf("%s [options]\n", prog);
|
printf("%s [options]\n", prog);
|
||||||
printf(" -f : fan info decoded\n");
|
printf(" -f : fan info decoded\n");
|
||||||
printf(" -h : help\n");
|
printf(" -h : help\n");
|
||||||
printf(" -k <key> : key to manipulate\n");
|
printf(" -k <key> : key to manipulate\n");
|
||||||
printf(" -l : list all keys and values\n");
|
printf(" -l : list all keys and values\n");
|
||||||
printf(" -r : read the value of a key\n");
|
printf(" -r : read the value of a key\n");
|
||||||
printf(" -w <value> : write the specified value to a key\n");
|
printf(" -w <value> : write the specified value to a key\n");
|
||||||
printf(" -v : version\n");
|
printf(" -v : version\n");
|
||||||
printf("\n");
|
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;
|
kern_return_t result;
|
||||||
SMCVal_t val;
|
SMCVal_t val;
|
||||||
int i;
|
int i;
|
||||||
char c[3];
|
char c[3];
|
||||||
for (i = 0; i < strlen(wvalue); i++)
|
for (i = 0; i < strlen(wvalue); i++)
|
||||||
{
|
{
|
||||||
sprintf(c, "%c%c", wvalue[i * 2], wvalue[(i * 2) + 1]);
|
sprintf(c, "%c%c", wvalue[i * 2], wvalue[(i * 2) + 1]);
|
||||||
val.bytes[i] = (int) strtol(c, NULL, 16);
|
val.bytes[i] = (int) strtol(c, NULL, 16);
|
||||||
}
|
}
|
||||||
val.dataSize = i / 2;
|
val.dataSize = i / 2;
|
||||||
sprintf(val.key, key);
|
sprintf(val.key, key);
|
||||||
result = SMCWriteKey2(val,conn);
|
result = SMCWriteKey2(val, conn);
|
||||||
if (result != kIOReturnSuccess)
|
if (result != kIOReturnSuccess)
|
||||||
printf("Error: SMCWriteKey() = %08x\n", result);
|
printf("Error: SMCWriteKey() = %08x\n", result);
|
||||||
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef CMD_TOOL
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
|
|
||||||
kern_return_t result;
|
kern_return_t result;
|
||||||
int op = OP_NONE;
|
int op = OP_NONE;
|
||||||
UInt32Char_t key = "\0";
|
UInt32Char_t key = { 0 }; //MAW
|
||||||
SMCVal_t val;
|
SMCVal_t val;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "fhk:lrw:v")) != -1)
|
while ((c = getopt(argc, argv, "fhk:lrw:v")) != -1)
|
||||||
{
|
{
|
||||||
switch(c)
|
switch(c)
|
||||||
{
|
{
|
||||||
case 'f':
|
case 'f':
|
||||||
op = OP_READ_FAN;
|
op = OP_READ_FAN;
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
strncpy(key, optarg, sizeof(key)); //fix for buffer overflow
|
strncpy(key, optarg, sizeof(key)); //fix for buffer overflow
|
||||||
break;
|
key[sizeof(key) - 1] = '\0';
|
||||||
case 'l':
|
break;
|
||||||
op = OP_LIST;
|
case 'l':
|
||||||
break;
|
op = OP_LIST;
|
||||||
case 'r':
|
break;
|
||||||
op = OP_READ;
|
case 'r':
|
||||||
break;
|
op = OP_READ;
|
||||||
case 'v':
|
break;
|
||||||
printf("%s\n", VERSION);
|
case 'v':
|
||||||
return 0;
|
printf("%s\n", VERSION);
|
||||||
break;
|
return 0;
|
||||||
case 'w':
|
break;
|
||||||
op = OP_WRITE;
|
case 'w':
|
||||||
|
op = OP_WRITE;
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char c[3];
|
char c[3];
|
||||||
@ -491,65 +481,67 @@ int main(int argc, char *argv[])
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
op = OP_NONE;
|
op = OP_NONE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op == OP_NONE)
|
if (op == OP_NONE)
|
||||||
{
|
{
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCOpen(&conn);
|
smc_init();
|
||||||
|
|
||||||
switch(op)
|
switch(op)
|
||||||
{
|
{
|
||||||
case OP_LIST:
|
case OP_LIST:
|
||||||
result = SMCPrintAll();
|
result = SMCPrintAll();
|
||||||
if (result != kIOReturnSuccess)
|
if (result != kIOReturnSuccess)
|
||||||
printf("Error: SMCPrintAll() = %08x\n", result);
|
printf("Error: SMCPrintAll() = %08x\n", result);
|
||||||
break;
|
break;
|
||||||
case OP_READ:
|
case OP_READ:
|
||||||
if (strlen(key) > 0)
|
if (strlen(key) > 0)
|
||||||
{
|
{
|
||||||
result = SMCReadKey(key, &val);
|
result = SMCReadKey(key, &val);
|
||||||
if (result != kIOReturnSuccess)
|
if (result != kIOReturnSuccess)
|
||||||
printf("Error: SMCReadKey() = %08x\n", result);
|
printf("Error: SMCReadKey() = %08x\n", result);
|
||||||
|
else
|
||||||
|
printVal(val);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
printVal(val);
|
{
|
||||||
}
|
printf("Error: specify a key to read\n");
|
||||||
else
|
}
|
||||||
{
|
break;
|
||||||
printf("Error: specify a key to read\n");
|
case OP_READ_FAN:
|
||||||
}
|
result = SMCPrintFans();
|
||||||
break;
|
|
||||||
case OP_READ_FAN:
|
|
||||||
result = SMCPrintFans();
|
|
||||||
if (result != kIOReturnSuccess)
|
|
||||||
printf("Error: SMCPrintFans() = %08x\n", result);
|
|
||||||
break;
|
|
||||||
case OP_WRITE:
|
|
||||||
if (strlen(key) > 0)
|
|
||||||
{
|
|
||||||
sprintf(val.key, key);
|
|
||||||
result = SMCWriteKey(val);
|
|
||||||
if (result != kIOReturnSuccess)
|
if (result != kIOReturnSuccess)
|
||||||
printf("Error: SMCWriteKey() = %08x\n", result);
|
printf("Error: SMCPrintFans() = %08x\n", result);
|
||||||
}
|
break;
|
||||||
else
|
case OP_WRITE:
|
||||||
{
|
if (strlen(key) > 0)
|
||||||
printf("Error: specify a key to write\n");
|
{
|
||||||
}
|
sprintf(val.key, key);
|
||||||
break;
|
result = SMCWriteKey(val);
|
||||||
|
if (result != kIOReturnSuccess)
|
||||||
|
printf("Error: SMCWriteKey() = %08x\n", result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Error: specify a key to write\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCClose(conn);
|
smc_close();
|
||||||
return 0;;
|
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
|
* Apple System Management Control (SMC) Tool
|
||||||
* Copyright (C) 2006 devnull
|
* Copyright (C) 2006 devnull
|
||||||
|
* Portions Copyright (C) 2013 Michael Wilber
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -89,13 +90,20 @@ typedef struct {
|
|||||||
} SMCVal_t;
|
} SMCVal_t;
|
||||||
|
|
||||||
UInt32 _strtoul(char *str, int size, int base);
|
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);
|
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