root/tools/testing/selftests/bpf/test_lirc_mode2_user.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. main

   1 // SPDX-License-Identifier: GPL-2.0
   2 // test ir decoder
   3 //
   4 // Copyright (C) 2018 Sean Young <sean@mess.org>
   5 
   6 // A lirc chardev is a device representing a consumer IR (cir) device which
   7 // 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. The
  10 // BPF program can decode this into scancodes so that rc-core can translate
  11 // 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 by
  14 // BPF and then decoded into scancodes. The lirc chardev must be the one
  15 // 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=y
  19 // CONFIG_BPF_RAWIR_EVENT=y
  20 // CONFIG_RC_LOOPBACK=y
  21 
  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 will
  26 //    end up in the bpf program
  27 // 4. bpf program should decode IR and report keycode
  28 // 5. We can read keycode from same /dev/lirc device
  29 
  30 #include <linux/bpf.h>
  31 #include <linux/lirc.h>
  32 #include <linux/input.h>
  33 #include <errno.h>
  34 #include <stdio.h>
  35 #include <stdlib.h>
  36 #include <string.h>
  37 #include <unistd.h>
  38 #include <poll.h>
  39 #include <sys/types.h>
  40 #include <sys/ioctl.h>
  41 #include <sys/stat.h>
  42 #include <fcntl.h>
  43 
  44 #include "bpf_util.h"
  45 #include <bpf/bpf.h>
  46 #include <bpf/libbpf.h>
  47 
  48 int main(int argc, char **argv)
  49 {
  50         struct bpf_object *obj;
  51         int ret, lircfd, progfd, inputfd;
  52         int testir1 = 0x1dead;
  53         int testir2 = 0x20101;
  54         u32 prog_ids[10], prog_flags[10], prog_cnt;
  55 
  56         if (argc != 3) {
  57                 printf("Usage: %s /dev/lircN /dev/input/eventM\n", argv[0]);
  58                 return 2;
  59         }
  60 
  61         ret = bpf_prog_load("test_lirc_mode2_kern.o",
  62                             BPF_PROG_TYPE_LIRC_MODE2, &obj, &progfd);
  63         if (ret) {
  64                 printf("Failed to load bpf program\n");
  65                 return 1;
  66         }
  67 
  68         lircfd = open(argv[1], O_RDWR | O_NONBLOCK);
  69         if (lircfd == -1) {
  70                 printf("failed to open lirc device %s: %m\n", argv[1]);
  71                 return 1;
  72         }
  73 
  74         /* Let's try detach it before it was ever attached */
  75         ret = bpf_prog_detach2(progfd, lircfd, BPF_LIRC_MODE2);
  76         if (ret != -1 || errno != ENOENT) {
  77                 printf("bpf_prog_detach2 not attached should fail: %m\n");
  78                 return 1;
  79         }
  80 
  81         inputfd = open(argv[2], O_RDONLY | O_NONBLOCK);
  82         if (inputfd == -1) {
  83                 printf("failed to open input device %s: %m\n", argv[1]);
  84                 return 1;
  85         }
  86 
  87         prog_cnt = 10;
  88         ret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,
  89                              &prog_cnt);
  90         if (ret) {
  91                 printf("Failed to query bpf programs on lirc device: %m\n");
  92                 return 1;
  93         }
  94 
  95         if (prog_cnt != 0) {
  96                 printf("Expected nothing to be attached\n");
  97                 return 1;
  98         }
  99 
 100         ret = bpf_prog_attach(progfd, lircfd, BPF_LIRC_MODE2, 0);
 101         if (ret) {
 102                 printf("Failed to attach bpf to lirc device: %m\n");
 103                 return 1;
 104         }
 105 
 106         /* Write raw IR */
 107         ret = write(lircfd, &testir1, sizeof(testir1));
 108         if (ret != sizeof(testir1)) {
 109                 printf("Failed to send test IR message: %m\n");
 110                 return 1;
 111         }
 112 
 113         struct pollfd pfd = { .fd = inputfd, .events = POLLIN };
 114         struct input_event event;
 115 
 116         for (;;) {
 117                 poll(&pfd, 1, 100);
 118 
 119                 /* Read decoded IR */
 120                 ret = read(inputfd, &event, sizeof(event));
 121                 if (ret != sizeof(event)) {
 122                         printf("Failed to read decoded IR: %m\n");
 123                         return 1;
 124                 }
 125 
 126                 if (event.type == EV_MSC && event.code == MSC_SCAN &&
 127                     event.value == 0xdead) {
 128                         break;
 129                 }
 130         }
 131 
 132         /* Write raw IR */
 133         ret = write(lircfd, &testir2, sizeof(testir2));
 134         if (ret != sizeof(testir2)) {
 135                 printf("Failed to send test IR message: %m\n");
 136                 return 1;
 137         }
 138 
 139         for (;;) {
 140                 poll(&pfd, 1, 100);
 141 
 142                 /* Read decoded IR */
 143                 ret = read(inputfd, &event, sizeof(event));
 144                 if (ret != sizeof(event)) {
 145                         printf("Failed to read decoded IR: %m\n");
 146                         return 1;
 147                 }
 148 
 149                 if (event.type == EV_REL && event.code == REL_Y &&
 150                     event.value == 1 ) {
 151                         break;
 152                 }
 153         }
 154 
 155         prog_cnt = 10;
 156         ret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,
 157                              &prog_cnt);
 158         if (ret) {
 159                 printf("Failed to query bpf programs on lirc device: %m\n");
 160                 return 1;
 161         }
 162 
 163         if (prog_cnt != 1) {
 164                 printf("Expected one program to be attached\n");
 165                 return 1;
 166         }
 167 
 168         /* Let's try detaching it now it is actually attached */
 169         ret = bpf_prog_detach2(progfd, lircfd, BPF_LIRC_MODE2);
 170         if (ret) {
 171                 printf("bpf_prog_detach2: returned %m\n");
 172                 return 1;
 173         }
 174 
 175         return 0;
 176 }

/* [<][>][^][v][top][bottom][index][help] */