162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * sysfs.c sysfs ABI access functions for TMON program 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2013 Intel Corporation. All rights reserved. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Jacob Pan <jacob.jun.pan@linux.intel.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <unistd.h> 1062306a36Sopenharmony_ci#include <stdio.h> 1162306a36Sopenharmony_ci#include <stdlib.h> 1262306a36Sopenharmony_ci#include <string.h> 1362306a36Sopenharmony_ci#include <stdint.h> 1462306a36Sopenharmony_ci#include <dirent.h> 1562306a36Sopenharmony_ci#include <libintl.h> 1662306a36Sopenharmony_ci#include <limits.h> 1762306a36Sopenharmony_ci#include <ctype.h> 1862306a36Sopenharmony_ci#include <time.h> 1962306a36Sopenharmony_ci#include <syslog.h> 2062306a36Sopenharmony_ci#include <sys/time.h> 2162306a36Sopenharmony_ci#include <errno.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "tmon.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct tmon_platform_data ptdata; 2662306a36Sopenharmony_ciconst char *trip_type_name[] = { 2762306a36Sopenharmony_ci "critical", 2862306a36Sopenharmony_ci "hot", 2962306a36Sopenharmony_ci "passive", 3062306a36Sopenharmony_ci "active", 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ciint sysfs_set_ulong(char *path, char *filename, unsigned long val) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci FILE *fd; 3662306a36Sopenharmony_ci int ret = -1; 3762306a36Sopenharmony_ci char filepath[PATH_MAX + 2]; /* NUL and '/' */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci snprintf(filepath, sizeof(filepath), "%s/%s", path, filename); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci fd = fopen(filepath, "w"); 4262306a36Sopenharmony_ci if (!fd) { 4362306a36Sopenharmony_ci syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath); 4462306a36Sopenharmony_ci return ret; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci ret = fprintf(fd, "%lu", val); 4762306a36Sopenharmony_ci fclose(fd); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci return 0; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* history of thermal data, used for control algo */ 5362306a36Sopenharmony_ci#define NR_THERMAL_RECORDS 3 5462306a36Sopenharmony_cistruct thermal_data_record trec[NR_THERMAL_RECORDS]; 5562306a36Sopenharmony_ciint cur_thermal_record; /* index to the trec array */ 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic int sysfs_get_ulong(char *path, char *filename, unsigned long *p_ulong) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci FILE *fd; 6062306a36Sopenharmony_ci int ret = -1; 6162306a36Sopenharmony_ci char filepath[PATH_MAX + 2]; /* NUL and '/' */ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci snprintf(filepath, sizeof(filepath), "%s/%s", path, filename); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci fd = fopen(filepath, "r"); 6662306a36Sopenharmony_ci if (!fd) { 6762306a36Sopenharmony_ci syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath); 6862306a36Sopenharmony_ci return ret; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci ret = fscanf(fd, "%lu", p_ulong); 7162306a36Sopenharmony_ci fclose(fd); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int sysfs_get_string(char *path, char *filename, char *str) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci FILE *fd; 7962306a36Sopenharmony_ci int ret = -1; 8062306a36Sopenharmony_ci char filepath[PATH_MAX + 2]; /* NUL and '/' */ 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci snprintf(filepath, sizeof(filepath), "%s/%s", path, filename); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci fd = fopen(filepath, "r"); 8562306a36Sopenharmony_ci if (!fd) { 8662306a36Sopenharmony_ci syslog(LOG_ERR, "Err: open %s: %s\n", __func__, filepath); 8762306a36Sopenharmony_ci return ret; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci ret = fscanf(fd, "%256s", str); 9062306a36Sopenharmony_ci fclose(fd); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return ret; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* get states of the cooling device instance */ 9662306a36Sopenharmony_cistatic int probe_cdev(struct cdev_info *cdi, char *path) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci sysfs_get_string(path, "type", cdi->type); 9962306a36Sopenharmony_ci sysfs_get_ulong(path, "max_state", &cdi->max_state); 10062306a36Sopenharmony_ci sysfs_get_ulong(path, "cur_state", &cdi->cur_state); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci syslog(LOG_INFO, "%s: %s: type %s, max %lu, curr %lu inst %d\n", 10362306a36Sopenharmony_ci __func__, path, 10462306a36Sopenharmony_ci cdi->type, cdi->max_state, cdi->cur_state, cdi->instance); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return 0; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int str_to_trip_type(char *name) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci int i; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci for (i = 0; i < NR_THERMAL_TRIP_TYPE; i++) { 11462306a36Sopenharmony_ci if (!strcmp(name, trip_type_name[i])) 11562306a36Sopenharmony_ci return i; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return -ENOENT; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* scan and fill in trip point info for a thermal zone and trip point id */ 12262306a36Sopenharmony_cistatic int get_trip_point_data(char *tz_path, int tzid, int tpid) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci char filename[256]; 12562306a36Sopenharmony_ci char temp_str[256]; 12662306a36Sopenharmony_ci int trip_type; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (tpid >= MAX_NR_TRIP) 12962306a36Sopenharmony_ci return -EINVAL; 13062306a36Sopenharmony_ci /* check trip point type */ 13162306a36Sopenharmony_ci snprintf(filename, sizeof(filename), "trip_point_%d_type", tpid); 13262306a36Sopenharmony_ci sysfs_get_string(tz_path, filename, temp_str); 13362306a36Sopenharmony_ci trip_type = str_to_trip_type(temp_str); 13462306a36Sopenharmony_ci if (trip_type < 0) { 13562306a36Sopenharmony_ci syslog(LOG_ERR, "%s:%s no matching type\n", __func__, temp_str); 13662306a36Sopenharmony_ci return -ENOENT; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci ptdata.tzi[tzid].tp[tpid].type = trip_type; 13962306a36Sopenharmony_ci syslog(LOG_INFO, "%s:tz:%d tp:%d:type:%s type id %d\n", __func__, tzid, 14062306a36Sopenharmony_ci tpid, temp_str, trip_type); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* TODO: check attribute */ 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/* return instance id for file format such as trip_point_4_temp */ 14862306a36Sopenharmony_cistatic int get_instance_id(char *name, int pos, int skip) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci char *ch; 15162306a36Sopenharmony_ci int i = 0; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci ch = strtok(name, "_"); 15462306a36Sopenharmony_ci while (ch != NULL) { 15562306a36Sopenharmony_ci ++i; 15662306a36Sopenharmony_ci syslog(LOG_INFO, "%s:%s:%s:%d", __func__, name, ch, i); 15762306a36Sopenharmony_ci ch = strtok(NULL, "_"); 15862306a36Sopenharmony_ci if (pos == i) 15962306a36Sopenharmony_ci return atol(ch + skip); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return -1; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* Find trip point info of a thermal zone */ 16662306a36Sopenharmony_cistatic int find_tzone_tp(char *tz_name, char *d_name, struct tz_info *tzi, 16762306a36Sopenharmony_ci int tz_id) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci int tp_id; 17062306a36Sopenharmony_ci unsigned long temp_ulong; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (strstr(d_name, "trip_point") && 17362306a36Sopenharmony_ci strstr(d_name, "temp")) { 17462306a36Sopenharmony_ci /* check if trip point temp is non-zero 17562306a36Sopenharmony_ci * ignore 0/invalid trip points 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci sysfs_get_ulong(tz_name, d_name, &temp_ulong); 17862306a36Sopenharmony_ci if (temp_ulong < MAX_TEMP_KC) { 17962306a36Sopenharmony_ci tzi->nr_trip_pts++; 18062306a36Sopenharmony_ci /* found a valid trip point */ 18162306a36Sopenharmony_ci tp_id = get_instance_id(d_name, 2, 0); 18262306a36Sopenharmony_ci syslog(LOG_DEBUG, "tzone %s trip %d temp %lu tpnode %s", 18362306a36Sopenharmony_ci tz_name, tp_id, temp_ulong, d_name); 18462306a36Sopenharmony_ci if (tp_id < 0 || tp_id >= MAX_NR_TRIP) { 18562306a36Sopenharmony_ci syslog(LOG_ERR, "Failed to find TP inst %s\n", 18662306a36Sopenharmony_ci d_name); 18762306a36Sopenharmony_ci return -1; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci get_trip_point_data(tz_name, tz_id, tp_id); 19062306a36Sopenharmony_ci tzi->tp[tp_id].temp = temp_ulong; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* check cooling devices for binding info. */ 19862306a36Sopenharmony_cistatic int find_tzone_cdev(struct dirent *nl, char *tz_name, 19962306a36Sopenharmony_ci struct tz_info *tzi, int tz_id, int cid) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci unsigned long trip_instance = 0; 20262306a36Sopenharmony_ci char cdev_name_linked[256]; 20362306a36Sopenharmony_ci char cdev_name[PATH_MAX]; 20462306a36Sopenharmony_ci char cdev_trip_name[PATH_MAX]; 20562306a36Sopenharmony_ci int cdev_id; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (nl->d_type == DT_LNK) { 20862306a36Sopenharmony_ci syslog(LOG_DEBUG, "TZ%d: cdev: %s cid %d\n", tz_id, nl->d_name, 20962306a36Sopenharmony_ci cid); 21062306a36Sopenharmony_ci tzi->nr_cdev++; 21162306a36Sopenharmony_ci if (tzi->nr_cdev > ptdata.nr_cooling_dev) { 21262306a36Sopenharmony_ci syslog(LOG_ERR, "Err: Too many cdev? %d\n", 21362306a36Sopenharmony_ci tzi->nr_cdev); 21462306a36Sopenharmony_ci return -EINVAL; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci /* find the link to real cooling device record binding */ 21762306a36Sopenharmony_ci snprintf(cdev_name, sizeof(cdev_name) - 2, "%s/%s", 21862306a36Sopenharmony_ci tz_name, nl->d_name); 21962306a36Sopenharmony_ci memset(cdev_name_linked, 0, sizeof(cdev_name_linked)); 22062306a36Sopenharmony_ci if (readlink(cdev_name, cdev_name_linked, 22162306a36Sopenharmony_ci sizeof(cdev_name_linked) - 1) != -1) { 22262306a36Sopenharmony_ci cdev_id = get_instance_id(cdev_name_linked, 1, 22362306a36Sopenharmony_ci sizeof("device") - 1); 22462306a36Sopenharmony_ci syslog(LOG_DEBUG, "cdev %s linked to %s : %d\n", 22562306a36Sopenharmony_ci cdev_name, cdev_name_linked, cdev_id); 22662306a36Sopenharmony_ci tzi->cdev_binding |= (1 << cdev_id); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* find the trip point in which the cdev is binded to 22962306a36Sopenharmony_ci * in this tzone 23062306a36Sopenharmony_ci */ 23162306a36Sopenharmony_ci snprintf(cdev_trip_name, sizeof(cdev_trip_name) - 1, 23262306a36Sopenharmony_ci "%s%s", nl->d_name, "_trip_point"); 23362306a36Sopenharmony_ci sysfs_get_ulong(tz_name, cdev_trip_name, 23462306a36Sopenharmony_ci &trip_instance); 23562306a36Sopenharmony_ci /* validate trip point range, e.g. trip could return -1 23662306a36Sopenharmony_ci * when passive is enabled 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci if (trip_instance > MAX_NR_TRIP) 23962306a36Sopenharmony_ci trip_instance = 0; 24062306a36Sopenharmony_ci tzi->trip_binding[cdev_id] |= 1 << trip_instance; 24162306a36Sopenharmony_ci syslog(LOG_DEBUG, "cdev %s -> trip:%lu: 0x%lx %d\n", 24262306a36Sopenharmony_ci cdev_name, trip_instance, 24362306a36Sopenharmony_ci tzi->trip_binding[cdev_id], 24462306a36Sopenharmony_ci cdev_id); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return -ENODEV; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/***************************************************************************** 25762306a36Sopenharmony_ci * Before calling scan_tzones, thermal sysfs must be probed to determine 25862306a36Sopenharmony_ci * the number of thermal zones and cooling devices. 25962306a36Sopenharmony_ci * We loop through each thermal zone and fill in tz_info struct, i.e. 26062306a36Sopenharmony_ci * ptdata.tzi[] 26162306a36Sopenharmony_ciroot@jacob-chiefriver:~# tree -d /sys/class/thermal/thermal_zone0 26262306a36Sopenharmony_ci/sys/class/thermal/thermal_zone0 26362306a36Sopenharmony_ci|-- cdev0 -> ../cooling_device4 26462306a36Sopenharmony_ci|-- cdev1 -> ../cooling_device3 26562306a36Sopenharmony_ci|-- cdev10 -> ../cooling_device7 26662306a36Sopenharmony_ci|-- cdev11 -> ../cooling_device6 26762306a36Sopenharmony_ci|-- cdev12 -> ../cooling_device5 26862306a36Sopenharmony_ci|-- cdev2 -> ../cooling_device2 26962306a36Sopenharmony_ci|-- cdev3 -> ../cooling_device1 27062306a36Sopenharmony_ci|-- cdev4 -> ../cooling_device0 27162306a36Sopenharmony_ci|-- cdev5 -> ../cooling_device12 27262306a36Sopenharmony_ci|-- cdev6 -> ../cooling_device11 27362306a36Sopenharmony_ci|-- cdev7 -> ../cooling_device10 27462306a36Sopenharmony_ci|-- cdev8 -> ../cooling_device9 27562306a36Sopenharmony_ci|-- cdev9 -> ../cooling_device8 27662306a36Sopenharmony_ci|-- device -> ../../../LNXSYSTM:00/device:62/LNXTHERM:00 27762306a36Sopenharmony_ci|-- power 27862306a36Sopenharmony_ci`-- subsystem -> ../../../../class/thermal 27962306a36Sopenharmony_ci*****************************************************************************/ 28062306a36Sopenharmony_cistatic int scan_tzones(void) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci DIR *dir; 28362306a36Sopenharmony_ci struct dirent **namelist; 28462306a36Sopenharmony_ci char tz_name[256]; 28562306a36Sopenharmony_ci int i, j, n, k = 0; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (!ptdata.nr_tz_sensor) 28862306a36Sopenharmony_ci return -1; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci for (i = 0; i <= ptdata.max_tz_instance; i++) { 29162306a36Sopenharmony_ci memset(tz_name, 0, sizeof(tz_name)); 29262306a36Sopenharmony_ci snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE, i); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci dir = opendir(tz_name); 29562306a36Sopenharmony_ci if (!dir) { 29662306a36Sopenharmony_ci syslog(LOG_INFO, "Thermal zone %s skipped\n", tz_name); 29762306a36Sopenharmony_ci continue; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci /* keep track of valid tzones */ 30062306a36Sopenharmony_ci n = scandir(tz_name, &namelist, 0, alphasort); 30162306a36Sopenharmony_ci if (n < 0) 30262306a36Sopenharmony_ci syslog(LOG_ERR, "scandir failed in %s", tz_name); 30362306a36Sopenharmony_ci else { 30462306a36Sopenharmony_ci sysfs_get_string(tz_name, "type", ptdata.tzi[k].type); 30562306a36Sopenharmony_ci ptdata.tzi[k].instance = i; 30662306a36Sopenharmony_ci /* detect trip points and cdev attached to this tzone */ 30762306a36Sopenharmony_ci j = 0; /* index for cdev */ 30862306a36Sopenharmony_ci ptdata.tzi[k].nr_cdev = 0; 30962306a36Sopenharmony_ci ptdata.tzi[k].nr_trip_pts = 0; 31062306a36Sopenharmony_ci while (n--) { 31162306a36Sopenharmony_ci char *temp_str; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (find_tzone_tp(tz_name, namelist[n]->d_name, 31462306a36Sopenharmony_ci &ptdata.tzi[k], k)) 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci temp_str = strstr(namelist[n]->d_name, "cdev"); 31762306a36Sopenharmony_ci if (!temp_str) { 31862306a36Sopenharmony_ci free(namelist[n]); 31962306a36Sopenharmony_ci continue; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci if (!find_tzone_cdev(namelist[n], tz_name, 32262306a36Sopenharmony_ci &ptdata.tzi[k], i, j)) 32362306a36Sopenharmony_ci j++; /* increment cdev index */ 32462306a36Sopenharmony_ci free(namelist[n]); 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci free(namelist); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci /*TODO: reverse trip points */ 32962306a36Sopenharmony_ci closedir(dir); 33062306a36Sopenharmony_ci syslog(LOG_INFO, "TZ %d has %d cdev\n", i, 33162306a36Sopenharmony_ci ptdata.tzi[k].nr_cdev); 33262306a36Sopenharmony_ci k++; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci return 0; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic int scan_cdevs(void) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci DIR *dir; 34162306a36Sopenharmony_ci struct dirent **namelist; 34262306a36Sopenharmony_ci char cdev_name[256]; 34362306a36Sopenharmony_ci int i, n, k = 0; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (!ptdata.nr_cooling_dev) { 34662306a36Sopenharmony_ci fprintf(stderr, "No cooling devices found\n"); 34762306a36Sopenharmony_ci return 0; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci for (i = 0; i <= ptdata.max_cdev_instance; i++) { 35062306a36Sopenharmony_ci memset(cdev_name, 0, sizeof(cdev_name)); 35162306a36Sopenharmony_ci snprintf(cdev_name, 256, "%s/%s%d", THERMAL_SYSFS, CDEV, i); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci dir = opendir(cdev_name); 35462306a36Sopenharmony_ci if (!dir) { 35562306a36Sopenharmony_ci syslog(LOG_INFO, "Cooling dev %s skipped\n", cdev_name); 35662306a36Sopenharmony_ci /* there is a gap in cooling device id, check again 35762306a36Sopenharmony_ci * for the same index. 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_ci continue; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci n = scandir(cdev_name, &namelist, 0, alphasort); 36362306a36Sopenharmony_ci if (n < 0) 36462306a36Sopenharmony_ci syslog(LOG_ERR, "scandir failed in %s", cdev_name); 36562306a36Sopenharmony_ci else { 36662306a36Sopenharmony_ci sysfs_get_string(cdev_name, "type", ptdata.cdi[k].type); 36762306a36Sopenharmony_ci ptdata.cdi[k].instance = i; 36862306a36Sopenharmony_ci if (strstr(ptdata.cdi[k].type, ctrl_cdev)) { 36962306a36Sopenharmony_ci ptdata.cdi[k].flag |= CDEV_FLAG_IN_CONTROL; 37062306a36Sopenharmony_ci syslog(LOG_DEBUG, "control cdev id %d\n", i); 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci while (n--) 37362306a36Sopenharmony_ci free(namelist[n]); 37462306a36Sopenharmony_ci free(namelist); 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci closedir(dir); 37762306a36Sopenharmony_ci k++; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ciint probe_thermal_sysfs(void) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci DIR *dir; 38662306a36Sopenharmony_ci struct dirent **namelist; 38762306a36Sopenharmony_ci int n; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci dir = opendir(THERMAL_SYSFS); 39062306a36Sopenharmony_ci if (!dir) { 39162306a36Sopenharmony_ci fprintf(stderr, "\nNo thermal sysfs, exit\n"); 39262306a36Sopenharmony_ci return -1; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci n = scandir(THERMAL_SYSFS, &namelist, 0, alphasort); 39562306a36Sopenharmony_ci if (n < 0) 39662306a36Sopenharmony_ci syslog(LOG_ERR, "scandir failed in thermal sysfs"); 39762306a36Sopenharmony_ci else { 39862306a36Sopenharmony_ci /* detect number of thermal zones and cooling devices */ 39962306a36Sopenharmony_ci while (n--) { 40062306a36Sopenharmony_ci int inst; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (strstr(namelist[n]->d_name, CDEV)) { 40362306a36Sopenharmony_ci inst = get_instance_id(namelist[n]->d_name, 1, 40462306a36Sopenharmony_ci sizeof("device") - 1); 40562306a36Sopenharmony_ci /* keep track of the max cooling device since 40662306a36Sopenharmony_ci * there may be gaps. 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_ci if (inst > ptdata.max_cdev_instance) 40962306a36Sopenharmony_ci ptdata.max_cdev_instance = inst; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci syslog(LOG_DEBUG, "found cdev: %s %d %d\n", 41262306a36Sopenharmony_ci namelist[n]->d_name, 41362306a36Sopenharmony_ci ptdata.nr_cooling_dev, 41462306a36Sopenharmony_ci ptdata.max_cdev_instance); 41562306a36Sopenharmony_ci ptdata.nr_cooling_dev++; 41662306a36Sopenharmony_ci } else if (strstr(namelist[n]->d_name, TZONE)) { 41762306a36Sopenharmony_ci inst = get_instance_id(namelist[n]->d_name, 1, 41862306a36Sopenharmony_ci sizeof("zone") - 1); 41962306a36Sopenharmony_ci if (inst > ptdata.max_tz_instance) 42062306a36Sopenharmony_ci ptdata.max_tz_instance = inst; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci syslog(LOG_DEBUG, "found tzone: %s %d %d\n", 42362306a36Sopenharmony_ci namelist[n]->d_name, 42462306a36Sopenharmony_ci ptdata.nr_tz_sensor, 42562306a36Sopenharmony_ci ptdata.max_tz_instance); 42662306a36Sopenharmony_ci ptdata.nr_tz_sensor++; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci free(namelist[n]); 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci free(namelist); 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci syslog(LOG_INFO, "found %d tzone(s), %d cdev(s), target zone %d\n", 43362306a36Sopenharmony_ci ptdata.nr_tz_sensor, ptdata.nr_cooling_dev, 43462306a36Sopenharmony_ci target_thermal_zone); 43562306a36Sopenharmony_ci closedir(dir); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (!ptdata.nr_tz_sensor) { 43862306a36Sopenharmony_ci fprintf(stderr, "\nNo thermal zones found, exit\n\n"); 43962306a36Sopenharmony_ci return -1; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci ptdata.tzi = calloc(ptdata.max_tz_instance+1, sizeof(struct tz_info)); 44362306a36Sopenharmony_ci if (!ptdata.tzi) { 44462306a36Sopenharmony_ci fprintf(stderr, "Err: allocate tz_info\n"); 44562306a36Sopenharmony_ci return -1; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* we still show thermal zone information if there is no cdev */ 44962306a36Sopenharmony_ci if (ptdata.nr_cooling_dev) { 45062306a36Sopenharmony_ci ptdata.cdi = calloc(ptdata.max_cdev_instance + 1, 45162306a36Sopenharmony_ci sizeof(struct cdev_info)); 45262306a36Sopenharmony_ci if (!ptdata.cdi) { 45362306a36Sopenharmony_ci free(ptdata.tzi); 45462306a36Sopenharmony_ci fprintf(stderr, "Err: allocate cdev_info\n"); 45562306a36Sopenharmony_ci return -1; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* now probe tzones */ 46062306a36Sopenharmony_ci if (scan_tzones()) 46162306a36Sopenharmony_ci return -1; 46262306a36Sopenharmony_ci if (scan_cdevs()) 46362306a36Sopenharmony_ci return -1; 46462306a36Sopenharmony_ci return 0; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci/* convert sysfs zone instance to zone array index */ 46862306a36Sopenharmony_ciint zone_instance_to_index(int zone_inst) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci int i; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci for (i = 0; i < ptdata.nr_tz_sensor; i++) 47362306a36Sopenharmony_ci if (ptdata.tzi[i].instance == zone_inst) 47462306a36Sopenharmony_ci return i; 47562306a36Sopenharmony_ci return -ENOENT; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci/* read temperature of all thermal zones */ 47962306a36Sopenharmony_ciint update_thermal_data() 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci int i; 48262306a36Sopenharmony_ci int next_thermal_record = cur_thermal_record + 1; 48362306a36Sopenharmony_ci char tz_name[256]; 48462306a36Sopenharmony_ci static unsigned long samples; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (!ptdata.nr_tz_sensor) { 48762306a36Sopenharmony_ci syslog(LOG_ERR, "No thermal zones found!\n"); 48862306a36Sopenharmony_ci return -1; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* circular buffer for keeping historic data */ 49262306a36Sopenharmony_ci if (next_thermal_record >= NR_THERMAL_RECORDS) 49362306a36Sopenharmony_ci next_thermal_record = 0; 49462306a36Sopenharmony_ci gettimeofday(&trec[next_thermal_record].tv, NULL); 49562306a36Sopenharmony_ci if (tmon_log) { 49662306a36Sopenharmony_ci fprintf(tmon_log, "%lu ", ++samples); 49762306a36Sopenharmony_ci fprintf(tmon_log, "%3.1f ", p_param.t_target); 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci for (i = 0; i < ptdata.nr_tz_sensor; i++) { 50062306a36Sopenharmony_ci memset(tz_name, 0, sizeof(tz_name)); 50162306a36Sopenharmony_ci snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE, 50262306a36Sopenharmony_ci ptdata.tzi[i].instance); 50362306a36Sopenharmony_ci sysfs_get_ulong(tz_name, "temp", 50462306a36Sopenharmony_ci &trec[next_thermal_record].temp[i]); 50562306a36Sopenharmony_ci if (tmon_log) 50662306a36Sopenharmony_ci fprintf(tmon_log, "%lu ", 50762306a36Sopenharmony_ci trec[next_thermal_record].temp[i] / 1000); 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci cur_thermal_record = next_thermal_record; 51062306a36Sopenharmony_ci for (i = 0; i < ptdata.nr_cooling_dev; i++) { 51162306a36Sopenharmony_ci char cdev_name[256]; 51262306a36Sopenharmony_ci unsigned long val; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci snprintf(cdev_name, 256, "%s/%s%d", THERMAL_SYSFS, CDEV, 51562306a36Sopenharmony_ci ptdata.cdi[i].instance); 51662306a36Sopenharmony_ci probe_cdev(&ptdata.cdi[i], cdev_name); 51762306a36Sopenharmony_ci val = ptdata.cdi[i].cur_state; 51862306a36Sopenharmony_ci if (val > 1000000) 51962306a36Sopenharmony_ci val = 0; 52062306a36Sopenharmony_ci if (tmon_log) 52162306a36Sopenharmony_ci fprintf(tmon_log, "%lu ", val); 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (tmon_log) { 52562306a36Sopenharmony_ci fprintf(tmon_log, "\n"); 52662306a36Sopenharmony_ci fflush(tmon_log); 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci return 0; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_civoid set_ctrl_state(unsigned long state) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci char ctrl_cdev_path[256]; 53562306a36Sopenharmony_ci int i; 53662306a36Sopenharmony_ci unsigned long cdev_state; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (no_control) 53962306a36Sopenharmony_ci return; 54062306a36Sopenharmony_ci /* set all ctrl cdev to the same state */ 54162306a36Sopenharmony_ci for (i = 0; i < ptdata.nr_cooling_dev; i++) { 54262306a36Sopenharmony_ci if (ptdata.cdi[i].flag & CDEV_FLAG_IN_CONTROL) { 54362306a36Sopenharmony_ci if (ptdata.cdi[i].max_state < 10) { 54462306a36Sopenharmony_ci strcpy(ctrl_cdev, "None."); 54562306a36Sopenharmony_ci return; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci /* scale to percentage of max_state */ 54862306a36Sopenharmony_ci cdev_state = state * ptdata.cdi[i].max_state/100; 54962306a36Sopenharmony_ci syslog(LOG_DEBUG, 55062306a36Sopenharmony_ci "ctrl cdev %d set state %lu scaled to %lu\n", 55162306a36Sopenharmony_ci ptdata.cdi[i].instance, state, cdev_state); 55262306a36Sopenharmony_ci snprintf(ctrl_cdev_path, 256, "%s/%s%d", THERMAL_SYSFS, 55362306a36Sopenharmony_ci CDEV, ptdata.cdi[i].instance); 55462306a36Sopenharmony_ci syslog(LOG_DEBUG, "ctrl cdev path %s", ctrl_cdev_path); 55562306a36Sopenharmony_ci sysfs_set_ulong(ctrl_cdev_path, "cur_state", 55662306a36Sopenharmony_ci cdev_state); 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_civoid get_ctrl_state(unsigned long *state) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci char ctrl_cdev_path[256]; 56462306a36Sopenharmony_ci int ctrl_cdev_id = -1; 56562306a36Sopenharmony_ci int i; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* TODO: take average of all ctrl types. also consider change based on 56862306a36Sopenharmony_ci * uevent. Take the first reading for now. 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_ci for (i = 0; i < ptdata.nr_cooling_dev; i++) { 57162306a36Sopenharmony_ci if (ptdata.cdi[i].flag & CDEV_FLAG_IN_CONTROL) { 57262306a36Sopenharmony_ci ctrl_cdev_id = ptdata.cdi[i].instance; 57362306a36Sopenharmony_ci syslog(LOG_INFO, "ctrl cdev %d get state\n", 57462306a36Sopenharmony_ci ptdata.cdi[i].instance); 57562306a36Sopenharmony_ci break; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci if (ctrl_cdev_id == -1) { 57962306a36Sopenharmony_ci *state = 0; 58062306a36Sopenharmony_ci return; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci snprintf(ctrl_cdev_path, 256, "%s/%s%d", THERMAL_SYSFS, 58362306a36Sopenharmony_ci CDEV, ctrl_cdev_id); 58462306a36Sopenharmony_ci sysfs_get_ulong(ctrl_cdev_path, "cur_state", state); 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_civoid free_thermal_data(void) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci free(ptdata.tzi); 59062306a36Sopenharmony_ci free(ptdata.cdi); 59162306a36Sopenharmony_ci} 592