blob: ebd070c0688848929fde3296280cce71c5797bf0 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <stdint.h>
5#include <dirent.h>
6#include <fcntl.h>
7#include <sys/ioctl.h>
8#include <sys/inotify.h>
9#include <sys/limits.h>
10#include <sys/poll.h>
11#include <linux/input.h>
12#include <errno.h>
13#include <cutils/log.h>
14
15static struct pollfd *ufds;
16static char **device_names;
17static int nfds;
18
19static int open_device(const char *device)
20{
21 int version;
22 int fd;
23 struct pollfd *new_ufds;
24 char **new_device_names;
25 char name[80];
26 char location[80];
27 char idstr[80];
28 struct input_id id;
29
30 fd = open(device, O_RDWR);
31 if(fd < 0) {
32 return -1;
33 }
34
35 if(ioctl(fd, EVIOCGVERSION, &version)) {
36 return -1;
37 }
38 if(ioctl(fd, EVIOCGID, &id)) {
39 return -1;
40 }
41 name[sizeof(name) - 1] = '\0';
42 location[sizeof(location) - 1] = '\0';
43 idstr[sizeof(idstr) - 1] = '\0';
44 if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
45 //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno));
46 name[0] = '\0';
47 }
48 if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
49 //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno));
50 location[0] = '\0';
51 }
52 if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
53 //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno));
54 idstr[0] = '\0';
55 }
56
57 new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
58 if(new_ufds == NULL) {
59 fprintf(stderr, "out of memory\n");
60 return -1;
61 }
62 ufds = new_ufds;
63 new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1));
64 if(new_device_names == NULL) {
65 fprintf(stderr, "out of memory\n");
66 return -1;
67 }
68 device_names = new_device_names;
69 ufds[nfds].fd = fd;
70 ufds[nfds].events = POLLIN;
71 device_names[nfds] = strdup(device);
72 nfds++;
73
74 return 0;
75}
76
77int close_device(const char *device)
78{
79 int i;
80 for(i = 1; i < nfds; i++) {
81 if(strcmp(device_names[i], device) == 0) {
82 int count = nfds - i - 1;
83 free(device_names[i]);
84 memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
85 memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
86 nfds--;
87 return 0;
88 }
89 }
90 return -1;
91}
92
93static int read_notify(const char *dirname, int nfd)
94{
95 int res;
96 char devname[PATH_MAX];
97 char *filename;
98 char event_buf[512];
99 int event_size;
100 int event_pos = 0;
101 struct inotify_event *event;
102
103 res = read(nfd, event_buf, sizeof(event_buf));
104 if(res < (int)sizeof(*event)) {
105 if(errno == EINTR)
106 return 0;
107 fprintf(stderr, "could not get event, %s\n", strerror(errno));
108 return 1;
109 }
110 //printf("got %d bytes of event information\n", res);
111
112 strcpy(devname, dirname);
113 filename = devname + strlen(devname);
114 *filename++ = '/';
115
116 while(res >= (int)sizeof(*event)) {
117 event = (struct inotify_event *)(event_buf + event_pos);
118 //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
119 if(event->len) {
120 strcpy(filename, event->name);
121 if(event->mask & IN_CREATE) {
122 open_device(devname);
123 }
124 else {
125 close_device(devname);
126 }
127 }
128 event_size = sizeof(*event) + event->len;
129 res -= event_size;
130 event_pos += event_size;
131 }
132 return 0;
133}
134
135static int scan_dir(const char *dirname)
136{
137 char devname[PATH_MAX];
138 char *filename;
139 DIR *dir;
140 struct dirent *de;
141 dir = opendir(dirname);
142 if(dir == NULL)
143 return -1;
144 strcpy(devname, dirname);
145 filename = devname + strlen(devname);
146 *filename++ = '/';
147 while((de = readdir(dir))) {
148 if(de->d_name[0] == '.' &&
149 (de->d_name[1] == '\0' ||
150 (de->d_name[1] == '.' && de->d_name[2] == '\0')))
151 continue;
152 strcpy(filename, de->d_name);
153 open_device(devname);
154 }
155 closedir(dir);
156 return 0;
157}
158
159int init_getevent()
160{
161 int res;
162 const char *device_path = "/dev/input";
163
164 nfds = 1;
165 ufds = calloc(1, sizeof(ufds[0]));
166 ufds[0].fd = inotify_init();
167 ufds[0].events = POLLIN;
168
169 res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
170 if(res < 0) {
171 return 1;
172 }
173 res = scan_dir(device_path);
174 if(res < 0) {
175 return 1;
176 }
177 return 0;
178}
179
180void uninit_getevent()
181{
182 int i;
183 for(i = 0; i < nfds; i++) {
184 close(ufds[i].fd);
185 }
186 free(ufds);
187 ufds = 0;
188 nfds = 0;
189}
190
191int get_event(struct input_event* event, int timeout)
192{
193 int res;
194 int i;
195 int pollres;
196 const char *device_path = "/dev/input";
197 while(1) {
198 pollres = poll(ufds, nfds, timeout);
199 if (pollres == 0) {
200 return 1;
201 }
202 if(ufds[0].revents & POLLIN) {
203 read_notify(device_path, ufds[0].fd);
204 }
205 for(i = 1; i < nfds; i++) {
206 if(ufds[i].revents) {
207 if(ufds[i].revents & POLLIN) {
208 res = read(ufds[i].fd, event, sizeof(*event));
209 if(res < (int)sizeof(event)) {
210 fprintf(stderr, "could not get event\n");
211 return -1;
212 }
213 return 0;
214 }
215 }
216 }
217 }
218 return 0;
219}