brintos

brintos / linux-shallow public Read only

0
0
Text · 5.6 KiB · f4a15cb Raw
220 lines · c
1// SPDX-License-Identifier: GPL-2.02// test ir decoder3//4// Copyright (C) 2018 Sean Young <sean@mess.org>5 6// When sending LIRC_MODE_SCANCODE, the IR will be encoded. rc-loopback7// will send this IR to the receiver side, where we try to read the decoded8// IR. Decoding happens in a separate kernel thread, so we will need to9// wait until that is scheduled, hence we use poll to check for read10// 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	1029#define SYSFS_PATH_MAX 25630#define DNAME_PATH_MAX 25631 32/*33 * Support ancient lirc.h which does not have these values. Can be removed34 * once RHEL 8 is no longer a relevant testing platform.35 */36#if RC_PROTO_MAX < 2637#define RC_PROTO_RCMM12 2438#define RC_PROTO_RCMM24 2539#define RC_PROTO_RCMM32 2640#endif41 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 = scancode165			};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			else203				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	else216		ksft_exit_pass();217 218	return 0;219}220