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