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