162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Copyright (c) 2022 Benjamin Tissoires
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include "vmlinux.h"
662306a36Sopenharmony_ci#include <bpf/bpf_helpers.h>
762306a36Sopenharmony_ci#include <bpf/bpf_tracing.h>
862306a36Sopenharmony_ci#include "hid_bpf_helpers.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define HID_UP_BUTTON		0x0009
1162306a36Sopenharmony_ci#define HID_GD_WHEEL		0x0038
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ciSEC("fmod_ret/hid_bpf_device_event")
1462306a36Sopenharmony_ciint BPF_PROG(hid_event, struct hid_bpf_ctx *hctx)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */);
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	if (!data)
1962306a36Sopenharmony_ci		return 0; /* EPERM check */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	/* Touch */
2262306a36Sopenharmony_ci	data[1] &= 0xfd;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	/* X */
2562306a36Sopenharmony_ci	data[4] = 0;
2662306a36Sopenharmony_ci	data[5] = 0;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	/* Y */
2962306a36Sopenharmony_ci	data[6] = 0;
3062306a36Sopenharmony_ci	data[7] = 0;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	return 0;
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/* 72 == 360 / 5 -> 1 report every 5 degrees */
3662306a36Sopenharmony_ciint resolution = 72;
3762306a36Sopenharmony_ciint physical = 5;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistruct haptic_syscall_args {
4062306a36Sopenharmony_ci	unsigned int hid;
4162306a36Sopenharmony_ci	int retval;
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic __u8 haptic_data[8];
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciSEC("syscall")
4762306a36Sopenharmony_ciint set_haptic(struct haptic_syscall_args *args)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct hid_bpf_ctx *ctx;
5062306a36Sopenharmony_ci	const size_t size = sizeof(haptic_data);
5162306a36Sopenharmony_ci	u16 *res;
5262306a36Sopenharmony_ci	int ret;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (size > sizeof(haptic_data))
5562306a36Sopenharmony_ci		return -7; /* -E2BIG */
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	ctx = hid_bpf_allocate_context(args->hid);
5862306a36Sopenharmony_ci	if (!ctx)
5962306a36Sopenharmony_ci		return -1; /* EPERM check */
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	haptic_data[0] = 1;  /* report ID */
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	ret = hid_bpf_hw_request(ctx, haptic_data, size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	bpf_printk("probed/remove event ret value: %d", ret);
6662306a36Sopenharmony_ci	bpf_printk("buf: %02x %02x %02x",
6762306a36Sopenharmony_ci		   haptic_data[0],
6862306a36Sopenharmony_ci		   haptic_data[1],
6962306a36Sopenharmony_ci		   haptic_data[2]);
7062306a36Sopenharmony_ci	bpf_printk("     %02x %02x %02x",
7162306a36Sopenharmony_ci		   haptic_data[3],
7262306a36Sopenharmony_ci		   haptic_data[4],
7362306a36Sopenharmony_ci		   haptic_data[5]);
7462306a36Sopenharmony_ci	bpf_printk("     %02x %02x",
7562306a36Sopenharmony_ci		   haptic_data[6],
7662306a36Sopenharmony_ci		   haptic_data[7]);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/* whenever resolution multiplier is not 3600, we have the fixed report descriptor */
7962306a36Sopenharmony_ci	res = (u16 *)&haptic_data[1];
8062306a36Sopenharmony_ci	if (*res != 3600) {
8162306a36Sopenharmony_ci//		haptic_data[1] = 72; /* resolution multiplier */
8262306a36Sopenharmony_ci//		haptic_data[2] = 0;  /* resolution multiplier */
8362306a36Sopenharmony_ci//		haptic_data[3] = 0;  /* Repeat Count */
8462306a36Sopenharmony_ci		haptic_data[4] = 3;  /* haptic Auto Trigger */
8562306a36Sopenharmony_ci//		haptic_data[5] = 5;  /* Waveform Cutoff Time */
8662306a36Sopenharmony_ci//		haptic_data[6] = 80; /* Retrigger Period */
8762306a36Sopenharmony_ci//		haptic_data[7] = 0;  /* Retrigger Period */
8862306a36Sopenharmony_ci	} else {
8962306a36Sopenharmony_ci		haptic_data[4] = 0;
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	ret = hid_bpf_hw_request(ctx, haptic_data, size, HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	bpf_printk("set haptic ret value: %d -> %d", ret, haptic_data[4]);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	args->retval = ret;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	hid_bpf_release_context(ctx);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return 0;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/* Convert REL_DIAL into REL_WHEEL */
10462306a36Sopenharmony_ciSEC("fmod_ret/hid_bpf_rdesc_fixup")
10562306a36Sopenharmony_ciint BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
10862306a36Sopenharmony_ci	__u16 *res, *phys;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (!data)
11162306a36Sopenharmony_ci		return 0; /* EPERM check */
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	/* Convert TOUCH into a button */
11462306a36Sopenharmony_ci	data[31] = HID_UP_BUTTON;
11562306a36Sopenharmony_ci	data[33] = 2;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	/* Convert REL_DIAL into REL_WHEEL */
11862306a36Sopenharmony_ci	data[45] = HID_GD_WHEEL;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/* Change Resolution Multiplier */
12162306a36Sopenharmony_ci	phys = (__u16 *)&data[61];
12262306a36Sopenharmony_ci	*phys = physical;
12362306a36Sopenharmony_ci	res = (__u16 *)&data[66];
12462306a36Sopenharmony_ci	*res = resolution;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* Convert X,Y from Abs to Rel */
12762306a36Sopenharmony_ci	data[88] = 0x06;
12862306a36Sopenharmony_ci	data[98] = 0x06;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	return 0;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cichar _license[] SEC("license") = "GPL";
13462306a36Sopenharmony_ciu32 _version SEC("version") = 1;
135