drivers: power: report battery voltage in AOSP compatible format
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / kernel / power / tuxonice_builtin.c
1 /*
2 * Copyright (C) 2004-2010 Nigel Cunningham (nigel at tuxonice net)
3 *
4 * This file is released under the GPLv2.
5 */
6 #include <linux/resume-trace.h>
7 #include <linux/kernel.h>
8 #include <linux/swap.h>
9 #include <linux/syscalls.h>
10 #include <linux/bio.h>
11 #include <linux/root_dev.h>
12 #include <linux/freezer.h>
13 #include <linux/reboot.h>
14 #include <linux/writeback.h>
15 #include <linux/tty.h>
16 #include <linux/crypto.h>
17 #include <linux/cpu.h>
18 #include <linux/ctype.h>
19 #include "tuxonice_io.h"
20 #include "tuxonice.h"
21 #include "tuxonice_extent.h"
22 #include "tuxonice_netlink.h"
23 #include "tuxonice_prepare_image.h"
24 #include "tuxonice_ui.h"
25 #include "tuxonice_sysfs.h"
26 #include "tuxonice_pagedir.h"
27 #include "tuxonice_modules.h"
28 #include "tuxonice_builtin.h"
29 #include "tuxonice_power_off.h"
30 #include "tuxonice_alloc.h"
31
32 unsigned long toi_bootflags_mask;
33 EXPORT_SYMBOL_GPL(toi_bootflags_mask);
34
35 /*
36 * Highmem related functions (x86 only).
37 */
38
39 #ifdef CONFIG_HIGHMEM
40
41 /**
42 * copyback_high: Restore highmem pages.
43 *
44 * Highmem data and pbe lists are/can be stored in highmem.
45 * The format is slightly different to the lowmem pbe lists
46 * used for the assembly code: the last pbe in each page is
47 * a struct page * instead of struct pbe *, pointing to the
48 * next page where pbes are stored (or NULL if happens to be
49 * the end of the list). Since we don't want to generate
50 * unnecessary deltas against swsusp code, we use a cast
51 * instead of a union.
52 **/
53
54 static void copyback_high(void)
55 {
56 struct page *pbe_page = (struct page *)restore_highmem_pblist;
57 struct pbe *this_pbe, *first_pbe;
58 unsigned long *origpage, *copypage;
59 int pbe_index = 1;
60
61 if (!pbe_page)
62 return;
63
64 this_pbe = (struct pbe *)kmap_atomic(pbe_page);
65 first_pbe = this_pbe;
66
67 while (this_pbe) {
68 int loop = (PAGE_SIZE / sizeof(unsigned long)) - 1;
69
70 origpage = kmap_atomic(pfn_to_page((unsigned long)this_pbe->orig_address));
71 copypage = kmap_atomic((struct page *)this_pbe->address);
72
73 while (loop >= 0) {
74 *(origpage + loop) = *(copypage + loop);
75 loop--;
76 }
77
78 kunmap_atomic(origpage);
79 kunmap_atomic(copypage);
80
81 if (!this_pbe->next)
82 break;
83
84 if (pbe_index < PBES_PER_PAGE) {
85 this_pbe++;
86 pbe_index++;
87 } else {
88 pbe_page = (struct page *)this_pbe->next;
89 kunmap_atomic(first_pbe);
90 if (!pbe_page)
91 return;
92 this_pbe = (struct pbe *)kmap_atomic(pbe_page);
93 first_pbe = this_pbe;
94 pbe_index = 1;
95 }
96 }
97 kunmap_atomic(first_pbe);
98 }
99
100 #else /* CONFIG_HIGHMEM */
101 static void copyback_high(void)
102 {
103 }
104 #endif
105
106 char toi_wait_for_keypress_dev_console(int timeout)
107 {
108 int fd, this_timeout = 255;
109 char key = '\0';
110 struct termios t, t_backup;
111
112 /* We should be guaranteed /dev/console exists after populate_rootfs()
113 * in init/main.c.
114 */
115 fd = sys_open("/dev/console", O_RDONLY, 0);
116 if (fd < 0) {
117 printk(KERN_INFO "Couldn't open /dev/console.\n");
118 return key;
119 }
120
121 if (sys_ioctl(fd, TCGETS, (long)&t) < 0)
122 goto out_close;
123
124 memcpy(&t_backup, &t, sizeof(t));
125
126 t.c_lflag &= ~(ISIG | ICANON | ECHO);
127 t.c_cc[VMIN] = 0;
128
129 new_timeout:
130 if (timeout > 0) {
131 this_timeout = timeout < 26 ? timeout : 25;
132 timeout -= this_timeout;
133 this_timeout *= 10;
134 }
135
136 t.c_cc[VTIME] = this_timeout;
137
138 if (sys_ioctl(fd, TCSETS, (long)&t) < 0)
139 goto out_restore;
140
141 while (1) {
142 if (sys_read(fd, &key, 1) <= 0) {
143 if (timeout)
144 goto new_timeout;
145 key = '\0';
146 break;
147 }
148 key = tolower(key);
149 if (test_toi_state(TOI_SANITY_CHECK_PROMPT)) {
150 if (key == 'c') {
151 set_toi_state(TOI_CONTINUE_REQ);
152 break;
153 } else if (key == ' ')
154 break;
155 } else
156 break;
157 }
158
159 out_restore:
160 sys_ioctl(fd, TCSETS, (long)&t_backup);
161 out_close:
162 sys_close(fd);
163
164 return key;
165 }
166 EXPORT_SYMBOL_GPL(toi_wait_for_keypress_dev_console);
167
168 struct toi_boot_kernel_data toi_bkd __nosavedata __attribute__ ((aligned(PAGE_SIZE))) = {
169 MY_BOOT_KERNEL_DATA_VERSION, 0,
170 #ifdef CONFIG_TOI_REPLACE_SWSUSP
171 (1 << TOI_REPLACE_SWSUSP) |
172 #endif
173 (1 << TOI_NO_FLUSHER_THREAD) |
174 /* (1 << TOI_NO_MULTITHREADED_IO) | */
175 (1 << TOI_LATE_CPU_HOTPLUG) | (1 << TOI_PAGESET2_FULL),};
176
177 EXPORT_SYMBOL_GPL(toi_bkd);
178
179 struct block_device *toi_open_by_devnum(dev_t dev)
180 {
181 struct block_device *bdev = bdget(dev);
182 int err = -ENOMEM;
183 if (bdev)
184 err = blkdev_get(bdev, FMODE_READ | FMODE_NDELAY, NULL);
185 return err ? ERR_PTR(err) : bdev;
186 }
187 EXPORT_SYMBOL_GPL(toi_open_by_devnum);
188
189 /**
190 * toi_close_bdev: Close a swap bdev.
191 *
192 * int: The swap entry number to close.
193 */
194 void toi_close_bdev(struct block_device *bdev)
195 {
196 blkdev_put(bdev, FMODE_READ | FMODE_NDELAY);
197 }
198 EXPORT_SYMBOL_GPL(toi_close_bdev);
199
200 int toi_wait = CONFIG_TOI_DEFAULT_WAIT;
201 EXPORT_SYMBOL_GPL(toi_wait);
202
203 struct toi_core_fns *toi_core_fns;
204 EXPORT_SYMBOL_GPL(toi_core_fns);
205
206 unsigned long toi_result;
207 EXPORT_SYMBOL_GPL(toi_result);
208
209 struct pagedir pagedir1 = { 1 };
210
211 EXPORT_SYMBOL_GPL(pagedir1);
212
213 unsigned long toi_get_nonconflicting_page(void)
214 {
215 return toi_core_fns->get_nonconflicting_page();
216 }
217
218 int toi_post_context_save(void)
219 {
220 return toi_core_fns->post_context_save();
221 }
222
223 int try_tuxonice_hibernate(void)
224 {
225 if (!toi_core_fns)
226 return -ENODEV;
227
228 return toi_core_fns->try_hibernate();
229 }
230
231 static int num_resume_calls;
232 #ifdef CONFIG_TOI_IGNORE_LATE_INITCALL
233 static int ignore_late_initcall = 1;
234 #else
235 static int ignore_late_initcall;
236 #endif
237
238 #ifdef CONFIG_TOI_ENHANCE
239 int toi_ignore_late_initcall(void)
240 {
241 return ignore_late_initcall;
242 }
243 EXPORT_SYMBOL_GPL(toi_ignore_late_initcall);
244 #endif
245
246 int toi_translate_err_default = TOI_CONTINUE_REQ;
247 EXPORT_SYMBOL_GPL(toi_translate_err_default);
248
249 void try_tuxonice_resume(void)
250 {
251 /* Don't let it wrap around eventually */
252 if (num_resume_calls < 2)
253 num_resume_calls++;
254
255 if (num_resume_calls == 1 && ignore_late_initcall) {
256 printk(KERN_INFO "TuxOnIce: Ignoring late initcall, as requested.\n");
257 return;
258 }
259
260 if (toi_core_fns)
261 toi_core_fns->try_resume();
262 else
263 printk(KERN_INFO "TuxOnIce core not loaded yet.\n");
264 }
265
266 int toi_lowlevel_builtin(void)
267 {
268 int error = 0;
269
270 save_processor_state();
271 error = swsusp_arch_suspend();
272 if (error)
273 printk(KERN_ERR "Error %d hibernating\n", error);
274
275 #ifdef CONFIG_TOI_ENHANCE
276 if (test_result_state(TOI_ARCH_PREPARE_FAILED)) {
277 hib_err("CAUTION: error(%d/0x%08x)\n", error, (unsigned int)toi_result);
278 }
279 #endif
280
281 /* Restore control flow appears here */
282 if (!toi_in_hibernate) {
283 copyback_high();
284 set_toi_state(TOI_NOW_RESUMING);
285 }
286
287 restore_processor_state();
288 return error;
289 }
290 EXPORT_SYMBOL_GPL(toi_lowlevel_builtin);
291
292 unsigned long toi_compress_bytes_in;
293 EXPORT_SYMBOL_GPL(toi_compress_bytes_in);
294
295 unsigned long toi_compress_bytes_out;
296 EXPORT_SYMBOL_GPL(toi_compress_bytes_out);
297
298 int toi_in_suspend(void)
299 {
300 return in_suspend;
301 }
302 EXPORT_SYMBOL_GPL(toi_in_suspend);
303
304 unsigned long toi_state = ((1 << TOI_BOOT_TIME) |
305 (1 << TOI_IGNORE_LOGLEVEL) | (1 << TOI_IO_STOPPED));
306 EXPORT_SYMBOL_GPL(toi_state);
307
308 /* The number of hibernates we have started (some may have been cancelled) */
309 unsigned int nr_hibernates;
310 EXPORT_SYMBOL_GPL(nr_hibernates);
311
312 int toi_running;
313 EXPORT_SYMBOL_GPL(toi_running);
314
315 __nosavedata int toi_in_hibernate;
316 EXPORT_SYMBOL_GPL(toi_in_hibernate);
317
318 __nosavedata struct pbe *restore_highmem_pblist;
319 EXPORT_SYMBOL_GPL(restore_highmem_pblist);
320
321 int toi_trace_allocs;
322 EXPORT_SYMBOL_GPL(toi_trace_allocs);
323
324 void toi_read_lock_tasklist(void)
325 {
326 read_lock(&tasklist_lock);
327 }
328 EXPORT_SYMBOL_GPL(toi_read_lock_tasklist);
329
330 void toi_read_unlock_tasklist(void)
331 {
332 read_unlock(&tasklist_lock);
333 }
334 EXPORT_SYMBOL_GPL(toi_read_unlock_tasklist);
335
336 #ifdef CONFIG_TOI_ZRAM_SUPPORT
337 int (*toi_flag_zram_disks) (void);
338 EXPORT_SYMBOL_GPL(toi_flag_zram_disks);
339
340 int toi_do_flag_zram_disks(void)
341 {
342 return toi_flag_zram_disks ? (*toi_flag_zram_disks) () : 0;
343 }
344 EXPORT_SYMBOL_GPL(toi_do_flag_zram_disks);
345 #endif
346
347 static int __init toi_wait_setup(char *str)
348 {
349 int value;
350
351 if (sscanf(str, "=%d", &value)) {
352 if (value < -1 || value > 255)
353 printk(KERN_INFO "TuxOnIce_wait outside range -1 to " "255.\n");
354 else
355 toi_wait = value;
356 }
357
358 return 1;
359 }
360
361 __setup("toi_wait", toi_wait_setup);
362
363 static int __init toi_translate_retry_setup(char *str)
364 {
365 toi_translate_err_default = 0;
366 return 1;
367 }
368
369 __setup("toi_translate_retry", toi_translate_retry_setup);
370
371 static int __init toi_debug_setup(char *str)
372 {
373 toi_bkd.toi_action |= (1 << TOI_LOGALL);
374 toi_bootflags_mask |= (1 << TOI_LOGALL);
375 toi_bkd.toi_debug_state = 255;
376 toi_bkd.toi_default_console_level = 7;
377 return 1;
378 }
379
380 __setup("toi_debug_setup", toi_debug_setup);
381
382 static int __init toi_pause_setup(char *str)
383 {
384 toi_bkd.toi_action |= (1 << TOI_PAUSE);
385 toi_bootflags_mask |= (1 << TOI_PAUSE);
386 return 1;
387 }
388
389 __setup("toi_pause", toi_pause_setup);
390
391 #ifdef CONFIG_PM_DEBUG
392 static int __init toi_trace_allocs_setup(char *str)
393 {
394 int value;
395
396 if (sscanf(str, "=%d", &value))
397 toi_trace_allocs = value;
398
399 return 1;
400 }
401
402 __setup("toi_trace_allocs", toi_trace_allocs_setup);
403 #endif
404
405 static int __init toi_ignore_late_initcall_setup(char *str)
406 {
407 int value;
408
409 if (sscanf(str, "=%d", &value))
410 ignore_late_initcall = value;
411
412 return 1;
413 }
414
415 __setup("toi_initramfs_resume_only", toi_ignore_late_initcall_setup);
416
417 static int __init toi_force_no_multithreaded_setup(char *str)
418 {
419 int value;
420
421 toi_bkd.toi_action &= ~(1 << TOI_NO_MULTITHREADED_IO);
422 toi_bootflags_mask |= (1 << TOI_NO_MULTITHREADED_IO);
423
424 if (sscanf(str, "=%d", &value) && value)
425 toi_bkd.toi_action |= (1 << TOI_NO_MULTITHREADED_IO);
426
427 return 1;
428 }
429
430 __setup("toi_no_multithreaded", toi_force_no_multithreaded_setup);
431
432 #ifdef CONFIG_KGDB
433 static int __init toi_post_resume_breakpoint_setup(char *str)
434 {
435 int value;
436
437 toi_bkd.toi_action &= ~(1 << TOI_POST_RESUME_BREAKPOINT);
438 toi_bootflags_mask |= (1 << TOI_POST_RESUME_BREAKPOINT);
439 if (sscanf(str, "=%d", &value) && value)
440 toi_bkd.toi_action |= (1 << TOI_POST_RESUME_BREAKPOINT);
441
442 return 1;
443 }
444
445 __setup("toi_post_resume_break", toi_post_resume_breakpoint_setup);
446 #endif
447
448 static int __init toi_disable_readahead_setup(char *str)
449 {
450 int value;
451
452 toi_bkd.toi_action &= ~(1 << TOI_NO_READAHEAD);
453 toi_bootflags_mask |= (1 << TOI_NO_READAHEAD);
454 if (sscanf(str, "=%d", &value) && value)
455 toi_bkd.toi_action |= (1 << TOI_NO_READAHEAD);
456
457 return 1;
458 }
459
460 __setup("toi_no_readahead", toi_disable_readahead_setup);