Hi, friends:
I got my own program which a dedicated fan controller. It been tested on my new Mac Mini early 2009 (Windows XP). And my source code is open. Everybody should use this to build up a nice GUI program.
NOTE: The program is only a proof of concept. So it only works but lack of functionalities.
1. The program need GIVEIO device driver support. You can get it by install speedfan. Or you can download the standalone package from anywhere.
2. It is a console command line program. Not easy to use, but easy for script. You can add temperature sensor detect function in it.
3. How to get the 'key' definitions of Apple SMC. Please install smcFanControl under OSX. There is a console program in /Application/smcFanControl.app/Contents/Resource/Source. It named 'smc'. Use the command line 'smc -l' to get all 'Key' definitions.
4. For the Apple SMC programming, please refer to Linux Kernel applesmc.c which a kernel extension. It is nice program to communicate with SMC under Linux. The code should help you and me.
BTW: Sorry for my poor English. I am from China. If you got better idea, please email me: iam.liuzhong@gmail.com
[codebox]
#include "stdlib.h"
#include "windows.h"
//Console inp and out functions
#include "conio.h"
#define APPLESMC
DATAPORT 0x300
/* command/status port used by Apple SMC */
#define APPLESMC
CMDPORT 0x304
#define APPLESMC
STATUSMASK 0x0f
#define APPLESMC
READCMD 0x10
#define APPLESMC
WRITECMD 0x11
#define APPLESMC
GET_KEY_BY_INDEXCMD 0x12
#define APPLESMC
GET_KEY_TYPECMD 0x13
SC_HANDLE hSCMan = NULL;
BOOL IsWinNT = FALSE;
BOOL IsDriverLoaded = FALSE;
// Return Value // Meaning
enum { DRIVER
ALREADYINSTALLED=100, //100 Driver is already Installed
DRIVER
INSTALLSUCCESS, //101
DRIVER
INSTALLFAILURE, //102
DRIVER
ALREADYUNINSTALLED, //103
DRIVER
UNINSTALLSUCCESS, //104
DRIVER
UNINSTALLFAILURE, //105
DRIVER
NOTINSTALLED, //106
DRIVER
ALREADYSTARTED, //107
DRIVER
INUSE
};
// SCM & GIVEIO control
BOOL InitSCM()
{
if ((hSCMan = OpenSCManager(NULL, NULL,SC
MANAGER_ALLACCESS)) == NULL)
{
printf("ERROR: Can't connect to Service Control Manager.\n");
return FALSE;
}
return TRUE;
}
BOOL ShutDownSCM(SC_HANDLE hSCMan)
{
return CloseServiceHandle(hSCMan);
}
DWORD DriverInstall(LPSTR lpPath, LPSTR lpDriver)
{
BOOL dwStatus = 0;
SC_HANDLE hService = NULL;
// add to service control manager's database
if ((hService = CreateService(hSCMan,
lpDriver,
lpDriver,
SERVICE
ALLACCESS,
SERVICE
KERNELDRIVER,
SERVICE
DEMANDSTART,
SERVICE
ERRORNORMAL,
lpPath, NULL, NULL, NULL, NULL, NULL)) == NULL)
dwStatus = GetLastError();
else
CloseServiceHandle(hService);
return dwStatus;
}
DWORD DriverRemove(LPSTR lpDriver)
{
BOOL dwStatus = 0;
SC_HANDLE hService = NULL;
// get a handle to the service
if ((hService = OpenService(hSCMan, lpDriver, SERVICE
ALLACCESS)) != NULL)
{
// remove the driver
if (!DeleteService(hService)) dwStatus = GetLastError();
}
else dwStatus = GetLastError();
if (hService != NULL) CloseServiceHandle(hService);
return dwStatus;
}
///////////////////////////////////////////////////////////////
// FUNC: GetDriverStatus
// DESC: Returns a Bool; 0 -> GiveIO Driver NOT loaded
// 1 -> GiveIO Driver LOADED
///////////////////////////////////////////////////////////////
int GetDriverStatus()
{
return IsDriverLoaded;
}
BOOL AttachDrv()
{
HANDLE h;
h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL,OPEN
EXISTING,FILE_ATTRIBUTENORMAL, NULL);
if(h == INVALID
HANDLEVALUE)
{
printf("ERROR: Couldn't access giveio device.\n");
return FALSE;
}
CloseHandle(h);
return TRUE;
}
BOOL AttachDIO()
{
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
IsWinNT = osvi.dwMajorVersion == 3 || osvi.dwMajorVersion == 4 || osvi.dwMajorVersion == 5 || osvi.dwMajorVersion == 6;
if(IsWinNT)
{
//Load the DirectIO Driver and attach it to this process
//try opening SCM ; if failed Bail out
if(!InitSCM()) return FALSE;
//Install the Driver
char szDrvPath[MAX_PATH];
GetSystemDirectory(szDrvPath,MAX_PATH);
lstrcat(szDrvPath,"\\Drivers\\GiveIO.sys");
DWORD dwRet = DriverInstall(szDrvPath,"giveio");
if(dwRet != 0 && dwRet != 0x00000431) //Success or already installed
{
printf("ERROR: Could not initialize GiveIO.sys Driver.\n");
return FALSE;
}
if(AttachDrv())
{
IsDriverLoaded = TRUE ;
return TRUE ; // Successful PROCESS_ATTACH
}
else
{
DriverRemove("giveio");
return FALSE;
}
}
return TRUE;
}
BOOL DetachDIO()
{
// Perform any necessary cleanup.
//if it is WinNT unload the giveIO driver
if(IsWinNT)
{
DriverRemove("giveio");
IsDriverLoaded = FALSE ;
return ShutDownSCM(hSCMan); //No Error Check :-P
}
return FALSE;
}
short OutPort( int PortAddress, int PortData )
{
short Dummy;
Dummy = (short)(_outp( PortAddress, PortData ));
return(Dummy);
}
short InPort( int PortAddress )
{
short PortData;
PortData = (short)(_inp( PortAddress ));
return( PortData );
}
int wait_status(short val)
{
unsigned int i;
val = val & APPLESMC
STATUSMASK;
for (i = 0; i < 200; i++) {
if ((InPort(APPLESMC
CMDPORT) & APPLESMC
STATUSMASK) == val) return 0;
Sleep(10);
}
return -1;
}
static int applesmc
readkey(const char* key, short* buffer, short len)
{
int i;
OutPort(APPLESMC
CMDPORT, APPLESMC
READCMD);
if (wait_status(0x0c)) return -1;
for (i = 0; i < 4; i++) {
OutPort(APPLESMC
DATAPORT, key
);
if (wait_status(0x04)) return -1;
}
OutPort(APPLESMCDATAPORT, len);
for (i = 0; i < len; i++) {
if (wait_status(0x05)) return -1;
buffer = InPort(APPLESMC
DATAPORT);
}
return 0;
}
static int applesmc
writekey(const char* key, short* buffer, short len)
{
int i;
OutPort(APPLESMC
CMDPORT, APPLESMC
WRITECMD);
if (wait_status(0x0c)) return -1;
for (i = 0; i < 4; i++) {
OutPort(APPLESMC
DATAPORT, key
);
if (wait_status(0x04)) return -1;
}
OutPort(APPLESMCDATAPORT, len);
for (i = 0; i < len; i++) {
if (wait_status(0x04)) return -1;
OutPort(APPLESMCDATAPORT, buffer);
}
return 0;
}
int main(int argc, char* argv[])
{
short speed[2];
char MINSPEED[5] = "F0Mn";
int st = 0;
AttachDIO();
st = GetDriverStatus();
printf("Driver Status: %d\n", st);
if (st != 1) return 1;
if (argc == 2) {
printf("Set the Minimal speed: %s\n", argv[1]);
st = atoi(argv[1]);
st = st * 4;
speed[0] = st >> 8;
speed[1] = st & 0x00FF;
for (int i = 0; i < 120; i++)
{
if (applesmc
writekey(MINSPEED, speed, 2) == 0) break;
Sleep(1000);
}
if (i == 120) {
printf("Failed, retry again!\n");
return 1;
}
printf("Update Successful\n");
}
for (int i = 0; i < 120; i++)
{
memset(speed, 0, sizeof(speed));
if (applesmc
readkey(MINSPEED, speed, 2) == 0) break;
Sleep(1000);
}
if (i == 120) {
printf("Failed, retry again!\n");
return 1;
}
st = (speed[0] * 0xFF + speed[1]) / 4;
printf("Current Minimal speed: %d\n", st);
printf("All OK!\n");
return 0;
}
[/codebox]
Usage: smc [Target minimal fan speed you like]