|  | // 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"; |