-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathux32vd.c
318 lines (283 loc) · 7.09 KB
/
ux32vd.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
// prikolchik 2013
// http://pastebin.com/Hp2pWeyL
// 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>
// where <fan speed> is fan speed 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(5*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 main(int argc, char ** argv) {
if(argc != 2) {
printf("usage: %s speed\n", argv[0]);
printf("speed: `auto' or a value between 1 and 15\n");
printf("keep in mind that `auto' will be even faster than 15!\n");
return 1;
}
uint8_t speed = 0xFF;
if(strcmp(argv[1], "auto") == 0)
printf("setting speed to 'auto'\n");
else {
int arg = atoi(argv[1]);
if(arg < 1 || arg > 255) {
printf("Error: the speed %d is not possible\n", arg);
return 1;
}
printf("setting speed to %d\n", arg);
speed = arg;
}
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("good\n");
}
// 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;
}