blob: 751c4fb6139b815011672215b54140428bee53ee [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>
29#include <cutils/log.h>
30
Christopher Ferris20303f82014-01-10 16:33:16 -080031static struct pollfd* ufds;
32static char** device_names;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080033static int nfds;
34
Christopher Ferris20303f82014-01-10 16:33:16 -080035static int open_device(const char* device) {
36 int version;
37 int fd;
38 struct pollfd* new_ufds;
39 char** new_device_names;
40 char name[80];
41 char location[80];
42 char idstr[80];
43 struct input_id id;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080044
Christopher Ferris20303f82014-01-10 16:33:16 -080045 fd = open(device, O_RDWR);
46 if (fd < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080047 return -1;
Christopher Ferris20303f82014-01-10 16:33:16 -080048 }
49
50 if (ioctl(fd, EVIOCGVERSION, &version)) {
51 return -1;
52 }
53 if (ioctl(fd, EVIOCGID, &id)) {
54 return -1;
55 }
56 name[sizeof(name) - 1] = '\0';
57 location[sizeof(location) - 1] = '\0';
58 idstr[sizeof(idstr) - 1] = '\0';
59 if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
60 name[0] = '\0';
61 }
62 if (ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
63 location[0] = '\0';
64 }
65 if (ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
66 idstr[0] = '\0';
67 }
68
69 new_ufds = reinterpret_cast<pollfd*>(realloc(ufds, sizeof(ufds[0]) * (nfds + 1)));
70 if (new_ufds == NULL) {
71 fprintf(stderr, "out of memory\n");
72 return -1;
73 }
74 ufds = new_ufds;
75 new_device_names = reinterpret_cast<char**>(realloc(
76 device_names, sizeof(device_names[0]) * (nfds + 1)));
77 if (new_device_names == NULL) {
78 fprintf(stderr, "out of memory\n");
79 return -1;
80 }
81 device_names = new_device_names;
82 ufds[nfds].fd = fd;
83 ufds[nfds].events = POLLIN;
84 device_names[nfds] = strdup(device);
85 nfds++;
86
87 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080088}
89
Christopher Ferris20303f82014-01-10 16:33:16 -080090int close_device(const char* device) {
91 int i;
92 for (i = 1; i < nfds; i++) {
93 if (strcmp(device_names[i], device) == 0) {
94 int count = nfds - i - 1;
95 free(device_names[i]);
96 memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
97 memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
98 nfds--;
99 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800100 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800101 }
102 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800103}
104
Christopher Ferris20303f82014-01-10 16:33:16 -0800105static int read_notify(const char* dirname, int nfd) {
106 int res;
107 char devname[PATH_MAX];
108 char* filename;
109 char event_buf[512];
110 int event_size;
111 int event_pos = 0;
112 struct inotify_event *event;
113
114 res = read(nfd, event_buf, sizeof(event_buf));
115 if (res < (int)sizeof(*event)) {
116 if (errno == EINTR)
117 return 0;
118 fprintf(stderr, "could not get event, %s\n", strerror(errno));
119 return 1;
120 }
121
122 strcpy(devname, dirname);
123 filename = devname + strlen(devname);
124 *filename++ = '/';
125
126 while (res >= (int)sizeof(*event)) {
127 event = reinterpret_cast<struct inotify_event*>(event_buf + event_pos);
128 if (event->len) {
129 strcpy(filename, event->name);
130 if (event->mask & IN_CREATE) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800131 open_device(devname);
Christopher Ferris20303f82014-01-10 16:33:16 -0800132 } else {
133 close_device(devname);
134 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800135 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800136 event_size = sizeof(*event) + event->len;
137 res -= event_size;
138 event_pos += event_size;
139 }
140 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800141}
142
Christopher Ferris20303f82014-01-10 16:33:16 -0800143static int scan_dir(const char* dirname) {
144 char devname[PATH_MAX];
145 char* filename;
146 DIR* dir;
147 struct dirent* de;
148 dir = opendir(dirname);
149 if (dir == NULL)
150 return -1;
151 strcpy(devname, dirname);
152 filename = devname + strlen(devname);
153 *filename++ = '/';
154 while ((de = readdir(dir))) {
155 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 }
161 closedir(dir);
162 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800163}
164
Christopher Ferris20303f82014-01-10 16:33:16 -0800165int init_getevent() {
166 int res;
167 const char* device_path = "/dev/input";
168
169 nfds = 1;
170 ufds = reinterpret_cast<pollfd*>(calloc(1, sizeof(ufds[0])));
171 ufds[0].fd = inotify_init();
172 ufds[0].events = POLLIN;
173
174 res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
175 if (res < 0) {
176 return 1;
177 }
178 res = scan_dir(device_path);
179 if (res < 0) {
180 return 1;
181 }
182 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800183}
184
Christopher Ferris20303f82014-01-10 16:33:16 -0800185void uninit_getevent() {
186 int i;
187 for (i = 0; i < nfds; i++) {
188 close(ufds[i].fd);
189 }
190 free(ufds);
191 ufds = 0;
192 nfds = 0;
193}
194
195int get_event(struct input_event* event, int timeout) {
196 int res;
197 int i;
198 int pollres;
199 const char* device_path = "/dev/input";
200 while (1) {
201 pollres = poll(ufds, nfds, timeout);
202 if (pollres == 0) {
203 return 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800204 }
Christopher Ferris20303f82014-01-10 16:33:16 -0800205 if (ufds[0].revents & POLLIN) {
206 read_notify(device_path, ufds[0].fd);
207 }
208 for (i = 1; i < nfds; i++) {
209 if (ufds[i].revents) {
210 if (ufds[i].revents & POLLIN) {
211 res = read(ufds[i].fd, event, sizeof(*event));
212 if (res < static_cast<int>(sizeof(event))) {
213 fprintf(stderr, "could not get event\n");
214 return -1;
215 }
216 return 0;
217 }
218 }
219 }
220 }
221 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800222}