Initial commit
This commit is contained in:
352
fancntrl.c
Normal file
352
fancntrl.c
Normal file
@@ -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 <fan speed at 40°C> <fan speed at 50°C> <fan speed at 60°C> <fan speed at 70°C> <fan speed at 80°C>
|
||||
// where <fan speed at T°C> 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 <stdio.h> // printf
|
||||
#include <stdlib.h> // atoi
|
||||
#include <stdint.h> // uint8_t, uint16_t
|
||||
#include <string.h> // strcmp
|
||||
#include <unistd.h> // usleep
|
||||
#include <sys/io.h> // 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user