init
[cpufrequi] / proc.c
1 /*
2  *  (C) 2004  Dominik Brodowski <linux@dominikbrodowski.de>
3  *
4  *  Licensed under the terms of the GNU GPL License version 2.
5  */
6
7 #include <stdio.h>
8 #include <errno.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "cpufreq.h"
13
14 #define MAX_LINE_LEN 255
15
16 static int readout_proc_cpufreq(unsigned int cpu, unsigned long *min, unsigned long *max, char **governor)
17 {
18         FILE *fp;
19         char value[MAX_LINE_LEN];
20         char gov_value[MAX_LINE_LEN];
21         int ret = -ENODEV;
22         unsigned int cpu_read;
23         unsigned int tmp1, tmp2;
24
25         if ((!min) || (!max) || (!governor))
26                 return -EINVAL;
27
28         fp = fopen("/proc/cpufreq","r");
29         if (!fp)
30                 return -ENODEV;
31
32
33         if (!fgets(value, MAX_LINE_LEN, fp)) {
34                 ret = -EIO;
35                 goto error;
36         }
37
38         if (strlen(value) > (MAX_LINE_LEN - 10)) {
39                 ret = -EIO;
40                 goto error;
41         }
42
43         while(!feof(fp)) {
44                 if (!fgets(value, MAX_LINE_LEN, fp)) {
45                         ret = -EIO;
46                         goto error;
47                 }
48
49                 if (strlen(value) > (MAX_LINE_LEN - 10)) {
50                         ret = -EIO;
51                         goto error;
52                 }
53
54                 ret = sscanf(value, "CPU%3d    %9lu kHz (%3d %%)  -  %9lu kHz (%3d %%)  -  %s",
55                              &cpu_read , min, &tmp1, max, &tmp2, gov_value);
56                 if (ret != 6) {
57                         ret = -EIO;
58                         goto error;
59                 }
60
61                 if (cpu_read != cpu)
62                         continue;
63
64                 if ((tmp2 < tmp1) || (tmp2 > 100) || (*max < *min)) {
65                         ret = -ENOSYS;
66                         goto error;
67                 }
68
69                 tmp1 = strlen(gov_value);
70                 if (tmp1 > 20) {
71                         ret = -ENOSYS;
72                         goto error;
73                 }
74
75                 *governor = malloc(sizeof(char) * (tmp1 + 2));
76                 if (!*governor) {
77                         ret = -ENOMEM;
78                         goto error;
79                 }
80
81                 strncpy(*governor, gov_value, tmp1);
82                 (*governor)[tmp1] = '\0';
83
84                 ret = 0;
85
86                 break;
87         }
88
89  error:
90         fclose(fp);
91         return (ret);
92 }
93
94 int proc_cpu_exists(unsigned int cpu) {
95         unsigned long tmp1, tmp2;
96         char *tmp3;
97         int ret;
98
99         ret = readout_proc_cpufreq(cpu, &tmp1, &tmp2, &tmp3);
100         if (ret)
101                 return -ENODEV;
102
103         free(tmp3);
104         return 0;
105 }
106
107 struct cpufreq_policy * proc_get_policy(unsigned int cpu) {
108         struct cpufreq_policy tmp;
109         struct cpufreq_policy *ret;
110         int err;
111
112         err = readout_proc_cpufreq(cpu, &tmp.min, &tmp.max, &tmp.governor);
113         if (err)
114                 return NULL;
115
116         ret = malloc(sizeof(struct cpufreq_policy));
117         if (!ret)
118                 return NULL;
119
120         ret->min = tmp.min;
121         ret->max = tmp.max;
122         ret->governor = tmp.governor;
123
124         return (ret);
125 }
126
127 unsigned long proc_get_freq_kernel(unsigned int cpu) {
128         FILE *fp;
129         char value[MAX_LINE_LEN];
130         char file[MAX_LINE_LEN];
131         unsigned long value2;
132
133         snprintf(file, MAX_LINE_LEN, "/proc/sys/cpu/%u/speed", cpu);
134
135         fp = fopen(file,"r");
136         if (!fp)
137                 return 0;
138
139         if (!fgets(value, MAX_LINE_LEN, fp)) {
140                 fclose(fp);
141                 return 0;
142         }
143
144         fclose(fp);
145
146         if (strlen(value) > (MAX_LINE_LEN - 10)) {
147                 return 0;
148         }
149
150         if (sscanf(value, "%lu", &value2) != 1)
151                 return 0;
152
153         return value2;
154 }
155
156 int proc_set_policy(unsigned int cpu, struct cpufreq_policy *policy) {
157         FILE *fp;
158         char value[MAX_LINE_LEN];
159         int ret = -ENODEV;
160
161         if ((!policy) || (!policy->governor) || (strlen(policy->governor) > 15))
162                 return -EINVAL;
163
164         snprintf(value, MAX_LINE_LEN, "%d:%lu:%lu:%s", cpu, policy->min, policy->max, policy->governor);
165
166         value[MAX_LINE_LEN - 1]='\0';
167
168         fp = fopen("/proc/cpufreq","r+");
169         if (!fp)
170                 return -ENODEV;
171         ret = fputs(value, fp);
172         fclose(fp);
173
174         if (ret < 0)
175                 return (ret);
176
177         return 0;
178 }
179
180 int proc_set_frequency(unsigned int cpu, unsigned long target_frequency) {
181         struct cpufreq_policy *pol = proc_get_policy(cpu);
182         struct cpufreq_policy new_pol;
183         char userspace_gov[] = "userspace";
184         FILE *fp;
185         char value[MAX_LINE_LEN];
186         char file[MAX_LINE_LEN];
187         int ret = 0;
188
189         if (!pol)
190                 return -ENODEV;
191
192         if (strncmp(pol->governor, userspace_gov, 9) != 0) {
193                 cpufreq_put_policy(pol);
194                 new_pol.min = pol->min;
195                 new_pol.max = pol->max;
196                 new_pol.governor = userspace_gov;
197                 ret = proc_set_policy(cpu, &new_pol);
198                 if (ret)
199                         return (ret);
200         }
201
202
203         snprintf(file, MAX_LINE_LEN, "/proc/sys/cpu/%u/speed", cpu);
204         snprintf(value, MAX_LINE_LEN, "%lu", target_frequency);
205
206         fp = fopen(file,"r+");
207         if (!fp)
208                 return -EINVAL;
209         ret = fputs(value, fp);
210         fclose(fp);
211
212         if (ret < 0)
213                 return (ret);
214
215         return 0;
216 }