habl
@habl
Инженер, спортсмен

Где моя ошибка в анализе алгоритма управления оборотами кулера?

Мне нужно понять алгоритм изменения скорости кулера процессора. Есть рабочий код управления регистрами контроллера (я проверял установкой программы, его содержащей, скорость кулера корректно регулируется) Я понимаю этот код так:

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);
}
  • Вопрос задан
  • 126 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы