Path: blob/master/drivers/hid/bpf/progs/Logitech__SpaceNavigator.bpf.c
38241 views
// SPDX-License-Identifier: GPL-2.0-only1/* Copyright (c) 2025 Curran Muhlberger2*/34#include "vmlinux.h"5#include "hid_bpf.h"6#include "hid_bpf_helpers.h"7#include <bpf/bpf_tracing.h>89#define VID_LOGITECH 0x046D10#define PID_SPACENAVIGATOR 0xC6261112HID_BPF_CONFIG(13HID_DEVICE(BUS_USB, HID_GROUP_ANY, VID_LOGITECH, PID_SPACENAVIGATOR)14);1516/*17* The 3Dconnexion SpaceNavigator 3D Mouse is a multi-axis controller with 618* axes (grouped as X,Y,Z and Rx,Ry,Rz). Axis data is absolute, but the report19* descriptor erroneously declares it to be relative. We fix the report20* descriptor to mark both axis collections as absolute.21*22* The kernel attempted to fix this in commit 24985cf68612 (HID: support23* Logitech/3DConnexion SpaceTraveler and SpaceNavigator), but the descriptor24* data offsets are incorrect for at least some SpaceNavigator units.25*/2627SEC(HID_BPF_RDESC_FIXUP)28int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx)29{30__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);3132if (!data)33return 0; /* EPERM check */3435/* Offset of Input item in X,Y,Z and Rx,Ry,Rz collections for all known36* firmware variants.37* - 2009 model: X,Y,Z @ 32-33, Rx,Ry,Rz @ 49-50 (fixup originally38* applied in kernel)39* - 2016 model (size==228): X,Y,Z @ 36-37, Rx,Ry,Rz @ 53-5440*41* The descriptor size of the 2009 model is not known, and there is evidence42* for at least two other variants (with sizes 202 & 217) besides the 201643* model, so we try all known offsets regardless of descriptor size.44*/45const u8 offsets[] = {32, 36, 49, 53};4647for (size_t idx = 0; idx < ARRAY_SIZE(offsets); idx++) {48u8 offset = offsets[idx];4950/* if Input (Data,Var,Rel) , make it Input (Data,Var,Abs) */51if (data[offset] == 0x81 && data[offset + 1] == 0x06)52data[offset + 1] = 0x02;53}5455return 0;56}5758HID_BPF_OPS(logitech_spacenavigator) = {59.hid_rdesc_fixup = (void *)hid_fix_rdesc,60};6162SEC("syscall")63int probe(struct hid_bpf_probe_args *ctx)64{65/* Ensure report descriptor size matches one of the known variants. */66if (ctx->rdesc_size != 202 &&67ctx->rdesc_size != 217 &&68ctx->rdesc_size != 228) {69ctx->retval = -EINVAL;70return 0;71}7273/* Check whether the kernel has already applied the fix. */74if ((ctx->rdesc[32] == 0x81 && ctx->rdesc[33] == 0x02 &&75ctx->rdesc[49] == 0x81 && ctx->rdesc[50] == 0x02) ||76(ctx->rdesc[36] == 0x81 && ctx->rdesc[37] == 0x02 &&77ctx->rdesc[53] == 0x81 && ctx->rdesc[54] == 0x02))78ctx->retval = -EINVAL;79else80ctx->retval = 0;8182return 0;83}8485char _license[] SEC("license") = "GPL";868788