drivers: power: report battery voltage in AOSP compatible format
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / kernel / power / tuxonice_modules.c
CommitLineData
6fa3eb70
S
1/*
2 * kernel/power/tuxonice_modules.c
3 *
4 * Copyright (C) 2004-2010 Nigel Cunningham (nigel at tuxonice net)
5 *
6 */
7
8#include <linux/suspend.h>
9#include "tuxonice.h"
10#include "tuxonice_modules.h"
11#include "tuxonice_sysfs.h"
12#include "tuxonice_ui.h"
13
14LIST_HEAD(toi_filters);
15LIST_HEAD(toiAllocators);
16
17LIST_HEAD(toi_modules);
18EXPORT_SYMBOL_GPL(toi_modules);
19
20struct toi_module_ops *toiActiveAllocator;
21EXPORT_SYMBOL_GPL(toiActiveAllocator);
22
23static int toi_num_filters;
24int toiNumAllocators, toi_num_modules;
25
26/*
27 * toi_header_storage_for_modules
28 *
29 * Returns the amount of space needed to store configuration
30 * data needed by the modules prior to copying back the original
31 * kernel. We can exclude data for pageset2 because it will be
32 * available anyway once the kernel is copied back.
33 */
34long toi_header_storage_for_modules(void)
35{
36 struct toi_module_ops *this_module;
37 int bytes = 0;
38
39 list_for_each_entry(this_module, &toi_modules, module_list) {
40 if (!this_module->enabled ||
41 (this_module->type == WRITER_MODULE && toiActiveAllocator != this_module))
42 continue;
43 if (this_module->storage_needed) {
44 int this = this_module->storage_needed() +
45 sizeof(struct toi_module_header) + sizeof(int);
46 this_module->header_requested = this;
47 bytes += this;
48 }
49 }
50
51 /* One more for the empty terminator */
52 return bytes + sizeof(struct toi_module_header);
53}
54
55void print_toi_header_storage_for_modules(void)
56{
57 struct toi_module_ops *this_module;
58 int bytes = 0;
59
60 printk(KERN_DEBUG "Header storage:\n");
61 list_for_each_entry(this_module, &toi_modules, module_list) {
62 if (!this_module->enabled ||
63 (this_module->type == WRITER_MODULE && toiActiveAllocator != this_module))
64 continue;
65 if (this_module->storage_needed) {
66 int this = this_module->storage_needed() +
67 sizeof(struct toi_module_header) + sizeof(int);
68 this_module->header_requested = this;
69 bytes += this;
70 printk(KERN_DEBUG "+ %16s : %-4d/%d.\n",
71 this_module->name, this_module->header_used, this);
72 }
73 }
74
75 printk(KERN_DEBUG "+ empty terminator : %zu.\n", sizeof(struct toi_module_header));
76 printk(KERN_DEBUG " ====\n");
77 printk(KERN_DEBUG " %zu\n", bytes + sizeof(struct toi_module_header));
78}
79EXPORT_SYMBOL_GPL(print_toi_header_storage_for_modules);
80
81/*
82 * toi_memory_for_modules
83 *
84 * Returns the amount of memory requested by modules for
85 * doing their work during the cycle.
86 */
87
88long toi_memory_for_modules(int print_parts)
89{
90 long bytes = 0, result;
91 struct toi_module_ops *this_module;
92
93 if (print_parts)
94 printk(KERN_INFO "Memory for modules:\n===================\n");
95 list_for_each_entry(this_module, &toi_modules, module_list) {
96 int this;
97 if (!this_module->enabled)
98 continue;
99 if (this_module->memory_needed) {
100 this = this_module->memory_needed();
101 if (print_parts)
102 printk(KERN_INFO "%10d bytes (%5ld pages) for "
103 "module '%s'.\n", this,
104 DIV_ROUND_UP(this, PAGE_SIZE), this_module->name);
105 bytes += this;
106 }
107 }
108
109 result = DIV_ROUND_UP(bytes, PAGE_SIZE);
110 if (print_parts)
111 printk(KERN_INFO " => %ld bytes, %ld pages.\n", bytes, result);
112
113 return result;
114}
115
116/*
117 * toi_expected_compression_ratio
118 *
119 * Returns the compression ratio expected when saving the image.
120 */
121
122int toi_expected_compression_ratio(void)
123{
124 int ratio = 100;
125 struct toi_module_ops *this_module;
126
127 list_for_each_entry(this_module, &toi_modules, module_list) {
128 if (!this_module->enabled)
129 continue;
130 if (this_module->expected_compression)
131 ratio = ratio * this_module->expected_compression()
132 / 100;
133 }
134
135 return ratio;
136}
137
138#ifdef CONFIG_TOI_ENHANCE
139/*
140 * toi_actual_compression_ratio
141 *
142 * Returns the actual compression ratio when saving the image.
143 */
144int toi_actual_compression_ratio(void)
145{
146 int ratio = 0;
147 struct toi_module_ops *this_module;
148
149 list_for_each_entry(this_module, &toi_modules, module_list) {
150 if (!this_module->enabled)
151 continue;
152 if (this_module->actual_compression)
153 ratio = this_module->actual_compression();
154 }
155
156 return ratio;
157}
158#endif /* CONFIG_TOI_ENHANCE */
159
160
161/* toi_find_module_given_dir
162 * Functionality : Return a module (if found), given a pointer
163 * to its directory name
164 */
165
166static struct toi_module_ops *toi_find_module_given_dir(char *name)
167{
168 struct toi_module_ops *this_module, *found_module = NULL;
169
170 list_for_each_entry(this_module, &toi_modules, module_list) {
171 if (!strcmp(name, this_module->directory)) {
172 found_module = this_module;
173 break;
174 }
175 }
176
177 return found_module;
178}
179
180/* toi_find_module_given_name
181 * Functionality : Return a module (if found), given a pointer
182 * to its name
183 */
184
185struct toi_module_ops *toi_find_module_given_name(char *name)
186{
187 struct toi_module_ops *this_module, *found_module = NULL;
188
189 list_for_each_entry(this_module, &toi_modules, module_list) {
190 if (!strcmp(name, this_module->name)) {
191 found_module = this_module;
192 break;
193 }
194 }
195
196 return found_module;
197}
198
199/*
200 * toi_print_module_debug_info
201 * Functionality : Get debugging info from modules into a buffer.
202 */
203int toi_print_module_debug_info(char *buffer, int buffer_size)
204{
205 struct toi_module_ops *this_module;
206 int len = 0;
207
208 list_for_each_entry(this_module, &toi_modules, module_list) {
209 if (!this_module->enabled)
210 continue;
211 if (this_module->print_debug_info) {
212 int result;
213 result = this_module->print_debug_info(buffer + len, buffer_size - len);
214 len += result;
215 }
216 }
217
218 /* Ensure null terminated */
219 buffer[buffer_size] = 0;
220
221 return len;
222}
223
224/*
225 * toi_register_module
226 *
227 * Register a module.
228 */
229int toi_register_module(struct toi_module_ops *module)
230{
231 int i;
232 struct kobject *kobj;
233
234 module->enabled = 1;
235
236 if (toi_find_module_given_name(module->name)) {
237 printk(KERN_INFO "TuxOnIce: Trying to load module %s,"
238 " which is already registered.\n", module->name);
239 return -EBUSY;
240 }
241
242 switch (module->type) {
243 case FILTER_MODULE:
244 list_add_tail(&module->type_list, &toi_filters);
245 toi_num_filters++;
246 break;
247 case WRITER_MODULE:
248 list_add_tail(&module->type_list, &toiAllocators);
249 toiNumAllocators++;
250 break;
251 case MISC_MODULE:
252 case MISC_HIDDEN_MODULE:
253 case BIO_ALLOCATOR_MODULE:
254 break;
255 default:
256 printk(KERN_ERR "Hmmm. Module '%s' has an invalid type."
257 " It has been ignored.\n", module->name);
258 return -EINVAL;
259 }
260 list_add_tail(&module->module_list, &toi_modules);
261 toi_num_modules++;
262
263 if ((!module->directory && !module->shared_directory) ||
264 !module->sysfs_data || !module->num_sysfs_entries)
265 return 0;
266
267 /*
268 * Modules may share a directory, but those with shared_dir
269 * set must be loaded (via symbol dependencies) after parents
270 * and unloaded beforehand.
271 */
272 if (module->shared_directory) {
273 struct toi_module_ops *shared = toi_find_module_given_dir(module->shared_directory);
274 if (!shared) {
275 printk(KERN_ERR "TuxOnIce: Module %s wants to share "
276 "%s's directory but %s isn't loaded.\n",
277 module->name, module->shared_directory, module->shared_directory);
278 toi_unregister_module(module);
279 return -ENODEV;
280 }
281 kobj = shared->dir_kobj;
282 } else {
283 if (!strncmp(module->directory, "[ROOT]", 6))
284 kobj = tuxonice_kobj;
285 else
286 kobj = make_toi_sysdir(module->directory);
287 }
288 module->dir_kobj = kobj;
289 for (i = 0; i < module->num_sysfs_entries; i++) {
290 int result = toi_register_sysfs_file(kobj,
291 &module->sysfs_data[i]);
292 if (result)
293 return result;
294 }
295 return 0;
296}
297EXPORT_SYMBOL_GPL(toi_register_module);
298
299/*
300 * toi_unregister_module
301 *
302 * Remove a module.
303 */
304void toi_unregister_module(struct toi_module_ops *module)
305{
306 int i;
307
308 if (module->dir_kobj)
309 for (i = 0; i < module->num_sysfs_entries; i++)
310 toi_unregister_sysfs_file(module->dir_kobj, &module->sysfs_data[i]);
311
312 if (!module->shared_directory && module->directory &&
313 strncmp(module->directory, "[ROOT]", 6))
314 remove_toi_sysdir(module->dir_kobj);
315
316 switch (module->type) {
317 case FILTER_MODULE:
318 list_del(&module->type_list);
319 toi_num_filters--;
320 break;
321 case WRITER_MODULE:
322 list_del(&module->type_list);
323 toiNumAllocators--;
324 if (toiActiveAllocator == module) {
325 toiActiveAllocator = NULL;
326 clear_toi_state(TOI_CAN_RESUME);
327 clear_toi_state(TOI_CAN_HIBERNATE);
328 }
329 break;
330 case MISC_MODULE:
331 case MISC_HIDDEN_MODULE:
332 case BIO_ALLOCATOR_MODULE:
333 break;
334 default:
335 printk(KERN_ERR "Module '%s' has an invalid type."
336 " It has been ignored.\n", module->name);
337 return;
338 }
339 list_del(&module->module_list);
340 toi_num_modules--;
341}
342EXPORT_SYMBOL_GPL(toi_unregister_module);
343
344/*
345 * toi_move_module_tail
346 *
347 * Rearrange modules when reloading the config.
348 */
349void toi_move_module_tail(struct toi_module_ops *module)
350{
351 switch (module->type) {
352 case FILTER_MODULE:
353 if (toi_num_filters > 1)
354 list_move_tail(&module->type_list, &toi_filters);
355 break;
356 case WRITER_MODULE:
357 if (toiNumAllocators > 1)
358 list_move_tail(&module->type_list, &toiAllocators);
359 break;
360 case MISC_MODULE:
361 case MISC_HIDDEN_MODULE:
362 case BIO_ALLOCATOR_MODULE:
363 break;
364 default:
365 printk(KERN_ERR "Module '%s' has an invalid type."
366 " It has been ignored.\n", module->name);
367 return;
368 }
369 if ((toi_num_filters + toiNumAllocators) > 1)
370 list_move_tail(&module->module_list, &toi_modules);
371}
372
373/*
374 * toi_initialise_modules
375 *
376 * Get ready to do some work!
377 */
378int toi_initialise_modules(int starting_cycle, int early)
379{
380 struct toi_module_ops *this_module;
381 int result;
382
383 list_for_each_entry(this_module, &toi_modules, module_list) {
384 this_module->header_requested = 0;
385 this_module->header_used = 0;
386 if (!this_module->enabled)
387 continue;
388 if (this_module->early != early)
389 continue;
390 if (this_module->initialise) {
391 result = this_module->initialise(starting_cycle);
392 if (result) {
393 toi_cleanup_modules(starting_cycle);
394 return result;
395 }
396 this_module->initialised = 1;
397 }
398 }
399
400 return 0;
401}
402
403/*
404 * toi_cleanup_modules
405 *
406 * Tell modules the work is done.
407 */
408void toi_cleanup_modules(int finishing_cycle)
409{
410 struct toi_module_ops *this_module;
411
412 list_for_each_entry(this_module, &toi_modules, module_list) {
413 if (!this_module->enabled || !this_module->initialised)
414 continue;
415 if (this_module->cleanup)
416 this_module->cleanup(finishing_cycle);
417 this_module->initialised = 0;
418 }
419}
420
421/*
422 * toi_pre_atomic_restore_modules
423 *
424 * Get ready to do some work!
425 */
426void toi_pre_atomic_restore_modules(struct toi_boot_kernel_data *bkd)
427{
428 struct toi_module_ops *this_module;
429
430 list_for_each_entry(this_module, &toi_modules, module_list) {
431 if (this_module->enabled && this_module->pre_atomic_restore)
432 this_module->pre_atomic_restore(bkd);
433 }
434}
435
436/*
437 * toi_post_atomic_restore_modules
438 *
439 * Get ready to do some work!
440 */
441void toi_post_atomic_restore_modules(struct toi_boot_kernel_data *bkd)
442{
443 struct toi_module_ops *this_module;
444
445 list_for_each_entry(this_module, &toi_modules, module_list) {
446 if (this_module->enabled && this_module->post_atomic_restore)
447 this_module->post_atomic_restore(bkd);
448 }
449}
450
451/*
452 * toi_get_next_filter
453 *
454 * Get the next filter in the pipeline.
455 */
456struct toi_module_ops *toi_get_next_filter(struct toi_module_ops *filter_sought)
457{
458 struct toi_module_ops *last_filter = NULL, *this_filter = NULL;
459
460 list_for_each_entry(this_filter, &toi_filters, type_list) {
461 if (!this_filter->enabled)
462 continue;
463 if ((last_filter == filter_sought) || (!filter_sought))
464 return this_filter;
465 last_filter = this_filter;
466 }
467
468 return toiActiveAllocator;
469}
470EXPORT_SYMBOL_GPL(toi_get_next_filter);
471
472/**
473 * toi_show_modules: Printk what support is loaded.
474 */
475void toi_print_modules(void)
476{
477 struct toi_module_ops *this_module;
478 int prev = 0;
479
480 printk(KERN_INFO "TuxOnIce " TOI_CORE_VERSION ", with support for");
481
482 list_for_each_entry(this_module, &toi_modules, module_list) {
483 if (this_module->type == MISC_HIDDEN_MODULE)
484 continue;
485 printk("%s %s%s%s", prev ? "," : "",
486 this_module->enabled ? "" : "[",
487 this_module->name, this_module->enabled ? "" : "]");
488 prev = 1;
489 }
490
491 printk(".\n");
492}
493
494/* toi_get_modules
495 *
496 * Take a reference to modules so they can't go away under us.
497 */
498
499int toi_get_modules(void)
500{
501 struct toi_module_ops *this_module;
502
503 list_for_each_entry(this_module, &toi_modules, module_list) {
504 struct toi_module_ops *this_module2;
505
506 if (try_module_get(this_module->module))
507 continue;
508
509 /* Failed! Reverse gets and return error */
510 list_for_each_entry(this_module2, &toi_modules, module_list) {
511 if (this_module == this_module2)
512 return -EINVAL;
513 module_put(this_module2->module);
514 }
515 }
516 return 0;
517}
518
519/* toi_put_modules
520 *
521 * Release our references to modules we used.
522 */
523
524void toi_put_modules(void)
525{
526 struct toi_module_ops *this_module;
527
528 list_for_each_entry(this_module, &toi_modules, module_list)
529 module_put(this_module->module);
530}