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