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