Merge branch 'master' of https://github.com/mw9074/smcFanControl into mw9074-master

Conflicts:
	smc-command/smc.c
	smc-command/smc.h
This commit is contained in:
Hendrik Holtmann
2014-02-10 01:47:40 +01:00
6 changed files with 492 additions and 383 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

254
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**
@ -169,11 +162,11 @@ NSString *authpw;
g_numFans = [smcWrapper get_fan_num];
s_menus=[[NSMutableArray alloc] init];
[s_menus autorelease];
int i;
for(i=0;i<[smcWrapper get_fan_num];i++){
for(i=0;i<g_numFans;i++){
NSMenuItem *mitem=[[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"Fan: %d",i] action:NULL keyEquivalent:@""];
[mitem setTag:(i+1)*10];
[s_menus insertObject:mitem atIndex:i];
@ -222,7 +215,7 @@ NSString *authpw;
//release MachineDefaults class first call
//add timer for reading to RunLoop
_readTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(readFanData:) userInfo:nil repeats:YES];
_readTimer = [NSTimer scheduledTimerWithTimeInterval:4.0 target:self selector:@selector(readFanData:) userInfo:nil repeats:YES];
[_readTimer fire];
//autoapply settings if valid
[self upgradeFavorites];
@ -243,6 +236,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];
}
@ -305,107 +303,145 @@ NSString *authpw;
}
// Called via a timer mechanism. This is where all the temp / RPM reading is done.
//reads fan data and updates the gui
-(void) readFanData:(NSTimer*)timer{
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]]];
}
// 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;
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"];
case 3:
bNeedTemp = true;
bNeedRpm = false;
break;
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;
}
}
case 4:
bNeedTemp = false;
bNeedRpm = true;
break;
}
fan=[NSString stringWithFormat:@"%@rpm",[nc stringForObjectValue:[NSNumber numberWithFloat:[smcWrapper get_fan_rpm:selected]]]];
NSString *temp = nil;
NSString *fan = nil;
float c_temp = 0.0f;
int selectedRpm = 0;
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 (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"];
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];
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:@"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:@"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];
}
}
}
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];
// 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 +510,7 @@ NSString *authpw;
-(void)terminate:(id)sender{
//get last active selection
[defaults synchronize];
SMCClose(conn);
[smcWrapper cleanUp];
[_readTimer invalidate];
[pw deregisterForSleepWakeNotification];
[pw deregisterForPowerChange];
@ -518,6 +554,23 @@ NSString *authpw;
}
}
// 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]]];
}
}
}
#pragma mark **Helper-Methods**
@ -669,20 +722,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;

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;

24
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,6 +24,7 @@
#import "smcWrapper.h"
#import <CommonCrypto/CommonDigest.h>
//TODO: This is the smcFanControl 2.4 checksum, it needs to be updated for the next release.
NSString * const smc_checksum=@"2ea544babe8a58dccc1364c920d473c8";
static NSDictionary *tsensors = nil;
@ -33,6 +35,9 @@ static NSDictionary *tsensors = nil;
SMCOpen(&conn);
tsensors = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tsensors" ofType:@"plist"]];
}
+(void)cleanUp{
SMCClose(conn);
}
+(float) get_maintemp{
float c_temp;
@ -43,22 +48,23 @@ static NSDictionary *tsensors = nil;
c_temp=[smcWrapper get_mptemp];
} else {
SMCVal_t val;
NSMutableArray *allTSensors = [[tsensors allKeys] mutableCopy];
NSString *foundKey = [tsensors objectForKey:[MachineDefaults computerModel]];
if (foundKey !=nil) {
foundKey = [MachineDefaults computerModel];
} else {
foundKey = @"standard";
}
[allTSensors removeObject:foundKey];
SMCReadKey2((char*)[[tsensors objectForKey:foundKey] UTF8String], &val,conn);
c_temp= ((val.bytes[0] * 256 + val.bytes[1]) >> 2)/64;
if (c_temp<=0) {
NSArray *allTSensors = [tsensors allKeys];
for (NSString *key in allTSensors) {
SMCReadKey2((char*)[[tsensors objectForKey:key] UTF8String], &val,conn);
c_temp= ((val.bytes[0] * 256 + val.bytes[1]) >> 2)/64;
if (c_temp>0) break;
if (![key isEqualToString:foundKey]) {
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 +174,16 @@ static NSDictionary *tsensors = nil;
}
//call smc binary with setuid rights and apply
// The smc binary is given root permissions in FanControl.m with the setRights method.
+(void)setKey_external:(NSString *)key value:(NSString *)value{
NSString *launchPath = [[NSBundle mainBundle] pathForResource:@"smc" ofType:@""];
//first check if it's the right binary (security)
NSString *checksum=[smcWrapper createCheckSum:launchPath];
// MW: Disabled smc binary checksum. This should be re-enabled in an official release.
/*NSString *checksum=[smcWrapper createCheckSum:launchPath];
if (![checksum isEqualToString:smc_checksum]) {
NSLog(@"smcFanControl: Security Error: smc-binary is not the distributed one");
return;
}
}*/
NSArray *argsArray = [NSArray arrayWithObjects: @"-k",key,@"-w",value,nil];
NSTask *task;
task = [[NSTask alloc] init];

423
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)
{
@ -70,13 +83,6 @@ float _strtof(unsigned char *str, int size, int e)
return total;
}
void smc_init(){
SMCOpen(&conn);
}
void smc_close(){
SMCClose(conn);
}
void printFP1F(SMCVal_t val)
{
@ -264,6 +270,9 @@ void printVal(SMCVal_t val)
printf("no data\n");
}
}
=======
#pragma mark Shared SMC functions
>>>>>>> 3328c0018f364d7873b2aabaeb4284f19d586cb0
kern_return_t SMCOpen(io_connect_t *conn)
{
@ -306,27 +315,6 @@ 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;
@ -334,17 +322,53 @@ kern_return_t SMCCall2(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *ou
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)
@ -359,11 +383,12 @@ kern_return_t SMCReadKey2(UInt32Char_t key, SMCVal_t *val,io_connect_t conn)
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);
@ -372,76 +397,81 @@ kern_return_t SMCReadKey2(UInt32Char_t key, SMCVal_t *val,io_connect_t conn)
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);
}
void printFPE2(SMCVal_t val)
{
/* FIXME: This decode is incomplete, last 2 bits are dropped */
printf("%.0f ", _strtof(val.bytes, val.dataSize, 2));
}
void printUInt(SMCVal_t val)
{
printf("%u ", (unsigned int) _strtoul(val.bytes, val.dataSize, 10));
}
void printBytesHex(SMCVal_t val)
{
int i;
printf("(bytes");
for (i = 0; i < val.dataSize; i++)
printf(" %02x", (unsigned char) val.bytes[i]);
printf(")\n");
}
void printVal(SMCVal_t val)
{
printf(" %-4s [%-4s] ", val.key, val.dataType);
if (val.dataSize > 0)
{
if ((strcmp(val.dataType, DATATYPE_UINT8) == 0) ||
(strcmp(val.dataType, DATATYPE_UINT16) == 0) ||
(strcmp(val.dataType, DATATYPE_UINT32) == 0))
printUInt(val);
else if (strcmp(val.dataType, DATATYPE_FPE2) == 0)
printFPE2(val);
printBytesHex(val);
}
else
{
printf("no data\n");
}
}
kern_return_t 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)
{
kern_return_t result;
SMCKeyData_t inputStructure;
SMCKeyData_t outputStructure;
memset(&inputStructure, 0, sizeof(SMCKeyData_t));
memset(&outputStructure, 0, sizeof(SMCKeyData_t));
memset(val, 0, sizeof(SMCVal_t));
inputStructure.key = _strtoul(key, 4, 16);
sprintf(val->key, key);
inputStructure.data8 = SMC_CMD_READ_KEYINFO;
result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure);
if (result != kIOReturnSuccess)
return result;
val->dataSize = outputStructure.keyInfo.dataSize;
_ultostr(val->dataType, outputStructure.keyInfo.dataType);
inputStructure.keyInfo.dataSize = val->dataSize;
inputStructure.data8 = SMC_CMD_READ_BYTES;
result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure);
if (result != kIOReturnSuccess)
return result;
memcpy(val->bytes, outputStructure.bytes, sizeof(outputStructure.bytes));
return kIOReturnSuccess;
return SMCReadKey2(key, val, g_conn);
}
kern_return_t SMCWriteKey(SMCVal_t writeVal)
{
kern_return_t result;
SMCKeyData_t inputStructure;
SMCKeyData_t outputStructure;
SMCVal_t readVal;
result = SMCReadKey(writeVal.key, &readVal);
if (result != kIOReturnSuccess)
return result;
if (readVal.dataSize != writeVal.dataSize)
return kIOReturnError;
memset(&inputStructure, 0, sizeof(SMCKeyData_t));
memset(&outputStructure, 0, sizeof(SMCKeyData_t));
inputStructure.key = _strtoul(writeVal.key, 4, 16);
inputStructure.data8 = SMC_CMD_WRITE_BYTES;
inputStructure.keyInfo.dataSize = writeVal.dataSize;
memcpy(inputStructure.bytes, writeVal.bytes, sizeof(writeVal.bytes));
result = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure,conn);
if (result != kIOReturnSuccess)
return result;
return kIOReturnSuccess;
}
kern_return_t SMCWriteKey2(SMCVal_t writeVal,io_connect_t conn)
kern_return_t SMCWriteKey2(SMCVal_t writeVal, io_connect_t conn)
{
kern_return_t result;
SMCKeyData_t inputStructure;
@ -470,6 +500,10 @@ kern_return_t SMCWriteKey2(SMCVal_t writeVal,io_connect_t conn)
return kIOReturnSuccess;
}
kern_return_t SMCWriteKey(SMCVal_t writeVal)
{
return SMCWriteKey2(writeVal, g_conn);
}
UInt32 SMCReadIndexCount(void)
{
@ -559,42 +593,40 @@ kern_return_t SMCPrintFans(void)
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;
@ -602,31 +634,32 @@ int main(int argc, char *argv[])
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];
@ -642,65 +675,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

20
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
@ -114,12 +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(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);
float _strtof(unsigned char *str, int size, int e);