| /* |
| * (C) 2004 Dominik Brodowski <linux@dominikbrodowski.de> |
| * |
| * Licensed under the terms of the GNU GPL License version 2. |
| */ |
| |
| #include <stdio.h> |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "cpufreq.h" |
| |
| #define MAX_LINE_LEN 255 |
| |
| static int readout_proc_cpufreq(unsigned int cpu, unsigned long *min, unsigned long *max, char **governor) |
| { |
| FILE *fp; |
| char value[MAX_LINE_LEN]; |
| char gov_value[MAX_LINE_LEN]; |
| int ret = -ENODEV; |
| unsigned int cpu_read; |
| unsigned int tmp1, tmp2; |
| |
| if ((!min) || (!max) || (!governor)) |
| return -EINVAL; |
| |
| fp = fopen("/proc/cpufreq","r"); |
| if (!fp) |
| return -ENODEV; |
| |
| |
| if (!fgets(value, MAX_LINE_LEN, fp)) { |
| ret = -EIO; |
| goto error; |
| } |
| |
| if (strlen(value) > (MAX_LINE_LEN - 10)) { |
| ret = -EIO; |
| goto error; |
| } |
| |
| while(!feof(fp)) { |
| if (!fgets(value, MAX_LINE_LEN, fp)) { |
| ret = -EIO; |
| goto error; |
| } |
| |
| if (strlen(value) > (MAX_LINE_LEN - 10)) { |
| ret = -EIO; |
| goto error; |
| } |
| |
| ret = sscanf(value, "CPU%3d %9lu kHz (%3d %%) - %9lu kHz (%3d %%) - %s", |
| &cpu_read , min, &tmp1, max, &tmp2, gov_value); |
| if (ret != 6) { |
| ret = -EIO; |
| goto error; |
| } |
| |
| if (cpu_read != cpu) |
| continue; |
| |
| if ((tmp2 < tmp1) || (tmp2 > 100) || (*max < *min)) { |
| ret = -ENOSYS; |
| goto error; |
| } |
| |
| tmp1 = strlen(gov_value); |
| if (tmp1 > 20) { |
| ret = -ENOSYS; |
| goto error; |
| } |
| |
| *governor = malloc(sizeof(char) * (tmp1 + 2)); |
| if (!*governor) { |
| ret = -ENOMEM; |
| goto error; |
| } |
| |
| strncpy(*governor, gov_value, tmp1); |
| (*governor)[tmp1] = '\0'; |
| |
| ret = 0; |
| |
| break; |
| } |
| |
| error: |
| fclose(fp); |
| return (ret); |
| } |
| |
| int proc_cpu_exists(unsigned int cpu) { |
| unsigned long tmp1, tmp2; |
| char *tmp3; |
| int ret; |
| |
| ret = readout_proc_cpufreq(cpu, &tmp1, &tmp2, &tmp3); |
| if (ret) |
| return -ENODEV; |
| |
| free(tmp3); |
| return 0; |
| } |
| |
| struct cpufreq_policy * proc_get_policy(unsigned int cpu) { |
| struct cpufreq_policy tmp; |
| struct cpufreq_policy *ret; |
| int err; |
| |
| err = readout_proc_cpufreq(cpu, &tmp.min, &tmp.max, &tmp.governor); |
| if (err) |
| return NULL; |
| |
| ret = malloc(sizeof(struct cpufreq_policy)); |
| if (!ret) |
| return NULL; |
| |
| ret->min = tmp.min; |
| ret->max = tmp.max; |
| ret->governor = tmp.governor; |
| |
| return (ret); |
| } |
| |
| unsigned long proc_get_freq_kernel(unsigned int cpu) { |
| FILE *fp; |
| char value[MAX_LINE_LEN]; |
| char file[MAX_LINE_LEN]; |
| unsigned long value2; |
| |
| snprintf(file, MAX_LINE_LEN, "/proc/sys/cpu/%u/speed", cpu); |
| |
| fp = fopen(file,"r"); |
| if (!fp) |
| return 0; |
| |
| if (!fgets(value, MAX_LINE_LEN, fp)) { |
| fclose(fp); |
| return 0; |
| } |
| |
| fclose(fp); |
| |
| if (strlen(value) > (MAX_LINE_LEN - 10)) { |
| return 0; |
| } |
| |
| if (sscanf(value, "%lu", &value2) != 1) |
| return 0; |
| |
| return value2; |
| } |
| |
| int proc_set_policy(unsigned int cpu, struct cpufreq_policy *policy) { |
| FILE *fp; |
| char value[MAX_LINE_LEN]; |
| int ret = -ENODEV; |
| |
| if ((!policy) || (!policy->governor) || (strlen(policy->governor) > 15)) |
| return -EINVAL; |
| |
| snprintf(value, MAX_LINE_LEN, "%d:%lu:%lu:%s", cpu, policy->min, policy->max, policy->governor); |
| |
| value[MAX_LINE_LEN - 1]='\0'; |
| |
| fp = fopen("/proc/cpufreq","r+"); |
| if (!fp) |
| return -ENODEV; |
| ret = fputs(value, fp); |
| fclose(fp); |
| |
| if (ret < 0) |
| return (ret); |
| |
| return 0; |
| } |
| |
| int proc_set_frequency(unsigned int cpu, unsigned long target_frequency) { |
| struct cpufreq_policy *pol = proc_get_policy(cpu); |
| struct cpufreq_policy new_pol; |
| char userspace_gov[] = "userspace"; |
| FILE *fp; |
| char value[MAX_LINE_LEN]; |
| char file[MAX_LINE_LEN]; |
| int ret = 0; |
| |
| if (!pol) |
| return -ENODEV; |
| |
| if (strncmp(pol->governor, userspace_gov, 9) != 0) { |
| cpufreq_put_policy(pol); |
| new_pol.min = pol->min; |
| new_pol.max = pol->max; |
| new_pol.governor = userspace_gov; |
| ret = proc_set_policy(cpu, &new_pol); |
| if (ret) |
| return (ret); |
| } |
| |
| |
| snprintf(file, MAX_LINE_LEN, "/proc/sys/cpu/%u/speed", cpu); |
| snprintf(value, MAX_LINE_LEN, "%lu", target_frequency); |
| |
| fp = fopen(file,"r+"); |
| if (!fp) |
| return -EINVAL; |
| ret = fputs(value, fp); |
| fclose(fp); |
| |
| if (ret < 0) |
| return (ret); |
| |
| return 0; |
| } |