Guest User

fancntrl.c: Asus UX32VD fan control proof of concept

a guest
Jan 24th, 2013
2,575
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
RAW Paste Data