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