ir_loopback.c (5717B)
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 SYSFS_PATH_MAX 256 30#define DNAME_PATH_MAX 256 31 32/* 33 * Support ancient lirc.h which does not have these values. Can be removed 34 * once RHEL 8 is no longer a relevant testing platform. 35 */ 36#if RC_PROTO_MAX < 26 37#define RC_PROTO_RCMM12 24 38#define RC_PROTO_RCMM24 25 39#define RC_PROTO_RCMM32 26 40#endif 41 42static const struct { 43 enum rc_proto proto; 44 const char *name; 45 unsigned int mask; 46 const char *decoder; 47} protocols[] = { 48 { RC_PROTO_RC5, "rc-5", 0x1f7f, "rc-5" }, 49 { RC_PROTO_RC5X_20, "rc-5x-20", 0x1f7f3f, "rc-5" }, 50 { RC_PROTO_RC5_SZ, "rc-5-sz", 0x2fff, "rc-5-sz" }, 51 { RC_PROTO_JVC, "jvc", 0xffff, "jvc" }, 52 { RC_PROTO_SONY12, "sony-12", 0x1f007f, "sony" }, 53 { RC_PROTO_SONY15, "sony-15", 0xff007f, "sony" }, 54 { RC_PROTO_SONY20, "sony-20", 0x1fff7f, "sony" }, 55 { RC_PROTO_NEC, "nec", 0xffff, "nec" }, 56 { RC_PROTO_NECX, "nec-x", 0xffffff, "nec" }, 57 { RC_PROTO_NEC32, "nec-32", 0xffffffff, "nec" }, 58 { RC_PROTO_SANYO, "sanyo", 0x1fffff, "sanyo" }, 59 { RC_PROTO_RC6_0, "rc-6-0", 0xffff, "rc-6" }, 60 { RC_PROTO_RC6_6A_20, "rc-6-6a-20", 0xfffff, "rc-6" }, 61 { RC_PROTO_RC6_6A_24, "rc-6-6a-24", 0xffffff, "rc-6" }, 62 { RC_PROTO_RC6_6A_32, "rc-6-6a-32", 0xffffffff, "rc-6" }, 63 { RC_PROTO_RC6_MCE, "rc-6-mce", 0x00007fff, "rc-6" }, 64 { RC_PROTO_SHARP, "sharp", 0x1fff, "sharp" }, 65 { RC_PROTO_IMON, "imon", 0x7fffffff, "imon" }, 66 { RC_PROTO_RCMM12, "rcmm-12", 0x00000fff, "rc-mm" }, 67 { RC_PROTO_RCMM24, "rcmm-24", 0x00ffffff, "rc-mm" }, 68 { RC_PROTO_RCMM32, "rcmm-32", 0xffffffff, "rc-mm" }, 69}; 70 71int lirc_open(const char *rc) 72{ 73 struct dirent *dent; 74 char buf[SYSFS_PATH_MAX + DNAME_PATH_MAX]; 75 DIR *d; 76 int fd; 77 78 snprintf(buf, sizeof(buf), "/sys/class/rc/%s", rc); 79 80 d = opendir(buf); 81 if (!d) 82 ksft_exit_fail_msg("cannot open %s: %m\n", buf); 83 84 while ((dent = readdir(d)) != NULL) { 85 if (!strncmp(dent->d_name, "lirc", 4)) { 86 snprintf(buf, sizeof(buf), "/dev/%s", dent->d_name); 87 break; 88 } 89 } 90 91 if (!dent) 92 ksft_exit_skip("cannot find lirc device for %s\n", rc); 93 94 closedir(d); 95 96 fd = open(buf, O_RDWR | O_NONBLOCK); 97 if (fd == -1) 98 ksft_exit_fail_msg("cannot open: %s: %m\n", buf); 99 100 return fd; 101} 102 103int main(int argc, char **argv) 104{ 105 unsigned int mode; 106 char buf[100]; 107 int rlircfd, wlircfd, protocolfd, i, n; 108 109 srand(time(NULL)); 110 111 if (argc != 3) 112 ksft_exit_fail_msg("Usage: %s <write rcN> <read rcN>\n", 113 argv[0]); 114 115 rlircfd = lirc_open(argv[2]); 116 mode = LIRC_MODE_SCANCODE; 117 if (ioctl(rlircfd, LIRC_SET_REC_MODE, &mode)) 118 ksft_exit_fail_msg("failed to set scancode rec mode %s: %m\n", 119 argv[2]); 120 121 wlircfd = lirc_open(argv[1]); 122 if (ioctl(wlircfd, LIRC_SET_SEND_MODE, &mode)) 123 ksft_exit_fail_msg("failed to set scancode send mode %s: %m\n", 124 argv[1]); 125 126 snprintf(buf, sizeof(buf), "/sys/class/rc/%s/protocols", argv[2]); 127 protocolfd = open(buf, O_WRONLY); 128 if (protocolfd == -1) 129 ksft_exit_fail_msg("failed to open %s: %m\n", buf); 130 131 printf("Sending IR on %s and receiving IR on %s.\n", argv[1], argv[2]); 132 133 for (i = 0; i < ARRAY_SIZE(protocols); i++) { 134 if (write(protocolfd, protocols[i].decoder, 135 strlen(protocols[i].decoder)) == -1) 136 ksft_exit_fail_msg("failed to set write decoder\n"); 137 138 printf("Testing protocol %s for decoder %s (%d/%d)...\n", 139 protocols[i].name, protocols[i].decoder, 140 i + 1, (int)ARRAY_SIZE(protocols)); 141 142 for (n = 0; n < TEST_SCANCODES; n++) { 143 unsigned int scancode = rand() & protocols[i].mask; 144 unsigned int rc_proto = protocols[i].proto; 145 146 if (rc_proto == RC_PROTO_RC6_MCE) 147 scancode |= 0x800f0000; 148 149 if (rc_proto == RC_PROTO_NECX && 150 (((scancode >> 16) ^ ~(scancode >> 8)) & 0xff) == 0) 151 continue; 152 153 if (rc_proto == RC_PROTO_NEC32 && 154 (((scancode >> 8) ^ ~scancode) & 0xff) == 0) 155 continue; 156 157 if (rc_proto == RC_PROTO_RCMM32 && 158 (scancode & 0x000c0000) != 0x000c0000 && 159 scancode & 0x00008000) 160 continue; 161 162 struct lirc_scancode lsc = { 163 .rc_proto = rc_proto, 164 .scancode = scancode 165 }; 166 167 printf("Testing scancode:%x\n", scancode); 168 169 while (write(wlircfd, &lsc, sizeof(lsc)) < 0) { 170 if (errno == EINTR) 171 continue; 172 173 ksft_exit_fail_msg("failed to send ir: %m\n"); 174 } 175 176 struct pollfd pfd = { .fd = rlircfd, .events = POLLIN }; 177 struct lirc_scancode lsc2; 178 179 poll(&pfd, 1, 1000); 180 181 bool decoded = true; 182 183 while (read(rlircfd, &lsc2, sizeof(lsc2)) < 0) { 184 if (errno == EINTR) 185 continue; 186 187 ksft_test_result_error("no scancode decoded: %m\n"); 188 decoded = false; 189 break; 190 } 191 192 if (!decoded) 193 continue; 194 195 if (lsc.rc_proto != lsc2.rc_proto) 196 ksft_test_result_error("decoded protocol is different: %d\n", 197 lsc2.rc_proto); 198 199 else if (lsc.scancode != lsc2.scancode) 200 ksft_test_result_error("decoded scancode is different: %llx\n", 201 lsc2.scancode); 202 else 203 ksft_inc_pass_cnt(); 204 } 205 206 printf("OK\n"); 207 } 208 209 close(rlircfd); 210 close(wlircfd); 211 close(protocolfd); 212 213 if (ksft_get_fail_cnt() > 0) 214 ksft_exit_fail(); 215 else 216 ksft_exit_pass(); 217 218 return 0; 219}