25 Commits
v2.4 ... v2.5ß

Author SHA1 Message Date
063d53b06c Changes for 2.5beta Release 2014-02-28 16:28:58 +01:00
d52a71e091 Testing different temperature readout method 2014-02-23 17:37:28 +01:00
8b1127b5b6 Fixed deletion of favorites on OS X 10.9 2014-02-23 17:13:43 +01:00
1b51b7d952 set timer tolerance for Mavericks 2014-02-10 02:09:25 +01:00
595fcd5957 Additional merging 2014-02-10 01:57:21 +01:00
7383e0819e Merge branch 'master' of https://github.com/mw9074/smcFanControl into mw9074-master
Conflicts:
	smc-command/smc.c
	smc-command/smc.h
2014-02-10 01:47:40 +01:00
f233b0846a Merge pull request #12 from nyeates/patch-1
Grammar fixes in Readme.md
2014-02-10 01:30:30 +01:00
0be72efddf Merge pull request #6 from denis2342/master
fixes the decoding of int values. this is important for the correct readout of the number of keys
2014-02-10 01:28:37 +01:00
3328c0018f No longer read unnecessary data in -readFanData
-readFanData was always reading the temperature and the speeds of all
of the fans regardless of what data was displayed in the menu bar. Now,
-readFanData only reads the data necessary to update the text in the
menubar, so, if only the temp is displayed, only the temp is read. The
updating of the fan speeds in the menu is now only done when the user
clicks on the menu. Also: cleaned up some test code and deleted an
unnecessary comment.
2013-12-25 09:47:10 -05:00
c537db9fdd 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.
2013-12-21 09:26:27 -05:00
32ced3b969 FAQ file references
The FAQ has a lot of good info and is well written. Any reader of this quick readme should know about the documentation within the FAQ file. I could not figure out a way to universally link to it within githubs flavor of .md markdown, so I just referenced it by textual explanation.
2013-12-07 04:06:21 -05:00
73c981e31a Grammar fixes in Readme.md 2013-12-07 03:08:12 -05:00
afebcc65f1 add more encoding types 2013-02-05 21:45:39 +01:00
77280ab43c support all found sp/fp oocurances I found so far 2013-02-05 20:54:26 +01:00
7ea2001e49 add '{pwm' decoding support 2013-02-03 04:40:08 +01:00
de8d762534 SP78 is signed, so print it that way 2013-02-03 04:40:08 +01:00
44c4e1d15a add support for SI16 signed integer type 2013-02-03 04:39:53 +01:00
dd63c65655 add support for SI8 signed integer type 2013-02-02 16:33:23 +01:00
3b87cc972d added the two missing bits to the result when decoding FPE2 values 2013-02-01 01:47:35 +01:00
b125097a07 add support for the sp78 format 2013-01-31 20:31:11 +01:00
afb554fc66 add the ID of the fan to the output 2013-01-31 18:43:03 +01:00
95dfefbe13 correctly read out int values, this fixes the wrong number of keys displayed and all other values which are ints with more than one byte 2013-01-31 18:36:00 +01:00
3212d78eac Updated read me 2012-08-21 17:55:14 +03:00
514a4e1757 new readme 2012-08-21 16:50:41 +02:00
b64ed93aec Updated Readme 2012-08-21 16:48:34 +02:00
13 changed files with 689 additions and 455 deletions

9
Classes/FanControl.h Normal file → Executable file
View 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
@ -38,7 +39,7 @@
#define kMenuBarHeight 22
@interface FanControl : NSObject
@interface FanControl : NSObject <NSMenuDelegate>
{
IBOutlet id currentSpeed;
@ -104,9 +105,6 @@
NSImage *menu_image;
NSImage *menu_image_alt;
}
-(void)terminate:(id)sender;
@ -133,6 +131,7 @@
- (void) syncBinder:(Boolean)bind;
- (IBAction) changeMenu:(id)sender;
- (IBAction)menuSelect:(id)sender;
- (void)menuNeedsUpdate:(NSMenu*)menu;
@end

305
Classes/FanControl.m Normal file → Executable file
View 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**
@ -100,7 +93,7 @@ NSString *authpw;
}
-(void) awakeFromNib {
s_sed = nil;
pw=[[Power alloc] init];
[pw setDelegate:self];
@ -162,6 +155,7 @@ NSString *authpw;
[NSNumber numberWithInt:0],@"selac",
[NSNumber numberWithInt:0],@"selload",
[NSNumber numberWithInt:0],@"MenuBar",
@"TC0D",@"TSensor",
feedURL,@"SUFeedURL",
[NSArchiver archivedDataWithRootObject:[NSColor blackColor]],@"MenuColor",
favorites,@"Favorites",
@ -169,11 +163,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 +216,10 @@ 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];
if ([_readTimer respondsToSelector:@selector(setTolerance:)]) {
[_readTimer setTolerance:2.0];
}
[_readTimer fire];
//autoapply settings if valid
[self upgradeFavorites];
@ -243,6 +240,11 @@ NSString *authpw;
for(i=0;i<[s_menus count];i++) {
[theMenu insertItem:[s_menus objectAtIndex:i] atIndex:i];
};
// Sign up for menuNeedsUpdate call
// so that the fan speeds in the menu can be updated
// only when needed.
[theMenu setDelegate:self];
}
@ -289,123 +291,166 @@ NSString *authpw;
}
}
- (IBAction)delete_favorite:(id)sender{
int pressesButton=NSRunCriticalAlertPanelRelativeToWindow(
NSLocalizedString(@"Delete favorite",nil),
[NSString stringWithFormat:NSLocalizedString(@"Do you really want to delete the favorite %@?",nil), [ [ [FavoritesController arrangedObjects] objectAtIndex:[FavoritesController selectionIndex]] objectForKey:@"Title"] ],
NSLocalizedString(@"No",nil),
NSLocalizedString(@"Yes",nil),nil,mainwindow);
if (pressesButton==0) {
- (void) deleteAlertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo;
{
if (returnCode==0) {
//delete favorite, but resets presets before
[self check_deletion:@"selbatt"];
[self check_deletion:@"selac"];
[self check_deletion:@"selload"];
[FavoritesController removeObjects:[FavoritesController selectedObjects]];
[FavoritesController removeObjects:[FavoritesController selectedObjects]];
}
}
- (IBAction)delete_favorite:(id)sender{
NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Delete favorite",nil) defaultButton:NSLocalizedString(@"No",nil) alternateButton:NSLocalizedString(@"Yes",nil) otherButton:nil informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"Do you really want to delete the favorite %@?",nil), [ [ [FavoritesController arrangedObjects] objectAtIndex:[FavoritesController selectionIndex]] objectForKey:@"Title"] ]];
[alert beginSheetModalForWindow:mainwindow modalDelegate:self didEndSelector:@selector(deleteAlertDidEnd:returnCode:contextInfo:) contextInfo:NULL];
}
// 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{
NSString *temp;
NSString *fan;
int i = 0;
//on init handling
if (s_sed==nil) {
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]]];
}
float c_temp=[smcWrapper get_maintemp];
if ([[defaults objectForKey:@"Unit"] intValue]==0) {
temp=[NSString stringWithFormat:@"%@%CC",[NSNumber numberWithFloat:c_temp],(unsigned short)0xb0];
} else {
NSNumberFormatter *ncf=[[[NSNumberFormatter alloc] init] autorelease];
[ncf setFormat:@"00;00;-00"];
temp=[NSString stringWithFormat:@"%@%CF",[ncf stringForObjectValue:[[NSNumber numberWithFloat:c_temp] celsius_fahrenheit]],(unsigned short)0xb0];
}
NSNumberFormatter *nc=[[[NSNumberFormatter alloc] init] autorelease];
//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:[smcWrapper get_fan_rpm:selected]]]];
// Determine what data is actually needed to keep the energy impact
// as low as possible.
bool bNeedTemp = false;
bool bNeedRpm = false;
const int menuBarSetting = [[defaults objectForKey:@"MenuBar"] intValue];
switch (menuBarSetting) {
default:
case 1:
bNeedTemp = true;
bNeedRpm = true;
break;
case 2:
bNeedTemp = true;
bNeedRpm = true;
break;
case 3:
bNeedTemp = true;
bNeedRpm = false;
break;
case 4:
bNeedTemp = false;
bNeedRpm = true;
break;
}
if ([[defaults objectForKey:@"MenuBar"] intValue]<=1) {
NSString *add;
int fsize;
if ([[defaults objectForKey:@"MenuBar"] intValue]==0) {
add=@"\n";
fsize=9;
[statusItem setLength:53];
} else {
add=@" ";
fsize=11;
[statusItem setLength:96];
}
NSMutableAttributedString *s_status=[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@%@%@",temp,add,fan]];
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[paragraphStyle setAlignment:NSLeftTextAlignment];
[s_status addAttribute:NSFontAttributeName value:[NSFont fontWithName:@"Lucida Grande" size:fsize] range:NSMakeRange(0,[s_status length])];
[s_status addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0,[s_status length])];
[s_status addAttribute:NSForegroundColorAttributeName value:(NSColor*)[NSUnarchiver unarchiveObjectWithData:[defaults objectForKey:@"MenuColor"]] range:NSMakeRange(0,[s_status length])];
[statusItem setAttributedTitle:s_status];
[statusItem setImage:nil];
[statusItem setAlternateImage:nil];
[paragraphStyle release];
[s_status release];
}
if ([[defaults objectForKey:@"MenuBar"] intValue]==2) {
[statusItem setLength:26];
[statusItem setTitle:nil];
[statusItem setToolTip:[NSString stringWithFormat:@"%@\n%@",temp,fan]];
[statusItem setImage:menu_image];
[statusItem setAlternateImage:menu_image_alt];
}
if ([[defaults objectForKey:@"MenuBar"] intValue]==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])];
[s_status addAttribute:NSForegroundColorAttributeName value:(NSColor*)[NSUnarchiver unarchiveObjectWithData:[defaults objectForKey:@"MenuColor"]] range:NSMakeRange(0,[s_status length])];
[statusItem setAttributedTitle:s_status];
[statusItem setImage:nil];
[statusItem setAlternateImage:nil];
[s_status release];
}
if ([[defaults objectForKey:@"MenuBar"] intValue]==4) {
[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])];
[s_status addAttribute:NSForegroundColorAttributeName value:(NSColor*)[NSUnarchiver unarchiveObjectWithData:[defaults objectForKey:@"MenuColor"]] range:NSMakeRange(0,[s_status length])];
[statusItem setAttributedTitle:s_status];
[statusItem setImage:nil];
[statusItem setAlternateImage:nil];
[s_status release];
}
NSString *temp = nil;
NSString *fan = nil;
float c_temp = 0.0f;
int selectedRpm = 0;
if (bNeedRpm == true) {
// Read the current fan speed for the desired fan and format text for display in the menubar.
NSArray *fans = [[[FavoritesController arrangedObjects] objectAtIndex:[FavoritesController selectionIndex]] objectForKey:@"FanData"];
for (i=0; i<g_numFans && i<[fans count]; i++)
{
if ([[[fans objectAtIndex:i] objectForKey:@"menu"] boolValue]==YES) {
selectedRpm = [smcWrapper get_fan_rpm:i];
break;
}
}
NSNumberFormatter *nc=[[[NSNumberFormatter alloc] init] autorelease];
//avoid jumping in menu bar
[nc setFormat:@"000;000;-000"];
fan = [NSString stringWithFormat:@"%@rpm",[nc stringForObjectValue:[NSNumber numberWithFloat:selectedRpm]]];
}
if (bNeedTemp == true) {
// Read current temperature and format text for the menubar.
c_temp = [smcWrapper get_maintemp];
if ([[defaults objectForKey:@"Unit"] intValue]==0) {
temp = [NSString stringWithFormat:@"%@%CC",[NSNumber numberWithFloat:c_temp],(unsigned short)0xb0];
} else {
NSNumberFormatter *ncf=[[[NSNumberFormatter alloc] init] autorelease];
[ncf setFormat:@"00;00;-00"];
temp = [NSString stringWithFormat:@"%@%CF",[ncf stringForObjectValue:[[NSNumber numberWithFloat:c_temp] celsius_fahrenheit]],(unsigned short)0xb0];
}
}
// Update the temp and/or fan speed text in the menubar.
NSMutableAttributedString *s_status = nil;
NSMutableParagraphStyle *paragraphStyle = nil;
switch (menuBarSetting) {
default:
case 1: {
int fsize = 0;
NSString *add = nil;
if (menuBarSetting==0) {
add=@"\n";
fsize=9;
[statusItem setLength:53];
} else {
add=@" ";
fsize=11;
[statusItem setLength:96];
}
s_status=[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@%@%@",temp,add,fan]];
paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[paragraphStyle setAlignment:NSLeftTextAlignment];
[s_status addAttribute:NSFontAttributeName value:[NSFont fontWithName:@"Lucida Grande" size:fsize] range:NSMakeRange(0,[s_status length])];
[s_status addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0,[s_status length])];
[s_status addAttribute:NSForegroundColorAttributeName value:(NSColor*)[NSUnarchiver unarchiveObjectWithData:[defaults objectForKey:@"MenuColor"]] range:NSMakeRange(0,[s_status length])];
[statusItem setAttributedTitle:s_status];
[statusItem setImage:nil];
[statusItem setAlternateImage:nil];
break;
}
case 2:
// TODO: Big waste of energy to update this tooltip every X seconds when the user
// is unlikely to hover the smcFanControl icon over and over again.
[statusItem setLength:26];
[statusItem setTitle:nil];
[statusItem setToolTip:[NSString stringWithFormat:@"%@\n%@",temp,fan]];
[statusItem setImage:menu_image];
[statusItem setAlternateImage:menu_image_alt];
break;
case 3:
[statusItem setLength:46];
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:NSForegroundColorAttributeName value:(NSColor*)[NSUnarchiver unarchiveObjectWithData:[defaults objectForKey:@"MenuColor"]] range:NSMakeRange(0,[s_status length])];
[statusItem setAttributedTitle:s_status];
[statusItem setImage:nil];
[statusItem setAlternateImage:nil];
break;
case 4:
[statusItem setLength:65];
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:NSForegroundColorAttributeName value:(NSColor*)[NSUnarchiver unarchiveObjectWithData:[defaults objectForKey:@"MenuColor"]] range:NSMakeRange(0,[s_status length])];
[statusItem setAttributedTitle:s_status];
[statusItem setImage:nil];
[statusItem setAlternateImage:nil];
break;
}
[paragraphStyle release];
[s_status release];
}
@ -474,7 +519,7 @@ NSString *authpw;
-(void)terminate:(id)sender{
//get last active selection
[defaults synchronize];
SMCClose(conn);
[smcWrapper cleanUp];
[_readTimer invalidate];
[pw deregisterForSleepWakeNotification];
[pw deregisterForPowerChange];
@ -516,7 +561,24 @@ NSString *authpw;
[[[FanController arrangedObjects] objectAtIndex:i] setValue:[NSNumber numberWithBool:NO] forKey:@"menu"];
}
}
}
}
// Called when user clicks on smcFanControl status bar item
// in the status area of the menubar. The fan speed
// menu items are now only updated here in order to
// reduce the energy impact of -readFanData.
- (void)menuNeedsUpdate:(NSMenu*)menu {
if (theMenu == menu) {
if (s_sed == nil)
return;
int i;
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:[smcWrapper get_fan_rpm:i]] stringValue]]];
}
}
}
@ -669,20 +731,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)) {
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;
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;

View File

@ -56,7 +56,9 @@ static void powerSourceChanged(void * refCon)
}
- (id)init{
[super init];
if (self = [super init]) {
}
return self;
}

5
Classes/smcWrapper.h Normal file → Executable file
View 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;

56
Classes/smcWrapper.m Normal file → Executable file
View 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,46 +24,43 @@
#import "smcWrapper.h"
#import <CommonCrypto/CommonDigest.h>
NSString * const smc_checksum=@"2ea544babe8a58dccc1364c920d473c8";
static NSDictionary *tsensors = nil;
//TODO: This is the smcFanControl 2.5ß checksum, it needs to be updated for the next release.
NSString * const smc_checksum=@"03548c5634bd01315b19c46bf329cceb";
static NSArray *allSensors = nil;
@implementation smcWrapper
io_connect_t conn;
+(void)init{
SMCOpen(&conn);
tsensors = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tsensors" ofType:@"plist"]];
allSensors = [[NSArray alloc] initWithObjects:@"TC0D",@"TC0H",@"TC0F",@"TCAH",@"TCBH",@"TC0P",nil];
}
+(void)cleanUp{
SMCClose(conn);
}
+(float) get_maintemp{
float c_temp;
NSRange range_pro=[[MachineDefaults computerModel] rangeOfString:@"MacPro"];
if (range_pro.length > 0) {
//special readout for MacPro
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) {
for (NSString *key in allTSensors) {
SMCReadKey2((char*)[[tsensors objectForKey:key] UTF8String], &val,conn);
SMCVal_t val;
NSString *sensor = [[NSUserDefaults standardUserDefaults] objectForKey:@"TSensor"];
SMCReadKey2((char*)[sensor UTF8String], &val,conn);
c_temp= ((val.bytes[0] * 256 + val.bytes[1]) >> 2)/64;
if (c_temp<=0) {
for (NSString *sensor in allSensors) {
SMCReadKey2((char*)[sensor UTF8String], &val,conn);
c_temp= ((val.bytes[0] * 256 + val.bytes[1]) >> 2)/64;
if (c_temp>0) break;
}
if (c_temp>0) {
[[NSUserDefaults standardUserDefaults] setObject:sensor forKey:@"TSensor"];
[[NSUserDefaults standardUserDefaults] synchronize];
break;
}
}
}
return c_temp;
}
@ -168,10 +166,12 @@ 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];
//first check if it's the right binary (security)
// MW: Disabled smc binary checksum. This should be re-enabled in an official release.
if (![checksum isEqualToString:smc_checksum]) {
NSLog(@"smcFanControl: Security Error: smc-binary is not the distributed one");
return;

View File

@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>smcFanControl</string>
<key>CFBundleGetInfoString</key>
<string>smcFanControl 2.4, Hendrik Holtmann (GPL)</string>
<string>smcFanControl 2., Hendrik Holtmann (GPL)</string>
<key>CFBundleIconFile</key>
<string>smcfancontrol_v2</string>
<key>CFBundleIdentifier</key>
@ -19,11 +19,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2.4</string>
<string>2.</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>2.4</string>
<string>2.</string>
<key>LSUIElement</key>
<string>1</string>
<key>NSHumanReadableCopyright</key>

5
README
View File

@ -1,5 +0,0 @@
smcFanControl lets the user set the minimum speed of the build in fans. So you can increase your minimum fan speed to make your Intel Mac run cooler. However in order not to damage your machines smcFanControl doesn't let you set a minimum speed to a value below Apple's defaults.
Requirements: Intel Mac / OS X 10.5 or higher
License: GPL 2

14
Readme.md Normal file
View File

@ -0,0 +1,14 @@
smcFanControl
=============
smcFanControl lets the user set a minimum speed for built-in fans. It allows you to increase your minimum fan speed to make your Intel Mac run cooler. In order to not damage your machine, smcFanControl does not let you set a minimum speed to a value below Apple's defaults.
![My image](https://dl.dropbox.com/u/363242/screenshots/smc_screenshot.png)
Requirements: Intel Mac / OS X 10.5 or higher
Compiled version: http://www.eidac.de/smcfancontrol/smcfancontrol_2_4.zip
FAQ / More info: Found in project under "Ressources/*.lproj/F.A.Q.rtf" or included in above .zip
License: GPL 2

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>standard</key>
<string>TC0D</string>
<key>lastAlternative</key>
<string>TCAH</string>
<key>MacBookPro10,1</key>
<string>TC0F</string>
<key>iMac12,2</key>
<string>TC0H</string>
<key>iMac12,1</key>
<string>TC0H</string>
</dict>
</plist>

658
smc-command/smc.c Normal file → Executable file
View 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)
{
@ -37,7 +50,7 @@ UInt32 _strtoul(char *str, int size, int base)
if (base == 16)
total += str[i] << (size - 1 - i) * 8;
else
total += (unsigned char) (str[i] << (size - 1 - i) * 8);
total += ((unsigned char) (str[i]) << (size - 1 - i) * 8);
}
return total;
}
@ -52,34 +65,68 @@ void _ultostr(char *str, UInt32 val)
(unsigned int) val);
}
float _strtof(char *str, int size, int e)
float _strtof(unsigned 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;
total += (str[i] & 0xff) >> e;
else
total += str[i] << (size - 1 - i) * (8 - e);
total += str[i] << (size - 1 - i) * (8 - e);
}
total += (str[size-1] & 0x03) * 0.25;
return total;
}
void smc_init(){
SMCOpen(&conn);
void printFP1F(SMCVal_t val)
{
printf("%.5f ", ntohs(*(UInt16*)val.bytes) / 32768.0);
}
void smc_close(){
SMCClose(conn);
void printFP4C(SMCVal_t val)
{
printf("%.5f ", ntohs(*(UInt16*)val.bytes) / 4096.0);
}
void printFP5B(SMCVal_t val)
{
printf("%.5f ", ntohs(*(UInt16*)val.bytes) / 2048.0);
}
void printFP6A(SMCVal_t val)
{
printf("%.4f ", ntohs(*(UInt16*)val.bytes) / 1024.0);
}
void printFP79(SMCVal_t val)
{
printf("%.4f ", ntohs(*(UInt16*)val.bytes) / 512.0);
}
void printFP88(SMCVal_t val)
{
printf("%.3f ", ntohs(*(UInt16*)val.bytes) / 256.0);
}
void printFPA6(SMCVal_t val)
{
printf("%.2f ", ntohs(*(UInt16*)val.bytes) / 64.0);
}
void printFPC4(SMCVal_t val)
{
printf("%.2f ", ntohs(*(UInt16*)val.bytes) / 16.0);
}
void printFPE2(SMCVal_t val)
{
/* FIXME: This decode is incomplete, last 2 bits are dropped */
printf("%.0f ", _strtof(val.bytes, val.dataSize, 2));
printf("%.2f ", ntohs(*(UInt16*)val.bytes) / 4.0);
}
void printUInt(SMCVal_t val)
@ -87,6 +134,71 @@ void printUInt(SMCVal_t val)
printf("%u ", (unsigned int) _strtoul(val.bytes, val.dataSize, 10));
}
void printSP1E(SMCVal_t val)
{
printf("%.5f ", ((SInt16)ntohs(*(UInt16*)val.bytes)) / 16384.0);
}
void printSP3C(SMCVal_t val)
{
printf("%.5f ", ((SInt16)ntohs(*(UInt16*)val.bytes)) / 4096.0);
}
void printSP4B(SMCVal_t val)
{
printf("%.4f ", ((SInt16)ntohs(*(UInt16*)val.bytes)) / 2048.0);
}
void printSP5A(SMCVal_t val)
{
printf("%.4f ", ((SInt16)ntohs(*(UInt16*)val.bytes)) / 1024.0);
}
void printSP69(SMCVal_t val)
{
printf("%.3f ", ((SInt16)ntohs(*(UInt16*)val.bytes)) / 512.0);
}
void printSP78(SMCVal_t val)
{
printf("%.3f ", ((SInt16)ntohs(*(UInt16*)val.bytes)) / 256.0);
}
void printSP87(SMCVal_t val)
{
printf("%.3f ", ((SInt16)ntohs(*(UInt16*)val.bytes)) / 128.0);
}
void printSP96(SMCVal_t val)
{
printf("%.2f ", ((SInt16)ntohs(*(UInt16*)val.bytes)) / 64.0);
}
void printSPB4(SMCVal_t val)
{
printf("%.2f ", ((SInt16)ntohs(*(UInt16*)val.bytes)) / 16.0);
}
void printSPF0(SMCVal_t val)
{
printf("%.0f ", (float)ntohs(*(UInt16*)val.bytes));
}
void printSI8(SMCVal_t val)
{
printf("%d ", (signed char)*val.bytes);
}
void printSI16(SMCVal_t val)
{
printf("%d ", ntohs(*(SInt16*)val.bytes));
}
void printPWM(SMCVal_t val)
{
printf("%.1f%% ", ntohs(*(UInt16*)val.bytes) * 100 / 65536.0);
}
void printBytesHex(SMCVal_t val)
{
int i;
@ -106,8 +218,50 @@ void printVal(SMCVal_t val)
(strcmp(val.dataType, DATATYPE_UINT16) == 0) ||
(strcmp(val.dataType, DATATYPE_UINT32) == 0))
printUInt(val);
else if (strcmp(val.dataType, DATATYPE_FPE2) == 0)
else if (strcmp(val.dataType, DATATYPE_FP1F) == 0 && val.dataSize == 2)
printFP1F(val);
else if (strcmp(val.dataType, DATATYPE_FP4C) == 0 && val.dataSize == 2)
printFP4C(val);
else if (strcmp(val.dataType, DATATYPE_FP5B) == 0 && val.dataSize == 2)
printFP5B(val);
else if (strcmp(val.dataType, DATATYPE_FP6A) == 0 && val.dataSize == 2)
printFP6A(val);
else if (strcmp(val.dataType, DATATYPE_FP79) == 0 && val.dataSize == 2)
printFP79(val);
else if (strcmp(val.dataType, DATATYPE_FP88) == 0 && val.dataSize == 2)
printFP88(val);
else if (strcmp(val.dataType, DATATYPE_FPA6) == 0 && val.dataSize == 2)
printFPA6(val);
else if (strcmp(val.dataType, DATATYPE_FPC4) == 0 && val.dataSize == 2)
printFPC4(val);
else if (strcmp(val.dataType, DATATYPE_FPE2) == 0 && val.dataSize == 2)
printFPE2(val);
else if (strcmp(val.dataType, DATATYPE_SP1E) == 0 && val.dataSize == 2)
printSP1E(val);
else if (strcmp(val.dataType, DATATYPE_SP3C) == 0 && val.dataSize == 2)
printSP3C(val);
else if (strcmp(val.dataType, DATATYPE_SP4B) == 0 && val.dataSize == 2)
printSP4B(val);
else if (strcmp(val.dataType, DATATYPE_SP5A) == 0 && val.dataSize == 2)
printSP5A(val);
else if (strcmp(val.dataType, DATATYPE_SP69) == 0 && val.dataSize == 2)
printSP69(val);
else if (strcmp(val.dataType, DATATYPE_SP78) == 0 && val.dataSize == 2)
printSP78(val);
else if (strcmp(val.dataType, DATATYPE_SP87) == 0 && val.dataSize == 2)
printSP87(val);
else if (strcmp(val.dataType, DATATYPE_SP96) == 0 && val.dataSize == 2)
printSP96(val);
else if (strcmp(val.dataType, DATATYPE_SPB4) == 0 && val.dataSize == 2)
printSPB4(val);
else if (strcmp(val.dataType, DATATYPE_SPF0) == 0 && val.dataSize == 2)
printSPF0(val);
else if (strcmp(val.dataType, DATATYPE_SI8) == 0 && val.dataSize == 1)
printSI8(val);
else if (strcmp(val.dataType, DATATYPE_SI16) == 0 && val.dataSize == 2)
printSI16(val);
else if (strcmp(val.dataType, DATATYPE_PWM) == 0 && val.dataSize == 2)
printPWM(val);
printBytesHex(val);
}
@ -117,15 +271,17 @@ void printVal(SMCVal_t val)
}
}
#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)
@ -133,7 +289,7 @@ kern_return_t SMCOpen(io_connect_t *conn)
printf("Error: IOServiceGetMatchingServices() = %08x\n", result);
return 1;
}
device = IOIteratorNext(iterator);
IOObjectRelease(iterator);
if (device == 0)
@ -141,7 +297,7 @@ kern_return_t SMCOpen(io_connect_t *conn)
printf("Error: no SMC found\n");
return 1;
}
result = IOServiceOpen(device, mach_task_self(), 0, conn);
IOObjectRelease(device);
if (result != kIOReturnSuccess)
@ -149,7 +305,7 @@ kern_return_t SMCOpen(io_connect_t *conn)
printf("Error: IOServiceOpen() = %08x\n", result);
return 1;
}
return kIOReturnSuccess;
}
@ -158,45 +314,60 @@ 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);
}
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);
}
// 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)
@ -204,129 +375,98 @@ 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);
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;
{
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(&g_conn);
}
void smc_close(){
SMCClose(g_conn);
}
kern_return_t SMCCall(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure)
{
return SMCCall2(index, inputStructure, outputStructure, g_conn);
}
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;
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));
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);
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;
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 = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure,conn);
if (result != kIOReturnSuccess)
return result;
return kIOReturnSuccess;
return SMCWriteKey2(writeVal, g_conn);
}
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)
{
SMCVal_t val;
SMCReadKey("#KEY", &val);
return _strtoul(val.bytes, val.dataSize, 10);
}
@ -336,31 +476,31 @@ 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);
_ultostr(key, outputStructure.key);
SMCReadKey(key, &val);
printVal(val);
}
return kIOReturnSuccess;
}
@ -370,112 +510,114 @@ kern_return_t SMCPrintFans(void)
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);
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%dID", i);
SMCReadKey(key, &val);
printf(" Fan ID : %s\n", val.bytes+4);
sprintf(key, "F%dAc", i);
SMCReadKey(key, &val);
printf(" Actual speed : %.0f\n", _strtof(val.bytes, val.dataSize, 2));
sprintf(key, "F%dMn", i);
sprintf(key, "F%dMn", i);
SMCReadKey(key, &val);
printf(" Minimum speed: %.0f\n", _strtof(val.bytes, val.dataSize, 2));
sprintf(key, "F%dMx", i);
sprintf(key, "F%dMx", i);
SMCReadKey(key, &val);
printf(" Maximum speed: %.0f\n", _strtof(val.bytes, val.dataSize, 2));
sprintf(key, "F%dSf", i);
sprintf(key, "F%dSf", i);
SMCReadKey(key, &val);
printf(" Safe speed : %.0f\n", _strtof(val.bytes, val.dataSize, 2));
sprintf(key, "F%dTg", i);
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");
printf(" Mode : auto\n");
else
printf(" Mode : forced\n");
}
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");
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");
}
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;
int i;
char c[3];
for (i = 0; i < strlen(wvalue); i++)
{
sprintf(c, "%c%c", wvalue[i * 2], wvalue[(i * 2) + 1]);
val.bytes[i] = (int) strtol(c, NULL, 16);
}
val.dataSize = i / 2;
sprintf(val.key, key);
result = SMCWriteKey2(val,conn);
if (result != kIOReturnSuccess)
printf("Error: SMCWriteKey() = %08x\n", result);
kern_return_t result;
SMCVal_t val;
int i;
char c[3];
for (i = 0; i < strlen(wvalue); i++)
{
sprintf(c, "%c%c", wvalue[i * 2], wvalue[(i * 2) + 1]);
val.bytes[i] = (int) strtol(c, NULL, 16);
}
val.dataSize = i / 2;
sprintf(val.key, key);
result = SMCWriteKey2(val, conn);
if (result != kIOReturnSuccess)
printf("Error: SMCWriteKey() = %08x\n", result);
return result;
return result;
}
#ifdef CMD_TOOL
int main(int argc, char *argv[])
{
int c;
extern char *optarg;
kern_return_t result;
int op = OP_NONE;
UInt32Char_t key = "\0";
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':
strncpy(key, optarg, sizeof(key)); //fix for buffer overflow
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;
case 'f':
op = OP_READ_FAN;
break;
case 'k':
strncpy(key, optarg, sizeof(key)); //fix for buffer overflow
key[sizeof(key) - 1] = '\0';
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];
@ -491,65 +633,67 @@ int main(int argc, char *argv[])
return 1;
}
}
break;
case 'h':
case '?':
op = OP_NONE;
break;
break;
case 'h':
case '?':
op = OP_NONE;
break;
}
}
if (op == OP_NONE)
{
usage(argv[0]);
return 1;
usage(argv[0]);
return 1;
}
SMCOpen(&conn);
smc_init();
switch(op)
{
case OP_LIST:
result = SMCPrintAll();
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);
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
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)
{
sprintf(val.key, key);
result = SMCWriteKey(val);
{
printf("Error: specify a key to read\n");
}
break;
case OP_READ_FAN:
result = SMCPrintFans();
if (result != kIOReturnSuccess)
printf("Error: SMCWriteKey() = %08x\n", result);
}
else
{
printf("Error: specify a key to write\n");
}
break;
printf("Error: SMCPrintFans() = %08x\n", result);
break;
case OP_WRITE:
if (strlen(key) > 0)
{
sprintf(val.key, 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;;
smc_close();
return 0;
}
#endif
#endif //#ifdef CMD_TOOL

46
smc-command/smc.h Normal file → Executable file
View 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
@ -38,11 +39,36 @@
#define SMC_CMD_READ_PLIMIT 11
#define SMC_CMD_READ_VERS 12
#define DATATYPE_FP1F "fp1f"
#define DATATYPE_FP4C "fp4c"
#define DATATYPE_FP5B "fp5b"
#define DATATYPE_FP6A "fp6a"
#define DATATYPE_FP79 "fp79"
#define DATATYPE_FP88 "fp88"
#define DATATYPE_FPA6 "fpa6"
#define DATATYPE_FPC4 "fpc4"
#define DATATYPE_FPE2 "fpe2"
#define DATATYPE_SP1E "sp1e"
#define DATATYPE_SP3C "sp3c"
#define DATATYPE_SP4B "sp4b"
#define DATATYPE_SP5A "sp5a"
#define DATATYPE_SP69 "sp69"
#define DATATYPE_SP78 "sp78"
#define DATATYPE_SP87 "sp87"
#define DATATYPE_SP96 "sp96"
#define DATATYPE_SPB4 "spb4"
#define DATATYPE_SPF0 "spf0"
#define DATATYPE_UINT8 "ui8 "
#define DATATYPE_UINT16 "ui16"
#define DATATYPE_UINT32 "ui32"
#define DATATYPE_SI8 "si8 "
#define DATATYPE_SI16 "si16"
#define DATATYPE_PWM "{pwm"
typedef struct {
char major;
char minor;
@ -65,7 +91,7 @@ typedef struct {
char dataAttributes;
} SMCKeyData_keyInfo_t;
typedef char SMCBytes_t[32];
typedef unsigned char SMCBytes_t[32];
typedef struct {
UInt32 key;
@ -89,13 +115,19 @@ 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);
float _strtof(unsigned 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);
float _strtof(char *str, int size, int e);
#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);

View File

@ -27,7 +27,6 @@
89949E8D0AEEA37700077E93 /* Power.m in Sources */ = {isa = PBXBuildFile; fileRef = 89949E8C0AEEA37700077E93 /* Power.m */; };
899D59DC15E1CF60003E322D /* smc in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8924ECEE15AC96E70031730C /* smc */; };
899D59DD15E1CFFF003E322D /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 895BDA390B8F8F42003CD894 /* Sparkle.framework */; };
899D59E315E228DF003E322D /* tsensors.plist in Resources */ = {isa = PBXBuildFile; fileRef = 899D59E215E228DF003E322D /* tsensors.plist */; };
89B243200B7E351000CAD103 /* smcfancontrol_v2.icns in Resources */ = {isa = PBXBuildFile; fileRef = 89B2431F0B7E351000CAD103 /* smcfancontrol_v2.icns */; };
89C053BE0ADAB7630037CA16 /* smc.c in Sources */ = {isa = PBXBuildFile; fileRef = 89C053BC0ADAB7630037CA16 /* smc.c */; };
89E7D3650ADE819B000F67AB /* Machines.plist in Resources */ = {isa = PBXBuildFile; fileRef = 89E7D3640ADE819B000F67AB /* Machines.plist */; };
@ -110,7 +109,6 @@
8987FBD00B878B3900A5ED8E /* smc.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = smc.png; sourceTree = "<group>"; };
89949E8B0AEEA37700077E93 /* Power.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Power.h; sourceTree = "<group>"; };
89949E8C0AEEA37700077E93 /* Power.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Power.m; sourceTree = "<group>"; };
899D59E215E228DF003E322D /* tsensors.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = tsensors.plist; sourceTree = "<group>"; };
89B2431F0B7E351000CAD103 /* smcfancontrol_v2.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = smcfancontrol_v2.icns; sourceTree = "<group>"; };
89C053BC0ADAB7630037CA16 /* smc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = smc.c; sourceTree = "<group>"; };
89C053BD0ADAB7630037CA16 /* smc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = smc.h; sourceTree = "<group>"; };
@ -231,7 +229,6 @@
89B2431F0B7E351000CAD103 /* smcfancontrol_v2.icns */,
8917FB850ADEECAD00443DA1 /* paypal.gif */,
89E7D3640ADE819B000F67AB /* Machines.plist */,
899D59E215E228DF003E322D /* tsensors.plist */,
089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
893506170B440255001BFBA5 /* Localizable.strings */,
89FE24050B7F4C2B00D2713C /* paypal.gif */,
@ -344,7 +341,6 @@
89033CA70B80E1EB00FDAF43 /* F.A.Q.rtf in Resources */,
8987FBD20B878B3900A5ED8E /* smc.png in Resources */,
89559A840BAC338500DBA37E /* smcover.png in Resources */,
899D59E315E228DF003E322D /* tsensors.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -438,7 +434,7 @@
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = CMD_TOOL;
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_VERSION = com.apple.compilers.llvmgcc42;
GCC_VERSION = "";
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
@ -446,7 +442,7 @@
ONLY_ACTIVE_ARCH = NO;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
SDKROOT = macosx10.7;
SDKROOT = macosx10.9;
};
name = Debug;
};
@ -463,14 +459,14 @@
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_PREPROCESSOR_DEFINITIONS = CMD_TOOL;
GCC_VERSION = com.apple.compilers.llvmgcc42;
GCC_VERSION = "";
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
MACOSX_DEPLOYMENT_TARGET = 10.5;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
SDKROOT = macosx10.7;
SDKROOT = macosx10.9;
};
name = Release;
};
@ -489,7 +485,7 @@
GCC_MODEL_PPC64 = NO;
GCC_MODEL_TUNING = "";
GCC_OPTIMIZATION_LEVEL = 0;
GCC_VERSION = com.apple.compilers.llvmgcc42;
GCC_VERSION = "";
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO;
INFOPLIST_FILE = Info.plist;
@ -502,7 +498,7 @@
ONLY_ACTIVE_ARCH = NO;
PRODUCT_NAME = smcFanControl;
PROVISIONING_PROFILE = "";
SDKROOT = macosx10.7;
SDKROOT = macosx10.9;
WRAPPER_EXTENSION = app;
ZERO_LINK = YES;
};
@ -522,7 +518,7 @@
FRAMEWORK_SEARCH_PATHS_QUOTED_2 = "\"$(SRCROOT)\"";
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = "";
GCC_VERSION = com.apple.compilers.llvmgcc42;
GCC_VERSION = "";
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO;
INFOPLIST_FILE = Info.plist;
@ -535,7 +531,7 @@
ONLY_ACTIVE_ARCH = NO;
PRODUCT_NAME = smcFanControl;
PROVISIONING_PROFILE = "";
SDKROOT = macosx10.7;
SDKROOT = macosx10.9;
VALID_ARCHS = "i386 x86_64";
WRAPPER_EXTENSION = app;
};