blob: 38d848396b5ec77ca4d3fc091b5e4a84544eee89 [file] [log] [blame]
/*
* (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;
}