apply FSL(Flora Software License)
[framework/system/power-manager.git] / pm_poll.c
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.tizenopensource.org/license
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15 */
16
17
18 /**
19  * @file        pm_poll.c
20  * @version     0.2
21  * @brief        Power Manager poll implementation (input devices & a domain socket file)
22  *
23  * This file includes the input device poll implementation.
24  * Default input devices are /dev/event0 and /dev/event1
25  * User can use "PM_INPUT" for setting another input device poll in an environment file (/etc/profile). 
26  * (ex: PM_INPUT=/dev/event0:/dev/event1:/dev/event5 )
27  */
28
29 #include <glib.h>
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
41 #include "util.h"
42 #include "pm_core.h"
43 #include "pm_poll.h"
44
45 #define DEV_PATH_DLM    ":"
46
47 PMMsg recv_data;
48 int (*g_pm_callback) (int, PMMsg *);
49
50 #ifdef ENABLE_KEY_FILTER
51 extern int check_key_filter(int length, char buf[]);
52 #  define CHECK_KEY_FILTER(a, b) do {\
53                                                         if (check_key_filter(a, b) != 0)\
54                                                                 return TRUE;\
55                                                         } while (0);
56
57 #else
58 #  define CHECK_KEY_FILTER(a, b)
59 #endif
60
61 #define DEFAULT_DEV_PATH "/dev/event1:/dev/event0"
62
63 static GSource *src;
64 static GSourceFuncs *funcs;
65 static int sockfd;
66
67 static gboolean pm_check(GSource *src)
68 {
69         GSList *fd_list;
70         GPollFD *tmp;
71
72         fd_list = src->poll_fds;
73         do {
74                 tmp = (GPollFD *) fd_list->data;
75                 if ((tmp->revents & (POLLIN | POLLPRI)))
76                         return TRUE;
77                 fd_list = fd_list->next;
78         } while (fd_list);
79
80         return FALSE;
81 }
82
83 static gboolean pm_dispatch(GSource *src, GSourceFunc callback, gpointer data)
84 {
85         callback(data);
86         return TRUE;
87 }
88
89 static gboolean pm_prepare(GSource *src, gint *timeout)
90 {
91         return FALSE;
92 }
93
94 gboolean pm_handler(gpointer data)
95 {
96         char buf[1024];
97         struct sockaddr_un clientaddr;
98
99         GPollFD *gpollfd = (GPollFD *) data;
100         int ret;
101         int clilen = sizeof(clientaddr);
102
103         if (g_pm_callback == NULL) {
104                 return FALSE;
105         }
106         if (gpollfd->fd == sockfd) {
107                 ret =
108                     recvfrom(gpollfd->fd, &recv_data, sizeof(recv_data), 0,
109                              (struct sockaddr *)&clientaddr,
110                              (socklen_t *)&clilen);
111                 (*g_pm_callback) (PM_CONTROL_EVENT, &recv_data);
112         } else {
113                 ret = read(gpollfd->fd, buf, sizeof(buf));
114                 CHECK_KEY_FILTER(ret, buf);
115                 (*g_pm_callback) (INPUT_POLL_EVENT, NULL);
116         }
117
118         return TRUE;
119 }
120
121 static int init_sock(char *sock_path)
122 {
123         struct sockaddr_un serveraddr;
124         int fd;
125
126         LOGINFO("initialize pm_socket for pm_control library");
127
128         if (sock_path == NULL || strcmp(sock_path, SOCK_PATH)) {
129                 LOGERR("invalid sock_path= %s");
130                 return -1;
131         }
132
133         fd = socket(AF_UNIX, SOCK_DGRAM, 0);
134         if (fd < 0) {
135                 LOGERR("socket error");
136                 return -1;
137         }
138
139         unlink(sock_path);
140
141         bzero(&serveraddr, sizeof(serveraddr));
142         serveraddr.sun_family = AF_UNIX;
143         strncpy(serveraddr.sun_path, sock_path, sizeof(serveraddr.sun_path) - 1);
144
145         if (bind(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) {
146                 LOGERR("bind error");
147                 return -1;
148         }
149
150         if (chmod(sock_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0)        /* 0777 */
151                 LOGERR("failed to change the socket permission");
152
153         if (!strcmp(sock_path, SOCK_PATH))
154                 sockfd = fd;
155
156         LOGDBG("init sock() sueccess!");
157         return fd;
158 }
159
160 int init_pm_poll(int (*pm_callback) (int, PMMsg *))
161 {
162
163         guint ret;
164         char *dev_paths, *path_tok, *pm_input_env, *save_ptr;
165         int dev_paths_size;
166
167         GPollFD *gpollfd;
168
169         g_pm_callback = pm_callback;
170
171         LOGINFO
172             ("initialize pm poll - input devices and domain socket(libpmapi)");
173
174         pm_input_env = getenv("PM_INPUT");
175         if ((pm_input_env != NULL) && (strlen(pm_input_env) < 1024)) {
176                 LOGDBG("Getting input device path from environment: %s",
177                        pm_input_env);
178                 /* Add 2 bytes for following strncat() */
179                 dev_paths_size =  strlen(pm_input_env) + strlen(SOCK_PATH) + strlen(DEV_PATH_DLM) + 1;
180                 dev_paths = (char *)malloc(dev_paths_size);
181                 snprintf(dev_paths, dev_paths_size, "%s", pm_input_env);
182         } else {
183                 /* Add 2 bytes for following strncat() */
184                 dev_paths_size = strlen(DEFAULT_DEV_PATH) + strlen(SOCK_PATH) + strlen(DEV_PATH_DLM) + 1;
185                 dev_paths = (char *)malloc(dev_paths_size);
186                 snprintf(dev_paths, dev_paths_size, "%s", DEFAULT_DEV_PATH);
187         }
188
189         /* add the UNIX domain socket file path */
190         strncat(dev_paths, DEV_PATH_DLM, strlen(DEV_PATH_DLM));
191         strncat(dev_paths, SOCK_PATH, strlen(SOCK_PATH));
192         dev_paths[dev_paths_size - 1] = '\0';
193
194         path_tok = strtok_r(dev_paths, DEV_PATH_DLM, &save_ptr);
195         if (path_tok == NULL) {
196                 LOGERR("Device Path Tokeninzing Failed");
197                 free(dev_paths);
198                 return -1;
199         }
200
201         funcs = (GSourceFuncs *) g_malloc(sizeof(GSourceFuncs));
202         funcs->prepare = pm_prepare;
203         funcs->check = pm_check;
204         funcs->dispatch = pm_dispatch;
205         funcs->finalize = NULL;
206
207         do {
208                 src = g_source_new(funcs, sizeof(GSource));
209
210                 gpollfd = (GPollFD *) g_malloc(sizeof(GPollFD));
211                 gpollfd->events = POLLIN;
212
213                 if (strcmp(path_tok, SOCK_PATH) == 0) {
214                         gpollfd->fd = init_sock(SOCK_PATH);
215                         LOGDBG("pm_poll domain socket file: %s, fd: %d",
216                                path_tok, gpollfd->fd);
217                 } else {
218                         gpollfd->fd = open(path_tok, O_RDONLY);
219                         LOGDBG("pm_poll input device file: %s, fd: %d",
220                                path_tok, gpollfd->fd);
221                 }
222
223                 if (gpollfd->fd == -1) {
224                         LOGERR("Cannot open the file: %s", path_tok);
225                         free(dev_paths);
226                         return -1;
227                 }
228                 g_source_add_poll(src, gpollfd);
229                 g_source_set_callback(src, (GSourceFunc) pm_handler,
230                                       (gpointer) gpollfd, NULL);
231
232                 g_source_set_priority(src, G_PRIORITY_LOW);
233                 ret = g_source_attach(src, NULL);
234                 if (ret == 0) {
235                         LOGERR("Failed g_source_attach() in init_pm_poll()");
236                         free(dev_paths);
237                         return -1;
238                 }
239                 g_source_unref(src);
240
241         } while ((path_tok = strtok_r(NULL, DEV_PATH_DLM, &save_ptr)));
242
243         free(dev_paths);
244         return 0;
245 }
246
247 int exit_pm_poll()
248 {
249         g_free(funcs);
250         close(sockfd);
251         unlink(SOCK_PATH);
252         LOGINFO("pm_poll is finished");
253         return 0;
254 }
255
256 int init_pm_poll_input(int (*pm_callback)(int , PMMsg * ), const char *path)
257 {
258         guint ret;
259         indev *adddev = NULL;
260
261         g_pm_callback = pm_callback;
262
263         GPollFD *gpollfd;
264         const char *devpath;
265         GSource *devsrc;
266
267         LOGINFO("initialize pm poll for bt %s",path);
268         adddev=(indev *)malloc(sizeof(indev));
269         adddev->dev_fd = (GPollFD *)g_malloc(sizeof(GPollFD));
270         (adddev->dev_fd)->events = POLLIN;
271         (adddev->dev_fd)->fd = open(path, O_RDONLY);
272         if((adddev->dev_fd)->fd == -1) {
273                 LOGERR("Cannot open the file for BT: %s",path);
274                 g_free(adddev->dev_fd);
275                 free(adddev);
276                 return -1;
277         }
278         adddev->dev_path = (char *)malloc(strlen(path) + 1);
279         strncpy(adddev->dev_path, path, strlen(path) + 1);
280         adddev->dev_src = g_source_new(funcs, sizeof(GSource));
281         LOGINFO("pm_poll for BT input device file(path: %s, gsource: %d, gpollfd: %d", adddev->dev_path, adddev->dev_src, adddev->dev_fd);
282         indev_list=g_list_append(indev_list, adddev);
283         
284         g_source_add_poll(adddev->dev_src, adddev->dev_fd);
285         
286         g_source_set_callback(adddev->dev_src, (GSourceFunc) pm_handler, (gpointer)adddev->dev_fd, NULL);
287         
288
289         g_source_set_priority(adddev->dev_src, G_PRIORITY_LOW );
290         
291         ret = g_source_attach(adddev->dev_src, NULL);
292         if(ret == 0)
293         {
294                 LOGERR("Failed g_source_attach() in init_pm_poll()");
295                 return -1;
296         }
297         g_source_unref(adddev->dev_src);
298         return 0;
299 }