gpio-event-mon.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. * gpio-event-mon - monitor GPIO line events from userspace
  3. *
  4. * Copyright (C) 2016 Linus Walleij
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License version 2 as published by
  8. * the Free Software Foundation.
  9. *
  10. * Usage:
  11. * gpio-event-mon -n <device-name> -o <offset>
  12. */
  13. #include <unistd.h>
  14. #include <stdlib.h>
  15. #include <stdbool.h>
  16. #include <stdio.h>
  17. #include <dirent.h>
  18. #include <errno.h>
  19. #include <string.h>
  20. #include <poll.h>
  21. #include <fcntl.h>
  22. #include <getopt.h>
  23. #include <inttypes.h>
  24. #include <sys/ioctl.h>
  25. #include <sys/types.h>
  26. #include <linux/gpio.h>
  27. int monitor_device(const char *device_name,
  28. unsigned int line,
  29. u_int32_t handleflags,
  30. u_int32_t eventflags,
  31. unsigned int loops)
  32. {
  33. struct gpioevent_request req;
  34. struct gpiohandle_data data;
  35. char *chrdev_name;
  36. int fd;
  37. int ret;
  38. int i = 0;
  39. ret = asprintf(&chrdev_name, "/dev/%s", device_name);
  40. if (ret < 0)
  41. return -ENOMEM;
  42. fd = open(chrdev_name, 0);
  43. if (fd == -1) {
  44. ret = -errno;
  45. fprintf(stderr, "Failed to open %s\n", chrdev_name);
  46. goto exit_close_error;
  47. }
  48. req.lineoffset = line;
  49. req.handleflags = handleflags;
  50. req.eventflags = eventflags;
  51. strcpy(req.consumer_label, "gpio-event-mon");
  52. ret = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &req);
  53. if (ret == -1) {
  54. ret = -errno;
  55. fprintf(stderr, "Failed to issue GET EVENT "
  56. "IOCTL (%d)\n",
  57. ret);
  58. goto exit_close_error;
  59. }
  60. /* Read initial states */
  61. ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
  62. if (ret == -1) {
  63. ret = -errno;
  64. fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE "
  65. "VALUES IOCTL (%d)\n",
  66. ret);
  67. goto exit_close_error;
  68. }
  69. fprintf(stdout, "Monitoring line %d on %s\n", line, device_name);
  70. fprintf(stdout, "Initial line value: %d\n", data.values[0]);
  71. while (1) {
  72. struct gpioevent_data event;
  73. ret = read(req.fd, &event, sizeof(event));
  74. if (ret == -1) {
  75. if (errno == -EAGAIN) {
  76. fprintf(stderr, "nothing available\n");
  77. continue;
  78. } else {
  79. ret = -errno;
  80. fprintf(stderr, "Failed to read event (%d)\n",
  81. ret);
  82. break;
  83. }
  84. }
  85. if (ret != sizeof(event)) {
  86. fprintf(stderr, "Reading event failed\n");
  87. ret = -EIO;
  88. break;
  89. }
  90. fprintf(stdout, "GPIO EVENT %" PRIu64 ": ", event.timestamp);
  91. switch (event.id) {
  92. case GPIOEVENT_EVENT_RISING_EDGE:
  93. fprintf(stdout, "rising edge");
  94. break;
  95. case GPIOEVENT_EVENT_FALLING_EDGE:
  96. fprintf(stdout, "falling edge");
  97. break;
  98. default:
  99. fprintf(stdout, "unknown event");
  100. }
  101. fprintf(stdout, "\n");
  102. i++;
  103. if (i == loops)
  104. break;
  105. }
  106. exit_close_error:
  107. if (close(fd) == -1)
  108. perror("Failed to close GPIO character device file");
  109. free(chrdev_name);
  110. return ret;
  111. }
  112. void print_usage(void)
  113. {
  114. fprintf(stderr, "Usage: gpio-event-mon [options]...\n"
  115. "Listen to events on GPIO lines, 0->1 1->0\n"
  116. " -n <name> Listen on GPIOs on a named device (must be stated)\n"
  117. " -o <n> Offset to monitor\n"
  118. " -d Set line as open drain\n"
  119. " -s Set line as open source\n"
  120. " -r Listen for rising edges\n"
  121. " -f Listen for falling edges\n"
  122. " [-c <n>] Do <n> loops (optional, infinite loop if not stated)\n"
  123. " -? This helptext\n"
  124. "\n"
  125. "Example:\n"
  126. "gpio-event-mon -n gpiochip0 -o 4 -r -f\n"
  127. );
  128. }
  129. int main(int argc, char **argv)
  130. {
  131. const char *device_name = NULL;
  132. unsigned int line = -1;
  133. unsigned int loops = 0;
  134. u_int32_t handleflags = GPIOHANDLE_REQUEST_INPUT;
  135. u_int32_t eventflags = 0;
  136. int c;
  137. while ((c = getopt(argc, argv, "c:n:o:dsrf?")) != -1) {
  138. switch (c) {
  139. case 'c':
  140. loops = strtoul(optarg, NULL, 10);
  141. break;
  142. case 'n':
  143. device_name = optarg;
  144. break;
  145. case 'o':
  146. line = strtoul(optarg, NULL, 10);
  147. break;
  148. case 'd':
  149. handleflags |= GPIOHANDLE_REQUEST_OPEN_DRAIN;
  150. break;
  151. case 's':
  152. handleflags |= GPIOHANDLE_REQUEST_OPEN_SOURCE;
  153. break;
  154. case 'r':
  155. eventflags |= GPIOEVENT_REQUEST_RISING_EDGE;
  156. break;
  157. case 'f':
  158. eventflags |= GPIOEVENT_REQUEST_FALLING_EDGE;
  159. break;
  160. case '?':
  161. print_usage();
  162. return -1;
  163. }
  164. }
  165. if (!device_name || line == -1) {
  166. print_usage();
  167. return -1;
  168. }
  169. if (!eventflags) {
  170. printf("No flags specified, listening on both rising and "
  171. "falling edges\n");
  172. eventflags = GPIOEVENT_REQUEST_BOTH_EDGES;
  173. }
  174. return monitor_device(device_name, line, handleflags,
  175. eventflags, loops);
  176. }