media: bpf: add bpf function to report mouse movement
authorSean Young <sean@mess.org>
Thu, 6 Dec 2018 13:01:03 +0000 (13:01 +0000)
committerAlexei Starovoitov <ast@kernel.org>
Sun, 9 Dec 2018 22:37:18 +0000 (14:37 -0800)
Some IR remotes have a directional pad or other pointer-like thing that
can be used as a mouse. Make it possible to decode these types of IR
protocols in BPF.

Cc: netdev@vger.kernel.org
Signed-off-by: Sean Young <sean@mess.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
drivers/media/rc/bpf-lirc.c
include/uapi/linux/bpf.h
tools/include/uapi/linux/bpf.h
tools/testing/selftests/bpf/bpf_helpers.h
tools/testing/selftests/bpf/test_lirc_mode2.sh
tools/testing/selftests/bpf/test_lirc_mode2_kern.c
tools/testing/selftests/bpf/test_lirc_mode2_user.c

index 8b97fd1f0ceaf8dbbe9086591c492eaa34f18cd3..390a722e6211320cd59764ac9de5cf8ff8cad9d6 100644 (file)
@@ -59,6 +59,28 @@ static const struct bpf_func_proto rc_keydown_proto = {
        .arg4_type = ARG_ANYTHING,
 };
 
+BPF_CALL_3(bpf_rc_pointer_rel, u32*, sample, s32, rel_x, s32, rel_y)
+{
+       struct ir_raw_event_ctrl *ctrl;
+
+       ctrl = container_of(sample, struct ir_raw_event_ctrl, bpf_sample);
+
+       input_report_rel(ctrl->dev->input_dev, REL_X, rel_x);
+       input_report_rel(ctrl->dev->input_dev, REL_Y, rel_y);
+       input_sync(ctrl->dev->input_dev);
+
+       return 0;
+}
+
+static const struct bpf_func_proto rc_pointer_rel_proto = {
+       .func      = bpf_rc_pointer_rel,
+       .gpl_only  = true,
+       .ret_type  = RET_INTEGER,
+       .arg1_type = ARG_PTR_TO_CTX,
+       .arg2_type = ARG_ANYTHING,
+       .arg3_type = ARG_ANYTHING,
+};
+
 static const struct bpf_func_proto *
 lirc_mode2_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
 {
@@ -67,6 +89,8 @@ lirc_mode2_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
                return &rc_repeat_proto;
        case BPF_FUNC_rc_keydown:
                return &rc_keydown_proto;
+       case BPF_FUNC_rc_pointer_rel:
+               return &rc_pointer_rel_proto;
        case BPF_FUNC_map_lookup_elem:
                return &bpf_map_lookup_elem_proto;
        case BPF_FUNC_map_update_elem:
index 7a66db8d15d56196d50095721ab41f1cd9bff5cb..1bee1135866a0fdf5ce74f7994ba576725f5d687 100644 (file)
@@ -2301,6 +2301,20 @@ union bpf_attr {
  *             payload and/or *pop* value being to large.
  *     Return
  *             0 on success, or a negative error in case of failure.
+ *
+ * int bpf_rc_pointer_rel(void *ctx, s32 rel_x, s32 rel_y)
+ *     Description
+ *             This helper is used in programs implementing IR decoding, to
+ *             report a successfully decoded pointer movement.
+ *
+ *             The *ctx* should point to the lirc sample as passed into
+ *             the program.
+ *
+ *             This helper is only available is the kernel was compiled with
+ *             the **CONFIG_BPF_LIRC_MODE2** configuration option set to
+ *             "**y**".
+ *     Return
+ *             0
  */
 #define __BPF_FUNC_MAPPER(FN)          \
        FN(unspec),                     \
@@ -2394,7 +2408,8 @@ union bpf_attr {
        FN(map_pop_elem),               \
        FN(map_peek_elem),              \
        FN(msg_push_data),              \
-       FN(msg_pop_data),
+       FN(msg_pop_data),               \
+       FN(rc_pointer_rel),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
index 7973c28b24a02f63b8a5788c378aa605a354161d..6ad50b6471d363d5c222911cab6f471d6294b64b 100644 (file)
@@ -2298,9 +2298,22 @@ union bpf_attr {
  *             if possible. Other errors can occur if input parameters are
  *             invalid either due to *start* byte not being valid part of msg
  *             payload and/or *pop* value being to large.
+ *     Return
+ *             0 on success, or a negative error in case of failure.
+ *
+ * int bpf_rc_pointer_rel(void *ctx, s32 rel_x, s32 rel_y)
+ *     Description
+ *             This helper is used in programs implementing IR decoding, to
+ *             report a successfully decoded pointer movement.
+ *
+ *             The *ctx* should point to the lirc sample as passed into
+ *             the program.
  *
+ *             This helper is only available is the kernel was compiled with
+ *             the **CONFIG_BPF_LIRC_MODE2** configuration option set to
+ *             "**y**".
  *     Return
- *             0 on success, or a negative erro in case of failure.
+ *             0
  */
 #define __BPF_FUNC_MAPPER(FN)          \
        FN(unspec),                     \
@@ -2394,7 +2407,8 @@ union bpf_attr {
        FN(map_pop_elem),               \
        FN(map_peek_elem),              \
        FN(msg_push_data),              \
-       FN(msg_pop_data),
+       FN(msg_pop_data),               \
+       FN(rc_pointer_rel),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
index 7b69519a09b15d38c7ef0659cf267284b8caad26..04c060e8f10a5c794b17e92b479f036c04bd98cf 100644 (file)
@@ -170,6 +170,8 @@ static int (*bpf_skb_vlan_push)(void *ctx, __be16 vlan_proto, __u16 vlan_tci) =
        (void *) BPF_FUNC_skb_vlan_push;
 static int (*bpf_skb_vlan_pop)(void *ctx) =
        (void *) BPF_FUNC_skb_vlan_pop;
+static int (*bpf_rc_pointer_rel)(void *ctx, int rel_x, int rel_y) =
+       (void *) BPF_FUNC_rc_pointer_rel;
 
 /* llvm builtin functions that eBPF C program may use to
  * emit BPF_LD_ABS and BPF_LD_IND instructions
index 677686198df34d799e67c0eb15ab25f4b68eba4c..ec4e15948e40631cdb063a5d700310796e3386de 100755 (executable)
@@ -21,13 +21,14 @@ do
        if grep -q DRV_NAME=rc-loopback $i/uevent
        then
                LIRCDEV=$(grep DEVNAME= $i/lirc*/uevent | sed sQDEVNAME=Q/dev/Q)
+               INPUTDEV=$(grep DEVNAME= $i/input*/event*/uevent | sed sQDEVNAME=Q/dev/Q)
        fi
 done
 
 if [ -n $LIRCDEV ];
 then
        TYPE=lirc_mode2
-       ./test_lirc_mode2_user $LIRCDEV
+       ./test_lirc_mode2_user $LIRCDEV $INPUTDEV
        ret=$?
        if [ $ret -ne 0 ]; then
                echo -e ${RED}"FAIL: $TYPE"${NC}
index ba26855563a5f848a7788b2ee1c6df649933338c..4147130cc3b7bc3d845838baa764f7a595cabbd4 100644 (file)
@@ -15,6 +15,9 @@ int bpf_decoder(unsigned int *sample)
 
                if (duration & 0x10000)
                        bpf_rc_keydown(sample, 0x40, duration & 0xffff, 0);
+               if (duration & 0x20000)
+                       bpf_rc_pointer_rel(sample, (duration >> 8) & 0xff,
+                                          duration & 0xff);
        }
 
        return 0;
index d470d63c33dbee631c49b48cd7d2dcd61a2651ad..fb5fd6841ef3954fba88646d38ed5e7a90a35547 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <linux/bpf.h>
 #include <linux/lirc.h>
+#include <linux/input.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 int main(int argc, char **argv)
 {
        struct bpf_object *obj;
-       int ret, lircfd, progfd, mode;
-       int testir = 0x1dead;
+       int ret, lircfd, progfd, inputfd;
+       int testir1 = 0x1dead;
+       int testir2 = 0x20101;
        u32 prog_ids[10], prog_flags[10], prog_cnt;
 
-       if (argc != 2) {
-               printf("Usage: %s /dev/lircN\n", argv[0]);
+       if (argc != 3) {
+               printf("Usage: %s /dev/lircN /dev/input/eventM\n", argv[0]);
                return 2;
        }
 
@@ -76,9 +78,9 @@ int main(int argc, char **argv)
                return 1;
        }
 
-       mode = LIRC_MODE_SCANCODE;
-       if (ioctl(lircfd, LIRC_SET_REC_MODE, &mode)) {
-               printf("failed to set rec mode: %m\n");
+       inputfd = open(argv[2], O_RDONLY | O_NONBLOCK);
+       if (inputfd == -1) {
+               printf("failed to open input device %s: %m\n", argv[1]);
                return 1;
        }
 
@@ -102,29 +104,54 @@ int main(int argc, char **argv)
        }
 
        /* Write raw IR */
-       ret = write(lircfd, &testir, sizeof(testir));
-       if (ret != sizeof(testir)) {
+       ret = write(lircfd, &testir1, sizeof(testir1));
+       if (ret != sizeof(testir1)) {
                printf("Failed to send test IR message: %m\n");
                return 1;
        }
 
-       struct pollfd pfd = { .fd = lircfd, .events = POLLIN };
-       struct lirc_scancode lsc;
+       struct pollfd pfd = { .fd = inputfd, .events = POLLIN };
+       struct input_event event;
 
-       poll(&pfd, 1, 100);
+       for (;;) {
+               poll(&pfd, 1, 100);
 
-       /* Read decoded IR */
-       ret = read(lircfd, &lsc, sizeof(lsc));
-       if (ret != sizeof(lsc)) {
-               printf("Failed to read decoded IR: %m\n");
-               return 1;
+               /* Read decoded IR */
+               ret = read(inputfd, &event, sizeof(event));
+               if (ret != sizeof(event)) {
+                       printf("Failed to read decoded IR: %m\n");
+                       return 1;
+               }
+
+               if (event.type == EV_MSC && event.code == MSC_SCAN &&
+                   event.value == 0xdead) {
+                       break;
+               }
        }
 
-       if (lsc.scancode != 0xdead || lsc.rc_proto != 64) {
-               printf("Incorrect scancode decoded\n");
+       /* Write raw IR */
+       ret = write(lircfd, &testir2, sizeof(testir2));
+       if (ret != sizeof(testir2)) {
+               printf("Failed to send test IR message: %m\n");
                return 1;
        }
 
+       for (;;) {
+               poll(&pfd, 1, 100);
+
+               /* Read decoded IR */
+               ret = read(inputfd, &event, sizeof(event));
+               if (ret != sizeof(event)) {
+                       printf("Failed to read decoded IR: %m\n");
+                       return 1;
+               }
+
+               if (event.type == EV_REL && event.code == REL_Y &&
+                   event.value == 1 ) {
+                       break;
+               }
+       }
+
        prog_cnt = 10;
        ret = bpf_prog_query(lircfd, BPF_LIRC_MODE2, 0, prog_flags, prog_ids,
                             &prog_cnt);