gpio-mockup-cdev.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * GPIO mockup cdev test helper
  4. *
  5. * Copyright (C) 2020 Kent Gibson
  6. */
  7. #include <errno.h>
  8. #include <fcntl.h>
  9. #include <signal.h>
  10. #include <stdint.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <unistd.h>
  15. #include <sys/ioctl.h>
  16. #include <linux/gpio.h>
  17. #define CONSUMER "gpio-mockup-cdev"
  18. static int request_line_v2(int cfd, unsigned int offset,
  19. uint64_t flags, unsigned int val)
  20. {
  21. struct gpio_v2_line_request req;
  22. int ret;
  23. memset(&req, 0, sizeof(req));
  24. req.num_lines = 1;
  25. req.offsets[0] = offset;
  26. req.config.flags = flags;
  27. strcpy(req.consumer, CONSUMER);
  28. if (flags & GPIO_V2_LINE_FLAG_OUTPUT) {
  29. req.config.num_attrs = 1;
  30. req.config.attrs[0].mask = 1;
  31. req.config.attrs[0].attr.id = GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES;
  32. if (val)
  33. req.config.attrs[0].attr.values = 1;
  34. }
  35. ret = ioctl(cfd, GPIO_V2_GET_LINE_IOCTL, &req);
  36. if (ret == -1)
  37. return -errno;
  38. return req.fd;
  39. }
  40. static int get_value_v2(int lfd)
  41. {
  42. struct gpio_v2_line_values vals;
  43. int ret;
  44. memset(&vals, 0, sizeof(vals));
  45. vals.mask = 1;
  46. ret = ioctl(lfd, GPIO_V2_LINE_GET_VALUES_IOCTL, &vals);
  47. if (ret == -1)
  48. return -errno;
  49. return vals.bits & 0x1;
  50. }
  51. static int request_line_v1(int cfd, unsigned int offset,
  52. uint32_t flags, unsigned int val)
  53. {
  54. struct gpiohandle_request req;
  55. int ret;
  56. memset(&req, 0, sizeof(req));
  57. req.lines = 1;
  58. req.lineoffsets[0] = offset;
  59. req.flags = flags;
  60. strcpy(req.consumer_label, CONSUMER);
  61. if (flags & GPIOHANDLE_REQUEST_OUTPUT)
  62. req.default_values[0] = val;
  63. ret = ioctl(cfd, GPIO_GET_LINEHANDLE_IOCTL, &req);
  64. if (ret == -1)
  65. return -errno;
  66. return req.fd;
  67. }
  68. static int get_value_v1(int lfd)
  69. {
  70. struct gpiohandle_data vals;
  71. int ret;
  72. memset(&vals, 0, sizeof(vals));
  73. ret = ioctl(lfd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &vals);
  74. if (ret == -1)
  75. return -errno;
  76. return vals.values[0];
  77. }
  78. static void usage(char *prog)
  79. {
  80. printf("Usage: %s [-l] [-b <bias>] [-s <value>] [-u <uAPI>] <gpiochip> <offset>\n", prog);
  81. printf(" -b: set line bias to one of pull-down, pull-up, disabled\n");
  82. printf(" (default is to leave bias unchanged):\n");
  83. printf(" -l: set line active low (default is active high)\n");
  84. printf(" -s: set line value (default is to get line value)\n");
  85. printf(" -u: uAPI version to use (default is 2)\n");
  86. exit(-1);
  87. }
  88. static int wait_signal(void)
  89. {
  90. int sig;
  91. sigset_t wset;
  92. sigemptyset(&wset);
  93. sigaddset(&wset, SIGHUP);
  94. sigaddset(&wset, SIGINT);
  95. sigaddset(&wset, SIGTERM);
  96. sigwait(&wset, &sig);
  97. return sig;
  98. }
  99. int main(int argc, char *argv[])
  100. {
  101. char *chip;
  102. int opt, ret, cfd, lfd;
  103. unsigned int offset, val = 0, abiv;
  104. uint32_t flags_v1;
  105. uint64_t flags_v2;
  106. abiv = 2;
  107. ret = 0;
  108. flags_v1 = GPIOHANDLE_REQUEST_INPUT;
  109. flags_v2 = GPIO_V2_LINE_FLAG_INPUT;
  110. while ((opt = getopt(argc, argv, "lb:s:u:")) != -1) {
  111. switch (opt) {
  112. case 'l':
  113. flags_v1 |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
  114. flags_v2 |= GPIO_V2_LINE_FLAG_ACTIVE_LOW;
  115. break;
  116. case 'b':
  117. if (strcmp("pull-up", optarg) == 0) {
  118. flags_v1 |= GPIOHANDLE_REQUEST_BIAS_PULL_UP;
  119. flags_v2 |= GPIO_V2_LINE_FLAG_BIAS_PULL_UP;
  120. } else if (strcmp("pull-down", optarg) == 0) {
  121. flags_v1 |= GPIOHANDLE_REQUEST_BIAS_PULL_DOWN;
  122. flags_v2 |= GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN;
  123. } else if (strcmp("disabled", optarg) == 0) {
  124. flags_v1 |= GPIOHANDLE_REQUEST_BIAS_DISABLE;
  125. flags_v2 |= GPIO_V2_LINE_FLAG_BIAS_DISABLED;
  126. }
  127. break;
  128. case 's':
  129. val = atoi(optarg);
  130. flags_v1 &= ~GPIOHANDLE_REQUEST_INPUT;
  131. flags_v1 |= GPIOHANDLE_REQUEST_OUTPUT;
  132. flags_v2 &= ~GPIO_V2_LINE_FLAG_INPUT;
  133. flags_v2 |= GPIO_V2_LINE_FLAG_OUTPUT;
  134. break;
  135. case 'u':
  136. abiv = atoi(optarg);
  137. break;
  138. default:
  139. usage(argv[0]);
  140. }
  141. }
  142. if (argc < optind + 2)
  143. usage(argv[0]);
  144. chip = argv[optind];
  145. offset = atoi(argv[optind + 1]);
  146. cfd = open(chip, 0);
  147. if (cfd == -1) {
  148. fprintf(stderr, "Failed to open %s: %s\n", chip, strerror(errno));
  149. return -errno;
  150. }
  151. if (abiv == 1)
  152. lfd = request_line_v1(cfd, offset, flags_v1, val);
  153. else
  154. lfd = request_line_v2(cfd, offset, flags_v2, val);
  155. close(cfd);
  156. if (lfd < 0) {
  157. fprintf(stderr, "Failed to request %s:%d: %s\n", chip, offset, strerror(-lfd));
  158. return lfd;
  159. }
  160. if (flags_v2 & GPIO_V2_LINE_FLAG_OUTPUT) {
  161. wait_signal();
  162. } else {
  163. if (abiv == 1)
  164. ret = get_value_v1(lfd);
  165. else
  166. ret = get_value_v2(lfd);
  167. }
  168. close(lfd);
  169. return ret;
  170. }