Мне нужно понять алгоритм изменения скорости кулера процессора. Есть
рабочий код управления регистрами контроллера (я проверял установкой программы, его содержащей, скорость кулера корректно регулируется) Я понимаю этот код так:
1) Послать в порт номер 0x66 команду 0x99
2) Для случая CPU FAN послать в порт 0x62 команду 0x1
3) Потом послать hex данные в порт 0x62
Где-то я ошибся, т.к. при ручном изменении регистров в соответствии с понятым мной алгоритмом, скорость кулера не меняется. Пожалуйста, помогите мне найти ошибку в моем анализе кода.
Это код доступа к регистрам, очищенный от функций, не имеющих отношения к ручному управлению оборотами кулера.
#include <napi.h>
#include <sys/io.h>
#include <unistd.h>
#define EC_COMMAND_PORT 0x66
#define EC_DATA_PORT 0x62
#define IBF 1
#define OBF 0
#define EC_SC_READ_CMD 0x80
#define EC_REG_CPU_FAN_RPMS_HI 0xD0
#define EC_REG_CPU_FAN_RPMS_LO 0xD1
#define EC_REG_GPU_FAN_RPMS_HI 0xD2
#define EC_REG_GPU_FAN_RPMS_LO 0xD3
#define TEMP 0x9E
/**
* Set IO port input/output permissions
* On success, zero is returned. On error, -1 is returned, and errno is
* set appropriately.
*
* @return Status of Operation
*/
static int EcInit()
{
if (ioperm(EC_DATA_PORT, 1, 1) != 0)
{
return EXIT_FAILURE;
}
if (ioperm(EC_COMMAND_PORT, 1, 1) != 0)
{
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
/**
* Wait on EC
*
* @param port The port for waiting
* @param flag
* @param value
*
* @return Status of Operation
*/
static int EcIoWait(const uint32_t port, const uint32_t flag, const char value)
{
uint8_t data = inb(port);
int i = 0;
while ((((data >> flag) & 0x1) != value) && (i++ < 100))
{
data = inb(port);
}
if (i >= 100)
{
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
/**
* Read the Port informations
*
* @param port The port for waiting
*
* @return the Data
*/
static uint8_t EcIoRead(const uint32_t port)
{
EcIoWait(EC_COMMAND_PORT, IBF, 0);
outb(EC_SC_READ_CMD, EC_COMMAND_PORT);
EcIoWait(EC_COMMAND_PORT, IBF, 0);
outb(port, EC_DATA_PORT);
EcIoWait(EC_COMMAND_PORT, OBF, 1);
uint8_t value = inb(EC_DATA_PORT);
return value;
}
/**
* Flush the EC
*/
static void EcFlush()
{
while ((inb(EC_COMMAND_PORT) & 0x1) == 0x1)
{
inb(EC_DATA_PORT);
}
}
/**
* Read a byte from EC
*
* @return Returns the current byte
*/
static int ReadByte()
{
int i = 1000000;
while ((inb(EC_COMMAND_PORT) & 1) == 0 && i > 0)
{
i -= 1;
}
if (i == 0)
{
return 0;
}
else
{
return inb(EC_DATA_PORT);
}
}
/**
* Send a command to the ec
*
* @param command the comamnd to send
*/
static void SendCommand(int command)
{
int tt = 0;
while((inb(EC_COMMAND_PORT) & 2))
{
tt++;
if(tt>30000)
{
break;
}
}
outb(command, EC_COMMAND_PORT);
}
/**
* Write data to ec
*
* @param data the data to write
*/
static void WriteData(int data)
{
while((inb(EC_COMMAND_PORT) & 2));
outb(data, EC_DATA_PORT);
}
/**
* Set the fan duty
*
* @param info the nodejs CallbackInfo
*
* @return Returns a bool to indicate was the operation sucessfully or not
*/
Napi::Boolean SetFanDuty(const Napi::CallbackInfo& info)
{
Napi::Env env = info.Env();
if (info.Length() != 2)
{
Napi::TypeError::New(env, "Wrong number of arguments").ThrowAsJavaScriptException();
return Napi::Boolean::New(env, false);
}
if (!info[0].IsNumber())
{
Napi::TypeError::New(env, "Wrong argument for index").ThrowAsJavaScriptException();
return Napi::Boolean::New(env, false);
}
if (!info[1].IsNumber())
{
Napi::TypeError::New(env, "Wrong argument for duty").ThrowAsJavaScriptException();
return Napi::Boolean::New(env, false);
}
uint32_t index = info[0].As<Napi::Number>();
uint32_t fanDuty = info[1].As<Napi::Number>();
if (fanDuty < 1 || fanDuty > 255)
{
std::string message = "Wrong fan duty to write: " + std::to_string(fanDuty) + "\n";
Napi::Error::New(env, message).ThrowAsJavaScriptException();
return Napi::Boolean::New(env, false);
}
EcInit();
SendCommand(0x99);
switch(index)
{
case 1:
WriteData(0x01);
break;
case 2:
WriteData(0x02);
break;
case 3:
WriteData(0x03);
break;
default:
return Napi::Boolean::New(env, false);
}
WriteData(fanDuty);
return Napi::Boolean::New(env, true);
}