copy license file to /usr/share/license
[platform/core/system/power-manager.git] / pm_core.c
1 /*
2  * power-manager
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16 */
17
18
19 /**
20  * @file        pm_core.c
21  * @version     0.2
22  * @brief       Power manager main loop.
23  *
24  * This file includes Main loop, the FSM, signal processing.
25  */
26 #include <signal.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <limits.h>
31 #include <glib.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <stdbool.h>
35 #include <time.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <heynoti.h>
40 #include <sysman.h>
41 #include <aul.h>
42 #include <vconf-keys.h>
43 #include <device-node.h>
44
45 #include "pm_core.h"
46 #include "pm_battery.h"
47
48 #define USB_CON_PIDFILE                 "/var/run/.system_server.pid"
49 #define PM_STATE_LOG_FILE               "/var/log/pm_state.log"
50 #define PM_WAKEUP_NOTI_NAME             "system_wakeup"
51 #define PM_EVENT_NOTI_NAME      "pm_event"
52 #define PM_EVENT_NOTI_PATH      "/opt/share/noti/"PM_EVENT_NOTI_NAME
53
54 /**
55  * @addtogroup POWER_MANAGER
56  * @{
57  */
58
59 #define LOCKSTATUS_TIMEOUT              3
60 #define TELEPHONY_SIGNAL_TIMEOUT        10
61
62 #define SET_BRIGHTNESS_IN_BOOTLOADER "/usr/bin/save_blenv SLP_LCD_BRIGHT"
63
64 /* default transition, action fuctions */
65 static int default_trans(int evt);
66 static int default_action(int timeout);
67 static int default_check(int next);
68
69 unsigned int status_flag;
70
71 static void (*power_saving_func) (int onoff);
72 static void reset_timeout(int timeout);
73
74 int cur_state;
75 int old_state;
76 static GMainLoop *mainloop;
77 guint timeout_src_id;
78 static time_t last_t;
79 static int pre_suspend_flag = false;
80 int system_wakeup_flag = false;
81
82 struct state states[S_END] = {
83         {S_START, default_trans, default_action, default_check,},
84         {S_NORMAL, default_trans, default_action, default_check,},
85         {S_LCDDIM, default_trans, default_action, default_check,},
86         {S_LCDOFF, default_trans, default_action, default_check,},
87         {S_SLEEP, default_trans, default_action, default_check,}
88 };
89
90 int (*pm_init_extention) (void *data);
91 void (*pm_exit_extention) (void);
92
93 static char state_string[5][10] =
94     { "S_START", "S_NORMAL", "S_LCDDIM", "S_LCDOFF", "S_SLEEP" };
95
96 static int trans_table[S_END][EVENT_END] = {
97         /* Timeout , Input */
98         {S_START, S_START},     /* S_START */
99         {S_LCDDIM, S_NORMAL},   /* S_NORMAL */
100         {S_LCDOFF, S_NORMAL},   /* S_LCDDIM */
101 #ifdef TIZEN_EMUL
102         {S_LCDOFF, S_NORMAL},   /* S_LCDOFF */
103 #else
104         {S_SLEEP, S_NORMAL},    /* S_LCDOFF */
105 #endif
106         {S_LCDOFF, S_NORMAL},   /* S_SLEEP, When wake up by devices, go lcd_off state  */
107 };
108
109 #define SHIFT_UNLOCK            4
110 #define MASK_RESET_TIMEOUT      0x8     /* 1000 */
111 #define MASK_MARGIN_TIMEOUT     (0x1 << 8)
112 #define SHIFT_CHANGE_STATE      7
113 #define CHANGE_STATE_BIT        0xF00   /* 1111 0000 0000 */
114 #define LOCK_SCREEN_TIMEOUT     5
115 #define SHIFT_HOLD_KEY_BLOCK    16
116
117 #define DEFAULT_NORMAL_TIMEOUT  30
118 #define DEFAULT_DIM_TIMEOUT             5
119 #define DEFAULT_OFF_TIMEOUT             5
120 #define GET_HOLDKEY_BLOCK_STATE(x) ((x >> SHIFT_HOLD_KEY_BLOCK) & 0x1)
121
122 static int received_sleep_cmd = 0;
123
124 typedef struct _node {
125         pid_t pid;
126         int timeout_id;
127         gboolean holdkey_block;
128         struct _node *next;
129 } Node;
130
131 static Node *cond_head[S_END];
132
133 static int refresh_app_cond()
134 {
135         trans_condition = 0;
136
137         if (cond_head[S_LCDDIM] != NULL)
138                 trans_condition = trans_condition | MASK_DIM;
139         if (cond_head[S_LCDOFF] != NULL)
140                 trans_condition = trans_condition | MASK_OFF;
141         if (cond_head[S_SLEEP] != NULL)
142                 trans_condition = trans_condition | MASK_SLP;
143
144         return 0;
145 }
146
147 static Node *find_node(enum state_t s_index, pid_t pid)
148 {
149         Node *t = cond_head[s_index];
150
151         while (t != NULL) {
152                 if (t->pid == pid)
153                         break;
154                 t = t->next;
155         }
156         return t;
157 }
158
159 static Node *add_node(enum state_t s_index, pid_t pid, int timeout_id,
160                 gboolean holdkey_block)
161 {
162         Node *n;
163
164         n = (Node *) malloc(sizeof(Node));
165         if (n == NULL) {
166                 LOGERR("Not enough memory, add cond. fail");
167                 return NULL;
168         }
169
170         n->pid = pid;
171         n->timeout_id = timeout_id;
172         n->holdkey_block = holdkey_block;
173         n->next = cond_head[s_index];
174         cond_head[s_index] = n;
175
176         refresh_app_cond();
177         return n;
178 }
179
180 static int del_node(enum state_t s_index, Node *n)
181 {
182         Node *t;
183         Node *prev;
184
185         if (n == NULL)
186                 return 0;
187
188         t = cond_head[s_index];
189         prev = NULL;
190         while (t != NULL) {
191                 if (t == n) {
192                         if (prev != NULL)
193                                 prev->next = t->next;
194                         else
195                                 cond_head[s_index] = cond_head[s_index]->next;
196                         free(t);
197                         break;
198                 }
199                 prev = t;
200                 t = t->next;
201         }
202         refresh_app_cond();
203         return 0;
204 }
205
206 static gboolean del_dim_cond(gpointer data)
207 {
208         Node *tmp = NULL;
209         LOGINFO("delete prohibit dim condition by timeout\n");
210
211         tmp = find_node(S_LCDDIM, (pid_t) data);
212         del_node(S_LCDDIM, tmp);
213
214         if (timeout_src_id == 0)
215                 states[cur_state].trans(EVENT_TIMEOUT);
216
217         return FALSE;
218 }
219
220 static gboolean del_off_cond(gpointer data)
221 {
222         Node *tmp = NULL;
223         LOGINFO("delete prohibit off condition by timeout\n");
224
225         tmp = find_node(S_LCDOFF, (pid_t) data);
226         del_node(S_LCDOFF, tmp);
227
228         if (timeout_src_id == 0)
229                 states[cur_state].trans(EVENT_TIMEOUT);
230
231         return FALSE;
232 }
233
234 static gboolean del_sleep_cond(gpointer data)
235 {
236         Node *tmp = NULL;
237         LOGINFO("delete prohibit sleep condition by timeout\n");
238
239         tmp = find_node(S_SLEEP, (pid_t) data);
240         del_node(S_SLEEP, tmp);
241
242         if (timeout_src_id == 0)
243                 states[cur_state].trans(EVENT_TIMEOUT);
244
245         sysman_inform_inactive((pid_t) data);
246         return FALSE;
247 }
248
249 /* update transition condition for application requrements */
250 static int proc_condition(PMMsg *data)
251 {
252         Node *tmp = NULL;
253         unsigned int val = data->cond;
254         pid_t pid = data->pid;
255         int cond_timeout_id = -1;
256         gboolean holdkey_block = 0;
257
258         if (val == 0)
259                 return 0;
260         /* for debug */
261         char pname[PATH_MAX];
262         char buf[PATH_MAX];
263         int fd_cmdline;
264         snprintf(buf, PATH_MAX, "/proc/%d/cmdline", pid);
265         fd_cmdline = open(buf, O_RDONLY);
266         if (fd_cmdline < 0) {
267                 snprintf(pname, PATH_MAX,
268                                 "does not exist now(may be dead without unlock)");
269         } else {
270                 read(fd_cmdline, pname, PATH_MAX);
271                 close(fd_cmdline);
272         }
273
274         if (val & MASK_DIM) {
275                 if (data->timeout > 0) {
276                         cond_timeout_id =
277                                 g_timeout_add_full(G_PRIORITY_DEFAULT,
278                                                 data->timeout,
279                                                 (GSourceFunc) del_dim_cond,
280                                                 (gpointer) pid, NULL);
281                 }
282                 holdkey_block = GET_HOLDKEY_BLOCK_STATE(val);
283                 tmp = find_node(S_LCDDIM, pid);
284                 if (tmp == NULL)
285                         add_node(S_LCDDIM, pid, cond_timeout_id, holdkey_block);
286                 else if (tmp->timeout_id > 0) {
287                         g_source_remove(tmp->timeout_id);
288                         tmp->timeout_id = cond_timeout_id;
289                         tmp->holdkey_block = holdkey_block;
290                 }
291                 /* for debug */
292                 LOGINFO("[%s] locked by pid %d - process %s\n", "S_NORMAL", pid,
293                                 pname);
294         }
295         if (val & MASK_OFF) {
296                 if (data->timeout > 0) {
297                         cond_timeout_id =
298                                 g_timeout_add_full(G_PRIORITY_DEFAULT,
299                                                 data->timeout,
300                                                 (GSourceFunc) del_off_cond,
301                                                 (gpointer) pid, NULL);
302                 }
303                 holdkey_block = GET_HOLDKEY_BLOCK_STATE(val);
304                 tmp = find_node(S_LCDOFF, pid);
305                 if (tmp == NULL)
306                         add_node(S_LCDOFF, pid, cond_timeout_id, holdkey_block);
307                 else if (tmp->timeout_id > 0) {
308                         g_source_remove(tmp->timeout_id);
309                         tmp->timeout_id = cond_timeout_id;
310                         tmp->holdkey_block = holdkey_block;
311                 }
312                 /* for debug */
313                 LOGINFO("[%s] locked by pid %d - process %s\n", "S_LCDDIM", pid,
314                                 pname);
315         }
316         if (val & MASK_SLP) {
317                 if (data->timeout > 0) {
318                         cond_timeout_id =
319                                 g_timeout_add_full(G_PRIORITY_DEFAULT,
320                                                 data->timeout,
321                                                 (GSourceFunc) del_sleep_cond,
322                                                 (gpointer) pid, NULL);
323                 }
324                 tmp = find_node(S_SLEEP, pid);
325                 if (tmp == NULL)
326                         add_node(S_SLEEP, pid, cond_timeout_id, 0);
327                 else if (tmp->timeout_id > 0) {
328                         g_source_remove(tmp->timeout_id);
329                         tmp->timeout_id = cond_timeout_id;
330                         tmp->holdkey_block = 0;
331                 }
332                 sysman_inform_active(pid);
333                 /* for debug */
334                 LOGINFO("[%s] locked by pid %d - process %s\n", "S_LCDOFF", pid,
335                                 pname);
336         }
337
338         /* UNLOCK(GRANT) condition processing */
339         val = val >> SHIFT_UNLOCK;
340         if (val & MASK_DIM) {
341                 tmp = find_node(S_LCDDIM, pid);
342                 del_node(S_LCDDIM, tmp);
343                 LOGINFO("[%s] unlocked by pid %d - process %s\n", "S_LORMAL",
344                                 pid, pname);
345         }
346         if (val & MASK_OFF) {
347                 tmp = find_node(S_LCDOFF, pid);
348                 del_node(S_LCDOFF, tmp);
349                 LOGINFO("[%s] unlocked by pid %d - process %s\n", "S_LCDDIM",
350                                 pid, pname);
351         }
352         if (val & MASK_SLP) {
353                 tmp = find_node(S_SLEEP, pid);
354                 del_node(S_SLEEP, tmp);
355                 sysman_inform_inactive(pid);
356                 LOGINFO("[%s] unlocked by pid %d - process %s\n", "S_LCDOFF",
357                                 pid, pname);
358         }
359         val = val >> 8;
360         if (val != 0) {
361                 if ((val & 0x1)) {
362                         reset_timeout(states[cur_state].timeout);
363                         LOGINFO("reset timeout\n", "S_LCDOFF", pid, pname);
364                 }
365         } else {
366                 /* guard time for suspend */
367                 if (cur_state == S_LCDOFF) {
368                         reset_timeout(5);
369                         LOGINFO("margin timeout (5 seconds)\n");
370                 }
371         }
372
373         if (timeout_src_id == 0)
374                 states[cur_state].trans(EVENT_TIMEOUT);
375
376         return 0;
377 }
378
379 static int proc_change_state(unsigned int cond)
380 {
381         int next_state = 0;
382         struct state *st;
383         int i;
384
385         for (i = S_NORMAL; i < S_END; i++) {
386                 if ((cond >> (SHIFT_CHANGE_STATE + i)) & 0x1) {
387                         next_state = i;
388                         break;
389                 }
390         }
391         LOGINFO("Change State to %s", state_string[next_state]);
392
393         switch (next_state) {
394                 case S_NORMAL:
395                 case S_LCDDIM:
396                 case S_LCDOFF:
397                         /* state transition */
398                         old_state = cur_state;
399                         cur_state = next_state;
400                         st = &states[cur_state];
401
402                         /* enter action */
403                         if (st->action) {
404                                 st->action(st->timeout);
405                         }
406                         break;
407                 case S_SLEEP:
408                         LOGINFO("Dangerous requests.");
409                         /* at first LCD_OFF and then goto sleep */
410                         /* state transition */
411                         old_state = cur_state;
412                         cur_state = S_LCDOFF;
413                         st = &states[cur_state];
414                         if (st->action) {
415                                 st->action(0);
416                         }
417                         old_state = cur_state;
418                         cur_state = S_SLEEP;
419                         st = &states[cur_state];
420                         if (st->action) {
421                                 st->action(0);
422                         }
423                         break;
424
425                 default:
426                         return -1;
427         }
428
429         return 0;
430 }
431
432 /* If some changed, return 1 */
433 int check_processes(enum state_t prohibit_state)
434 {
435         Node *t = cond_head[prohibit_state];
436         Node *tmp = NULL;
437         int ret = 0;
438
439         while (t != NULL) {
440                 if (kill(t->pid, 0) == -1) {
441                         LOGERR
442                                 ("%d process does not exist, delete the REQ - prohibit state %d ",
443                                  t->pid, prohibit_state);
444                         tmp = t;
445                         ret = 1;
446                 }
447                 t = t->next;
448
449                 if (tmp != NULL) {
450                         del_node(prohibit_state, tmp);
451                         tmp = NULL;
452                 }
453         }
454
455         return ret;
456 }
457
458 int check_holdkey_block(enum state_t state)
459 {
460         Node *t = cond_head[state];
461         int ret = 0;
462
463         LOGINFO("check holdkey block : state of %s", state_string[state]);
464
465         while(t != NULL) {
466                 if(t->holdkey_block == true) {
467                         ret = 1;
468                         LOGINFO("Hold key blocked by pid(%d)!", t->pid);
469                         break;
470                 }
471                 t = t->next;
472         }
473
474         return ret;
475 }
476
477 int delete_condition(enum state_t state)
478 {
479         Node *t = cond_head[state];
480         int ret = 0;
481         Node *tmp = NULL;
482
483         LOGINFO("delete condition : state of %s", state_string[state]);
484
485         while(t != NULL) {
486                 if(t->timeout_id > 0) {
487                         g_source_remove(t->timeout_id);
488                 }
489                 tmp = t;
490                 t = t->next;
491                 LOGINFO("delete node of pid(%d)", tmp->pid);
492                 del_node(state, tmp);
493         }
494
495         return 0;
496 }
497
498 /* SIGINT, SIGTERM, SIGQUIT signal handler */
499 static void sig_quit(int signo)
500 {
501         LOGINFO("received %d signal : stops a main loop", signo);
502         if (mainloop)
503                 g_main_loop_quit(mainloop);
504 }
505
506 void print_info(int fd)
507 {
508         int s_index = 0;
509         char buf[255];
510         int i = 1, ret;
511
512         if (fd < 0)
513                 return;
514
515         snprintf(buf, sizeof(buf), 
516                         "\n======================================================================\n");
517         write(fd, buf, strlen(buf));
518         snprintf(buf, sizeof(buf),"Timeout Info: Run[%d] Dim[%d] Off[%d]\n",
519                         states[S_NORMAL].timeout,
520                         states[S_LCDDIM].timeout, states[S_LCDOFF].timeout);
521         write(fd, buf, strlen(buf));
522
523         snprintf(buf, sizeof(buf), "Tran. Locked : %s %s %s\n",
524                         (trans_condition & MASK_DIM) ? state_string[S_NORMAL] : "-",
525                         (trans_condition & MASK_OFF) ? state_string[S_LCDDIM] : "-",
526                         (trans_condition & MASK_SLP) ? state_string[S_LCDOFF] : "-");
527         write(fd, buf, strlen(buf));
528
529         snprintf(buf, sizeof(buf), "Current State: %s\n", state_string[cur_state]);
530         write(fd, buf, strlen(buf));
531
532         snprintf(buf, sizeof(buf), "Current Lock Conditions: \n");
533         write(fd, buf, strlen(buf));
534
535         for (s_index = S_NORMAL; s_index < S_END; s_index++) {
536                 Node *t;
537                 char pname[PATH_MAX];
538                 int fd_cmdline;
539                 t = cond_head[s_index];
540
541                 while (t != NULL) {
542                         snprintf(buf, sizeof(buf), "/proc/%d/cmdline", t->pid);
543                         fd_cmdline = open(buf, O_RDONLY);
544                         if (fd_cmdline < 0) {
545                                 snprintf(pname, PATH_MAX,
546                                                 "does not exist now(may be dead without unlock)");
547                         } else {
548                                 read(fd_cmdline, pname, PATH_MAX);
549                                 close(fd_cmdline);
550                         }
551                         snprintf(buf, sizeof(buf),
552                                         " %d: [%s] locked by pid %d - process %s\n",
553                                         i++, state_string[s_index - 1], t->pid, pname);
554                         write(fd, buf, strlen(buf));
555                         t = t->next;
556                 }
557         }
558 }
559
560 /* SIGHUP signal handler 
561  * For debug... print info to syslog
562  */
563 static void sig_hup(int signo)
564 {
565         int fd;
566         char buf[255];
567         time_t now_time;
568
569         time(&now_time);
570
571         fd = open(PM_STATE_LOG_FILE, O_CREAT | O_WRONLY, 0644);
572         if (fd != -1) {
573                 snprintf(buf, sizeof(buf), "\npm_state_log now-time : %d (s)\n\n",
574                                 (int)now_time);
575                 write(fd, buf, strlen(buf));
576
577                 snprintf(buf, sizeof(buf), "status_flag: %x\n", status_flag);
578                 write(fd, buf, strlen(buf));
579
580                 snprintf(buf, sizeof(buf), "received sleep cmd count : %d\n",
581                                 received_sleep_cmd);
582                 write(fd, buf, strlen(buf));
583
584                 print_info(fd);
585                 close(fd);
586         }
587
588         fd = open("/dev/console", O_WRONLY);
589         if (fd != -1) {
590                 print_info(fd);
591                 close(fd);
592         }
593 }
594
595 /* timeout handler  */
596 gboolean timeout_handler(gpointer data)
597 {
598         LOGINFO("Time out state %s\n", state_string[cur_state]);
599
600         if (timeout_src_id != 0) {
601                 g_source_remove(timeout_src_id);
602                 timeout_src_id = 0;
603         }
604
605         if ((status_flag & VCALL_FLAG)
606                         && (cur_state == S_LCDOFF || cur_state == S_SLEEP)) {
607                 status_flag &= ~(VCALL_FLAG);
608                 reset_timeout(TELEPHONY_SIGNAL_TIMEOUT);
609                 return FALSE;
610         }
611         states[cur_state].trans(EVENT_TIMEOUT);
612         return FALSE;
613 }
614
615 static void reset_timeout(int timeout)
616 {
617         if (timeout_src_id != 0) {
618                 g_source_remove(timeout_src_id);
619                 timeout_src_id = 0;
620         }
621         if (timeout > 0) {
622                 timeout_src_id = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
623                                 timeout,
624                                 (GSourceFunc)
625                                 timeout_handler,
626                                 NULL, NULL);
627         }
628 }
629
630 static void sig_usr(int signo)
631 {
632         status_flag |= VCALL_FLAG;
633 }
634
635 static void sig_break_block(int signo)
636 {
637         LOGINFO("We got signal to break that pending checking in kernel\n");
638 }
639
640 /* 
641  * default transition function
642  *   1. call check 
643  *   2. transition 
644  *   3. call enter action function
645  */
646 static int default_trans(int evt)
647 {
648         struct state *st = &states[cur_state];
649         int next_state;
650
651         if(cur_state == S_NORMAL && st->timeout == 0) {
652                 LOGINFO("LCD always on enabled!");
653                 return 0;
654         }
655
656         next_state = (enum state_t)trans_table[cur_state][evt];
657
658         /* check conditions */
659         while (st->check && !st->check(next_state)) {
660                 /* There is a condition. */
661                 LOGINFO("%s -> %s : check fail", state_string[cur_state],
662                        state_string[next_state]);
663                 if (!check_processes(next_state)) {
664                         /* this is valid condition - the application that sent the condition is running now. */
665                         return -1;
666                 }
667         }
668
669         /* state transition */
670         old_state = cur_state;
671         cur_state = next_state;
672         st = &states[cur_state];
673
674         /* enter action */
675         if (st->action) {
676                 st->action(st->timeout);
677         }
678
679         return 0;
680 }
681
682 /* default enter action function */
683 static int default_action(int timeout)
684 {
685         int ret;
686         int wakeup_count = -1;
687         char buf[NAME_MAX];
688         char *pkgname = NULL;
689         int i = 0;
690         int lock_state = -1;
691         struct itimerval val;
692
693         if (cur_state != old_state && cur_state != S_SLEEP)
694                 set_setting_pmstate(cur_state);
695
696         switch (cur_state) {
697                 case S_NORMAL:
698                         /* normal state : backlight on and restore the previous brightness */
699                         if (old_state == S_LCDOFF || old_state == S_SLEEP) {
700                                 if (pre_suspend_flag == true) {
701                                         system_post_resume();
702                                         pre_suspend_flag = false;
703                                 }
704                                 for (i = 0; i < 14; i++) {
705                                 vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock_state);
706                                 LOGERR("Idle lock check : %d, vonf : %d", i, lock_state);
707                                         if (lock_state)
708                                                 break;
709                                         usleep(50000);
710                                 }
711 #ifndef X86 /* Different with ARM FB driver, IA gfx driver is sensitive to the order. */
712                                 backlight_restore();
713                                 backlight_on();
714 #else
715                                 backlight_on();
716                                 backlight_restore();
717 #endif
718                         } else if (old_state == S_LCDDIM)
719                                 backlight_restore();
720                         break;
721
722                 case S_LCDDIM:
723                         if (old_state == S_LCDOFF || old_state == S_SLEEP) {
724                                 backlight_on();
725                         }
726                         /* lcd dim state : dim the brightness */
727                         backlight_dim();
728                         break;
729
730                 case S_LCDOFF:
731                         if (old_state != S_SLEEP && old_state != S_LCDOFF) {
732                                 /* lcd off state : turn off the backlight */
733                                 backlight_off();
734                                 if (pre_suspend_flag == false) {
735                                         pre_suspend_flag = true;
736                                         system_pre_suspend();
737                                 }
738                         }
739                         break;
740
741                 case S_SLEEP:
742                         /*
743                          * We can not always be blocked here because of that
744                          * in-progress checking in kernel for wakeup count,
745                          * if we cannot get the result within some time, then
746                          * just give it up and then retry it in the next time,
747                          * this method would not break that original expected
748                          * 'aggresive suspend' idea, but at the same time make
749                          * the system is 'always' responsible to some keypress
750                          * actions like power button press.
751                          */
752                         val.it_value.tv_sec = TOLERANCE_SLOT;
753                         val.it_value.tv_usec = 0;
754                         val.it_interval.tv_sec = val.it_interval.tv_usec = 0;
755                         setitimer(ITIMER_REAL, &val, NULL);
756
757                         /* sleep state : set system mode to SUSPEND */
758                         if (0 > device_get_property(DEVICE_TYPE_POWER, PROP_POWER_WAKEUP_COUNT, &wakeup_count))
759                                 LOGERR("wakeup count read error");
760
761                         if (wakeup_count < 0) {
762                                 LOGINFO("Wakup Event! Can not enter suspend mode.");
763                                 goto go_lcd_off;
764                         }
765
766                         if (0 > device_set_property(DEVICE_TYPE_POWER, PROP_POWER_WAKEUP_COUNT, wakeup_count)) {
767                                 LOGERR("wakeup count write error");
768                                 goto go_lcd_off;
769                         }
770
771                         goto go_suspend;
772         }
773
774         /* set timer with current state timeout */
775         reset_timeout(timeout);
776         LOGINFO("timout set: %s state %d sec", state_string[cur_state], timeout);
777
778         return 0;
779
780 go_suspend:
781         system_suspend();
782         LOGINFO("system wakeup!!");
783         system_wakeup_flag = true;
784         heynoti_publish(PM_WAKEUP_NOTI_NAME);
785         /* Resume !! */
786         if (check_wakeup_src() == EVENT_DEVICE)
787                 /* system waked up by devices */
788                 states[cur_state].trans(EVENT_DEVICE);
789         else
790                 /* system waked up by user input */
791                 states[cur_state].trans(EVENT_INPUT);
792         return 0;
793
794 go_lcd_off:
795         heynoti_publish(PM_WAKEUP_NOTI_NAME);
796         /* Resume !! */
797         states[cur_state].trans(EVENT_DEVICE);
798         return 0;
799 }
800
801 /* 
802  * default check function
803  *   return 
804  *    0 : can't transit, others : transitable
805  */
806 static int default_check(int next)
807 {
808         int trans_cond = trans_condition & MASK_BIT;
809         int lock_state = -1;
810
811         LOGINFO("trans_cond : %x", trans_cond);
812
813         vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock_state);
814         if(lock_state==VCONFKEY_IDLE_LOCK && next != S_SLEEP) {
815                 LOGINFO("default_check : LOCK STATE, it's transitable");
816                 return 1;
817         }
818
819         switch (next) {
820                 case S_LCDDIM:
821                         trans_cond = trans_cond & MASK_DIM;
822                         break;
823                 case S_LCDOFF:
824                         trans_cond = trans_cond & MASK_OFF;
825                         break;
826                 case S_SLEEP:
827                         trans_cond = trans_cond & MASK_SLP;
828                         break;
829                 default:                /* S_NORMAL is exceptional */
830                         trans_cond = 0;
831                         break;
832         }
833
834         if (trans_cond != 0)
835                 return 0;
836
837         return 1;               /* transitable */
838 }
839
840 /* get configurations from setting */
841 static int get_settings()
842 {
843         int i;
844         int val = 0;
845         int ret = -1;
846         char buf[255];
847
848         for (i = 0; i < S_END; i++) {
849                 switch (states[i].state) {
850                         case S_NORMAL:
851                                 ret = get_run_timeout(&val);
852                                 if (ret != 0) {
853                                         ret = get_env("PM_TO_NORMAL", buf, 255);
854                                         val = atoi(buf);
855                                 }
856                                 break;
857                         case S_LCDDIM:
858                                 ret = get_dim_timeout(&val);
859                                 break;
860                         case S_LCDOFF:
861                                 ret = get_off_timeout(&val);
862                                 break;
863                         default:
864                                 /* This state doesn't need to set time out. */
865                                 ret = -1;
866                                 break;
867                 }
868                 if (ret == 0 || val < 0) {
869                         states[i].timeout = val;
870                 } else {
871                         switch (states[i].state) {
872                                 case S_NORMAL:
873                                         states[i].timeout = DEFAULT_NORMAL_TIMEOUT;
874                                         break;
875                                 case S_LCDDIM:
876                                         states[i].timeout = DEFAULT_DIM_TIMEOUT;
877                                         break;
878                                 case S_LCDOFF:
879                                         states[i].timeout = DEFAULT_OFF_TIMEOUT;
880                                         break;
881                                 default:
882                                         states[i].timeout = 0;
883                                         break;
884                         }
885                 }
886                 LOGINFO("%s state : %d timeout", state_string[i], states[i].timeout);
887         }
888
889         return 0;
890 }
891
892 static void default_saving_mode(int onoff)
893 {
894         if (onoff) {
895                 status_flag |= PWRSV_FLAG;
896         } else {
897                 status_flag &= ~PWRSV_FLAG;
898         }
899         if (cur_state == S_NORMAL)
900                 backlight_restore();
901 }
902
903 static int poll_callback(int condition, PMMsg *data)
904 {
905         time_t now;
906
907         if (condition == INPUT_POLL_EVENT) {
908                 if (cur_state == S_LCDOFF || cur_state == S_SLEEP)
909                         LOGINFO("Power key input");
910                 time(&now);
911                 if (last_t != now) {
912                         states[cur_state].trans(EVENT_INPUT);
913                         last_t = now;
914                 }
915         } else if (condition == PM_CONTROL_EVENT) {
916                 LOGINFO("process pid(%d) pm_control condition : %x ", data->pid,
917                                 data->cond);
918
919                 if (data->cond & MASK_BIT
920                                 || (data->cond >> SHIFT_UNLOCK) & MASK_BIT)
921                         proc_condition(data);
922
923                 if (data->cond & CHANGE_STATE_BIT) {
924
925                         LOGINFO("Change state by pid(%d) request.", data->pid);
926                         proc_change_state(data->cond);
927                 }
928         }
929
930         return 0;
931 }
932
933 static int update_setting(int key_idx, int val)
934 {
935         char buf[PATH_MAX];
936         int ret = -1;
937         int dim_timeout = -1;
938         int run_timeout = -1;
939         int power_saving_stat = -1;
940         int power_saving_display_stat = -1;
941
942         switch (key_idx) {
943         case SETTING_TO_NORMAL:
944                 ret = get_dim_timeout(&dim_timeout);
945                 if(ret < 0 || dim_timeout < 0) {
946                         LOGERR("Can not get dim timeout. set default 5 seconds");
947                         dim_timeout = 5;
948                 }
949                 if(val < 0) {
950                         LOGERR("LCD timeout is wrong, set default 15 seconds");
951                         val = 15;
952                 }
953                 if(val == 0) {
954                         states[S_NORMAL].timeout = 0;
955                 } else if(val > dim_timeout) {
956                         states[S_NORMAL].timeout = val - dim_timeout;
957                 } else {
958                         states[S_NORMAL].timeout = 1;
959                 }
960                 states[cur_state].trans(EVENT_INPUT);
961                 break;
962         case SETTING_LOW_BATT:
963                 if (val < VCONFKEY_SYSMAN_BAT_WARNING_LOW) {
964                         if (!(status_flag & CHRGR_FLAG))
965                                 power_saving_func(true);
966                         status_flag |= LOWBT_FLAG;
967                 } else {
968                         if (status_flag & PWRSV_FLAG)
969                                 power_saving_func(false);
970                         status_flag &= ~LOWBT_FLAG;
971                         status_flag &= ~BRTCH_FLAG;
972                         vconf_set_bool(VCONFKEY_PM_BRIGHTNESS_CHANGED_IN_LPM,
973                             false);
974                 }
975                 break;
976         case SETTING_CHARGING:
977                 if (val) {
978                         if (status_flag & LOWBT_FLAG) {
979                                 power_saving_func(false);
980                                 status_flag &= ~LOWBT_FLAG;
981                         }
982                         status_flag |= CHRGR_FLAG;
983                 } else {
984                         int bat_state = VCONFKEY_SYSMAN_BAT_NORMAL;
985                         vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &bat_state);
986                         if(bat_state < VCONFKEY_SYSMAN_BAT_NORMAL) {
987                                 power_saving_func(true);
988                                 status_flag |= LOWBT_FLAG;
989                         }
990                         status_flag &= ~CHRGR_FLAG;
991                 }
992                 break;
993         case SETTING_BRT_LEVEL:
994                 if (status_flag & PWRSV_FLAG) {
995                         status_flag |= BRTCH_FLAG;
996                         vconf_set_bool(VCONFKEY_PM_BRIGHTNESS_CHANGED_IN_LPM,
997                             true);
998                         LOGINFO("brightness changed in low battery, escape dim state");
999                 }
1000                 set_default_brt(val);
1001                 snprintf(buf, sizeof(buf), "%s %d", SET_BRIGHTNESS_IN_BOOTLOADER, val);
1002                 LOGINFO("Brightness set in bl : %d",val);
1003                 system(buf);
1004                 break;
1005         case SETTING_LOCK_SCREEN:
1006                 if (val == VCONFKEY_IDLE_LOCK) {
1007                         states[S_NORMAL].timeout = LOCK_SCREEN_TIMEOUT;
1008                         LOGERR("LCD NORMAL timeout is set by %d seconds for lock screen", LOCK_SCREEN_TIMEOUT);
1009                 } else {
1010                         get_run_timeout(&run_timeout);
1011                         if(run_timeout < 0) {
1012                                 LOGERR("Can not get run timeout. set default 15 seconds(includes dim 5 seconds)");
1013                                 run_timeout = 10;
1014                         }
1015                         states[S_NORMAL].timeout = run_timeout;
1016                         LOGINFO("LCD NORMAL timeout is set by %d seconds because phone is unlocked", run_timeout);
1017                 }
1018                 if (cur_state == S_NORMAL) {
1019                         states[cur_state].trans(EVENT_INPUT);
1020                 }
1021                 break;
1022         case SETTING_POWER_SAVING:
1023                 if (val == 1)
1024                         vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_CUSTMODE_DISPLAY, &power_saving_display_stat);
1025                 if (power_saving_display_stat != 1)
1026                         power_saving_display_stat = 0;
1027                 device_set_property(DEVICE_TYPE_DISPLAY, PROP_DISPLAY_FRAME_RATE, power_saving_display_stat);
1028                 backlight_restore();
1029                 break;
1030         case SETTING_POWER_SAVING_DISPLAY:
1031                 vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_SYSMODE_STATUS, &power_saving_stat);
1032                 if (power_saving_stat == 1) {
1033                         if (val == 1)
1034                                 power_saving_display_stat = 1;
1035                         else
1036                                 power_saving_display_stat = 0;
1037                         device_set_property(DEVICE_TYPE_DISPLAY, PROP_DISPLAY_FRAME_RATE, power_saving_display_stat);
1038                         backlight_restore();
1039                 }
1040                 break;
1041         default:
1042                 return -1;
1043         }
1044         return 0;
1045 }
1046
1047 static void check_seed_status(void)
1048 {
1049         int ret = -1;
1050         int tmp = 0;
1051         int bat_state = VCONFKEY_SYSMAN_BAT_NORMAL;
1052         int max_brt = 0;
1053         int brt = 0;
1054         int lock_state = -1;
1055
1056         /* Charging check */
1057         if ((get_charging_status(&tmp) == 0) && (tmp > 0)) {
1058                 status_flag |= CHRGR_FLAG;
1059         }
1060
1061         ret = get_setting_brightness(&tmp);
1062         if (ret != 0 || (tmp < PM_MIN_BRIGHTNESS || tmp > PM_MAX_BRIGHTNESS)) {
1063                 LOGINFO("fail to read vconf value for brightness");
1064                 brt = PM_DEFAULT_BRIGHTNESS;
1065                 if(tmp < PM_MIN_BRIGHTNESS || tmp > PM_MAX_BRIGHTNESS)
1066                         vconf_set_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS, brt);
1067                 tmp = brt;
1068         }
1069         LOGINFO("Set brightness from Setting App. %d", tmp);
1070         set_default_brt(tmp);
1071
1072         vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &bat_state);
1073         if (bat_state < VCONFKEY_SYSMAN_BAT_NORMAL) {
1074                 if (!(status_flag & CHRGR_FLAG)) {
1075                         power_saving_func(true);
1076                         status_flag |= LOWBT_FLAG;
1077                 }
1078         }
1079         backlight_restore();
1080
1081         /* USB connection check
1082          * If connected, add sleep prohibit condition */
1083         if ((get_usb_status(&tmp) == 0) && (tmp > 0)) {
1084                 tmp = readpid(USB_CON_PIDFILE);
1085                 if (tmp != -1) {
1086                         add_node(S_SLEEP, tmp, -1, 0);
1087                 }
1088         }
1089
1090         /* lock screen check */
1091         ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock_state);
1092         if(lock_state == VCONFKEY_IDLE_LOCK) {
1093                 states[S_NORMAL].timeout = LOCK_SCREEN_TIMEOUT;
1094                 LOGERR("LCD NORMAL timeout is set by %d seconds for lock screen", LOCK_SCREEN_TIMEOUT);
1095         }
1096
1097         return;
1098 }
1099
1100 enum {
1101         INIT_SETTING = 0,
1102         INIT_INTERFACE,
1103         INIT_POLL,
1104         INIT_FIFO,
1105         INIT_END
1106 };
1107
1108 static char *errMSG[INIT_END] = {
1109         [INIT_SETTING] = "setting init error",
1110         [INIT_INTERFACE] = "lowlevel interface(sysfs or others) init error",
1111         [INIT_POLL] = "input devices poll init error",
1112         [INIT_FIFO] = "FIFO poll init error",
1113 };
1114
1115 /* logging indev_list for debug */
1116 void printglist()
1117 {
1118         int i;
1119         guint total=0;
1120         indev *tmp;
1121
1122         total=g_list_length(indev_list);
1123         LOGINFO("***** total list : %d *****",total);
1124         for(i=0;i<total;i++) {
1125                 tmp=(indev*)(g_list_nth(indev_list, i)->data);
1126                 LOGINFO("* %d | path:%s, gsource:%d, gfd:%d", i, tmp->dev_path, tmp->dev_src, tmp->dev_fd);
1127                 if(i==total-1 && g_list_nth(indev_list, i)->next==NULL)
1128                         LOGINFO("okokok");
1129         }
1130         LOGINFO("***************************\n");
1131 }
1132
1133 static GList *find_glist(GList *glist, char *path)
1134 {
1135         int i;
1136         guint total=0;
1137         indev *tmp;
1138
1139         total=g_list_length(indev_list);
1140         for(i=0;i<total;i++) {
1141                 tmp=(indev*)(g_list_nth(indev_list, i)->data);
1142                 if(!strcmp(tmp->dev_path, path)){
1143                         LOGINFO("nth : %d, path:%s, gsource:%d, gfd:%d", i, tmp->dev_path, tmp->dev_src, tmp->dev_fd);
1144                         return g_list_nth(indev_list, i);
1145                 }
1146         }
1147         return NULL;
1148 }
1149
1150 static void input_cb(void* data)
1151 {
1152         FILE *fp;
1153         char input_act[NAME_MAX], input_path[MAX_INPUT];
1154         char args[NAME_MAX + MAX_INPUT];
1155         int i, ret = -1;
1156         GList *glist = NULL;
1157
1158         fp = fopen((char *) data, "r");
1159         if (fp == NULL) {
1160                 LOGERR("input file open fail");
1161                 return ;
1162         }
1163
1164         while (fgets(args, NAME_MAX + MAX_INPUT, fp) != NULL){
1165                 if( args[strlen(args)-1] != '\n'){
1166                         LOGERR("input file must be terminated with new line character\n");
1167                         break;
1168                 }
1169                 args[strlen(args) - 1] = '\0';
1170                 for(i = 0; i< NAME_MAX + MAX_INPUT; i++){
1171                         if(args[i] == ' '){
1172                                 if( i >= NAME_MAX ){
1173                                         LOGERR("bsfile name is over the name_max(255)\n");
1174                                         break;
1175                                 }
1176                                 strncpy(input_act, args, i < NAME_MAX ? i : NAME_MAX);
1177                                 input_act[i]='\0';
1178                                 strncpy(input_path, args + i + 1, MAX_INPUT);
1179                                 input_path[MAX_INPUT - 1] = '\0';
1180
1181                                 if( !strcmp("add", input_act) ){
1182                                         LOGINFO("add input path:%s",input_path);
1183
1184                                         ret=init_pm_poll_input(poll_callback, input_path);
1185
1186                                 } else if ( !strcmp("remove", input_act) ){
1187                                         glist=find_glist(indev_list, input_path);
1188                                         if(glist != NULL){
1189                                                 LOGINFO("remove input dev");
1190                                                 g_source_remove_poll(((indev*)(glist->data))->dev_src, ((indev*)(glist->data))->dev_fd);
1191                                                 g_source_destroy(((indev*)(glist->data))->dev_src);
1192                                                 close(((indev*)(glist->data))->dev_fd->fd);
1193                                                 g_free(((indev*)(glist->data))->dev_fd);
1194                                                 free(((indev*)(glist->data))->dev_path);
1195                                                 indev_list=g_list_remove(indev_list, glist->data);
1196                                         }
1197                                         ret=0;
1198                                 }
1199                                 /* debug */
1200                                 printglist();
1201
1202                                 break;
1203                         }
1204                 }
1205                 if(ret<0)
1206                         break;
1207         }
1208         fclose(fp);
1209
1210         if ( ret != -1) {
1211                 fp = fopen((char *) data, "w");
1212                 if (fp == NULL) {
1213                         return ;
1214                 }
1215                 fclose(fp);
1216         }
1217
1218         return ;
1219 }
1220
1221 static int set_noti(int *noti_fd)
1222 {
1223         int fd;
1224         char buf[PATH_MAX];
1225
1226         fd = heynoti_init();
1227         if (fd < 0) {
1228                 LOGERR("heynoti_init error");
1229                 return -1;
1230         }
1231
1232         if (heynoti_subscribe(fd, PM_EVENT_NOTI_NAME, input_cb, PM_EVENT_NOTI_PATH) < 0) {
1233                 LOGERR("input file change noti add failed(%s). %s", buf, strerror(errno));
1234                 return -1;
1235         } else {
1236                 LOGERR("input file change noti add ok");
1237         }
1238
1239         if (heynoti_attach_handler(fd) < 0) {
1240                 LOGERR("heynoti_attach_handler error");
1241                 return -1;
1242         }
1243
1244         *noti_fd = fd;
1245         return 0;
1246 }
1247
1248 static int unset_noti(int noti_fd)
1249 {
1250         if (noti_fd < 0) {
1251                 LOGINFO("set noti already failed. nothing to do in unset");
1252                 return 0;
1253         }
1254
1255         if (heynoti_unsubscribe(noti_fd, PM_EVENT_NOTI_NAME, input_cb) < 0 || heynoti_detach_handler(noti_fd) < 0) {
1256                 LOGERR("heynoti unsubsribe or detach error");
1257                 return -1;
1258         }
1259         return 0;
1260 }
1261
1262 /**
1263  * Power manager Main loop
1264  *
1265  * @internal
1266  * @param[in] flags If the first bit of this is set, start managing without Start notification.
1267  *                                      If the second bit of ths is set, use unified device manager functions.
1268  */
1269 void start_main(unsigned int flags)
1270 {
1271         int ret, i;
1272
1273         LOGINFO("Start power manager daemon");
1274
1275         signal(SIGINT, sig_quit);
1276         signal(SIGTERM, sig_quit);
1277         signal(SIGQUIT, sig_quit);
1278         signal(SIGHUP, sig_hup);
1279         signal(SIGCHLD, SIG_IGN);
1280         signal(SIGUSR1, sig_usr);
1281         signal(SIGALRM, sig_break_block);
1282
1283         mainloop = g_main_loop_new(NULL, FALSE);
1284         power_saving_func = default_saving_mode;
1285
1286         /* noti init for new input device like bt mouse */
1287         int noti_fd = -1;
1288         indev_list=NULL;
1289         set_noti(&noti_fd);
1290
1291         for (i = INIT_SETTING; i < INIT_END; i++) {
1292                 switch (i) {
1293                         case INIT_SETTING:
1294                                 ret = init_setting(update_setting);
1295                                 break;
1296                         case INIT_INTERFACE:
1297                                 get_settings();
1298                                 ret = init_sysfs(flags);
1299                                 break;
1300                         case INIT_POLL:
1301                                 LOGINFO("poll init");
1302                                 ret = init_pm_poll(poll_callback);
1303                                 break;
1304                 }
1305                 if (ret != 0) {
1306                         LOGERR(errMSG[i]);
1307                         break;
1308                 }
1309         }
1310
1311         if (i == INIT_END) {
1312                 check_seed_status();
1313
1314                 if (pm_init_extention != NULL)
1315                         pm_init_extention(NULL);
1316
1317                 if (flags & WITHOUT_STARTNOTI) {        /* start without noti */
1318                         LOGINFO("Start Power managing without noti");
1319                         cur_state = S_NORMAL;
1320                         set_setting_pmstate(cur_state);
1321                         reset_timeout(states[S_NORMAL].timeout);
1322                 }
1323                 if (start_battinfo_gathering(BATTERY_POLLING_PERIOD) < 0)
1324                         LOGERR("Start Battery time info failed!");
1325
1326                 g_main_loop_run(mainloop);
1327                 g_main_loop_unref(mainloop);
1328         }
1329
1330         end_battinfo_gathering();
1331         for (i = i - 1; i >= INIT_SETTING; i--) {
1332                 switch (i) {
1333                         case INIT_SETTING:
1334                                 exit_setting();
1335                                 break;
1336                         case INIT_INTERFACE:
1337                                 exit_sysfs();
1338                                 break;
1339                         case INIT_POLL:
1340                                 unset_noti(noti_fd);
1341                                 exit_pm_poll();
1342                                 break;
1343                 }
1344         }
1345
1346         if (pm_exit_extention != NULL)
1347                 pm_exit_extention();
1348
1349         LOGINFO("Terminate power manager daemon");
1350 }
1351
1352 /**
1353  * @}
1354  */