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

📄 portio.cpp

📁 通过EC的SMBUS接口读取电池信息
💻 CPP
📖 第 1 页 / 共 2 页
字号:

// --------------------------------------------------------------
//
//  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 + -