0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <unistd.h>
0010 #include <stdio.h>
0011 #include <stdlib.h>
0012 #include <string.h>
0013 #include <stdint.h>
0014 #include <dirent.h>
0015 #include <libintl.h>
0016 #include <limits.h>
0017 #include <ctype.h>
0018 #include <time.h>
0019 #include <syslog.h>
0020 #include <sys/time.h>
0021 #include <errno.h>
0022
0023 #include "tmon.h"
0024
0025 struct tmon_platform_data ptdata;
0026 const char *trip_type_name[] = {
0027 "critical",
0028 "hot",
0029 "passive",
0030 "active",
0031 };
0032
0033 int sysfs_set_ulong(char *path, char *filename, unsigned long val)
0034 {
0035 FILE *fd;
0036 int ret = -1;
0037 char filepath[PATH_MAX + 2];
0038
0039 snprintf(filepath, sizeof(filepath), "%s/%s", path, filename);
0040
0041 fd = fopen(filepath, "w");
0042 if (!fd) {
0043 syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath);
0044 return ret;
0045 }
0046 ret = fprintf(fd, "%lu", val);
0047 fclose(fd);
0048
0049 return 0;
0050 }
0051
0052
0053 #define NR_THERMAL_RECORDS 3
0054 struct thermal_data_record trec[NR_THERMAL_RECORDS];
0055 int cur_thermal_record;
0056
0057 static int sysfs_get_ulong(char *path, char *filename, unsigned long *p_ulong)
0058 {
0059 FILE *fd;
0060 int ret = -1;
0061 char filepath[PATH_MAX + 2];
0062
0063 snprintf(filepath, sizeof(filepath), "%s/%s", path, filename);
0064
0065 fd = fopen(filepath, "r");
0066 if (!fd) {
0067 syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath);
0068 return ret;
0069 }
0070 ret = fscanf(fd, "%lu", p_ulong);
0071 fclose(fd);
0072
0073 return 0;
0074 }
0075
0076 static int sysfs_get_string(char *path, char *filename, char *str)
0077 {
0078 FILE *fd;
0079 int ret = -1;
0080 char filepath[PATH_MAX + 2];
0081
0082 snprintf(filepath, sizeof(filepath), "%s/%s", path, filename);
0083
0084 fd = fopen(filepath, "r");
0085 if (!fd) {
0086 syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath);
0087 return ret;
0088 }
0089 ret = fscanf(fd, "%256s", str);
0090 fclose(fd);
0091
0092 return ret;
0093 }
0094
0095
0096 static int probe_cdev(struct cdev_info *cdi, char *path)
0097 {
0098 sysfs_get_string(path, "type", cdi->type);
0099 sysfs_get_ulong(path, "max_state", &cdi->max_state);
0100 sysfs_get_ulong(path, "cur_state", &cdi->cur_state);
0101
0102 syslog(LOG_INFO, "%s: %s: type %s, max %lu, curr %lu inst %d\n",
0103 __func__, path,
0104 cdi->type, cdi->max_state, cdi->cur_state, cdi->instance);
0105
0106 return 0;
0107 }
0108
0109 static int str_to_trip_type(char *name)
0110 {
0111 int i;
0112
0113 for (i = 0; i < NR_THERMAL_TRIP_TYPE; i++) {
0114 if (!strcmp(name, trip_type_name[i]))
0115 return i;
0116 }
0117
0118 return -ENOENT;
0119 }
0120
0121
0122 static int get_trip_point_data(char *tz_path, int tzid, int tpid)
0123 {
0124 char filename[256];
0125 char temp_str[256];
0126 int trip_type;
0127
0128 if (tpid >= MAX_NR_TRIP)
0129 return -EINVAL;
0130
0131 snprintf(filename, sizeof(filename), "trip_point_%d_type", tpid);
0132 sysfs_get_string(tz_path, filename, temp_str);
0133 trip_type = str_to_trip_type(temp_str);
0134 if (trip_type < 0) {
0135 syslog(LOG_ERR, "%s:%s no matching type\n", __func__, temp_str);
0136 return -ENOENT;
0137 }
0138 ptdata.tzi[tzid].tp[tpid].type = trip_type;
0139 syslog(LOG_INFO, "%s:tz:%d tp:%d:type:%s type id %d\n", __func__, tzid,
0140 tpid, temp_str, trip_type);
0141
0142
0143
0144 return 0;
0145 }
0146
0147
0148 static int get_instance_id(char *name, int pos, int skip)
0149 {
0150 char *ch;
0151 int i = 0;
0152
0153 ch = strtok(name, "_");
0154 while (ch != NULL) {
0155 ++i;
0156 syslog(LOG_INFO, "%s:%s:%s:%d", __func__, name, ch, i);
0157 ch = strtok(NULL, "_");
0158 if (pos == i)
0159 return atol(ch + skip);
0160 }
0161
0162 return -1;
0163 }
0164
0165
0166 static int find_tzone_tp(char *tz_name, char *d_name, struct tz_info *tzi,
0167 int tz_id)
0168 {
0169 int tp_id;
0170 unsigned long temp_ulong;
0171
0172 if (strstr(d_name, "trip_point") &&
0173 strstr(d_name, "temp")) {
0174
0175
0176
0177 sysfs_get_ulong(tz_name, d_name, &temp_ulong);
0178 if (temp_ulong < MAX_TEMP_KC) {
0179 tzi->nr_trip_pts++;
0180
0181 tp_id = get_instance_id(d_name, 2, 0);
0182 syslog(LOG_DEBUG, "tzone %s trip %d temp %lu tpnode %s",
0183 tz_name, tp_id, temp_ulong, d_name);
0184 if (tp_id < 0 || tp_id >= MAX_NR_TRIP) {
0185 syslog(LOG_ERR, "Failed to find TP inst %s\n",
0186 d_name);
0187 return -1;
0188 }
0189 get_trip_point_data(tz_name, tz_id, tp_id);
0190 tzi->tp[tp_id].temp = temp_ulong;
0191 }
0192 }
0193
0194 return 0;
0195 }
0196
0197
0198 static int find_tzone_cdev(struct dirent *nl, char *tz_name,
0199 struct tz_info *tzi, int tz_id, int cid)
0200 {
0201 unsigned long trip_instance = 0;
0202 char cdev_name_linked[256];
0203 char cdev_name[PATH_MAX];
0204 char cdev_trip_name[PATH_MAX];
0205 int cdev_id;
0206
0207 if (nl->d_type == DT_LNK) {
0208 syslog(LOG_DEBUG, "TZ%d: cdev: %s cid %d\n", tz_id, nl->d_name,
0209 cid);
0210 tzi->nr_cdev++;
0211 if (tzi->nr_cdev > ptdata.nr_cooling_dev) {
0212 syslog(LOG_ERR, "Err: Too many cdev? %d\n",
0213 tzi->nr_cdev);
0214 return -EINVAL;
0215 }
0216
0217 snprintf(cdev_name, sizeof(cdev_name) - 2, "%s/%s",
0218 tz_name, nl->d_name);
0219 memset(cdev_name_linked, 0, sizeof(cdev_name_linked));
0220 if (readlink(cdev_name, cdev_name_linked,
0221 sizeof(cdev_name_linked) - 1) != -1) {
0222 cdev_id = get_instance_id(cdev_name_linked, 1,
0223 sizeof("device") - 1);
0224 syslog(LOG_DEBUG, "cdev %s linked to %s : %d\n",
0225 cdev_name, cdev_name_linked, cdev_id);
0226 tzi->cdev_binding |= (1 << cdev_id);
0227
0228
0229
0230
0231 snprintf(cdev_trip_name, sizeof(cdev_trip_name) - 1,
0232 "%s%s", nl->d_name, "_trip_point");
0233 sysfs_get_ulong(tz_name, cdev_trip_name,
0234 &trip_instance);
0235
0236
0237
0238 if (trip_instance > MAX_NR_TRIP)
0239 trip_instance = 0;
0240 tzi->trip_binding[cdev_id] |= 1 << trip_instance;
0241 syslog(LOG_DEBUG, "cdev %s -> trip:%lu: 0x%lx %d\n",
0242 cdev_name, trip_instance,
0243 tzi->trip_binding[cdev_id],
0244 cdev_id);
0245
0246
0247 }
0248 return 0;
0249 }
0250
0251 return -ENODEV;
0252 }
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280 static int scan_tzones(void)
0281 {
0282 DIR *dir;
0283 struct dirent **namelist;
0284 char tz_name[256];
0285 int i, j, n, k = 0;
0286
0287 if (!ptdata.nr_tz_sensor)
0288 return -1;
0289
0290 for (i = 0; i <= ptdata.max_tz_instance; i++) {
0291 memset(tz_name, 0, sizeof(tz_name));
0292 snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE, i);
0293
0294 dir = opendir(tz_name);
0295 if (!dir) {
0296 syslog(LOG_INFO, "Thermal zone %s skipped\n", tz_name);
0297 continue;
0298 }
0299
0300 n = scandir(tz_name, &namelist, 0, alphasort);
0301 if (n < 0)
0302 syslog(LOG_ERR, "scandir failed in %s", tz_name);
0303 else {
0304 sysfs_get_string(tz_name, "type", ptdata.tzi[k].type);
0305 ptdata.tzi[k].instance = i;
0306
0307 j = 0;
0308 ptdata.tzi[k].nr_cdev = 0;
0309 ptdata.tzi[k].nr_trip_pts = 0;
0310 while (n--) {
0311 char *temp_str;
0312
0313 if (find_tzone_tp(tz_name, namelist[n]->d_name,
0314 &ptdata.tzi[k], k))
0315 break;
0316 temp_str = strstr(namelist[n]->d_name, "cdev");
0317 if (!temp_str) {
0318 free(namelist[n]);
0319 continue;
0320 }
0321 if (!find_tzone_cdev(namelist[n], tz_name,
0322 &ptdata.tzi[k], i, j))
0323 j++;
0324 free(namelist[n]);
0325 }
0326 free(namelist);
0327 }
0328
0329 closedir(dir);
0330 syslog(LOG_INFO, "TZ %d has %d cdev\n", i,
0331 ptdata.tzi[k].nr_cdev);
0332 k++;
0333 }
0334
0335 return 0;
0336 }
0337
0338 static int scan_cdevs(void)
0339 {
0340 DIR *dir;
0341 struct dirent **namelist;
0342 char cdev_name[256];
0343 int i, n, k = 0;
0344
0345 if (!ptdata.nr_cooling_dev) {
0346 fprintf(stderr, "No cooling devices found\n");
0347 return 0;
0348 }
0349 for (i = 0; i <= ptdata.max_cdev_instance; i++) {
0350 memset(cdev_name, 0, sizeof(cdev_name));
0351 snprintf(cdev_name, 256, "%s/%s%d", THERMAL_SYSFS, CDEV, i);
0352
0353 dir = opendir(cdev_name);
0354 if (!dir) {
0355 syslog(LOG_INFO, "Cooling dev %s skipped\n", cdev_name);
0356
0357
0358
0359 continue;
0360 }
0361
0362 n = scandir(cdev_name, &namelist, 0, alphasort);
0363 if (n < 0)
0364 syslog(LOG_ERR, "scandir failed in %s", cdev_name);
0365 else {
0366 sysfs_get_string(cdev_name, "type", ptdata.cdi[k].type);
0367 ptdata.cdi[k].instance = i;
0368 if (strstr(ptdata.cdi[k].type, ctrl_cdev)) {
0369 ptdata.cdi[k].flag |= CDEV_FLAG_IN_CONTROL;
0370 syslog(LOG_DEBUG, "control cdev id %d\n", i);
0371 }
0372 while (n--)
0373 free(namelist[n]);
0374 free(namelist);
0375 }
0376 closedir(dir);
0377 k++;
0378 }
0379 return 0;
0380 }
0381
0382
0383 int probe_thermal_sysfs(void)
0384 {
0385 DIR *dir;
0386 struct dirent **namelist;
0387 int n;
0388
0389 dir = opendir(THERMAL_SYSFS);
0390 if (!dir) {
0391 fprintf(stderr, "\nNo thermal sysfs, exit\n");
0392 return -1;
0393 }
0394 n = scandir(THERMAL_SYSFS, &namelist, 0, alphasort);
0395 if (n < 0)
0396 syslog(LOG_ERR, "scandir failed in thermal sysfs");
0397 else {
0398
0399 while (n--) {
0400 int inst;
0401
0402 if (strstr(namelist[n]->d_name, CDEV)) {
0403 inst = get_instance_id(namelist[n]->d_name, 1,
0404 sizeof("device") - 1);
0405
0406
0407
0408 if (inst > ptdata.max_cdev_instance)
0409 ptdata.max_cdev_instance = inst;
0410
0411 syslog(LOG_DEBUG, "found cdev: %s %d %d\n",
0412 namelist[n]->d_name,
0413 ptdata.nr_cooling_dev,
0414 ptdata.max_cdev_instance);
0415 ptdata.nr_cooling_dev++;
0416 } else if (strstr(namelist[n]->d_name, TZONE)) {
0417 inst = get_instance_id(namelist[n]->d_name, 1,
0418 sizeof("zone") - 1);
0419 if (inst > ptdata.max_tz_instance)
0420 ptdata.max_tz_instance = inst;
0421
0422 syslog(LOG_DEBUG, "found tzone: %s %d %d\n",
0423 namelist[n]->d_name,
0424 ptdata.nr_tz_sensor,
0425 ptdata.max_tz_instance);
0426 ptdata.nr_tz_sensor++;
0427 }
0428 free(namelist[n]);
0429 }
0430 free(namelist);
0431 }
0432 syslog(LOG_INFO, "found %d tzone(s), %d cdev(s), target zone %d\n",
0433 ptdata.nr_tz_sensor, ptdata.nr_cooling_dev,
0434 target_thermal_zone);
0435 closedir(dir);
0436
0437 if (!ptdata.nr_tz_sensor) {
0438 fprintf(stderr, "\nNo thermal zones found, exit\n\n");
0439 return -1;
0440 }
0441
0442 ptdata.tzi = calloc(ptdata.max_tz_instance+1, sizeof(struct tz_info));
0443 if (!ptdata.tzi) {
0444 fprintf(stderr, "Err: allocate tz_info\n");
0445 return -1;
0446 }
0447
0448
0449 if (ptdata.nr_cooling_dev) {
0450 ptdata.cdi = calloc(ptdata.max_cdev_instance + 1,
0451 sizeof(struct cdev_info));
0452 if (!ptdata.cdi) {
0453 free(ptdata.tzi);
0454 fprintf(stderr, "Err: allocate cdev_info\n");
0455 return -1;
0456 }
0457 }
0458
0459
0460 if (scan_tzones())
0461 return -1;
0462 if (scan_cdevs())
0463 return -1;
0464 return 0;
0465 }
0466
0467
0468 int zone_instance_to_index(int zone_inst)
0469 {
0470 int i;
0471
0472 for (i = 0; i < ptdata.nr_tz_sensor; i++)
0473 if (ptdata.tzi[i].instance == zone_inst)
0474 return i;
0475 return -ENOENT;
0476 }
0477
0478
0479 int update_thermal_data()
0480 {
0481 int i;
0482 int next_thermal_record = cur_thermal_record + 1;
0483 char tz_name[256];
0484 static unsigned long samples;
0485
0486 if (!ptdata.nr_tz_sensor) {
0487 syslog(LOG_ERR, "No thermal zones found!\n");
0488 return -1;
0489 }
0490
0491
0492 if (next_thermal_record >= NR_THERMAL_RECORDS)
0493 next_thermal_record = 0;
0494 gettimeofday(&trec[next_thermal_record].tv, NULL);
0495 if (tmon_log) {
0496 fprintf(tmon_log, "%lu ", ++samples);
0497 fprintf(tmon_log, "%3.1f ", p_param.t_target);
0498 }
0499 for (i = 0; i < ptdata.nr_tz_sensor; i++) {
0500 memset(tz_name, 0, sizeof(tz_name));
0501 snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE,
0502 ptdata.tzi[i].instance);
0503 sysfs_get_ulong(tz_name, "temp",
0504 &trec[next_thermal_record].temp[i]);
0505 if (tmon_log)
0506 fprintf(tmon_log, "%lu ",
0507 trec[next_thermal_record].temp[i] / 1000);
0508 }
0509 cur_thermal_record = next_thermal_record;
0510 for (i = 0; i < ptdata.nr_cooling_dev; i++) {
0511 char cdev_name[256];
0512 unsigned long val;
0513
0514 snprintf(cdev_name, 256, "%s/%s%d", THERMAL_SYSFS, CDEV,
0515 ptdata.cdi[i].instance);
0516 probe_cdev(&ptdata.cdi[i], cdev_name);
0517 val = ptdata.cdi[i].cur_state;
0518 if (val > 1000000)
0519 val = 0;
0520 if (tmon_log)
0521 fprintf(tmon_log, "%lu ", val);
0522 }
0523
0524 if (tmon_log) {
0525 fprintf(tmon_log, "\n");
0526 fflush(tmon_log);
0527 }
0528
0529 return 0;
0530 }
0531
0532 void set_ctrl_state(unsigned long state)
0533 {
0534 char ctrl_cdev_path[256];
0535 int i;
0536 unsigned long cdev_state;
0537
0538 if (no_control)
0539 return;
0540
0541 for (i = 0; i < ptdata.nr_cooling_dev; i++) {
0542 if (ptdata.cdi[i].flag & CDEV_FLAG_IN_CONTROL) {
0543 if (ptdata.cdi[i].max_state < 10) {
0544 strcpy(ctrl_cdev, "None.");
0545 return;
0546 }
0547
0548 cdev_state = state * ptdata.cdi[i].max_state/100;
0549 syslog(LOG_DEBUG,
0550 "ctrl cdev %d set state %lu scaled to %lu\n",
0551 ptdata.cdi[i].instance, state, cdev_state);
0552 snprintf(ctrl_cdev_path, 256, "%s/%s%d", THERMAL_SYSFS,
0553 CDEV, ptdata.cdi[i].instance);
0554 syslog(LOG_DEBUG, "ctrl cdev path %s", ctrl_cdev_path);
0555 sysfs_set_ulong(ctrl_cdev_path, "cur_state",
0556 cdev_state);
0557 }
0558 }
0559 }
0560
0561 void get_ctrl_state(unsigned long *state)
0562 {
0563 char ctrl_cdev_path[256];
0564 int ctrl_cdev_id = -1;
0565 int i;
0566
0567
0568
0569
0570 for (i = 0; i < ptdata.nr_cooling_dev; i++) {
0571 if (ptdata.cdi[i].flag & CDEV_FLAG_IN_CONTROL) {
0572 ctrl_cdev_id = ptdata.cdi[i].instance;
0573 syslog(LOG_INFO, "ctrl cdev %d get state\n",
0574 ptdata.cdi[i].instance);
0575 break;
0576 }
0577 }
0578 if (ctrl_cdev_id == -1) {
0579 *state = 0;
0580 return;
0581 }
0582 snprintf(ctrl_cdev_path, 256, "%s/%s%d", THERMAL_SYSFS,
0583 CDEV, ctrl_cdev_id);
0584 sysfs_get_ulong(ctrl_cdev_path, "cur_state", state);
0585 }
0586
0587 void free_thermal_data(void)
0588 {
0589 free(ptdata.tzi);
0590 free(ptdata.cdi);
0591 }