blob: dfa7bec0268687081184555d8cf472df4ffe3ac2 [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 Salyzyn66ce3e02016-09-28 10:07:20 -070029
James Hawkins588a2ca2016-02-18 14:52:46 -080030#include <memory>
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070031
32#include <android/log.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080033
Christopher Ferris20303f82014-01-10 16:33:16 -080034static struct pollfd* ufds;
35static char** device_names;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080036static int nfds;
37
Christopher Ferris20303f82014-01-10 16:33:16 -080038static int open_device(const char* device) {
39 int version;
40 int fd;
41 struct pollfd* new_ufds;
42 char** new_device_names;
43 char name[80];
44 char location[80];
45 char idstr[80];
46 struct input_id id;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080047
Christopher Ferris20303f82014-01-10 16:33:16 -080048 fd = open(device, O_RDWR);
49 if (fd < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080050 return -1;
Christopher Ferris20303f82014-01-10 16:33:16 -080051 }
52
53 if (ioctl(fd, EVIOCGVERSION, &version)) {
54 return -1;
55 }
56 if (ioctl(fd, EVIOCGID, &id)) {
57 return -1;
58 }
59 name[sizeof(name) - 1] = '\0';
60 location[sizeof(location) - 1] = '\0';
61 idstr[sizeof(idstr) - 1] = '\0';
62 if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
63 name[0] = '\0';
64 }
65 if (ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
66 location[0] = '\0';
67 }
68 if (ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
69 idstr[0] = '\0';
70 }
71
72 new_ufds = reinterpret_cast<pollfd*>(realloc(ufds, sizeof(ufds[0]) * (nfds + 1)));
73 if (new_ufds == NULL) {
74 fprintf(stderr, "out of memory\n");
75 return -1;
76 }
77 ufds = new_ufds;
78 new_device_names = reinterpret_cast<char**>(realloc(
79 device_names, sizeof(device_names[0]) * (nfds + 1)));
80 if (new_device_names == NULL) {
81 fprintf(stderr, "out of memory\n");
82 return -1;
83 }
84 device_names = new_device_names;
85 ufds[nfds].fd = fd;
86 ufds[nfds].events = POLLIN;
87 device_names[nfds] = strdup(device);
88 nfds++;
89
90 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080091}
92
Christopher Ferris20303f82014-01-10 16:33:16 -080093int close_device(const char* device) {
94 int i;
95 for (i = 1; i < nfds; i++) {
96 if (strcmp(device_names[i], device) == 0) {
97 int count = nfds - i - 1;
98 free(device_names[i]);
99 memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
100 memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
101 nfds--;
102 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800103 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800104 }
105 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800106}
107
Christopher Ferris20303f82014-01-10 16:33:16 -0800108static int read_notify(const char* dirname, int nfd) {
109 int res;
110 char devname[PATH_MAX];
111 char* filename;
112 char event_buf[512];
113 int event_size;
114 int event_pos = 0;
115 struct inotify_event *event;
116
117 res = read(nfd, event_buf, sizeof(event_buf));
118 if (res < (int)sizeof(*event)) {
119 if (errno == EINTR)
120 return 0;
121 fprintf(stderr, "could not get event, %s\n", strerror(errno));
122 return 1;
123 }
124
125 strcpy(devname, dirname);
126 filename = devname + strlen(devname);
127 *filename++ = '/';
128
129 while (res >= (int)sizeof(*event)) {
130 event = reinterpret_cast<struct inotify_event*>(event_buf + event_pos);
131 if (event->len) {
132 strcpy(filename, event->name);
133 if (event->mask & IN_CREATE) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800134 open_device(devname);
Christopher Ferris20303f82014-01-10 16:33:16 -0800135 } else {
136 close_device(devname);
137 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800138 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800139 event_size = sizeof(*event) + event->len;
140 res -= event_size;
141 event_pos += event_size;
142 }
143 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800144}
145
Christopher Ferris20303f82014-01-10 16:33:16 -0800146static int scan_dir(const char* dirname) {
147 char devname[PATH_MAX];
148 char* filename;
Christopher Ferris20303f82014-01-10 16:33:16 -0800149 struct dirent* de;
James Hawkins588a2ca2016-02-18 14:52:46 -0800150 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
Christopher Ferris20303f82014-01-10 16:33:16 -0800151 if (dir == NULL)
152 return -1;
153 strcpy(devname, dirname);
154 filename = devname + strlen(devname);
155 *filename++ = '/';
James Hawkins588a2ca2016-02-18 14:52:46 -0800156 while ((de = readdir(dir.get()))) {
Christopher Ferris20303f82014-01-10 16:33:16 -0800157 if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
158 (de->d_name[1] == '.' && de->d_name[2] == '\0'))
159 continue;
160 strcpy(filename, de->d_name);
161 open_device(devname);
162 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800163 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800164}
165
Christopher Ferris20303f82014-01-10 16:33:16 -0800166int init_getevent() {
167 int res;
168 const char* device_path = "/dev/input";
169
170 nfds = 1;
171 ufds = reinterpret_cast<pollfd*>(calloc(1, sizeof(ufds[0])));
172 ufds[0].fd = inotify_init();
173 ufds[0].events = POLLIN;
174
175 res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
176 if (res < 0) {
177 return 1;
178 }
179 res = scan_dir(device_path);
180 if (res < 0) {
181 return 1;
182 }
183 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800184}
185
Christopher Ferris20303f82014-01-10 16:33:16 -0800186void uninit_getevent() {
187 int i;
188 for (i = 0; i < nfds; i++) {
189 close(ufds[i].fd);
190 }
191 free(ufds);
192 ufds = 0;
193 nfds = 0;
194}
195
196int get_event(struct input_event* event, int timeout) {
197 int res;
198 int i;
199 int pollres;
200 const char* device_path = "/dev/input";
201 while (1) {
202 pollres = poll(ufds, nfds, timeout);
203 if (pollres == 0) {
204 return 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800205 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800206 if (ufds[0].revents & POLLIN) {
207 read_notify(device_path, ufds[0].fd);
208 }
209 for (i = 1; i < nfds; i++) {
210 if (ufds[i].revents) {
211 if (ufds[i].revents & POLLIN) {
212 res = read(ufds[i].fd, event, sizeof(*event));
213 if (res < static_cast<int>(sizeof(event))) {
214 fprintf(stderr, "could not get event\n");
215 return -1;
216 }
217 return 0;
218 }
219 }
220 }
221 }
222 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800223}