From 49b81066f550a13c9fd755627f82ffdad40eacaa Mon Sep 17 00:00:00 2001 From: don Date: Thu, 25 May 2023 00:09:32 +0200 Subject: [PATCH] Initial commit --- fancntrl.c | 352 +++++++++++++++++++++++++++++++++++++++++++++++++++++ run.sh | 4 + 2 files changed, 356 insertions(+) create mode 100644 fancntrl.c create mode 100644 run.sh diff --git a/fancntrl.c b/fancntrl.c new file mode 100644 index 0000000..5cdd4f7 --- /dev/null +++ b/fancntrl.c @@ -0,0 +1,352 @@ +// Tested on ASUS UX32VD +// DO NOT TRY ON ANY OTHER COMPUTER UNLESS YOU KNOW WHAT YOU ARE DOING! +// +// code taken from http://www.aneas.org/knowledge/asus_f3jp_fan_control.php +// and modified for UX32VD + +// File: fancntrl.c +// Compile: gcc fancntrl.c -o fanctrl +// Usage: sudo ./fanctrl +// where is the fan speed expected at T°C from 0x00 (off) to 0xFF (MAX) + +// WARNING!!! This file is proof of concept and is an UGLY hack! + + +#include // printf +#include // atoi +#include // uint8_t, uint16_t +#include // strcmp +#include // usleep +#include // inb, outb + +//#define DEBUG + +// IO ports +const uint16_t EC4D = 0x0257; // data register +const uint16_t EC4C = 0x0258; // command register + +#define ERROR16 (0xFFFF) + +// waits for the status bit to clear, max ERROR16 tries +uint8_t WEIE() { +#ifdef DEBUG + printf("Called : WEIE\n"); +#endif + uint16_t Local0 = 0xFFFF; + uint8_t Local1 = inb(EC4C) & 0x02; + while(Local0 != 0 && Local1 == 0x02) { + Local1 = inb(EC4C) & 0x02; + Local0--; + usleep(10*1000); //sleep 5 msec + } +#ifdef DEBUG + printf("Left : WEIE\n"); +#endif + + return (Local0 == 0); +} + +// waits for the status bit to clear, max ERROR16 tries +uint8_t WEOE () { +#ifdef DEBUG + printf("Called : WEOE\n"); +#endif + uint16_t Local0 = 0xFFFF; + uint8_t Local1 = inb(EC4C) & 0x01; + while(Local0 != 0 && Local1 == 0x01) { + Local1 = inb(EC4C) & 0x01; + Local0--; + usleep(5*1000); //sleep 5 msec + inb(EC4D); // maybe not needed? + } +#ifdef DEBUG + printf("Left : WEOE\n"); +#endif + + return (Local0 == 0); +} + +uint8_t WEOF() { +#ifdef DEBUG + printf("Called : WEOF\n"); +#endif + uint16_t Local0 = 0xFFFF; + uint8_t Local1 = inb(EC4C) & 0x01; + while(Local0 != 0 && Local1 == 0x01) { + Local1 = inb(EC4C) & 0x01; + Local0--; + usleep(5*1000); //sleep 5 msec + } +#ifdef DEBUG + printf("Left : WEOF\n"); +#endif + + return (Local0 == 0); +} +/* read from RAM */ +uint16_t RRAM (uint16_t Arg0) { + uint16_t Local0, Local1; + Local0 = Arg0; + Local1 = Local0 & 0xFF; + Local0 = (Local0 >> 0x08); + Local0 = Local0 & 0xFF; + + if (WEOE() != 0){ return ERROR16; } + if (WEIE() != 0){ return ERROR16; } + outb(0xFF, EC4C); + if (WEIE() != 0){ return ERROR16; } + outb(0x80, EC4C); + if (WEIE() != 0){ return ERROR16; } + outb(Local0, EC4D); + if (WEIE() != 0){ return ERROR16; } + outb(Local1, EC4D); + if (WEIE() != 0){ return ERROR16; } + if (WEOF() != 0){ return ERROR16; } + + return inb(EC4D); +} + +/* write to RAM */ +uint16_t WRAM (uint16_t Arg0, uint8_t Arg1) { + uint16_t Local0, Local1; + Local0 = Arg0; + Local1 = Local0 & 0xFF; + Local0 = (Local0 >> 0x08); + Local0 = Local0 & 0xFF; + + if (WEOE() != 0){ return ERROR16; } + if (WEIE() != 0){ return ERROR16; } + outb(0xFF, EC4C); + if (WEIE() != 0){ return ERROR16; } + outb(0x81, EC4C); + if (WEIE() != 0){ return ERROR16; } + outb(Local0, EC4D); + if (WEIE() != 0){ return ERROR16; } + outb(Local1, EC4D); + if (WEIE() != 0){ return ERROR16; } + outb(Arg1, EC4D); + if (WEIE() != 0){ return ERROR16; } + + return 0; +} + +// sets the QUIET fan speed +uint16_t WMFN (uint8_t Arg0) { //ST98 +#ifdef DEBUG + printf("Called : WMFN 0x%X\n", Arg0); +#endif + if (WEOE() != 0){ return ERROR16; } + if (WEIE() != 0){ return ERROR16; } + outb(0xFF, EC4C); + if (WEIE() != 0){ return ERROR16; } + outb(0x98, EC4C); + if (WEIE() != 0){ return ERROR16; } + outb(Arg0, EC4D); + if (WEIE() != 0){ return ERROR16; } + if (WEIE() != 0){ return ERROR16; } //not needed? +#ifdef DEBUG + printf("Left : WMFN\n"); +#endif + + return 0; +} + +/* +ST83 Arg0 Arg1 + Read speed of the fan(s). DOES NOT WORK IN MANUAL MODE + Args: + Arg0 - 0 = fan1 + - 1 = fan2 + Returns: + - fan speed 0x0(OFF) - 0xFF(MAX) +*/ +uint16_t RFOV (uint8_t Arg0) { //ST83 +#ifdef DEBUG + printf("Called : RFOV 0x%X\n", Arg0); +#endif + if (Arg0 > 0x01) { + return ERROR16; + } + if (WEOE() != 0){ return ERROR16; } + if (WEIE() != 0){ return ERROR16; } + outb(0xFF, EC4C); + if (WEIE() != 0){ return ERROR16; } + outb(0x83, EC4C); + if (WEIE() != 0){ return ERROR16; } + outb(Arg0, EC4D); + if (WEIE() != 0){ return ERROR16; } + if (WEOF() != 0){ return ERROR16; } +#ifdef DEBUG + printf("Left : RFOV\n"); +#endif + + return inb(EC4D); +} + +/* +ST84 Arg0 Arg1 + Sets speed of the fan(s) + Args: + Arg0 - 0 = fan1 + - 1 = fan2 + Arg1 - fan speed 0x0(OFF) - 0xFF(MAX) +*/ + +uint16_t WFOV (uint8_t Arg0, uint8_t Arg1) { //ST84 + if (Arg0 > 0x01) { + return ERROR16; + } + if (WEOE() != 0){ return ERROR16; } + if (WEIE() != 0){ return ERROR16; } + outb(0xFF, EC4C); + if (WEIE() != 0){ return ERROR16; } + outb(0x84, EC4C); + if (WEIE() != 0){ return ERROR16; } + outb(Arg0, EC4D); + if (WEIE() != 0){ return ERROR16; } + outb(Arg1, EC4D); + if (WEIE() != 0){ return ERROR16; } + + return 0; +} + +/* +SFNV Arg0 Arg1 + Sets speed of the fan(s) + Args: + Arg0 - 0 to reset fans to AUTO + - 1 = fan1 + - 2 = fan2 + Arg1 - if Arg0 == 0, then 0x1 bit reset fan1 0x2 bit reset fan2 + - fan speed 0x0(OFF) - 0xFF(MAX) +*/ +#define SFNV_SET_FAN1 (0x01) +#define SFNV_SET_FAN2 (0x02) +#define SFNV_AUTO_FAN1 (0x01) +#define SFNV_AUTO_FAN2 (0x02) +#define SFNV_AUTO_ALL (SFNV_AUTO_FAN1 | SFNV_AUTO_FAN2) + +uint16_t SFNV (uint8_t Arg0, uint8_t Arg1) { + uint16_t Local0; + // Set the fans to automatic + if (Arg0 == 0) { + // set fan1 to AUTO + if (Arg1 & SFNV_AUTO_FAN1) { + if ((Local0 = RRAM(0x0521)) == ERROR16) {return ERROR16; }; + Local0 |= 0x80; + WRAM (0x0521, (uint8_t) (0xFF & Local0)); //ignore error? + } + // set fan2 to AUTO + if (Arg1 & SFNV_AUTO_FAN2) { + if ((Local0 = RRAM(0x0522)) == ERROR16) {return ERROR16; }; + Local0 |= 0x80; + WRAM (0x0522, (uint8_t) (0xFF & Local0)); //ignore error? + } + return 0; + } + // Set the speed of fan1 + else if (Arg0 == SFNV_SET_FAN1) { + if ((Local0 = RRAM(0x0521)) == ERROR16) {return ERROR16; }; + Local0 &= 0x7F; + WRAM (0x0521, (uint8_t) (0xFF & Local0)); //ignore error? + // DECF |= 0x1 + return WFOV (0x00, Arg1); + } + // Set the speed of fan2 + else if (Arg0 == SFNV_SET_FAN2) { + if ((Local0 = RRAM(0x0522) == ERROR16)) {return ERROR16; }; + Local0 &= 0x7F; + WRAM (0x0522, (uint8_t) (0xFF & Local0)); //ignore error? + // DECF |= 0x2 + return WFOV (0x01, Arg1); + } + return ERROR16; +} + +int set(int speed) { + if(ioperm(EC4D, 1, 1)) { + printf("Error: could not gain access to IO port EC4D (0x%X). Are you root?\n", EC4D); + return 1; + } + + if(ioperm(EC4C, 1, 1)) { + printf("Error: could not gain access to IO port EC4C (0x%X). Are you root?\n", EC4C); + return 1; + } + +#if 0 + printf("Fan speeds: \tFan1: %d, Fan2: %d\n", RFOV(0x00), RFOV(0x01)); +#endif + if (WMFN(speed)) { + printf("error\n"); + } + else { + printf("speed has been set to %d\n",speed); + } + + // Set FAN1 speed to 0xFF (MAX) +// SFNV(0x1, 0xFF); + // Set FAN2 speed to 0x00 (OFF) +// SFNV(0x2, 0x00); + // reset both fans back to AUTO control +// SFNV(0x0, 0x01|0x02); + + return 0; +} + +int main(int argc, char ** argv) { + if(argc != 6) { + printf("usage:\n %s speed[40] speed[50] speed[60] speed[70] speed[80]\n", argv[0]); + printf("speed[T] is the speed you expect at temperature T (°C)\n"); + return 1; + } + + uint8_t speed = 0xFF; + int speed40 = atoi(argv[1]); + int speed50 = atoi(argv[2]); + int speed60 = atoi(argv[3]); + int speed70 = atoi(argv[4]); + int speed80 = atoi(argv[5]); + + if(speed40 < 1 || speed40 > 255) { + printf("Error: the speed %d is not possible\n", speed40); + return 1; + } + if(speed50 < 1 || speed50 > 255) { + printf("Error: the speed %d is not possible\n", speed50); + return 1; + } + if(speed60 < 1 || speed60 > 255) { + printf("Error: the speed %d is not possible\n", speed60); + return 1; + } + if(speed70 < 1 || speed70 > 255) { + printf("Error: the speed %d is not possible\n", speed70); + return 1; + } + if(speed80 < 1 || speed80 > 255) { + printf("Error: the speed %d is not possible\n", speed80); + return 1; + } + FILE *fp; + int temperature; + while(1){ + fp = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + fscanf(fp, "%d", &temperature); + fclose(fp); + printf("temperature: %d\n",temperature); + if (temperature < 40000) + speed = speed40; + else if (temperature < 50000) + speed = speed40 + (temperature-40000)*(speed50-speed40)/10000; + else if (temperature < 60000) + speed = speed50 + (temperature-50000)*(speed60-speed50)/10000; + else if (temperature < 70000) + speed = speed60 + (temperature-60000)*(speed70-speed60)/10000; + else + {speed = speed70 + (temperature-35000)*(speed80-speed70)/10000; + if (speed > 255) speed = 255;} + set(speed); + sleep(5); + } +} diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..0c05750 --- /dev/null +++ b/run.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +gcc fancntrl.c -o fanctrl +sudo ./fanctrl 1 1 128 255 255