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