📄 portio.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"
#include "winio.h"
// Registers of the embedded controller
#define EC_DATAPORT 0x62 // EC data io-port
#define EC_CTRLPORT 0x66 // EC control io-port
// Embedded controller status register bits
#define EC_STAT_OBF 0x01 // Output buffer full
#define EC_STAT_IBF 0x02 // Input buffer full
#define EC_STAT_CMD 0x08 // Last write was a command write (0=data)
// Embedded controller commands
// (write to EC_CTRLPORT to initiate read/write operation)
#define EC_CTRLPORT_READ (char)0x80
#define EC_CTRLPORT_WRITE (char)0x81
#define EC_CTRLPORT_QUERY (char)0x84
#define EC_SMPR 0x0
#define EC_SMST 0x1
#define EC_SMAD 0x2
#define EC_SMCM 0x3
#define EC_SMD0 0x4 // 32 byte
#define EC_BCNT 0x24
#define EC_SMAA 0x25
int verbosity= 0; // verbosity for the logbuf (0= nothing)
char lasterrorstring[256]= "",
logbuf[8192]= "";
//-------------------------------------------------------------------------
// read control port and wait for set/clear of a status bit
//-------------------------------------------------------------------------
int
waitportstatus(int bits, int onoff= false, int timeout= 1000)
{
int ok= false,
port= EC_CTRLPORT,
time= 0,
tick= 10;
strcpy(lasterrorstring, "");
//
// wait until input on control port has desired state or times out
//
for (time= 0; time<timeout; time+= tick) {
DWORD data= 0;
int done= GetPortVal(port, &data, 1);
if (verbosity>0)
sprintf(logbuf+strlen(logbuf), "waitportstatus: tick port= %02x, status= %02x => data was %02x\n", port, bits, data);
if (!done) {
strcpy(lasterrorstring, "waitportstatus: GetPortValue failed");
break;
}
// check for desired result
int flagstate= (((char)data) & bits)!=0,
wantedstate= onoff!=0;
if (flagstate==wantedstate) {
ok= true;
break;
}
// try again after a moment
::Sleep(tick);
}
if (!ok && strlen(lasterrorstring)==0) {
sprintf(lasterrorstring, "waitportstatus: timeout waiting for port %02x to change to status %02x/%d", port, bits, onoff);
}
if (!ok) {
sprintf(logbuf+strlen(logbuf), "waitportstatus returns failed: ok= %d\n", ok);
}
return ok;
}
//-------------------------------------------------------------------------
// write a character to an io port through WinIO device
//-------------------------------------------------------------------------
int
writeport(int port, char data)
{
strcpy(lasterrorstring, "");
// write byte via WINIO.SYS
int done= SetPortVal(port, data, 1);
if (!done) {
sprintf(lasterrorstring, "writeport: port %02x, data %02x failed\n", port, data);
}
if (verbosity>1) {
sprintf(logbuf+strlen(logbuf), "writeport port= %02x, data= %02x, done= %d\n", port, data, done);
}
return done;
}
//-------------------------------------------------------------------------
// read a character from an io port through WinIO device
//-------------------------------------------------------------------------
int
readport(int port, char *pdata)
{
DWORD data= -1;
// read byte via WINIO.SYS
int done= GetPortVal(port, &data, 1);
if (done) {
*pdata= (char)data;
}
else {
sprintf(lasterrorstring, "readport: port %02x failed\n", port, data);
}
if (verbosity>1)
sprintf(logbuf+strlen(logbuf), "readport port= %02x, data= %02x, done= %d\n", port, (char)data, done);
return done;
}
//-------------------------------------------------------------------------
// read a byte from the embedded controller (EC) via port io
//-------------------------------------------------------------------------
int
FANCONTROL::ReadByteFromEC(int offset, char *pdata)
{
int ok;
// wait for IBF and OBF to clear
ok= waitportstatus(EC_STAT_IBF | EC_STAT_OBF, false);
if (ok) {
// tell 'em we want to "READ"
ok= writeport(EC_CTRLPORT, EC_CTRLPORT_READ);
if (ok) {
// wait for IBF to clear (command byte removed from EC's input queue)
ok= waitportstatus(EC_STAT_IBF, false);
if (ok) {
// tell 'em where we want to read from
ok= writeport(EC_DATAPORT, offset);
if (ok) {
// wait for IBF to clear (address byte removed from EC's input queue)
// Note: Techically we should waitportstatus(OBF,TRUE) here,(a byte being
// in the EC's output buffer being ready to read). For some reason
// this never seems to happen
ok= waitportstatus(EC_STAT_IBF, false);
if (ok) {
char data= -1;
// read result (EC byte at offset)
ok= readport(EC_DATAPORT, &data);
if (ok)
*pdata= data;
}
}
}
}
}
if (verbosity>0)
sprintf(logbuf+strlen(logbuf), "readec: offset= %x, data= %02x, ok= %d\n", offset, *pdata, ok);
return ok;
}
//-------------------------------------------------------------------------
// write a byte to the embedded controller (EC) via port io
//-------------------------------------------------------------------------
int
FANCONTROL::WriteByteToEC(int offset, char data)
{
int ok;
// wait for IBF and OBF to clear
ok= waitportstatus(EC_STAT_IBF| EC_STAT_OBF, false);
if (ok) {
// tell 'em we want to "WRITE"
ok= writeport(EC_CTRLPORT, EC_CTRLPORT_WRITE);
if (ok) {
// wait for IBF to clear (command byte removed from EC's input queue)
ok= waitportstatus(EC_STAT_IBF, false);
if (ok) {
// tell 'em where we want to write to
ok= writeport(EC_DATAPORT, offset);
if (ok) {
// wait for IBF to clear (address byte removed from EC's input queue)
ok= waitportstatus(EC_STAT_IBF, false);
if (ok) {
// tell 'em what we want to write there
ok= writeport(EC_DATAPORT, data);
if (ok) {
// wait for IBF to clear (data byte removed from EC's input queue)
ok= waitportstatus(EC_STAT_IBF, false);
}
}
}
}
}
}
if (verbosity>2)
sprintf(logbuf+strlen(logbuf), "writeec: offset= %x, data= %02x, ok= %d\n", offset, data, ok);
return ok;
}
//-------------------------------------------------------------------------
// write a byte to the embedded controller (EC) via port io
//-------------------------------------------------------------------------
int
FANCONTROL::ECSMBusWaitComplete(char SMBusBaseOffsetInERAM, int Timeout)
//
// SWTC (Wait for Transaction Complete):
// -------------------------------------------
// Wait until the previous SMBus transaction has completed.
//
// Parameters:
// Arg0 = Timeout Value (in ms)
//
// Return Value:
// 0x00 = OK
// 0x07 = Unknown Failure
// 0x10 = Address Not Acknowledged
// 0x11 = Device Error
// 0x12 = Command Access Denied
// 0x13 = Unknown Error
// 0x17 = Device Access Denied
// 0x18 = Timeout
// 0x19 = Unsupported Protocol
// 0x1A = Bus Busy
// 0x1F = PEC (CRC-8) Error
//
//Method(SWTC, 1)
{
char buffer;
int status = 0x07;
//Store(Arg0, Local0)
//Store(0x07, Local2)
//
// The previous command has completed when the protocol
// register is equal to 0 (zero). Wait <timeout> ms
// (in 10ms chunks) for this to occur.
//
//Store(1, Local1)
//While(LEqual(Local1, 1))
while ( Timeout )
{
//If(LEqual(PRTC, 0))
status = ReadByteFromEC( SMBusBaseOffsetInERAM + EC_SMPR, &buffer) ;
if(status != TRUE) return 0x07;
if( buffer == 0 )
{
//And(STS, 0x1F, Local2) // Store status code.
//Store(0x00, Local1) // Terminate loop.
status = ReadByteFromEC( SMBusBaseOffsetInERAM +EC_SMST, &buffer) ;
if(status != TRUE) return 0x07;
status = buffer & 0x1F;
break;
}
//Else
else
{
//
// Transaction isn't complete. Check for timeout, and if not,
// sleep 10ms and loop again.
//
/*If(LLess(Local0, 10))
{
Store(0x18, Local2) // ERROR: Timeout occurred.
Store(0x00, Local1) // Terminate loop.
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -