Blue Sky N141WUファンから熱を放出するとノイズが発生する

Blue Sky N141WUファンから熱を放出するとノイズが発生する

たった一つ買った青い空N141WU(システム76ではガラゴプロとして知られています)はデンマークのPCストアで販売されています。

ほとんどの場合、うまく機能しますが、作業量が多い後にファンが回転を停止すると、非常に高い音が鳴り始め、ファンが停止します(ファンが回転するのに必要な電圧を受け取らないように聞こえます)。

店舗に電話したところ、ソリューションが一部のWindowsソフトウェアでしたが、PCにはウィンドウがなく、Linuxを実行するために最初に購入しました(ガラゴプロと同じだったので動作すると思いました)。

ノートブックがsystem76 Linuxを実行しているので、これが可能でなければならないと思いました。

より良い実行のためにインストールする必要がありますか?それとも、ファンを幸せにするBIOSトリックを知っている人はいますか?

私はSolus 3.Xを実行しています。ここで x は挿入に時間がかかるだけの 9 です;-)

キーボードショートカットFn+ 1(system76 galago proノイズの多いファンの投稿にあります)を2回使用すると、ファンの電源がオンまたはオフになります。これにより、次回ハードロードまで音が聞こえなくなります。

元の投稿から2つの事実が見つかりました。

  • system76にはいくつかのファームウェアアップデートがありますが、他の販売代理店のラップトップを持っている人にそれを送る意思があるかどうか誰が知っていますか? (彼らに聞いてほしいと思います。)
  • System76には、ファンコントロールを提供できるUbuntuのsystem76-dkmsというパッケージがありますが、Solusリポジトリにはありません。 (今夜、Solus ircに梱包がどのように機能するか尋ねることもできます。)

答え1

Windows 10では、次のコードを使用して成功しました。これはファンの2つの可能なエラーを処理します。つまり、「ファン負荷=0でファンが突然停止する。」 「rpm> 10000でファンが突然停止し、ファンから電気ノイズが聞こえます。」バックグラウンドで実行するには、Winring0(ThrottleStopなど)をロードするプログラムが必要です。 Blue Sky Control Centerをインストールした状態でテストしてみませんでした。 MinGW-w64を使用してコンパイルされました。\yourmingwpath\i686-w64-mingw32-gcc.exe \yoursourcepath\main.c -o \yourexepath\main.exe -Wall -mwindows

#define UNICODE 1
#define _UNICODE 1

#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
#include <stddef.h>

#define OLS_TYPE 40000
#define IOCTL_OLS_READ_IO_PORT_BYTE CTL_CODE(OLS_TYPE, 0x833, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_OLS_WRITE_IO_PORT_BYTE CTL_CODE(OLS_TYPE, 0x836, METHOD_BUFFERED, FILE_WRITE_ACCESS)

#define EC_SC 0x66
#define EC_DATA 0x62

#define IBF 1
#define OBF 0
#define EC_SC_READ_CMD 0x80

typedef struct _OLS_WRITE_IO_PORT_INPUT {
    ULONG   PortNumber; 
    union {
        ULONG   LongData;
        USHORT  ShortData;
        UCHAR   CharData;
    };
}   OLS_WRITE_IO_PORT_INPUT;

HANDLE hDevice = INVALID_HANDLE_VALUE;
char filename[1024] = {0};

WORD WInp(WORD port) {
    FILE *outlog;
    unsigned int error = 0;

    DWORD   returnedLength = 0;
    WORD    value = 0;
    BOOL    bResult = FALSE;
    bResult = DeviceIoControl(hDevice,
                            IOCTL_OLS_READ_IO_PORT_BYTE,
                            &port, sizeof(port),
                            &value, sizeof(value),
                            &returnedLength,
                            NULL );
    if (bResult) {
        /*outlog = fopen(filename, "ab");
        fprintf(outlog, "port=%d, value=%d, retlength=%d\n", port, value, (int)returnedLength);
        fclose(outlog);*/
        return value;
    } else {
        error = GetLastError();
        outlog = fopen(filename, "ab");
        fprintf(outlog, "DeviceIoControl (read) failed. Error %d.\n", error);
        fclose(outlog);
        CloseHandle(hDevice);
        return 0;
    }
}

WORD WOutp(WORD port, BYTE value) {
    FILE *outlog;
    unsigned int error = 0;

    DWORD   returnedLength = 0;
    BOOL    bResult = FALSE;
    DWORD   length = 0;
    OLS_WRITE_IO_PORT_INPUT inBuf;
    inBuf.CharData = value;
    inBuf.PortNumber = port;
    length = offsetof(OLS_WRITE_IO_PORT_INPUT, CharData) + sizeof(inBuf.CharData);
    bResult = DeviceIoControl(hDevice,
                            IOCTL_OLS_WRITE_IO_PORT_BYTE,
                            &inBuf, length,
                            NULL, 0,
                            &returnedLength,
                            NULL);
    if (bResult) {
        /*outlog = fopen(filename, "ab");
        fprintf(outlog, "port=%d, value=%d, retlength=%d\n", port, value, (int)returnedLength);
        fclose(outlog);*/
        return value;
    } else {
        error = GetLastError();
        outlog = fopen(filename, "ab");
        fprintf(outlog, "DeviceIoControl (write) failed. Error %d.\n", error);
        fclose(outlog);
        CloseHandle(hDevice);
        return 0;
    }
}

int wait_ec(const unsigned int port, const unsigned int flag, const char value) {
    int i = 0;
    unsigned char data = WInp(port);

    while (((data >> flag)&0x1)!=value) {
        Sleep(1);
        if (i>10) {
            //printf( "Still waiting on port 0x%x, data=0x%x, flag=0x%x, value=0x%x, i=%d\n", port, data, flag, value, i);
            return 0;
        }
        i++;
        data = WInp(port);
    }
    //printf( "Succeeded port 0x%x, data=0x%x, flag=0x%x, value=0x%x, i=%d\n", port, data, flag, value, i);
    return 0;
}

unsigned char read_ec(const unsigned int port) {
    wait_ec(EC_SC, IBF, 0);
    WOutp(EC_SC, EC_SC_READ_CMD);
    wait_ec(EC_SC, IBF, 0);
    WOutp(EC_DATA, port);
    wait_ec(EC_SC, OBF, 1);
    return WInp(EC_DATA);
}

void do_ec(const unsigned int cmd, const unsigned int port, const unsigned char value) {
    wait_ec(EC_SC, IBF, 0);
    WOutp(EC_SC, cmd);
    wait_ec(EC_SC, IBF, 0);
    WOutp(EC_DATA, port);
    wait_ec(EC_SC, IBF, 0);
    WOutp(EC_DATA, value);
    wait_ec(EC_SC, IBF, 0);
    return;
}

void write_fan_duty(int duty_percentage) {
    do_ec(0x99, 0x01, (int)(((double) duty_percentage) / 100.0 * 255.0));
    //FILE *outlog = fopen(filename, "ab");
    //fprintf(outlog, "Fan set to %d\n", duty_percentage);
    //fclose(outlog);
    return;
}

int main(){
    // get the path of this executable and append "stdout.txt\0" to it for the log file.
    int i = GetModuleFileNameA(NULL, filename, 1024);
    for (;i>0 && filename[i] != '\\';i--) {}
    char *dest=&filename[i+1], *src="stdout.txt\0";
    for (i=0;i<11;i++) dest[i]=src[i];

    FILE *outlog;
    outlog = fopen(filename, "wb"); // clear the log at every start
    fclose(outlog);
    unsigned int error = 0;

    // I could loop CreateFile until a valid handle is returned (which means that WinRing0_1_2_0 got started by throttlestop)
    // but windows defender blocks the program at start for a few seconds with 100% core usage if i do that.

    Sleep(3000); // ... so this is what i have to do instead. Disgusting.

    hDevice = CreateFile(L"\\\\.\\WinRing0_1_2_0",
                        GENERIC_READ | GENERIC_WRITE,
                        0,
                        NULL,
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL);

    if (hDevice == INVALID_HANDLE_VALUE) {
        error = GetLastError();
        if (error == ERROR_ACCESS_DENIED) {
            outlog = fopen(filename, "ab");
            fprintf(outlog, "CreateFile failed. Please retry as administrator.\n");
            fclose(outlog);
        } else if (error == ERROR_FILE_NOT_FOUND) {
            outlog = fopen(filename, "ab");
            fprintf(outlog, "CreateFile failed. The WinRing0 driver is probably not loaded yet.\n");
            fclose(outlog);
        } else {
            outlog = fopen(filename, "ab");
            fprintf(outlog, "CreateFile failed. Error %d.\n", error);
            fclose(outlog);
        }
        return 0;
    }

    int val_duty, raw_rpm, val_rpm, temp, last_valid_duty=50;
    while (1) {
        val_duty = (int) ((double) (read_ec(0xCE)) / 255.0 * 100.0);
        raw_rpm = (read_ec(0xD0) << 8) + (read_ec(0xD1));
        if (raw_rpm == 0)
            val_rpm = 0;
        else
            val_rpm = 2156220 / raw_rpm;
        temp = read_ec(0x07);

        //outlog = fopen(filename, "ab");
        //fprintf(outlog, "FAN Duty: %d%%, FAN RPMs: %d RPM, CPU Temp: %d°C\n", val_duty, val_rpm, temp);
        //fclose(outlog);

        if (val_rpm > 10000 || val_duty == 0) {
            // there are two malfunctions that can happen:
            // - fan stops suddenly with fan duty=0
            // - fan stops suddenly with rpm > 10000 with a electric noise that can be heard coming from the fan.
            outlog = fopen(filename, "ab");
            fprintf(outlog, "MALFUNCTION DETECTED: val_rpm=%d, val_duty=%d\n", val_rpm, val_duty);
            fclose(outlog);
            // Panic :O
            if (last_valid_duty<80) {
                write_fan_duty(last_valid_duty+20);
            } else {
                write_fan_duty(last_valid_duty-20);
            }
        } else {
            // This is the custom fan curve code. Can be adjusted to your liking.
            // It's required because i don't know to to set the fan back to "automatic" without manual intervention.
            // Can definitely conflict with other fan speed programs, so be careful.
            // Writes to fan speed are limited to only if the target fan duty changes.
            if (temp<55) {
                if (last_valid_duty > 32 || last_valid_duty < 29) write_fan_duty(31);
            } else if (temp<60) {
                if (last_valid_duty > 42 || last_valid_duty < 39) write_fan_duty(41);
            } else if (temp<65) {
                if (last_valid_duty > 52 || last_valid_duty < 49) write_fan_duty(51);
            } else if (temp<70) {
                if (last_valid_duty > 62 || last_valid_duty < 59) write_fan_duty(61);
            } else if (temp<75) {
                if (last_valid_duty > 72 || last_valid_duty < 69) write_fan_duty(71);
            } else if (temp<80) {
                if (last_valid_duty > 82 || last_valid_duty < 79) write_fan_duty(81);
            } else if (temp<85) {
                if (last_valid_duty > 92 || last_valid_duty < 89) write_fan_duty(91);
            } else {
                if (last_valid_duty < 98) write_fan_duty(100);
            }
            last_valid_duty = val_duty;
        }
        Sleep(200);
    }
    return 0;
}

Linuxベースのオペレーティングシステムで使用するためにコードを移植していません。これを行うには、次のものが必要です。

  • 合計関数をおよびWInp(port)で置き換えます。WOutp(port, value)inb(port)outb(value, port)
  • ioperm最初に追加してください。このコードスニペットでは
  • Sleep(milliseconds)usleep(microseconds)に交換
  • 今、役に立たない包含、定義、構造、ハンドルをすべて整理し、
  • GetModuleFileNameA同等の機能と交換してください。

関連情報