3 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * @brief Power Manager poll implementation (input devices & a domain socket file)
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 )
33 #include <sys/types.h>
39 #include <sys/socket.h>
46 #define DEV_PATH_DLM ":"
49 int (*g_pm_callback) (int, PMMsg *);
51 #ifdef ENABLE_KEY_FILTER
52 extern int check_key_filter(int length, char buf[]);
53 # define CHECK_KEY_FILTER(a, b) do {\
54 if (check_key_filter(a, b) != 0)\
59 # define CHECK_KEY_FILTER(a, b)
62 #define DEFAULT_DEV_PATH "/dev/event1:/dev/event0"
65 static GSourceFuncs *funcs;
68 static gboolean pm_check(GSource *src)
73 fd_list = src->poll_fds;
75 tmp = (GPollFD *) fd_list->data;
76 if ((tmp->revents & (POLLIN | POLLPRI)))
78 fd_list = fd_list->next;
84 static gboolean pm_dispatch(GSource *src, GSourceFunc callback, gpointer data)
90 static gboolean pm_prepare(GSource *src, gint *timeout)
95 gboolean pm_handler(gpointer data)
98 struct sockaddr_un clientaddr;
100 GPollFD *gpollfd = (GPollFD *) data;
102 int clilen = sizeof(clientaddr);
104 if (g_pm_callback == NULL) {
107 if (gpollfd->fd == sockfd) {
109 recvfrom(gpollfd->fd, &recv_data, sizeof(recv_data), 0,
110 (struct sockaddr *)&clientaddr,
111 (socklen_t *)&clilen);
112 (*g_pm_callback) (PM_CONTROL_EVENT, &recv_data);
114 ret = read(gpollfd->fd, buf, sizeof(buf));
115 CHECK_KEY_FILTER(ret, buf);
116 (*g_pm_callback) (INPUT_POLL_EVENT, NULL);
122 static GList *find_indev_list(char *path)
128 total = g_list_length(indev_list);
130 for (i = 0; i < total; i++) {
131 tmp = (indev*) (g_list_nth(indev_list, i)->data);
133 if (!strcmp(tmp->dev_path, path)) {
134 LOGINFO("%s is already in dev list! gfd(%d)", path, tmp->dev_fd);
135 return g_list_nth(indev_list, i);
142 static int init_sock(char *sock_path)
144 struct sockaddr_un serveraddr;
147 LOGINFO("initialize pm_socket for pm_control library");
149 if (sock_path == NULL || strcmp(sock_path, SOCK_PATH)) {
150 LOGERR("invalid sock_path= %s");
154 fd = socket(AF_UNIX, SOCK_DGRAM, 0);
156 LOGERR("socket error");
162 bzero(&serveraddr, sizeof(serveraddr));
163 serveraddr.sun_family = AF_UNIX;
164 strncpy(serveraddr.sun_path, sock_path, sizeof(serveraddr.sun_path) - 1);
166 if (bind(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) {
167 LOGERR("bind error");
172 if (chmod(sock_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) /* 0777 */
173 LOGERR("failed to change the socket permission");
175 if (!strcmp(sock_path, SOCK_PATH))
178 LOGINFO("init sock() sueccess!");
182 int init_pm_poll(int (*pm_callback) (int, PMMsg *))
186 char *dev_paths, *path_tok, *pm_input_env, *save_ptr;
191 g_pm_callback = pm_callback;
194 ("initialize pm poll - input devices and domain socket(libpmapi)");
196 pm_input_env = getenv("PM_INPUT");
197 if ((pm_input_env != NULL) && (strlen(pm_input_env) < 1024)) {
198 LOGINFO("Getting input device path from environment: %s",
200 /* Add 2 bytes for following strncat() */
201 dev_paths_size = strlen(pm_input_env) + strlen(SOCK_PATH) + strlen(DEV_PATH_DLM) + 1;
202 dev_paths = (char *)malloc(dev_paths_size);
203 snprintf(dev_paths, dev_paths_size, "%s", pm_input_env);
205 /* Add 2 bytes for following strncat() */
206 dev_paths_size = strlen(DEFAULT_DEV_PATH) + strlen(SOCK_PATH) + strlen(DEV_PATH_DLM) + 1;
207 dev_paths = (char *)malloc(dev_paths_size);
208 snprintf(dev_paths, dev_paths_size, "%s", DEFAULT_DEV_PATH);
211 /* add the UNIX domain socket file path */
212 strncat(dev_paths, DEV_PATH_DLM, strlen(DEV_PATH_DLM));
213 strncat(dev_paths, SOCK_PATH, strlen(SOCK_PATH));
214 dev_paths[dev_paths_size - 1] = '\0';
216 path_tok = strtok_r(dev_paths, DEV_PATH_DLM, &save_ptr);
217 if (path_tok == NULL) {
218 LOGERR("Device Path Tokeninzing Failed");
223 funcs = (GSourceFuncs *) g_malloc(sizeof(GSourceFuncs));
224 funcs->prepare = pm_prepare;
225 funcs->check = pm_check;
226 funcs->dispatch = pm_dispatch;
227 funcs->finalize = NULL;
230 indev *adddev = NULL;
231 char *path, *new_path;
234 src = g_source_new(funcs, sizeof(GSource));
236 gpollfd = (GPollFD *) g_malloc(sizeof(GPollFD));
237 gpollfd->events = POLLIN;
239 if (strcmp(path_tok, SOCK_PATH) == 0) {
240 gpollfd->fd = init_sock(SOCK_PATH);
242 LOGINFO("pm_poll domain socket file: %s, fd: %d",
243 path_tok, gpollfd->fd);
245 gpollfd->fd = open(path_tok, O_RDONLY);
247 LOGINFO("pm_poll input device file: %s, fd: %d",
248 path_tok, gpollfd->fd);
251 if (gpollfd->fd == -1) {
252 LOGERR("Cannot open the file: %s", path_tok);
257 len = strlen(path) + 1;
258 new_path = (char *) malloc(len);
260 LOGERR("Fail to alloc new path: %s", path_tok);
264 strncpy(new_path, path, len);
266 adddev = (indev *) malloc(sizeof(indev));
268 LOGERR("Fail to alloc indev: %s", path_tok);
273 adddev->dev_path = new_path;
274 adddev->dev_src = src;
275 adddev->dev_fd = gpollfd;
277 indev_list = g_list_append(indev_list, adddev);
278 LOGINFO("pm_poll for input dev file(path:%s, gsource:%d, gpollfd:%d",
279 adddev->dev_path, adddev->dev_src, adddev->dev_fd);
281 g_source_add_poll(src, gpollfd);
282 g_source_set_callback(src, (GSourceFunc) pm_handler,
283 (gpointer) gpollfd, NULL);
285 g_source_set_priority(src, G_PRIORITY_LOW);
286 ret = g_source_attach(src, NULL);
288 LOGERR("Failed g_source_attach() in init_pm_poll()");
294 } while ((path_tok = strtok_r(NULL, DEV_PATH_DLM, &save_ptr)));
305 LOGINFO("pm_poll is finished");
309 int init_pm_poll_input(int (*pm_callback)(int , PMMsg * ), const char *path)
312 indev *adddev = NULL;
314 g_pm_callback = pm_callback;
320 LOGINFO("initialize pm poll for bt %s",path);
322 if(find_indev_list(path)) {
323 LOGERR("%s is already in dev list!", path);
327 adddev=(indev *)malloc(sizeof(indev));
328 adddev->dev_fd = (GPollFD *)g_malloc(sizeof(GPollFD));
329 (adddev->dev_fd)->events = POLLIN;
330 (adddev->dev_fd)->fd = open(path, O_RDONLY);
331 if((adddev->dev_fd)->fd == -1) {
332 LOGERR("Cannot open the file for BT: %s",path);
333 g_free(adddev->dev_fd);
337 adddev->dev_path = (char *)malloc(strlen(path) + 1);
338 strncpy(adddev->dev_path, path, strlen(path) + 1);
339 adddev->dev_src = g_source_new(funcs, sizeof(GSource));
340 LOGINFO("pm_poll for BT input device file(path: %s, gsource: %d, gpollfd: %d", adddev->dev_path, adddev->dev_src, adddev->dev_fd);
341 indev_list=g_list_append(indev_list, adddev);
343 g_source_add_poll(adddev->dev_src, adddev->dev_fd);
345 g_source_set_callback(adddev->dev_src, (GSourceFunc) pm_handler, (gpointer)adddev->dev_fd, NULL);
348 g_source_set_priority(adddev->dev_src, G_PRIORITY_LOW );
350 ret = g_source_attach(adddev->dev_src, NULL);
353 LOGERR("Failed g_source_attach() in init_pm_poll()");
356 g_source_unref(adddev->dev_src);