Imported Upstream version 2.20070211+git20110911.4e1e3fc
[debian/omnibook.git] / fan_policy.c
1 /*
2  * fan_policy.c -- fan policy support
3  * 
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2, or (at your option) any
7  * later version.
8  * 
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * Written by Soós Péter <sp@osb.hu>, 2002-2004
15  * Modified by Mathieu Bérard <mathieu.berard@crans.org>, 2006
16  */
17
18 #include "omnibook.h"
19
20 #include <linux/ctype.h>
21 #include "hardware.h"
22
23 /*
24  * Default temperature limits.
25  * Danger! You may overheat your CPU!
26  * Do not change these values unless you exactly know what you do.
27  */
28
29 #define OMNIBOOK_FAN_LEVELS                     8
30 #define OMNIBOOK_FAN_MIN                        25      /* Minimal value of fan off temperature */
31 #define OMNIBOOK_FOT_MAX                        75      /* Maximal value of fan off temperature */
32 #define OMNIBOOK_FAN_MAX                        95      /* Maximal value of fan on temperature */
33 #define OMNIBOOK_FOT_DEFAULT                    60      /* Default value of fan off temperature */
34 #define OMNIBOOK_FAN1_DEFAULT                   75      /* Default value of fan on temperature */
35 #define OMNIBOOK_FAN2_DEFAULT                   85      /* Default value of fan level 2 temperature */
36 #define OMNIBOOK_FAN3_DEFAULT                   90      /* Default value of fan level 3 temperature */
37 #define OMNIBOOK_FAN4_DEFAULT                   95      /* Default value of fan level 4 temperature */
38 #define OMNIBOOK_FAN5_DEFAULT                   95      /* Default value of fan level 5 temperature */
39 #define OMNIBOOK_FAN6_DEFAULT                   95      /* Default value of fan level 6 temperature */
40 #define OMNIBOOK_FAN7_DEFAULT                   95      /* Default value of fan level 7 temperature */
41
42 static const u8 fan_defaults[] = {
43                 OMNIBOOK_FOT_DEFAULT,
44                 OMNIBOOK_FAN1_DEFAULT,
45                 OMNIBOOK_FAN2_DEFAULT,
46                 OMNIBOOK_FAN3_DEFAULT,
47                 OMNIBOOK_FAN4_DEFAULT,
48                 OMNIBOOK_FAN5_DEFAULT,
49                 OMNIBOOK_FAN6_DEFAULT,
50                 OMNIBOOK_FAN7_DEFAULT,
51 };
52
53 static int omnibook_get_fan_policy(struct omnibook_operation *io_op, u8 *fan_policy)
54 {
55         int retval ;
56         int i;
57
58         for (i = 0; i < OMNIBOOK_FAN_LEVELS; i++) {
59                 io_op->read_addr = XE3GF_FOT + i;
60                 if ((retval = __backend_byte_read(io_op, &fan_policy[i])))
61                         return retval;
62         }
63
64         return 0;
65 }
66
67 static int omnibook_set_fan_policy(struct omnibook_operation *io_op, const u8 *fan_policy)
68 {
69         int retval;
70         int i;
71
72         if (fan_policy[0] > OMNIBOOK_FOT_MAX)
73                 return -EINVAL;
74
75         for (i = 0; i < OMNIBOOK_FAN_LEVELS; i++) {
76                 if ((fan_policy[i] > fan_policy[i + 1])
77                     || (fan_policy[i] < OMNIBOOK_FAN_MIN)
78                     || (fan_policy[i] > OMNIBOOK_FAN_MAX))
79                         return -EINVAL;
80         }
81         for (i = 0; i < OMNIBOOK_FAN_LEVELS; i++) {
82                 io_op->write_addr = XE3GF_FOT + i;
83                 if ((retval = __backend_byte_write(io_op, fan_policy[i])))
84                         return retval;
85         }
86
87         return 0;
88 }
89
90 static int omnibook_fan_policy_read(char *buffer, struct omnibook_operation *io_op)
91 {
92         int retval;
93         int len = 0;
94         u8 i;
95         u8 fan_policy[OMNIBOOK_FAN_LEVELS];
96
97         if(mutex_lock_interruptible(&io_op->backend->mutex))
98                 return -ERESTARTSYS;
99
100         retval = omnibook_get_fan_policy(io_op, &fan_policy[0]);
101
102         mutex_unlock(&io_op->backend->mutex);
103
104         if(retval)
105                 return retval;
106
107         len += sprintf(buffer + len, "Fan off temperature:        %2d C\n", fan_policy[0]);
108         len += sprintf(buffer + len, "Fan on temperature:         %2d C\n", fan_policy[1]);
109         for (i = 2; i < OMNIBOOK_FAN_LEVELS; i++) {
110                 len +=
111                     sprintf(buffer + len, "Fan level %1d temperature:    %2d C\n", i,
112                             fan_policy[i]);
113         }
114         len += sprintf(buffer + len, "Minimal temperature to set: %2d C\n", OMNIBOOK_FAN_MIN);
115         len += sprintf(buffer + len, "Maximal temperature to set: %2d C\n", OMNIBOOK_FAN_MAX);
116
117         return len;
118 }
119
120 static int omnibook_fan_policy_write(char *buffer, struct omnibook_operation *io_op)
121 {
122         int n = 0;
123         char *b;
124         char *endp;
125         int retval;
126         int temp;
127         u8 fan_policy[OMNIBOOK_FAN_LEVELS];
128
129         if(mutex_lock_interruptible(&io_op->backend->mutex))
130                 return -ERESTARTSYS;
131
132         if ((retval = omnibook_get_fan_policy(io_op, &fan_policy[0])))
133                 goto out;
134
135         /* 
136          * Could also be done much simpler using sscanf(,"%u %u ... 
137          * but this would hardcode OMNIBOOK_FAN_LEVELS.
138          * The parsed format is "%u " repeated OMNIBOOK_FAN_LEVELS+1 times
139          */
140
141         b = buffer;
142         do {
143                 dprintk("n=[%i] b=[%s]\n", n, b);
144                 if (n > OMNIBOOK_FAN_LEVELS) {
145                         retval = -EINVAL;
146                         goto out;
147                 }
148                 if (!isspace(*b)) {
149                         temp = simple_strtoul(b, &endp, 10);
150                         if (endp != b) {        /* there was a match */
151                                 fan_policy[n++] = temp;
152                                 b = endp;
153                         } else {
154                                 retval = -EINVAL;
155                                 goto out;
156                         }
157                 } else
158                         b++;
159         } while ((*b != '\0') && (*b != '\n'));
160
161         /* A zero value set the defaults */
162         if ((fan_policy[0] == 0) && (n == 1))
163                 retval = omnibook_set_fan_policy(io_op, &fan_defaults[0]);
164         else
165                 retval = omnibook_set_fan_policy(io_op, &fan_policy[0]);
166
167         out:
168         mutex_unlock(&io_op->backend->mutex);
169         return retval;
170 }
171
172 static struct omnibook_tbl fan_policy_table[] __initdata = {
173         {XE3GF, {EC,}},
174         {0,}
175 };
176
177 static struct omnibook_feature __declared_feature fan_policy_driver = {
178         .name = "fan_policy",
179         .enabled = 1,
180         .read = omnibook_fan_policy_read,
181         .write = omnibook_fan_policy_write,
182         .ectypes = XE3GF,
183         .tbl = fan_policy_table,
184 };
185
186 module_param_named(fan_policy, fan_policy_driver.enabled, int, S_IRUGO);
187 MODULE_PARM_DESC(fan_policy, "Use 0 to disable, 1 to enable fan control policy support");
188 /* End of file */