drivers: power: report battery voltage in AOSP compatible format
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / kernel / power / tuxonice_userui.c
CommitLineData
6fa3eb70
S
1/*
2 * kernel/power/user_ui.c
3 *
4 * Copyright (C) 2005-2007 Bernard Blackham
5 * Copyright (C) 2002-2010 Nigel Cunningham (nigel at tuxonice net)
6 *
7 * This file is released under the GPLv2.
8 *
9 * Routines for TuxOnIce's user interface.
10 *
11 * The user interface code talks to a userspace program via a
12 * netlink socket.
13 *
14 * The kernel side:
15 * - starts the userui program;
16 * - sends text messages and progress bar status;
17 *
18 * The user space side:
19 * - passes messages regarding user requests (abort, toggle reboot etc)
20 *
21 */
22
23#define __KERNEL_SYSCALLS__
24
25#include <linux/suspend.h>
26#include <linux/freezer.h>
27#include <linux/console.h>
28#include <linux/ctype.h>
29#include <linux/tty.h>
30#include <linux/vt_kern.h>
31#include <linux/reboot.h>
32#include <linux/security.h>
33#include <linux/syscalls.h>
34#include <linux/vt.h>
35
36#include "tuxonice_sysfs.h"
37#include "tuxonice_modules.h"
38#include "tuxonice.h"
39#include "tuxonice_ui.h"
40#include "tuxonice_netlink.h"
41#include "tuxonice_power_off.h"
42
43static char local_printf_buf[1024]; /* Same as printk - should be safe */
44
45static struct user_helper_data ui_helper_data;
46static struct toi_module_ops userui_ops;
47static int orig_kmsg;
48
49static char lastheader[512];
50static int lastheader_message_len;
51static int ui_helper_changed; /* Used at resume-time so don't overwrite value
52 set from initrd/ramfs. */
53
54/* Number of distinct progress amounts that userspace can display */
55static int progress_granularity = 30;
56
57static DECLARE_WAIT_QUEUE_HEAD(userui_wait_for_key);
58
59/**
60 * ui_nl_set_state - Update toi_action based on a message from userui.
61 *
62 * @n: The bit (1 << bit) to set.
63 */
64static void ui_nl_set_state(int n)
65{
66 /* Only let them change certain settings */
67 static const u32 toi_action_mask =
68 (1 << TOI_REBOOT) | (1 << TOI_PAUSE) |
69 (1 << TOI_LOGALL) | (1 << TOI_SINGLESTEP) | (1 << TOI_PAUSE_NEAR_PAGESET_END);
70 static unsigned long new_action;
71
72 new_action = (toi_bkd.toi_action & (~toi_action_mask)) | (n & toi_action_mask);
73
74 printk(KERN_DEBUG "n is %x. Action flags being changed from %lx "
75 "to %lx.", n, toi_bkd.toi_action, new_action);
76 toi_bkd.toi_action = new_action;
77
78 if (!test_action_state(TOI_PAUSE) && !test_action_state(TOI_SINGLESTEP))
79 wake_up_interruptible(&userui_wait_for_key);
80}
81
82/**
83 * userui_post_atomic_restore - Tell userui that atomic restore just happened.
84 *
85 * Tell userui that atomic restore just occured, so that it can do things like
86 * redrawing the screen, re-getting settings and so on.
87 */
88static void userui_post_atomic_restore(struct toi_boot_kernel_data *bkd)
89{
90 toi_send_netlink_message(&ui_helper_data, USERUI_MSG_POST_ATOMIC_RESTORE, NULL, 0);
91}
92
93/**
94 * userui_storage_needed - Report how much memory in image header is needed.
95 */
96static int userui_storage_needed(void)
97{
98 return sizeof(ui_helper_data.program) + 1 + sizeof(int);
99}
100
101/**
102 * userui_save_config_info - Fill buffer with config info for image header.
103 *
104 * @buf: Buffer into which to put the config info we want to save.
105 */
106static int userui_save_config_info(char *buf)
107{
108 *((int *)buf) = progress_granularity;
109 memcpy(buf + sizeof(int), ui_helper_data.program, sizeof(ui_helper_data.program));
110 return sizeof(ui_helper_data.program) + sizeof(int) + 1;
111}
112
113/**
114 * userui_load_config_info - Restore config info from buffer.
115 *
116 * @buf: Buffer containing header info loaded.
117 * @size: Size of data loaded for this module.
118 */
119static void userui_load_config_info(char *buf, int size)
120{
121 progress_granularity = *((int *)buf);
122 size -= sizeof(int);
123
124 /* Don't load the saved path if one has already been set */
125 if (ui_helper_changed)
126 return;
127
128 if (size > sizeof(ui_helper_data.program))
129 size = sizeof(ui_helper_data.program);
130
131 memcpy(ui_helper_data.program, buf + sizeof(int), size);
132 ui_helper_data.program[sizeof(ui_helper_data.program) - 1] = '\0';
133}
134
135/**
136 * set_ui_program_set: Record that userui program was changed.
137 *
138 * Side effect routine for when the userui program is set. In an initrd or
139 * ramfs, the user may set a location for the userui program. If this happens,
140 * we don't want to reload the value that was saved in the image header. This
141 * routine allows us to flag that we shouldn't restore the program name from
142 * the image header.
143 */
144static void set_ui_program_set(void)
145{
146 ui_helper_changed = 1;
147}
148
149/**
150 * userui_memory_needed - Tell core how much memory to reserve for us.
151 */
152static int userui_memory_needed(void)
153{
154 /* ball park figure of 128 pages */
155 return 128 * PAGE_SIZE;
156}
157
158/**
159 * userui_update_status - Update the progress bar and (if on) in-bar message.
160 *
161 * @value: Current progress percentage numerator.
162 * @maximum: Current progress percentage denominator.
163 * @fmt: Message to be displayed in the middle of the progress bar.
164 *
165 * Note that a NULL message does not mean that any previous message is erased!
166 * For that, you need toi_prepare_status with clearbar on.
167 *
168 * Returns an unsigned long, being the next numerator (as determined by the
169 * maximum and progress granularity) where status needs to be updated.
170 * This is to reduce unnecessary calls to update_status.
171 */
172static u32 userui_update_status(u32 value, u32 maximum, const char *fmt, ...)
173{
174 static u32 last_step = 9999;
175 struct userui_msg_params msg;
176 u32 this_step, next_update;
177 int bitshift;
178
179 if (ui_helper_data.pid == -1)
180 return 0;
181
182 if ((!maximum) || (!progress_granularity))
183 return maximum;
184
185 if (value < 0)
186 value = 0;
187
188 if (value > maximum)
189 value = maximum;
190
191 /* Try to avoid math problems - we can't do 64 bit math here
192 * (and shouldn't need it - anyone got screen resolution
193 * of 65536 pixels or more?) */
194 bitshift = fls(maximum) - 16;
195 if (bitshift > 0) {
196 u32 temp_maximum = maximum >> bitshift;
197 u32 temp_value = value >> bitshift;
198 this_step = (u32)
199 (temp_value * progress_granularity / temp_maximum);
200 next_update = (((this_step + 1) * temp_maximum /
201 progress_granularity) + 1) << bitshift;
202 } else {
203 this_step = (u32) (value * progress_granularity / maximum);
204 next_update = ((this_step + 1) * maximum / progress_granularity) + 1;
205 }
206
207 if (this_step == last_step)
208 return next_update;
209
210 memset(&msg, 0, sizeof(msg));
211
212 msg.a = this_step;
213 msg.b = progress_granularity;
214
215 if (fmt) {
216 va_list args;
217 va_start(args, fmt);
218 vsnprintf(msg.text, sizeof(msg.text), fmt, args);
219 va_end(args);
220 msg.text[sizeof(msg.text) - 1] = '\0';
221 }
222
223 toi_send_netlink_message(&ui_helper_data, USERUI_MSG_PROGRESS, &msg, sizeof(msg));
224 last_step = this_step;
225
226 return next_update;
227}
228
229/**
230 * userui_message - Display a message without necessarily logging it.
231 *
232 * @section: Type of message. Messages can be filtered by type.
233 * @level: Degree of importance of the message. Lower values = higher priority.
234 * @normally_logged: Whether logged even if log_everything is off.
235 * @fmt: Message (and parameters).
236 *
237 * This function is intended to do the same job as printk, but without normally
238 * logging what is printed. The point is to be able to get debugging info on
239 * screen without filling the logs with "1/534. ^M 2/534^M. 3/534^M"
240 *
241 * It may be called from an interrupt context - can't sleep!
242 */
243static void userui_message(u32 section, u32 level, u32 normally_logged, const char *fmt, ...)
244{
245 struct userui_msg_params msg;
246
247 if ((level) && (level > console_loglevel))
248 return;
249
250 memset(&msg, 0, sizeof(msg));
251
252 msg.a = section;
253 msg.b = level;
254 msg.c = normally_logged;
255
256 if (fmt) {
257 va_list args;
258 va_start(args, fmt);
259 vsnprintf(msg.text, sizeof(msg.text), fmt, args);
260 va_end(args);
261 msg.text[sizeof(msg.text) - 1] = '\0';
262 }
263
264 if (test_action_state(TOI_LOGALL))
265 printk(KERN_INFO "%s\n", msg.text);
266
267 toi_send_netlink_message(&ui_helper_data, USERUI_MSG_MESSAGE, &msg, sizeof(msg));
268}
269
270/**
271 * wait_for_key_via_userui - Wait for userui to receive a keypress.
272 */
273static void wait_for_key_via_userui(void)
274{
275 DECLARE_WAITQUEUE(wait, current);
276
277 add_wait_queue(&userui_wait_for_key, &wait);
278 set_current_state(TASK_INTERRUPTIBLE);
279
280 interruptible_sleep_on(&userui_wait_for_key);
281
282 set_current_state(TASK_RUNNING);
283 remove_wait_queue(&userui_wait_for_key, &wait);
284}
285
286/**
287 * userui_prepare_status - Display high level messages.
288 *
289 * @clearbar: Whether to clear the progress bar.
290 * @fmt...: New message for the title.
291 *
292 * Prepare the 'nice display', drawing the header and version, along with the
293 * current action and perhaps also resetting the progress bar.
294 */
295static void userui_prepare_status(int clearbar, const char *fmt, ...)
296{
297 va_list args;
298
299 if (fmt) {
300 va_start(args, fmt);
301 lastheader_message_len = vsnprintf(lastheader, 512, fmt, args);
302 va_end(args);
303 }
304
305 if (clearbar)
306 toi_update_status(0, 1, NULL);
307
308 if (ui_helper_data.pid == -1)
309 printk(KERN_EMERG "%s\n", lastheader);
310 else
311 toi_message(0, TOI_STATUS, 1, lastheader, NULL);
312}
313
314/**
315 * toi_wait_for_keypress - Wait for keypress via userui.
316 *
317 * @timeout: Maximum time to wait.
318 *
319 * Wait for a keypress from userui.
320 *
321 * FIXME: Implement timeout?
322 */
323static char userui_wait_for_keypress(int timeout)
324{
325 char key = '\0';
326
327 if (ui_helper_data.pid != -1) {
328 wait_for_key_via_userui();
329 key = ' ';
330 }
331
332 return key;
333}
334
335/**
336 * userui_abort_hibernate - Abort a cycle & tell user if they didn't request it.
337 *
338 * @result_code: Reason why we're aborting (1 << bit).
339 * @fmt: Message to display if telling the user what's going on.
340 *
341 * Abort a cycle. If this wasn't at the user's request (and we're displaying
342 * output), tell the user why and wait for them to acknowledge the message.
343 */
344static void userui_abort_hibernate(int result_code, const char *fmt, ...)
345{
346 va_list args;
347 int printed_len = 0;
348
349 set_result_state(result_code);
350
351 if (test_result_state(TOI_ABORTED))
352 return;
353
354 set_result_state(TOI_ABORTED);
355
356 if (test_result_state(TOI_ABORT_REQUESTED))
357 return;
358
359 va_start(args, fmt);
360 printed_len = vsnprintf(local_printf_buf, sizeof(local_printf_buf), fmt, args);
361 va_end(args);
362 if (ui_helper_data.pid != -1)
363 printed_len = sprintf(local_printf_buf + printed_len, " (Press SPACE to continue)");
364
365 toi_prepare_status(CLEAR_BAR, "%s", local_printf_buf);
366
367 if (ui_helper_data.pid != -1)
368 userui_wait_for_keypress(0);
369}
370
371/**
372 * request_abort_hibernate - Abort hibernating or resuming at user request.
373 *
374 * Handle the user requesting the cancellation of a hibernation or resume by
375 * pressing escape.
376 */
377static void request_abort_hibernate(void)
378{
379 if (test_result_state(TOI_ABORT_REQUESTED) || !test_action_state(TOI_CAN_CANCEL))
380 return;
381
382 if (test_toi_state(TOI_NOW_RESUMING)) {
383 toi_prepare_status(CLEAR_BAR, "Escape pressed. " "Powering down again.");
384 set_toi_state(TOI_STOP_RESUME);
385 while (!test_toi_state(TOI_IO_STOPPED))
386 schedule();
387 if (toiActiveAllocator->mark_resume_attempted)
388 toiActiveAllocator->mark_resume_attempted(0);
389 toi_power_down();
390 }
391
392 toi_prepare_status(CLEAR_BAR, "--- ESCAPE PRESSED :" " ABORTING HIBERNATION ---");
393 set_abort_result(TOI_ABORT_REQUESTED);
394 wake_up_interruptible(&userui_wait_for_key);
395}
396
397/**
398 * userui_user_rcv_msg - Receive a netlink message from userui.
399 *
400 * @skb: skb received.
401 * @nlh: Netlink header received.
402 */
403static int userui_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
404{
405 int type;
406 int *data;
407
408 type = nlh->nlmsg_type;
409
410 /* A control message: ignore them */
411 if (type < NETLINK_MSG_BASE)
412 return 0;
413
414 /* Unknown message: reply with EINVAL */
415 if (type >= USERUI_MSG_MAX)
416 return -EINVAL;
417
418 /* All operations require privileges, even GET */
419 if (!capable(CAP_NET_ADMIN))
420 return -EPERM;
421
422 /* Only allow one task to receive NOFREEZE privileges */
423 if (type == NETLINK_MSG_NOFREEZE_ME && ui_helper_data.pid != -1) {
424 printk(KERN_INFO "Got NOFREEZE_ME request when "
425 "ui_helper_data.pid is %d.\n", ui_helper_data.pid);
426 return -EBUSY;
427 }
428
429 data = (int *)NLMSG_DATA(nlh);
430
431 switch (type) {
432 case USERUI_MSG_ABORT:
433 request_abort_hibernate();
434 return 0;
435 case USERUI_MSG_GET_STATE:
436 toi_send_netlink_message(&ui_helper_data,
437 USERUI_MSG_GET_STATE, &toi_bkd.toi_action,
438 sizeof(toi_bkd.toi_action));
439 return 0;
440 case USERUI_MSG_GET_DEBUG_STATE:
441 toi_send_netlink_message(&ui_helper_data,
442 USERUI_MSG_GET_DEBUG_STATE,
443 &toi_bkd.toi_debug_state, sizeof(toi_bkd.toi_debug_state));
444 return 0;
445 case USERUI_MSG_SET_STATE:
446 if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
447 return -EINVAL;
448 ui_nl_set_state(*data);
449 return 0;
450 case USERUI_MSG_SET_DEBUG_STATE:
451 if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
452 return -EINVAL;
453 toi_bkd.toi_debug_state = (*data);
454 return 0;
455 case USERUI_MSG_SPACE:
456 wake_up_interruptible(&userui_wait_for_key);
457 return 0;
458 case USERUI_MSG_GET_POWERDOWN_METHOD:
459 toi_send_netlink_message(&ui_helper_data,
460 USERUI_MSG_GET_POWERDOWN_METHOD,
461 &toi_poweroff_method, sizeof(toi_poweroff_method));
462 return 0;
463 case USERUI_MSG_SET_POWERDOWN_METHOD:
464 if (nlh->nlmsg_len != NLMSG_LENGTH(sizeof(char)))
465 return -EINVAL;
466 toi_poweroff_method = (unsigned long)(*data);
467 return 0;
468 case USERUI_MSG_GET_LOGLEVEL:
469 toi_send_netlink_message(&ui_helper_data,
470 USERUI_MSG_GET_LOGLEVEL,
471 &toi_bkd.toi_default_console_level,
472 sizeof(toi_bkd.toi_default_console_level));
473 return 0;
474 case USERUI_MSG_SET_LOGLEVEL:
475 if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int)))
476 return -EINVAL;
477 toi_bkd.toi_default_console_level = (*data);
478 return 0;
479 case USERUI_MSG_PRINTK:
480 printk(KERN_INFO "%s", (char *)data);
481 return 0;
482 }
483
484 /* Unhandled here */
485 return 1;
486}
487
488/**
489 * userui_cond_pause - Possibly pause at user request.
490 *
491 * @pause: Whether to pause or just display the message.
492 * @message: Message to display at the start of pausing.
493 *
494 * Potentially pause and wait for the user to tell us to continue. We normally
495 * only pause when @pause is set. While paused, the user can do things like
496 * changing the loglevel, toggling the display of debugging sections and such
497 * like.
498 */
499static void userui_cond_pause(int pause, char *message)
500{
501 int displayed_message = 0, last_key = 0;
502
503 while (last_key != 32 &&
504 ui_helper_data.pid != -1 &&
505 ((test_action_state(TOI_PAUSE) && pause) || (test_action_state(TOI_SINGLESTEP)))) {
506 if (!displayed_message) {
507 toi_prepare_status(DONT_CLEAR_BAR,
508 "%s Press SPACE to continue.%s",
509 message ? message : "",
510 (test_action_state(TOI_SINGLESTEP)) ?
511 " Single step on." : "");
512 displayed_message = 1;
513 }
514 last_key = userui_wait_for_keypress(0);
515 }
516 schedule();
517}
518
519/**
520 * userui_prepare_console - Prepare the console for use.
521 *
522 * Prepare a console for use, saving current kmsg settings and attempting to
523 * start userui. Console loglevel changes are handled by userui.
524 */
525static void userui_prepare_console(void)
526{
527 orig_kmsg = vt_kmsg_redirect(fg_console + 1);
528
529 ui_helper_data.pid = -1;
530
531 if (!userui_ops.enabled) {
532 printk(KERN_INFO "TuxOnIce: Userui disabled.\n");
533 return;
534 }
535
536 if (*ui_helper_data.program)
537 toi_netlink_setup(&ui_helper_data);
538 else
539 printk(KERN_INFO "TuxOnIce: Userui program not configured.\n");
540}
541
542/**
543 * userui_cleanup_console - Cleanup after a cycle.
544 *
545 * Tell userui to cleanup, and restore kmsg_redirect to its original value.
546 */
547
548static void userui_cleanup_console(void)
549{
550 if (ui_helper_data.pid > -1)
551 toi_netlink_close(&ui_helper_data);
552
553 vt_kmsg_redirect(orig_kmsg);
554}
555
556/*
557 * User interface specific /sys/power/tuxonice entries.
558 */
559
560static struct toi_sysfs_data sysfs_params[] = {
561#if defined(CONFIG_NET) && defined(CONFIG_SYSFS)
562 SYSFS_BIT("enable_escape", SYSFS_RW, &toi_bkd.toi_action,
563 TOI_CAN_CANCEL, 0),
564 SYSFS_BIT("pause_between_steps", SYSFS_RW, &toi_bkd.toi_action,
565 TOI_PAUSE, 0),
566 SYSFS_INT("enabled", SYSFS_RW, &userui_ops.enabled, 0, 1, 0, NULL),
567 SYSFS_INT("progress_granularity", SYSFS_RW, &progress_granularity, 1,
568 2048, 0, NULL),
569 SYSFS_STRING("program", SYSFS_RW, ui_helper_data.program, 255, 0,
570 set_ui_program_set),
571 SYSFS_INT("debug", SYSFS_RW, &ui_helper_data.debug, 0, 1, 0, NULL)
572#endif
573};
574
575static struct toi_module_ops userui_ops = {
576 .type = MISC_MODULE,
577 .name = "userui",
578 .shared_directory = "user_interface",
579 .module = THIS_MODULE,
580 .storage_needed = userui_storage_needed,
581 .save_config_info = userui_save_config_info,
582 .load_config_info = userui_load_config_info,
583 .memory_needed = userui_memory_needed,
584 .post_atomic_restore = userui_post_atomic_restore,
585 .sysfs_data = sysfs_params,
586 .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct toi_sysfs_data),
587};
588
589static struct ui_ops my_ui_ops = {
590 .update_status = userui_update_status,
591 .message = userui_message,
592 .prepare_status = userui_prepare_status,
593 .abort = userui_abort_hibernate,
594 .cond_pause = userui_cond_pause,
595 .prepare = userui_prepare_console,
596 .cleanup = userui_cleanup_console,
597 .wait_for_key = userui_wait_for_keypress,
598};
599
600/**
601 * toi_user_ui_init - Boot time initialisation for user interface.
602 *
603 * Invoked from the core init routine.
604 */
605static __init int toi_user_ui_init(void)
606{
607 int result;
608
609 ui_helper_data.nl = NULL;
610 strncpy(ui_helper_data.program, CONFIG_TOI_USERUI_DEFAULT_PATH, 255);
611 ui_helper_data.pid = -1;
612 ui_helper_data.skb_size = sizeof(struct userui_msg_params);
613 ui_helper_data.pool_limit = 6;
614 ui_helper_data.netlink_id = NETLINK_TOI_USERUI;
615 ui_helper_data.name = "userspace ui";
616 ui_helper_data.rcv_msg = userui_user_rcv_msg;
617 ui_helper_data.interface_version = 8;
618 ui_helper_data.must_init = 0;
619 ui_helper_data.not_ready = userui_cleanup_console;
620 init_completion(&ui_helper_data.wait_for_process);
621 result = toi_register_module(&userui_ops);
622 if (!result)
623 result = toi_register_ui_ops(&my_ui_ops);
624 if (result)
625 toi_unregister_module(&userui_ops);
626
627 return result;
628}
629
630#ifdef MODULE
631/**
632 * toi_user_ui_ext - Cleanup code for if the core is unloaded.
633 */
634static __exit void toi_user_ui_exit(void)
635{
636 toi_netlink_close_complete(&ui_helper_data);
637 toi_remove_ui_ops(&my_ui_ops);
638 toi_unregister_module(&userui_ops);
639}
640module_init(toi_user_ui_init);
641module_exit(toi_user_ui_exit);
642MODULE_AUTHOR("Nigel Cunningham");
643MODULE_DESCRIPTION("TuxOnIce Userui Support");
644MODULE_LICENSE("GPL");
645#else
646late_initcall(toi_user_ui_init);
647#endif