Want more features on Pastebin? Sign Up, it's FREE!
Guest

fancntrl.c: Asus UX32VD fan control proof of concept

By: a guest on Jan 24th, 2013  |  syntax: None  |  size: 7.34 KB  |  views: 1,303  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. // Tested on ASUS UX32VD
  2. // DO NOT TRY ON ANY OTHER COMPUTER UNLESS YOU KNOW WHAT YOU ARE DOING!
  3. //
  4. // code taken from http://www.aneas.org/knowledge/asus_f3jp_fan_control.php
  5. // and modified for UX32VD
  6.  
  7. // File: fancntrl.c
  8. // Compile: gcc fancntrl.c -o fanctrl
  9. // Usage: sudo ./fanctrl <fan speed>
  10. //      where <fan speed> is fan speed from 0x00 (off) to 0xFF (MAX)
  11.  
  12. // WARNING!!! This file is proof of concept and is an UGLY hack!
  13.  
  14.  
  15. #include <stdio.h> // printf
  16. #include <stdlib.h> // atoi
  17. #include <stdint.h> // uint8_t, uint16_t
  18. #include <string.h> // strcmp
  19. #include <unistd.h> // usleep
  20. #include <sys/io.h> // inb, outb
  21.  
  22. #define DEBUG
  23.  
  24. // IO ports
  25. const uint16_t EC4D = 0x0257; // data register
  26. const uint16_t EC4C = 0x0258; // command register
  27.  
  28. #define ERROR16 (0xFFFF)
  29.  
  30. // waits for the status bit to clear, max ERROR16 tries
  31. uint8_t WEIE() {
  32. #ifdef DEBUG
  33.         printf("Called : WEIE\n");
  34. #endif
  35.         uint16_t Local0 = 0xFFFF;
  36.         uint8_t Local1 = inb(EC4C) & 0x02;
  37.         while(Local0 != 0 && Local1 == 0x02) {
  38.                 Local1 = inb(EC4C) & 0x02;
  39.                 Local0--;
  40.                 usleep(5*1000); //sleep 5 msec
  41.         }
  42. #ifdef DEBUG
  43.         printf("Left : WEIE\n");
  44. #endif
  45.  
  46.         return (Local0 == 0);
  47. }
  48.  
  49. // waits for the status bit to clear, max ERROR16 tries
  50. uint8_t WEOE () {
  51. #ifdef DEBUG
  52.         printf("Called : WEOE\n");
  53. #endif
  54.         uint16_t Local0 = 0xFFFF;
  55.         uint8_t Local1 = inb(EC4C) & 0x01;
  56.         while(Local0 != 0 && Local1 == 0x01) {
  57.                 Local1 = inb(EC4C) & 0x01;
  58.                 Local0--;
  59.                 usleep(5*1000); //sleep 5 msec
  60.                 inb(EC4D); // maybe not needed?
  61.         }
  62. #ifdef DEBUG
  63.         printf("Left : WEOE\n");
  64. #endif
  65.  
  66.         return (Local0 == 0);
  67. }
  68.  
  69. uint8_t WEOF() {
  70. #ifdef DEBUG
  71.         printf("Called : WEOF\n");
  72. #endif
  73.         uint16_t Local0 = 0xFFFF;
  74.         uint8_t Local1 = inb(EC4C) & 0x01;
  75.         while(Local0 != 0 && Local1 == 0x01) {
  76.                 Local1 = inb(EC4C) & 0x01;
  77.                 Local0--;
  78.                 usleep(5*1000); //sleep 5 msec
  79.         }
  80. #ifdef DEBUG
  81.         printf("Left : WEOF\n");
  82. #endif
  83.  
  84.         return (Local0 == 0);
  85. }
  86. /* read from RAM */
  87. uint16_t RRAM (uint16_t Arg0) {
  88.         uint16_t Local0, Local1;
  89.         Local0 = Arg0;
  90.         Local1 = Local0 & 0xFF;
  91.         Local0 = (Local0 >> 0x08);
  92.         Local0 = Local0 & 0xFF;
  93.  
  94.         if (WEOE() != 0){ return ERROR16; }
  95.         if (WEIE() != 0){ return ERROR16; }
  96.         outb(0xFF, EC4C);
  97.         if (WEIE() != 0){ return ERROR16; }
  98.         outb(0x80, EC4C);
  99.         if (WEIE() != 0){ return ERROR16; }
  100.         outb(Local0, EC4D);
  101.         if (WEIE() != 0){ return ERROR16; }
  102.         outb(Local1, EC4D);
  103.         if (WEIE() != 0){ return ERROR16; }
  104.         if (WEOF() != 0){ return ERROR16; }
  105.        
  106.         return inb(EC4D);
  107. }
  108.  
  109. /* write to RAM */
  110. uint16_t WRAM (uint16_t Arg0, uint8_t Arg1) {
  111.         uint16_t Local0, Local1;
  112.         Local0 = Arg0;
  113.         Local1 = Local0 & 0xFF;
  114.         Local0 = (Local0 >> 0x08);
  115.         Local0 = Local0 & 0xFF;
  116.  
  117.         if (WEOE() != 0){ return ERROR16; }
  118.         if (WEIE() != 0){ return ERROR16; }
  119.         outb(0xFF, EC4C);
  120.         if (WEIE() != 0){ return ERROR16; }
  121.         outb(0x81, EC4C);
  122.         if (WEIE() != 0){ return ERROR16; }
  123.         outb(Local0, EC4D);
  124.         if (WEIE() != 0){ return ERROR16; }
  125.         outb(Local1, EC4D);
  126.         if (WEIE() != 0){ return ERROR16; }
  127.         outb(Arg1, EC4D);
  128.         if (WEIE() != 0){ return ERROR16; }
  129.  
  130.         return 0;
  131. }
  132.  
  133. // sets the QUIET fan speed
  134. uint16_t WMFN (uint8_t Arg0) { //ST98
  135. #ifdef DEBUG
  136.         printf("Called : WMFN 0x%X\n", Arg0);
  137. #endif
  138.         if (WEOE() != 0){ return ERROR16; }
  139.         if (WEIE() != 0){ return ERROR16; }
  140.         outb(0xFF, EC4C);
  141.         if (WEIE() != 0){ return ERROR16; }
  142.         outb(0x98, EC4C);
  143.         if (WEIE() != 0){ return ERROR16; }
  144.         outb(Arg0, EC4D);
  145.         if (WEIE() != 0){ return ERROR16; }
  146.         if (WEIE() != 0){ return ERROR16; } //not needed?
  147. #ifdef DEBUG
  148.         printf("Left : WMFN\n");
  149. #endif
  150.        
  151.         return 0;
  152. }
  153.  
  154. /*
  155. ST83 Arg0 Arg1
  156.         Read speed of the fan(s). DOES NOT WORK IN MANUAL MODE
  157.   Args:
  158.         Arg0    - 0 = fan1
  159.                 - 1 = fan2
  160.   Returns:
  161.                 - fan speed 0x0(OFF) - 0xFF(MAX)
  162. */
  163. uint16_t RFOV (uint8_t Arg0) { //ST83
  164. #ifdef DEBUG
  165.         printf("Called : RFOV 0x%X\n", Arg0);
  166. #endif
  167.         if (Arg0 > 0x01) {
  168.                 return ERROR16;
  169.         }
  170.         if (WEOE() != 0){ return ERROR16; }
  171.         if (WEIE() != 0){ return ERROR16; }
  172.         outb(0xFF, EC4C);
  173.         if (WEIE() != 0){ return ERROR16; }
  174.         outb(0x83, EC4C);
  175.         if (WEIE() != 0){ return ERROR16; }
  176.         outb(Arg0, EC4D);
  177.         if (WEIE() != 0){ return ERROR16; }
  178.         if (WEOF() != 0){ return ERROR16; }
  179. #ifdef DEBUG
  180.         printf("Left : RFOV\n");
  181. #endif
  182.  
  183.         return inb(EC4D);
  184. }
  185.  
  186. /*
  187. ST84 Arg0 Arg1
  188.         Sets speed of the fan(s)
  189.   Args:
  190.         Arg0    - 0 = fan1
  191.                 - 1 = fan2
  192.         Arg1    - fan speed 0x0(OFF) - 0xFF(MAX)
  193. */
  194.  
  195. uint16_t WFOV (uint8_t Arg0, uint8_t Arg1) { //ST84
  196.         if (Arg0 > 0x01) {
  197.                 return ERROR16;
  198.         }
  199.         if (WEOE() != 0){ return ERROR16; }
  200.         if (WEIE() != 0){ return ERROR16; }
  201.         outb(0xFF, EC4C);
  202.         if (WEIE() != 0){ return ERROR16; }
  203.         outb(0x84, EC4C);
  204.         if (WEIE() != 0){ return ERROR16; }
  205.         outb(Arg0, EC4D);
  206.         if (WEIE() != 0){ return ERROR16; }
  207.         outb(Arg1, EC4D);
  208.         if (WEIE() != 0){ return ERROR16; }
  209.        
  210.         return 0;
  211. }
  212.  
  213. /*
  214. SFNV Arg0 Arg1
  215.         Sets speed of the fan(s)
  216.   Args:
  217.         Arg0    - 0 to reset fans to AUTO
  218.                 - 1 = fan1
  219.                 - 2 = fan2
  220.         Arg1    - if Arg0 == 0, then 0x1 bit reset fan1 0x2 bit reset fan2
  221.                 - fan speed 0x0(OFF) - 0xFF(MAX)
  222. */
  223. #define SFNV_SET_FAN1 (0x01)
  224. #define SFNV_SET_FAN2 (0x02)
  225. #define SFNV_AUTO_FAN1 (0x01)
  226. #define SFNV_AUTO_FAN2 (0x02)
  227. #define SFNV_AUTO_ALL (SFNV_AUTO_FAN1 | SFNV_AUTO_FAN2)
  228.  
  229. uint16_t SFNV (uint8_t Arg0, uint8_t Arg1) {
  230.         uint16_t Local0;
  231.         // Set the fans to automatic
  232.         if (Arg0 == 0) {
  233.                 // set fan1 to AUTO
  234.                 if (Arg1 & SFNV_AUTO_FAN1) {
  235.                         if ((Local0 = RRAM(0x0521)) == ERROR16) {return ERROR16; };
  236.                         Local0 |= 0x80;
  237.                         WRAM (0x0521, (uint8_t) (0xFF & Local0)); //ignore error?
  238.                 }
  239.                 // set fan2 to AUTO
  240.                 if (Arg1 & SFNV_AUTO_FAN2) {
  241.                         if ((Local0 = RRAM(0x0522)) == ERROR16) {return ERROR16; };
  242.                         Local0 |= 0x80;
  243.                         WRAM (0x0522, (uint8_t) (0xFF & Local0)); //ignore error?
  244.                 }
  245.                 return 0;
  246.         }
  247.         // Set the speed of fan1
  248.         else if (Arg0 == SFNV_SET_FAN1) {
  249.                 if ((Local0 = RRAM(0x0521)) == ERROR16) {return ERROR16; };
  250.                 Local0 &= 0x7F;
  251.                 WRAM (0x0521, (uint8_t) (0xFF & Local0)); //ignore error?
  252.                 // DECF |= 0x1
  253.                 return WFOV (0x00, Arg1);
  254.         }
  255.         // Set the speed of fan2
  256.         else if (Arg0 == SFNV_SET_FAN2) {
  257.                 if ((Local0 = RRAM(0x0522) == ERROR16)) {return ERROR16; };
  258.                 Local0 &= 0x7F;
  259.                 WRAM (0x0522, (uint8_t) (0xFF & Local0)); //ignore error?
  260.                 // DECF |= 0x2
  261.                 return WFOV (0x01, Arg1);
  262.         }
  263.         return ERROR16;
  264. }
  265.  
  266. int main(int argc, char ** argv) {
  267.         if(argc != 2) {
  268.                 printf("usage: %s speed\n", argv[0]);
  269.                 printf("speed: `auto' or a value between 1 and 15\n");
  270.                 printf("keep in mind that `auto' will be even faster than 15!\n");
  271.                 return 1;
  272.         }
  273.  
  274.         uint8_t speed = 0xFF;
  275.         if(strcmp(argv[1], "auto") == 0)
  276.                 printf("setting speed to 'auto'\n");
  277.         else {
  278.                 int arg = atoi(argv[1]);
  279.                 if(arg < 1 || arg > 255) {
  280.                         printf("Error: the speed %d is not possible\n", arg);
  281.                         return 1;
  282.                 }
  283.                 printf("setting speed to %d\n", arg);
  284.                 speed = arg;
  285.         }
  286.  
  287.         if(ioperm(EC4D, 1, 1)) {
  288.                 printf("Error: could not gain access to IO port EC4D (0x%X). Are you root?\n", EC4D);
  289.                 return 1;
  290.         }
  291.  
  292.         if(ioperm(EC4C, 1, 1)) {
  293.                 printf("Error: could not gain access to IO port EC4C (0x%X). Are you root?\n", EC4C);
  294.                 return 1;
  295.         }
  296.  
  297. #if 0
  298.         printf("Fan speeds: \tFan1: %d, Fan2: %d\n", RFOV(0x00), RFOV(0x01));
  299. #endif
  300.         if (WMFN(speed)) {
  301.                 printf("error\n");
  302.         }
  303.         else {
  304.                 printf("good\n");
  305.         }
  306.  
  307.         // Set FAN1 speed to 0xFF (MAX)
  308. //      SFNV(0x1, 0xFF);
  309.         // Set FAN2 speed to 0x00 (OFF)
  310. //      SFNV(0x2, 0x00);
  311.         // reset both fans back to AUTO control
  312. //      SFNV(0x0, 0x01|0x02);
  313.  
  314.         return 0;
  315. }
clone this paste RAW Paste Data