diff options
Diffstat (limited to 'tools/thermal/tmon/sysfs.c')
-rw-r--r-- | tools/thermal/tmon/sysfs.c | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/tools/thermal/tmon/sysfs.c b/tools/thermal/tmon/sysfs.c new file mode 100644 index 000000000000..dfe454855cd2 --- /dev/null +++ b/tools/thermal/tmon/sysfs.c | |||
@@ -0,0 +1,596 @@ | |||
1 | /* | ||
2 | * sysfs.c sysfs ABI access functions for TMON program | ||
3 | * | ||
4 | * Copyright (C) 2013 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 or later as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * Author: Jacob Pan <jacob.jun.pan@linux.intel.com> | ||
16 | * | ||
17 | */ | ||
18 | #include <unistd.h> | ||
19 | #include <stdio.h> | ||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | #include <stdint.h> | ||
23 | #include <dirent.h> | ||
24 | #include <libintl.h> | ||
25 | #include <ctype.h> | ||
26 | #include <time.h> | ||
27 | #include <syslog.h> | ||
28 | #include <sys/time.h> | ||
29 | #include <errno.h> | ||
30 | |||
31 | #include "tmon.h" | ||
32 | |||
33 | struct tmon_platform_data ptdata; | ||
34 | const char *trip_type_name[] = { | ||
35 | "critical", | ||
36 | "hot", | ||
37 | "passive", | ||
38 | "active", | ||
39 | }; | ||
40 | |||
41 | int sysfs_set_ulong(char *path, char *filename, unsigned long val) | ||
42 | { | ||
43 | FILE *fd; | ||
44 | int ret = -1; | ||
45 | char filepath[256]; | ||
46 | |||
47 | snprintf(filepath, 256, "%s/%s", path, filename); | ||
48 | |||
49 | fd = fopen(filepath, "w"); | ||
50 | if (!fd) { | ||
51 | syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath); | ||
52 | return ret; | ||
53 | } | ||
54 | ret = fprintf(fd, "%lu", val); | ||
55 | fclose(fd); | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | /* history of thermal data, used for control algo */ | ||
61 | #define NR_THERMAL_RECORDS 3 | ||
62 | struct thermal_data_record trec[NR_THERMAL_RECORDS]; | ||
63 | int cur_thermal_record; /* index to the trec array */ | ||
64 | |||
65 | static int sysfs_get_ulong(char *path, char *filename, unsigned long *p_ulong) | ||
66 | { | ||
67 | FILE *fd; | ||
68 | int ret = -1; | ||
69 | char filepath[256]; | ||
70 | |||
71 | snprintf(filepath, 256, "%s/%s", path, filename); | ||
72 | |||
73 | fd = fopen(filepath, "r"); | ||
74 | if (!fd) { | ||
75 | syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath); | ||
76 | return ret; | ||
77 | } | ||
78 | ret = fscanf(fd, "%lu", p_ulong); | ||
79 | fclose(fd); | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int sysfs_get_string(char *path, char *filename, char *str) | ||
85 | { | ||
86 | FILE *fd; | ||
87 | int ret = -1; | ||
88 | char filepath[256]; | ||
89 | |||
90 | snprintf(filepath, 256, "%s/%s", path, filename); | ||
91 | |||
92 | fd = fopen(filepath, "r"); | ||
93 | if (!fd) { | ||
94 | syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath); | ||
95 | return ret; | ||
96 | } | ||
97 | ret = fscanf(fd, "%256s", str); | ||
98 | fclose(fd); | ||
99 | |||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | /* get states of the cooling device instance */ | ||
104 | static int probe_cdev(struct cdev_info *cdi, char *path) | ||
105 | { | ||
106 | sysfs_get_string(path, "type", cdi->type); | ||
107 | sysfs_get_ulong(path, "max_state", &cdi->max_state); | ||
108 | sysfs_get_ulong(path, "cur_state", &cdi->cur_state); | ||
109 | |||
110 | syslog(LOG_INFO, "%s: %s: type %s, max %lu, curr %lu inst %d\n", | ||
111 | __func__, path, | ||
112 | cdi->type, cdi->max_state, cdi->cur_state, cdi->instance); | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static int str_to_trip_type(char *name) | ||
118 | { | ||
119 | int i; | ||
120 | |||
121 | for (i = 0; i < NR_THERMAL_TRIP_TYPE; i++) { | ||
122 | if (!strcmp(name, trip_type_name[i])) | ||
123 | return i; | ||
124 | } | ||
125 | |||
126 | return -ENOENT; | ||
127 | } | ||
128 | |||
129 | /* scan and fill in trip point info for a thermal zone and trip point id */ | ||
130 | static int get_trip_point_data(char *tz_path, int tzid, int tpid) | ||
131 | { | ||
132 | char filename[256]; | ||
133 | char temp_str[256]; | ||
134 | int trip_type; | ||
135 | |||
136 | if (tpid >= MAX_NR_TRIP) | ||
137 | return -EINVAL; | ||
138 | /* check trip point type */ | ||
139 | snprintf(filename, sizeof(filename), "trip_point_%d_type", tpid); | ||
140 | sysfs_get_string(tz_path, filename, temp_str); | ||
141 | trip_type = str_to_trip_type(temp_str); | ||
142 | if (trip_type < 0) { | ||
143 | syslog(LOG_ERR, "%s:%s no matching type\n", __func__, temp_str); | ||
144 | return -ENOENT; | ||
145 | } | ||
146 | ptdata.tzi[tzid].tp[tpid].type = trip_type; | ||
147 | syslog(LOG_INFO, "%s:tz:%d tp:%d:type:%s type id %d\n", __func__, tzid, | ||
148 | tpid, temp_str, trip_type); | ||
149 | |||
150 | /* TODO: check attribute */ | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | /* return instance id for file format such as trip_point_4_temp */ | ||
156 | static int get_instance_id(char *name, int pos, int skip) | ||
157 | { | ||
158 | char *ch; | ||
159 | int i = 0; | ||
160 | |||
161 | ch = strtok(name, "_"); | ||
162 | while (ch != NULL) { | ||
163 | ++i; | ||
164 | syslog(LOG_INFO, "%s:%s:%s:%d", __func__, name, ch, i); | ||
165 | ch = strtok(NULL, "_"); | ||
166 | if (pos == i) | ||
167 | return atol(ch + skip); | ||
168 | } | ||
169 | |||
170 | return -1; | ||
171 | } | ||
172 | |||
173 | /* Find trip point info of a thermal zone */ | ||
174 | static int find_tzone_tp(char *tz_name, char *d_name, struct tz_info *tzi, | ||
175 | int tz_id) | ||
176 | { | ||
177 | int tp_id; | ||
178 | unsigned long temp_ulong; | ||
179 | |||
180 | if (strstr(d_name, "trip_point") && | ||
181 | strstr(d_name, "temp")) { | ||
182 | /* check if trip point temp is non-zero | ||
183 | * ignore 0/invalid trip points | ||
184 | */ | ||
185 | sysfs_get_ulong(tz_name, d_name, &temp_ulong); | ||
186 | if (temp_ulong < MAX_TEMP_KC) { | ||
187 | tzi->nr_trip_pts++; | ||
188 | /* found a valid trip point */ | ||
189 | tp_id = get_instance_id(d_name, 2, 0); | ||
190 | syslog(LOG_DEBUG, "tzone %s trip %d temp %lu tpnode %s", | ||
191 | tz_name, tp_id, temp_ulong, d_name); | ||
192 | if (tp_id < 0 || tp_id >= MAX_NR_TRIP) { | ||
193 | syslog(LOG_ERR, "Failed to find TP inst %s\n", | ||
194 | d_name); | ||
195 | return -1; | ||
196 | } | ||
197 | get_trip_point_data(tz_name, tz_id, tp_id); | ||
198 | tzi->tp[tp_id].temp = temp_ulong; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | /* check cooling devices for binding info. */ | ||
206 | static int find_tzone_cdev(struct dirent *nl, char *tz_name, | ||
207 | struct tz_info *tzi, int tz_id, int cid) | ||
208 | { | ||
209 | unsigned long trip_instance = 0; | ||
210 | char cdev_name_linked[256]; | ||
211 | char cdev_name[256]; | ||
212 | char cdev_trip_name[256]; | ||
213 | int cdev_id; | ||
214 | |||
215 | if (nl->d_type == DT_LNK) { | ||
216 | syslog(LOG_DEBUG, "TZ%d: cdev: %s cid %d\n", tz_id, nl->d_name, | ||
217 | cid); | ||
218 | tzi->nr_cdev++; | ||
219 | if (tzi->nr_cdev > ptdata.nr_cooling_dev) { | ||
220 | syslog(LOG_ERR, "Err: Too many cdev? %d\n", | ||
221 | tzi->nr_cdev); | ||
222 | return -EINVAL; | ||
223 | } | ||
224 | /* find the link to real cooling device record binding */ | ||
225 | snprintf(cdev_name, 256, "%s/%s", tz_name, nl->d_name); | ||
226 | memset(cdev_name_linked, 0, sizeof(cdev_name_linked)); | ||
227 | if (readlink(cdev_name, cdev_name_linked, | ||
228 | sizeof(cdev_name_linked) - 1) != -1) { | ||
229 | cdev_id = get_instance_id(cdev_name_linked, 1, | ||
230 | sizeof("device") - 1); | ||
231 | syslog(LOG_DEBUG, "cdev %s linked to %s : %d\n", | ||
232 | cdev_name, cdev_name_linked, cdev_id); | ||
233 | tzi->cdev_binding |= (1 << cdev_id); | ||
234 | |||
235 | /* find the trip point in which the cdev is binded to | ||
236 | * in this tzone | ||
237 | */ | ||
238 | snprintf(cdev_trip_name, 256, "%s%s", nl->d_name, | ||
239 | "_trip_point"); | ||
240 | sysfs_get_ulong(tz_name, cdev_trip_name, | ||
241 | &trip_instance); | ||
242 | /* validate trip point range, e.g. trip could return -1 | ||
243 | * when passive is enabled | ||
244 | */ | ||
245 | if (trip_instance > MAX_NR_TRIP) | ||
246 | trip_instance = 0; | ||
247 | tzi->trip_binding[cdev_id] |= 1 << trip_instance; | ||
248 | syslog(LOG_DEBUG, "cdev %s -> trip:%lu: 0x%lx %d\n", | ||
249 | cdev_name, trip_instance, | ||
250 | tzi->trip_binding[cdev_id], | ||
251 | cdev_id); | ||
252 | |||
253 | |||
254 | } | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | return -ENODEV; | ||
259 | } | ||
260 | |||
261 | |||
262 | |||
263 | /***************************************************************************** | ||
264 | * Before calling scan_tzones, thermal sysfs must be probed to determine | ||
265 | * the number of thermal zones and cooling devices. | ||
266 | * We loop through each thermal zone and fill in tz_info struct, i.e. | ||
267 | * ptdata.tzi[] | ||
268 | root@jacob-chiefriver:~# tree -d /sys/class/thermal/thermal_zone0 | ||
269 | /sys/class/thermal/thermal_zone0 | ||
270 | |-- cdev0 -> ../cooling_device4 | ||
271 | |-- cdev1 -> ../cooling_device3 | ||
272 | |-- cdev10 -> ../cooling_device7 | ||
273 | |-- cdev11 -> ../cooling_device6 | ||
274 | |-- cdev12 -> ../cooling_device5 | ||
275 | |-- cdev2 -> ../cooling_device2 | ||
276 | |-- cdev3 -> ../cooling_device1 | ||
277 | |-- cdev4 -> ../cooling_device0 | ||
278 | |-- cdev5 -> ../cooling_device12 | ||
279 | |-- cdev6 -> ../cooling_device11 | ||
280 | |-- cdev7 -> ../cooling_device10 | ||
281 | |-- cdev8 -> ../cooling_device9 | ||
282 | |-- cdev9 -> ../cooling_device8 | ||
283 | |-- device -> ../../../LNXSYSTM:00/device:62/LNXTHERM:00 | ||
284 | |-- power | ||
285 | `-- subsystem -> ../../../../class/thermal | ||
286 | *****************************************************************************/ | ||
287 | static int scan_tzones(void) | ||
288 | { | ||
289 | DIR *dir; | ||
290 | struct dirent **namelist; | ||
291 | char tz_name[256]; | ||
292 | int i, j, n, k = 0; | ||
293 | |||
294 | if (!ptdata.nr_tz_sensor) | ||
295 | return -1; | ||
296 | |||
297 | for (i = 0; i <= ptdata.max_tz_instance; i++) { | ||
298 | memset(tz_name, 0, sizeof(tz_name)); | ||
299 | snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE, i); | ||
300 | |||
301 | dir = opendir(tz_name); | ||
302 | if (!dir) { | ||
303 | syslog(LOG_INFO, "Thermal zone %s skipped\n", tz_name); | ||
304 | continue; | ||
305 | } | ||
306 | /* keep track of valid tzones */ | ||
307 | n = scandir(tz_name, &namelist, 0, alphasort); | ||
308 | if (n < 0) | ||
309 | syslog(LOG_ERR, "scandir failed in %s", tz_name); | ||
310 | else { | ||
311 | sysfs_get_string(tz_name, "type", ptdata.tzi[k].type); | ||
312 | ptdata.tzi[k].instance = i; | ||
313 | /* detect trip points and cdev attached to this tzone */ | ||
314 | j = 0; /* index for cdev */ | ||
315 | ptdata.tzi[k].nr_cdev = 0; | ||
316 | ptdata.tzi[k].nr_trip_pts = 0; | ||
317 | while (n--) { | ||
318 | char *temp_str; | ||
319 | |||
320 | if (find_tzone_tp(tz_name, namelist[n]->d_name, | ||
321 | &ptdata.tzi[k], k)) | ||
322 | break; | ||
323 | temp_str = strstr(namelist[n]->d_name, "cdev"); | ||
324 | if (!temp_str) { | ||
325 | free(namelist[n]); | ||
326 | continue; | ||
327 | } | ||
328 | if (!find_tzone_cdev(namelist[n], tz_name, | ||
329 | &ptdata.tzi[k], i, j)) | ||
330 | j++; /* increment cdev index */ | ||
331 | free(namelist[n]); | ||
332 | } | ||
333 | free(namelist); | ||
334 | } | ||
335 | /*TODO: reverse trip points */ | ||
336 | closedir(dir); | ||
337 | syslog(LOG_INFO, "TZ %d has %d cdev\n", i, | ||
338 | ptdata.tzi[k].nr_cdev); | ||
339 | k++; | ||
340 | } | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static int scan_cdevs(void) | ||
346 | { | ||
347 | DIR *dir; | ||
348 | struct dirent **namelist; | ||
349 | char cdev_name[256]; | ||
350 | int i, n, k = 0; | ||
351 | |||
352 | if (!ptdata.nr_cooling_dev) { | ||
353 | fprintf(stderr, "No cooling devices found\n"); | ||
354 | return 0; | ||
355 | } | ||
356 | for (i = 0; i <= ptdata.max_cdev_instance; i++) { | ||
357 | memset(cdev_name, 0, sizeof(cdev_name)); | ||
358 | snprintf(cdev_name, 256, "%s/%s%d", THERMAL_SYSFS, CDEV, i); | ||
359 | |||
360 | dir = opendir(cdev_name); | ||
361 | if (!dir) { | ||
362 | syslog(LOG_INFO, "Cooling dev %s skipped\n", cdev_name); | ||
363 | /* there is a gap in cooling device id, check again | ||
364 | * for the same index. | ||
365 | */ | ||
366 | continue; | ||
367 | } | ||
368 | |||
369 | n = scandir(cdev_name, &namelist, 0, alphasort); | ||
370 | if (n < 0) | ||
371 | syslog(LOG_ERR, "scandir failed in %s", cdev_name); | ||
372 | else { | ||
373 | sysfs_get_string(cdev_name, "type", ptdata.cdi[k].type); | ||
374 | ptdata.cdi[k].instance = i; | ||
375 | if (strstr(ptdata.cdi[k].type, ctrl_cdev)) { | ||
376 | ptdata.cdi[k].flag |= CDEV_FLAG_IN_CONTROL; | ||
377 | syslog(LOG_DEBUG, "control cdev id %d\n", i); | ||
378 | } | ||
379 | while (n--) | ||
380 | free(namelist[n]); | ||
381 | free(namelist); | ||
382 | } | ||
383 | closedir(dir); | ||
384 | k++; | ||
385 | } | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | |||
390 | int probe_thermal_sysfs(void) | ||
391 | { | ||
392 | DIR *dir; | ||
393 | struct dirent **namelist; | ||
394 | int n; | ||
395 | |||
396 | dir = opendir(THERMAL_SYSFS); | ||
397 | if (!dir) { | ||
398 | fprintf(stderr, "\nNo thermal sysfs, exit\n"); | ||
399 | return -1; | ||
400 | } | ||
401 | n = scandir(THERMAL_SYSFS, &namelist, 0, alphasort); | ||
402 | if (n < 0) | ||
403 | syslog(LOG_ERR, "scandir failed in thermal sysfs"); | ||
404 | else { | ||
405 | /* detect number of thermal zones and cooling devices */ | ||
406 | while (n--) { | ||
407 | int inst; | ||
408 | |||
409 | if (strstr(namelist[n]->d_name, CDEV)) { | ||
410 | inst = get_instance_id(namelist[n]->d_name, 1, | ||
411 | sizeof("device") - 1); | ||
412 | /* keep track of the max cooling device since | ||
413 | * there may be gaps. | ||
414 | */ | ||
415 | if (inst > ptdata.max_cdev_instance) | ||
416 | ptdata.max_cdev_instance = inst; | ||
417 | |||
418 | syslog(LOG_DEBUG, "found cdev: %s %d %d\n", | ||
419 | namelist[n]->d_name, | ||
420 | ptdata.nr_cooling_dev, | ||
421 | ptdata.max_cdev_instance); | ||
422 | ptdata.nr_cooling_dev++; | ||
423 | } else if (strstr(namelist[n]->d_name, TZONE)) { | ||
424 | inst = get_instance_id(namelist[n]->d_name, 1, | ||
425 | sizeof("zone") - 1); | ||
426 | if (inst > ptdata.max_tz_instance) | ||
427 | ptdata.max_tz_instance = inst; | ||
428 | |||
429 | syslog(LOG_DEBUG, "found tzone: %s %d %d\n", | ||
430 | namelist[n]->d_name, | ||
431 | ptdata.nr_tz_sensor, | ||
432 | ptdata.max_tz_instance); | ||
433 | ptdata.nr_tz_sensor++; | ||
434 | } | ||
435 | free(namelist[n]); | ||
436 | } | ||
437 | free(namelist); | ||
438 | } | ||
439 | syslog(LOG_INFO, "found %d tzone(s), %d cdev(s), target zone %d\n", | ||
440 | ptdata.nr_tz_sensor, ptdata.nr_cooling_dev, | ||
441 | target_thermal_zone); | ||
442 | closedir(dir); | ||
443 | |||
444 | if (!ptdata.nr_tz_sensor) { | ||
445 | fprintf(stderr, "\nNo thermal zones found, exit\n\n"); | ||
446 | return -1; | ||
447 | } | ||
448 | |||
449 | ptdata.tzi = calloc(sizeof(struct tz_info), ptdata.max_tz_instance+1); | ||
450 | if (!ptdata.tzi) { | ||
451 | fprintf(stderr, "Err: allocate tz_info\n"); | ||
452 | return -1; | ||
453 | } | ||
454 | |||
455 | /* we still show thermal zone information if there is no cdev */ | ||
456 | if (ptdata.nr_cooling_dev) { | ||
457 | ptdata.cdi = calloc(sizeof(struct cdev_info), | ||
458 | ptdata.max_cdev_instance + 1); | ||
459 | if (!ptdata.cdi) { | ||
460 | free(ptdata.tzi); | ||
461 | fprintf(stderr, "Err: allocate cdev_info\n"); | ||
462 | return -1; | ||
463 | } | ||
464 | } | ||
465 | |||
466 | /* now probe tzones */ | ||
467 | if (scan_tzones()) | ||
468 | return -1; | ||
469 | if (scan_cdevs()) | ||
470 | return -1; | ||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | /* convert sysfs zone instance to zone array index */ | ||
475 | int zone_instance_to_index(int zone_inst) | ||
476 | { | ||
477 | int i; | ||
478 | |||
479 | for (i = 0; i < ptdata.nr_tz_sensor; i++) | ||
480 | if (ptdata.tzi[i].instance == zone_inst) | ||
481 | return i; | ||
482 | return -ENOENT; | ||
483 | } | ||
484 | |||
485 | /* read temperature of all thermal zones */ | ||
486 | int update_thermal_data() | ||
487 | { | ||
488 | int i; | ||
489 | char tz_name[256]; | ||
490 | static unsigned long samples; | ||
491 | |||
492 | if (!ptdata.nr_tz_sensor) { | ||
493 | syslog(LOG_ERR, "No thermal zones found!\n"); | ||
494 | return -1; | ||
495 | } | ||
496 | |||
497 | /* circular buffer for keeping historic data */ | ||
498 | if (cur_thermal_record >= NR_THERMAL_RECORDS) | ||
499 | cur_thermal_record = 0; | ||
500 | gettimeofday(&trec[cur_thermal_record].tv, NULL); | ||
501 | if (tmon_log) { | ||
502 | fprintf(tmon_log, "%lu ", ++samples); | ||
503 | fprintf(tmon_log, "%3.1f ", p_param.t_target); | ||
504 | } | ||
505 | for (i = 0; i < ptdata.nr_tz_sensor; i++) { | ||
506 | memset(tz_name, 0, sizeof(tz_name)); | ||
507 | snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE, | ||
508 | ptdata.tzi[i].instance); | ||
509 | sysfs_get_ulong(tz_name, "temp", | ||
510 | &trec[cur_thermal_record].temp[i]); | ||
511 | if (tmon_log) | ||
512 | fprintf(tmon_log, "%lu ", | ||
513 | trec[cur_thermal_record].temp[i]/1000); | ||
514 | } | ||
515 | for (i = 0; i < ptdata.nr_cooling_dev; i++) { | ||
516 | char cdev_name[256]; | ||
517 | unsigned long val; | ||
518 | |||
519 | snprintf(cdev_name, 256, "%s/%s%d", THERMAL_SYSFS, CDEV, | ||
520 | ptdata.cdi[i].instance); | ||
521 | probe_cdev(&ptdata.cdi[i], cdev_name); | ||
522 | val = ptdata.cdi[i].cur_state; | ||
523 | if (val > 1000000) | ||
524 | val = 0; | ||
525 | if (tmon_log) | ||
526 | fprintf(tmon_log, "%lu ", val); | ||
527 | } | ||
528 | |||
529 | if (tmon_log) { | ||
530 | fprintf(tmon_log, "\n"); | ||
531 | fflush(tmon_log); | ||
532 | } | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | void set_ctrl_state(unsigned long state) | ||
538 | { | ||
539 | char ctrl_cdev_path[256]; | ||
540 | int i; | ||
541 | unsigned long cdev_state; | ||
542 | |||
543 | if (no_control) | ||
544 | return; | ||
545 | /* set all ctrl cdev to the same state */ | ||
546 | for (i = 0; i < ptdata.nr_cooling_dev; i++) { | ||
547 | if (ptdata.cdi[i].flag & CDEV_FLAG_IN_CONTROL) { | ||
548 | if (ptdata.cdi[i].max_state < 10) { | ||
549 | strcpy(ctrl_cdev, "None."); | ||
550 | return; | ||
551 | } | ||
552 | /* scale to percentage of max_state */ | ||
553 | cdev_state = state * ptdata.cdi[i].max_state/100; | ||
554 | syslog(LOG_DEBUG, | ||
555 | "ctrl cdev %d set state %lu scaled to %lu\n", | ||
556 | ptdata.cdi[i].instance, state, cdev_state); | ||
557 | snprintf(ctrl_cdev_path, 256, "%s/%s%d", THERMAL_SYSFS, | ||
558 | CDEV, ptdata.cdi[i].instance); | ||
559 | syslog(LOG_DEBUG, "ctrl cdev path %s", ctrl_cdev_path); | ||
560 | sysfs_set_ulong(ctrl_cdev_path, "cur_state", | ||
561 | cdev_state); | ||
562 | } | ||
563 | } | ||
564 | } | ||
565 | |||
566 | void get_ctrl_state(unsigned long *state) | ||
567 | { | ||
568 | char ctrl_cdev_path[256]; | ||
569 | int ctrl_cdev_id = -1; | ||
570 | int i; | ||
571 | |||
572 | /* TODO: take average of all ctrl types. also consider change based on | ||
573 | * uevent. Take the first reading for now. | ||
574 | */ | ||
575 | for (i = 0; i < ptdata.nr_cooling_dev; i++) { | ||
576 | if (ptdata.cdi[i].flag & CDEV_FLAG_IN_CONTROL) { | ||
577 | ctrl_cdev_id = ptdata.cdi[i].instance; | ||
578 | syslog(LOG_INFO, "ctrl cdev %d get state\n", | ||
579 | ptdata.cdi[i].instance); | ||
580 | break; | ||
581 | } | ||
582 | } | ||
583 | if (ctrl_cdev_id == -1) { | ||
584 | *state = 0; | ||
585 | return; | ||
586 | } | ||
587 | snprintf(ctrl_cdev_path, 256, "%s/%s%d", THERMAL_SYSFS, | ||
588 | CDEV, ctrl_cdev_id); | ||
589 | sysfs_get_ulong(ctrl_cdev_path, "cur_state", state); | ||
590 | } | ||
591 | |||
592 | void free_thermal_data(void) | ||
593 | { | ||
594 | free(ptdata.tzi); | ||
595 | free(ptdata.cdi); | ||
596 | } | ||