首页 > 系统相关 >联想笔记本电脑在Windows下通过联想驱动实现风扇控制

联想笔记本电脑在Windows下通过联想驱动实现风扇控制

时间:2024-10-31 19:30:36浏览次数:5  
标签:00 Lenovo NORMAL Windows 联想 风扇 fan mode

概述

本文旨在解决部分联想笔记本电脑无法使用主流的风扇控制工具(如Fan Control, SpeedFan)控制风扇的问题。主流的风扇控制工具在这些电脑上会因无法找到控制风扇的EC寄存器而无法发挥作用。但这是不是就意味着没办法控制风扇了呢?答案是否定的。在出厂自带的联想电脑管家程序中有一个叫做降温除尘的工具,运行这个工具能够让风扇达到最高转速,维持几秒然后恢复正常转速。

查看联想电脑管家程序文件,这个降温除尘工具其实是调用了一个叫做IdeaFanPlugin.dll的链接库,根据这个dll的名称猜测这可能是一个叫做IdeaFan程序的插件,通过搜索引擎得知IdeaFan是一个用于控制联想电脑风扇的程序。测试发现无论是联想电脑管家还是IdeaFan,都是通过Lenovo ACPI-Compliant Virtual Power Controller驱动来控制风扇的,这个驱动正是联想笔记本电脑所特有的电源控制驱动。

按照这个思路,笔者最终找到了2个相关的开源项目FanControlLenovo-IdeaPad-Z500-Fan-Controller,这2个项目通过逆向了相关驱动,找到了使用Lenovo ACPI-Compliant Virtual Power Controller驱动控制风扇的方法,不过美中不足的是只能控制风扇在最高转速和正常转速间切换,而不能设定和读取风扇的具体转速。

这2个项目还有个问题,就是只能实现让风扇断断续续地以最高转速运行,而我通过调试找到了解决这个问题的方法,详见下文。

具体实现

以下代码主要参考了FanControl项目,查看该开源项目的源码,发现需要用到的核心函数就2个,一个用于控制风扇,一个用于获取风扇状态,且都是通过直接读写\\.\EnergyDrv这个设备的某些字节实现的,以下是修改项目源码得到的一个简单的样例:

#include <stdio.h>
#include <Windows.h>

// NORMAL: Fan spins at normal speed.
// FAST: Fan spins at the highest speed.
enum FanMode { NORMAL, FAST };

// Control the operating mode of the fan.
int fan_control(enum FanMode mode) {
	HANDLE hndl = CreateFileW(L"\\\\.\\EnergyDrv", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hndl == INVALID_HANDLE_VALUE) {
		return -1;
	}

	// lpInBuffer value: 06 00 00 00  01 00 00 00  01 00 00 00 ~ [ 6, 1, 1 ] (inv endian)
	DWORD inBuffer[3] = { 6, 1 };
	inBuffer[2] = mode;
	DWORD bytesReturned = 0;

	DeviceIoControl(hndl, 0x831020C0, inBuffer, sizeof(inBuffer), NULL, 0, &bytesReturned, NULL);
	CloseHandle(hndl);

	return 1;
}

// Get the current operating mode of the fan.
int read_state() {
	HANDLE hndl = CreateFileW(L"\\\\.\\EnergyDrv", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hndl == INVALID_HANDLE_VALUE) {
		return -1;
	}
	// lpInBuffer value: 0E 00 00 00 ~ [ 14 ] (inv endian)
	DWORD inBuffer = 14;
	DWORD outBuffer;
    DWORD bytesReturned = 0;

	DeviceIoControl(hndl, 0x831020C4, &inBuffer, sizeof(inBuffer), &outBuffer, sizeof(outBuffer), &bytesReturned, NULL);
	CloseHandle(hndl);

    if (outBuffer == 3) {
        return FAST;
    }
	return Normal;
}

int main() {
    int mode = read_state();
    if (mode == -1) {
        printf("Failed to open \\\\.\\EnergyDrv\n");
        return 1;
    }
    if (mode == NORMAL) {
        printf("FAST mode on\n");
        fan_control(FAST);
    } else {
        printf("NORMAL mode on\n");
        fan_control(NORMAL);
    }
    return 0;
}

函数int fan_control(enum FanMode mode)用于控制风扇的运行状态,参数mode指定风扇运行模式,取值0控制风扇恢复正常转速,取值1控制风扇达到最高转速。 返回值-1表示没有找到联想电源管理驱动,无法实现控制,返回1表示成功实现控制。

函数int read_state()用于获取风扇当前的运行状态,返回0表示当前风扇为正常转速模式,返回1表示当前风扇为最高速运行模式。

编译运行程序,控制台输出FAST mode on则风扇开启最高转速,程序结束运行,再次运行程序控制台输出NORMAL mode on,风扇恢复正常运行状态。如果输出Failed to open \\.\EnergyDrv则说明没有安装Lenovo ACPI-Compliant Virtual Power Controller驱动,或没有驱动正常运行。

到这里事情还没结束,上述代码控制风扇所使用的实际上是驱动所提供的一个风扇除尘功能(联想电脑管家和IdeaFan也是如此),在实际使用中风扇并非如我们所设想的那样一直保持最高转速状态运行,而是会先以最高速度转约9秒钟,暂停2秒,再以最高转速转9秒,再停顿2秒如此循环往复,直到大约2分钟后风扇恢复正常运行状态,风扇又重新交给系统进行控制。

也就是说,开源项目中的上述代码只能让风扇断断续续地运行,且只能维持2分钟,需要继续改进。

通过不断调试,笔者找到了能让风扇保持高速运行的方法,代码如下:

void keep_fast() {
    int interval = 9000; // ms, fine-tuned, see https://www.allstone.lt/ideafan/
    while (1) {
        if (read_state() == FAST) {
            Sleep(interval);
            fan_control(NORMAL); // Reset the fan to NORMAL mode, than switch to FAST mode as soon as possible.
        } else {
            fan_control(FAST);
            Sleep(10);
        }
    }
}

在函数void keep_fast()中,先循环判断风扇当前运行状态,如果不为高速运行状态则不断尝试控制风扇高速运行,当风扇此时为高速运行状态时,维持9秒后将风扇切换回正常运行状态以此重置计时,随后在风扇停止转动前又立即切换回高速运行状态,这样一次快速的切换就能让风扇跳过原来2秒漫长的停顿,取而代之的是0.1秒左右的短暂停顿,这样不断循环就能实现风扇一直以高速状态运行了。

void keep_fast()整合进样例中得到能够完美控制风扇的代码:

#include <stdio.h>
#include <Windows.h>

// NORMAL: Fan spins at normal speed.
// FAST: Fan spins at the highest speed.
enum FanMode { NORMAL, FAST };

// Control the operating mode of the fan.
int fan_control(enum FanMode mode) {
	HANDLE hndl = CreateFileW(L"\\\\.\\EnergyDrv", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hndl == INVALID_HANDLE_VALUE) {
		return -1;
	}

	// lpInBuffer value: 06 00 00 00  01 00 00 00  01 00 00 00 ~ [ 6, 1, 1 ] (inv endian)
	DWORD inBuffer[3] = { 6, 1 };
	inBuffer[2] = mode;
	DWORD bytesReturned = 0;

	DeviceIoControl(hndl, 0x831020C0, inBuffer, sizeof(inBuffer), NULL, 0, &bytesReturned, NULL);
	CloseHandle(hndl);

	return 1;
}

// Get the current operating mode of the fan.
int read_state() {
	HANDLE hndl = CreateFileW(L"\\\\.\\EnergyDrv", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hndl == INVALID_HANDLE_VALUE) {
		return -1;
	}
	// lpInBuffer value: 0E 00 00 00 ~ [ 14 ] (inv endian)
	DWORD inBuffer = 14;
	DWORD outBuffer;
    DWORD bytesReturned = 0;

	DeviceIoControl(hndl, 0x831020C4, &inBuffer, sizeof(inBuffer), &outBuffer, sizeof(outBuffer), &bytesReturned, NULL);
	CloseHandle(hndl);

    if (outBuffer == 3) {
        return FAST;
    }
    return NORMAL;
}

// Try to keep the fan in fast mode. Blocking.
void keep_fast() {
    int interval = 9000; // ms, fine-tuned, see https://www.allstone.lt/ideafan/
    while (1) {
        if (read_state() == FAST) {
            Sleep(interval);
            fan_control(NORMAL); // Reset the fan to NORMAL mode, than switch to FAST mode as soon as possible.
        } else {
            fan_control(FAST);
            Sleep(10);
        }
    }
}

int main() {
    int mode = read_state();
    switch (mode) {
        case -1:
            printf("Failed to open \\\\.\\EnergyDrv\n");
            break;
        case FAST:
            printf("NORMAL mode on\n");
            fan_control(NORMAL);
            break;
        default:
            printf("FAST mode on\n");
            keep_fast();
    }
    printf("Enter to exit...");
    getchar();
    return 0;
}

相关进一步完善的代码及样例程序我已上传至Github:

https://github.com/jiarandiana0307/Lenovo-Fan-Control

原理探讨

那么这样控制风扇的原理是什么呢?归根结底,笔记本电脑的风扇一般是由嵌入式控制器(Embedded Controller, EC)控制的,我们可以通过改变EC中寄存器的值来控制风扇。

但是,有些电脑的数据手册并没有说明EC用于控制风扇转速的是哪个寄存器,所以,前文提到的开源项目的作者逆向了Lenovo Energy Manager和相关驱动,最终发现可以通过Lenovo ACPI-Compliant Virtual Power Controller驱动控制EC,进而实现控制风扇的目的。

前文代码中出现的\\.\EnergyDrv就是由Lenovo ACPI-Compliant Virtual Power Controller驱动所生成的设备,也是该驱动向外提供的用于控制和访问的接口,上文的代码中直接读写\\.\EnergyDrv这个设备其实就是在与驱动交互,进而实现控制风扇、获取风扇状态的目的。进一步实验也证实了这一点,当这个驱动正常工作时,可以正常访问\\.\EnergyDrv设备,而当卸载了驱动并重启后这个设备就不存在且无法访问了。

不妨大胆假设,只要是安装了Lenovo ACPI-Compliant Virtual Power Controller驱动的联想笔记本电脑,应该都可以实现风扇控制。根据网上的信息和我自己的测试,以下联想机型是可行的:

  • Lenovo G500
  • Lenovo G580
  • Lenovo Ideapad 3 15ALC6 82KU
  • Lenovo Ideapad 3 15ITL6
  • Lenovo IdeaPad 330
  • Lenovo IdeaPad Y510
  • Lenovo Ideapad Z580
  • Lenovo Xiaoxin 15IIL 2020
  • Lenovo Y410P
  • Lenovo Y500
  • Lenovo Y50-70
  • Lenovo Y510p
  • Lenovo Y580
  • Lenovo Z580

但是碍于身边没有其他的联想笔记本电脑,无法进行更多的测试,无法确定其他机型是否使用。

参考

  1. Lenovo-Fan-Control
  2. IdeaFan
  3. FanControl
  4. Lenovo-IdeaPad-Z500-Fan-Controller
  5. Windows Drivers Reverse Engineering Methodology

标签:00,Lenovo,NORMAL,Windows,联想,风扇,fan,mode
From: https://www.cnblogs.com/kiradiana/p/18518728

相关文章

  • 【YOLO目标检测实战 】1.Windows安装WSL2和Linux子系统
    1下载安装显卡驱动下载地址:https://www.nvidia.cn/geforce/drivers/根据显卡型号,下载显卡驱动根据默认选项,安装显卡驱动查看显卡驱动是否安装成功右键开启菜单->命令提示符(管理员)在命令行中输入nvidia-smi.exe命令,查看显卡驱动是否安装成功。2下载安装MobaXte......
  • windows 命令行执行.bat ,显示已经达到最大的setlocal递归层,解决办法
    windows命令行执行.bat,显示已经达到最大的setlocal递归层,网上也没有一个确切的解决办法,自己摸索寻找解决如下:C:\Users\yangz\Desktop>pingwww.baidu.com已经达到最大的setlocal递归层。一.解决思路:这条信息表明你在使用Windows命令提示符(CMD)时遇到了一个错误。错误信......
  • nltest 是一个 Windows 命令行工具,用于测试和管理 Windows 域的信任和连接状态。以下
    Nltest|MicrosoftLearnnltest是一个Windows命令行工具,用于测试和管理Windows域的信任和连接状态。以下是一些常用的nltest命令示例:1.查询域信任关系bashCopyCodenltest/domain_trusts该命令显示当前计算机与其域和其他信任域之间的信任关系。2.验证域控制器b......
  • 实现Linux系统与Windows系统之间文件共享
    实现Linux系统与Windows系统之间文件共享Samba服务1:先到yum仓库安装相关服务[root@linuxprobe~]#yuminstallsambaLoadedplugins:langpacks,product-id,subscription-manager省略Installing:sambax86_644.1.1-31.el7rhel527kTransactionSummary=======......
  • Windows安全加固
    一、账号和口令管理账号分配compmgmt.msc>计算机管理>本地用户和组​结合要求和实际业务情况判断符合要求,根据系统的要求,设定不同的账户和账户组,管理员用户,数据库用户,审计用户,来宾用户如存在与设备运行、维护等与工作无关的账号,可进行删除或锁定重命名Administrato......
  • Windows11系统iisetw.dll文件丢失问题
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个iisetw.dll文件(挑选合适的版本文件)把它放......
  • Adobe Animate 2025 v25.0 (macOS, Windows) - 动画制作
    AdobeAnimate2025v25.0(macOS,Windows)-动画制作Acrobat、AfterEffects、Animate、Audition、Bridge、CharacterAnimator、Dimension、Dreamweaver、Illustrator、InCopy、InDesign、LightroomClassic、MediaEncoder、Photoshop、PremierePro、AdobeXD请访问原文链......
  • Adobe After Effects 2025 v25.0 (macOS, Windows) - 后期特效
    AdobeAfterEffects2025v25.0(macOS,Windows)-后期特效Acrobat、AfterEffects、Animate、Audition、Bridge、CharacterAnimator、Dimension、Dreamweaver、Illustrator、InCopy、InDesign、LightroomClassic、MediaEncoder、Photoshop、PremierePro、AdobeXD请访问......
  • Adobe Illustrator 2025 v29.0 (macOS, Windows) - 矢量绘图
    AdobeIllustrator2025v29.0(macOS,Windows)-矢量绘图Acrobat、AfterEffects、Animate、Audition、Bridge、CharacterAnimator、Dimension、Dreamweaver、Illustrator、InCopy、InDesign、LightroomClassic、MediaEncoder、Photoshop、PremierePro、AdobeXD请访问原......
  • Adobe Character Animator 2025 v25.0 (macOS, Windows) - 动作捕获动画软件
    AdobeCharacterAnimator2025v25.0(macOS,Windows)-动作捕获动画软件Acrobat、AfterEffects、Animate、Audition、Bridge、CharacterAnimator、Dimension、Dreamweaver、Illustrator、InCopy、InDesign、LightroomClassic、MediaEncoder、Photoshop、PremierePro、Ad......