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 31static struct pollfd* ufds; 32static char** device_names; 33static int nfds; 34 35static 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 90int 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 105static 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 143static 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 165int 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 185void 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; 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