getevent.c revision 4f6e8d7a00cbeda1e70cc15be9c4af1018bdad53
1#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}
220