xref: /linux/samples/hid/hid_surface_dial.bpf.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1a56a2569SBenjamin Tissoires // SPDX-License-Identifier: GPL-2.0-only
2a56a2569SBenjamin Tissoires /* Copyright (c) 2022 Benjamin Tissoires
3a56a2569SBenjamin Tissoires  */
4a56a2569SBenjamin Tissoires 
5a56a2569SBenjamin Tissoires #include "vmlinux.h"
6a56a2569SBenjamin Tissoires #include <bpf/bpf_helpers.h>
7a56a2569SBenjamin Tissoires #include <bpf/bpf_tracing.h>
8a56a2569SBenjamin Tissoires #include "hid_bpf_helpers.h"
9a56a2569SBenjamin Tissoires 
10a56a2569SBenjamin Tissoires #define HID_UP_BUTTON		0x0009
11a56a2569SBenjamin Tissoires #define HID_GD_WHEEL		0x0038
12a56a2569SBenjamin Tissoires 
13*a67a1debSBenjamin Tissoires SEC("struct_ops/hid_device_event")
BPF_PROG(hid_event,struct hid_bpf_ctx * hctx)14a56a2569SBenjamin Tissoires int BPF_PROG(hid_event, struct hid_bpf_ctx *hctx)
15a56a2569SBenjamin Tissoires {
16a56a2569SBenjamin Tissoires 	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */);
17a56a2569SBenjamin Tissoires 
18a56a2569SBenjamin Tissoires 	if (!data)
19a56a2569SBenjamin Tissoires 		return 0; /* EPERM check */
20a56a2569SBenjamin Tissoires 
21a56a2569SBenjamin Tissoires 	/* Touch */
22a56a2569SBenjamin Tissoires 	data[1] &= 0xfd;
23a56a2569SBenjamin Tissoires 
24a56a2569SBenjamin Tissoires 	/* X */
25a56a2569SBenjamin Tissoires 	data[4] = 0;
26a56a2569SBenjamin Tissoires 	data[5] = 0;
27a56a2569SBenjamin Tissoires 
28a56a2569SBenjamin Tissoires 	/* Y */
29a56a2569SBenjamin Tissoires 	data[6] = 0;
30a56a2569SBenjamin Tissoires 	data[7] = 0;
31a56a2569SBenjamin Tissoires 
32a56a2569SBenjamin Tissoires 	return 0;
33a56a2569SBenjamin Tissoires }
34a56a2569SBenjamin Tissoires 
35a56a2569SBenjamin Tissoires /* 72 == 360 / 5 -> 1 report every 5 degrees */
36a56a2569SBenjamin Tissoires int resolution = 72;
37a56a2569SBenjamin Tissoires int physical = 5;
38a56a2569SBenjamin Tissoires 
39a56a2569SBenjamin Tissoires struct haptic_syscall_args {
40a56a2569SBenjamin Tissoires 	unsigned int hid;
41a56a2569SBenjamin Tissoires 	int retval;
42a56a2569SBenjamin Tissoires };
43a56a2569SBenjamin Tissoires 
44a56a2569SBenjamin Tissoires static __u8 haptic_data[8];
45a56a2569SBenjamin Tissoires 
46a56a2569SBenjamin Tissoires SEC("syscall")
set_haptic(struct haptic_syscall_args * args)47a56a2569SBenjamin Tissoires int set_haptic(struct haptic_syscall_args *args)
48a56a2569SBenjamin Tissoires {
49a56a2569SBenjamin Tissoires 	struct hid_bpf_ctx *ctx;
50a56a2569SBenjamin Tissoires 	const size_t size = sizeof(haptic_data);
51a56a2569SBenjamin Tissoires 	u16 *res;
52a56a2569SBenjamin Tissoires 	int ret;
53a56a2569SBenjamin Tissoires 
54a56a2569SBenjamin Tissoires 	if (size > sizeof(haptic_data))
55a56a2569SBenjamin Tissoires 		return -7; /* -E2BIG */
56a56a2569SBenjamin Tissoires 
57a56a2569SBenjamin Tissoires 	ctx = hid_bpf_allocate_context(args->hid);
58a56a2569SBenjamin Tissoires 	if (!ctx)
59a56a2569SBenjamin Tissoires 		return -1; /* EPERM check */
60a56a2569SBenjamin Tissoires 
61a56a2569SBenjamin Tissoires 	haptic_data[0] = 1;  /* report ID */
62a56a2569SBenjamin Tissoires 
63a56a2569SBenjamin Tissoires 	ret = hid_bpf_hw_request(ctx, haptic_data, size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
64a56a2569SBenjamin Tissoires 
65a56a2569SBenjamin Tissoires 	bpf_printk("probed/remove event ret value: %d", ret);
66a56a2569SBenjamin Tissoires 	bpf_printk("buf: %02x %02x %02x",
67a56a2569SBenjamin Tissoires 		   haptic_data[0],
68a56a2569SBenjamin Tissoires 		   haptic_data[1],
69a56a2569SBenjamin Tissoires 		   haptic_data[2]);
70a56a2569SBenjamin Tissoires 	bpf_printk("     %02x %02x %02x",
71a56a2569SBenjamin Tissoires 		   haptic_data[3],
72a56a2569SBenjamin Tissoires 		   haptic_data[4],
73a56a2569SBenjamin Tissoires 		   haptic_data[5]);
74a56a2569SBenjamin Tissoires 	bpf_printk("     %02x %02x",
75a56a2569SBenjamin Tissoires 		   haptic_data[6],
76a56a2569SBenjamin Tissoires 		   haptic_data[7]);
77a56a2569SBenjamin Tissoires 
78a56a2569SBenjamin Tissoires 	/* whenever resolution multiplier is not 3600, we have the fixed report descriptor */
79a56a2569SBenjamin Tissoires 	res = (u16 *)&haptic_data[1];
80a56a2569SBenjamin Tissoires 	if (*res != 3600) {
81a56a2569SBenjamin Tissoires //		haptic_data[1] = 72; /* resolution multiplier */
82a56a2569SBenjamin Tissoires //		haptic_data[2] = 0;  /* resolution multiplier */
83a56a2569SBenjamin Tissoires //		haptic_data[3] = 0;  /* Repeat Count */
84a56a2569SBenjamin Tissoires 		haptic_data[4] = 3;  /* haptic Auto Trigger */
85a56a2569SBenjamin Tissoires //		haptic_data[5] = 5;  /* Waveform Cutoff Time */
86a56a2569SBenjamin Tissoires //		haptic_data[6] = 80; /* Retrigger Period */
87a56a2569SBenjamin Tissoires //		haptic_data[7] = 0;  /* Retrigger Period */
88a56a2569SBenjamin Tissoires 	} else {
89a56a2569SBenjamin Tissoires 		haptic_data[4] = 0;
90a56a2569SBenjamin Tissoires 	}
91a56a2569SBenjamin Tissoires 
92a56a2569SBenjamin Tissoires 	ret = hid_bpf_hw_request(ctx, haptic_data, size, HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
93a56a2569SBenjamin Tissoires 
94a56a2569SBenjamin Tissoires 	bpf_printk("set haptic ret value: %d -> %d", ret, haptic_data[4]);
95a56a2569SBenjamin Tissoires 
96a56a2569SBenjamin Tissoires 	args->retval = ret;
97a56a2569SBenjamin Tissoires 
98a56a2569SBenjamin Tissoires 	hid_bpf_release_context(ctx);
99a56a2569SBenjamin Tissoires 
100a56a2569SBenjamin Tissoires 	return 0;
101a56a2569SBenjamin Tissoires }
102a56a2569SBenjamin Tissoires 
103a56a2569SBenjamin Tissoires /* Convert REL_DIAL into REL_WHEEL */
104*a67a1debSBenjamin Tissoires SEC("struct_ops/hid_rdesc_fixup")
BPF_PROG(hid_rdesc_fixup,struct hid_bpf_ctx * hctx)105a56a2569SBenjamin Tissoires int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx)
106a56a2569SBenjamin Tissoires {
107a56a2569SBenjamin Tissoires 	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
108a56a2569SBenjamin Tissoires 	__u16 *res, *phys;
109a56a2569SBenjamin Tissoires 
110a56a2569SBenjamin Tissoires 	if (!data)
111a56a2569SBenjamin Tissoires 		return 0; /* EPERM check */
112a56a2569SBenjamin Tissoires 
113a56a2569SBenjamin Tissoires 	/* Convert TOUCH into a button */
114a56a2569SBenjamin Tissoires 	data[31] = HID_UP_BUTTON;
115a56a2569SBenjamin Tissoires 	data[33] = 2;
116a56a2569SBenjamin Tissoires 
117a56a2569SBenjamin Tissoires 	/* Convert REL_DIAL into REL_WHEEL */
118a56a2569SBenjamin Tissoires 	data[45] = HID_GD_WHEEL;
119a56a2569SBenjamin Tissoires 
120a56a2569SBenjamin Tissoires 	/* Change Resolution Multiplier */
121a56a2569SBenjamin Tissoires 	phys = (__u16 *)&data[61];
122a56a2569SBenjamin Tissoires 	*phys = physical;
123a56a2569SBenjamin Tissoires 	res = (__u16 *)&data[66];
124a56a2569SBenjamin Tissoires 	*res = resolution;
125a56a2569SBenjamin Tissoires 
126a56a2569SBenjamin Tissoires 	/* Convert X,Y from Abs to Rel */
127a56a2569SBenjamin Tissoires 	data[88] = 0x06;
128a56a2569SBenjamin Tissoires 	data[98] = 0x06;
129a56a2569SBenjamin Tissoires 
130a56a2569SBenjamin Tissoires 	return 0;
131a56a2569SBenjamin Tissoires }
132a56a2569SBenjamin Tissoires 
133e342d6f6SBenjamin Tissoires SEC(".struct_ops.link")
134e342d6f6SBenjamin Tissoires struct hid_bpf_ops surface_dial = {
135*a67a1debSBenjamin Tissoires 	.hid_rdesc_fixup = (void *)hid_rdesc_fixup,
136*a67a1debSBenjamin Tissoires 	.hid_device_event = (void *)hid_event,
137e342d6f6SBenjamin Tissoires };
138e342d6f6SBenjamin Tissoires 
139a56a2569SBenjamin Tissoires char _license[] SEC("license") = "GPL";
140a56a2569SBenjamin Tissoires u32 _version SEC("version") = 1;
141