• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
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 #include <stdio.h>
18 #include <stdlib.h>
19 #include <fcntl.h>
20 #include <dirent.h>
21 #include <sys/epoll.h>
22 
23 #include <linux/input.h>
24 
25 #include "minui.h"
26 
27 #define MAX_DEVICES 16
28 #define MAX_MISC_FDS 16
29 
30 #define BITS_PER_LONG (sizeof(unsigned long) * 8)
31 #define BITS_TO_LONGS(x) (((x) + BITS_PER_LONG - 1) / BITS_PER_LONG)
32 
33 #define test_bit(bit, array) \
34     ((array)[(bit)/BITS_PER_LONG] & (1 << ((bit) % BITS_PER_LONG)))
35 
36 struct fd_info {
37     int fd;
38     ev_callback cb;
39     void *data;
40 };
41 
42 static int epollfd;
43 static struct epoll_event polledevents[MAX_DEVICES + MAX_MISC_FDS];
44 static int npolledevents;
45 
46 static struct fd_info ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS];
47 
48 static unsigned ev_count = 0;
49 static unsigned ev_dev_count = 0;
50 static unsigned ev_misc_count = 0;
51 
ev_init(ev_callback input_cb,void * data)52 int ev_init(ev_callback input_cb, void *data)
53 {
54     DIR *dir;
55     struct dirent *de;
56     int fd;
57     struct epoll_event ev;
58     bool epollctlfail = false;
59 
60     epollfd = epoll_create(MAX_DEVICES + MAX_MISC_FDS);
61     if (epollfd == -1)
62         return -1;
63 
64     dir = opendir("/dev/input");
65     if(dir != 0) {
66         while((de = readdir(dir))) {
67             unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
68 
69 //            fprintf(stderr,"/dev/input/%s\n", de->d_name);
70             if(strncmp(de->d_name,"event",5)) continue;
71             fd = openat(dirfd(dir), de->d_name, O_RDONLY);
72             if(fd < 0) continue;
73 
74             /* read the evbits of the input device */
75             if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) {
76                 close(fd);
77                 continue;
78             }
79 
80             /* TODO: add ability to specify event masks. For now, just assume
81              * that only EV_KEY and EV_REL event types are ever needed. */
82             if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits)) {
83                 close(fd);
84                 continue;
85             }
86 
87             ev.events = EPOLLIN | EPOLLWAKEUP;
88             ev.data.ptr = (void *)&ev_fdinfo[ev_count];
89             if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev)) {
90                 close(fd);
91                 epollctlfail = true;
92                 continue;
93             }
94 
95             ev_fdinfo[ev_count].fd = fd;
96             ev_fdinfo[ev_count].cb = input_cb;
97             ev_fdinfo[ev_count].data = data;
98             ev_count++;
99             ev_dev_count++;
100             if(ev_dev_count == MAX_DEVICES) break;
101         }
102     }
103 
104     if (epollctlfail && !ev_count) {
105         close(epollfd);
106         epollfd = -1;
107         return -1;
108     }
109 
110     return 0;
111 }
112 
ev_add_fd(int fd,ev_callback cb,void * data)113 int ev_add_fd(int fd, ev_callback cb, void *data)
114 {
115     struct epoll_event ev;
116     int ret;
117 
118     if (ev_misc_count == MAX_MISC_FDS || cb == NULL)
119         return -1;
120 
121     ev.events = EPOLLIN | EPOLLWAKEUP;
122     ev.data.ptr = (void *)&ev_fdinfo[ev_count];
123     ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
124     if (!ret) {
125         ev_fdinfo[ev_count].fd = fd;
126         ev_fdinfo[ev_count].cb = cb;
127         ev_fdinfo[ev_count].data = data;
128         ev_count++;
129         ev_misc_count++;
130     }
131 
132     return ret;
133 }
134 
ev_get_epollfd(void)135 int ev_get_epollfd(void)
136 {
137     return epollfd;
138 }
139 
ev_exit(void)140 void ev_exit(void)
141 {
142     while (ev_count > 0) {
143         close(ev_fdinfo[--ev_count].fd);
144     }
145     ev_misc_count = 0;
146     ev_dev_count = 0;
147     close(epollfd);
148 }
149 
ev_wait(int timeout)150 int ev_wait(int timeout)
151 {
152     npolledevents = epoll_wait(epollfd, polledevents, ev_count, timeout);
153     if (npolledevents <= 0)
154         return -1;
155     return 0;
156 }
157 
ev_dispatch(void)158 void ev_dispatch(void)
159 {
160     int n;
161     int ret;
162 
163     for (n = 0; n < npolledevents; n++) {
164         struct fd_info *fdi = polledevents[n].data.ptr;
165         ev_callback cb = fdi->cb;
166         if (cb)
167             cb(fdi->fd, polledevents[n].events, fdi->data);
168     }
169 }
170 
ev_get_input(int fd,uint32_t epevents,struct input_event * ev)171 int ev_get_input(int fd, uint32_t epevents, struct input_event *ev)
172 {
173     int r;
174 
175     if (epevents & EPOLLIN) {
176         r = read(fd, ev, sizeof(*ev));
177         if (r == sizeof(*ev))
178             return 0;
179     }
180     return -1;
181 }
182 
ev_sync_key_state(ev_set_key_callback set_key_cb,void * data)183 int ev_sync_key_state(ev_set_key_callback set_key_cb, void *data)
184 {
185     unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];
186     unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
187     unsigned i;
188     int ret;
189 
190     for (i = 0; i < ev_dev_count; i++) {
191         int code;
192 
193         memset(key_bits, 0, sizeof(key_bits));
194         memset(ev_bits, 0, sizeof(ev_bits));
195 
196         ret = ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits);
197         if (ret < 0 || !test_bit(EV_KEY, ev_bits))
198             continue;
199 
200         ret = ioctl(ev_fdinfo[i].fd, EVIOCGKEY(sizeof(key_bits)), key_bits);
201         if (ret < 0)
202             continue;
203 
204         for (code = 0; code <= KEY_MAX; code++) {
205             if (test_bit(code, key_bits))
206                 set_key_cb(code, 1, data);
207         }
208     }
209 
210     return 0;
211 }
212