patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / cpufreq / proc_intf.c
1 /*
2  * linux/drivers/cpufreq/proc_intf.c
3  *
4  * Copyright (C) 2002 - 2003 Dominik Brodowski
5  */
6
7 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/init.h>
10 #include <linux/cpufreq.h>
11 #include <linux/ctype.h>
12 #include <linux/proc_fs.h>
13 #include <asm/uaccess.h>
14
15
16 #define CPUFREQ_ALL_CPUS                ((NR_CPUS))
17
18 /**
19  * cpufreq_parse_policy - parse a policy string
20  * @input_string: the string to parse.
21  * @policy: the policy written inside input_string
22  *
23  * This function parses a "policy string" - something the user echo'es into
24  * /proc/cpufreq or gives as boot parameter - into a struct cpufreq_policy.
25  * If there are invalid/missing entries, they are replaced with current
26  * cpufreq policy.
27  */
28 static int cpufreq_parse_policy(char input_string[42], struct cpufreq_policy *policy)
29 {
30         unsigned int            min = 0;
31         unsigned int            max = 0;
32         unsigned int            cpu = 0;
33         char                    str_governor[16];
34         struct cpufreq_policy   current_policy;
35         unsigned int            result = -EFAULT;
36
37         if (!policy)
38                 return -EINVAL;
39
40         policy->min = 0;
41         policy->max = 0;
42         policy->policy = 0;
43         policy->cpu = CPUFREQ_ALL_CPUS;
44
45         if (sscanf(input_string, "%d:%d:%d:%15s", &cpu, &min, &max, str_governor) == 4) 
46         {
47                 policy->min = min;
48                 policy->max = max;
49                 policy->cpu = cpu;
50                 result = 0;
51                 goto scan_policy;
52         }
53         if (sscanf(input_string, "%d%%%d%%%d%%%15s", &cpu, &min, &max, str_governor) == 4)
54         {
55                 if (!cpufreq_get_policy(&current_policy, cpu)) {
56                         policy->min = (min * current_policy.cpuinfo.max_freq) / 100;
57                         policy->max = (max * current_policy.cpuinfo.max_freq) / 100;
58                         policy->cpu = cpu;
59                         result = 0;
60                         goto scan_policy;
61                 }
62         }
63
64         if (sscanf(input_string, "%d:%d:%15s", &min, &max, str_governor) == 3) 
65         {
66                 policy->min = min;
67                 policy->max = max;
68                 result = 0;
69                 goto scan_policy;
70         }
71
72         if (sscanf(input_string, "%d%%%d%%%15s", &min, &max, str_governor) == 3)
73         {
74                 if (!cpufreq_get_policy(&current_policy, cpu)) {
75                         policy->min = (min * current_policy.cpuinfo.max_freq) / 100;
76                         policy->max = (max * current_policy.cpuinfo.max_freq) / 100;
77                         result = 0;
78                         goto scan_policy;
79                 }
80         }
81
82         return -EINVAL;
83
84 scan_policy:
85         result = cpufreq_parse_governor(str_governor, &policy->policy, &policy->governor);
86
87         return result;
88 }
89
90 /**
91  * cpufreq_proc_read - read /proc/cpufreq
92  *
93  * This function prints out the current cpufreq policy.
94  */
95 static int cpufreq_proc_read (
96         char                    *page,
97         char                    **start,
98         off_t                   off,
99         int                     count,
100         int                     *eof,
101         void                    *data)
102 {
103         char                    *p = page;
104         int                     len = 0;
105         struct cpufreq_policy   policy;
106         unsigned int            min_pctg = 0;
107         unsigned int            max_pctg = 0;
108         unsigned int            i = 0;
109
110         if (off != 0)
111                 goto end;
112
113         p += sprintf(p, "          minimum CPU frequency  -  maximum CPU frequency  -  policy\n");
114         for (i=0;i<NR_CPUS;i++) {
115                 if (!cpu_online(i))
116                         continue;
117
118                 if (cpufreq_get_policy(&policy, i))
119                         continue;
120
121                 if (!policy.cpuinfo.max_freq)
122                         continue;
123
124                 min_pctg = (policy.min * 100) / policy.cpuinfo.max_freq;
125                 max_pctg = (policy.max * 100) / policy.cpuinfo.max_freq;
126
127                 p += sprintf(p, "CPU%3d    %9d kHz (%3d %%)  -  %9d kHz (%3d %%)  -  ",
128                              i , policy.min, min_pctg, policy.max, max_pctg);
129                 if (policy.policy) {
130                         switch (policy.policy) {
131                                 case CPUFREQ_POLICY_POWERSAVE:
132                                 p += sprintf(p, "powersave\n");
133                                 break;  
134                         case CPUFREQ_POLICY_PERFORMANCE:
135                                 p += sprintf(p, "performance\n");
136                                 break;
137                         default:
138                                 p += sprintf(p, "INVALID\n");
139                                 break;
140                         } 
141                 } else
142                         p += scnprintf(p, CPUFREQ_NAME_LEN, "%s\n", policy.governor->name);
143         }
144 end:
145         len = (p - page);
146         if (len <= off+count) 
147                 *eof = 1;
148         *start = page + off;
149         len -= off;
150         if (len>count) 
151                 len = count;
152         if (len<0) 
153                 len = 0;
154
155         return len;
156 }
157
158
159 /**
160  * cpufreq_proc_write - handles writing into /proc/cpufreq
161  *
162  * This function calls the parsing script and then sets the policy
163  * accordingly.
164  */
165 static int cpufreq_proc_write (
166         struct file             *file,
167         const char              __user *buffer,
168         unsigned long           count,
169         void                    *data)
170 {
171         int                     result = 0;
172         char                    proc_string[42] = {'\0'};
173         struct cpufreq_policy   policy;
174         unsigned int            i = 0;
175
176
177         if ((count > sizeof(proc_string) - 1))
178                 return -EINVAL;
179         
180         if (copy_from_user(proc_string, buffer, count))
181                 return -EFAULT;
182         
183         proc_string[count] = '\0';
184
185         result = cpufreq_parse_policy(proc_string, &policy);
186         if (result)
187                 return -EFAULT;
188
189         if (policy.cpu == CPUFREQ_ALL_CPUS)
190         {
191                 for (i=0; i<NR_CPUS; i++) 
192                 {
193                         policy.cpu = i;
194                         if (cpu_online(i))
195                                 cpufreq_set_policy(&policy);
196                 }
197         } 
198         else
199                 cpufreq_set_policy(&policy);
200
201         return count;
202 }
203
204
205 /**
206  * cpufreq_proc_init - add "cpufreq" to the /proc root directory
207  *
208  * This function adds "cpufreq" to the /proc root directory.
209  */
210 static int __init cpufreq_proc_init (void)
211 {
212         struct proc_dir_entry *entry = NULL;
213
214         /* are these acceptable values? */
215         entry = create_proc_entry("cpufreq", S_IFREG|S_IRUGO|S_IWUSR, 
216                                   &proc_root);
217
218         if (!entry) {
219                 printk(KERN_ERR "unable to create /proc/cpufreq entry\n");
220                 return -EIO;
221         } else {
222                 entry->read_proc = cpufreq_proc_read;
223                 entry->write_proc = cpufreq_proc_write;
224         }
225
226         return 0;
227 }
228
229
230 /**
231  * cpufreq_proc_exit - removes "cpufreq" from the /proc root directory.
232  *
233  * This function removes "cpufreq" from the /proc root directory.
234  */
235 static void __exit cpufreq_proc_exit (void)
236 {
237         remove_proc_entry("cpufreq", &proc_root);
238         return;
239 }
240
241 MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
242 MODULE_DESCRIPTION ("CPUfreq /proc/cpufreq interface");
243 MODULE_LICENSE ("GPL");
244
245 module_init(cpufreq_proc_init);
246 module_exit(cpufreq_proc_exit);