• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 #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 
31 static struct pollfd* ufds;
32 static char** device_names;
33 static int nfds;
34 
open_device(const char * device)35 static 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;
44 
45   fd = open(device, O_RDWR);
46   if (fd < 0) {
47     return -1;
48   }
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;
88 }
89 
close_device(const char * device)90 int 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;
100     }
101   }
102   return -1;
103 }
104 
read_notify(const char * dirname,int nfd)105 static 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) {
131         open_device(devname);
132       } else {
133         close_device(devname);
134       }
135     }
136     event_size = sizeof(*event) + event->len;
137     res -= event_size;
138     event_pos += event_size;
139   }
140   return 0;
141 }
142 
scan_dir(const char * dirname)143 static 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;
163 }
164 
init_getevent()165 int 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;
183 }
184 
uninit_getevent()185 void 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 
get_event(struct input_event * event,int timeout)195 int 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;
204     }
205     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;
222 }
223