ir_loopback.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // SPDX-License-Identifier: GPL-2.0
  2. // test ir decoder
  3. //
  4. // Copyright (C) 2018 Sean Young <[email protected]>
  5. // When sending LIRC_MODE_SCANCODE, the IR will be encoded. rc-loopback
  6. // will send this IR to the receiver side, where we try to read the decoded
  7. // IR. Decoding happens in a separate kernel thread, so we will need to
  8. // wait until that is scheduled, hence we use poll to check for read
  9. // readiness.
  10. #include <linux/lirc.h>
  11. #include <errno.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <stdbool.h>
  15. #include <string.h>
  16. #include <unistd.h>
  17. #include <poll.h>
  18. #include <time.h>
  19. #include <sys/types.h>
  20. #include <sys/ioctl.h>
  21. #include <dirent.h>
  22. #include <sys/stat.h>
  23. #include <fcntl.h>
  24. #include "../kselftest.h"
  25. #define TEST_SCANCODES 10
  26. #define SYSFS_PATH_MAX 256
  27. #define DNAME_PATH_MAX 256
  28. /*
  29. * Support ancient lirc.h which does not have these values. Can be removed
  30. * once RHEL 8 is no longer a relevant testing platform.
  31. */
  32. #if RC_PROTO_MAX < 26
  33. #define RC_PROTO_RCMM12 24
  34. #define RC_PROTO_RCMM24 25
  35. #define RC_PROTO_RCMM32 26
  36. #endif
  37. static const struct {
  38. enum rc_proto proto;
  39. const char *name;
  40. unsigned int mask;
  41. const char *decoder;
  42. } protocols[] = {
  43. { RC_PROTO_RC5, "rc-5", 0x1f7f, "rc-5" },
  44. { RC_PROTO_RC5X_20, "rc-5x-20", 0x1f7f3f, "rc-5" },
  45. { RC_PROTO_RC5_SZ, "rc-5-sz", 0x2fff, "rc-5-sz" },
  46. { RC_PROTO_JVC, "jvc", 0xffff, "jvc" },
  47. { RC_PROTO_SONY12, "sony-12", 0x1f007f, "sony" },
  48. { RC_PROTO_SONY15, "sony-15", 0xff007f, "sony" },
  49. { RC_PROTO_SONY20, "sony-20", 0x1fff7f, "sony" },
  50. { RC_PROTO_NEC, "nec", 0xffff, "nec" },
  51. { RC_PROTO_NECX, "nec-x", 0xffffff, "nec" },
  52. { RC_PROTO_NEC32, "nec-32", 0xffffffff, "nec" },
  53. { RC_PROTO_SANYO, "sanyo", 0x1fffff, "sanyo" },
  54. { RC_PROTO_RC6_0, "rc-6-0", 0xffff, "rc-6" },
  55. { RC_PROTO_RC6_6A_20, "rc-6-6a-20", 0xfffff, "rc-6" },
  56. { RC_PROTO_RC6_6A_24, "rc-6-6a-24", 0xffffff, "rc-6" },
  57. { RC_PROTO_RC6_6A_32, "rc-6-6a-32", 0xffffffff, "rc-6" },
  58. { RC_PROTO_RC6_MCE, "rc-6-mce", 0x00007fff, "rc-6" },
  59. { RC_PROTO_SHARP, "sharp", 0x1fff, "sharp" },
  60. { RC_PROTO_IMON, "imon", 0x7fffffff, "imon" },
  61. { RC_PROTO_RCMM12, "rcmm-12", 0x00000fff, "rc-mm" },
  62. { RC_PROTO_RCMM24, "rcmm-24", 0x00ffffff, "rc-mm" },
  63. { RC_PROTO_RCMM32, "rcmm-32", 0xffffffff, "rc-mm" },
  64. };
  65. int lirc_open(const char *rc)
  66. {
  67. struct dirent *dent;
  68. char buf[SYSFS_PATH_MAX + DNAME_PATH_MAX];
  69. DIR *d;
  70. int fd;
  71. snprintf(buf, sizeof(buf), "/sys/class/rc/%s", rc);
  72. d = opendir(buf);
  73. if (!d)
  74. ksft_exit_fail_msg("cannot open %s: %m\n", buf);
  75. while ((dent = readdir(d)) != NULL) {
  76. if (!strncmp(dent->d_name, "lirc", 4)) {
  77. snprintf(buf, sizeof(buf), "/dev/%s", dent->d_name);
  78. break;
  79. }
  80. }
  81. if (!dent)
  82. ksft_exit_skip("cannot find lirc device for %s\n", rc);
  83. closedir(d);
  84. fd = open(buf, O_RDWR | O_NONBLOCK);
  85. if (fd == -1)
  86. ksft_exit_fail_msg("cannot open: %s: %m\n", buf);
  87. return fd;
  88. }
  89. int main(int argc, char **argv)
  90. {
  91. unsigned int mode;
  92. char buf[100];
  93. int rlircfd, wlircfd, protocolfd, i, n;
  94. srand(time(NULL));
  95. if (argc != 3)
  96. ksft_exit_fail_msg("Usage: %s <write rcN> <read rcN>\n",
  97. argv[0]);
  98. rlircfd = lirc_open(argv[2]);
  99. mode = LIRC_MODE_SCANCODE;
  100. if (ioctl(rlircfd, LIRC_SET_REC_MODE, &mode))
  101. ksft_exit_fail_msg("failed to set scancode rec mode %s: %m\n",
  102. argv[2]);
  103. wlircfd = lirc_open(argv[1]);
  104. if (ioctl(wlircfd, LIRC_SET_SEND_MODE, &mode))
  105. ksft_exit_fail_msg("failed to set scancode send mode %s: %m\n",
  106. argv[1]);
  107. snprintf(buf, sizeof(buf), "/sys/class/rc/%s/protocols", argv[2]);
  108. protocolfd = open(buf, O_WRONLY);
  109. if (protocolfd == -1)
  110. ksft_exit_fail_msg("failed to open %s: %m\n", buf);
  111. printf("Sending IR on %s and receiving IR on %s.\n", argv[1], argv[2]);
  112. for (i = 0; i < ARRAY_SIZE(protocols); i++) {
  113. if (write(protocolfd, protocols[i].decoder,
  114. strlen(protocols[i].decoder)) == -1)
  115. ksft_exit_fail_msg("failed to set write decoder\n");
  116. printf("Testing protocol %s for decoder %s (%d/%d)...\n",
  117. protocols[i].name, protocols[i].decoder,
  118. i + 1, (int)ARRAY_SIZE(protocols));
  119. for (n = 0; n < TEST_SCANCODES; n++) {
  120. unsigned int scancode = rand() & protocols[i].mask;
  121. unsigned int rc_proto = protocols[i].proto;
  122. if (rc_proto == RC_PROTO_RC6_MCE)
  123. scancode |= 0x800f0000;
  124. if (rc_proto == RC_PROTO_NECX &&
  125. (((scancode >> 16) ^ ~(scancode >> 8)) & 0xff) == 0)
  126. continue;
  127. if (rc_proto == RC_PROTO_NEC32 &&
  128. (((scancode >> 8) ^ ~scancode) & 0xff) == 0)
  129. continue;
  130. if (rc_proto == RC_PROTO_RCMM32 &&
  131. (scancode & 0x000c0000) != 0x000c0000 &&
  132. scancode & 0x00008000)
  133. continue;
  134. struct lirc_scancode lsc = {
  135. .rc_proto = rc_proto,
  136. .scancode = scancode
  137. };
  138. printf("Testing scancode:%x\n", scancode);
  139. while (write(wlircfd, &lsc, sizeof(lsc)) < 0) {
  140. if (errno == EINTR)
  141. continue;
  142. ksft_exit_fail_msg("failed to send ir: %m\n");
  143. }
  144. struct pollfd pfd = { .fd = rlircfd, .events = POLLIN };
  145. struct lirc_scancode lsc2;
  146. poll(&pfd, 1, 1000);
  147. bool decoded = true;
  148. while (read(rlircfd, &lsc2, sizeof(lsc2)) < 0) {
  149. if (errno == EINTR)
  150. continue;
  151. ksft_test_result_error("no scancode decoded: %m\n");
  152. decoded = false;
  153. break;
  154. }
  155. if (!decoded)
  156. continue;
  157. if (lsc.rc_proto != lsc2.rc_proto)
  158. ksft_test_result_error("decoded protocol is different: %d\n",
  159. lsc2.rc_proto);
  160. else if (lsc.scancode != lsc2.scancode)
  161. ksft_test_result_error("decoded scancode is different: %llx\n",
  162. lsc2.scancode);
  163. else
  164. ksft_inc_pass_cnt();
  165. }
  166. printf("OK\n");
  167. }
  168. close(rlircfd);
  169. close(wlircfd);
  170. close(protocolfd);
  171. if (ksft_get_fail_cnt() > 0)
  172. ksft_exit_fail();
  173. else
  174. ksft_exit_pass();
  175. return 0;
  176. }