Initialize Tizen 2.3
[framework/system/deviced.git] / src / display / poll.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 /**
21  * @file        poll.c
22  * @brief        Power Manager poll implementation (input devices & a domain socket file)
23  *
24  * This file includes the input device poll implementation.
25  * Default input devices are /dev/event0 and /dev/event1
26  * User can use "PM_INPUT" for setting another input device poll in an environment file (/etc/profile).
27  * (ex: PM_INPUT=/dev/event0:/dev/event1:/dev/event5 )
28  */
29
30 #include <stdio.h>
31 #include <poll.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <stdlib.h>
38 #include <sys/socket.h>
39 #include <sys/un.h>
40 #include <Ecore.h>
41 #include <core/devices.h>
42 #include <core/device-handler.h>
43 #include "util.h"
44 #include "core.h"
45 #include "poll.h"
46
47 #define SHIFT_UNLOCK                    4
48 #define SHIFT_UNLOCK_PARAMETER          12
49 #define SHIFT_CHANGE_STATE              8
50 #define SHIFT_CHANGE_TIMEOUT            20
51 #define LOCK_FLAG_SHIFT                 16
52 #define __HOLDKEY_BLOCK_BIT              0x1
53 #define __STANDBY_MODE_BIT               0x2
54 #define HOLDKEY_BLOCK_BIT               (__HOLDKEY_BLOCK_BIT << LOCK_FLAG_SHIFT)
55 #define STANDBY_MODE_BIT                (__STANDBY_MODE_BIT << LOCK_FLAG_SHIFT)
56
57 #define DEV_PATH_DLM    ":"
58
59 PMMsg recv_data;
60 int (*g_pm_callback) (int, PMMsg *);
61
62 #ifdef ENABLE_KEY_FILTER
63 extern int check_key_filter(int length, char buf[], int fd);
64 #  define CHECK_KEY_FILTER(a, b, c) \
65         do { \
66                 if (CHECK_OPS(keyfilter_ops, check) && \
67                     keyfilter_ops->check(a, b, c) != 0) \
68                         return EINA_TRUE;\
69         } while (0);
70 #else
71 #  define CHECK_KEY_FILTER(a, b, c)
72 #endif
73
74 #define DEFAULT_DEV_PATH "/dev/event1:/dev/event0"
75
76 static Eina_Bool pm_handler(void *data, Ecore_Fd_Handler *fd_handler)
77 {
78         char buf[1024];
79         struct sockaddr_un clientaddr;
80
81         int fd = (int)data;
82         int ret;
83         static const struct device_ops *display_device_ops;
84
85         if (!display_device_ops) {
86                 display_device_ops = find_device("display");
87                 if (!display_device_ops)
88                         return -ENODEV;
89         }
90
91         if (device_get_status(display_device_ops) != DEVICE_OPS_STATUS_START) {
92                 _E("display is not started!");
93                 return EINA_FALSE;
94         }
95
96         if (g_pm_callback == NULL) {
97                 return EINA_FALSE;
98         }
99
100         ret = read(fd, buf, sizeof(buf));
101         CHECK_KEY_FILTER(ret, buf, fd);
102         (*g_pm_callback) (INPUT_POLL_EVENT, NULL);
103
104         return EINA_TRUE;
105 }
106
107 int init_pm_poll(int (*pm_callback) (int, PMMsg *))
108 {
109         char *dev_paths, *path_tok, *pm_input_env, *save_ptr;
110         int dev_paths_size;
111
112         Ecore_Fd_Handler *fd_handler;
113         int fd = -1;
114         indev *new_dev = NULL;
115
116         g_pm_callback = pm_callback;
117
118         _I("initialize pm poll - input devices(deviced)");
119
120         pm_input_env = getenv("PM_INPUT");
121         if ((pm_input_env != NULL) && (strlen(pm_input_env) < 1024)) {
122                 _I("Getting input device path from environment: %s",
123                        pm_input_env);
124                 /* Add 2 bytes for following strncat() */
125                 dev_paths_size =  strlen(pm_input_env) + 1;
126                 dev_paths = (char *)malloc(dev_paths_size);
127                 if (!dev_paths) {
128                         _E("Fail to malloc for dev path");
129                         return -ENOMEM;
130                 }
131                 snprintf(dev_paths, dev_paths_size, "%s", pm_input_env);
132         } else {
133                 /* Add 2 bytes for following strncat() */
134                 dev_paths_size = strlen(DEFAULT_DEV_PATH) + 1;
135                 dev_paths = (char *)malloc(dev_paths_size);
136                 if (!dev_paths) {
137                         _E("Fail to malloc for dev path");
138                         return -ENOMEM;
139                 }
140                 snprintf(dev_paths, dev_paths_size, "%s", DEFAULT_DEV_PATH);
141         }
142
143         /* add the UNIX domain socket file path */
144         strncat(dev_paths, DEV_PATH_DLM, strlen(DEV_PATH_DLM));
145         dev_paths[dev_paths_size - 1] = '\0';
146
147         path_tok = strtok_r(dev_paths, DEV_PATH_DLM, &save_ptr);
148         if (path_tok == NULL) {
149                 _E("Device Path Tokeninzing Failed");
150                 free(dev_paths);
151                 return -1;
152         }
153
154         do {
155                 char *path, *new_path;
156                 int len;
157
158                 fd = open(path_tok, O_RDONLY);
159                 path = path_tok;
160                 _I("pm_poll input device file: %s, fd: %d", path_tok, fd);
161
162                 if (fd == -1) {
163                         _E("Cannot open the file: %s", path_tok);
164                         goto out1;
165                 }
166
167                 fd_handler = ecore_main_fd_handler_add(fd,
168                                     ECORE_FD_READ|ECORE_FD_ERROR,
169                                     pm_handler, (void *)fd, NULL, NULL);
170                 if (fd_handler == NULL) {
171                         _E("Failed ecore_main_handler_add() in init_pm_poll()");
172                         goto out2;
173                 }
174
175                 new_dev = (indev *)malloc(sizeof(indev));
176
177                 if (!new_dev) {
178                         _E("Fail to malloc for new_dev %s", path);
179                         goto out3;
180                 }
181
182                 memset(new_dev, 0, sizeof(indev));
183
184                 len = strlen(path) + 1;
185                 new_path = (char*) malloc(len);
186                 if (!new_path) {
187                         _E("Fail to malloc for dev_path %s", path);
188                         goto out4;
189                 }
190
191                 strncpy(new_path, path, len);
192                 new_dev->dev_path = new_path;
193                 new_dev->fd = fd;
194                 new_dev->dev_fd = fd_handler;
195                 new_dev->pre_install = true;
196                 indev_list = eina_list_append(indev_list, new_dev);
197
198         } while ((path_tok = strtok_r(NULL, DEV_PATH_DLM, &save_ptr)));
199
200         free(dev_paths);
201         return 0;
202
203 out4:
204         free(new_dev);
205 out3:
206         ecore_main_fd_handler_del(fd_handler);
207 out2:
208         close(fd);
209 out1:
210         free(dev_paths);
211
212         return -ENOMEM;
213 }
214
215 int exit_pm_poll(void)
216 {
217         Eina_List *l = NULL;
218         Eina_List *l_next = NULL;
219         indev *data = NULL;
220
221         EINA_LIST_FOREACH_SAFE(indev_list, l, l_next, data) {
222                 ecore_main_fd_handler_del(data->dev_fd);
223                 close(data->fd);
224                 free(data->dev_path);
225                 free(data);
226                 indev_list = eina_list_remove_list(indev_list, l);
227         }
228
229         _I("pm_poll is finished");
230         return 0;
231 }
232
233 int init_pm_poll_input(int (*pm_callback)(int , PMMsg * ), const char *path)
234 {
235         indev *new_dev = NULL;
236         indev *data = NULL;
237         Ecore_Fd_Handler *fd_handler = NULL;
238         Eina_List *l = NULL;
239         Eina_List *l_next = NULL;
240         int fd = -1;
241         char *dev_path = NULL;
242
243         if (!pm_callback || !path) {
244                 _E("argument is NULL! (%x,%x)", pm_callback, path);
245                 return -1;
246         }
247
248         EINA_LIST_FOREACH_SAFE(indev_list, l, l_next, data)
249                 if(!strcmp(path, data->dev_path)) {
250                         _E("%s is already polled!", path);
251                         return -1;
252                 }
253
254         _I("initialize pm poll for bt %s", path);
255
256         g_pm_callback = pm_callback;
257
258         fd = open(path, O_RDONLY);
259         if (fd == -1) {
260                 _E("Cannot open the file for BT: %s", path);
261                 return -1;
262         }
263
264         dev_path = (char*)malloc(strlen(path) + 1);
265         if (!dev_path) {
266                 _E("Fail to malloc for dev_path");
267                 close(fd);
268                 return -1;
269         }
270         strncpy(dev_path, path, strlen(path) +1);
271
272         fd_handler = ecore_main_fd_handler_add(fd,
273                             ECORE_FD_READ|ECORE_FD_ERROR,
274                             pm_handler, (void *)fd, NULL, NULL);
275         if (!fd_handler) {
276                 _E("Fail to ecore fd handler add! %s", path);
277                 close(fd);
278                 free(dev_path);
279                 return -1;
280         }
281
282         new_dev = (indev *)malloc(sizeof(indev));
283         if (!new_dev) {
284                 _E("Fail to malloc for new_dev %s", path);
285                 ecore_main_fd_handler_del(fd_handler);
286                 close(fd);
287                 free(dev_path);
288                 return -1;
289         }
290         new_dev->dev_path = dev_path;
291         new_dev->fd = fd;
292         new_dev->dev_fd = fd_handler;
293         new_dev->pre_install = false;
294
295         _I("pm_poll for BT input device file(path: %s, fd: %d",
296                     new_dev->dev_path, new_dev->fd);
297         indev_list = eina_list_append(indev_list, new_dev);
298
299         return 0;
300 }
301
302 int check_pre_install(int fd)
303 {
304         indev *data = NULL;
305         Eina_List *l = NULL;
306         Eina_List *l_next = NULL;
307
308         EINA_LIST_FOREACH_SAFE(indev_list, l, l_next, data)
309                 if(fd == data->fd) {
310                         return data->pre_install;
311                 }
312
313         return -ENODEV;
314 }
315
316 int check_dimstay(int next_state, int flag)
317 {
318         if (next_state != LCD_OFF)
319                 return false;
320
321         if (!(flag & GOTO_STATE_NOW))
322                 return false;
323
324         if (!(pm_status_flag & DIMSTAY_FLAG))
325                 return false;
326
327         if (check_abnormal_popup() != HEALTH_BAD)
328                 return false;
329
330         return true;
331 }
332
333 int pm_lock_internal(pid_t pid, int s_bits, int flag, int timeout)
334 {
335         if (!g_pm_callback)
336                 return -1;
337
338         switch (s_bits) {
339         case LCD_NORMAL:
340         case LCD_DIM:
341         case LCD_OFF:
342                 break;
343         default:
344                 return -1;
345         }
346         if (flag & GOTO_STATE_NOW)
347                 /* if the flag is true, go to the locking state directly */
348                 s_bits = s_bits | (s_bits << SHIFT_CHANGE_STATE);
349
350         if (flag & HOLD_KEY_BLOCK)
351                 s_bits = s_bits | HOLDKEY_BLOCK_BIT;
352
353         if (flag & STANDBY_MODE)
354                 s_bits = s_bits | STANDBY_MODE_BIT;
355
356         recv_data.pid = pid;
357         recv_data.cond = s_bits;
358         recv_data.timeout = timeout;
359
360         (*g_pm_callback)(PM_CONTROL_EVENT, &recv_data);
361
362         return 0;
363 }
364
365 int pm_unlock_internal(pid_t pid, int s_bits, int flag)
366 {
367         if (!g_pm_callback)
368                 return -1;
369
370         switch (s_bits) {
371         case LCD_NORMAL:
372         case LCD_DIM:
373         case LCD_OFF:
374                 break;
375         default:
376                 return -1;
377         }
378
379         s_bits = (s_bits << SHIFT_UNLOCK);
380         s_bits = (s_bits | (flag << SHIFT_UNLOCK_PARAMETER));
381
382         recv_data.pid = pid;
383         recv_data.cond = s_bits;
384
385         (*g_pm_callback)(PM_CONTROL_EVENT, &recv_data);
386
387         return 0;
388 }
389
390 int pm_change_internal(pid_t pid, int s_bits)
391 {
392         if (!g_pm_callback)
393                 return -1;
394
395         switch (s_bits) {
396         case LCD_NORMAL:
397         case LCD_DIM:
398         case LCD_OFF:
399         case SUSPEND:
400                 break;
401         default:
402                 return -1;
403         }
404
405         recv_data.pid = pid;
406         recv_data.cond = s_bits << SHIFT_CHANGE_STATE;
407
408         (*g_pm_callback)(PM_CONTROL_EVENT, &recv_data);
409
410         return 0;
411 }
412