18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <stdio.h> 88c2ecf20Sopenharmony_ci#include <errno.h> 98c2ecf20Sopenharmony_ci#include <stdlib.h> 108c2ecf20Sopenharmony_ci#include <string.h> 118c2ecf20Sopenharmony_ci#include <sys/types.h> 128c2ecf20Sopenharmony_ci#include <sys/stat.h> 138c2ecf20Sopenharmony_ci#include <fcntl.h> 148c2ecf20Sopenharmony_ci#include <unistd.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "cpufreq.h" 178c2ecf20Sopenharmony_ci#include "cpupower_intern.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* CPUFREQ sysfs access **************************************************/ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* helper function to read file from /sys into given buffer */ 228c2ecf20Sopenharmony_ci/* fname is a relative path under "cpuX/cpufreq" dir */ 238c2ecf20Sopenharmony_cistatic unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname, 248c2ecf20Sopenharmony_ci char *buf, size_t buflen) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci char path[SYSFS_PATH_MAX]; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", 298c2ecf20Sopenharmony_ci cpu, fname); 308c2ecf20Sopenharmony_ci return cpupower_read_sysfs(path, buf, buflen); 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* helper function to write a new value to a /sys file */ 348c2ecf20Sopenharmony_ci/* fname is a relative path under "cpuX/cpufreq" dir */ 358c2ecf20Sopenharmony_cistatic unsigned int sysfs_cpufreq_write_file(unsigned int cpu, 368c2ecf20Sopenharmony_ci const char *fname, 378c2ecf20Sopenharmony_ci const char *value, size_t len) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci char path[SYSFS_PATH_MAX]; 408c2ecf20Sopenharmony_ci int fd; 418c2ecf20Sopenharmony_ci ssize_t numwrite; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", 448c2ecf20Sopenharmony_ci cpu, fname); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci fd = open(path, O_WRONLY); 478c2ecf20Sopenharmony_ci if (fd == -1) 488c2ecf20Sopenharmony_ci return 0; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci numwrite = write(fd, value, len); 518c2ecf20Sopenharmony_ci if (numwrite < 1) { 528c2ecf20Sopenharmony_ci close(fd); 538c2ecf20Sopenharmony_ci return 0; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci close(fd); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci return (unsigned int) numwrite; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* read access to files which contain one numeric value */ 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cienum cpufreq_value { 648c2ecf20Sopenharmony_ci CPUINFO_CUR_FREQ, 658c2ecf20Sopenharmony_ci CPUINFO_MIN_FREQ, 668c2ecf20Sopenharmony_ci CPUINFO_MAX_FREQ, 678c2ecf20Sopenharmony_ci CPUINFO_LATENCY, 688c2ecf20Sopenharmony_ci SCALING_CUR_FREQ, 698c2ecf20Sopenharmony_ci SCALING_MIN_FREQ, 708c2ecf20Sopenharmony_ci SCALING_MAX_FREQ, 718c2ecf20Sopenharmony_ci STATS_NUM_TRANSITIONS, 728c2ecf20Sopenharmony_ci MAX_CPUFREQ_VALUE_READ_FILES 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = { 768c2ecf20Sopenharmony_ci [CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq", 778c2ecf20Sopenharmony_ci [CPUINFO_MIN_FREQ] = "cpuinfo_min_freq", 788c2ecf20Sopenharmony_ci [CPUINFO_MAX_FREQ] = "cpuinfo_max_freq", 798c2ecf20Sopenharmony_ci [CPUINFO_LATENCY] = "cpuinfo_transition_latency", 808c2ecf20Sopenharmony_ci [SCALING_CUR_FREQ] = "scaling_cur_freq", 818c2ecf20Sopenharmony_ci [SCALING_MIN_FREQ] = "scaling_min_freq", 828c2ecf20Sopenharmony_ci [SCALING_MAX_FREQ] = "scaling_max_freq", 838c2ecf20Sopenharmony_ci [STATS_NUM_TRANSITIONS] = "stats/total_trans" 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu, 888c2ecf20Sopenharmony_ci enum cpufreq_value which) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci unsigned long value; 918c2ecf20Sopenharmony_ci unsigned int len; 928c2ecf20Sopenharmony_ci char linebuf[MAX_LINE_LEN]; 938c2ecf20Sopenharmony_ci char *endp; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (which >= MAX_CPUFREQ_VALUE_READ_FILES) 968c2ecf20Sopenharmony_ci return 0; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which], 998c2ecf20Sopenharmony_ci linebuf, sizeof(linebuf)); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (len == 0) 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci value = strtoul(linebuf, &endp, 0); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (endp == linebuf || errno == ERANGE) 1078c2ecf20Sopenharmony_ci return 0; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return value; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* read access to files which contain one string */ 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cienum cpufreq_string { 1158c2ecf20Sopenharmony_ci SCALING_DRIVER, 1168c2ecf20Sopenharmony_ci SCALING_GOVERNOR, 1178c2ecf20Sopenharmony_ci MAX_CPUFREQ_STRING_FILES 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = { 1218c2ecf20Sopenharmony_ci [SCALING_DRIVER] = "scaling_driver", 1228c2ecf20Sopenharmony_ci [SCALING_GOVERNOR] = "scaling_governor", 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic char *sysfs_cpufreq_get_one_string(unsigned int cpu, 1278c2ecf20Sopenharmony_ci enum cpufreq_string which) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci char linebuf[MAX_LINE_LEN]; 1308c2ecf20Sopenharmony_ci char *result; 1318c2ecf20Sopenharmony_ci unsigned int len; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (which >= MAX_CPUFREQ_STRING_FILES) 1348c2ecf20Sopenharmony_ci return NULL; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which], 1378c2ecf20Sopenharmony_ci linebuf, sizeof(linebuf)); 1388c2ecf20Sopenharmony_ci if (len == 0) 1398c2ecf20Sopenharmony_ci return NULL; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci result = strdup(linebuf); 1428c2ecf20Sopenharmony_ci if (result == NULL) 1438c2ecf20Sopenharmony_ci return NULL; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (result[strlen(result) - 1] == '\n') 1468c2ecf20Sopenharmony_ci result[strlen(result) - 1] = '\0'; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return result; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* write access */ 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cienum cpufreq_write { 1548c2ecf20Sopenharmony_ci WRITE_SCALING_MIN_FREQ, 1558c2ecf20Sopenharmony_ci WRITE_SCALING_MAX_FREQ, 1568c2ecf20Sopenharmony_ci WRITE_SCALING_GOVERNOR, 1578c2ecf20Sopenharmony_ci WRITE_SCALING_SET_SPEED, 1588c2ecf20Sopenharmony_ci MAX_CPUFREQ_WRITE_FILES 1598c2ecf20Sopenharmony_ci}; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = { 1628c2ecf20Sopenharmony_ci [WRITE_SCALING_MIN_FREQ] = "scaling_min_freq", 1638c2ecf20Sopenharmony_ci [WRITE_SCALING_MAX_FREQ] = "scaling_max_freq", 1648c2ecf20Sopenharmony_ci [WRITE_SCALING_GOVERNOR] = "scaling_governor", 1658c2ecf20Sopenharmony_ci [WRITE_SCALING_SET_SPEED] = "scaling_setspeed", 1668c2ecf20Sopenharmony_ci}; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int sysfs_cpufreq_write_one_value(unsigned int cpu, 1698c2ecf20Sopenharmony_ci enum cpufreq_write which, 1708c2ecf20Sopenharmony_ci const char *new_value, size_t len) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci if (which >= MAX_CPUFREQ_WRITE_FILES) 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which], 1768c2ecf20Sopenharmony_ci new_value, len) != len) 1778c2ecf20Sopenharmony_ci return -ENODEV; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci}; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciunsigned long cpufreq_get_freq_kernel(unsigned int cpu) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ciunsigned long cpufreq_get_freq_hardware(unsigned int cpu) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ciunsigned long cpufreq_get_transition_latency(unsigned int cpu) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ciint cpufreq_get_hardware_limits(unsigned int cpu, 1988c2ecf20Sopenharmony_ci unsigned long *min, 1998c2ecf20Sopenharmony_ci unsigned long *max) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci if ((!min) || (!max)) 2028c2ecf20Sopenharmony_ci return -EINVAL; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci *min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ); 2058c2ecf20Sopenharmony_ci if (!*min) 2068c2ecf20Sopenharmony_ci return -ENODEV; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci *max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ); 2098c2ecf20Sopenharmony_ci if (!*max) 2108c2ecf20Sopenharmony_ci return -ENODEV; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cichar *cpufreq_get_driver(unsigned int cpu) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_civoid cpufreq_put_driver(char *ptr) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci if (!ptr) 2238c2ecf20Sopenharmony_ci return; 2248c2ecf20Sopenharmony_ci free(ptr); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistruct cpufreq_policy *cpufreq_get_policy(unsigned int cpu) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci struct cpufreq_policy *policy; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci policy = malloc(sizeof(struct cpufreq_policy)); 2328c2ecf20Sopenharmony_ci if (!policy) 2338c2ecf20Sopenharmony_ci return NULL; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR); 2368c2ecf20Sopenharmony_ci if (!policy->governor) { 2378c2ecf20Sopenharmony_ci free(policy); 2388c2ecf20Sopenharmony_ci return NULL; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); 2418c2ecf20Sopenharmony_ci policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ); 2428c2ecf20Sopenharmony_ci if ((!policy->min) || (!policy->max)) { 2438c2ecf20Sopenharmony_ci free(policy->governor); 2448c2ecf20Sopenharmony_ci free(policy); 2458c2ecf20Sopenharmony_ci return NULL; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return policy; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_civoid cpufreq_put_policy(struct cpufreq_policy *policy) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci if ((!policy) || (!policy->governor)) 2548c2ecf20Sopenharmony_ci return; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci free(policy->governor); 2578c2ecf20Sopenharmony_ci policy->governor = NULL; 2588c2ecf20Sopenharmony_ci free(policy); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistruct cpufreq_available_governors *cpufreq_get_available_governors(unsigned 2628c2ecf20Sopenharmony_ci int cpu) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct cpufreq_available_governors *first = NULL; 2658c2ecf20Sopenharmony_ci struct cpufreq_available_governors *current = NULL; 2668c2ecf20Sopenharmony_ci char linebuf[MAX_LINE_LEN]; 2678c2ecf20Sopenharmony_ci unsigned int pos, i; 2688c2ecf20Sopenharmony_ci unsigned int len; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors", 2718c2ecf20Sopenharmony_ci linebuf, sizeof(linebuf)); 2728c2ecf20Sopenharmony_ci if (len == 0) 2738c2ecf20Sopenharmony_ci return NULL; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci pos = 0; 2768c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 2778c2ecf20Sopenharmony_ci if (linebuf[i] == ' ' || linebuf[i] == '\n') { 2788c2ecf20Sopenharmony_ci if (i - pos < 2) 2798c2ecf20Sopenharmony_ci continue; 2808c2ecf20Sopenharmony_ci if (current) { 2818c2ecf20Sopenharmony_ci current->next = malloc(sizeof(*current)); 2828c2ecf20Sopenharmony_ci if (!current->next) 2838c2ecf20Sopenharmony_ci goto error_out; 2848c2ecf20Sopenharmony_ci current = current->next; 2858c2ecf20Sopenharmony_ci } else { 2868c2ecf20Sopenharmony_ci first = malloc(sizeof(*first)); 2878c2ecf20Sopenharmony_ci if (!first) 2888c2ecf20Sopenharmony_ci return NULL; 2898c2ecf20Sopenharmony_ci current = first; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci current->first = first; 2928c2ecf20Sopenharmony_ci current->next = NULL; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci current->governor = malloc(i - pos + 1); 2958c2ecf20Sopenharmony_ci if (!current->governor) 2968c2ecf20Sopenharmony_ci goto error_out; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci memcpy(current->governor, linebuf + pos, i - pos); 2998c2ecf20Sopenharmony_ci current->governor[i - pos] = '\0'; 3008c2ecf20Sopenharmony_ci pos = i + 1; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return first; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci error_out: 3078c2ecf20Sopenharmony_ci while (first) { 3088c2ecf20Sopenharmony_ci current = first->next; 3098c2ecf20Sopenharmony_ci if (first->governor) 3108c2ecf20Sopenharmony_ci free(first->governor); 3118c2ecf20Sopenharmony_ci free(first); 3128c2ecf20Sopenharmony_ci first = current; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci return NULL; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_civoid cpufreq_put_available_governors(struct cpufreq_available_governors *any) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct cpufreq_available_governors *tmp, *next; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (!any) 3228c2ecf20Sopenharmony_ci return; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci tmp = any->first; 3258c2ecf20Sopenharmony_ci while (tmp) { 3268c2ecf20Sopenharmony_ci next = tmp->next; 3278c2ecf20Sopenharmony_ci if (tmp->governor) 3288c2ecf20Sopenharmony_ci free(tmp->governor); 3298c2ecf20Sopenharmony_ci free(tmp); 3308c2ecf20Sopenharmony_ci tmp = next; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistruct cpufreq_available_frequencies 3368c2ecf20Sopenharmony_ci*cpufreq_get_available_frequencies(unsigned int cpu) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct cpufreq_available_frequencies *first = NULL; 3398c2ecf20Sopenharmony_ci struct cpufreq_available_frequencies *current = NULL; 3408c2ecf20Sopenharmony_ci char one_value[SYSFS_PATH_MAX]; 3418c2ecf20Sopenharmony_ci char linebuf[MAX_LINE_LEN]; 3428c2ecf20Sopenharmony_ci unsigned int pos, i; 3438c2ecf20Sopenharmony_ci unsigned int len; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies", 3468c2ecf20Sopenharmony_ci linebuf, sizeof(linebuf)); 3478c2ecf20Sopenharmony_ci if (len == 0) 3488c2ecf20Sopenharmony_ci return NULL; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci pos = 0; 3518c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 3528c2ecf20Sopenharmony_ci if (linebuf[i] == ' ' || linebuf[i] == '\n') { 3538c2ecf20Sopenharmony_ci if (i - pos < 2) 3548c2ecf20Sopenharmony_ci continue; 3558c2ecf20Sopenharmony_ci if (i - pos >= SYSFS_PATH_MAX) 3568c2ecf20Sopenharmony_ci goto error_out; 3578c2ecf20Sopenharmony_ci if (current) { 3588c2ecf20Sopenharmony_ci current->next = malloc(sizeof(*current)); 3598c2ecf20Sopenharmony_ci if (!current->next) 3608c2ecf20Sopenharmony_ci goto error_out; 3618c2ecf20Sopenharmony_ci current = current->next; 3628c2ecf20Sopenharmony_ci } else { 3638c2ecf20Sopenharmony_ci first = malloc(sizeof(*first)); 3648c2ecf20Sopenharmony_ci if (!first) 3658c2ecf20Sopenharmony_ci return NULL; 3668c2ecf20Sopenharmony_ci current = first; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci current->first = first; 3698c2ecf20Sopenharmony_ci current->next = NULL; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci memcpy(one_value, linebuf + pos, i - pos); 3728c2ecf20Sopenharmony_ci one_value[i - pos] = '\0'; 3738c2ecf20Sopenharmony_ci if (sscanf(one_value, "%lu", ¤t->frequency) != 1) 3748c2ecf20Sopenharmony_ci goto error_out; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci pos = i + 1; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return first; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci error_out: 3838c2ecf20Sopenharmony_ci while (first) { 3848c2ecf20Sopenharmony_ci current = first->next; 3858c2ecf20Sopenharmony_ci free(first); 3868c2ecf20Sopenharmony_ci first = current; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci return NULL; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistruct cpufreq_available_frequencies 3928c2ecf20Sopenharmony_ci*cpufreq_get_boost_frequencies(unsigned int cpu) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct cpufreq_available_frequencies *first = NULL; 3958c2ecf20Sopenharmony_ci struct cpufreq_available_frequencies *current = NULL; 3968c2ecf20Sopenharmony_ci char one_value[SYSFS_PATH_MAX]; 3978c2ecf20Sopenharmony_ci char linebuf[MAX_LINE_LEN]; 3988c2ecf20Sopenharmony_ci unsigned int pos, i; 3998c2ecf20Sopenharmony_ci unsigned int len; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci len = sysfs_cpufreq_read_file(cpu, "scaling_boost_frequencies", 4028c2ecf20Sopenharmony_ci linebuf, sizeof(linebuf)); 4038c2ecf20Sopenharmony_ci if (len == 0) 4048c2ecf20Sopenharmony_ci return NULL; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci pos = 0; 4078c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 4088c2ecf20Sopenharmony_ci if (linebuf[i] == ' ' || linebuf[i] == '\n') { 4098c2ecf20Sopenharmony_ci if (i - pos < 2) 4108c2ecf20Sopenharmony_ci continue; 4118c2ecf20Sopenharmony_ci if (i - pos >= SYSFS_PATH_MAX) 4128c2ecf20Sopenharmony_ci goto error_out; 4138c2ecf20Sopenharmony_ci if (current) { 4148c2ecf20Sopenharmony_ci current->next = malloc(sizeof(*current)); 4158c2ecf20Sopenharmony_ci if (!current->next) 4168c2ecf20Sopenharmony_ci goto error_out; 4178c2ecf20Sopenharmony_ci current = current->next; 4188c2ecf20Sopenharmony_ci } else { 4198c2ecf20Sopenharmony_ci first = malloc(sizeof(*first)); 4208c2ecf20Sopenharmony_ci if (!first) 4218c2ecf20Sopenharmony_ci return NULL; 4228c2ecf20Sopenharmony_ci current = first; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci current->first = first; 4258c2ecf20Sopenharmony_ci current->next = NULL; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci memcpy(one_value, linebuf + pos, i - pos); 4288c2ecf20Sopenharmony_ci one_value[i - pos] = '\0'; 4298c2ecf20Sopenharmony_ci if (sscanf(one_value, "%lu", ¤t->frequency) != 1) 4308c2ecf20Sopenharmony_ci goto error_out; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci pos = i + 1; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return first; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci error_out: 4398c2ecf20Sopenharmony_ci while (first) { 4408c2ecf20Sopenharmony_ci current = first->next; 4418c2ecf20Sopenharmony_ci free(first); 4428c2ecf20Sopenharmony_ci first = current; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci return NULL; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_civoid cpufreq_put_available_frequencies(struct cpufreq_available_frequencies *any) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct cpufreq_available_frequencies *tmp, *next; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (!any) 4528c2ecf20Sopenharmony_ci return; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci tmp = any->first; 4558c2ecf20Sopenharmony_ci while (tmp) { 4568c2ecf20Sopenharmony_ci next = tmp->next; 4578c2ecf20Sopenharmony_ci free(tmp); 4588c2ecf20Sopenharmony_ci tmp = next; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_civoid cpufreq_put_boost_frequencies(struct cpufreq_available_frequencies *any) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci cpufreq_put_available_frequencies(any); 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu, 4688c2ecf20Sopenharmony_ci const char *file) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci struct cpufreq_affected_cpus *first = NULL; 4718c2ecf20Sopenharmony_ci struct cpufreq_affected_cpus *current = NULL; 4728c2ecf20Sopenharmony_ci char one_value[SYSFS_PATH_MAX]; 4738c2ecf20Sopenharmony_ci char linebuf[MAX_LINE_LEN]; 4748c2ecf20Sopenharmony_ci unsigned int pos, i; 4758c2ecf20Sopenharmony_ci unsigned int len; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf)); 4788c2ecf20Sopenharmony_ci if (len == 0) 4798c2ecf20Sopenharmony_ci return NULL; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci pos = 0; 4828c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 4838c2ecf20Sopenharmony_ci if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') { 4848c2ecf20Sopenharmony_ci if (i - pos < 1) 4858c2ecf20Sopenharmony_ci continue; 4868c2ecf20Sopenharmony_ci if (i - pos >= SYSFS_PATH_MAX) 4878c2ecf20Sopenharmony_ci goto error_out; 4888c2ecf20Sopenharmony_ci if (current) { 4898c2ecf20Sopenharmony_ci current->next = malloc(sizeof(*current)); 4908c2ecf20Sopenharmony_ci if (!current->next) 4918c2ecf20Sopenharmony_ci goto error_out; 4928c2ecf20Sopenharmony_ci current = current->next; 4938c2ecf20Sopenharmony_ci } else { 4948c2ecf20Sopenharmony_ci first = malloc(sizeof(*first)); 4958c2ecf20Sopenharmony_ci if (!first) 4968c2ecf20Sopenharmony_ci return NULL; 4978c2ecf20Sopenharmony_ci current = first; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci current->first = first; 5008c2ecf20Sopenharmony_ci current->next = NULL; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci memcpy(one_value, linebuf + pos, i - pos); 5038c2ecf20Sopenharmony_ci one_value[i - pos] = '\0'; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (sscanf(one_value, "%u", ¤t->cpu) != 1) 5068c2ecf20Sopenharmony_ci goto error_out; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci pos = i + 1; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci return first; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci error_out: 5158c2ecf20Sopenharmony_ci while (first) { 5168c2ecf20Sopenharmony_ci current = first->next; 5178c2ecf20Sopenharmony_ci free(first); 5188c2ecf20Sopenharmony_ci first = current; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci return NULL; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistruct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned int cpu) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci return sysfs_get_cpu_list(cpu, "affected_cpus"); 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_civoid cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci struct cpufreq_affected_cpus *tmp, *next; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (!any) 5338c2ecf20Sopenharmony_ci return; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci tmp = any->first; 5368c2ecf20Sopenharmony_ci while (tmp) { 5378c2ecf20Sopenharmony_ci next = tmp->next; 5388c2ecf20Sopenharmony_ci free(tmp); 5398c2ecf20Sopenharmony_ci tmp = next; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistruct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned int cpu) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci return sysfs_get_cpu_list(cpu, "related_cpus"); 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_civoid cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci cpufreq_put_affected_cpus(any); 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic int verify_gov(char *new_gov, char *passed_gov) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci unsigned int i, j = 0; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (!passed_gov || (strlen(passed_gov) > 19)) 5598c2ecf20Sopenharmony_ci return -EINVAL; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci strncpy(new_gov, passed_gov, 20); 5628c2ecf20Sopenharmony_ci for (i = 0; i < 20; i++) { 5638c2ecf20Sopenharmony_ci if (j) { 5648c2ecf20Sopenharmony_ci new_gov[i] = '\0'; 5658c2ecf20Sopenharmony_ci continue; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z')) 5688c2ecf20Sopenharmony_ci continue; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z')) 5718c2ecf20Sopenharmony_ci continue; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (new_gov[i] == '-') 5748c2ecf20Sopenharmony_ci continue; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (new_gov[i] == '_') 5778c2ecf20Sopenharmony_ci continue; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (new_gov[i] == '\0') { 5808c2ecf20Sopenharmony_ci j = 1; 5818c2ecf20Sopenharmony_ci continue; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci return -EINVAL; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci new_gov[19] = '\0'; 5868c2ecf20Sopenharmony_ci return 0; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ciint cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci char min[SYSFS_PATH_MAX]; 5928c2ecf20Sopenharmony_ci char max[SYSFS_PATH_MAX]; 5938c2ecf20Sopenharmony_ci char gov[SYSFS_PATH_MAX]; 5948c2ecf20Sopenharmony_ci int ret; 5958c2ecf20Sopenharmony_ci unsigned long old_min; 5968c2ecf20Sopenharmony_ci int write_max_first; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (!policy || !(policy->governor)) 5998c2ecf20Sopenharmony_ci return -EINVAL; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (policy->max < policy->min) 6028c2ecf20Sopenharmony_ci return -EINVAL; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (verify_gov(gov, policy->governor)) 6058c2ecf20Sopenharmony_ci return -EINVAL; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min); 6088c2ecf20Sopenharmony_ci snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); 6118c2ecf20Sopenharmony_ci write_max_first = (old_min && (policy->max < old_min) ? 0 : 1); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (write_max_first) { 6148c2ecf20Sopenharmony_ci ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, 6158c2ecf20Sopenharmony_ci max, strlen(max)); 6168c2ecf20Sopenharmony_ci if (ret) 6178c2ecf20Sopenharmony_ci return ret; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min, 6218c2ecf20Sopenharmony_ci strlen(min)); 6228c2ecf20Sopenharmony_ci if (ret) 6238c2ecf20Sopenharmony_ci return ret; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (!write_max_first) { 6268c2ecf20Sopenharmony_ci ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, 6278c2ecf20Sopenharmony_ci max, strlen(max)); 6288c2ecf20Sopenharmony_ci if (ret) 6298c2ecf20Sopenharmony_ci return ret; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, 6338c2ecf20Sopenharmony_ci gov, strlen(gov)); 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ciint cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci char value[SYSFS_PATH_MAX]; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, 6448c2ecf20Sopenharmony_ci value, strlen(value)); 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ciint cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci char value[SYSFS_PATH_MAX]; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, 6558c2ecf20Sopenharmony_ci value, strlen(value)); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ciint cpufreq_modify_policy_governor(unsigned int cpu, char *governor) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci char new_gov[SYSFS_PATH_MAX]; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if ((!governor) || (strlen(governor) > 19)) 6638c2ecf20Sopenharmony_ci return -EINVAL; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (verify_gov(new_gov, governor)) 6668c2ecf20Sopenharmony_ci return -EINVAL; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, 6698c2ecf20Sopenharmony_ci new_gov, strlen(new_gov)); 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ciint cpufreq_set_frequency(unsigned int cpu, unsigned long target_frequency) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci struct cpufreq_policy *pol = cpufreq_get_policy(cpu); 6758c2ecf20Sopenharmony_ci char userspace_gov[] = "userspace"; 6768c2ecf20Sopenharmony_ci char freq[SYSFS_PATH_MAX]; 6778c2ecf20Sopenharmony_ci int ret; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (!pol) 6808c2ecf20Sopenharmony_ci return -ENODEV; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci if (strncmp(pol->governor, userspace_gov, 9) != 0) { 6838c2ecf20Sopenharmony_ci ret = cpufreq_modify_policy_governor(cpu, userspace_gov); 6848c2ecf20Sopenharmony_ci if (ret) { 6858c2ecf20Sopenharmony_ci cpufreq_put_policy(pol); 6868c2ecf20Sopenharmony_ci return ret; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci cpufreq_put_policy(pol); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED, 6958c2ecf20Sopenharmony_ci freq, strlen(freq)); 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cistruct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, 6998c2ecf20Sopenharmony_ci unsigned long long *total_time) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci struct cpufreq_stats *first = NULL; 7028c2ecf20Sopenharmony_ci struct cpufreq_stats *current = NULL; 7038c2ecf20Sopenharmony_ci char one_value[SYSFS_PATH_MAX]; 7048c2ecf20Sopenharmony_ci char linebuf[MAX_LINE_LEN]; 7058c2ecf20Sopenharmony_ci unsigned int pos, i; 7068c2ecf20Sopenharmony_ci unsigned int len; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state", 7098c2ecf20Sopenharmony_ci linebuf, sizeof(linebuf)); 7108c2ecf20Sopenharmony_ci if (len == 0) 7118c2ecf20Sopenharmony_ci return NULL; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci *total_time = 0; 7148c2ecf20Sopenharmony_ci pos = 0; 7158c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 7168c2ecf20Sopenharmony_ci if (i == strlen(linebuf) || linebuf[i] == '\n') { 7178c2ecf20Sopenharmony_ci if (i - pos < 2) 7188c2ecf20Sopenharmony_ci continue; 7198c2ecf20Sopenharmony_ci if ((i - pos) >= SYSFS_PATH_MAX) 7208c2ecf20Sopenharmony_ci goto error_out; 7218c2ecf20Sopenharmony_ci if (current) { 7228c2ecf20Sopenharmony_ci current->next = malloc(sizeof(*current)); 7238c2ecf20Sopenharmony_ci if (!current->next) 7248c2ecf20Sopenharmony_ci goto error_out; 7258c2ecf20Sopenharmony_ci current = current->next; 7268c2ecf20Sopenharmony_ci } else { 7278c2ecf20Sopenharmony_ci first = malloc(sizeof(*first)); 7288c2ecf20Sopenharmony_ci if (!first) 7298c2ecf20Sopenharmony_ci return NULL; 7308c2ecf20Sopenharmony_ci current = first; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci current->first = first; 7338c2ecf20Sopenharmony_ci current->next = NULL; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci memcpy(one_value, linebuf + pos, i - pos); 7368c2ecf20Sopenharmony_ci one_value[i - pos] = '\0'; 7378c2ecf20Sopenharmony_ci if (sscanf(one_value, "%lu %llu", 7388c2ecf20Sopenharmony_ci ¤t->frequency, 7398c2ecf20Sopenharmony_ci ¤t->time_in_state) != 2) 7408c2ecf20Sopenharmony_ci goto error_out; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci *total_time = *total_time + current->time_in_state; 7438c2ecf20Sopenharmony_ci pos = i + 1; 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci return first; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci error_out: 7508c2ecf20Sopenharmony_ci while (first) { 7518c2ecf20Sopenharmony_ci current = first->next; 7528c2ecf20Sopenharmony_ci free(first); 7538c2ecf20Sopenharmony_ci first = current; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci return NULL; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_civoid cpufreq_put_stats(struct cpufreq_stats *any) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct cpufreq_stats *tmp, *next; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (!any) 7638c2ecf20Sopenharmony_ci return; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci tmp = any->first; 7668c2ecf20Sopenharmony_ci while (tmp) { 7678c2ecf20Sopenharmony_ci next = tmp->next; 7688c2ecf20Sopenharmony_ci free(tmp); 7698c2ecf20Sopenharmony_ci tmp = next; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ciunsigned long cpufreq_get_transitions(unsigned int cpu) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS); 7768c2ecf20Sopenharmony_ci} 777