PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/toolbox/getevent.c

https://github.com/CharlieWood/platform_system_core
C | 470 lines | 438 code | 26 blank | 6 comment | 102 complexity | 450c44d98aaa05e28f1ecd00d118e94f MD5 | raw file
  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> // this does not compile
  12. #include <errno.h>
  13. static struct pollfd *ufds;
  14. static char **device_names;
  15. static int nfds;
  16. enum {
  17. PRINT_DEVICE_ERRORS = 1U << 0,
  18. PRINT_DEVICE = 1U << 1,
  19. PRINT_DEVICE_NAME = 1U << 2,
  20. PRINT_DEVICE_INFO = 1U << 3,
  21. PRINT_VERSION = 1U << 4,
  22. PRINT_POSSIBLE_EVENTS = 1U << 5,
  23. };
  24. static int print_possible_events(int fd)
  25. {
  26. uint8_t *bits = NULL;
  27. ssize_t bits_size = 0;
  28. const char* label;
  29. int i, j, k;
  30. int res, res2;
  31. printf(" events:\n");
  32. for(i = 0; i <= EV_MAX; i++) {
  33. int count = 0;
  34. while(1) {
  35. res = ioctl(fd, EVIOCGBIT(i, bits_size), bits);
  36. if(res < bits_size)
  37. break;
  38. bits_size = res + 16;
  39. bits = realloc(bits, bits_size * 2);
  40. if(bits == NULL) {
  41. fprintf(stderr, "failed to allocate buffer of size %d\n", bits_size);
  42. return 1;
  43. }
  44. }
  45. res2 = 0;
  46. switch(i) {
  47. case EV_SYN:
  48. label = "SYN";
  49. break;
  50. case EV_KEY:
  51. res2 = ioctl(fd, EVIOCGKEY(res), bits + bits_size);
  52. label = "KEY";
  53. break;
  54. case EV_REL:
  55. label = "REL";
  56. break;
  57. case EV_ABS:
  58. label = "ABS";
  59. break;
  60. case EV_MSC:
  61. label = "MSC";
  62. break;
  63. case EV_LED:
  64. res2 = ioctl(fd, EVIOCGLED(res), bits + bits_size);
  65. label = "LED";
  66. break;
  67. case EV_SND:
  68. res2 = ioctl(fd, EVIOCGSND(res), bits + bits_size);
  69. label = "SND";
  70. break;
  71. case EV_SW:
  72. res2 = ioctl(fd, EVIOCGSW(bits_size), bits + bits_size);
  73. label = "SW ";
  74. break;
  75. case EV_REP:
  76. label = "REP";
  77. break;
  78. case EV_FF:
  79. label = "FF ";
  80. break;
  81. case EV_PWR:
  82. label = "PWR";
  83. break;
  84. default:
  85. res2 = 0;
  86. label = "???";
  87. }
  88. for(j = 0; j < res; j++) {
  89. for(k = 0; k < 8; k++)
  90. if(bits[j] & 1 << k) {
  91. char down;
  92. if(j < res2 && (bits[j + bits_size] & 1 << k))
  93. down = '*';
  94. else
  95. down = ' ';
  96. if(count == 0)
  97. printf(" %s (%04x):", label, i);
  98. else if((count & 0x7) == 0 || i == EV_ABS)
  99. printf("\n ");
  100. printf(" %04x%c", j * 8 + k, down);
  101. if(i == EV_ABS) {
  102. struct input_absinfo abs;
  103. if(ioctl(fd, EVIOCGABS(j * 8 + k), &abs) == 0) {
  104. printf(" value %d, min %d, max %d, fuzz %d flat %d", abs.value, abs.minimum, abs.maximum, abs.fuzz, abs.flat);
  105. }
  106. }
  107. count++;
  108. }
  109. }
  110. if(count)
  111. printf("\n");
  112. }
  113. free(bits);
  114. return 0;
  115. }
  116. static int open_device(const char *device, int print_flags)
  117. {
  118. int version;
  119. int fd;
  120. struct pollfd *new_ufds;
  121. char **new_device_names;
  122. char name[80];
  123. char location[80];
  124. char idstr[80];
  125. struct input_id id;
  126. fd = open(device, O_RDWR);
  127. if(fd < 0) {
  128. if(print_flags & PRINT_DEVICE_ERRORS)
  129. fprintf(stderr, "could not open %s, %s\n", device, strerror(errno));
  130. return -1;
  131. }
  132. if(ioctl(fd, EVIOCGVERSION, &version)) {
  133. if(print_flags & PRINT_DEVICE_ERRORS)
  134. fprintf(stderr, "could not get driver version for %s, %s\n", device, strerror(errno));
  135. return -1;
  136. }
  137. if(ioctl(fd, EVIOCGID, &id)) {
  138. if(print_flags & PRINT_DEVICE_ERRORS)
  139. fprintf(stderr, "could not get driver id for %s, %s\n", device, strerror(errno));
  140. return -1;
  141. }
  142. name[sizeof(name) - 1] = '\0';
  143. location[sizeof(location) - 1] = '\0';
  144. idstr[sizeof(idstr) - 1] = '\0';
  145. if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
  146. //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno));
  147. name[0] = '\0';
  148. }
  149. if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
  150. //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno));
  151. location[0] = '\0';
  152. }
  153. if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
  154. //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno));
  155. idstr[0] = '\0';
  156. }
  157. new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
  158. if(new_ufds == NULL) {
  159. fprintf(stderr, "out of memory\n");
  160. return -1;
  161. }
  162. ufds = new_ufds;
  163. new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1));
  164. if(new_device_names == NULL) {
  165. fprintf(stderr, "out of memory\n");
  166. return -1;
  167. }
  168. device_names = new_device_names;
  169. if(print_flags & PRINT_DEVICE)
  170. printf("add device %d: %s\n", nfds, device);
  171. if(print_flags & PRINT_DEVICE_INFO)
  172. printf(" bus: %04x\n"
  173. " vendor %04x\n"
  174. " product %04x\n"
  175. " version %04x\n",
  176. id.bustype, id.vendor, id.product, id.version);
  177. if(print_flags & PRINT_DEVICE_NAME)
  178. printf(" name: \"%s\"\n", name);
  179. if(print_flags & PRINT_DEVICE_INFO)
  180. printf(" location: \"%s\"\n"
  181. " id: \"%s\"\n", location, idstr);
  182. if(print_flags & PRINT_VERSION)
  183. printf(" version: %d.%d.%d\n",
  184. version >> 16, (version >> 8) & 0xff, version & 0xff);
  185. if(print_flags & PRINT_POSSIBLE_EVENTS) {
  186. print_possible_events(fd);
  187. }
  188. ufds[nfds].fd = fd;
  189. ufds[nfds].events = POLLIN;
  190. device_names[nfds] = strdup(device);
  191. nfds++;
  192. return 0;
  193. }
  194. int close_device(const char *device, int print_flags)
  195. {
  196. int i;
  197. for(i = 1; i < nfds; i++) {
  198. if(strcmp(device_names[i], device) == 0) {
  199. int count = nfds - i - 1;
  200. if(print_flags & PRINT_DEVICE)
  201. printf("remove device %d: %s\n", i, device);
  202. free(device_names[i]);
  203. memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
  204. memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
  205. nfds--;
  206. return 0;
  207. }
  208. }
  209. if(print_flags & PRINT_DEVICE_ERRORS)
  210. fprintf(stderr, "remote device: %s not found\n", device);
  211. return -1;
  212. }
  213. static int read_notify(const char *dirname, int nfd, int print_flags)
  214. {
  215. int res;
  216. char devname[PATH_MAX];
  217. char *filename;
  218. char event_buf[512];
  219. int event_size;
  220. int event_pos = 0;
  221. struct inotify_event *event;
  222. res = read(nfd, event_buf, sizeof(event_buf));
  223. if(res < (int)sizeof(*event)) {
  224. if(errno == EINTR)
  225. return 0;
  226. fprintf(stderr, "could not get event, %s\n", strerror(errno));
  227. return 1;
  228. }
  229. //printf("got %d bytes of event information\n", res);
  230. strcpy(devname, dirname);
  231. filename = devname + strlen(devname);
  232. *filename++ = '/';
  233. while(res >= (int)sizeof(*event)) {
  234. event = (struct inotify_event *)(event_buf + event_pos);
  235. //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
  236. if(event->len) {
  237. strcpy(filename, event->name);
  238. if(event->mask & IN_CREATE) {
  239. open_device(devname, print_flags);
  240. }
  241. else {
  242. close_device(devname, print_flags);
  243. }
  244. }
  245. event_size = sizeof(*event) + event->len;
  246. res -= event_size;
  247. event_pos += event_size;
  248. }
  249. return 0;
  250. }
  251. static int scan_dir(const char *dirname, int print_flags)
  252. {
  253. char devname[PATH_MAX];
  254. char *filename;
  255. DIR *dir;
  256. struct dirent *de;
  257. dir = opendir(dirname);
  258. if(dir == NULL)
  259. return -1;
  260. strcpy(devname, dirname);
  261. filename = devname + strlen(devname);
  262. *filename++ = '/';
  263. while((de = readdir(dir))) {
  264. if(de->d_name[0] == '.' &&
  265. (de->d_name[1] == '\0' ||
  266. (de->d_name[1] == '.' && de->d_name[2] == '\0')))
  267. continue;
  268. strcpy(filename, de->d_name);
  269. open_device(devname, print_flags);
  270. }
  271. closedir(dir);
  272. return 0;
  273. }
  274. static void usage(int argc, char *argv[])
  275. {
  276. fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-p] [-q] [-c count] [-r] [device]\n", argv[0]);
  277. fprintf(stderr, " -t: show time stamps\n");
  278. fprintf(stderr, " -n: don't print newlines\n");
  279. fprintf(stderr, " -s: print switch states for given bits\n");
  280. fprintf(stderr, " -S: print all switch states\n");
  281. fprintf(stderr, " -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32)\n");
  282. fprintf(stderr, " -p: show possible events (errs, dev, name, pos. events)\n");
  283. fprintf(stderr, " -q: quiet (clear verbosity mask)\n");
  284. fprintf(stderr, " -c: print given number of events then exit\n");
  285. fprintf(stderr, " -r: print rate events are received\n");
  286. }
  287. int getevent_main(int argc, char *argv[])
  288. {
  289. int c;
  290. int i;
  291. int res;
  292. int pollres;
  293. int get_time = 0;
  294. int print_device = 0;
  295. char *newline = "\n";
  296. uint16_t get_switch = 0;
  297. struct input_event event;
  298. int version;
  299. int print_flags = PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME;
  300. int print_flags_set = 0;
  301. int dont_block = -1;
  302. int event_count = 0;
  303. int sync_rate = 0;
  304. int64_t last_sync_time = 0;
  305. const char *device = NULL;
  306. const char *device_path = "/dev/input";
  307. opterr = 0;
  308. do {
  309. c = getopt(argc, argv, "tns:Sv::pqc:rh");
  310. if (c == EOF)
  311. break;
  312. switch (c) {
  313. case 't':
  314. get_time = 1;
  315. break;
  316. case 'n':
  317. newline = "";
  318. break;
  319. case 's':
  320. get_switch = strtoul(optarg, NULL, 0);
  321. if(dont_block == -1)
  322. dont_block = 1;
  323. break;
  324. case 'S':
  325. get_switch = ~0;
  326. if(dont_block == -1)
  327. dont_block = 1;
  328. break;
  329. case 'v':
  330. if(optarg)
  331. print_flags = strtoul(optarg, NULL, 0);
  332. else
  333. print_flags |= PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_DEVICE_INFO | PRINT_VERSION;
  334. print_flags_set = 1;
  335. break;
  336. case 'p':
  337. print_flags = PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_POSSIBLE_EVENTS;
  338. print_flags_set = 1;
  339. if(dont_block == -1)
  340. dont_block = 1;
  341. break;
  342. case 'q':
  343. print_flags = 0;
  344. print_flags_set = 1;
  345. break;
  346. case 'c':
  347. event_count = atoi(optarg);
  348. dont_block = 0;
  349. break;
  350. case 'r':
  351. sync_rate = 1;
  352. break;
  353. case '?':
  354. fprintf(stderr, "%s: invalid option -%c\n",
  355. argv[0], optopt);
  356. case 'h':
  357. usage(argc, argv);
  358. exit(1);
  359. }
  360. } while (1);
  361. if(dont_block == -1)
  362. dont_block = 0;
  363. if (optind + 1 == argc) {
  364. device = argv[optind];
  365. optind++;
  366. }
  367. if (optind != argc) {
  368. usage(argc, argv);
  369. exit(1);
  370. }
  371. nfds = 1;
  372. ufds = calloc(1, sizeof(ufds[0]));
  373. ufds[0].fd = inotify_init();
  374. ufds[0].events = POLLIN;
  375. if(device) {
  376. if(!print_flags_set)
  377. print_flags = PRINT_DEVICE_ERRORS;
  378. res = open_device(device, print_flags);
  379. if(res < 0) {
  380. return 1;
  381. }
  382. }
  383. else {
  384. print_device = 1;
  385. res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
  386. if(res < 0) {
  387. fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno));
  388. return 1;
  389. }
  390. res = scan_dir(device_path, print_flags);
  391. if(res < 0) {
  392. fprintf(stderr, "scan dir failed for %s\n", device_path);
  393. return 1;
  394. }
  395. }
  396. if(get_switch) {
  397. for(i = 1; i < nfds; i++) {
  398. uint16_t sw;
  399. res = ioctl(ufds[i].fd, EVIOCGSW(1), &sw);
  400. if(res < 0) {
  401. fprintf(stderr, "could not get switch state, %s\n", strerror(errno));
  402. return 1;
  403. }
  404. sw &= get_switch;
  405. printf("%04x%s", sw, newline);
  406. }
  407. }
  408. if(dont_block)
  409. return 0;
  410. while(1) {
  411. pollres = poll(ufds, nfds, -1);
  412. //printf("poll %d, returned %d\n", nfds, pollres);
  413. if(ufds[0].revents & POLLIN) {
  414. read_notify(device_path, ufds[0].fd, print_flags);
  415. }
  416. for(i = 1; i < nfds; i++) {
  417. if(ufds[i].revents) {
  418. if(ufds[i].revents & POLLIN) {
  419. res = read(ufds[i].fd, &event, sizeof(event));
  420. if(res < (int)sizeof(event)) {
  421. fprintf(stderr, "could not get event\n");
  422. return 1;
  423. }
  424. if(get_time) {
  425. printf("%ld-%ld: ", event.time.tv_sec, event.time.tv_usec);
  426. }
  427. if(print_device)
  428. printf("%s: ", device_names[i]);
  429. printf("%04x %04x %08x", event.type, event.code, event.value);
  430. if(sync_rate && event.type == 0 && event.code == 0) {
  431. int64_t now = event.time.tv_sec * 1000000LL + event.time.tv_usec;
  432. if(last_sync_time)
  433. printf(" rate %lld", 1000000LL / (now - last_sync_time));
  434. last_sync_time = now;
  435. }
  436. printf("%s", newline);
  437. if(event_count && --event_count == 0)
  438. return 0;
  439. }
  440. }
  441. }
  442. }
  443. return 0;
  444. }