test_lirc_mode2_user.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // SPDX-License-Identifier: GPL-2.0
  2. // test ir decoder
  3. //
  4. // Copyright (C) 2018 Sean Young <sean@mess.org>
  5. // A lirc chardev is a device representing a consumer IR (cir) device which
  6. // can receive infrared signals from remote control and/or transmit IR.
  7. //
  8. // IR is sent as a series of pulses and space somewhat like morse code. The
  9. // BPF program can decode this into scancodes so that rc-core can translate
  10. // this into input key codes using the rc keymap.
  11. //
  12. // This test works by sending IR over rc-loopback, so the IR is processed by
  13. // BPF and then decoded into scancodes. The lirc chardev must be the one
  14. // associated with rc-loopback, see the output of ir-keytable(1).
  15. //
  16. // The following CONFIG options must be enabled for the test to succeed:
  17. // CONFIG_RC_CORE=y
  18. // CONFIG_BPF_RAWIR_EVENT=y
  19. // CONFIG_RC_LOOPBACK=y
  20. // Steps:
  21. // 1. Open the /dev/lircN device for rc-loopback (given on command line)
  22. // 2. Attach bpf_lirc_mode2 program which decodes some IR.
  23. // 3. Send some IR to the same IR device; since it is loopback, this will
  24. // end up in the bpf program
  25. // 4. bpf program should decode IR and report keycode
  26. // 5. We can read keycode from same /dev/lirc device
  27. #include <linux/bpf.h>
  28. #include <linux/input.h>
  29. #include <errno.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <unistd.h>
  34. #include <poll.h>
  35. #include <sys/types.h>
  36. #include <sys/ioctl.h>
  37. #include <sys/stat.h>
  38. #include <fcntl.h>
  39. #include "bpf_util.h"
  40. #include <bpf/bpf.h>
  41. #include <bpf/libbpf.h>
  42. #include "testing_helpers.h"
  43. int main(int argc, char **argv)
  44. {
  45. struct bpf_object *obj;
  46. int ret, lircfd, progfd, inputfd;
  47. int testir1 = 0x1dead;
  48. int testir2 = 0x20101;
  49. u32 prog_ids[10], prog_flags[10], prog_cnt;
  50. if (argc != 3) {
  51. printf("Usage: %s /dev/lircN /dev/input/eventM\n", argv[0]);
  52. return 2;
  53. }
  54. ret = bpf_prog_test_load("test_lirc_mode2_kern.bpf.o",
  55. BPF_PROG_TYPE_LIRC_MODE2, &obj, &progfd);
  56. if (ret) {
  57. printf("Failed to load bpf program\n");
  58. return 1;
  59. }
  60. lircfd = open(argv[1], O_RDWR | O_NONBLOCK);
  61. if (lircfd == -1) {
  62. printf("failed to open lirc device %s: %m\n", argv[1]);
  63. return 1;
  64. }
  65. /* Let's try detach it before it was ever attached */
  66. ret = bpf_prog_detach2(progfd, lircfd, BPF_LIRC_MODE2);
  67. if (ret != -ENOENT) {
  68. printf("bpf_prog_detach2 not attached should fail: %m\n");
  69. return 1;
  70. }
  71. inputfd = open(argv[2], O_RDONLY | O_NONBLOCK);
  72. if (inputfd == -1) {
  73. printf("failed to open input device %s: %m\n", argv[1]);
  74. return 1;
  75. }
  76. prog_cnt = 10;
  77. ret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,
  78. &prog_cnt);
  79. if (ret) {
  80. printf("Failed to query bpf programs on lirc device: %m\n");
  81. return 1;
  82. }
  83. if (prog_cnt != 0) {
  84. printf("Expected nothing to be attached\n");
  85. return 1;
  86. }
  87. ret = bpf_prog_attach(progfd, lircfd, BPF_LIRC_MODE2, 0);
  88. if (ret) {
  89. printf("Failed to attach bpf to lirc device: %m\n");
  90. return 1;
  91. }
  92. /* Write raw IR */
  93. ret = write(lircfd, &testir1, sizeof(testir1));
  94. if (ret != sizeof(testir1)) {
  95. printf("Failed to send test IR message: %m\n");
  96. return 1;
  97. }
  98. struct pollfd pfd = { .fd = inputfd, .events = POLLIN };
  99. struct input_event event;
  100. for (;;) {
  101. poll(&pfd, 1, 100);
  102. /* Read decoded IR */
  103. ret = read(inputfd, &event, sizeof(event));
  104. if (ret != sizeof(event)) {
  105. printf("Failed to read decoded IR: %m\n");
  106. return 1;
  107. }
  108. if (event.type == EV_MSC && event.code == MSC_SCAN &&
  109. event.value == 0xdead) {
  110. break;
  111. }
  112. }
  113. /* Write raw IR */
  114. ret = write(lircfd, &testir2, sizeof(testir2));
  115. if (ret != sizeof(testir2)) {
  116. printf("Failed to send test IR message: %m\n");
  117. return 1;
  118. }
  119. for (;;) {
  120. poll(&pfd, 1, 100);
  121. /* Read decoded IR */
  122. ret = read(inputfd, &event, sizeof(event));
  123. if (ret != sizeof(event)) {
  124. printf("Failed to read decoded IR: %m\n");
  125. return 1;
  126. }
  127. if (event.type == EV_REL && event.code == REL_Y &&
  128. event.value == 1 ) {
  129. break;
  130. }
  131. }
  132. prog_cnt = 10;
  133. ret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,
  134. &prog_cnt);
  135. if (ret) {
  136. printf("Failed to query bpf programs on lirc device: %m\n");
  137. return 1;
  138. }
  139. if (prog_cnt != 1) {
  140. printf("Expected one program to be attached\n");
  141. return 1;
  142. }
  143. /* Let's try detaching it now it is actually attached */
  144. ret = bpf_prog_detach2(progfd, lircfd, BPF_LIRC_MODE2);
  145. if (ret) {
  146. printf("bpf_prog_detach2: returned %m\n");
  147. return 1;
  148. }
  149. return 0;
  150. }