blob: dbb878acbaf481a2eb1b542d2120e8f975a8b4d6 [file] [log] [blame]
Christopher Ferris20303f82014-01-10 16:33:16 -08001/*
2 * Copyright (C) 2014 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
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070017#include <dirent.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <linux/input.h>
21#include <stdint.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080022#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080025#include <sys/inotify.h>
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070026#include <sys/ioctl.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080027#include <sys/limits.h>
28#include <sys/poll.h>
Mark Salyzyncfd5b082016-10-17 14:28:00 -070029#include <unistd.h>
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070030
James Hawkins588a2ca2016-02-18 14:52:46 -080031#include <memory>
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070032
33#include <android/log.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080034
Christopher Ferris20303f82014-01-10 16:33:16 -080035static struct pollfd* ufds;
36static char** device_names;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080037static int nfds;
38
Christopher Ferris20303f82014-01-10 16:33:16 -080039static int open_device(const char* device) {
40 int version;
41 int fd;
42 struct pollfd* new_ufds;
43 char** new_device_names;
44 char name[80];
45 char location[80];
46 char idstr[80];
47 struct input_id id;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080048
Christopher Ferris20303f82014-01-10 16:33:16 -080049 fd = open(device, O_RDWR);
50 if (fd < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080051 return -1;
Christopher Ferris20303f82014-01-10 16:33:16 -080052 }
53
54 if (ioctl(fd, EVIOCGVERSION, &version)) {
55 return -1;
56 }
57 if (ioctl(fd, EVIOCGID, &id)) {
58 return -1;
59 }
60 name[sizeof(name) - 1] = '\0';
61 location[sizeof(location) - 1] = '\0';
62 idstr[sizeof(idstr) - 1] = '\0';
63 if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
64 name[0] = '\0';
65 }
66 if (ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
67 location[0] = '\0';
68 }
69 if (ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
70 idstr[0] = '\0';
71 }
72
73 new_ufds = reinterpret_cast<pollfd*>(realloc(ufds, sizeof(ufds[0]) * (nfds + 1)));
74 if (new_ufds == NULL) {
75 fprintf(stderr, "out of memory\n");
76 return -1;
77 }
78 ufds = new_ufds;
79 new_device_names = reinterpret_cast<char**>(realloc(
80 device_names, sizeof(device_names[0]) * (nfds + 1)));
81 if (new_device_names == NULL) {
82 fprintf(stderr, "out of memory\n");
83 return -1;
84 }
85 device_names = new_device_names;
86 ufds[nfds].fd = fd;
87 ufds[nfds].events = POLLIN;
88 device_names[nfds] = strdup(device);
89 nfds++;
90
91 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080092}
93
Christopher Ferris20303f82014-01-10 16:33:16 -080094int close_device(const char* device) {
95 int i;
96 for (i = 1; i < nfds; i++) {
97 if (strcmp(device_names[i], device) == 0) {
98 int count = nfds - i - 1;
99 free(device_names[i]);
100 memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
101 memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
102 nfds--;
103 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800104 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800105 }
106 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800107}
108
Christopher Ferris20303f82014-01-10 16:33:16 -0800109static int read_notify(const char* dirname, int nfd) {
110 int res;
111 char devname[PATH_MAX];
112 char* filename;
113 char event_buf[512];
114 int event_size;
115 int event_pos = 0;
116 struct inotify_event *event;
117
118 res = read(nfd, event_buf, sizeof(event_buf));
119 if (res < (int)sizeof(*event)) {
120 if (errno == EINTR)
121 return 0;
122 fprintf(stderr, "could not get event, %s\n", strerror(errno));
123 return 1;
124 }
125
126 strcpy(devname, dirname);
127 filename = devname + strlen(devname);
128 *filename++ = '/';
129
130 while (res >= (int)sizeof(*event)) {
131 event = reinterpret_cast<struct inotify_event*>(event_buf + event_pos);
132 if (event->len) {
133 strcpy(filename, event->name);
134 if (event->mask & IN_CREATE) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800135 open_device(devname);
Christopher Ferris20303f82014-01-10 16:33:16 -0800136 } else {
137 close_device(devname);
138 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800139 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800140 event_size = sizeof(*event) + event->len;
141 res -= event_size;
142 event_pos += event_size;
143 }
144 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800145}
146
Christopher Ferris20303f82014-01-10 16:33:16 -0800147static int scan_dir(const char* dirname) {
148 char devname[PATH_MAX];
149 char* filename;
Christopher Ferris20303f82014-01-10 16:33:16 -0800150 struct dirent* de;
James Hawkins588a2ca2016-02-18 14:52:46 -0800151 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
Christopher Ferris20303f82014-01-10 16:33:16 -0800152 if (dir == NULL)
153 return -1;
154 strcpy(devname, dirname);
155 filename = devname + strlen(devname);
156 *filename++ = '/';
James Hawkins588a2ca2016-02-18 14:52:46 -0800157 while ((de = readdir(dir.get()))) {
Christopher Ferris20303f82014-01-10 16:33:16 -0800158 if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
159 (de->d_name[1] == '.' && de->d_name[2] == '\0'))
160 continue;
161 strcpy(filename, de->d_name);
162 open_device(devname);
163 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800164 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800165}
166
Christopher Ferris20303f82014-01-10 16:33:16 -0800167int init_getevent() {
168 int res;
169 const char* device_path = "/dev/input";
170
171 nfds = 1;
172 ufds = reinterpret_cast<pollfd*>(calloc(1, sizeof(ufds[0])));
173 ufds[0].fd = inotify_init();
174 ufds[0].events = POLLIN;
175
176 res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
177 if (res < 0) {
178 return 1;
179 }
180 res = scan_dir(device_path);
181 if (res < 0) {
182 return 1;
183 }
184 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800185}
186
Christopher Ferris20303f82014-01-10 16:33:16 -0800187void uninit_getevent() {
188 int i;
189 for (i = 0; i < nfds; i++) {
190 close(ufds[i].fd);
191 }
192 free(ufds);
193 ufds = 0;
194 nfds = 0;
195}
196
197int get_event(struct input_event* event, int timeout) {
198 int res;
199 int i;
200 int pollres;
201 const char* device_path = "/dev/input";
202 while (1) {
203 pollres = poll(ufds, nfds, timeout);
204 if (pollres == 0) {
205 return 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800206 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800207 if (ufds[0].revents & POLLIN) {
208 read_notify(device_path, ufds[0].fd);
209 }
210 for (i = 1; i < nfds; i++) {
211 if (ufds[i].revents) {
212 if (ufds[i].revents & POLLIN) {
213 res = read(ufds[i].fd, event, sizeof(*event));
214 if (res < static_cast<int>(sizeof(event))) {
215 fprintf(stderr, "could not get event\n");
216 return -1;
217 }
218 return 0;
219 }
220 }
221 }
222 }
223 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800224}