1*040adbe8SBenjamin Tissoires // SPDX-License-Identifier: GPL-2.0-only 2*040adbe8SBenjamin Tissoires /* Copyright (c) 2025 Red Hat 3*040adbe8SBenjamin Tissoires */ 4*040adbe8SBenjamin Tissoires 5*040adbe8SBenjamin Tissoires #include "vmlinux.h" 6*040adbe8SBenjamin Tissoires #include "hid_bpf.h" 7*040adbe8SBenjamin Tissoires #include "hid_bpf_helpers.h" 8*040adbe8SBenjamin Tissoires #include <bpf/bpf_tracing.h> 9*040adbe8SBenjamin Tissoires 10*040adbe8SBenjamin Tissoires #define VID_WALTOP 0x172F 11*040adbe8SBenjamin Tissoires #define PID_BATTERYLESS_TABLET 0x0505 12*040adbe8SBenjamin Tissoires 13*040adbe8SBenjamin Tissoires HID_BPF_CONFIG( 14*040adbe8SBenjamin Tissoires HID_DEVICE(BUS_USB, HID_GROUP_ANY, VID_WALTOP, PID_BATTERYLESS_TABLET) 15*040adbe8SBenjamin Tissoires ); 16*040adbe8SBenjamin Tissoires 17*040adbe8SBenjamin Tissoires #define EXPECTED_RDESC_SIZE 335 18*040adbe8SBenjamin Tissoires #define PEN_REPORT_ID 16 19*040adbe8SBenjamin Tissoires 20*040adbe8SBenjamin Tissoires #define TIP_SWITCH BIT(0) 21*040adbe8SBenjamin Tissoires #define BARREL_SWITCH BIT(1) 22*040adbe8SBenjamin Tissoires #define SECONDARY_BARREL_SWITCH BIT(5) 23*040adbe8SBenjamin Tissoires 24*040adbe8SBenjamin Tissoires static __u8 last_button_state; 25*040adbe8SBenjamin Tissoires 26*040adbe8SBenjamin Tissoires static const __u8 fixed_rdesc[] = { 27*040adbe8SBenjamin Tissoires 0x05, 0x01, // Usage Page (Generic Desktop) 28*040adbe8SBenjamin Tissoires 0x09, 0x02, // Usage (Mouse) 29*040adbe8SBenjamin Tissoires 0xa1, 0x01, // Collection (Application) 30*040adbe8SBenjamin Tissoires 0x85, 0x01, // Report ID (1) 31*040adbe8SBenjamin Tissoires 0x09, 0x01, // Usage (Pointer) 32*040adbe8SBenjamin Tissoires 0xa1, 0x00, // Collection (Physical) 33*040adbe8SBenjamin Tissoires 0x05, 0x09, // Usage Page (Button) 34*040adbe8SBenjamin Tissoires 0x19, 0x01, // Usage Minimum (1) 35*040adbe8SBenjamin Tissoires 0x29, 0x05, // Usage Maximum (5) 36*040adbe8SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 37*040adbe8SBenjamin Tissoires 0x25, 0x01, // Logical Maximum (1) 38*040adbe8SBenjamin Tissoires 0x75, 0x01, // Report Size (1) 39*040adbe8SBenjamin Tissoires 0x95, 0x05, // Report Count (5) 40*040adbe8SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 41*040adbe8SBenjamin Tissoires 0x75, 0x03, // Report Size (3) 42*040adbe8SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 43*040adbe8SBenjamin Tissoires 0x81, 0x03, // Input (Cnst,Var,Abs) 44*040adbe8SBenjamin Tissoires 0x05, 0x01, // Usage Page (Generic Desktop) 45*040adbe8SBenjamin Tissoires 0x09, 0x30, // Usage (X) 46*040adbe8SBenjamin Tissoires 0x09, 0x31, // Usage (Y) 47*040adbe8SBenjamin Tissoires 0x09, 0x38, // Usage (Wheel) 48*040adbe8SBenjamin Tissoires 0x15, 0x81, // Logical Minimum (-127) 49*040adbe8SBenjamin Tissoires 0x25, 0x7f, // Logical Maximum (127) 50*040adbe8SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 51*040adbe8SBenjamin Tissoires 0x95, 0x03, // Report Count (3) 52*040adbe8SBenjamin Tissoires 0x81, 0x06, // Input (Data,Var,Rel) 53*040adbe8SBenjamin Tissoires 0x05, 0x0c, // Usage Page (Consumer) 54*040adbe8SBenjamin Tissoires 0x15, 0x81, // Logical Minimum (-127) 55*040adbe8SBenjamin Tissoires 0x25, 0x7f, // Logical Maximum (127) 56*040adbe8SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 57*040adbe8SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 58*040adbe8SBenjamin Tissoires 0x0a, 0x38, 0x02, // Usage (AC Pan) 59*040adbe8SBenjamin Tissoires 0x81, 0x06, // Input (Data,Var,Rel) 60*040adbe8SBenjamin Tissoires 0xc0, // End Collection 61*040adbe8SBenjamin Tissoires 0xc0, // End Collection 62*040adbe8SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 63*040adbe8SBenjamin Tissoires 0x09, 0x02, // Usage (Pen) 64*040adbe8SBenjamin Tissoires 0xa1, 0x01, // Collection (Application) 65*040adbe8SBenjamin Tissoires 0x85, 0x02, // Report ID (2) 66*040adbe8SBenjamin Tissoires 0x09, 0x20, // Usage (Stylus) 67*040adbe8SBenjamin Tissoires 0xa1, 0x00, // Collection (Physical) 68*040adbe8SBenjamin Tissoires 0x09, 0x00, // Usage (0x0000) 69*040adbe8SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 70*040adbe8SBenjamin Tissoires 0x26, 0xff, 0x00, // Logical Maximum (255) 71*040adbe8SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 72*040adbe8SBenjamin Tissoires 0x95, 0x09, // Report Count (9) 73*040adbe8SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 74*040adbe8SBenjamin Tissoires 0x09, 0x3f, // Usage (Azimuth) 75*040adbe8SBenjamin Tissoires 0x09, 0x40, // Usage (Altitude) 76*040adbe8SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 77*040adbe8SBenjamin Tissoires 0x26, 0xff, 0x00, // Logical Maximum (255) 78*040adbe8SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 79*040adbe8SBenjamin Tissoires 0x95, 0x02, // Report Count (2) 80*040adbe8SBenjamin Tissoires 0xb1, 0x02, // Feature (Data,Var,Abs) 81*040adbe8SBenjamin Tissoires 0xc0, // End Collection 82*040adbe8SBenjamin Tissoires 0x85, 0x05, // Report ID (5) 83*040adbe8SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 84*040adbe8SBenjamin Tissoires 0x09, 0x20, // Usage (Stylus) 85*040adbe8SBenjamin Tissoires 0xa1, 0x00, // Collection (Physical) 86*040adbe8SBenjamin Tissoires 0x09, 0x00, // Usage (0x0000) 87*040adbe8SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 88*040adbe8SBenjamin Tissoires 0x26, 0xff, 0x00, // Logical Maximum (255) 89*040adbe8SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 90*040adbe8SBenjamin Tissoires 0x95, 0x07, // Report Count (7) 91*040adbe8SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 92*040adbe8SBenjamin Tissoires 0xc0, // End Collection 93*040adbe8SBenjamin Tissoires 0x85, 0x0a, // Report ID (10) 94*040adbe8SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 95*040adbe8SBenjamin Tissoires 0x09, 0x20, // Usage (Stylus) 96*040adbe8SBenjamin Tissoires 0xa1, 0x00, // Collection (Physical) 97*040adbe8SBenjamin Tissoires 0x09, 0x00, // Usage (0x0000) 98*040adbe8SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 99*040adbe8SBenjamin Tissoires 0x26, 0xff, 0x00, // Logical Maximum (255) 100*040adbe8SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 101*040adbe8SBenjamin Tissoires 0x95, 0x07, // Report Count (7) 102*040adbe8SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 103*040adbe8SBenjamin Tissoires 0xc0, // End Collection 104*040adbe8SBenjamin Tissoires 0x85, 0x10, // Report ID (16) 105*040adbe8SBenjamin Tissoires 0x09, 0x20, // Usage (Stylus) 106*040adbe8SBenjamin Tissoires 0xa1, 0x00, // Collection (Physical) 107*040adbe8SBenjamin Tissoires 0x09, 0x42, // Usage (Tip Switch) 108*040adbe8SBenjamin Tissoires 0x09, 0x44, // Usage (Barrel Switch) 109*040adbe8SBenjamin Tissoires 0x09, 0x3c, // Usage (Invert) 110*040adbe8SBenjamin Tissoires 0x09, 0x45, // Usage (Eraser) 111*040adbe8SBenjamin Tissoires 0x09, 0x32, // Usage (In Range) 112*040adbe8SBenjamin Tissoires 0x09, 0x5a, // Usage (Secondary Barrel Switch) <-- added 113*040adbe8SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 114*040adbe8SBenjamin Tissoires 0x25, 0x01, // Logical Maximum (1) 115*040adbe8SBenjamin Tissoires 0x75, 0x01, // Report Size (1) 116*040adbe8SBenjamin Tissoires 0x95, 0x06, // Report Count (6) <--- changed from 5 117*040adbe8SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 118*040adbe8SBenjamin Tissoires 0x95, 0x02, // Report Count (2) <--- changed from 3 119*040adbe8SBenjamin Tissoires 0x81, 0x03, // Input (Cnst,Var,Abs) 120*040adbe8SBenjamin Tissoires 0x05, 0x01, // Usage Page (Generic Desktop) 121*040adbe8SBenjamin Tissoires 0x09, 0x30, // Usage (X) 122*040adbe8SBenjamin Tissoires 0x75, 0x10, // Report Size (16) 123*040adbe8SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 124*040adbe8SBenjamin Tissoires 0xa4, // Push 125*040adbe8SBenjamin Tissoires 0x55, 0x0d, // Unit Exponent (-3) 126*040adbe8SBenjamin Tissoires 0x65, 0x33, // Unit (EnglishLinear: in³) 127*040adbe8SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 128*040adbe8SBenjamin Tissoires 0x26, 0x00, 0x7d, // Logical Maximum (32000) 129*040adbe8SBenjamin Tissoires 0x35, 0x00, // Physical Minimum (0) 130*040adbe8SBenjamin Tissoires 0x46, 0x00, 0x7d, // Physical Maximum (32000) 131*040adbe8SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 132*040adbe8SBenjamin Tissoires 0x09, 0x31, // Usage (Y) 133*040adbe8SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 134*040adbe8SBenjamin Tissoires 0x26, 0x20, 0x4e, // Logical Maximum (20000) 135*040adbe8SBenjamin Tissoires 0x35, 0x00, // Physical Minimum (0) 136*040adbe8SBenjamin Tissoires 0x46, 0x20, 0x4e, // Physical Maximum (20000) 137*040adbe8SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 138*040adbe8SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 139*040adbe8SBenjamin Tissoires 0x09, 0x30, // Usage (Tip Pressure) 140*040adbe8SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 141*040adbe8SBenjamin Tissoires 0x26, 0xff, 0x07, // Logical Maximum (2047) 142*040adbe8SBenjamin Tissoires 0x35, 0x00, // Physical Minimum (0) 143*040adbe8SBenjamin Tissoires 0x46, 0xff, 0x07, // Physical Maximum (2047) 144*040adbe8SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 145*040adbe8SBenjamin Tissoires 0x05, 0x0d, // Usage Page (Digitizers) 146*040adbe8SBenjamin Tissoires 0x09, 0x3d, // Usage (X Tilt) 147*040adbe8SBenjamin Tissoires 0x09, 0x3e, // Usage (Y Tilt) 148*040adbe8SBenjamin Tissoires 0x15, 0xc4, // Logical Minimum (-60) <- changed from -127 149*040adbe8SBenjamin Tissoires 0x25, 0x3c, // Logical Maximum (60) <- changed from 127 150*040adbe8SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 151*040adbe8SBenjamin Tissoires 0x95, 0x02, // Report Count (2) 152*040adbe8SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 153*040adbe8SBenjamin Tissoires 0xc0, // End Collection 154*040adbe8SBenjamin Tissoires 0xc0, // End Collection 155*040adbe8SBenjamin Tissoires 0x05, 0x01, // Usage Page (Generic Desktop) 156*040adbe8SBenjamin Tissoires 0x09, 0x06, // Usage (Keyboard) 157*040adbe8SBenjamin Tissoires 0xa1, 0x01, // Collection (Application) 158*040adbe8SBenjamin Tissoires 0x85, 0x0d, // Report ID (13) 159*040adbe8SBenjamin Tissoires 0x05, 0x07, // Usage Page (Keyboard/Keypad) 160*040adbe8SBenjamin Tissoires 0x19, 0xe0, // Usage Minimum (224) 161*040adbe8SBenjamin Tissoires 0x29, 0xe7, // Usage Maximum (231) 162*040adbe8SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 163*040adbe8SBenjamin Tissoires 0x25, 0x01, // Logical Maximum (1) 164*040adbe8SBenjamin Tissoires 0x75, 0x01, // Report Size (1) 165*040adbe8SBenjamin Tissoires 0x95, 0x08, // Report Count (8) 166*040adbe8SBenjamin Tissoires 0x81, 0x02, // Input (Data,Var,Abs) 167*040adbe8SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 168*040adbe8SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 169*040adbe8SBenjamin Tissoires 0x81, 0x01, // Input (Cnst,Arr,Abs) 170*040adbe8SBenjamin Tissoires 0x05, 0x07, // Usage Page (Keyboard/Keypad) 171*040adbe8SBenjamin Tissoires 0x19, 0x00, // Usage Minimum (0) 172*040adbe8SBenjamin Tissoires 0x29, 0x65, // Usage Maximum (101) 173*040adbe8SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 174*040adbe8SBenjamin Tissoires 0x25, 0x65, // Logical Maximum (101) 175*040adbe8SBenjamin Tissoires 0x75, 0x08, // Report Size (8) 176*040adbe8SBenjamin Tissoires 0x95, 0x05, // Report Count (5) 177*040adbe8SBenjamin Tissoires 0x81, 0x00, // Input (Data,Arr,Abs) 178*040adbe8SBenjamin Tissoires 0xc0, // End Collection 179*040adbe8SBenjamin Tissoires 0x05, 0x0c, // Usage Page (Consumer) 180*040adbe8SBenjamin Tissoires 0x09, 0x01, // Usage (Consumer Control) 181*040adbe8SBenjamin Tissoires 0xa1, 0x01, // Collection (Application) 182*040adbe8SBenjamin Tissoires 0x85, 0x0c, // Report ID (12) 183*040adbe8SBenjamin Tissoires 0x09, 0xe9, // Usage (Volume Increment) 184*040adbe8SBenjamin Tissoires 0x09, 0xea, // Usage (Volume Decrement) 185*040adbe8SBenjamin Tissoires 0x09, 0xe2, // Usage (Mute) 186*040adbe8SBenjamin Tissoires 0x15, 0x00, // Logical Minimum (0) 187*040adbe8SBenjamin Tissoires 0x25, 0x01, // Logical Maximum (1) 188*040adbe8SBenjamin Tissoires 0x75, 0x01, // Report Size (1) 189*040adbe8SBenjamin Tissoires 0x95, 0x03, // Report Count (3) 190*040adbe8SBenjamin Tissoires 0x81, 0x06, // Input (Data,Var,Rel) 191*040adbe8SBenjamin Tissoires 0x75, 0x05, // Report Size (5) 192*040adbe8SBenjamin Tissoires 0x95, 0x01, // Report Count (1) 193*040adbe8SBenjamin Tissoires 0x81, 0x07, // Input (Cnst,Var,Rel) 194*040adbe8SBenjamin Tissoires 0xc0, // End Collection 195*040adbe8SBenjamin Tissoires }; 196*040adbe8SBenjamin Tissoires 197*040adbe8SBenjamin Tissoires static inline unsigned int bitwidth32(__u32 x) 198*040adbe8SBenjamin Tissoires { 199*040adbe8SBenjamin Tissoires return 32 - __builtin_clzg(x, 32); 200*040adbe8SBenjamin Tissoires } 201*040adbe8SBenjamin Tissoires 202*040adbe8SBenjamin Tissoires static inline unsigned int floor_log2_32(__u32 x) 203*040adbe8SBenjamin Tissoires { 204*040adbe8SBenjamin Tissoires return bitwidth32(x) - 1; 205*040adbe8SBenjamin Tissoires } 206*040adbe8SBenjamin Tissoires 207*040adbe8SBenjamin Tissoires /* Maps the interval [0, 2047] to itself using a scaled 208*040adbe8SBenjamin Tissoires * approximation of the function log2(x+1). 209*040adbe8SBenjamin Tissoires */ 210*040adbe8SBenjamin Tissoires static unsigned int scaled_log2(__u16 v) 211*040adbe8SBenjamin Tissoires { 212*040adbe8SBenjamin Tissoires const unsigned int XMAX = 2047; 213*040adbe8SBenjamin Tissoires const unsigned int YMAX = 11; /* log2(2048) = 11 */ 214*040adbe8SBenjamin Tissoires 215*040adbe8SBenjamin Tissoires unsigned int x = v + 1; 216*040adbe8SBenjamin Tissoires unsigned int n = floor_log2_32(x); 217*040adbe8SBenjamin Tissoires unsigned int b = 1 << n; 218*040adbe8SBenjamin Tissoires 219*040adbe8SBenjamin Tissoires /* Fixed-point fraction in [0, 1), linearly 220*040adbe8SBenjamin Tissoires * interpolated using delta-y = 1 and 221*040adbe8SBenjamin Tissoires * delta-x = (2b - b) = b. 222*040adbe8SBenjamin Tissoires */ 223*040adbe8SBenjamin Tissoires unsigned int frac = (x - b) << YMAX; 224*040adbe8SBenjamin Tissoires unsigned int lerp = frac / b; 225*040adbe8SBenjamin Tissoires unsigned int log2 = (n << YMAX) + lerp; 226*040adbe8SBenjamin Tissoires 227*040adbe8SBenjamin Tissoires return ((log2 * XMAX) / YMAX) >> YMAX; 228*040adbe8SBenjamin Tissoires } 229*040adbe8SBenjamin Tissoires 230*040adbe8SBenjamin Tissoires SEC(HID_BPF_RDESC_FIXUP) 231*040adbe8SBenjamin Tissoires int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx) 232*040adbe8SBenjamin Tissoires { 233*040adbe8SBenjamin Tissoires __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */); 234*040adbe8SBenjamin Tissoires 235*040adbe8SBenjamin Tissoires if (!data) 236*040adbe8SBenjamin Tissoires return 0; /* EPERM check */ 237*040adbe8SBenjamin Tissoires 238*040adbe8SBenjamin Tissoires __builtin_memcpy(data, fixed_rdesc, sizeof(fixed_rdesc)); 239*040adbe8SBenjamin Tissoires 240*040adbe8SBenjamin Tissoires return sizeof(fixed_rdesc); 241*040adbe8SBenjamin Tissoires } 242*040adbe8SBenjamin Tissoires 243*040adbe8SBenjamin Tissoires SEC(HID_BPF_DEVICE_EVENT) 244*040adbe8SBenjamin Tissoires int BPF_PROG(waltop_fix_events, struct hid_bpf_ctx *hctx) 245*040adbe8SBenjamin Tissoires { 246*040adbe8SBenjamin Tissoires __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */); 247*040adbe8SBenjamin Tissoires 248*040adbe8SBenjamin Tissoires if (!data) 249*040adbe8SBenjamin Tissoires return 0; /* EPERM check */ 250*040adbe8SBenjamin Tissoires 251*040adbe8SBenjamin Tissoires __u8 report_id = data[0]; 252*040adbe8SBenjamin Tissoires 253*040adbe8SBenjamin Tissoires if (report_id != PEN_REPORT_ID) 254*040adbe8SBenjamin Tissoires return 0; 255*040adbe8SBenjamin Tissoires 256*040adbe8SBenjamin Tissoires /* On this tablet if the secondary barrel switch is pressed, 257*040adbe8SBenjamin Tissoires * the tablet sends tip down and barrel down. Change this to 258*040adbe8SBenjamin Tissoires * just secondary barrel down when there is no ambiguity. 259*040adbe8SBenjamin Tissoires * 260*040adbe8SBenjamin Tissoires * It's possible that there is a bug in the firmware and the 261*040adbe8SBenjamin Tissoires * device intends to set invert + eraser instead (i.e. the 262*040adbe8SBenjamin Tissoires * pysical button is an eraser button) but since 263*040adbe8SBenjamin Tissoires * the pressure is always zero, said eraser button 264*040adbe8SBenjamin Tissoires * would be useless anyway. 265*040adbe8SBenjamin Tissoires * 266*040adbe8SBenjamin Tissoires * So let's just change the button to secondary barrel down. 267*040adbe8SBenjamin Tissoires */ 268*040adbe8SBenjamin Tissoires 269*040adbe8SBenjamin Tissoires __u8 tip_switch = data[1] & TIP_SWITCH; 270*040adbe8SBenjamin Tissoires __u8 barrel_switch = data[1] & BARREL_SWITCH; 271*040adbe8SBenjamin Tissoires 272*040adbe8SBenjamin Tissoires __u8 tip_held = last_button_state & TIP_SWITCH; 273*040adbe8SBenjamin Tissoires __u8 barrel_held = last_button_state & BARREL_SWITCH; 274*040adbe8SBenjamin Tissoires 275*040adbe8SBenjamin Tissoires if (tip_switch && barrel_switch && !tip_held && !barrel_held) { 276*040adbe8SBenjamin Tissoires data[1] &= ~(TIP_SWITCH | BARREL_SWITCH); /* release tip and barrel */ 277*040adbe8SBenjamin Tissoires data[1] |= SECONDARY_BARREL_SWITCH; /* set secondary barrel switch */ 278*040adbe8SBenjamin Tissoires } 279*040adbe8SBenjamin Tissoires 280*040adbe8SBenjamin Tissoires last_button_state = data[1]; 281*040adbe8SBenjamin Tissoires 282*040adbe8SBenjamin Tissoires /* The pressure sensor on this tablet maps around half of the 283*040adbe8SBenjamin Tissoires * logical pressure range into the interval [0-100]. Further 284*040adbe8SBenjamin Tissoires * pressure causes the sensor value to increase exponentially 285*040adbe8SBenjamin Tissoires * up to a maximum value of 2047. 286*040adbe8SBenjamin Tissoires * 287*040adbe8SBenjamin Tissoires * The values 12 and 102 were chosen to have an integer slope 288*040adbe8SBenjamin Tissoires * with smooth transition between the two curves around the 289*040adbe8SBenjamin Tissoires * value 100. 290*040adbe8SBenjamin Tissoires */ 291*040adbe8SBenjamin Tissoires 292*040adbe8SBenjamin Tissoires __u16 pressure = (((__u16)data[6]) << 0) | (((__u16)data[7]) << 8); 293*040adbe8SBenjamin Tissoires 294*040adbe8SBenjamin Tissoires if (pressure <= 102) 295*040adbe8SBenjamin Tissoires pressure *= 12; 296*040adbe8SBenjamin Tissoires else 297*040adbe8SBenjamin Tissoires pressure = scaled_log2(pressure); 298*040adbe8SBenjamin Tissoires 299*040adbe8SBenjamin Tissoires data[6] = pressure >> 0; 300*040adbe8SBenjamin Tissoires data[7] = pressure >> 8; 301*040adbe8SBenjamin Tissoires 302*040adbe8SBenjamin Tissoires return 0; 303*040adbe8SBenjamin Tissoires } 304*040adbe8SBenjamin Tissoires 305*040adbe8SBenjamin Tissoires HID_BPF_OPS(waltop_batteryless) = { 306*040adbe8SBenjamin Tissoires .hid_device_event = (void *)waltop_fix_events, 307*040adbe8SBenjamin Tissoires .hid_rdesc_fixup = (void *)hid_fix_rdesc, 308*040adbe8SBenjamin Tissoires }; 309*040adbe8SBenjamin Tissoires 310*040adbe8SBenjamin Tissoires SEC("syscall") 311*040adbe8SBenjamin Tissoires int probe(struct hid_bpf_probe_args *ctx) 312*040adbe8SBenjamin Tissoires { 313*040adbe8SBenjamin Tissoires if (ctx->rdesc_size == EXPECTED_RDESC_SIZE) 314*040adbe8SBenjamin Tissoires ctx->retval = 0; 315*040adbe8SBenjamin Tissoires else 316*040adbe8SBenjamin Tissoires ctx->retval = -EINVAL; 317*040adbe8SBenjamin Tissoires 318*040adbe8SBenjamin Tissoires return 0; 319*040adbe8SBenjamin Tissoires } 320*040adbe8SBenjamin Tissoires 321*040adbe8SBenjamin Tissoires char _license[] SEC("license") = "GPL"; 322