blob: e5acd1744f09a83a4640c9869549d5a637480480 [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
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080017#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <stdint.h>
21#include <dirent.h>
22#include <fcntl.h>
23#include <sys/ioctl.h>
24#include <sys/inotify.h>
25#include <sys/limits.h>
26#include <sys/poll.h>
27#include <linux/input.h>
28#include <errno.h>
James Hawkins588a2ca2016-02-18 14:52:46 -080029#include <memory>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080030#include <cutils/log.h>
31
Christopher Ferris20303f82014-01-10 16:33:16 -080032static struct pollfd* ufds;
33static char** device_names;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080034static int nfds;
35
Christopher Ferris20303f82014-01-10 16:33:16 -080036static int open_device(const char* device) {
37 int version;
38 int fd;
39 struct pollfd* new_ufds;
40 char** new_device_names;
41 char name[80];
42 char location[80];
43 char idstr[80];
44 struct input_id id;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080045
Christopher Ferris20303f82014-01-10 16:33:16 -080046 fd = open(device, O_RDWR);
47 if (fd < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080048 return -1;
Christopher Ferris20303f82014-01-10 16:33:16 -080049 }
50
51 if (ioctl(fd, EVIOCGVERSION, &version)) {
52 return -1;
53 }
54 if (ioctl(fd, EVIOCGID, &id)) {
55 return -1;
56 }
57 name[sizeof(name) - 1] = '\0';
58 location[sizeof(location) - 1] = '\0';
59 idstr[sizeof(idstr) - 1] = '\0';
60 if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
61 name[0] = '\0';
62 }
63 if (ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
64 location[0] = '\0';
65 }
66 if (ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
67 idstr[0] = '\0';
68 }
69
70 new_ufds = reinterpret_cast<pollfd*>(realloc(ufds, sizeof(ufds[0]) * (nfds + 1)));
71 if (new_ufds == NULL) {
72 fprintf(stderr, "out of memory\n");
73 return -1;
74 }
75 ufds = new_ufds;
76 new_device_names = reinterpret_cast<char**>(realloc(
77 device_names, sizeof(device_names[0]) * (nfds + 1)));
78 if (new_device_names == NULL) {
79 fprintf(stderr, "out of memory\n");
80 return -1;
81 }
82 device_names = new_device_names;
83 ufds[nfds].fd = fd;
84 ufds[nfds].events = POLLIN;
85 device_names[nfds] = strdup(device);
86 nfds++;
87
88 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080089}
90
Christopher Ferris20303f82014-01-10 16:33:16 -080091int close_device(const char* device) {
92 int i;
93 for (i = 1; i < nfds; i++) {
94 if (strcmp(device_names[i], device) == 0) {
95 int count = nfds - i - 1;
96 free(device_names[i]);
97 memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
98 memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
99 nfds--;
100 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800101 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800102 }
103 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800104}
105
Christopher Ferris20303f82014-01-10 16:33:16 -0800106static int read_notify(const char* dirname, int nfd) {
107 int res;
108 char devname[PATH_MAX];
109 char* filename;
110 char event_buf[512];
111 int event_size;
112 int event_pos = 0;
113 struct inotify_event *event;
114
115 res = read(nfd, event_buf, sizeof(event_buf));
116 if (res < (int)sizeof(*event)) {
117 if (errno == EINTR)
118 return 0;
119 fprintf(stderr, "could not get event, %s\n", strerror(errno));
120 return 1;
121 }
122
123 strcpy(devname, dirname);
124 filename = devname + strlen(devname);
125 *filename++ = '/';
126
127 while (res >= (int)sizeof(*event)) {
128 event = reinterpret_cast<struct inotify_event*>(event_buf + event_pos);
129 if (event->len) {
130 strcpy(filename, event->name);
131 if (event->mask & IN_CREATE) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800132 open_device(devname);
Christopher Ferris20303f82014-01-10 16:33:16 -0800133 } else {
134 close_device(devname);
135 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800136 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800137 event_size = sizeof(*event) + event->len;
138 res -= event_size;
139 event_pos += event_size;
140 }
141 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800142}
143
Christopher Ferris20303f82014-01-10 16:33:16 -0800144static int scan_dir(const char* dirname) {
145 char devname[PATH_MAX];
146 char* filename;
Christopher Ferris20303f82014-01-10 16:33:16 -0800147 struct dirent* de;
James Hawkins588a2ca2016-02-18 14:52:46 -0800148 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
Christopher Ferris20303f82014-01-10 16:33:16 -0800149 if (dir == NULL)
150 return -1;
151 strcpy(devname, dirname);
152 filename = devname + strlen(devname);
153 *filename++ = '/';
James Hawkins588a2ca2016-02-18 14:52:46 -0800154 while ((de = readdir(dir.get()))) {
Christopher Ferris20303f82014-01-10 16:33:16 -0800155 if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
156 (de->d_name[1] == '.' && de->d_name[2] == '\0'))
157 continue;
158 strcpy(filename, de->d_name);
159 open_device(devname);
160 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800161 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800162}
163
Christopher Ferris20303f82014-01-10 16:33:16 -0800164int init_getevent() {
165 int res;
166 const char* device_path = "/dev/input";
167
168 nfds = 1;
169 ufds = reinterpret_cast<pollfd*>(calloc(1, sizeof(ufds[0])));
170 ufds[0].fd = inotify_init();
171 ufds[0].events = POLLIN;
172
173 res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
174 if (res < 0) {
175 return 1;
176 }
177 res = scan_dir(device_path);
178 if (res < 0) {
179 return 1;
180 }
181 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800182}
183
Christopher Ferris20303f82014-01-10 16:33:16 -0800184void uninit_getevent() {
185 int i;
186 for (i = 0; i < nfds; i++) {
187 close(ufds[i].fd);
188 }
189 free(ufds);
190 ufds = 0;
191 nfds = 0;
192}
193
194int get_event(struct input_event* event, int timeout) {
195 int res;
196 int i;
197 int pollres;
198 const char* device_path = "/dev/input";
199 while (1) {
200 pollres = poll(ufds, nfds, timeout);
201 if (pollres == 0) {
202 return 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800203 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800204 if (ufds[0].revents & POLLIN) {
205 read_notify(device_path, ufds[0].fd);
206 }
207 for (i = 1; i < nfds; i++) {
208 if (ufds[i].revents) {
209 if (ufds[i].revents & POLLIN) {
210 res = read(ufds[i].fd, event, sizeof(*event));
211 if (res < static_cast<int>(sizeof(event))) {
212 fprintf(stderr, "could not get event\n");
213 return -1;
214 }
215 return 0;
216 }
217 }
218 }
219 }
220 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800221}