This source file includes following definitions.
- sysfs_set_ulong
- sysfs_get_ulong
- sysfs_get_string
- probe_cdev
- str_to_trip_type
- get_trip_point_data
- get_instance_id
- find_tzone_tp
- find_tzone_cdev
- scan_tzones
- scan_cdevs
- probe_thermal_sysfs
- zone_instance_to_index
- update_thermal_data
- set_ctrl_state
- get_ctrl_state
- free_thermal_data
1
2
3
4
5
6
7
8
9 #include <unistd.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <stdint.h>
14 #include <dirent.h>
15 #include <libintl.h>
16 #include <ctype.h>
17 #include <time.h>
18 #include <syslog.h>
19 #include <sys/time.h>
20 #include <errno.h>
21
22 #include "tmon.h"
23
24 struct tmon_platform_data ptdata;
25 const char *trip_type_name[] = {
26 "critical",
27 "hot",
28 "passive",
29 "active",
30 };
31
32 int sysfs_set_ulong(char *path, char *filename, unsigned long val)
33 {
34 FILE *fd;
35 int ret = -1;
36 char filepath[256];
37
38 snprintf(filepath, 256, "%s/%s", path, filename);
39
40 fd = fopen(filepath, "w");
41 if (!fd) {
42 syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath);
43 return ret;
44 }
45 ret = fprintf(fd, "%lu", val);
46 fclose(fd);
47
48 return 0;
49 }
50
51
52 #define NR_THERMAL_RECORDS 3
53 struct thermal_data_record trec[NR_THERMAL_RECORDS];
54 int cur_thermal_record;
55
56 static int sysfs_get_ulong(char *path, char *filename, unsigned long *p_ulong)
57 {
58 FILE *fd;
59 int ret = -1;
60 char filepath[256];
61
62 snprintf(filepath, 256, "%s/%s", path, filename);
63
64 fd = fopen(filepath, "r");
65 if (!fd) {
66 syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath);
67 return ret;
68 }
69 ret = fscanf(fd, "%lu", p_ulong);
70 fclose(fd);
71
72 return 0;
73 }
74
75 static int sysfs_get_string(char *path, char *filename, char *str)
76 {
77 FILE *fd;
78 int ret = -1;
79 char filepath[256];
80
81 snprintf(filepath, 256, "%s/%s", path, filename);
82
83 fd = fopen(filepath, "r");
84 if (!fd) {
85 syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath);
86 return ret;
87 }
88 ret = fscanf(fd, "%256s", str);
89 fclose(fd);
90
91 return ret;
92 }
93
94
95 static int probe_cdev(struct cdev_info *cdi, char *path)
96 {
97 sysfs_get_string(path, "type", cdi->type);
98 sysfs_get_ulong(path, "max_state", &cdi->max_state);
99 sysfs_get_ulong(path, "cur_state", &cdi->cur_state);
100
101 syslog(LOG_INFO, "%s: %s: type %s, max %lu, curr %lu inst %d\n",
102 __func__, path,
103 cdi->type, cdi->max_state, cdi->cur_state, cdi->instance);
104
105 return 0;
106 }
107
108 static int str_to_trip_type(char *name)
109 {
110 int i;
111
112 for (i = 0; i < NR_THERMAL_TRIP_TYPE; i++) {
113 if (!strcmp(name, trip_type_name[i]))
114 return i;
115 }
116
117 return -ENOENT;
118 }
119
120
121 static int get_trip_point_data(char *tz_path, int tzid, int tpid)
122 {
123 char filename[256];
124 char temp_str[256];
125 int trip_type;
126
127 if (tpid >= MAX_NR_TRIP)
128 return -EINVAL;
129
130 snprintf(filename, sizeof(filename), "trip_point_%d_type", tpid);
131 sysfs_get_string(tz_path, filename, temp_str);
132 trip_type = str_to_trip_type(temp_str);
133 if (trip_type < 0) {
134 syslog(LOG_ERR, "%s:%s no matching type\n", __func__, temp_str);
135 return -ENOENT;
136 }
137 ptdata.tzi[tzid].tp[tpid].type = trip_type;
138 syslog(LOG_INFO, "%s:tz:%d tp:%d:type:%s type id %d\n", __func__, tzid,
139 tpid, temp_str, trip_type);
140
141
142
143 return 0;
144 }
145
146
147 static int get_instance_id(char *name, int pos, int skip)
148 {
149 char *ch;
150 int i = 0;
151
152 ch = strtok(name, "_");
153 while (ch != NULL) {
154 ++i;
155 syslog(LOG_INFO, "%s:%s:%s:%d", __func__, name, ch, i);
156 ch = strtok(NULL, "_");
157 if (pos == i)
158 return atol(ch + skip);
159 }
160
161 return -1;
162 }
163
164
165 static int find_tzone_tp(char *tz_name, char *d_name, struct tz_info *tzi,
166 int tz_id)
167 {
168 int tp_id;
169 unsigned long temp_ulong;
170
171 if (strstr(d_name, "trip_point") &&
172 strstr(d_name, "temp")) {
173
174
175
176 sysfs_get_ulong(tz_name, d_name, &temp_ulong);
177 if (temp_ulong < MAX_TEMP_KC) {
178 tzi->nr_trip_pts++;
179
180 tp_id = get_instance_id(d_name, 2, 0);
181 syslog(LOG_DEBUG, "tzone %s trip %d temp %lu tpnode %s",
182 tz_name, tp_id, temp_ulong, d_name);
183 if (tp_id < 0 || tp_id >= MAX_NR_TRIP) {
184 syslog(LOG_ERR, "Failed to find TP inst %s\n",
185 d_name);
186 return -1;
187 }
188 get_trip_point_data(tz_name, tz_id, tp_id);
189 tzi->tp[tp_id].temp = temp_ulong;
190 }
191 }
192
193 return 0;
194 }
195
196
197 static int find_tzone_cdev(struct dirent *nl, char *tz_name,
198 struct tz_info *tzi, int tz_id, int cid)
199 {
200 unsigned long trip_instance = 0;
201 char cdev_name_linked[256];
202 char cdev_name[256];
203 char cdev_trip_name[256];
204 int cdev_id;
205
206 if (nl->d_type == DT_LNK) {
207 syslog(LOG_DEBUG, "TZ%d: cdev: %s cid %d\n", tz_id, nl->d_name,
208 cid);
209 tzi->nr_cdev++;
210 if (tzi->nr_cdev > ptdata.nr_cooling_dev) {
211 syslog(LOG_ERR, "Err: Too many cdev? %d\n",
212 tzi->nr_cdev);
213 return -EINVAL;
214 }
215
216 snprintf(cdev_name, 256, "%s/%s", tz_name, nl->d_name);
217 memset(cdev_name_linked, 0, sizeof(cdev_name_linked));
218 if (readlink(cdev_name, cdev_name_linked,
219 sizeof(cdev_name_linked) - 1) != -1) {
220 cdev_id = get_instance_id(cdev_name_linked, 1,
221 sizeof("device") - 1);
222 syslog(LOG_DEBUG, "cdev %s linked to %s : %d\n",
223 cdev_name, cdev_name_linked, cdev_id);
224 tzi->cdev_binding |= (1 << cdev_id);
225
226
227
228
229 snprintf(cdev_trip_name, 256, "%s%s", nl->d_name,
230 "_trip_point");
231 sysfs_get_ulong(tz_name, cdev_trip_name,
232 &trip_instance);
233
234
235
236 if (trip_instance > MAX_NR_TRIP)
237 trip_instance = 0;
238 tzi->trip_binding[cdev_id] |= 1 << trip_instance;
239 syslog(LOG_DEBUG, "cdev %s -> trip:%lu: 0x%lx %d\n",
240 cdev_name, trip_instance,
241 tzi->trip_binding[cdev_id],
242 cdev_id);
243
244
245 }
246 return 0;
247 }
248
249 return -ENODEV;
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 static int scan_tzones(void)
279 {
280 DIR *dir;
281 struct dirent **namelist;
282 char tz_name[256];
283 int i, j, n, k = 0;
284
285 if (!ptdata.nr_tz_sensor)
286 return -1;
287
288 for (i = 0; i <= ptdata.max_tz_instance; i++) {
289 memset(tz_name, 0, sizeof(tz_name));
290 snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE, i);
291
292 dir = opendir(tz_name);
293 if (!dir) {
294 syslog(LOG_INFO, "Thermal zone %s skipped\n", tz_name);
295 continue;
296 }
297
298 n = scandir(tz_name, &namelist, 0, alphasort);
299 if (n < 0)
300 syslog(LOG_ERR, "scandir failed in %s", tz_name);
301 else {
302 sysfs_get_string(tz_name, "type", ptdata.tzi[k].type);
303 ptdata.tzi[k].instance = i;
304
305 j = 0;
306 ptdata.tzi[k].nr_cdev = 0;
307 ptdata.tzi[k].nr_trip_pts = 0;
308 while (n--) {
309 char *temp_str;
310
311 if (find_tzone_tp(tz_name, namelist[n]->d_name,
312 &ptdata.tzi[k], k))
313 break;
314 temp_str = strstr(namelist[n]->d_name, "cdev");
315 if (!temp_str) {
316 free(namelist[n]);
317 continue;
318 }
319 if (!find_tzone_cdev(namelist[n], tz_name,
320 &ptdata.tzi[k], i, j))
321 j++;
322 free(namelist[n]);
323 }
324 free(namelist);
325 }
326
327 closedir(dir);
328 syslog(LOG_INFO, "TZ %d has %d cdev\n", i,
329 ptdata.tzi[k].nr_cdev);
330 k++;
331 }
332
333 return 0;
334 }
335
336 static int scan_cdevs(void)
337 {
338 DIR *dir;
339 struct dirent **namelist;
340 char cdev_name[256];
341 int i, n, k = 0;
342
343 if (!ptdata.nr_cooling_dev) {
344 fprintf(stderr, "No cooling devices found\n");
345 return 0;
346 }
347 for (i = 0; i <= ptdata.max_cdev_instance; i++) {
348 memset(cdev_name, 0, sizeof(cdev_name));
349 snprintf(cdev_name, 256, "%s/%s%d", THERMAL_SYSFS, CDEV, i);
350
351 dir = opendir(cdev_name);
352 if (!dir) {
353 syslog(LOG_INFO, "Cooling dev %s skipped\n", cdev_name);
354
355
356
357 continue;
358 }
359
360 n = scandir(cdev_name, &namelist, 0, alphasort);
361 if (n < 0)
362 syslog(LOG_ERR, "scandir failed in %s", cdev_name);
363 else {
364 sysfs_get_string(cdev_name, "type", ptdata.cdi[k].type);
365 ptdata.cdi[k].instance = i;
366 if (strstr(ptdata.cdi[k].type, ctrl_cdev)) {
367 ptdata.cdi[k].flag |= CDEV_FLAG_IN_CONTROL;
368 syslog(LOG_DEBUG, "control cdev id %d\n", i);
369 }
370 while (n--)
371 free(namelist[n]);
372 free(namelist);
373 }
374 closedir(dir);
375 k++;
376 }
377 return 0;
378 }
379
380
381 int probe_thermal_sysfs(void)
382 {
383 DIR *dir;
384 struct dirent **namelist;
385 int n;
386
387 dir = opendir(THERMAL_SYSFS);
388 if (!dir) {
389 fprintf(stderr, "\nNo thermal sysfs, exit\n");
390 return -1;
391 }
392 n = scandir(THERMAL_SYSFS, &namelist, 0, alphasort);
393 if (n < 0)
394 syslog(LOG_ERR, "scandir failed in thermal sysfs");
395 else {
396
397 while (n--) {
398 int inst;
399
400 if (strstr(namelist[n]->d_name, CDEV)) {
401 inst = get_instance_id(namelist[n]->d_name, 1,
402 sizeof("device") - 1);
403
404
405
406 if (inst > ptdata.max_cdev_instance)
407 ptdata.max_cdev_instance = inst;
408
409 syslog(LOG_DEBUG, "found cdev: %s %d %d\n",
410 namelist[n]->d_name,
411 ptdata.nr_cooling_dev,
412 ptdata.max_cdev_instance);
413 ptdata.nr_cooling_dev++;
414 } else if (strstr(namelist[n]->d_name, TZONE)) {
415 inst = get_instance_id(namelist[n]->d_name, 1,
416 sizeof("zone") - 1);
417 if (inst > ptdata.max_tz_instance)
418 ptdata.max_tz_instance = inst;
419
420 syslog(LOG_DEBUG, "found tzone: %s %d %d\n",
421 namelist[n]->d_name,
422 ptdata.nr_tz_sensor,
423 ptdata.max_tz_instance);
424 ptdata.nr_tz_sensor++;
425 }
426 free(namelist[n]);
427 }
428 free(namelist);
429 }
430 syslog(LOG_INFO, "found %d tzone(s), %d cdev(s), target zone %d\n",
431 ptdata.nr_tz_sensor, ptdata.nr_cooling_dev,
432 target_thermal_zone);
433 closedir(dir);
434
435 if (!ptdata.nr_tz_sensor) {
436 fprintf(stderr, "\nNo thermal zones found, exit\n\n");
437 return -1;
438 }
439
440 ptdata.tzi = calloc(ptdata.max_tz_instance+1, sizeof(struct tz_info));
441 if (!ptdata.tzi) {
442 fprintf(stderr, "Err: allocate tz_info\n");
443 return -1;
444 }
445
446
447 if (ptdata.nr_cooling_dev) {
448 ptdata.cdi = calloc(ptdata.max_cdev_instance + 1,
449 sizeof(struct cdev_info));
450 if (!ptdata.cdi) {
451 free(ptdata.tzi);
452 fprintf(stderr, "Err: allocate cdev_info\n");
453 return -1;
454 }
455 }
456
457
458 if (scan_tzones())
459 return -1;
460 if (scan_cdevs())
461 return -1;
462 return 0;
463 }
464
465
466 int zone_instance_to_index(int zone_inst)
467 {
468 int i;
469
470 for (i = 0; i < ptdata.nr_tz_sensor; i++)
471 if (ptdata.tzi[i].instance == zone_inst)
472 return i;
473 return -ENOENT;
474 }
475
476
477 int update_thermal_data()
478 {
479 int i;
480 int next_thermal_record = cur_thermal_record + 1;
481 char tz_name[256];
482 static unsigned long samples;
483
484 if (!ptdata.nr_tz_sensor) {
485 syslog(LOG_ERR, "No thermal zones found!\n");
486 return -1;
487 }
488
489
490 if (next_thermal_record >= NR_THERMAL_RECORDS)
491 next_thermal_record = 0;
492 gettimeofday(&trec[next_thermal_record].tv, NULL);
493 if (tmon_log) {
494 fprintf(tmon_log, "%lu ", ++samples);
495 fprintf(tmon_log, "%3.1f ", p_param.t_target);
496 }
497 for (i = 0; i < ptdata.nr_tz_sensor; i++) {
498 memset(tz_name, 0, sizeof(tz_name));
499 snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE,
500 ptdata.tzi[i].instance);
501 sysfs_get_ulong(tz_name, "temp",
502 &trec[next_thermal_record].temp[i]);
503 if (tmon_log)
504 fprintf(tmon_log, "%lu ",
505 trec[next_thermal_record].temp[i] / 1000);
506 }
507 cur_thermal_record = next_thermal_record;
508 for (i = 0; i < ptdata.nr_cooling_dev; i++) {
509 char cdev_name[256];
510 unsigned long val;
511
512 snprintf(cdev_name, 256, "%s/%s%d", THERMAL_SYSFS, CDEV,
513 ptdata.cdi[i].instance);
514 probe_cdev(&ptdata.cdi[i], cdev_name);
515 val = ptdata.cdi[i].cur_state;
516 if (val > 1000000)
517 val = 0;
518 if (tmon_log)
519 fprintf(tmon_log, "%lu ", val);
520 }
521
522 if (tmon_log) {
523 fprintf(tmon_log, "\n");
524 fflush(tmon_log);
525 }
526
527 return 0;
528 }
529
530 void set_ctrl_state(unsigned long state)
531 {
532 char ctrl_cdev_path[256];
533 int i;
534 unsigned long cdev_state;
535
536 if (no_control)
537 return;
538
539 for (i = 0; i < ptdata.nr_cooling_dev; i++) {
540 if (ptdata.cdi[i].flag & CDEV_FLAG_IN_CONTROL) {
541 if (ptdata.cdi[i].max_state < 10) {
542 strcpy(ctrl_cdev, "None.");
543 return;
544 }
545
546 cdev_state = state * ptdata.cdi[i].max_state/100;
547 syslog(LOG_DEBUG,
548 "ctrl cdev %d set state %lu scaled to %lu\n",
549 ptdata.cdi[i].instance, state, cdev_state);
550 snprintf(ctrl_cdev_path, 256, "%s/%s%d", THERMAL_SYSFS,
551 CDEV, ptdata.cdi[i].instance);
552 syslog(LOG_DEBUG, "ctrl cdev path %s", ctrl_cdev_path);
553 sysfs_set_ulong(ctrl_cdev_path, "cur_state",
554 cdev_state);
555 }
556 }
557 }
558
559 void get_ctrl_state(unsigned long *state)
560 {
561 char ctrl_cdev_path[256];
562 int ctrl_cdev_id = -1;
563 int i;
564
565
566
567
568 for (i = 0; i < ptdata.nr_cooling_dev; i++) {
569 if (ptdata.cdi[i].flag & CDEV_FLAG_IN_CONTROL) {
570 ctrl_cdev_id = ptdata.cdi[i].instance;
571 syslog(LOG_INFO, "ctrl cdev %d get state\n",
572 ptdata.cdi[i].instance);
573 break;
574 }
575 }
576 if (ctrl_cdev_id == -1) {
577 *state = 0;
578 return;
579 }
580 snprintf(ctrl_cdev_path, 256, "%s/%s%d", THERMAL_SYSFS,
581 CDEV, ctrl_cdev_id);
582 sysfs_get_ulong(ctrl_cdev_path, "cur_state", state);
583 }
584
585 void free_thermal_data(void)
586 {
587 free(ptdata.tzi);
588 free(ptdata.cdi);
589 }