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