1 /*
2  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
3  * Not a contribution
4  * Copyright (C) 2016 The Android Open Source Project
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <dirent.h>
24 
25 #define LOG_TAG "ThermalHAL-UTIL"
26 #include <utils/Log.h>
27 
28 #include <hardware/hardware.h>
29 #include <hardware/thermal.h>
30 #include "thermal_common.h"
31 
32 #define MAX_LENGTH    50
33 #define MAX_PATH      (256)
34 #define CPU_LABEL      "CPU%d"
35 #define THERMAL_SYSFS  "/sys/devices/virtual/thermal"
36 #define TZ_DIR_NAME    "thermal_zone"
37 #define TZ_DIR_FMT     "thermal_zone%d"
38 #define THERMAL_TYPE "/sys/devices/virtual/thermal/%s/type"
39 #define TEMPERATURE_FILE_FORMAT  "/sys/class/thermal/thermal_zone%d/temp"
40 
41 static char **cpu_label;
42 static struct vendor_temperature *sensors;
43 static unsigned int sensor_cnt;
44 
45 /**
46  * Get number of cpus of target.
47  *
48  * @return number of cpus on success or 0 on error.
49  */
get_num_cpus()50 size_t get_num_cpus() {
51     ALOGD("Entering %s",__func__);
52     static int ncpus;
53 
54     if (!ncpus) {
55         ncpus = (int)sysconf(_SC_NPROCESSORS_CONF);
56         if (ncpus < 1)
57             ALOGE("%s: Error retrieving number of cores", __func__);
58     }
59     return ncpus;
60 }
61 
62 /**
63  * Get cpu label for a given cpu.
64  *
65  * @param cpu_num: cpu number.
66  *
67  * @return cpu label string on success or NULL on error.
68  */
get_cpu_label(unsigned int cpu_num)69 const char *get_cpu_label(unsigned int cpu_num) {
70     ALOGD("Entering %s",__func__);
71     unsigned int cpu = 0;
72 
73     if (cpu_label == NULL) {
74         cpu_label= (char**)calloc(get_num_cpus(), sizeof(char *));
75 	if (!cpu_label)
76 		return NULL;
77 	for(cpu = 0; cpu < get_num_cpus(); cpu++) {
78             cpu_label[cpu] = (char *)calloc(sizeof("CPUN"), sizeof(char));
79             if(!cpu_label[cpu])
80                 return NULL;
81             snprintf(cpu_label[cpu], sizeof("CPUN"), CPU_LABEL, cpu);
82 	}
83     }
84     if(cpu_num >= get_num_cpus())
85         return NULL;
86 
87     return cpu_label[cpu_num];
88 }
89 
90 /**
91  * Read data from a target sysfs file.
92  *
93  * @param path: Absolute path for a file to be read.
94  * @param buf: Char buffer to store data from file.
95  * @param count: Size of data buffer.
96  *
97  * @return number of bytes read on success or negative value on error.
98  */
read_line_from_file(const char * path,char * buf,size_t count)99 int read_line_from_file(const char *path, char *buf, size_t count)
100 {
101     char * fgets_ret;
102     FILE * fd;
103     int rv;
104 
105     fd = fopen(path, "r");
106     if (fd == NULL)
107         return -1;
108 
109     fgets_ret = fgets(buf, (int)count, fd);
110     if (NULL != fgets_ret) {
111         rv = (int)strlen(buf);
112     } else {
113         rv = ferror(fd);
114     }
115 
116     fclose(fd);
117 
118     return rv;
119 }
120 
121 /**
122  * Function to get thermal zone id from sensor name.
123  *
124  * @param sensor_name: Name of sensor.
125  *
126  * @return positive integer on success or negative value on error.
127  */
get_tzn(const char * sensor_name)128 static int get_tzn(const char *sensor_name)
129 {
130     DIR *tdir = NULL;
131     struct dirent *tdirent = NULL;
132     int found = -1;
133     int tzn = 0;
134     char name[MAX_PATH] = {0};
135     char cwd[MAX_PATH] = {0};
136     int ret = 0;
137 
138     if (!getcwd(cwd, sizeof(cwd)))
139         return found;
140 
141     /* Change dir to read the entries. Doesnt work otherwise */
142     ret = chdir(THERMAL_SYSFS);
143     if (ret) {
144         ALOGE("Unable to change to %s\n", THERMAL_SYSFS);
145         return found;
146     }
147     tdir = opendir(THERMAL_SYSFS);
148     if (!tdir) {
149         ALOGE("Unable to open %s\n", THERMAL_SYSFS);
150         return found;
151     }
152 
153     while ((tdirent = readdir(tdir))) {
154         char buf[50];
155         struct dirent *tzdirent;
156         DIR *tzdir = NULL;
157 
158         if (strncmp(tdirent->d_name, TZ_DIR_NAME,
159             strlen(TZ_DIR_NAME)) != 0)
160             continue;
161 
162         tzdir = opendir(tdirent->d_name);
163         if (!tzdir)
164             continue;
165         while ((tzdirent = readdir(tzdir))) {
166             if (strcmp(tzdirent->d_name, "type"))
167                 continue;
168             snprintf(name, MAX_PATH, THERMAL_TYPE,
169                     tdirent->d_name);
170             ret = read_line_from_file(name, buf, sizeof(buf));
171             if (ret <= 0) {
172                 ALOGE("%s: sensor name read error for tz:%s\n",
173                         __func__, tdirent->d_name);
174                 break;
175             }
176             if (buf[ret - 1] == '\n')
177                 buf[ret - 1] = '\0';
178             else
179                 buf[ret] = '\0';
180 
181             if (!strcmp(buf, sensor_name)) {
182                 found = 1;
183 		break;
184             }
185         }
186         closedir(tzdir);
187         if (found == 1)
188             break;
189     }
190 
191     if (found == 1) {
192         sscanf(tdirent->d_name, TZ_DIR_FMT, &tzn);
193         ALOGD("Sensor %s found at tz: %d\n",
194                 sensor_name, tzn);
195         found = tzn;
196     }
197 
198     closedir(tdir);
199     /* Restore current working dir */
200     ret = chdir(cwd);
201 
202     return found;
203 }
204 
205 /**
206  * Helper function for sensor intialization.
207  *
208  * @param v_sen_t: pointer to a sensor static config.
209  * @param sensor: pointer to a sensor vendor_temperature structure.
210  * @param type: Type of sensor ie cpu, battery, gpu, skin etc.
211  * @param sens_idx: Index for sensor of same type.
212  *
213  * @return 0 on success or negative value -errno on error.
214  */
initialize_sensor(struct target_therm_cfg * v_sen_t,struct vendor_temperature * sensor,enum temperature_type type,int sens_idx)215 static int initialize_sensor(struct target_therm_cfg *v_sen_t,
216                                struct vendor_temperature *sensor,
217                                enum temperature_type type,
218                                int sens_idx)
219 {
220     if (v_sen_t == NULL || sensor == NULL ||
221         sens_idx < 0) {
222          ALOGE("%s:Invalid input, sens_idx%d\n", __func__, sens_idx);
223          return -1;
224     }
225 
226     sensor->tzn = get_tzn(v_sen_t->sensor_list[sens_idx]);
227     if (sensor->tzn < 0) {
228         ALOGE("No thermal zone for sensor: %s, ret:%d\n",
229                v_sen_t->sensor_list[sens_idx], sensor->tzn);
230         return -1;
231     }
232     if (type == DEVICE_TEMPERATURE_CPU)
233         sensor->t.name = get_cpu_label(sens_idx);
234     else
235         sensor->t.name = v_sen_t->label;
236 
237     sensor->t.type = v_sen_t->type;
238     sensor->mult = v_sen_t->mult;
239 
240     if (v_sen_t->throt_thresh != 0)
241         sensor->t.throttling_threshold = v_sen_t->throt_thresh;
242     else
243         sensor->t.throttling_threshold = UNKNOWN_TEMPERATURE;
244 
245     if (v_sen_t->shutdwn_thresh != 0)
246         sensor->t.shutdown_threshold = v_sen_t->shutdwn_thresh;
247     else
248         sensor->t.shutdown_threshold = UNKNOWN_TEMPERATURE;
249 
250     if (v_sen_t->vr_thresh != 0)
251         sensor->t.vr_throttling_threshold = v_sen_t->vr_thresh;
252     else
253         sensor->t.vr_throttling_threshold = UNKNOWN_TEMPERATURE;
254 
255     return 0;
256 }
257 
258 /**
259  * Initialize all sensors.
260  *
261  * @param v_sen_t: Base pointer to array of target specific sensor configs.
262  * @param cfg_cnt: Number of set of config for a given target.
263  *
264  * @return number of sensor on success or negative value or zero on error.
265  */
thermal_zone_init(struct target_therm_cfg * v_sen_t,int cfg_cnt)266 int thermal_zone_init(struct target_therm_cfg *v_sen_t, int cfg_cnt)
267 {
268     unsigned int idx = 0, cpu = 0;
269     int j = 0;
270 
271     if (sensors != NULL && sensor_cnt != 0)
272         return sensor_cnt;
273 
274     if (v_sen_t == NULL || cfg_cnt == 0) {
275         ALOGE("%s:Invalid input\n", __func__);
276         return -1;
277     }
278     sensors = calloc(get_num_cpus() + cfg_cnt - 1,
279         sizeof(struct vendor_temperature));
280 
281     for (j = 0, idx = 0; j < cfg_cnt &&
282                 idx < (get_num_cpus() + cfg_cnt - 1); j++) {
283         if (v_sen_t[j].type == DEVICE_TEMPERATURE_CPU) {
284             /* Initialize cpu thermal zone id */
285             for (cpu = 0; cpu < get_num_cpus() &&
286                         idx < (get_num_cpus() + cfg_cnt - 1); cpu++, idx++) {
287                 if (initialize_sensor(&v_sen_t[j], &sensors[idx],
288                       v_sen_t[j].type, cpu)) {
289                         free(sensors);
290                         return -1;
291                 }
292            }
293         } else {
294             /* Initialize misc thermal zone id */
295             if (initialize_sensor(&v_sen_t[j], &sensors[idx],
296                   v_sen_t[j].type, 0)) {
297                 free(sensors);
298                 return -1;
299             }
300             idx++;
301        }
302     }
303     sensor_cnt = idx;
304 
305     return sensor_cnt;
306 }
307 
308 /**
309  * Reads sensor temperature.
310  *
311  * @param sensor_num: thermal zone id for the sensor to be read
312  * @param type: Device temperature type.
313  * @param name: Device temperature name.
314  * @param mult: Multiplier used to translate temperature to Celsius.
315  * @param throttling_threshold: Throttling threshold for the sensor.
316  * @param shutdown_threshold: Shutdown threshold for the sensor.
317  * @param out: Pointer to temperature_t structure that will be filled with
318  *     temperature values.
319  *
320  * @return 0 on success or negative value -errno on error.
321  */
read_temperature(int sensor_num,int type,const char * name,float mult,float throttling_threshold,float shutdown_threshold,float vr_throttling_threshold,temperature_t * out)322 static ssize_t read_temperature(int sensor_num, int type, const char *name,
323         float mult, float throttling_threshold, float shutdown_threshold,
324         float vr_throttling_threshold,
325         temperature_t *out) {
326     ALOGD("Entering %s",__func__);
327     char file_name[MAX_LENGTH];
328     float temp;
329     char buf[16] = {0};
330     int ret = 0;
331 
332     snprintf(file_name, sizeof(file_name), TEMPERATURE_FILE_FORMAT, sensor_num);
333     ret = read_line_from_file(file_name, buf, sizeof(buf));
334     if (ret <= 0) {
335         ALOGE("Temperature read error: %d for sensor[%d]:%s\n",
336             ret, sensor_num, name);
337 	return -1;
338     }
339     temp = atof(buf);
340 
341     (*out) = (temperature_t) {
342         .type = type,
343         .name = name,
344         .current_value = temp * mult,
345         .throttling_threshold = throttling_threshold,
346         .shutdown_threshold = shutdown_threshold,
347         .vr_throttling_threshold = vr_throttling_threshold
348     };
349 
350     return 0;
351 }
352 
353 /**
354  * Reads all sensor temperature.
355  *
356  * @param list: Base pointer to array of temperature_t structure that will be
357  *     filled with temperature values.
358  * @param size: Number of sensor temperature needs to be filled in list.
359  *
360  * @return number of sensor data filled on success or 0 or negative value
361  *     -errno on error.
362  */
get_temperature_for_all(temperature_t * list,size_t size)363 ssize_t get_temperature_for_all(temperature_t *list, size_t size)
364 {
365     ALOGD("Entering %s",__func__);
366     size_t idx;
367 
368     if (sensors == NULL) {
369         ALOGE("No sensor configured\n");
370 	return 0;
371     }
372 
373     for (idx = 0; idx < sensor_cnt && idx < size; idx++) {
374         ssize_t result = read_temperature(sensors[idx].tzn, sensors[idx].t.type,
375                 sensors[idx].t.name, sensors[idx].mult,
376                 sensors[idx].t.throttling_threshold,
377                 sensors[idx].t.shutdown_threshold,
378                 sensors[idx].t.vr_throttling_threshold,
379                 &list[idx]);
380         if (result != 0)
381             return result;
382     }
383     return idx;
384 }
385 
386