⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fanstuff.cpp

📁 这是老外开发的IBM、LENOVE风扇控制程序
💻 CPP
字号:

// --------------------------------------------------------------
//
//  Thinkpad Fan Control
//
// --------------------------------------------------------------
//
//	This program and source code is in the public domain.
//
//	The author claims no copyright, copyleft, license or
//	whatsoever for the program itself (with exception of
//	WinIO driver).  You may use, reuse or distribute it's 
//	binaries or source code in any desired way or form,  
//	Useage of binaries or source shall be entirely and 
//	without exception at your own risk. 
// 
// --------------------------------------------------------------

#include "fancontrol.h"



#define TP_ECOFFSET_FAN		 (char)0x2F	// 1 byte (binary xyzz zzz)
#define TP_ECOFFSET_FANSPEED (char)0x84 // 16 bit word, lo/hi byte
#define TP_ECOFFSET_TEMP0    (char)0x78	// 8 temp sensor bytes from here
#define TP_ECOFFSET_TEMP1    (char)0xC0 // 4 temp sensor bytes from here




// Thanks for the following to "Thinker" on 
// http://www.thinkwiki.org/wiki/Talk:ACPI_fan_control_script
const char *gSensorNames[]= {

	// 78-7F (state index 0-7)
	"CPU", // main processor
	"APS", // harddisk protection gyroscope
	"PCM", // under PCMCIA slot (front left)
	"GPU", // graphical processor
	"BAT", // inside T43 battery
	"X7D", // usually n/a
	"BAT", // inside T43 battery
	"X7F", // usually n/a

	// C0-C4 (state index 8-11)
	"BUS", // unknown
	"PCI", // mini-pci, WLAN, southbridge area
	"PWR", // power supply (get's hot while charging battery)
	"XC3", // usually n/a

	// future
	"",
	"",
	"",
	"",
	""
};

		


//-------------------------------------------------------------------------
//  switch fan according to settings
//-------------------------------------------------------------------------
int 
FANCONTROL::HandleData(void)
{
	char obuf[256]= "", obuf2[128]="", 
		 templist[256]= "", templist2[512], 
		 manlevel[16]= "", title2[128]= "";
	int i, maxtemp, ok= 0;



	//
	// determine highest temp.
	// 

	// build a list of sensors to ignore, separated by "|", e.g. "|XC1|BAT|CPU|"
	char what[16], list[128];
	sprintf(list, "|%s|", this->IgnoreSensors);
	for (i= 0; list[i]!='\0'; i++) {
		if (list[i]==',')	
			list[i]= '|';
	}

	maxtemp= 0;
	
	for (i= 0; i<12; i++) {
		sprintf(what, "|%s|", this->State.SensorName[i]); // name (e.g. "|CPU|") to match against list above

		if (this->State.Sensors[i]!=0x80 && this-State.Sensors[i]!=0x00 && strstr(list, what)==0) {
			maxtemp= __max(this->State.Sensors[i], maxtemp);
		}
	}

	this->MaxTemp= maxtemp;


	//
	// update dialog elements
	//

	// title string (for minimized window)
	sprintf(title2, "%d癈", this->MaxTemp);



	// display fan statte
	int fanctrl= this->State.FanCtrl;
	sprintf(obuf2, "0x%02x (", fanctrl);
	if (fanctrl & 0x80)	{
		strcat(obuf2, "BIOS Controlled)");
		strcat(title2, " Default Fan");
	}
	else {
		sprintf(obuf2+strlen(obuf2), "Fan Level %d, Non Bios)", fanctrl & 0x3F);
		sprintf(title2+strlen(title2), " Fan %d (%s)",
						 fanctrl & 0x3F,
						 this->CurrentModeFromDialog()==2 ? "Smart" : "Fixed");
	}
	::SetDlgItemText(this->hwndDialog, 8100, obuf2);

	strcpy(this->Title2, title2);
	

	// display fan speed (experimental, not visible)
	int fanspeed= (this->State.FanSpeedHi << 8) | this->State.FanSpeedLo;
	if (fanspeed && (short)fanspeed!=(short)0xffff)
		sprintf(obuf2, "%d RPM", fanspeed);
	else
		strcpy(obuf2, "off");
	::SetDlgItemText(this->hwndDialog, 8102, obuf2);



	// display temperature list
	sprintf(obuf2, "%d癈", this->MaxTemp);
	::SetDlgItemText(this->hwndDialog, 8103, obuf2);


	strcpy(templist2, "");
	for (i= 0; i<12; i++) {
		int temp= this->State.Sensors[i];

		if (temp!=128) {
			sprintf(obuf2, "%d癈", temp);
			sprintf(templist2+strlen(templist2), "%s %s (0x%02x)", 
							this->State.SensorName[i],
							obuf2, 
							this->State.SensorAddr[i]);
			strcat(templist2, "\r\n");
		}
		else {
			// strcat(templist2, "n/a\r\n");
		}

	}
	::SetDlgItemText(this->hwndDialog, 8101, templist2);


	// compact single line status (combined)
	strcpy(templist, "");
	for (i= 0; i<12; i++) {
		if (this->State.Sensors[i]!=128) {
			sprintf(templist+strlen(templist), "%d ", this->State.Sensors[i]);
		}
		else {
			strcat(templist, "n/a ");
		}

	}
	templist[strlen(templist)-1]= '\0';
	sprintf(this->CurrentStatus, "Fan: 0x%02x / Highest: %d癈 (%s)", this->State.FanCtrl, this->MaxTemp, templist);
	::SetDlgItemText(this->hwndDialog, 8112, this->CurrentStatus);



	//
	// handle fan control according to mode
	//

	this->CurrentModeFromDialog();

	switch (this->CurrentMode) {

		case 1: // Bios Auto
				if (this->State.FanCtrl!=0x080) 
					ok= this->SetFan("Mode switch", 0x80);
				break;


		case 2: // Smart
				this->SmartControl();
				break;


		case 3: // fixed manual
				::GetDlgItemText(this->hwndDialog, 8310, manlevel, sizeof(manlevel));

				if (isdigit(manlevel[0]) && atoi(manlevel)>=0 && atoi(manlevel)<=255) {

					if (this->State.FanCtrl!=atoi(manlevel)) {
						ok= this->SetFan("Manual", atoi(manlevel));
					}
					else 
						ok= true;
				}
				break;
	}

	this->PreviousMode= this->CurrentMode;

	return ok;
}




//-------------------------------------------------------------------------
//  smart fan control depending on temperature
//-------------------------------------------------------------------------
int 
FANCONTROL::SmartControl(void)
{
	int ok= 0, i,
		newfanctrl= -1,	
		fanctrl= this->State.FanCtrl;	


	// if currently auto force initial fan speed according to rules
	if ((fanctrl & 0x80)!=0 && this->PreviousMode==1) {  
		fanctrl= -1;
		newfanctrl= 0;
	}

	// check for fan-up
	for (i= 0; this->SmartLevels[i].temp!=-1; i++) {
		if (this->MaxTemp>=this->SmartLevels[i].temp && this->SmartLevels[i].fan>fanctrl) 
			newfanctrl= this->SmartLevels[i].fan; 
	}

	// not uptriggered check for downtrigger (previous level hit)
	if (newfanctrl==-1) {	
		for (i= 0; this->SmartLevels[i].temp!=-1; i++) {
			if (this->MaxTemp<=this->SmartLevels[i].temp && this->SmartLevels[i].fan<fanctrl) {
				newfanctrl= this->SmartLevels[i].fan; 
				break;
			}
		}
	}

	// fan speed needs change?
	if (newfanctrl!=-1 && newfanctrl!=fanctrl) {

		if (newfanctrl==0x80) { // switch to BIOS-auto mode
		//	this->ModeToDialog(1); // bios
		}
			
		ok= this->SetFan("Smart", newfanctrl);			
	}

	return ok;
}



//-------------------------------------------------------------------------
//  set fan state via EC
//-------------------------------------------------------------------------
int 
FANCONTROL::SetFan(const char *source, int fanctrl, BOOL final)
{
	int ok= 0;
	char obuf[256]= "", obuf2[256], datebuf[128];

	if (this->FanBeepFreq && this->FanBeepDura)
		::Beep(this->FanBeepFreq, this->FanBeepDura);

	this->CurrentDateTimeLocalized(datebuf, sizeof(datebuf));

	
	sprintf(obuf+strlen(obuf), "%s: Set fan control to 0x%02x, ", source, fanctrl);
	sprintf(obuf+strlen(obuf), "Result: ");

	if (this->ActiveMode && !this->FinalSeen) {

		this->EcAccess.Lock();

		// set new fan level
		ok= this->WriteByteToEC(TP_ECOFFSET_FAN, fanctrl);

		// verify completion
		ok= this->ReadByteFromEC(TP_ECOFFSET_FAN, &this->State.FanCtrl);

		if (ok && final) 
			this->FinalSeen= true;	// prevent further changes when setting final mode

		this->EcAccess.Unlock();

		if (this->State.FanCtrl==fanctrl) {
			sprintf(obuf+strlen(obuf), "OK");
			ok= true;
		}
		else {
			sprintf(obuf+strlen(obuf), "COULD NOT SET FAN STATE!!!!");

			::Beep(880, 300);
			::Sleep(200);
			::Beep(880, 300);
			::Sleep(200);
			::Beep(880, 300);
			ok= false;
		}
	}
	else {
		sprintf(obuf+strlen(obuf), "CMD IGNORED (PASSIVE MODE)");
	}

	// display result
	sprintf(obuf2, "%s   (%s)", obuf, datebuf);
	::SetDlgItemText(this->hwndDialog, 8113, obuf2);

	this->Trace(this->CurrentStatus);
	this->Trace(obuf);

	if (!final)
		::PostMessage(this->hwndDialog, WM__GETDATA, 0, 0);

	return ok;
}



//-------------------------------------------------------------------------
//  read fan and temperatures from embedded controller
//-------------------------------------------------------------------------
int 
FANCONTROL::ReadEcStatus(FCSTATE *pfcstate)
{
	DWORD i, ok, rc= 0;

	FCSTATE sample= { 0, }, 
			sample2= { 0, };

	setzero(pfcstate, sizeof(*pfcstate));

	
	// reading from the EC seems to yield erratic results at times (probably
	// due to collision with other drivers reading from the port).  So try
	// up to three times to read two samples which look oka and have matching
	// value

	this->EcAccess.Lock();

	for (i= 0; i<3; i++) {
		ok= this->ReadEcRaw(&sample);
		if (ok) {
			ok= this->ReadEcRaw(&sample2);
			if (ok) {

				// match for identical fanctrl settings and temperature differences
				// of no more than 1癈
				BOOL match= sample.FanCtrl==sample2.FanCtrl;
				for (int j= 0; j<12 && match; j++) {
					if (sample.Sensors[j]>128 || sample2.Sensors[j]>128 ||
						abs(sample.Sensors[j]-sample2.Sensors[j])>1) {
						match= false;
					}
				}
				
				if (match) {	// looks good
					ok= true;
					break;
				}
				else {		// try again after short delay
					ok= false;
					::Sleep(200);
				}
			}
		}
	} 

	this->EcAccess.Unlock();

	if (ok) {
		memcpy(pfcstate, &sample, sizeof(*pfcstate));
	}

	return ok;
}



//-------------------------------------------------------------------------
//  read fan and temperatures from embedded controller
//-------------------------------------------------------------------------
int 
FANCONTROL::ReadEcRaw(FCSTATE *pfcstate)
{
	int i, idxtemp, ok;

	pfcstate->FanSpeedLo= 0;
	pfcstate->FanSpeedHi= 0;
	pfcstate->FanCtrl= -1;
	memset(pfcstate->Sensors, 0, sizeof(pfcstate->Sensors));

	
	ok= ReadByteFromEC(TP_ECOFFSET_FAN, &pfcstate->FanCtrl);

	if (ok)
		ok= ReadByteFromEC(TP_ECOFFSET_FANSPEED, &pfcstate->FanSpeedLo);

	if (ok)
		ok= ReadByteFromEC(TP_ECOFFSET_FANSPEED+1, &pfcstate->FanSpeedHi);

	idxtemp= 0;
	for (i= 0; i<8 && ok; i++) {	// temp sensors 0x78 - 0x7f
		ok= ReadByteFromEC(TP_ECOFFSET_TEMP0+i, &pfcstate->Sensors[idxtemp]);
		pfcstate->SensorAddr[idxtemp]= TP_ECOFFSET_TEMP0+i;
		pfcstate->SensorName[idxtemp]= gSensorNames[idxtemp];
		idxtemp++;
	}

	for (i= 0; i<4 && ok; i++) {	// temp sensors 0xC0 - 0xC4
		ok= ReadByteFromEC(TP_ECOFFSET_TEMP1+i, &pfcstate->Sensors[idxtemp]);
		pfcstate->SensorAddr[idxtemp]= TP_ECOFFSET_TEMP1+i;
		pfcstate->SensorName[idxtemp]= gSensorNames[idxtemp];
		idxtemp++;
	}

	return ok;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -