Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // test ir decoder
0003 //
0004 // Copyright (C) 2018 Sean Young <sean@mess.org>
0005 
0006 // A lirc chardev is a device representing a consumer IR (cir) device which
0007 // can receive infrared signals from remote control and/or transmit IR.
0008 //
0009 // IR is sent as a series of pulses and space somewhat like morse code. The
0010 // BPF program can decode this into scancodes so that rc-core can translate
0011 // this into input key codes using the rc keymap.
0012 //
0013 // This test works by sending IR over rc-loopback, so the IR is processed by
0014 // BPF and then decoded into scancodes. The lirc chardev must be the one
0015 // associated with rc-loopback, see the output of ir-keytable(1).
0016 //
0017 // The following CONFIG options must be enabled for the test to succeed:
0018 // CONFIG_RC_CORE=y
0019 // CONFIG_BPF_RAWIR_EVENT=y
0020 // CONFIG_RC_LOOPBACK=y
0021 
0022 // Steps:
0023 // 1. Open the /dev/lircN device for rc-loopback (given on command line)
0024 // 2. Attach bpf_lirc_mode2 program which decodes some IR.
0025 // 3. Send some IR to the same IR device; since it is loopback, this will
0026 //    end up in the bpf program
0027 // 4. bpf program should decode IR and report keycode
0028 // 5. We can read keycode from same /dev/lirc device
0029 
0030 #include <linux/bpf.h>
0031 #include <linux/input.h>
0032 #include <errno.h>
0033 #include <stdio.h>
0034 #include <stdlib.h>
0035 #include <string.h>
0036 #include <unistd.h>
0037 #include <poll.h>
0038 #include <sys/types.h>
0039 #include <sys/ioctl.h>
0040 #include <sys/stat.h>
0041 #include <fcntl.h>
0042 
0043 #include "bpf_util.h"
0044 #include <bpf/bpf.h>
0045 #include <bpf/libbpf.h>
0046 
0047 #include "testing_helpers.h"
0048 
0049 int main(int argc, char **argv)
0050 {
0051     struct bpf_object *obj;
0052     int ret, lircfd, progfd, inputfd;
0053     int testir1 = 0x1dead;
0054     int testir2 = 0x20101;
0055     u32 prog_ids[10], prog_flags[10], prog_cnt;
0056 
0057     if (argc != 3) {
0058         printf("Usage: %s /dev/lircN /dev/input/eventM\n", argv[0]);
0059         return 2;
0060     }
0061 
0062     ret = bpf_prog_test_load("test_lirc_mode2_kern.o",
0063                  BPF_PROG_TYPE_LIRC_MODE2, &obj, &progfd);
0064     if (ret) {
0065         printf("Failed to load bpf program\n");
0066         return 1;
0067     }
0068 
0069     lircfd = open(argv[1], O_RDWR | O_NONBLOCK);
0070     if (lircfd == -1) {
0071         printf("failed to open lirc device %s: %m\n", argv[1]);
0072         return 1;
0073     }
0074 
0075     /* Let's try detach it before it was ever attached */
0076     ret = bpf_prog_detach2(progfd, lircfd, BPF_LIRC_MODE2);
0077     if (ret != -1 || errno != ENOENT) {
0078         printf("bpf_prog_detach2 not attached should fail: %m\n");
0079         return 1;
0080     }
0081 
0082     inputfd = open(argv[2], O_RDONLY | O_NONBLOCK);
0083     if (inputfd == -1) {
0084         printf("failed to open input device %s: %m\n", argv[1]);
0085         return 1;
0086     }
0087 
0088     prog_cnt = 10;
0089     ret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,
0090                  &prog_cnt);
0091     if (ret) {
0092         printf("Failed to query bpf programs on lirc device: %m\n");
0093         return 1;
0094     }
0095 
0096     if (prog_cnt != 0) {
0097         printf("Expected nothing to be attached\n");
0098         return 1;
0099     }
0100 
0101     ret = bpf_prog_attach(progfd, lircfd, BPF_LIRC_MODE2, 0);
0102     if (ret) {
0103         printf("Failed to attach bpf to lirc device: %m\n");
0104         return 1;
0105     }
0106 
0107     /* Write raw IR */
0108     ret = write(lircfd, &testir1, sizeof(testir1));
0109     if (ret != sizeof(testir1)) {
0110         printf("Failed to send test IR message: %m\n");
0111         return 1;
0112     }
0113 
0114     struct pollfd pfd = { .fd = inputfd, .events = POLLIN };
0115     struct input_event event;
0116 
0117     for (;;) {
0118         poll(&pfd, 1, 100);
0119 
0120         /* Read decoded IR */
0121         ret = read(inputfd, &event, sizeof(event));
0122         if (ret != sizeof(event)) {
0123             printf("Failed to read decoded IR: %m\n");
0124             return 1;
0125         }
0126 
0127         if (event.type == EV_MSC && event.code == MSC_SCAN &&
0128             event.value == 0xdead) {
0129             break;
0130         }
0131     }
0132 
0133     /* Write raw IR */
0134     ret = write(lircfd, &testir2, sizeof(testir2));
0135     if (ret != sizeof(testir2)) {
0136         printf("Failed to send test IR message: %m\n");
0137         return 1;
0138     }
0139 
0140     for (;;) {
0141         poll(&pfd, 1, 100);
0142 
0143         /* Read decoded IR */
0144         ret = read(inputfd, &event, sizeof(event));
0145         if (ret != sizeof(event)) {
0146             printf("Failed to read decoded IR: %m\n");
0147             return 1;
0148         }
0149 
0150         if (event.type == EV_REL && event.code == REL_Y &&
0151             event.value == 1 ) {
0152             break;
0153         }
0154     }
0155 
0156     prog_cnt = 10;
0157     ret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,
0158                  &prog_cnt);
0159     if (ret) {
0160         printf("Failed to query bpf programs on lirc device: %m\n");
0161         return 1;
0162     }
0163 
0164     if (prog_cnt != 1) {
0165         printf("Expected one program to be attached\n");
0166         return 1;
0167     }
0168 
0169     /* Let's try detaching it now it is actually attached */
0170     ret = bpf_prog_detach2(progfd, lircfd, BPF_LIRC_MODE2);
0171     if (ret) {
0172         printf("bpf_prog_detach2: returned %m\n");
0173         return 1;
0174     }
0175 
0176     return 0;
0177 }