root/samples/hid/hid_mouse.bpf.c
// SPDX-License-Identifier: GPL-2.0

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "hid_bpf_helpers.h"

static int hid_y_event(struct hid_bpf_ctx *hctx)
{
        s16 y;
        __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */);

        if (!data)
                return 0; /* EPERM check */

        bpf_printk("event: size: %d", hctx->size);
        bpf_printk("incoming event: %02x %02x %02x",
                   data[0],
                   data[1],
                   data[2]);
        bpf_printk("                %02x %02x %02x",
                   data[3],
                   data[4],
                   data[5]);
        bpf_printk("                %02x %02x %02x",
                   data[6],
                   data[7],
                   data[8]);

        y = data[3] | (data[4] << 8);

        y = -y;

        data[3] = y & 0xFF;
        data[4] = (y >> 8) & 0xFF;

        bpf_printk("modified event: %02x %02x %02x",
                   data[0],
                   data[1],
                   data[2]);
        bpf_printk("                %02x %02x %02x",
                   data[3],
                   data[4],
                   data[5]);
        bpf_printk("                %02x %02x %02x",
                   data[6],
                   data[7],
                   data[8]);

        return 0;
}

static int hid_x_event(struct hid_bpf_ctx *hctx)
{
        s16 x;
        __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */);

        if (!data)
                return 0; /* EPERM check */

        x = data[1] | (data[2] << 8);

        x = -x;

        data[1] = x & 0xFF;
        data[2] = (x >> 8) & 0xFF;
        return 0;
}

SEC("struct_ops/hid_device_event")
int BPF_PROG(hid_event, struct hid_bpf_ctx *hctx, enum hid_report_type type)
{
        int ret = hid_y_event(hctx);

        if (ret)
                return ret;

        return hid_x_event(hctx);
}


SEC("struct_ops/hid_rdesc_fixup")
int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx)
{
        __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);

        if (!data)
                return 0; /* EPERM check */

        bpf_printk("rdesc: %02x %02x %02x",
                   data[0],
                   data[1],
                   data[2]);
        bpf_printk("       %02x %02x %02x",
                   data[3],
                   data[4],
                   data[5]);
        bpf_printk("       %02x %02x %02x ...",
                   data[6],
                   data[7],
                   data[8]);

        /*
         * The original report descriptor contains:
         *
         * 0x05, 0x01,                    //   Usage Page (Generic Desktop)      30
         * 0x16, 0x01, 0x80,              //   Logical Minimum (-32767)          32
         * 0x26, 0xff, 0x7f,              //   Logical Maximum (32767)           35
         * 0x09, 0x30,                    //   Usage (X)                         38
         * 0x09, 0x31,                    //   Usage (Y)                         40
         *
         * So byte 39 contains Usage X and byte 41 Usage Y.
         *
         * We simply swap the axes here.
         */
        data[39] = 0x31;
        data[41] = 0x30;

        return 0;
}

SEC(".struct_ops.link")
struct hid_bpf_ops mouse_invert = {
        .hid_rdesc_fixup = (void *)hid_rdesc_fixup,
        .hid_device_event = (void *)hid_event,
};

char _license[] SEC("license") = "GPL";