-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathacer-fan-control.c
144 lines (120 loc) · 2.65 KB
/
acer-fan-control.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
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kthread.h> // for threads
#include <linux/time.h>
#include <linux/timer.h>
#define EC_VAL 0x62
#define EC_CMD 0x66
#ifndef SLEEP_MILLI_SEC
#define SLEEP_MILLI_SEC(nMilliSec)\
do { \
long timeout = (nMilliSec) * HZ / 1000; \
while(timeout > 0) \
{ \
timeout = schedule_timeout(timeout); \
} \
}while(0);
#endif
static struct task_struct *thread1;
static int fanSpeed;
static int maxFanSpeed = 130;
static int minFanSpeed = 50;
static void wait_write_ec(void)
{
while((inb(EC_CMD) & 0x02) != 0) {
}
}
static void wait_read_ec(void)
{
while ((inb(EC_CMD) & 0x01) == 0) {
}
}
static void write_ec(short addr, short value)
{
wait_write_ec();
outb(0x81,EC_CMD);
wait_write_ec();
outb(addr,EC_VAL);
wait_write_ec();
outb(value,EC_VAL);
}
static int read_ec(short addr)
{
wait_write_ec();
outb(0x80,EC_CMD);
wait_write_ec();
outb(addr,EC_VAL);
wait_read_ec();
return inb(EC_VAL);
}
static void set_speed(short speed)
{
write_ec(0x94, (255-(speed * 135) / 100));
}
static int get_max(short cpu, short gpu)
{
int retval = 0;
if (cpu > gpu) {
retval = cpu;
} else {
retval = gpu;
}
return retval;
}
int thread_fn(void *data)
{
short cpu_temp,gpu_temp,max_temp;
set_current_state(TASK_INTERRUPTIBLE);
while(!kthread_should_stop())
{
SLEEP_MILLI_SEC(30000);
cpu_temp = 0;
gpu_temp = 0;
cpu_temp = read_ec(0xA8);
gpu_temp = read_ec(0xAF);
max_temp = get_max(cpu_temp, gpu_temp);
if (max_temp < 60) {
fanSpeed = minFanSpeed;
}
if (max_temp > 60) {
fanSpeed = minFanSpeed+20;
}
if (max_temp > 70) {
fanSpeed = minFanSpeed+40;
}
if (max_temp > 80) {
fanSpeed = maxFanSpeed;
}
set_speed(fanSpeed);
printk(KERN_INFO "cpu temp: %d, gpu temp: %d, fan speed: %d", cpu_temp, gpu_temp, fanSpeed);
schedule();
set_current_state(TASK_INTERRUPTIBLE);
}
set_current_state(TASK_RUNNING);
return 0;
}
static int __init init_fan_module(void)
{
char name[16]="acer_fan_control";
printk(KERN_CRIT "Fan control started\n");
// turn BIOS fan control off
write_ec(0x93, 0x14);
printk(KERN_INFO "in init");
thread1 = kthread_run(thread_fn,NULL,name);
return 0;
}
static void __exit fan_module_exit(void)
{
int ret;
ret = kthread_stop(thread1);
if(!ret)
printk(KERN_INFO "Thread stopped");
printk(KERN_CRIT "Fan control cleanup\n");
}
module_init(init_fan_module);
module_exit(fan_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jason Miesionczek");
MODULE_DESCRIPTION("Control fan speed for Acer 7551g Notebooks");