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