Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'hid-for-linus-2025120201' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid

Pull HID updates from Jiri Kosina:

- Proper mapping of HID_GD_Z to ABS_DISTANCE for stylus/pen types of
devices (Ping Cheng)

- Power management/hibernation improvements in intel-ish (Zhang Lixu)

- Improved support for several Logitech devices, e.g. G Pro X
Superlight 2, new iteration of Lighspeed receiver, G13, G510 (Nathan
Rossi, Mavroudis Chatzilazaridis, Leo L Schwab, Hans de Goede)

- Support for UcLogic XP-PEN Artist 24 Pro (Joshua Goins)

- WinWing Orion2 throttle support improvement (Ivan Gorinov)

- other assorted small fixes and device ID additions

* tag 'hid-for-linus-2025120201' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (37 commits)
drivers: hid: renegotiate resolution multipliers with device after reset
HID: evision: Fix Report Descriptor for Evision Wireless Receiver 320f:226f
HID: logitech-dj: Fix probe failure when used with KVM
HID: logitech-dj: Remove duplicate error logging
HID: logitech-dj: Add support for G Pro X Superlight 2 receiver
selftests/hid-tablet: add ABS_DISTANCE test for stylus/pen
HID: input: map HID_GD_Z to ABS_DISTANCE for stylus/pen
HID: bpf: fix typo in HID usage table
HID: bpf: add the Huion Kamvas 27 Pro
HID: bpf: add heuristics to the Huion Inspiroy 2S eraser button
HID: bpf: Add support for XP-Pen Deco02
HID: bpf: Add support for the XP-Pen Deco 01 V3
HID: bpf: Add support for the Waltop Batteryless Tablet
HID: bpf: Add fixup for Logitech SpaceNavigator variants
HID: bpf: support for Huion Kamvas 16 Gen 3
HID: bpf: add support for Huion Kamvas 13 (Gen 3) (model GS1333)
HID: bpf: Add support for the Inspiroy 2M
Documentation: hid-alps: Format DataByte* subsection headings
Documentation: hid-alps: Fix packet format section headings
HID: nintendo: add WQ_PERCPU to alloc_workqueue users
...

+4980 -213
+6 -2
Documentation/hid/hid-alps.rst
··· 69 69 The command format is as below. 70 70 71 71 DataByte(SET_REPORT) 72 + ~~~~~~~~~~~~~~~~~~~~ 72 73 73 74 ===== ====================== 74 75 Byte1 Command Byte ··· 90 89 When you read RAM, there is no meaning. 91 90 92 91 DataByte(GET_REPORT) 92 + ~~~~~~~~~~~~~~~~~~~~ 93 93 94 94 ===== ====================== 95 95 Byte1 Response Byte ··· 106 104 107 105 108 106 Packet Format 107 + ------------- 108 + 109 109 Touchpad data byte 110 - ------------------ 110 + ~~~~~~~~~~~~~~~~~~ 111 111 112 112 113 113 ======= ======= ======= ======= ======= ======= ======= ======= ===== ··· 160 156 161 157 162 158 StickPointer data byte 163 - ---------------------- 159 + ~~~~~~~~~~~~~~~~~~~~~~ 164 160 165 161 ======= ======= ======= ======= ======= ======= ======= ======= ===== 166 162 - b7 b6 b5 b4 b3 b2 b1 b0
+3
drivers/hid/Kconfig
··· 383 383 help 384 384 Support for some EVision keyboards. Note that this is needed only when 385 385 applying customization using userspace programs. 386 + Support for some EVision devices requiring report descriptor fixups. 386 387 387 388 config HID_EZKEY 388 389 tristate "Ezkey BTC 8193 keyboard" ··· 1319 1318 help 1320 1319 Support for WinWing Orion2 throttle base with the following grips: 1321 1320 1321 + * TGRIP-15E 1322 + * TGRIP-15EX 1322 1323 * TGRIP-16EX 1323 1324 * TGRIP-18 1324 1325
+563
drivers/hid/bpf/progs/Huion__Inspiroy-2-M.bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright (c) 2024 Red Hat, Inc 3 + */ 4 + 5 + #include "vmlinux.h" 6 + #include "hid_bpf.h" 7 + #include "hid_bpf_helpers.h" 8 + #include "hid_report_helpers.h" 9 + #include <bpf/bpf_tracing.h> 10 + 11 + #define VID_HUION 0x256C 12 + #define PID_INSPIROY_2_M 0x0067 13 + 14 + HID_BPF_CONFIG( 15 + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HUION, PID_INSPIROY_2_M), 16 + ); 17 + 18 + /* Filled in by udev-hid-bpf */ 19 + char UDEV_PROP_HUION_FIRMWARE_ID[64]; 20 + 21 + /* The prefix of the firmware ID we expect for this device. The full firmware 22 + * string has a date suffix, e.g. HUION_T21j_221221 23 + */ 24 + char EXPECTED_FIRMWARE_ID[] = "HUION_T21k_"; 25 + 26 + /* How this BPF program works: the tablet has two modes, firmware mode and 27 + * tablet mode. In firmware mode (out of the box) the tablet sends button events 28 + * and the dial as keyboard combinations. In tablet mode it uses a vendor specific 29 + * hid report to report everything instead. 30 + * Depending on the mode some hid reports are never sent and the corresponding 31 + * devices are mute. 32 + * 33 + * To switch the tablet use e.g. https://github.com/whot/huion-switcher 34 + * or one of the tools from the digimend project 35 + * 36 + * This BPF works for both modes. The huion-switcher tool sets the 37 + * HUION_FIRMWARE_ID udev property - if that is set then we disable the firmware 38 + * pad and pen reports (by making them vendor collections that are ignored). 39 + * If that property is not set we fix all hidraw nodes so the tablet works in 40 + * either mode though the drawback is that the device will show up twice if 41 + * you bind it to all event nodes 42 + * 43 + * Default report descriptor for the first exposed hidraw node: 44 + * 45 + * # HUION Huion Tablet_H641P 46 + * # Report descriptor length: 18 bytes 47 + * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 0xFF00) 0 48 + * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 3 49 + * # 0xa1, 0x01, // Collection (Application) 5 50 + * # 0x85, 0x08, // Report ID (8) 7 51 + * # 0x75, 0x58, // Report Size (88) 9 52 + * # 0x95, 0x01, // Report Count (1) 11 53 + * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 13 54 + * # 0x81, 0x02, // Input (Data,Var,Abs) 15 55 + * # 0xc0, // End Collection 17 56 + * R: 18 06 00 ff 09 01 a1 01 85 08 75 58 95 01 09 01 81 02 c0 57 + * 58 + * This rdesc does nothing until the tablet is switched to raw mode, see 59 + * https://github.com/whot/huion-switcher 60 + * 61 + * 62 + * Second hidraw node is the Pen. This one sends events until the tablet is 63 + * switched to raw mode, then it's mute. 64 + * 65 + * # Report descriptor length: 93 bytes 66 + * # 0x05, 0x0d, // Usage Page (Digitizers) 0 67 + * # 0x09, 0x02, // Usage (Pen) 2 68 + * # 0xa1, 0x01, // Collection (Application) 4 69 + * # 0x85, 0x0a, // Report ID (10) 6 70 + * # 0x09, 0x20, // Usage (Stylus) 8 71 + * # 0xa1, 0x01, // Collection (Application) 10 72 + * # 0x09, 0x42, // Usage (Tip Switch) 12 73 + * # 0x09, 0x44, // Usage (Barrel Switch) 14 74 + * # 0x09, 0x45, // Usage (Eraser) 16 75 + * # 0x09, 0x3c, // Usage (Invert) 18 <-- has no Invert eraser 76 + * # 0x15, 0x00, // Logical Minimum (0) 20 77 + * # 0x25, 0x01, // Logical Maximum (1) 22 78 + * # 0x75, 0x01, // Report Size (1) 24 79 + * # 0x95, 0x06, // Report Count (6) 26 80 + * # 0x81, 0x02, // Input (Data,Var,Abs) 28 81 + * # 0x09, 0x32, // Usage (In Range) 30 82 + * # 0x75, 0x01, // Report Size (1) 32 83 + * # 0x95, 0x01, // Report Count (1) 34 84 + * # 0x81, 0x02, // Input (Data,Var,Abs) 36 85 + * # 0x81, 0x03, // Input (Cnst,Var,Abs) 38 86 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 40 87 + * # 0x09, 0x30, // Usage (X) 42 88 + * # 0x09, 0x31, // Usage (Y) 44 89 + * # 0x55, 0x0d, // Unit Exponent (-3) 46 <-- change to -2 90 + * # 0x65, 0x33, // Unit (EnglishLinear: in³) 48 <-- change in³ to in 91 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 50 92 + * # 0x35, 0x00, // Physical Minimum (0) 53 93 + * # 0x46, 0x00, 0x08, // Physical Maximum (2048) 55 <-- invalid size 94 + * # 0x75, 0x10, // Report Size (16) 58 95 + * # 0x95, 0x02, // Report Count (2) 60 96 + * # 0x81, 0x02, // Input (Data,Var,Abs) 62 97 + * # 0x05, 0x0d, // Usage Page (Digitizers) 64 98 + * # 0x09, 0x30, // Usage (Tip Pressure) 66 99 + * # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 68 100 + * # 0x75, 0x10, // Report Size (16) 71 101 + * # 0x95, 0x01, // Report Count (1) 73 102 + * # 0x81, 0x02, // Input (Data,Var,Abs) 75 103 + * # 0x09, 0x3d, // Usage (X Tilt) 77 <-- No tilt reported 104 + * # 0x09, 0x3e, // Usage (Y Tilt) 79 105 + * # 0x15, 0x81, // Logical Minimum (-127) 81 106 + * # 0x25, 0x7f, // Logical Maximum (127) 83 107 + * # 0x75, 0x08, // Report Size (8) 85 108 + * # 0x95, 0x02, // Report Count (2) 87 109 + * # 0x81, 0x02, // Input (Data,Var,Abs) 89 110 + * # 0xc0, // End Collection 91 111 + * # 0xc0, // End Collection 92 112 + * R: 93 05 0d 09 02 a1 01 85 0a 09 20 a1 01 09 42 09 44 09 45 09 3c 15 00 25 01 7501 95 06 81 02 09 32 75 01 95 01 81 02 81 03 05 01 09 30 09 31 55 0d 65 33 26 ff7f 35 00 46 00 08 75 10 95 02 81 02 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 09 3d09 3e 15 81 25 7f 75 08 95 02 81 02 c0 c0 113 + * 114 + * Third hidraw node is the pad which sends a combination of keyboard shortcuts until 115 + * the tablet is switched to raw mode, then it's mute: 116 + * 117 + * # Report descriptor length: 65 bytes 118 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 0 119 + * # 0x09, 0x06, // Usage (Keyboard) 2 120 + * # 0xa1, 0x01, // Collection (Application) 4 121 + * # 0x85, 0x03, // Report ID (3) 6 122 + * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 8 123 + * # 0x19, 0xe0, // UsageMinimum (224) 10 124 + * # 0x29, 0xe7, // UsageMaximum (231) 12 125 + * # 0x15, 0x00, // Logical Minimum (0) 14 126 + * # 0x25, 0x01, // Logical Maximum (1) 16 127 + * # 0x75, 0x01, // Report Size (1) 18 128 + * # 0x95, 0x08, // Report Count (8) 20 129 + * # 0x81, 0x02, // Input (Data,Var,Abs) 22 130 + * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 24 131 + * # 0x19, 0x00, // UsageMinimum (0) 26 132 + * # 0x29, 0xff, // UsageMaximum (255) 28 133 + * # 0x26, 0xff, 0x00, // Logical Maximum (255) 30 134 + * # 0x75, 0x08, // Report Size (8) 33 135 + * # 0x95, 0x06, // Report Count (6) 35 136 + * # 0x81, 0x00, // Input (Data,Arr,Abs) 37 137 + * # 0xc0, // End Collection 39 138 + * # 0x05, 0x0c, // Usage Page (Consumer) 40 139 + * # 0x09, 0x01, // Usage (Consumer Control) 42 140 + * # 0xa1, 0x01, // Collection (Application) 44 141 + * # 0x85, 0x04, // Report ID (4) 46 142 + * # 0x19, 0x00, // UsageMinimum (0) 48 143 + * # 0x2a, 0x3c, 0x02, // UsageMaximum (572) 50 144 + * # 0x15, 0x00, // Logical Minimum (0) 53 145 + * # 0x26, 0x3c, 0x02, // Logical Maximum (572) 55 146 + * # 0x95, 0x01, // Report Count (1) 58 147 + * # 0x75, 0x10, // Report Size (16) 60 148 + * # 0x81, 0x00, // Input (Data,Arr,Abs) 62 149 + * # 0xc0, // End Collection 64 150 + * R: 65 05 01 09 06 a1 01 85 03 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 0507 19 00 29 ff 26 ff 00 75 08 95 06 81 00 c0 05 0c 09 01 a1 01 85 04 19 00 2a 3c02 15 00 26 3c 02 95 01 75 10 81 00 c0 151 + * N: HUION Huion Tablet_H641P 152 + */ 153 + 154 + #define PAD_REPORT_DESCRIPTOR_LENGTH 133 155 + #define PEN_REPORT_DESCRIPTOR_LENGTH 93 156 + #define VENDOR_REPORT_DESCRIPTOR_LENGTH 36 157 + #define PAD_REPORT_ID 3 158 + #define PEN_REPORT_ID 10 159 + #define VENDOR_REPORT_ID 8 160 + #define PAD_REPORT_LENGTH 8 161 + #define PEN_REPORT_LENGTH 10 162 + #define VENDOR_REPORT_LENGTH 12 163 + 164 + 165 + __u16 last_button_state; 166 + 167 + static const __u8 fixed_rdesc_pad[] = { 168 + UsagePage_GenericDesktop 169 + Usage_GD_Keypad 170 + CollectionApplication( 171 + // -- Byte 0 in report 172 + ReportId(PAD_REPORT_ID) 173 + LogicalMinimum_i8(0) 174 + LogicalMaximum_i8(1) 175 + UsagePage_Digitizers 176 + Usage_Dig_TabletFunctionKeys 177 + CollectionPhysical( 178 + // Byte 1 in report - just exists so we get to be a tablet pad 179 + Usage_Dig_BarrelSwitch // BTN_STYLUS 180 + ReportCount(1) 181 + ReportSize(1) 182 + Input(Var|Abs) 183 + ReportCount(7) // padding 184 + Input(Const) 185 + // Bytes 2/3 in report - just exists so we get to be a tablet pad 186 + UsagePage_GenericDesktop 187 + Usage_GD_X 188 + Usage_GD_Y 189 + ReportCount(2) 190 + ReportSize(8) 191 + Input(Var|Abs) 192 + // Byte 4 in report is the wheel 193 + Usage_GD_Wheel 194 + LogicalMinimum_i8(-1) 195 + LogicalMaximum_i8(1) 196 + ReportCount(1) 197 + ReportSize(8) 198 + Input(Var|Rel) 199 + // Byte 5 is the button state 200 + UsagePage_Button 201 + UsageMinimum_i8(0x1) 202 + UsageMaximum_i8(0x8) 203 + LogicalMinimum_i8(0x1) 204 + LogicalMaximum_i8(0x8) 205 + ReportCount(1) 206 + ReportSize(8) 207 + Input(Arr|Abs) 208 + ) 209 + // Make sure we match our original report length 210 + FixedSizeVendorReport(PAD_REPORT_LENGTH) 211 + ) 212 + }; 213 + 214 + static const __u8 fixed_rdesc_pen[] = { 215 + UsagePage_Digitizers 216 + Usage_Dig_Pen 217 + CollectionApplication( 218 + // -- Byte 0 in report 219 + ReportId(PEN_REPORT_ID) 220 + Usage_Dig_Pen 221 + CollectionPhysical( 222 + // -- Byte 1 in report 223 + Usage_Dig_TipSwitch 224 + Usage_Dig_BarrelSwitch 225 + Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2 226 + LogicalMinimum_i8(0) 227 + LogicalMaximum_i8(1) 228 + ReportSize(1) 229 + ReportCount(3) 230 + Input(Var|Abs) 231 + ReportCount(4) // Padding 232 + Input(Const) 233 + Usage_Dig_InRange 234 + ReportCount(1) 235 + Input(Var|Abs) 236 + ReportSize(16) 237 + ReportCount(1) 238 + PushPop( 239 + UsagePage_GenericDesktop 240 + Unit(cm) 241 + UnitExponent(-1) 242 + PhysicalMinimum_i16(0) 243 + PhysicalMaximum_i16(160) 244 + LogicalMinimum_i16(0) 245 + LogicalMaximum_i16(32767) 246 + Usage_GD_X 247 + Input(Var|Abs) // Bytes 2+3 248 + PhysicalMinimum_i16(0) 249 + PhysicalMaximum_i16(100) 250 + LogicalMinimum_i16(0) 251 + LogicalMaximum_i16(32767) 252 + Usage_GD_Y 253 + Input(Var|Abs) // Bytes 4+5 254 + ) 255 + UsagePage_Digitizers 256 + Usage_Dig_TipPressure 257 + LogicalMinimum_i16(0) 258 + LogicalMaximum_i16(8191) 259 + Input(Var|Abs) // Byte 6+7 260 + // Two bytes padding so we don't need to change the report at all 261 + ReportSize(8) 262 + ReportCount(2) 263 + Input(Const) // Byte 6+7 264 + ) 265 + ) 266 + }; 267 + 268 + static const __u8 fixed_rdesc_vendor[] = { 269 + UsagePage_Digitizers 270 + Usage_Dig_Pen 271 + CollectionApplication( 272 + // Byte 0 273 + // We leave the pen on the vendor report ID 274 + ReportId(VENDOR_REPORT_ID) 275 + Usage_Dig_Pen 276 + CollectionPhysical( 277 + // Byte 1 are the buttons 278 + LogicalMinimum_i8(0) 279 + LogicalMaximum_i8(1) 280 + ReportSize(1) 281 + Usage_Dig_TipSwitch 282 + Usage_Dig_BarrelSwitch 283 + Usage_Dig_SecondaryBarrelSwitch 284 + ReportCount(3) 285 + Input(Var|Abs) 286 + ReportCount(4) // Padding 287 + Input(Const) 288 + Usage_Dig_InRange 289 + ReportCount(1) 290 + Input(Var|Abs) 291 + ReportSize(16) 292 + ReportCount(1) 293 + PushPop( 294 + UsagePage_GenericDesktop 295 + Unit(cm) 296 + UnitExponent(-1) 297 + // Note: reported logical range differs 298 + // from the pen report ID for x and y 299 + LogicalMinimum_i16(0) 300 + LogicalMaximum_i16(32000) 301 + PhysicalMinimum_i16(0) 302 + PhysicalMaximum_i16(160) 303 + // Bytes 2/3 in report 304 + Usage_GD_X 305 + Input(Var|Abs) 306 + LogicalMinimum_i16(0) 307 + LogicalMaximum_i16(20000) 308 + PhysicalMinimum_i16(0) 309 + PhysicalMaximum_i16(100) 310 + // Bytes 4/5 in report 311 + Usage_GD_Y 312 + Input(Var|Abs) 313 + ) 314 + // Bytes 6/7 in report 315 + LogicalMinimum_i16(0) 316 + LogicalMaximum_i16(8192) 317 + Usage_Dig_TipPressure 318 + Input(Var|Abs) 319 + ) 320 + ) 321 + UsagePage_GenericDesktop 322 + Usage_GD_Keypad 323 + CollectionApplication( 324 + // Byte 0 325 + ReportId(PAD_REPORT_ID) 326 + LogicalMinimum_i8(0) 327 + LogicalMaximum_i8(1) 328 + UsagePage_Digitizers 329 + Usage_Dig_TabletFunctionKeys 330 + CollectionPhysical( 331 + // Byte 1 are the buttons 332 + Usage_Dig_BarrelSwitch // BTN_STYLUS, needed so we get to be a tablet pad 333 + ReportCount(1) 334 + ReportSize(1) 335 + Input(Var|Abs) 336 + ReportCount(7) // Padding 337 + Input(Const) 338 + // Bytes 2/3 - x/y just exist so we get to be a tablet pad 339 + UsagePage_GenericDesktop 340 + Usage_GD_X 341 + Usage_GD_Y 342 + ReportCount(2) 343 + ReportSize(8) 344 + Input(Var|Abs) 345 + // Bytes 4 and 5 are the button state 346 + UsagePage_Button 347 + UsageMinimum_i8(0x1) 348 + UsageMaximum_i8(0xa) 349 + LogicalMinimum_i8(0x0) 350 + LogicalMaximum_i8(0x1) 351 + ReportCount(10) 352 + ReportSize(1) 353 + Input(Var|Abs) 354 + Usage_i8(0x31) // maps to BTN_SOUTH 355 + ReportCount(1) 356 + Input(Var|Abs) 357 + ReportCount(5) 358 + Input(Const) 359 + // Byte 6 is the wheel 360 + UsagePage_GenericDesktop 361 + Usage_GD_Wheel 362 + LogicalMinimum_i8(-1) 363 + LogicalMaximum_i8(1) 364 + ReportCount(1) 365 + ReportSize(8) 366 + Input(Var|Rel) 367 + ) 368 + // Make sure we match our original report length 369 + FixedSizeVendorReport(VENDOR_REPORT_LENGTH) 370 + ) 371 + }; 372 + 373 + static const __u8 disabled_rdesc_pen[] = { 374 + FixedSizeVendorReport(PEN_REPORT_LENGTH) 375 + }; 376 + 377 + static const __u8 disabled_rdesc_pad[] = { 378 + FixedSizeVendorReport(PAD_REPORT_LENGTH) 379 + }; 380 + 381 + SEC(HID_BPF_RDESC_FIXUP) 382 + int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx) 383 + { 384 + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */); 385 + __s32 rdesc_size = hctx->size; 386 + __u8 have_fw_id; 387 + 388 + if (!data) 389 + return 0; /* EPERM check */ 390 + 391 + /* If we have a firmware ID and it matches our expected prefix, we 392 + * disable the default pad/pen nodes. They won't send events 393 + * but cause duplicate devices. 394 + */ 395 + have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID, 396 + EXPECTED_FIRMWARE_ID, 397 + sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0; 398 + if (rdesc_size == PAD_REPORT_DESCRIPTOR_LENGTH) { 399 + if (have_fw_id) { 400 + __builtin_memcpy(data, disabled_rdesc_pad, sizeof(disabled_rdesc_pad)); 401 + return sizeof(disabled_rdesc_pad); 402 + } 403 + 404 + __builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad)); 405 + return sizeof(fixed_rdesc_pad); 406 + } 407 + if (rdesc_size == PEN_REPORT_DESCRIPTOR_LENGTH) { 408 + if (have_fw_id) { 409 + __builtin_memcpy(data, disabled_rdesc_pen, sizeof(disabled_rdesc_pen)); 410 + return sizeof(disabled_rdesc_pen); 411 + } 412 + 413 + __builtin_memcpy(data, fixed_rdesc_pen, sizeof(fixed_rdesc_pen)); 414 + return sizeof(fixed_rdesc_pen); 415 + } 416 + /* Always fix the vendor mode so the tablet will work even if nothing sets 417 + * the udev property (e.g. huion-switcher run manually) 418 + */ 419 + if (rdesc_size == VENDOR_REPORT_DESCRIPTOR_LENGTH) { 420 + __builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor)); 421 + return sizeof(fixed_rdesc_vendor); 422 + } 423 + return 0; 424 + } 425 + 426 + SEC(HID_BPF_DEVICE_EVENT) 427 + int BPF_PROG(inspiroy_2_fix_events, struct hid_bpf_ctx *hctx) 428 + { 429 + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */); 430 + 431 + if (!data) 432 + return 0; /* EPERM check */ 433 + 434 + /* Only sent if tablet is in default mode */ 435 + if (data[0] == PAD_REPORT_ID) { 436 + /* Nicely enough, this device only supports one button down at a time so 437 + * the reports are easy to match. Buttons numbered from the top 438 + * Button released: 03 00 00 00 00 00 00 00 439 + * Button 1: 03 00 05 00 00 00 00 00 -> b 440 + * Button 2: 03 07 11 00 00 00 00 00 -> Ctrl Shift N 441 + * Button 3: 03 00 08 00 00 00 00 00 -> e 442 + * Button 4: 03 00 0c 00 00 00 00 00 -> i 443 + * Button 5: 03 00 2c 00 00 00 00 00 -> space 444 + * Button 6: 03 01 08 00 00 00 00 00 -> Ctrl E 445 + * Button 7: 03 01 16 00 00 00 00 00 -> Ctrl S 446 + * Button 8: 03 05 1d 00 00 00 00 00 -> Ctrl Alt Z 447 + * 448 + * Wheel down: 03 01 2d 00 00 00 00 00 -> Ctrl - 449 + * Wheel up: 03 01 2e 00 00 00 00 00 -> Ctrl = 450 + */ 451 + __u8 button = 0; 452 + __u8 wheel = 0; 453 + 454 + switch (data[1] << 8 | data[2]) { 455 + case 0x0000: 456 + break; 457 + case 0x0005: 458 + button = 1; 459 + break; 460 + case 0x0711: 461 + button = 2; 462 + break; 463 + case 0x0008: 464 + button = 3; 465 + break; 466 + case 0x000c: 467 + button = 4; 468 + break; 469 + case 0x002c: 470 + button = 5; 471 + break; 472 + case 0x0108: 473 + button = 6; 474 + break; 475 + case 0x0116: 476 + button = 7; 477 + break; 478 + case 0x051d: 479 + button = 8; 480 + break; 481 + case 0x012d: 482 + wheel = -1; 483 + break; 484 + case 0x012e: 485 + wheel = 1; 486 + break; 487 + } 488 + 489 + __u8 report[6] = {PAD_REPORT_ID, 0x0, 0x0, 0x0, wheel, button}; 490 + 491 + __builtin_memcpy(data, report, sizeof(report)); 492 + return sizeof(report); 493 + } 494 + 495 + /* Nothing to do for the PEN_REPORT_ID, it's already mapped */ 496 + 497 + /* Only sent if tablet is in raw mode */ 498 + if (data[0] == VENDOR_REPORT_ID) { 499 + /* Pad reports */ 500 + if (data[1] & 0x20) { 501 + /* See fixed_rdesc_pad */ 502 + struct pad_report { 503 + __u8 report_id; 504 + __u8 btn_stylus; 505 + __u8 x; 506 + __u8 y; 507 + __u16 buttons; 508 + __u8 wheel; 509 + } __attribute__((packed)) *pad_report; 510 + __u8 wheel = 0; 511 + 512 + /* Wheel report */ 513 + if (data[1] == 0xf1) { 514 + if (data[5] == 2) 515 + wheel = 0xff; 516 + else 517 + wheel = data[5]; 518 + } else { 519 + /* data[4] and data[5] are the buttons, mapped correctly */ 520 + last_button_state = data[4] | (data[5] << 8); 521 + wheel = 0; // wheel 522 + } 523 + 524 + pad_report = (struct pad_report *)data; 525 + 526 + pad_report->report_id = PAD_REPORT_ID; 527 + pad_report->btn_stylus = 0; 528 + pad_report->x = 0; 529 + pad_report->y = 0; 530 + pad_report->buttons = last_button_state; 531 + pad_report->wheel = wheel; 532 + 533 + return sizeof(struct pad_report); 534 + } 535 + 536 + /* Pen reports need nothing done */ 537 + } 538 + 539 + return 0; 540 + } 541 + 542 + HID_BPF_OPS(inspiroy_2) = { 543 + .hid_device_event = (void *)inspiroy_2_fix_events, 544 + .hid_rdesc_fixup = (void *)hid_fix_rdesc, 545 + }; 546 + 547 + SEC("syscall") 548 + int probe(struct hid_bpf_probe_args *ctx) 549 + { 550 + switch (ctx->rdesc_size) { 551 + case PAD_REPORT_DESCRIPTOR_LENGTH: 552 + case PEN_REPORT_DESCRIPTOR_LENGTH: 553 + case VENDOR_REPORT_DESCRIPTOR_LENGTH: 554 + ctx->retval = 0; 555 + break; 556 + default: 557 + ctx->retval = -EINVAL; 558 + } 559 + 560 + return 0; 561 + } 562 + 563 + char _license[] SEC("license") = "GPL";
+27 -2
drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c
··· 163 163 164 164 165 165 __u8 last_button_state; 166 + __u8 last_tip_state; 167 + __u8 last_sec_barrel_state; 168 + __u8 force_tip_down_count; 166 169 167 170 static const __u8 fixed_rdesc_pad[] = { 168 171 UsagePage_GenericDesktop ··· 525 522 pad_report->wheel = wheel; 526 523 527 524 return sizeof(struct pad_report); 528 - } 525 + } else if (data[1] & 0x80) { /* Pen reports with InRange 1 */ 526 + __u8 tip_state = data[1] & 0x1; 527 + __u8 sec_barrel_state = data[1] & 0x4; 529 528 530 - /* Pen reports need nothing done */ 529 + if (force_tip_down_count > 0) { 530 + data[1] |= 0x1; 531 + --force_tip_down_count; 532 + if (tip_state) 533 + force_tip_down_count = 0; 534 + } 535 + 536 + /* Tip was down and we just pressed or released the 537 + * secondary barrel switch (the physical eraser 538 + * button). The device will send up to 4 539 + * reports with Tip Switch 0 and sometimes 540 + * this report has Tip Switch 0. 541 + */ 542 + if (last_tip_state && 543 + last_sec_barrel_state != sec_barrel_state) { 544 + force_tip_down_count = 4; 545 + data[1] |= 0x1; 546 + } 547 + last_tip_state = tip_state; 548 + last_sec_barrel_state = sec_barrel_state; 549 + } 531 550 } 532 551 533 552 return 0;
+5 -1
drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c
··· 9 9 10 10 #define VID_HUION 0x256C 11 11 #define PID_KAMVAS_PRO_19 0x006B 12 + #define PID_KAMVAS_PRO_27 0x006c 12 13 #define NAME_KAMVAS_PRO_19 "HUION Huion Tablet_GT1902" 14 + #define NAME_KAMVAS_PRO_27 "HUION Huion Tablet_GT2701" 13 15 14 16 #define TEST_PREFIX "uhid test " 15 17 16 18 HID_BPF_CONFIG( 17 19 HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, VID_HUION, PID_KAMVAS_PRO_19), 20 + HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, VID_HUION, PID_KAMVAS_PRO_27), 18 21 ); 19 22 20 23 bool prev_was_out_of_range; ··· 354 351 if (!__builtin_memcmp(name, TEST_PREFIX, sizeof(TEST_PREFIX) - 1)) 355 352 name += sizeof(TEST_PREFIX) - 1; 356 353 357 - if (__builtin_memcmp(name, NAME_KAMVAS_PRO_19, sizeof(NAME_KAMVAS_PRO_19))) 354 + if (__builtin_memcmp(name, NAME_KAMVAS_PRO_19, sizeof(NAME_KAMVAS_PRO_19)) && 355 + __builtin_memcmp(name, NAME_KAMVAS_PRO_27, sizeof(NAME_KAMVAS_PRO_27))) 358 356 ctx->retval = -EINVAL; 359 357 360 358 hid_bpf_release_context(hctx);
+1395
drivers/hid/bpf/progs/Huion__Kamvas13Gen3.bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright (c) 2025 Nicholas LaPointe 3 + */ 4 + 5 + #include "vmlinux.h" 6 + #include "hid_bpf.h" 7 + #include "hid_bpf_helpers.h" 8 + #include "hid_report_helpers.h" 9 + #include <bpf/bpf_tracing.h> 10 + 11 + #define VID_HUION 0x256c 12 + #define PID_KAMVAS13_GEN3 0x2008 13 + 14 + #define VENDOR_DESCRIPTOR_LENGTH 36 15 + #define TABLET_DESCRIPTOR_LENGTH 368 16 + #define WHEEL_DESCRIPTOR_LENGTH 108 17 + 18 + #define VENDOR_REPORT_ID 8 19 + #define VENDOR_REPORT_LENGTH 14 20 + 21 + #define VENDOR_REPORT_SUBTYPE_PEN 0x08 22 + #define VENDOR_REPORT_SUBTYPE_PEN_OUT 0x00 23 + #define VENDOR_REPORT_SUBTYPE_BUTTONS 0x0e 24 + #define VENDOR_REPORT_SUBTYPE_WHEELS 0x0f 25 + 26 + /* For the reports that we create ourselves */ 27 + #define CUSTOM_PAD_REPORT_ID 9 28 + 29 + HID_BPF_CONFIG( 30 + HID_DEVICE(BUS_USB, HID_GROUP_ANY, VID_HUION, PID_KAMVAS13_GEN3), 31 + ); 32 + 33 + 34 + /* 35 + * This tablet can send reports using one of two different data formats, 36 + * depending on what "mode" the tablet is in. 37 + * 38 + * By default, the tablet will send reports that can be decoded using its 39 + * included HID descriptors (descriptors 1 and 2, shown below). 40 + * This mode will be called "firmware mode" throughout this file. 41 + * 42 + * The HID descriptor that describes pen events in firmware mode (descriptor 1) 43 + * has multiple bugs: 44 + * * "Secondary Tip Switch" instead of "Secondary Barrel Switch" 45 + * * "Invert" instead of (or potentially shared with) third barrel button 46 + * * Specified tablet area of 2048 in³ instead of 293.8 x 165.2mm 47 + * * Specified tilt range of -90 to +90 instead of -60 to +60 48 + * 49 + * While these can be easily patched up by editing the descriptor, a larger 50 + * problem with the firmware mode exists: it is impossible to tell which of the 51 + * two wheels are being rotated (or having their central button pressed). 52 + * 53 + * 54 + * By using a tool such as huion-switcher (https://github.com/whot/huion-switcher), 55 + * the tablet can be made to send reports using a proprietary format that is not 56 + * adequately described by its relevant descriptor (descriptor 0, shown below). 57 + * This mode will be called "vendor mode" throughout this file. 58 + * 59 + * The reports sent while in vendor mode allow for proper decoding of the wheels. 60 + * 61 + * For simplicity and maximum functionality, this BPF focuses strictly on 62 + * enabling one to make use of the vendor mode. 63 + */ 64 + 65 + /* 66 + * DESCRIPTORS 67 + * DESCRIPTOR 0 68 + * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 0 69 + * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 3 70 + * # 0xa1, 0x01, // Collection (Application) 5 71 + * # ┅ 0x85, 0x08, // Report ID (8) 7 72 + * # 0x75, 0x68, // Report Size (104) 9 73 + * # 0x95, 0x01, // Report Count (1) 11 74 + * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 13 75 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 15 76 + * # 0xc0, // End Collection 17 77 + * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 18 78 + * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 21 79 + * # 0xa1, 0x01, // Collection (Application) 23 80 + * # ┅ 0x85, 0x16, // Report ID (22) 25 81 + * # 0x75, 0x08, // Report Size (8) 27 82 + * # 0x95, 0x07, // Report Count (7) 29 83 + * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 31 84 + * # ║ 0xb1, 0x02, // Feature (Data,Var,Abs) 33 85 + * # 0xc0, // End Collection 35 86 + * R: 36 06 00 ff 09 01 a1 01 85 08 75 68 95 01 09 01 81 02 c0 06 00 ff 09 01 a1 01 85 16 75 08 95 07 09 01 b1 02 c0 87 + * N: HUION Huion Tablet_GS1333 88 + * I: 3 256c 2008 89 + * 90 + * DESCRIPTOR 1 91 + * # 0x05, 0x0d, // Usage Page (Digitizers) 0 92 + * # 0x09, 0x02, // Usage (Pen) 2 93 + * # 0xa1, 0x01, // Collection (Application) 4 94 + * # ┅ 0x85, 0x0a, // Report ID (10) 6 95 + * # 0x09, 0x20, // Usage (Stylus) 8 96 + * # 0xa1, 0x01, // Collection (Application) 10 97 + * # 0x09, 0x42, // Usage (Tip Switch) 12 98 + * # 0x09, 0x44, // Usage (Barrel Switch) 14 99 + * # 0x09, 0x43, // Usage (Secondary Tip Switch) 16 100 + * # 0x09, 0x3c, // Usage (Invert) 18 101 + * # 0x09, 0x45, // Usage (Eraser) 20 102 + * # 0x15, 0x00, // Logical Minimum (0) 22 103 + * # 0x25, 0x01, // Logical Maximum (1) 24 104 + * # 0x75, 0x01, // Report Size (1) 26 105 + * # 0x95, 0x06, // Report Count (6) 28 106 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 30 107 + * # 0x09, 0x32, // Usage (In Range) 32 108 + * # 0x75, 0x01, // Report Size (1) 34 109 + * # 0x95, 0x01, // Report Count (1) 36 110 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 38 111 + * # ┇ 0x81, 0x03, // Input (Cnst,Var,Abs) 40 112 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 42 113 + * # 0x09, 0x30, // Usage (X) 44 114 + * # 0x09, 0x31, // Usage (Y) 46 115 + * # 0x55, 0x0d, // Unit Exponent (-3) 48 116 + * # 0x65, 0x33, // Unit (EnglishLinear: in³) 50 117 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 52 118 + * # 0x35, 0x00, // Physical Minimum (0) 55 119 + * # 0x46, 0x00, 0x08, // Physical Maximum (2048) 57 120 + * # 0x75, 0x10, // Report Size (16) 60 121 + * # 0x95, 0x02, // Report Count (2) 62 122 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 64 123 + * # 0x05, 0x0d, // Usage Page (Digitizers) 66 124 + * # 0x09, 0x30, // Usage (Tip Pressure) 68 125 + * # 0x26, 0xff, 0x3f, // Logical Maximum (16383) 70 126 + * # 0x75, 0x10, // Report Size (16) 73 127 + * # 0x95, 0x01, // Report Count (1) 75 128 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 77 129 + * # 0x09, 0x3d, // Usage (X Tilt) 79 130 + * # 0x09, 0x3e, // Usage (Y Tilt) 81 131 + * # 0x15, 0xa6, // Logical Minimum (-90) 83 132 + * # 0x25, 0x5a, // Logical Maximum (90) 85 133 + * # 0x75, 0x08, // Report Size (8) 87 134 + * # 0x95, 0x02, // Report Count (2) 89 135 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 91 136 + * # 0xc0, // End Collection 93 137 + * # 0xc0, // End Collection 94 138 + * # 0x05, 0x0d, // Usage Page (Digitizers) 95 139 + * # 0x09, 0x04, // Usage (Touch Screen) 97 140 + * # 0xa1, 0x01, // Collection (Application) 99 141 + * # ┅ 0x85, 0x04, // Report ID (4) 101 142 + * # 0x09, 0x22, // Usage (Finger) 103 143 + * # 0xa1, 0x02, // Collection (Logical) 105 144 + * # 0x05, 0x0d, // Usage Page (Digitizers) 107 145 + * # 0x95, 0x01, // Report Count (1) 109 146 + * # 0x75, 0x06, // Report Size (6) 111 147 + * # 0x09, 0x51, // Usage (Contact Identifier) 113 148 + * # 0x15, 0x00, // Logical Minimum (0) 115 149 + * # 0x25, 0x3f, // Logical Maximum (63) 117 150 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 119 151 + * # 0x09, 0x42, // Usage (Tip Switch) 121 152 + * # 0x25, 0x01, // Logical Maximum (1) 123 153 + * # 0x75, 0x01, // Report Size (1) 125 154 + * # 0x95, 0x01, // Report Count (1) 127 155 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 129 156 + * # 0x75, 0x01, // Report Size (1) 131 157 + * # 0x95, 0x01, // Report Count (1) 133 158 + * # ┇ 0x81, 0x03, // Input (Cnst,Var,Abs) 135 159 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 137 160 + * # 0x75, 0x10, // Report Size (16) 139 161 + * # 0x55, 0x0e, // Unit Exponent (-2) 141 162 + * # 0x65, 0x11, // Unit (SILinear: cm) 143 163 + * # 0x09, 0x30, // Usage (X) 145 164 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 147 165 + * # 0x35, 0x00, // Physical Minimum (0) 150 166 + * # 0x46, 0x15, 0x0c, // Physical Maximum (3093) 152 167 + * # ┇ 0x81, 0x42, // Input (Data,Var,Abs,Null) 155 168 + * # 0x09, 0x31, // Usage (Y) 157 169 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 159 170 + * # 0x46, 0xcb, 0x06, // Physical Maximum (1739) 162 171 + * # ┇ 0x81, 0x42, // Input (Data,Var,Abs,Null) 165 172 + * # 0x05, 0x0d, // Usage Page (Digitizers) 167 173 + * # 0x09, 0x30, // Usage (Tip Pressure) 169 174 + * # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 171 175 + * # 0x75, 0x10, // Report Size (16) 174 176 + * # 0x95, 0x01, // Report Count (1) 176 177 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 178 178 + * # 0xc0, // End Collection 180 179 + * # 0x05, 0x0d, // Usage Page (Digitizers) 181 180 + * # 0x09, 0x22, // Usage (Finger) 183 181 + * # 0xa1, 0x02, // Collection (Logical) 185 182 + * # 0x05, 0x0d, // Usage Page (Digitizers) 187 183 + * # 0x95, 0x01, // Report Count (1) 189 184 + * # 0x75, 0x06, // Report Size (6) 191 185 + * # 0x09, 0x51, // Usage (Contact Identifier) 193 186 + * # 0x15, 0x00, // Logical Minimum (0) 195 187 + * # 0x25, 0x3f, // Logical Maximum (63) 197 188 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 199 189 + * # 0x09, 0x42, // Usage (Tip Switch) 201 190 + * # 0x25, 0x01, // Logical Maximum (1) 203 191 + * # 0x75, 0x01, // Report Size (1) 205 192 + * # 0x95, 0x01, // Report Count (1) 207 193 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 209 194 + * # 0x75, 0x01, // Report Size (1) 211 195 + * # 0x95, 0x01, // Report Count (1) 213 196 + * # ┇ 0x81, 0x03, // Input (Cnst,Var,Abs) 215 197 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 217 198 + * # 0x75, 0x10, // Report Size (16) 219 199 + * # 0x55, 0x0e, // Unit Exponent (-2) 221 200 + * # 0x65, 0x11, // Unit (SILinear: cm) 223 201 + * # 0x09, 0x30, // Usage (X) 225 202 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 227 203 + * # 0x35, 0x00, // Physical Minimum (0) 230 204 + * # 0x46, 0x15, 0x0c, // Physical Maximum (3093) 232 205 + * # ┇ 0x81, 0x42, // Input (Data,Var,Abs,Null) 235 206 + * # 0x09, 0x31, // Usage (Y) 237 207 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 239 208 + * # 0x46, 0xcb, 0x06, // Physical Maximum (1739) 242 209 + * # ┇ 0x81, 0x42, // Input (Data,Var,Abs,Null) 245 210 + * # 0x05, 0x0d, // Usage Page (Digitizers) 247 211 + * # 0x09, 0x30, // Usage (Tip Pressure) 249 212 + * # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 251 213 + * # 0x75, 0x10, // Report Size (16) 254 214 + * # 0x95, 0x01, // Report Count (1) 256 215 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 258 216 + * # 0xc0, // End Collection 260 217 + * # 0x05, 0x0d, // Usage Page (Digitizers) 261 218 + * # 0x09, 0x56, // Usage (Scan Time) 263 219 + * # 0x55, 0x00, // Unit Exponent (0) 265 220 + * # 0x65, 0x00, // Unit (None) 267 221 + * # 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 269 222 + * # 0x95, 0x01, // Report Count (1) 274 223 + * # 0x75, 0x20, // Report Size (32) 276 224 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 278 225 + * # 0x09, 0x54, // Usage (Contact Count) 280 226 + * # 0x25, 0x7f, // Logical Maximum (127) 282 227 + * # 0x95, 0x01, // Report Count (1) 284 228 + * # 0x75, 0x08, // Report Size (8) 286 229 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 288 230 + * # 0x75, 0x08, // Report Size (8) 290 231 + * # 0x95, 0x08, // Report Count (8) 292 232 + * # ┇ 0x81, 0x03, // Input (Cnst,Var,Abs) 294 233 + * # ┅ 0x85, 0x05, // Report ID (5) 296 234 + * # 0x09, 0x55, // Usage (Contact Count Maximum) 298 235 + * # 0x25, 0x0a, // Logical Maximum (10) 300 236 + * # 0x75, 0x08, // Report Size (8) 302 237 + * # 0x95, 0x01, // Report Count (1) 304 238 + * # ║ 0xb1, 0x02, // Feature (Data,Var,Abs) 306 239 + * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 308 240 + * # 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 311 241 + * # ┅ 0x85, 0x06, // Report ID (6) 313 242 + * # 0x15, 0x00, // Logical Minimum (0) 315 243 + * # 0x26, 0xff, 0x00, // Logical Maximum (255) 317 244 + * # 0x75, 0x08, // Report Size (8) 320 245 + * # 0x96, 0x00, 0x01, // Report Count (256) 322 246 + * # ║ 0xb1, 0x02, // Feature (Data,Var,Abs) 325 247 + * # 0xc0, // End Collection 327 248 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 328 249 + * # 0x09, 0x06, // Usage (Keyboard) 330 250 + * # 0xa1, 0x01, // Collection (Application) 332 251 + * # ┅ 0x85, 0x03, // Report ID (3) 334 252 + * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 336 253 + * # 0x19, 0xe0, // UsageMinimum (224) 338 254 + * # 0x29, 0xe7, // UsageMaximum (231) 340 255 + * # 0x15, 0x00, // Logical Minimum (0) 342 256 + * # 0x25, 0x01, // Logical Maximum (1) 344 257 + * # 0x75, 0x01, // Report Size (1) 346 258 + * # 0x95, 0x08, // Report Count (8) 348 259 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 350 260 + * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 352 261 + * # 0x19, 0x00, // UsageMinimum (0) 354 262 + * # 0x29, 0xff, // UsageMaximum (255) 356 263 + * # 0x26, 0xff, 0x00, // Logical Maximum (255) 358 264 + * # 0x75, 0x08, // Report Size (8) 361 265 + * # 0x95, 0x06, // Report Count (6) 363 266 + * # ┇ 0x81, 0x00, // Input (Data,Arr,Abs) 365 267 + * # 0xc0, // End Collection 367 268 + * R: 368 05 0d 09 02 a1 01 85 0a 09 20 a1 01 09 42 09 44 09 43 09 3c 09 45 15 00 25 01 75 01 95 06 81 02 09 32 75 01 95 01 81 02 81 03 05 01 09 30 09 31 55 0d 65 33 26 ff 7f 35 00 46 00 08 75 10 95 02 81 02 05 0d 09 30 26 ff 3f 75 10 95 01 81 02 09 3d 09 3e 15 a6 25 5a 75 08 95 02 81 02 c0 c0 05 0d 09 04 a1 01 85 04 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 56 55 00 65 00 27 ff ff ff 7f 95 01 75 20 81 02 09 54 25 7f 95 01 75 08 81 02 75 08 95 08 81 03 85 05 09 55 25 0a 75 08 95 01 b1 02 06 00 ff 09 c5 85 06 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 01 09 06 a1 01 85 03 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 05 07 19 00 29 ff 26 ff 00 75 08 95 06 81 00 c0 269 + * N: HUION Huion Tablet_GS1333 270 + * I: 3 256c 2008 271 + * 272 + * DESCRIPTOR 2 273 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 0 274 + * # 0x09, 0x0e, // Usage (System Multi-Axis Controller) 2 275 + * # 0xa1, 0x01, // Collection (Application) 4 276 + * # ┅ 0x85, 0x11, // Report ID (17) 6 277 + * # 0x05, 0x0d, // Usage Page (Digitizers) 8 278 + * # 0x09, 0x21, // Usage (Puck) 10 279 + * # 0xa1, 0x02, // Collection (Logical) 12 280 + * # 0x15, 0x00, // Logical Minimum (0) 14 281 + * # 0x25, 0x01, // Logical Maximum (1) 16 282 + * # 0x75, 0x01, // Report Size (1) 18 283 + * # 0x95, 0x01, // Report Count (1) 20 284 + * # 0xa1, 0x00, // Collection (Physical) 22 285 + * # 0x05, 0x09, // Usage Page (Button) 24 286 + * # 0x09, 0x01, // Usage (Button 1) 26 287 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 28 288 + * # 0x05, 0x0d, // Usage Page (Digitizers) 30 289 + * # 0x09, 0x33, // Usage (Touch) 32 290 + * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 34 291 + * # 0x95, 0x06, // Report Count (6) 36 292 + * # ┇ 0x81, 0x03, // Input (Cnst,Var,Abs) 38 293 + * # 0xa1, 0x02, // Collection (Logical) 40 294 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 42 295 + * # 0x09, 0x37, // Usage (Dial) 44 296 + * # 0x16, 0x00, 0x80, // Logical Minimum (-32768) 46 297 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 49 298 + * # 0x75, 0x10, // Report Size (16) 52 299 + * # 0x95, 0x01, // Report Count (1) 54 300 + * # ┇ 0x81, 0x06, // Input (Data,Var,Rel) 56 301 + * # 0x35, 0x00, // Physical Minimum (0) 58 302 + * # 0x46, 0x10, 0x0e, // Physical Maximum (3600) 60 303 + * # 0x15, 0x00, // Logical Minimum (0) 63 304 + * # 0x26, 0x10, 0x0e, // Logical Maximum (3600) 65 305 + * # 0x09, 0x48, // Usage (Resolution Multiplier) 68 306 + * # ║ 0xb1, 0x02, // Feature (Data,Var,Abs) 70 307 + * # 0x45, 0x00, // Physical Maximum (0) 72 308 + * # 0xc0, // End Collection 74 309 + * # 0x75, 0x08, // Report Size (8) 75 310 + * # 0x95, 0x01, // Report Count (1) 77 311 + * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 79 312 + * # 0x75, 0x08, // Report Size (8) 81 313 + * # 0x95, 0x01, // Report Count (1) 83 314 + * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 85 315 + * # 0x75, 0x08, // Report Size (8) 87 316 + * # 0x95, 0x01, // Report Count (1) 89 317 + * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 91 318 + * # 0x75, 0x08, // Report Size (8) 93 319 + * # 0x95, 0x01, // Report Count (1) 95 320 + * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 97 321 + * # 0x75, 0x08, // Report Size (8) 99 322 + * # 0x95, 0x01, // Report Count (1) 101 323 + * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 103 324 + * # 0xc0, // End Collection 105 325 + * # 0xc0, // End Collection 106 326 + * # 0xc0, // End Collection 107 327 + * R: 108 05 01 09 0e a1 01 85 11 05 0d 09 21 a1 02 15 00 25 01 75 01 95 01 a1 00 05 09 09 01 81 02 05 0d 09 33 81 02 95 06 81 03 a1 02 05 01 09 37 16 00 80 26 ff 7f 75 10 95 01 81 06 35 00 46 10 0e 15 00 26 10 0e 09 48 b1 02 45 00 c0 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 c0 c0 c0 328 + * N: HUION Huion Tablet_GS1333 329 + * I: 3 256c 2008 330 + * 331 + * 332 + * 333 + * 334 + * 335 + * 336 + * 337 + * 338 + * VENDOR MODE 339 + * HUION_FIRMWARE_ID="HUION_M22c_240606" 340 + * HUION_MAGIC_BYTES="140388e500108100ff3fd8130307008008004010" 341 + * 342 + * MAGIC BYTES 343 + * [LogicalMaximum, X] [LogicalMaximum, Y] [LogicalMaximum, Pressure] [ LPI] 344 + * 14 03 [ 88 e5] 00 [ 10 81] 00 [ ff 3f] [d8 13] 03 07 00 80 08 00 40 10 345 + * 346 + * 347 + * HIDRAW 0 348 + * DESCRIPTIONS 349 + * report_subtype = (data[1] >> 4) & 0x0f 350 + * 351 + * REPORT SUBTYPES 352 + * 0x0e Buttons 353 + * (data[4] & 0x01) button 1 354 + * (data[4] & 0x02) button 2 355 + * (data[4] & 0x04) button 3 356 + * (data[4] & 0x08) button 4 357 + * (data[4] & 0x10) button 5 358 + * (data[4] & 0x20) button 6 (top wheel button) 359 + * (data[4] & 0x40) button 7 (bottom wheel button) 360 + * 361 + * All tablet buttons release with the same report: 362 + * 08 e0 01 01 00 00 00 00 00 00 00 00 00 00 363 + * 364 + * Despite data[4] looking like a bit field, only one button 365 + * can be unambiguously tracked at a time. 366 + * (See NOTES ON SIMULTANEOUS BUTTON HOLDS at the end of this 367 + * comment for examples of the confusion this can create.) 368 + * 369 + * All buttons, with the exceptions of 6 and 7, will repeatedly 370 + * report a press event approximately every 225ms while held. 371 + * 372 + * 0x0f Wheels 373 + * data[3] == 1: top wheel 374 + * data[3] == 2: bottom wheel 375 + * data[5] == 1: clockwise 376 + * data[5] == 2: counter-clockwise 377 + * 378 + * 0x08/0x00 Pen 379 + * report_subtype == 0x08: in-range 380 + * report_subtype == 0x00: out-of-range 381 + * For clarity, this is also equivalent to: 382 + * (data[1] & 0x80) in-range 383 + * 384 + * Switches 385 + * (data[1] & 0x01) tip switch 386 + * (data[1] & 0x02) barrel switch 387 + * (data[1] & 0x04) secondary barrel switch 388 + * (data[1] & 0x08) third barrel switch 389 + * 390 + * Unfortunately, I don't have a pen with an eraser, so I can't 391 + * confirm where the invert and eraser bits reside. 392 + * If we guess using the definitions from HID descriptor 1, 393 + * then they might be... 394 + * (data[1] & 0x08) invert (conflicts with third barrel switch) 395 + * (data[1] & 0x10) eraser 396 + * 397 + * data[2], data[3] X (little-endian, maximum 0xe588) 398 + * 399 + * data[4], data[5] Y (little-endian, maximum 0x8110) 400 + * 401 + * data[6], data[7] Pressure (little-endian, maximum 0x3fff) 402 + * 403 + * data[10] X tilt (signed, -60 to +60) 404 + * data[11] Y tilt (signed, -60 to +60, inverted) 405 + * 406 + * 407 + * EXAMPLE REPORTS 408 + * Top wheel button, press, hold, then release 409 + * E: 000000.000040 14 08 e0 01 01 20 00 00 00 00 00 00 00 00 00 410 + * E: 000001.531559 14 08 e0 01 01 00 00 00 00 00 00 00 00 00 00 411 + * 412 + * Bottom wheel button, press, hold, then release 413 + * E: 000002.787603 14 08 e0 01 01 40 00 00 00 00 00 00 00 00 00 414 + * E: 000004.215609 14 08 e0 01 01 00 00 00 00 00 00 00 00 00 00 415 + * 416 + * 417 + * Top wheel rotation, one detent CW 418 + * E: 000194.003899 14 08 f1 01 01 00 01 00 00 00 00 00 00 00 00 419 + * 420 + * Top wheel rotation, one detent CCW 421 + * E: 000194.997812 14 08 f1 01 01 00 02 00 00 00 00 00 00 00 00 422 + * 423 + * Bottom wheel rotation, one detent CW 424 + * E: 000196.693840 14 08 f1 01 02 00 01 00 00 00 00 00 00 00 00 425 + * 426 + * Bottom wheel rotation, one detent CCW 427 + * E: 000197.757895 14 08 f1 01 02 00 02 00 00 00 00 00 00 00 00 428 + * 429 + * 430 + * Button 1, press, hold, then release 431 + * E: 000000.000149 14 08 e0 01 01 01 00 00 00 00 00 00 00 00 00 < press 432 + * E: 000000.447598 14 08 e0 01 01 01 00 00 00 00 00 00 00 00 00 < starting to auto-repeat, every ~225ms 433 + * E: 000000.673586 14 08 e0 01 01 01 00 00 00 00 00 00 00 00 00 434 + * E: 000000.900582 14 08 e0 01 01 01 00 00 00 00 00 00 00 00 00 435 + * E: 000001.126703 14 08 e0 01 01 01 00 00 00 00 00 00 00 00 00 436 + * E: 000001.347706 14 08 e0 01 01 01 00 00 00 00 00 00 00 00 00 437 + * E: 000001.533721 14 08 e0 01 01 00 00 00 00 00 00 00 00 00 00 < release 438 + * 439 + * Button 2, press, hold, then release 440 + * E: 000003.304735 14 08 e0 01 01 02 00 00 00 00 00 00 00 00 00 < press 441 + * E: 000003.746743 14 08 e0 01 01 02 00 00 00 00 00 00 00 00 00 < starting to auto-repeat, every ~225ms 442 + * E: 000003.973741 14 08 e0 01 01 02 00 00 00 00 00 00 00 00 00 443 + * E: 000004.199832 14 08 e0 01 01 02 00 00 00 00 00 00 00 00 00 444 + * E: 000004.426732 14 08 e0 01 01 02 00 00 00 00 00 00 00 00 00 445 + * E: 000004.647738 14 08 e0 01 01 02 00 00 00 00 00 00 00 00 00 446 + * E: 000004.874733 14 08 e0 01 01 02 00 00 00 00 00 00 00 00 00 447 + * E: 000004.930713 14 08 e0 01 01 00 00 00 00 00 00 00 00 00 00 < release 448 + * 449 + * Button 3, press, hold, then release 450 + * E: 000006.650346 14 08 e0 01 01 04 00 00 00 00 00 00 00 00 00 < press 451 + * E: 000007.051782 14 08 e0 01 01 04 00 00 00 00 00 00 00 00 00 < starting to auto-repeat, every ~225ms 452 + * E: 000007.273738 14 08 e0 01 01 04 00 00 00 00 00 00 00 00 00 453 + * E: 000007.499794 14 08 e0 01 01 04 00 00 00 00 00 00 00 00 00 454 + * E: 000007.726725 14 08 e0 01 01 04 00 00 00 00 00 00 00 00 00 455 + * E: 000007.947765 14 08 e0 01 01 04 00 00 00 00 00 00 00 00 00 456 + * E: 000008.174755 14 08 e0 01 01 04 00 00 00 00 00 00 00 00 00 457 + * E: 000008.328786 14 08 e0 01 01 00 00 00 00 00 00 00 00 00 00 < release 458 + * 459 + * Button 4, press, hold, then release 460 + * E: 000009.893820 14 08 e0 01 01 08 00 00 00 00 00 00 00 00 00 < press 461 + * E: 000010.274781 14 08 e0 01 01 08 00 00 00 00 00 00 00 00 00 < starting to auto-repeat, every ~225ms 462 + * E: 000010.500931 14 08 e0 01 01 08 00 00 00 00 00 00 00 00 00 463 + * E: 000010.722777 14 08 e0 01 01 08 00 00 00 00 00 00 00 00 00 464 + * E: 000010.948778 14 08 e0 01 01 08 00 00 00 00 00 00 00 00 00 465 + * E: 000011.175799 14 08 e0 01 01 08 00 00 00 00 00 00 00 00 00 466 + * E: 000011.401153 14 08 e0 01 01 08 00 00 00 00 00 00 00 00 00 467 + * E: 000011.432114 14 08 e0 01 01 00 00 00 00 00 00 00 00 00 00 < release 468 + * 469 + * Button 5, press, hold, then release 470 + * E: 000013.007778 14 08 e0 01 01 10 00 00 00 00 00 00 00 00 00 < press 471 + * E: 000013.424741 14 08 e0 01 01 10 00 00 00 00 00 00 00 00 00 < starting to auto-repeat, every ~225ms 472 + * E: 000013.651715 14 08 e0 01 01 10 00 00 00 00 00 00 00 00 00 473 + * E: 000013.872763 14 08 e0 01 01 10 00 00 00 00 00 00 00 00 00 474 + * E: 000014.099789 14 08 e0 01 01 10 00 00 00 00 00 00 00 00 00 475 + * E: 000014.325734 14 08 e0 01 01 10 00 00 00 00 00 00 00 00 00 476 + * E: 000014.438080 14 08 e0 01 01 00 00 00 00 00 00 00 00 00 00 < release 477 + * 478 + * 479 + * Pen: Top-left, then out of range 480 + * E: 000368.572184 14 08 80 00 00 00 00 00 00 00 00 fb ed 03 00 481 + * E: 000368.573030 14 08 00 00 00 00 00 00 00 00 00 fb ed 03 00 482 + * 483 + * Pen: Bottom-right, then out of range 484 + * E: 000544.433185 14 08 80 88 e5 10 81 00 00 00 00 00 00 03 00 485 + * E: 000544.434183 14 08 00 88 e5 10 81 00 00 00 00 00 00 03 00 486 + * 487 + * Pen: Max Y tilt (tip of pen points down) 488 + * E: 000002.231927 14 08 80 f5 5d 6c 36 00 00 00 00 09 3c 03 00 489 + * 490 + * Pen: Min Y Tilt (tip of pen points up) 491 + * E: 000657.593338 14 08 80 5f 69 fa 2c 00 00 00 00 fe c4 03 00 492 + * 493 + * Pen: Max X tilt (tip of pen points left) 494 + * E: 000742.246503 14 08 80 2a 4f c4 38 00 00 00 00 3c ed 03 00 495 + * 496 + * Pen: Min X Tilt (tip of pen points right) 497 + * E: 000776.404446 14 08 00 18 85 7c 3b 00 00 00 00 c4 ed 03 00 498 + * 499 + * Pen: Tip switch, max pressure, then low pressure 500 + * E: 001138.935675 14 08 81 d2 66 04 40 ff 3f 00 00 00 08 03 00 501 + * 502 + * E: 001142.403715 14 08 81 9d 69 47 3e 82 04 00 00 00 07 03 00 503 + * 504 + * Pen: Barrel switch 505 + * E: 001210.645652 14 08 82 0d 72 ea 2b 00 00 00 00 db c4 03 00 506 + * 507 + * Pen: Secondary barrel switch 508 + * E: 001211.519729 14 08 84 2c 71 51 2b 00 00 00 00 da c4 03 00 509 + * 510 + * Pen: Third switch 511 + * E: 001212.443722 14 08 88 1d 72 df 2b 00 00 00 00 dc c4 03 00 512 + * 513 + * 514 + * HIDRAW 1 515 + * No reports 516 + * 517 + * 518 + * HIDRAW 2 519 + * No reports 520 + * 521 + * 522 + * 523 + * 524 + * 525 + * 526 + * 527 + * 528 + * FIRMWARE MODE 529 + * HIDRAW 0 530 + * No reports 531 + * 532 + * 533 + * HIDRAW 1 534 + * EXAMPLE REPORTS 535 + * Top wheel button, *release* 536 + * E: 000067.043739 8 03 00 00 00 00 00 00 00 537 + * 538 + * Bottom wheel button, *release* 539 + * E: 000068.219161 8 03 00 00 00 00 00 00 00 540 + * 541 + * 542 + * Button 1, press, then release 543 + * E: 000163.767870 8 03 00 05 00 00 00 00 00 544 + * E: 000165.969193 8 03 00 00 00 00 00 00 00 545 + * 546 + * Button 2, press, then release 547 + * E: 000261.728935 8 03 05 11 00 00 00 00 00 548 + * E: 000262.956220 8 03 00 00 00 00 00 00 00 549 + * 550 + * Button 3, press, then release 551 + * E: 000289.127881 8 03 01 16 00 00 00 00 00 552 + * E: 000290.014594 8 03 00 00 00 00 00 00 00 553 + * 554 + * Button 4, press, then release 555 + * E: 000303.025839 8 03 00 2c 00 00 00 00 00 556 + * E: 000303.994479 8 03 00 00 00 00 00 00 00 557 + * 558 + * Button 5, press, then release 559 + * E: 000315.500835 8 03 05 1d 00 00 00 00 00 560 + * E: 000316.603274 8 03 00 00 00 00 00 00 00 561 + * 562 + * BUTTON SUMMARY 563 + * 1 E: 000163.767870 8 03 00 05 00 00 00 00 00 Keyboard: B 564 + * 2 E: 000261.728935 8 03 05 11 00 00 00 00 00 Keyboard: LCtrl+LAlt N 565 + * 3 E: 000289.127881 8 03 01 16 00 00 00 00 00 Keyboard: LCtrl S 566 + * 4 E: 000303.025839 8 03 00 2c 00 00 00 00 00 Keyboard: Space 567 + * 5 E: 000315.500835 8 03 05 1d 00 00 00 00 00 Keyboard: LCtrl+LAlt 568 + * 569 + * All buttons (including the wheel buttons) release the same way: 570 + * 03 00 00 00 00 00 00 00 571 + * 572 + * 573 + * Pen: Top-left, then out of range 574 + * E: 000063.196828 10 0a c0 00 00 00 00 00 00 00 02 575 + * E: 000063.197762 10 0a 00 00 00 00 00 00 00 00 02 576 + * 577 + * Pen: Bottom-right, then out of range 578 + * E: 000197.123138 10 0a c0 ff 7f ff 7f 00 00 00 00 579 + * E: 000197.124915 10 0a 00 ff 7f ff 7f 00 00 00 00 580 + * 581 + * Pen: Max Y Tilt (tip of pen points up) 582 + * E: 000291.399541 10 0a c0 19 32 0b 58 00 00 00 3c 583 + * 584 + * Pen: Min Y tilt (tip of pen points down) 585 + * E: 000340.888288 10 0a c0 85 40 89 6e 00 00 17 c4 586 + * 587 + * Pen: Max X tilt (tip of pen points left) 588 + * E: 000165.575115 10 0a c0 a7 34 99 42 00 00 3c f4 589 + * 590 + * Pen: Min X Tilt (tip of pen points right) 591 + * E: 000129.507883 10 0a c0 ea 4b 08 40 00 00 c4 1a 592 + * 593 + * Pen: Tip switch, max pressure, then low pressure 594 + * E: 000242.077160 10 0a c1 7e 3c 12 31 ff 3f 03 fd 595 + * 596 + * E: 000339.139188 10 0a c1 ee 3a 9e 32 b5 00 06 f6 597 + * 598 + * Pen: Barrel switch 599 + * E: 000037.949777 10 0a c2 5c 28 47 2a 00 00 f6 3c 600 + * 601 + * Pen: Secondary barrel switch 602 + * E: 000038.320840 10 0a c4 e4 27 fd 29 00 00 f3 38 603 + * 604 + * Pen: Third switch 605 + * E: 000038.923822 10 0a c8 97 27 5f 29 00 00 f2 33 606 + * 607 + * 608 + * HIDRAW 2 609 + * EXAMPLE REPORTS 610 + * Either wheel rotation, one detent CW 611 + * E: 000097.276573 9 11 00 01 00 00 00 00 00 00 612 + * 613 + * Either wheel rotation, one detent CCW 614 + * E: 000153.416538 9 11 00 ff ff 00 00 00 00 00 615 + * 616 + * Either wheel rotation, increasing rotation speed CW 617 + * (Note that the wheels on my particular tablet may be 618 + * damaged, so the false rotation direction changes 619 + * that can be observed might not happen on other units.) 620 + * E: 000210.514925 9 11 00 01 00 00 00 00 00 00 621 + * E: 000210.725718 9 11 00 01 00 00 00 00 00 00 622 + * E: 000210.924009 9 11 00 01 00 00 00 00 00 00 623 + * E: 000211.205629 9 11 00 01 00 00 00 00 00 00 624 + * E: 000211.280521 9 11 00 0b 00 00 00 00 00 00 625 + * E: 000211.340121 9 11 00 0e 00 00 00 00 00 00 626 + * E: 000211.404018 9 11 00 0d 00 00 00 00 00 00 627 + * E: 000211.462060 9 11 00 0e 00 00 00 00 00 00 628 + * E: 000211.544886 9 11 00 0a 00 00 00 00 00 00 629 + * E: 000211.606130 9 11 00 0d 00 00 00 00 00 00 630 + * E: 000211.674560 9 11 00 0c 00 00 00 00 00 00 631 + * E: 000211.712039 9 11 00 16 00 00 00 00 00 00 632 + * E: 000211.748076 9 11 00 17 00 00 00 00 00 00 633 + * E: 000211.786016 9 11 00 17 00 00 00 00 00 00 634 + * E: 000211.832960 9 11 00 11 00 00 00 00 00 00 635 + * E: 000211.874081 9 11 00 14 00 00 00 00 00 00 636 + * E: 000211.925094 9 11 00 10 00 00 00 00 00 00 637 + * E: 000211.959048 9 11 00 18 00 00 00 00 00 00 638 + * E: 000212.006937 9 11 00 11 00 00 00 00 00 00 639 + * E: 000212.050055 9 11 00 13 00 00 00 00 00 00 640 + * E: 000212.091947 9 11 00 14 00 00 00 00 00 00 641 + * E: 000212.122989 9 11 00 1a 00 00 00 00 00 00 642 + * E: 000212.160866 9 11 00 16 00 00 00 00 00 00 643 + * E: 000212.194002 9 11 00 19 00 00 00 00 00 00 644 + * E: 000212.242249 9 11 00 11 00 00 00 00 00 00 645 + * E: 000212.278061 9 11 00 18 00 00 00 00 00 00 646 + * E: 000212.328899 9 11 00 10 00 00 00 00 00 00 647 + * E: 000212.354005 9 11 00 22 00 00 00 00 00 00 648 + * E: 000212.398995 9 11 00 12 00 00 00 00 00 00 649 + * E: 000212.432050 9 11 00 19 00 00 00 00 00 00 650 + * E: 000212.471164 9 11 00 16 00 00 00 00 00 00 651 + * E: 000212.507047 9 11 00 17 00 00 00 00 00 00 652 + * E: 000212.540964 9 11 00 19 00 00 00 00 00 00 653 + * E: 000212.567942 9 11 00 1f 00 00 00 00 00 00 654 + * E: 000212.610007 9 11 00 14 00 00 00 00 00 00 655 + * E: 000212.641101 9 11 00 1b 00 00 00 00 00 00 656 + * E: 000212.674113 9 11 00 19 00 00 00 00 00 00 657 + * E: 000212.674909 9 11 00 01 00 00 00 00 00 00 658 + * E: 000212.677062 9 11 00 00 02 00 00 00 00 00 659 + * E: 000212.679048 9 11 00 55 01 00 00 00 00 00 660 + * E: 000212.682166 9 11 00 55 01 00 00 00 00 00 661 + * E: 000212.682788 9 11 00 ff ff 00 00 00 00 00 662 + * E: 000212.683899 9 11 00 01 00 00 00 00 00 00 663 + * E: 000212.685827 9 11 00 67 fe 00 00 00 00 00 664 + * E: 000212.686941 9 11 00 00 08 00 00 00 00 00 665 + * E: 000212.727840 9 11 00 14 00 00 00 00 00 00 666 + * E: 000212.772884 9 11 00 13 00 00 00 00 00 00 667 + * E: 000212.810975 9 11 00 16 00 00 00 00 00 00 668 + * E: 000212.811793 9 11 00 00 08 00 00 00 00 00 669 + * E: 000212.812683 9 11 00 01 00 00 00 00 00 00 670 + * E: 000212.813905 9 11 00 01 00 00 00 00 00 00 671 + * E: 000212.814909 9 11 00 00 04 00 00 00 00 00 672 + * E: 000212.816942 9 11 00 01 00 00 00 00 00 00 673 + * E: 000212.817851 9 11 00 ff ff 00 00 00 00 00 674 + * E: 000212.818752 9 11 00 01 00 00 00 00 00 00 675 + * E: 000212.819910 9 11 00 56 fd 00 00 00 00 00 676 + * E: 000212.820781 9 11 00 ff ff 00 00 00 00 00 677 + * E: 000212.821811 9 11 00 00 04 00 00 00 00 00 678 + * E: 000212.822920 9 11 00 00 08 00 00 00 00 00 679 + * E: 000212.823861 9 11 00 00 02 00 00 00 00 00 680 + * E: 000212.828781 9 11 00 ba 00 00 00 00 00 00 681 + * E: 000212.874097 9 11 00 12 00 00 00 00 00 00 682 + * E: 000212.874872 9 11 00 00 fc 00 00 00 00 00 683 + * E: 000212.876136 9 11 00 00 fc 00 00 00 00 00 684 + * E: 000212.877036 9 11 00 00 f8 00 00 00 00 00 685 + * E: 000212.877993 9 11 00 00 f8 00 00 00 00 00 686 + * E: 000212.879748 9 11 00 01 00 00 00 00 00 00 687 + * E: 000212.880728 9 11 00 01 00 00 00 00 00 00 688 + * E: 000212.881956 9 11 00 00 04 00 00 00 00 00 689 + * E: 000212.885065 9 11 00 ff ff 00 00 00 00 00 690 + * E: 000212.917060 9 11 00 1a 00 00 00 00 00 00 691 + * E: 000212.936458 9 11 00 2d 00 00 00 00 00 00 692 + * E: 000212.957860 9 11 00 25 00 00 00 00 00 00 693 + * E: 000212.984019 9 11 00 20 00 00 00 00 00 00 694 + * E: 000213.017915 9 11 00 19 00 00 00 00 00 00 695 + * E: 000213.039973 9 11 00 27 00 00 00 00 00 00 696 + * E: 000213.065933 9 11 00 21 00 00 00 00 00 00 697 + * E: 000213.085807 9 11 00 28 00 00 00 00 00 00 698 + * E: 000213.108888 9 11 00 25 00 00 00 00 00 00 699 + * E: 000213.129726 9 11 00 29 00 00 00 00 00 00 700 + * E: 000213.172043 9 11 00 14 00 00 00 00 00 00 701 + * E: 000213.195873 9 11 00 23 00 00 00 00 00 00 702 + * E: 000213.222884 9 11 00 20 00 00 00 00 00 00 703 + * E: 000213.243220 9 11 00 2a 00 00 00 00 00 00 704 + * E: 000213.266778 9 11 00 24 00 00 00 00 00 00 705 + * E: 000213.285951 9 11 00 2b 00 00 00 00 00 00 706 + * E: 000213.306045 9 11 00 2a 00 00 00 00 00 00 707 + * E: 000213.306796 9 11 00 ff ff 00 00 00 00 00 708 + * E: 000213.307755 9 11 00 ff ff 00 00 00 00 00 709 + * E: 000213.308820 9 11 00 ff ff 00 00 00 00 00 710 + * E: 000213.309971 9 11 00 ff ff 00 00 00 00 00 711 + * E: 000213.310980 9 11 00 01 00 00 00 00 00 00 712 + * E: 000213.311853 9 11 00 01 00 00 00 00 00 00 713 + * E: 000213.312861 9 11 00 aa 02 00 00 00 00 00 714 + * E: 000213.313884 9 11 00 00 f8 00 00 00 00 00 715 + * E: 000213.315111 9 11 00 ff ff 00 00 00 00 00 716 + * E: 000213.315992 9 11 00 01 00 00 00 00 00 00 717 + * E: 000213.316955 9 11 00 00 08 00 00 00 00 00 718 + * E: 000213.346065 9 11 00 1d 00 00 00 00 00 00 719 + * E: 000213.346963 9 11 00 ff ff 00 00 00 00 00 720 + * E: 000213.347874 9 11 00 00 08 00 00 00 00 00 721 + * E: 000213.348736 9 11 00 00 08 00 00 00 00 00 722 + * E: 000213.349795 9 11 00 00 04 00 00 00 00 00 723 + * E: 000213.350791 9 11 00 01 00 00 00 00 00 00 724 + * E: 000213.351791 9 11 00 01 00 00 00 00 00 00 725 + * E: 000213.352729 9 11 00 00 f8 00 00 00 00 00 726 + * E: 000213.353811 9 11 00 01 00 00 00 00 00 00 727 + * E: 000213.354755 9 11 00 00 f8 00 00 00 00 00 728 + * E: 000213.355795 9 11 00 00 f8 00 00 00 00 00 729 + * E: 000213.356813 9 11 00 01 00 00 00 00 00 00 730 + * E: 000213.357817 9 11 00 00 04 00 00 00 00 00 731 + * E: 000213.393838 9 11 00 17 00 00 00 00 00 00 732 + * E: 000213.394719 9 11 00 00 04 00 00 00 00 00 733 + * E: 000213.395682 9 11 00 00 08 00 00 00 00 00 734 + * E: 000213.396679 9 11 00 00 04 00 00 00 00 00 735 + * E: 000213.397651 9 11 00 00 fc 00 00 00 00 00 736 + * E: 000213.398661 9 11 00 ff ff 00 00 00 00 00 737 + * E: 000213.400308 9 11 00 56 fd 00 00 00 00 00 738 + * E: 000213.400909 9 11 00 00 f8 00 00 00 00 00 739 + * E: 000213.401837 9 11 00 01 00 00 00 00 00 00 740 + * 741 + * Either wheel rotation, increasing rotation speed CCW 742 + * (Note that the wheels on my particular tablet may be 743 + * damaged, so the false rotation direction changes 744 + * that can be observed might not happen on other units.) 745 + * E: 000040.527820 9 11 00 ff ff 00 00 00 00 00 746 + * E: 000040.816644 9 11 00 ff ff 00 00 00 00 00 747 + * E: 000040.880423 9 11 00 f3 ff 00 00 00 00 00 748 + * E: 000040.882570 9 11 00 ff ff 00 00 00 00 00 749 + * E: 000040.883381 9 11 00 ff ff 00 00 00 00 00 750 + * E: 000040.885463 9 11 00 aa 02 00 00 00 00 00 751 + * E: 000040.924106 9 11 00 ea ff 00 00 00 00 00 752 + * E: 000041.006155 9 11 00 f6 ff 00 00 00 00 00 753 + * E: 000041.085799 9 11 00 f6 ff 00 00 00 00 00 754 + * E: 000041.168492 9 11 00 f6 ff 00 00 00 00 00 755 + * E: 000041.233453 9 11 00 f3 ff 00 00 00 00 00 756 + * E: 000041.296641 9 11 00 f3 ff 00 00 00 00 00 757 + * E: 000041.370302 9 11 00 f5 ff 00 00 00 00 00 758 + * E: 000041.437410 9 11 00 f4 ff 00 00 00 00 00 759 + * E: 000041.474514 9 11 00 e9 ff 00 00 00 00 00 760 + * E: 000041.522171 9 11 00 ef ff 00 00 00 00 00 761 + * E: 000041.568160 9 11 00 ee ff 00 00 00 00 00 762 + * E: 000041.608146 9 11 00 ec ff 00 00 00 00 00 763 + * E: 000041.627132 9 11 00 d3 ff 00 00 00 00 00 764 + * E: 000041.656151 9 11 00 e3 ff 00 00 00 00 00 765 + * E: 000041.682264 9 11 00 e0 ff 00 00 00 00 00 766 + * E: 000041.714186 9 11 00 e6 ff 00 00 00 00 00 767 + * E: 000041.740339 9 11 00 e0 ff 00 00 00 00 00 768 + * E: 000041.772087 9 11 00 e5 ff 00 00 00 00 00 769 + * E: 000041.801093 9 11 00 e3 ff 00 00 00 00 00 770 + * E: 000041.834051 9 11 00 e7 ff 00 00 00 00 00 771 + * E: 000041.863094 9 11 00 e3 ff 00 00 00 00 00 772 + * E: 000041.901016 9 11 00 ea ff 00 00 00 00 00 773 + * E: 000041.901956 9 11 00 00 04 00 00 00 00 00 774 + * E: 000041.902837 9 11 00 00 fe 00 00 00 00 00 775 + * E: 000041.903927 9 11 00 01 00 00 00 00 00 00 776 + * E: 000041.905066 9 11 00 01 00 00 00 00 00 00 777 + * E: 000041.907214 9 11 00 00 fe 00 00 00 00 00 778 + * E: 000041.909011 9 11 00 01 00 00 00 00 00 00 779 + * E: 000041.909953 9 11 00 01 00 00 00 00 00 00 780 + * E: 000041.910917 9 11 00 00 08 00 00 00 00 00 781 + * E: 000041.913280 9 11 00 00 fe 00 00 00 00 00 782 + * E: 000041.914121 9 11 00 56 fd 00 00 00 00 00 783 + * E: 000041.915346 9 11 00 ff ff 00 00 00 00 00 784 + * E: 000041.962101 9 11 00 ee ff 00 00 00 00 00 785 + * E: 000041.964062 9 11 00 56 fd 00 00 00 00 00 786 + * E: 000041.964978 9 11 00 00 fc 00 00 00 00 00 787 + * E: 000041.968058 9 11 00 24 01 00 00 00 00 00 788 + * E: 000041.968880 9 11 00 56 fd 00 00 00 00 00 789 + * E: 000041.970977 9 11 00 aa 02 00 00 00 00 00 790 + * E: 000041.971932 9 11 00 ff ff 00 00 00 00 00 791 + * E: 000041.972943 9 11 00 01 00 00 00 00 00 00 792 + * E: 000041.975291 9 11 00 ff ff 00 00 00 00 00 793 + * E: 000041.978274 9 11 00 01 00 00 00 00 00 00 794 + * E: 000042.035079 9 11 00 01 00 00 00 00 00 00 795 + * E: 000042.041283 9 11 00 ff ff 00 00 00 00 00 796 + * E: 000042.042057 9 11 00 00 04 00 00 00 00 00 797 + * E: 000042.045169 9 11 00 ff ff 00 00 00 00 00 798 + * E: 000042.051242 9 11 00 ff ff 00 00 00 00 00 799 + * E: 000042.056099 9 11 00 63 ff 00 00 00 00 00 800 + * E: 000042.106329 9 11 00 ef ff 00 00 00 00 00 801 + * E: 000042.108601 9 11 00 ff ff 00 00 00 00 00 802 + * E: 000042.116259 9 11 00 6b 00 00 00 00 00 00 803 + * E: 000042.119140 9 11 00 55 01 00 00 00 00 00 804 + * E: 000042.126101 9 11 00 88 ff 00 00 00 00 00 805 + * E: 000042.158009 9 11 00 e6 ff 00 00 00 00 00 806 + * E: 000042.172108 9 11 00 be ff 00 00 00 00 00 807 + * E: 000042.207417 9 11 00 e8 ff 00 00 00 00 00 808 + * E: 000042.223155 9 11 00 cc ff 00 00 00 00 00 809 + * E: 000042.255185 9 11 00 e6 ff 00 00 00 00 00 810 + * E: 000042.276280 9 11 00 d7 ff 00 00 00 00 00 811 + * E: 000042.302128 9 11 00 e0 ff 00 00 00 00 00 812 + * E: 000042.317423 9 11 00 c8 ff 00 00 00 00 00 813 + * E: 000042.345226 9 11 00 e1 ff 00 00 00 00 00 814 + * E: 000042.357243 9 11 00 bc ff 00 00 00 00 00 815 + * E: 000042.381308 9 11 00 dc ff 00 00 00 00 00 816 + * E: 000042.383180 9 11 00 dc fe 00 00 00 00 00 817 + * E: 000042.412288 9 11 00 e3 ff 00 00 00 00 00 818 + * E: 000042.451216 9 11 00 eb ff 00 00 00 00 00 819 + * E: 000042.478372 9 11 00 e0 ff 00 00 00 00 00 820 + * E: 000042.502116 9 11 00 dd ff 00 00 00 00 00 821 + * E: 000042.520105 9 11 00 d3 ff 00 00 00 00 00 822 + * E: 000042.540345 9 11 00 d6 ff 00 00 00 00 00 823 + * E: 000042.541021 9 11 00 00 08 00 00 00 00 00 824 + * E: 000042.542009 9 11 00 01 00 00 00 00 00 00 825 + * E: 000042.543045 9 11 00 00 04 00 00 00 00 00 826 + * E: 000042.544279 9 11 00 ff ff 00 00 00 00 00 827 + * E: 000042.545097 9 11 00 ff ff 00 00 00 00 00 828 + * E: 000042.546074 9 11 00 00 08 00 00 00 00 00 829 + * E: 000042.547237 9 11 00 00 08 00 00 00 00 00 830 + * E: 000042.548029 9 11 00 ff ff 00 00 00 00 00 831 + * E: 000042.549304 9 11 00 00 f8 00 00 00 00 00 832 + * E: 000042.553123 9 11 00 00 ff 00 00 00 00 00 833 + * E: 000042.581186 9 11 00 e1 ff 00 00 00 00 00 834 + * E: 000042.582238 9 11 00 00 f8 00 00 00 00 00 835 + * E: 000042.583150 9 11 00 00 fc 00 00 00 00 00 836 + * E: 000042.584273 9 11 00 00 f8 00 00 00 00 00 837 + * E: 000042.585019 9 11 00 00 fc 00 00 00 00 00 838 + * E: 000042.586059 9 11 00 01 00 00 00 00 00 00 839 + * E: 000042.589012 9 11 00 67 fe 00 00 00 00 00 840 + * E: 000042.590066 9 11 00 00 fc 00 00 00 00 00 841 + * E: 000042.592916 9 11 00 dc fe 00 00 00 00 00 842 + * E: 000042.621124 9 11 00 e1 ff 00 00 00 00 00 843 + * E: 000042.622092 9 11 00 ff ff 00 00 00 00 00 844 + * E: 000042.623069 9 11 00 01 00 00 00 00 00 00 845 + * E: 000042.624030 9 11 00 ff ff 00 00 00 00 00 846 + * E: 000042.625006 9 11 00 00 08 00 00 00 00 00 847 + * E: 000042.626068 9 11 00 00 04 00 00 00 00 00 848 + * E: 000042.626876 9 11 00 00 08 00 00 00 00 00 849 + * E: 000042.628392 9 11 00 00 08 00 00 00 00 00 850 + * E: 000042.628918 9 11 00 01 00 00 00 00 00 00 851 + * E: 000042.630009 9 11 00 ff ff 00 00 00 00 00 852 + * E: 000042.631934 9 11 00 00 fe 00 00 00 00 00 853 + * E: 000042.656285 9 11 00 dd ff 00 00 00 00 00 854 + * E: 000042.659870 9 11 00 cc 00 00 00 00 00 00 855 + * E: 000042.666128 9 11 00 9d 00 00 00 00 00 00 856 + * E: 000042.672458 9 11 00 80 ff 00 00 00 00 00 857 + * E: 000042.696106 9 11 00 dc ff 00 00 00 00 00 858 + * E: 000042.705129 9 11 00 61 00 00 00 00 00 00 859 + * E: 000042.731303 9 11 00 e0 ff 00 00 00 00 00 860 + * E: 000042.741278 9 11 00 ab ff 00 00 00 00 00 861 + * E: 000042.788181 9 11 00 ee ff 00 00 00 00 00 862 + * E: 000042.810441 9 11 00 db ff 00 00 00 00 00 863 + * E: 000042.838073 9 11 00 e1 ff 00 00 00 00 00 864 + * E: 000042.852235 9 11 00 c4 ff 00 00 00 00 00 865 + * E: 000042.882290 9 11 00 e4 ff 00 00 00 00 00 866 + * 867 + * Either wheel button, press, hold, then release 868 + * E: 000202.084982 9 11 02 00 00 00 00 00 00 00 869 + * E: 000202.090172 9 11 03 00 00 00 00 00 00 00 870 + * E: 000202.094139 9 11 03 00 00 00 00 00 00 00 871 + * E: 000202.099172 9 11 03 00 00 00 00 00 00 00 872 + * E: 000202.105055 9 11 03 00 00 00 00 00 00 00 873 + * E: 000202.109132 9 11 03 00 00 00 00 00 00 00 874 + * E: 000202.114185 9 11 03 00 00 00 00 00 00 00 875 + * E: 000202.119212 9 11 03 00 00 00 00 00 00 00 876 + * E: 000202.124264 9 11 03 00 00 00 00 00 00 00 877 + * E: 000202.130147 9 11 03 00 00 00 00 00 00 00 878 + * E: 000202.135138 9 11 03 00 00 00 00 00 00 00 879 + * E: 000202.140072 9 11 03 00 00 00 00 00 00 00 880 + * E: 000202.145146 9 11 03 00 00 00 00 00 00 00 881 + * E: 000202.150157 9 11 03 00 00 00 00 00 00 00 882 + * E: 000202.155339 9 11 03 00 00 00 00 00 00 00 883 + * E: 000202.160064 9 11 03 00 00 00 00 00 00 00 884 + * E: 000202.165026 9 11 03 00 00 00 00 00 00 00 885 + * E: 000202.170037 9 11 03 00 00 00 00 00 00 00 886 + * E: 000202.175154 9 11 03 00 00 00 00 00 00 00 887 + * E: 000202.180044 9 11 03 00 00 00 00 00 00 00 888 + * E: 000202.186280 9 11 03 00 00 00 00 00 00 00 889 + * E: 000202.191281 9 11 03 00 00 00 00 00 00 00 890 + * E: 000202.196106 9 11 03 00 00 00 00 00 00 00 891 + * E: 000202.201083 9 11 03 00 00 00 00 00 00 00 892 + * E: 000202.206166 9 11 03 00 00 00 00 00 00 00 893 + * E: 000202.211084 9 11 03 00 00 00 00 00 00 00 894 + * E: 000202.216175 9 11 03 00 00 00 00 00 00 00 895 + * E: 000202.221036 9 11 03 00 00 00 00 00 00 00 896 + * E: 000202.226271 9 11 03 00 00 00 00 00 00 00 897 + * E: 000202.231150 9 11 03 00 00 00 00 00 00 00 898 + * E: 000202.235924 9 11 03 00 00 00 00 00 00 00 899 + * E: 000202.242046 9 11 03 00 00 00 00 00 00 00 900 + * E: 000202.247164 9 11 03 00 00 00 00 00 00 00 901 + * E: 000202.252359 9 11 03 00 00 00 00 00 00 00 902 + * E: 000202.257295 9 11 03 00 00 00 00 00 00 00 903 + * E: 000202.262167 9 11 03 00 00 00 00 00 00 00 904 + * E: 000202.267081 9 11 03 00 00 00 00 00 00 00 905 + * E: 000202.272175 9 11 03 00 00 00 00 00 00 00 906 + * E: 000202.277085 9 11 03 00 00 00 00 00 00 00 907 + * E: 000202.282596 9 11 03 00 00 00 00 00 00 00 908 + * E: 000202.287078 9 11 03 00 00 00 00 00 00 00 909 + * E: 000202.292191 9 11 03 00 00 00 00 00 00 00 910 + * E: 000202.298196 9 11 03 00 00 00 00 00 00 00 911 + * E: 000202.303004 9 11 03 00 00 00 00 00 00 00 912 + * E: 000202.308113 9 11 03 00 00 00 00 00 00 00 913 + * E: 000202.313079 9 11 03 00 00 00 00 00 00 00 914 + * E: 000202.318243 9 11 03 00 00 00 00 00 00 00 915 + * E: 000202.323309 9 11 03 00 00 00 00 00 00 00 916 + * E: 000202.328190 9 11 03 00 00 00 00 00 00 00 917 + * E: 000202.333050 9 11 03 00 00 00 00 00 00 00 918 + * E: 000202.338162 9 11 03 00 00 00 00 00 00 00 919 + * E: 000202.343022 9 11 03 00 00 00 00 00 00 00 920 + * E: 000202.348113 9 11 03 00 00 00 00 00 00 00 921 + * E: 000202.354133 9 11 03 00 00 00 00 00 00 00 922 + * E: 000202.359132 9 11 03 00 00 00 00 00 00 00 923 + * E: 000202.364053 9 11 03 00 00 00 00 00 00 00 924 + * E: 000202.369034 9 11 03 00 00 00 00 00 00 00 925 + * E: 000202.374144 9 11 03 00 00 00 00 00 00 00 926 + * E: 000202.379027 9 11 03 00 00 00 00 00 00 00 927 + * E: 000202.384238 9 11 03 00 00 00 00 00 00 00 928 + * E: 000202.389249 9 11 03 00 00 00 00 00 00 00 929 + * E: 000202.394049 9 11 03 00 00 00 00 00 00 00 930 + * E: 000202.398949 9 11 03 00 00 00 00 00 00 00 931 + * E: 000202.404203 9 11 03 00 00 00 00 00 00 00 932 + * E: 000202.410098 9 11 03 00 00 00 00 00 00 00 933 + * E: 000202.415237 9 11 00 00 00 00 00 00 00 00 934 + * 935 + * 936 + * Top wheel button press and release while holding bottom wheel button 937 + * (The reverse action (a bottom wheel button press while holding the top wheel button) is invisible.) 938 + * E: 000071.126966 9 11 03 00 00 00 00 00 00 00 939 + * E: 000071.133117 9 11 03 00 00 00 00 00 00 00 940 + * E: 000071.137481 9 11 03 00 00 00 00 00 00 00 941 + * E: 000071.142036 9 11 03 00 00 00 00 00 00 00 942 + * E: 000071.147027 9 11 03 00 00 00 00 00 00 00 943 + * E: 000071.151988 9 11 03 00 00 00 00 00 00 00 944 + * E: 000071.157945 9 11 03 00 00 00 00 00 00 00 945 + * E: 000071.163657 9 11 03 00 00 00 00 00 00 00 946 + * E: 000071.168240 9 11 03 00 00 00 00 00 00 00 947 + * E: 000071.173109 9 11 02 00 00 00 00 00 00 00 < top wheel button press? 948 + * E: 000071.178119 9 11 03 00 00 00 00 00 00 00 949 + * E: 000071.183046 9 11 03 00 00 00 00 00 00 00 950 + * E: 000071.187983 9 11 03 00 00 00 00 00 00 00 951 + * E: 000071.192996 9 11 03 00 00 00 00 00 00 00 952 + * E: 000071.198341 9 11 03 00 00 00 00 00 00 00 953 + * E: 000071.203122 9 11 03 00 00 00 00 00 00 00 954 + * E: 000071.208998 9 11 03 00 00 00 00 00 00 00 955 + * E: 000071.214037 9 11 03 00 00 00 00 00 00 00 956 + * E: 000071.218945 9 11 03 00 00 00 00 00 00 00 957 + * E: 000071.223835 9 11 03 00 00 00 00 00 00 00 958 + * E: 000071.228987 9 11 03 00 00 00 00 00 00 00 959 + * E: 000071.234082 9 11 03 00 00 00 00 00 00 00 960 + * E: 000071.239028 9 11 03 00 00 00 00 00 00 00 961 + * E: 000071.244307 9 11 00 00 00 00 00 00 00 00 < top wheel button release? 962 + * E: 000071.245867 9 11 03 00 00 00 00 00 00 00 < continued hold of bottom button 963 + * E: 000071.249959 9 11 03 00 00 00 00 00 00 00 964 + * E: 000071.255032 9 11 03 00 00 00 00 00 00 00 965 + * E: 000071.259972 9 11 03 00 00 00 00 00 00 00 966 + * E: 000071.265409 9 11 03 00 00 00 00 00 00 00 967 + * E: 000071.270156 9 11 03 00 00 00 00 00 00 00 968 + * E: 000071.275530 9 11 03 00 00 00 00 00 00 00 969 + * E: 000071.279975 9 11 03 00 00 00 00 00 00 00 970 + * E: 000071.285046 9 11 03 00 00 00 00 00 00 00 971 + * E: 000071.290906 9 11 03 00 00 00 00 00 00 00 972 + * E: 000071.296146 9 11 03 00 00 00 00 00 00 00 973 + * E: 000071.301288 9 11 03 00 00 00 00 00 00 00 974 + * 975 + * Top wheel button hold while top wheel rotate CCW 976 + * (I did not test the other combinations of this) 977 + * E: 000022.253144 9 11 03 00 00 00 00 00 00 00 978 + * E: 000022.258157 9 11 03 00 00 00 00 00 00 00 979 + * E: 000022.262011 9 11 00 ff ff 00 00 00 00 00 980 + * E: 000022.264015 9 11 03 00 00 00 00 00 00 00 981 + * E: 000022.268976 9 11 03 00 00 00 00 00 00 00 982 + * 983 + * 984 + * 985 + * 986 + * 987 + * 988 + * 989 + * 990 + * NOTES ON SIMULTANEOUS BUTTON HOLDS 991 + * (applies to vendor mode only) 992 + * Value replacements for ease of reading: 993 + * .7 = 0x40 (button 7, a wheel button) 994 + * .1 = 0x01 (button 1, a pad button) 995 + * rr = 0x00 (no buttons pressed) 996 + * 997 + * Press 7 998 + * Press 1 999 + * Release 7 1000 + * Release 1 1001 + * B: 000000.000152 42 08 e0 01 01 .7 00 00 00 00 00 00 00 00 00 1002 + * B: 000000.781784 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1003 + * B: 000000.869845 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1004 + * B: 000001.095688 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1005 + * B: 000001.322635 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1006 + * B: 000001.543643 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1007 + * B: 000001.770652 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1008 + * B: 000001.885659 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00 release of 7 1009 + * B: 000001.993620 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1010 + * B: 000002.220671 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1011 + * B: 000002.446589 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1012 + * B: 000002.672559 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1013 + * B: 000002.765183 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00 release of 1 1014 + * 1015 + * Press 7 1016 + * Press 1 1017 + * Release 1 1018 + * Release 7 1019 + * B: 000017.071517 42 08 e0 01 01 .7 00 00 00 00 00 00 00 00 00 1020 + * B: 000018.270461 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1021 + * B: 000018.419486 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1022 + * B: 000018.646438 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1023 + * B: 000018.872493 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1024 + * B: 000019.094422 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1025 + * B: 000019.320488 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1026 + * B: 000020.360505 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00 release of 1 is not reported until 7 is released, then both are rapidly reported 1027 + * B: 000020.361091 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00 1028 + * 1029 + * Press 1 1030 + * Press 7 1031 + * Release 7 1032 + * Release 1 1033 + * B: 000031.516315 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1034 + * B: 000031.922299 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1035 + * B: 000032.144165 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1036 + * B: 000032.370262 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1037 + * B: 000032.396242 42 08 e0 01 01 .7 00 00 00 00 00 00 00 00 00 1038 + * B: 000032.597270 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1039 + * B: 000032.818187 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1040 + * B: 000033.045143 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1041 + * B: 000033.267535 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00 release of 7 1042 + * B: 000033.272602 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1043 + * B: 000033.494246 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1044 + * B: 000033.721266 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1045 + * B: 000033.947237 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1046 + * B: 000034.169294 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1047 + * B: 000034.183585 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00 release of 1 1048 + * 1049 + * Press 1 1050 + * Press 7 1051 + * Release 1 1052 + * Release 7 1053 + * B: 000056.628429 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1054 + * B: 000057.046348 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1055 + * B: 000057.272044 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1056 + * B: 000057.494434 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1057 + * B: 000057.601224 42 08 e0 01 01 .7 00 00 00 00 00 00 00 00 00 1058 + * B: 000057.719262 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1059 + * B: 000057.946941 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1060 + * B: 000058.172346 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1061 + * B: 000058.393994 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00 1062 + * B: 000059.434576 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00 release of 1 is not reported until 7 is released, then both are rapidly reported 1063 + * B: 000059.435857 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00 1064 + */ 1065 + 1066 + 1067 + /* Filled in by udev-hid-bpf */ 1068 + char UDEV_PROP_HUION_FIRMWARE_ID[64]; 1069 + 1070 + char EXPECTED_FIRMWARE_ID[] = "HUION_M22c_"; 1071 + 1072 + __u8 last_button_state; 1073 + 1074 + static const __u8 disabled_rdesc_tablet[] = { 1075 + FixedSizeVendorReport(28) /* Input report 4 */ 1076 + }; 1077 + 1078 + static const __u8 disabled_rdesc_wheel[] = { 1079 + FixedSizeVendorReport(9) /* Input report 17 */ 1080 + }; 1081 + 1082 + static const __u8 fixed_rdesc_vendor[] = { 1083 + UsagePage_Digitizers 1084 + Usage_Dig_Pen 1085 + CollectionApplication( 1086 + ReportId(VENDOR_REPORT_ID) 1087 + UsagePage_Digitizers 1088 + Usage_Dig_Pen 1089 + CollectionPhysical( 1090 + /* 1091 + * I have only examined the tablet's behavior while using 1092 + * the PW600L pen, which does not have an eraser. 1093 + * Because of this, I don't know where the Eraser and Invert 1094 + * bits will go, or if they work as one would expect. 1095 + * 1096 + * For the time being, there is no expectation that a pen 1097 + * with an eraser will work without modifications here. 1098 + */ 1099 + ReportSize(1) 1100 + LogicalMinimum_i8(0) 1101 + LogicalMaximum_i8(1) 1102 + ReportCount(3) 1103 + Usage_Dig_TipSwitch 1104 + Usage_Dig_BarrelSwitch 1105 + Usage_Dig_SecondaryBarrelSwitch 1106 + Input(Var|Abs) 1107 + PushPop( 1108 + ReportCount(1) 1109 + UsagePage_Button 1110 + Usage_i8(0x4a) /* (BTN_STYLUS3 + 1) & 0xff */ 1111 + Input(Var|Abs) 1112 + ) 1113 + ReportCount(3) 1114 + Input(Const) 1115 + ReportCount(1) 1116 + Usage_Dig_InRange 1117 + Input(Var|Abs) 1118 + ReportSize(16) 1119 + ReportCount(1) 1120 + PushPop( 1121 + UsagePage_GenericDesktop 1122 + Unit(cm) 1123 + UnitExponent(-2) 1124 + LogicalMinimum_i16(0) 1125 + PhysicalMinimum_i16(0) 1126 + /* 1127 + * The tablet has a logical maximum of 58760 x 33040 1128 + * and a claimed resolution of 5080 LPI (200 L/mm) 1129 + * This works out to a physical maximum of 1130 + * 293.8 x 165.2mm, which matches Huion's advertised 1131 + * active area dimensions from 1132 + * https://www.huion.com/products/pen_display/Kamvas/kamvas-13-gen-3.html 1133 + */ 1134 + LogicalMaximum_i16(58760) 1135 + PhysicalMaximum_i16(2938) 1136 + Usage_GD_X 1137 + Input(Var|Abs) 1138 + LogicalMaximum_i16(33040) 1139 + PhysicalMaximum_i16(1652) 1140 + Usage_GD_Y 1141 + Input(Var|Abs) 1142 + ) 1143 + LogicalMinimum_i16(0) 1144 + LogicalMaximum_i16(16383) 1145 + Usage_Dig_TipPressure 1146 + Input(Var|Abs) 1147 + ReportCount(1) 1148 + Input(Const) 1149 + ReportSize(8) 1150 + ReportCount(2) 1151 + PushPop( 1152 + Unit(deg) 1153 + UnitExponent(0) 1154 + LogicalMinimum_i8(-60) 1155 + PhysicalMinimum_i8(-60) 1156 + LogicalMaximum_i8(60) 1157 + PhysicalMaximum_i8(60) 1158 + Usage_Dig_XTilt 1159 + Usage_Dig_YTilt 1160 + Input(Var|Abs) 1161 + ) 1162 + ) 1163 + ) 1164 + UsagePage_GenericDesktop 1165 + Usage_GD_Keypad 1166 + CollectionApplication( 1167 + ReportId(CUSTOM_PAD_REPORT_ID) 1168 + LogicalMinimum_i8(0) 1169 + LogicalMaximum_i8(1) 1170 + UsagePage_Digitizers 1171 + Usage_Dig_TabletFunctionKeys 1172 + CollectionPhysical( 1173 + /* 1174 + * The first 3 bytes are somewhat vestigial and will 1175 + * always be set to zero. Their presence here is needed 1176 + * to ensure that this device will be detected as a 1177 + * tablet pad by software that otherwise wouldn't know 1178 + * any better. 1179 + */ 1180 + /* (data[1] & 0x01) barrel switch */ 1181 + ReportSize(1) 1182 + ReportCount(1) 1183 + Usage_Dig_BarrelSwitch 1184 + Input(Var|Abs) 1185 + ReportCount(7) 1186 + Input(Const) 1187 + /* data[2] X */ 1188 + /* data[3] Y */ 1189 + ReportSize(8) 1190 + ReportCount(2) 1191 + UsagePage_GenericDesktop 1192 + Usage_GD_X 1193 + Usage_GD_Y 1194 + Input(Var|Abs) 1195 + /* 1196 + * (data[4] & 0x01) button 1 1197 + * (data[4] & 0x02) button 2 1198 + * (data[4] & 0x04) button 3 1199 + * (data[4] & 0x08) button 4 1200 + * (data[4] & 0x10) button 5 1201 + * (data[4] & 0x20) button 6 (top wheel button) 1202 + * (data[4] & 0x40) button 7 (bottom wheel button) 1203 + */ 1204 + ReportSize(1) 1205 + ReportCount(7) 1206 + UsagePage_Button 1207 + UsageMinimum_i8(1) 1208 + UsageMaximum_i8(7) 1209 + Input(Var|Abs) 1210 + ReportCount(1) 1211 + Input(Const) 1212 + /* data[5] top wheel (signed, positive clockwise) */ 1213 + ReportSize(8) 1214 + ReportCount(1) 1215 + UsagePage_GenericDesktop 1216 + Usage_GD_Wheel 1217 + LogicalMinimum_i8(-1) 1218 + LogicalMaximum_i8(1) 1219 + Input(Var|Rel) 1220 + /* data[6] bottom wheel (signed, positive clockwise) */ 1221 + UsagePage_Consumer 1222 + Usage_Con_ACPan 1223 + Input(Var|Rel) 1224 + ) 1225 + /* 1226 + * The kernel will drop reports that are bigger than the 1227 + * largest report specified in the HID descriptor. 1228 + * Therefore, our modified descriptor needs to have at least one 1229 + * HID report that is as long as, or longer than, the largest 1230 + * report in the original descriptor. 1231 + * 1232 + * This macro expands to a no-op report that is padded to the 1233 + * provided length. 1234 + */ 1235 + FixedSizeVendorReport(VENDOR_REPORT_LENGTH) 1236 + ) 1237 + }; 1238 + 1239 + SEC(HID_BPF_RDESC_FIXUP) 1240 + int BPF_PROG(hid_fix_rdesc_huion_kamvas13_gen3, struct hid_bpf_ctx *hid_ctx) 1241 + { 1242 + __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */); 1243 + __s32 rdesc_size = hid_ctx->size; 1244 + __u8 have_fw_id; 1245 + 1246 + if (!data) 1247 + return 0; /* EPERM check */ 1248 + 1249 + have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID, 1250 + EXPECTED_FIRMWARE_ID, 1251 + sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0; 1252 + 1253 + if (have_fw_id) { 1254 + /* 1255 + * Tablet should be in vendor mode. 1256 + * Disable the unused devices 1257 + */ 1258 + if (rdesc_size == TABLET_DESCRIPTOR_LENGTH) { 1259 + __builtin_memcpy(data, disabled_rdesc_tablet, 1260 + sizeof(disabled_rdesc_tablet)); 1261 + return sizeof(disabled_rdesc_tablet); 1262 + } 1263 + 1264 + if (rdesc_size == WHEEL_DESCRIPTOR_LENGTH) { 1265 + __builtin_memcpy(data, disabled_rdesc_wheel, 1266 + sizeof(disabled_rdesc_wheel)); 1267 + return sizeof(disabled_rdesc_wheel); 1268 + } 1269 + } 1270 + 1271 + /* 1272 + * Regardless of which mode the tablet is in, always fix the vendor 1273 + * descriptor in case the udev property just happened to not be set 1274 + */ 1275 + if (rdesc_size == VENDOR_DESCRIPTOR_LENGTH) { 1276 + __builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor)); 1277 + return sizeof(fixed_rdesc_vendor); 1278 + } 1279 + 1280 + return 0; 1281 + } 1282 + 1283 + SEC(HID_BPF_DEVICE_EVENT) 1284 + int BPF_PROG(hid_fix_event_huion_kamvas13_gen3, struct hid_bpf_ctx *hid_ctx) 1285 + { 1286 + __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, VENDOR_REPORT_LENGTH /* size */); 1287 + 1288 + if (!data) 1289 + return 0; /* EPERM check */ 1290 + 1291 + /* Handle vendor reports only */ 1292 + if (hid_ctx->size != VENDOR_REPORT_LENGTH) 1293 + return 0; 1294 + if (data[0] != VENDOR_REPORT_ID) 1295 + return 0; 1296 + 1297 + __u8 report_subtype = (data[1] >> 4) & 0x0f; 1298 + 1299 + if (report_subtype == VENDOR_REPORT_SUBTYPE_PEN || 1300 + report_subtype == VENDOR_REPORT_SUBTYPE_PEN_OUT) { 1301 + /* Invert Y tilt */ 1302 + data[11] = -data[11]; 1303 + 1304 + } else if (report_subtype == VENDOR_REPORT_SUBTYPE_BUTTONS || 1305 + report_subtype == VENDOR_REPORT_SUBTYPE_WHEELS) { 1306 + struct pad_report { 1307 + __u8 report_id; 1308 + __u8 btn_stylus:1; 1309 + __u8 padding:7; 1310 + __u8 x; 1311 + __u8 y; 1312 + __u8 buttons; 1313 + __s8 top_wheel; 1314 + __s8 bottom_wheel; 1315 + } __attribute__((packed)) *pad_report; 1316 + 1317 + __s8 top_wheel = 0; 1318 + __s8 bottom_wheel = 0; 1319 + 1320 + switch (report_subtype) { 1321 + case VENDOR_REPORT_SUBTYPE_WHEELS: 1322 + /* 1323 + * The wheel direction byte is 1 for clockwise rotation 1324 + * and 2 for counter-clockwise. 1325 + * Change it to 1 and -1, respectively. 1326 + */ 1327 + switch (data[3]) { 1328 + case 1: 1329 + top_wheel = (data[5] == 1) ? 1 : -1; 1330 + break; 1331 + case 2: 1332 + bottom_wheel = (data[5] == 1) ? 1 : -1; 1333 + break; 1334 + } 1335 + break; 1336 + 1337 + case VENDOR_REPORT_SUBTYPE_BUTTONS: 1338 + /* 1339 + * If a button is already being held, ignore any new 1340 + * button event unless it's a release. 1341 + * 1342 + * The tablet only cleanly handles one button being held 1343 + * at a time, and trying to hold multiple buttons 1344 + * (particularly wheel+pad buttons) can result in sequences 1345 + * of reports that look like imaginary presses and releases. 1346 + * 1347 + * This is an imperfect way to filter out some of these 1348 + * reports. 1349 + */ 1350 + if (last_button_state != 0x00 && data[4] != 0x00) 1351 + break; 1352 + 1353 + last_button_state = data[4]; 1354 + break; 1355 + } 1356 + 1357 + 1358 + pad_report = (struct pad_report *)data; 1359 + 1360 + pad_report->report_id = CUSTOM_PAD_REPORT_ID; 1361 + pad_report->btn_stylus = 0; 1362 + pad_report->x = 0; 1363 + pad_report->y = 0; 1364 + pad_report->buttons = last_button_state; 1365 + pad_report->top_wheel = top_wheel; 1366 + pad_report->bottom_wheel = bottom_wheel; 1367 + 1368 + return sizeof(struct pad_report); 1369 + } 1370 + 1371 + return 0; 1372 + } 1373 + 1374 + HID_BPF_OPS(huion_kamvas13_gen3) = { 1375 + .hid_device_event = (void *)hid_fix_event_huion_kamvas13_gen3, 1376 + .hid_rdesc_fixup = (void *)hid_fix_rdesc_huion_kamvas13_gen3, 1377 + }; 1378 + 1379 + SEC("syscall") 1380 + int probe(struct hid_bpf_probe_args *ctx) 1381 + { 1382 + switch (ctx->rdesc_size) { 1383 + case VENDOR_DESCRIPTOR_LENGTH: 1384 + case TABLET_DESCRIPTOR_LENGTH: 1385 + case WHEEL_DESCRIPTOR_LENGTH: 1386 + ctx->retval = 0; 1387 + break; 1388 + default: 1389 + ctx->retval = -EINVAL; 1390 + } 1391 + 1392 + return 0; 1393 + } 1394 + 1395 + char _license[] SEC("license") = "GPL";
+724
drivers/hid/bpf/progs/Huion__Kamvas16Gen3.bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright (c) 2025 Nicholas LaPointe 3 + * Copyright (c) 2025 Higgins Dragon 4 + */ 5 + 6 + #include "vmlinux.h" 7 + #include "hid_bpf.h" 8 + #include "hid_bpf_helpers.h" 9 + #include "hid_report_helpers.h" 10 + #include <bpf/bpf_tracing.h> 11 + 12 + #define VID_HUION 0x256c 13 + #define PID_KAMVAS16_GEN3 0x2009 14 + 15 + #define VENDOR_DESCRIPTOR_LENGTH 36 16 + #define TABLET_DESCRIPTOR_LENGTH 328 17 + #define WHEEL_DESCRIPTOR_LENGTH 200 18 + 19 + #define VENDOR_REPORT_ID 8 20 + #define VENDOR_REPORT_LENGTH 14 21 + 22 + #define VENDOR_REPORT_SUBTYPE_PEN 0x08 23 + #define VENDOR_REPORT_SUBTYPE_PEN_OUT 0x00 24 + #define VENDOR_REPORT_SUBTYPE_BUTTONS 0x0e 25 + #define VENDOR_REPORT_SUBTYPE_WHEELS 0x0f 26 + 27 + /* For the reports that we create ourselves */ 28 + #define CUSTOM_PAD_REPORT_ID 9 29 + 30 + HID_BPF_CONFIG( 31 + HID_DEVICE(BUS_USB, HID_GROUP_ANY, VID_HUION, PID_KAMVAS16_GEN3), 32 + ); 33 + 34 + /* 35 + * This tablet can send reports using one of two different data formats, 36 + * depending on what "mode" the tablet is in. 37 + * 38 + * By default, the tablet will send reports that can be decoded using its 39 + * included HID descriptors (descriptors 1 and 2, shown below). 40 + * This mode will be called "firmware mode" throughout this file. 41 + * 42 + * The HID descriptor that describes pen events in firmware mode (descriptor 1) 43 + * has multiple bugs: 44 + * * "Secondary Tip Switch" instead of "Secondary Barrel Switch" 45 + * * "Invert" instead of (or potentially shared with) third barrel button 46 + * * Specified tablet area of 2048 in³ instead of 293.8 x 165.2mm 47 + * * Specified tilt range of -90 to +90 instead of -60 to +60 48 + * 49 + * While these can be easily patched up by editing the descriptor, a larger 50 + * problem with the firmware mode exists: it is impossible to tell which of the 51 + * two wheels are being rotated (or having their central button pressed). 52 + * 53 + * 54 + * By using a tool such as huion-switcher (https://github.com/whot/huion-switcher), 55 + * the tablet can be made to send reports using a proprietary format that is not 56 + * adequately described by its relevant descriptor (descriptor 0, shown below). 57 + * This mode will be called "vendor mode" throughout this file. 58 + * 59 + * The reports sent while in vendor mode allow for proper decoding of the wheels. 60 + * 61 + * For simplicity and maximum functionality, this BPF focuses strictly on 62 + * enabling one to make use of the vendor mode. 63 + */ 64 + 65 + /* 66 + * DESCRIPTORS 67 + * DESCRIPTOR 0 68 + * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 0 69 + * # 0x09, 0x01, // Usage (Vendor Usage 1) 3 70 + * # 0xa1, 0x01, // Collection (Application) 5 71 + * # 0x85, 0x08, // Report ID (8) 7 72 + * # 0x75, 0x68, // Report Size (104) 9 73 + * # 0x95, 0x01, // Report Count (1) 11 74 + * # 0x09, 0x01, // Usage (Vendor Usage 1) 13 75 + * # 0x81, 0x02, // Input (Data,Var,Abs) 15 76 + * # 0xc0, // End Collection 17 77 + * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 18 78 + * # 0x09, 0x01, // Usage (Vendor Usage 1) 21 79 + * # 0xa1, 0x01, // Collection (Application) 23 80 + * # 0x85, 0x16, // Report ID (22) 25 81 + * # 0x75, 0x08, // Report Size (8) 27 82 + * # 0x95, 0x07, // Report Count (7) 29 83 + * # 0x09, 0x01, // Usage (Vendor Usage 1) 31 84 + * # 0xb1, 0x02, // Feature (Data,Var,Abs) 33 85 + * # 0xc0, // End Collection 35 86 + * # 87 + * R: 36 06 00 ff 09 01 a1 01 85 08 75 68 95 01 09 01 81 02 c0 06 00 ff 09 01 a1 01 85 16 75 08 95 07 09 01 b1 02 c0 88 + * N: HUION Huion Tablet_GS1563 89 + * I: 3 256c 2009 90 + * 91 + * 92 + * DESCRIPTOR 1 93 + * # 0x05, 0x0d, // Usage Page (Digitizers) 0 94 + * # 0x09, 0x02, // Usage (Pen) 2 95 + * # 0xa1, 0x01, // Collection (Application) 4 96 + * # 0x85, 0x0a, // Report ID (10) 6 97 + * # 0x09, 0x20, // Usage (Stylus) 8 98 + * # 0xa1, 0x01, // Collection (Application) 10 99 + * # 0x09, 0x42, // Usage (Tip Switch) 12 100 + * # 0x09, 0x44, // Usage (Barrel Switch) 14 101 + * # 0x09, 0x43, // Usage (Secondary Tip Switch) 16 102 + * # 0x09, 0x3c, // Usage (Invert) 18 103 + * # 0x09, 0x45, // Usage (Eraser) 20 104 + * # 0x15, 0x00, // Logical Minimum (0) 22 105 + * # 0x25, 0x01, // Logical Maximum (1) 24 106 + * # 0x75, 0x01, // Report Size (1) 26 107 + * # 0x95, 0x06, // Report Count (6) 28 108 + * # 0x81, 0x02, // Input (Data,Var,Abs) 30 109 + * # 0x09, 0x32, // Usage (In Range) 32 110 + * # 0x75, 0x01, // Report Size (1) 34 111 + * # 0x95, 0x01, // Report Count (1) 36 112 + * # 0x81, 0x02, // Input (Data,Var,Abs) 38 113 + * # 0x81, 0x03, // Input (Cnst,Var,Abs) 40 114 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 42 115 + * # 0x09, 0x30, // Usage (X) 44 116 + * # 0x09, 0x31, // Usage (Y) 46 117 + * # 0x55, 0x0d, // Unit Exponent (-3) 48 118 + * # 0x65, 0x33, // Unit (EnglishLinear: in³) 50 119 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 52 120 + * # 0x35, 0x00, // Physical Minimum (0) 55 121 + * # 0x46, 0x00, 0x08, // Physical Maximum (2048) 57 122 + * # 0x75, 0x10, // Report Size (16) 60 123 + * # 0x95, 0x02, // Report Count (2) 62 124 + * # 0x81, 0x02, // Input (Data,Var,Abs) 64 125 + * # 0x05, 0x0d, // Usage Page (Digitizers) 66 126 + * # 0x09, 0x30, // Usage (Tip Pressure) 68 127 + * # 0x26, 0xff, 0x3f, // Logical Maximum (16383) 70 128 + * # 0x75, 0x10, // Report Size (16) 73 129 + * # 0x95, 0x01, // Report Count (1) 75 130 + * # 0x81, 0x02, // Input (Data,Var,Abs) 77 131 + * # 0x09, 0x3d, // Usage (X Tilt) 79 132 + * # 0x09, 0x3e, // Usage (Y Tilt) 81 133 + * # 0x15, 0xa6, // Logical Minimum (-90) 83 134 + * # 0x25, 0x5a, // Logical Maximum (90) 85 135 + * # 0x75, 0x08, // Report Size (8) 87 136 + * # 0x95, 0x02, // Report Count (2) 89 137 + * # 0x81, 0x02, // Input (Data,Var,Abs) 91 138 + * # 0xc0, // End Collection 93 139 + * # 0xc0, // End Collection 94 140 + * # 0x05, 0x0d, // Usage Page (Digitizers) 95 141 + * # 0x09, 0x04, // Usage (Touch Screen) 97 142 + * # 0xa1, 0x01, // Collection (Application) 99 143 + * # 0x85, 0x04, // Report ID (4) 101 144 + * # 0x09, 0x22, // Usage (Finger) 103 145 + * # 0xa1, 0x02, // Collection (Logical) 105 146 + * # 0x05, 0x0d, // Usage Page (Digitizers) 107 147 + * # 0x95, 0x01, // Report Count (1) 109 148 + * # 0x75, 0x06, // Report Size (6) 111 149 + * # 0x09, 0x51, // Usage (Contact Id) 113 150 + * # 0x15, 0x00, // Logical Minimum (0) 115 151 + * # 0x25, 0x3f, // Logical Maximum (63) 117 152 + * # 0x81, 0x02, // Input (Data,Var,Abs) 119 153 + * # 0x09, 0x42, // Usage (Tip Switch) 121 154 + * # 0x25, 0x01, // Logical Maximum (1) 123 155 + * # 0x75, 0x01, // Report Size (1) 125 156 + * # 0x95, 0x01, // Report Count (1) 127 157 + * # 0x81, 0x02, // Input (Data,Var,Abs) 129 158 + * # 0x75, 0x01, // Report Size (1) 131 159 + * # 0x95, 0x01, // Report Count (1) 133 160 + * # 0x81, 0x03, // Input (Cnst,Var,Abs) 135 161 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 137 162 + * # 0x75, 0x10, // Report Size (16) 139 163 + * # 0x55, 0x0e, // Unit Exponent (-2) 141 164 + * # 0x65, 0x11, // Unit (SILinear: cm) 143 165 + * # 0x09, 0x30, // Usage (X) 145 166 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 147 167 + * # 0x35, 0x00, // Physical Minimum (0) 150 168 + * # 0x46, 0x15, 0x0c, // Physical Maximum (3093) 152 169 + * # 0x81, 0x42, // Input (Data,Var,Abs,Null) 155 170 + * # 0x09, 0x31, // Usage (Y) 157 171 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 159 172 + * # 0x46, 0xcb, 0x06, // Physical Maximum (1739) 162 173 + * # 0x81, 0x42, // Input (Data,Var,Abs,Null) 165 174 + * # 0x05, 0x0d, // Usage Page (Digitizers) 167 175 + * # 0x09, 0x30, // Usage (Tip Pressure) 169 176 + * # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 171 177 + * # 0x75, 0x10, // Report Size (16) 174 178 + * # 0x95, 0x01, // Report Count (1) 176 179 + * # 0x81, 0x02, // Input (Data,Var,Abs) 178 180 + * # 0xc0, // End Collection 180 181 + * # 0x05, 0x0d, // Usage Page (Digitizers) 181 182 + * # 0x09, 0x22, // Usage (Finger) 183 183 + * # 0xa1, 0x02, // Collection (Logical) 185 184 + * # 0x05, 0x0d, // Usage Page (Digitizers) 187 185 + * # 0x95, 0x01, // Report Count (1) 189 186 + * # 0x75, 0x06, // Report Size (6) 191 187 + * # 0x09, 0x51, // Usage (Contact Id) 193 188 + * # 0x15, 0x00, // Logical Minimum (0) 195 189 + * # 0x25, 0x3f, // Logical Maximum (63) 197 190 + * # 0x81, 0x02, // Input (Data,Var,Abs) 199 191 + * # 0x09, 0x42, // Usage (Tip Switch) 201 192 + * # 0x25, 0x01, // Logical Maximum (1) 203 193 + * # 0x75, 0x01, // Report Size (1) 205 194 + * # 0x95, 0x01, // Report Count (1) 207 195 + * # 0x81, 0x02, // Input (Data,Var,Abs) 209 196 + * # 0x75, 0x01, // Report Size (1) 211 197 + * # 0x95, 0x01, // Report Count (1) 213 198 + * # 0x81, 0x03, // Input (Cnst,Var,Abs) 215 199 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 217 200 + * # 0x75, 0x10, // Report Size (16) 219 201 + * # 0x55, 0x0e, // Unit Exponent (-2) 221 202 + * # 0x65, 0x11, // Unit (SILinear: cm) 223 203 + * # 0x09, 0x30, // Usage (X) 225 204 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 227 205 + * # 0x35, 0x00, // Physical Minimum (0) 230 206 + * # 0x46, 0x15, 0x0c, // Physical Maximum (3093) 232 207 + * # 0x81, 0x42, // Input (Data,Var,Abs,Null) 235 208 + * # 0x09, 0x31, // Usage (Y) 237 209 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 239 210 + * # 0x46, 0xcb, 0x06, // Physical Maximum (1739) 242 211 + * # 0x81, 0x42, // Input (Data,Var,Abs,Null) 245 212 + * # 0x05, 0x0d, // Usage Page (Digitizers) 247 213 + * # 0x09, 0x30, // Usage (Tip Pressure) 249 214 + * # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 251 215 + * # 0x75, 0x10, // Report Size (16) 254 216 + * # 0x95, 0x01, // Report Count (1) 256 217 + * # 0x81, 0x02, // Input (Data,Var,Abs) 258 218 + * # 0xc0, // End Collection 260 219 + * # 0x05, 0x0d, // Usage Page (Digitizers) 261 220 + * # 0x09, 0x56, // Usage (Scan Time) 263 221 + * # 0x55, 0x00, // Unit Exponent (0) 265 222 + * # 0x65, 0x00, // Unit (None) 267 223 + * # 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 269 224 + * # 0x95, 0x01, // Report Count (1) 274 225 + * # 0x75, 0x20, // Report Size (32) 276 226 + * # 0x81, 0x02, // Input (Data,Var,Abs) 278 227 + * # 0x09, 0x54, // Usage (Contact Count) 280 228 + * # 0x25, 0x7f, // Logical Maximum (127) 282 229 + * # 0x95, 0x01, // Report Count (1) 284 230 + * # 0x75, 0x08, // Report Size (8) 286 231 + * # 0x81, 0x02, // Input (Data,Var,Abs) 288 232 + * # 0x75, 0x08, // Report Size (8) 290 233 + * # 0x95, 0x08, // Report Count (8) 292 234 + * # 0x81, 0x03, // Input (Cnst,Var,Abs) 294 235 + * # 0x85, 0x05, // Report ID (5) 296 236 + * # 0x09, 0x55, // Usage (Contact Max) 298 237 + * # 0x25, 0x0a, // Logical Maximum (10) 300 238 + * # 0x75, 0x08, // Report Size (8) 302 239 + * # 0x95, 0x01, // Report Count (1) 304 240 + * # 0xb1, 0x02, // Feature (Data,Var,Abs) 306 241 + * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 308 242 + * # 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 311 243 + * # 0x85, 0x06, // Report ID (6) 313 244 + * # 0x15, 0x00, // Logical Minimum (0) 315 245 + * # 0x26, 0xff, 0x00, // Logical Maximum (255) 317 246 + * # 0x75, 0x08, // Report Size (8) 320 247 + * # 0x96, 0x00, 0x01, // Report Count (256) 322 248 + * # 0xb1, 0x02, // Feature (Data,Var,Abs) 325 249 + * # 0xc0, // End Collection 327 250 + * # 251 + * R: 328 05 0d 09 02 a1 01 85 0a 09 20 a1 01 09 42 09 44 09 43 09 3c 09 45 15 00 25 01 75 01 95 06 81 02 09 32 75 01 95 01 81 02 81 03 05 01 09 30 09 31 55 0d 65 33 26 ff 7f 35 00 46 00 08 75 10 95 02 81 02 05 0d 09 30 26 ff 3f 75 10 95 01 81 02 09 3d 09 3e 15 a6 25 5a 75 08 95 02 81 02 c0 c0 05 0d 09 04 a1 01 85 04 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 56 55 00 65 00 27 ff ff ff 7f 95 01 75 20 81 02 09 54 25 7f 95 01 75 08 81 02 75 08 95 08 81 03 85 05 09 55 25 0a 75 08 95 01 b1 02 06 00 ff 09 c5 85 06 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 252 + * N: HUION Huion Tablet_GS1563 253 + * I: 3 256c 2009 254 + * 255 + * DESCRIPTOR 2 256 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 0 257 + * # 0x09, 0x0e, // Usage (System Multi-Axis Controller) 2 258 + * # 0xa1, 0x01, // Collection (Application) 4 259 + * # 0x85, 0x11, // Report ID (17) 6 260 + * # 0x05, 0x0d, // Usage Page (Digitizers) 8 261 + * # 0x09, 0x21, // Usage (Puck) 10 262 + * # 0xa1, 0x02, // Collection (Logical) 12 263 + * # 0x15, 0x00, // Logical Minimum (0) 14 264 + * # 0x25, 0x01, // Logical Maximum (1) 16 265 + * # 0x75, 0x01, // Report Size (1) 18 266 + * # 0x95, 0x01, // Report Count (1) 20 267 + * # 0xa1, 0x00, // Collection (Physical) 22 268 + * # 0x05, 0x09, // Usage Page (Button) 24 269 + * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 26 270 + * # 0x81, 0x02, // Input (Data,Var,Abs) 28 271 + * # 0x05, 0x0d, // Usage Page (Digitizers) 30 272 + * # 0x09, 0x33, // Usage (Touch) 32 273 + * # 0x81, 0x02, // Input (Data,Var,Abs) 34 274 + * # 0x95, 0x06, // Report Count (6) 36 275 + * # 0x81, 0x03, // Input (Cnst,Var,Abs) 38 276 + * # 0xa1, 0x02, // Collection (Logical) 40 277 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 42 278 + * # 0x09, 0x37, // Usage (Dial) 44 279 + * # 0x16, 0x00, 0x80, // Logical Minimum (-32768) 46 280 + * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 49 281 + * # 0x75, 0x10, // Report Size (16) 52 282 + * # 0x95, 0x01, // Report Count (1) 54 283 + * # 0x81, 0x06, // Input (Data,Var,Rel) 56 284 + * # 0x35, 0x00, // Physical Minimum (0) 58 285 + * # 0x46, 0x10, 0x0e, // Physical Maximum (3600) 60 286 + * # 0x15, 0x00, // Logical Minimum (0) 63 287 + * # 0x26, 0x10, 0x0e, // Logical Maximum (3600) 65 288 + * # 0x09, 0x48, // Usage (Resolution Multiplier) 68 289 + * # 0xb1, 0x02, // Feature (Data,Var,Abs) 70 290 + * # 0x45, 0x00, // Physical Maximum (0) 72 291 + * # 0xc0, // End Collection 74 292 + * # 0x75, 0x08, // Report Size (8) 75 293 + * # 0x95, 0x01, // Report Count (1) 77 294 + * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 79 295 + * # 0x75, 0x08, // Report Size (8) 81 296 + * # 0x95, 0x01, // Report Count (1) 83 297 + * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 85 298 + * # 0x75, 0x08, // Report Size (8) 87 299 + * # 0x95, 0x01, // Report Count (1) 89 300 + * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 91 301 + * # 0x75, 0x08, // Report Size (8) 93 302 + * # 0x95, 0x01, // Report Count (1) 95 303 + * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 97 304 + * # 0x75, 0x08, // Report Size (8) 99 305 + * # 0x95, 0x01, // Report Count (1) 101 306 + * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 103 307 + * # 0xc0, // End Collection 105 308 + * # 0xc0, // End Collection 106 309 + * # 0xc0, // End Collection 107 310 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 108 311 + * # 0x09, 0x06, // Usage (Keyboard) 110 312 + * # 0xa1, 0x01, // Collection (Application) 112 313 + * # 0x85, 0x03, // Report ID (3) 114 314 + * # 0x05, 0x07, // Usage Page (Keyboard) 116 315 + * # 0x19, 0xe0, // Usage Minimum (224) 118 316 + * # 0x29, 0xe7, // Usage Maximum (231) 120 317 + * # 0x15, 0x00, // Logical Minimum (0) 122 318 + * # 0x25, 0x01, // Logical Maximum (1) 124 319 + * # 0x75, 0x01, // Report Size (1) 126 320 + * # 0x95, 0x08, // Report Count (8) 128 321 + * # 0x81, 0x02, // Input (Data,Var,Abs) 130 322 + * # 0x05, 0x07, // Usage Page (Keyboard) 132 323 + * # 0x19, 0x00, // Usage Minimum (0) 134 324 + * # 0x29, 0xff, // Usage Maximum (255) 136 325 + * # 0x26, 0xff, 0x00, // Logical Maximum (255) 138 326 + * # 0x75, 0x08, // Report Size (8) 141 327 + * # 0x95, 0x06, // Report Count (6) 143 328 + * # 0x81, 0x00, // Input (Data,Arr,Abs) 145 329 + * # 0xc0, // End Collection 147 330 + * # 0x05, 0x0c, // Usage Page (Consumer Devices) 148 331 + * # 0x09, 0x01, // Usage (Consumer Control) 150 332 + * # 0xa1, 0x01, // Collection (Application) 152 333 + * # 0x85, 0x04, // Report ID (4) 154 334 + * # 0x19, 0x01, // Usage Minimum (1) 156 335 + * # 0x2a, 0x9c, 0x02, // Usage Maximum (668) 158 336 + * # 0x15, 0x01, // Logical Minimum (1) 161 337 + * # 0x26, 0x9c, 0x02, // Logical Maximum (668) 163 338 + * # 0x95, 0x01, // Report Count (1) 166 339 + * # 0x75, 0x10, // Report Size (16) 168 340 + * # 0x81, 0x00, // Input (Data,Arr,Abs) 170 341 + * # 0xc0, // End Collection 172 342 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 173 343 + * # 0x09, 0x80, // Usage (System Control) 175 344 + * # 0xa1, 0x01, // Collection (Application) 177 345 + * # 0x85, 0x05, // Report ID (5) 179 346 + * # 0x19, 0x81, // Usage Minimum (129) 181 347 + * # 0x29, 0x83, // Usage Maximum (131) 183 348 + * # 0x15, 0x00, // Logical Minimum (0) 185 349 + * # 0x25, 0x01, // Logical Maximum (1) 187 350 + * # 0x75, 0x01, // Report Size (1) 189 351 + * # 0x95, 0x03, // Report Count (3) 191 352 + * # 0x81, 0x02, // Input (Data,Var,Abs) 193 353 + * # 0x95, 0x05, // Report Count (5) 195 354 + * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 197 355 + * # 0xc0, // End Collection 199 356 + * # 357 + * R: 200 05 01 09 0e a1 01 85 11 05 0d 09 21 a1 02 15 00 25 01 75 01 95 01 a1 00 05 09 09 01 81 02 05 0d 09 33 81 02 95 06 81 03 a1 02 05 01 09 37 16 00 80 26 ff 7f 75 10 95 01 81 06 35 00 46 10 0e 15 00 26 10 0e 09 48 b1 02 45 00 c0 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 c0 c0 c0 05 01 09 06 a1 01 85 03 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 05 07 19 00 29 ff 26 ff 00 75 08 95 06 81 00 c0 05 0c 09 01 a1 01 85 04 19 01 2a 9c 02 15 01 26 9c 02 95 01 75 10 81 00 c0 05 01 09 80 a1 01 85 05 19 81 29 83 15 00 25 01 75 01 95 03 81 02 95 05 81 01 c0 358 + * N: HUION Huion Tablet_GS1563 359 + * I: 3 256c 2009 360 + * 361 + * 362 + * 363 + * VENDOR MODE 364 + * HUION_FIRMWARE_ID="HUION_M22d_241101" 365 + * HUION_MAGIC_BYTES="1403201101ac9900ff3fd81305080080083c4010" 366 + * 367 + * MAGIC BYTES 368 + * [LogicalMaximum, X ] [LogicalMaximum, Y ] [LogicalMaximum, Pressure] [ LPI] 369 + * 14 03 [ 20 11 01] [ ac 99 00] [ ff 3f] [d8 13] 05 08 00 80 08 3c 40 10 370 + * 371 + * See Huion__Kamvas13Gen3.bpf.c for more details on detailed button/dial reports and caveats. It's very 372 + * similar to the Kamvas 16 Gen 3. 373 + */ 374 + 375 + 376 + /* Filled in by udev-hid-bpf */ 377 + char UDEV_PROP_HUION_FIRMWARE_ID[64]; 378 + 379 + char EXPECTED_FIRMWARE_ID[] = "HUION_M22d_"; 380 + 381 + __u8 last_button_state; 382 + 383 + static const __u8 disabled_rdesc_tablet[] = { 384 + FixedSizeVendorReport(28) /* Input report 4 */ 385 + }; 386 + 387 + static const __u8 disabled_rdesc_wheel[] = { 388 + FixedSizeVendorReport(9) /* Input report 17 */ 389 + }; 390 + 391 + static const __u8 fixed_rdesc_vendor[] = { 392 + UsagePage_Digitizers 393 + Usage_Dig_Pen 394 + CollectionApplication( 395 + ReportId(VENDOR_REPORT_ID) 396 + UsagePage_Digitizers 397 + Usage_Dig_Pen 398 + CollectionPhysical( 399 + /* 400 + * I have only examined the tablet's behavior while using 401 + * the PW600L pen, which does not have an eraser. 402 + * Because of this, I don't know where the Eraser and Invert 403 + * bits will go, or if they work as one would expect. 404 + * 405 + * For the time being, there is no expectation that a pen 406 + * with an eraser will work without modifications here. 407 + */ 408 + ReportSize(1) 409 + LogicalMinimum_i8(0) 410 + LogicalMaximum_i8(1) 411 + ReportCount(3) 412 + Usage_Dig_TipSwitch 413 + Usage_Dig_BarrelSwitch 414 + Usage_Dig_SecondaryBarrelSwitch 415 + Input(Var|Abs) 416 + PushPop( 417 + ReportCount(1) 418 + UsagePage_Button 419 + Usage_i8(0x4a) /* (BTN_STYLUS3 + 1) & 0xff */ 420 + Input(Var|Abs) 421 + ) 422 + ReportCount(3) 423 + Input(Const) 424 + ReportCount(1) 425 + Usage_Dig_InRange 426 + Input(Var|Abs) 427 + ReportSize(16) 428 + ReportCount(1) 429 + PushPop( 430 + UsagePage_GenericDesktop 431 + Unit(cm) 432 + UnitExponent(-2) 433 + LogicalMinimum_i16(0) 434 + PhysicalMinimum_i16(0) 435 + /* 436 + * The tablet has a logical maximum of 69920 x 39340 437 + * and a claimed resolution of 5080 LPI (200 L/mm) 438 + * This works out to a physical maximum of 439 + * 349.6 x 196.7mm, which matches Huion's advertised 440 + * (rounded) active area dimensions from 441 + * https://www.huion.com/products/pen_display/Kamvas/kamvas-16-gen-3.html 442 + * 443 + * The Kamvas uses data[8] for the 3rd byte of the X-axis, and adding 444 + * that after data[2] and data[3] makes a contiguous little-endian 445 + * 24-bit value. (See BPF_PROG below) 446 + */ 447 + ReportSize(24) 448 + LogicalMaximum_i32(69920) 449 + PhysicalMaximum_i16(3496) 450 + Usage_GD_X 451 + Input(Var|Abs) 452 + ReportSize(16) 453 + LogicalMaximum_i16(39340) 454 + PhysicalMaximum_i16(1967) 455 + Usage_GD_Y 456 + Input(Var|Abs) 457 + ) 458 + ReportSize(16) 459 + LogicalMinimum_i16(0) 460 + LogicalMaximum_i16(16383) 461 + Usage_Dig_TipPressure 462 + Input(Var|Abs) 463 + ReportSize(8) 464 + ReportCount(1) 465 + Input(Const) 466 + ReportCount(2) 467 + PushPop( 468 + Unit(deg) 469 + UnitExponent(0) 470 + LogicalMinimum_i8(-60) 471 + PhysicalMinimum_i8(-60) 472 + LogicalMaximum_i8(60) 473 + PhysicalMaximum_i8(60) 474 + Usage_Dig_XTilt 475 + Usage_Dig_YTilt 476 + Input(Var|Abs) 477 + ) 478 + ) 479 + ) 480 + UsagePage_GenericDesktop 481 + Usage_GD_Keypad 482 + CollectionApplication( 483 + ReportId(CUSTOM_PAD_REPORT_ID) 484 + LogicalMinimum_i8(0) 485 + LogicalMaximum_i8(1) 486 + UsagePage_Digitizers 487 + Usage_Dig_TabletFunctionKeys 488 + CollectionPhysical( 489 + /* 490 + * The first 3 bytes are somewhat vestigial and will 491 + * always be set to zero. Their presence here is needed 492 + * to ensure that this device will be detected as a 493 + * tablet pad by software that otherwise wouldn't know 494 + * any better. 495 + */ 496 + /* (data[1] & 0x01) barrel switch */ 497 + ReportSize(1) 498 + ReportCount(1) 499 + Usage_Dig_BarrelSwitch 500 + Input(Var|Abs) 501 + ReportCount(7) 502 + Input(Const) 503 + /* data[2] X */ 504 + /* data[3] Y */ 505 + ReportSize(8) 506 + ReportCount(2) 507 + UsagePage_GenericDesktop 508 + Usage_GD_X 509 + Usage_GD_Y 510 + Input(Var|Abs) 511 + /* 512 + * (data[4] & 0x01) button 1 513 + * (data[4] & 0x02) button 2 514 + * (data[4] & 0x04) button 3 515 + * (data[4] & 0x08) button 4 516 + * (data[4] & 0x10) button 5 517 + * (data[4] & 0x20) button 6 518 + * (data[4] & 0x40) button 7 (top wheel button) 519 + * (data[4] & 0x80) button 8 (bottom wheel button) 520 + */ 521 + ReportSize(1) 522 + ReportCount(8) 523 + UsagePage_Button 524 + UsageMinimum_i8(1) 525 + UsageMaximum_i8(8) 526 + Input(Var|Abs) 527 + /* data[5] top wheel (signed, positive clockwise) */ 528 + ReportSize(8) 529 + ReportCount(1) 530 + UsagePage_GenericDesktop 531 + Usage_GD_Wheel 532 + LogicalMinimum_i8(-1) 533 + LogicalMaximum_i8(1) 534 + Input(Var|Rel) 535 + /* data[6] bottom wheel (signed, positive clockwise) */ 536 + UsagePage_Consumer 537 + Usage_Con_ACPan 538 + Input(Var|Rel) 539 + ) 540 + /* 541 + * The kernel will drop reports that are bigger than the 542 + * largest report specified in the HID descriptor. 543 + * Therefore, our modified descriptor needs to have at least one 544 + * HID report that is as long as, or longer than, the largest 545 + * report in the original descriptor. 546 + * 547 + * This macro expands to a no-op report that is padded to the 548 + * provided length. 549 + */ 550 + FixedSizeVendorReport(VENDOR_REPORT_LENGTH) 551 + ) 552 + }; 553 + 554 + SEC(HID_BPF_RDESC_FIXUP) 555 + int BPF_PROG(hid_fix_rdesc_huion_kamvas16_gen3, struct hid_bpf_ctx *hid_ctx) 556 + { 557 + __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */); 558 + __s32 rdesc_size = hid_ctx->size; 559 + __u8 have_fw_id; 560 + 561 + if (!data) 562 + return 0; /* EPERM check */ 563 + 564 + have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID, 565 + EXPECTED_FIRMWARE_ID, 566 + sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0; 567 + 568 + if (have_fw_id) { 569 + /* 570 + * Tablet should be in vendor mode. 571 + * Disable the unused devices 572 + */ 573 + if (rdesc_size == TABLET_DESCRIPTOR_LENGTH) { 574 + __builtin_memcpy(data, disabled_rdesc_tablet, 575 + sizeof(disabled_rdesc_tablet)); 576 + return sizeof(disabled_rdesc_tablet); 577 + } 578 + 579 + if (rdesc_size == WHEEL_DESCRIPTOR_LENGTH) { 580 + __builtin_memcpy(data, disabled_rdesc_wheel, 581 + sizeof(disabled_rdesc_wheel)); 582 + return sizeof(disabled_rdesc_wheel); 583 + } 584 + } 585 + 586 + /* 587 + * Regardless of which mode the tablet is in, always fix the vendor 588 + * descriptor in case the udev property just happened to not be set 589 + */ 590 + if (rdesc_size == VENDOR_DESCRIPTOR_LENGTH) { 591 + __builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor)); 592 + return sizeof(fixed_rdesc_vendor); 593 + } 594 + 595 + return 0; 596 + } 597 + 598 + SEC(HID_BPF_DEVICE_EVENT) 599 + int BPF_PROG(hid_fix_event_huion_kamvas16_gen3, struct hid_bpf_ctx *hid_ctx) 600 + { 601 + __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, VENDOR_REPORT_LENGTH /* size */); 602 + 603 + if (!data) 604 + return 0; /* EPERM check */ 605 + 606 + /* Handle vendor reports only */ 607 + if (hid_ctx->size != VENDOR_REPORT_LENGTH) 608 + return 0; 609 + if (data[0] != VENDOR_REPORT_ID) 610 + return 0; 611 + 612 + __u8 report_subtype = (data[1] >> 4) & 0x0f; 613 + 614 + if (report_subtype == VENDOR_REPORT_SUBTYPE_PEN || 615 + report_subtype == VENDOR_REPORT_SUBTYPE_PEN_OUT) { 616 + /* Invert Y tilt */ 617 + data[11] = -data[11]; 618 + 619 + /* 620 + * Rearrange the bytes of the report so that 621 + * [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] 622 + * will be arranged as 623 + * [0, 1, 2, 3, 8, 4, 5, 6, 7, 9, 10, 11, 12, 13] 624 + */ 625 + __u8 x_24 = data[8]; 626 + 627 + data[8] = data[7]; 628 + data[7] = data[6]; 629 + data[6] = data[5]; 630 + data[5] = data[4]; 631 + 632 + data[4] = x_24; 633 + 634 + } else if (report_subtype == VENDOR_REPORT_SUBTYPE_BUTTONS || 635 + report_subtype == VENDOR_REPORT_SUBTYPE_WHEELS) { 636 + struct pad_report { 637 + __u8 report_id; 638 + __u8 btn_stylus:1; 639 + __u8 padding:7; 640 + __u8 x; 641 + __u8 y; 642 + __u8 buttons; 643 + __s8 top_wheel; 644 + __s8 bottom_wheel; 645 + } __attribute__((packed)) *pad_report; 646 + 647 + __s8 top_wheel = 0; 648 + __s8 bottom_wheel = 0; 649 + 650 + switch (report_subtype) { 651 + case VENDOR_REPORT_SUBTYPE_WHEELS: 652 + /* 653 + * The wheel direction byte is 1 for clockwise rotation 654 + * and 2 for counter-clockwise. 655 + * Change it to 1 and -1, respectively. 656 + */ 657 + switch (data[3]) { 658 + case 1: 659 + top_wheel = (data[5] == 1) ? 1 : -1; 660 + break; 661 + case 2: 662 + bottom_wheel = (data[5] == 1) ? 1 : -1; 663 + break; 664 + } 665 + break; 666 + 667 + case VENDOR_REPORT_SUBTYPE_BUTTONS: 668 + /* 669 + * If a button is already being held, ignore any new 670 + * button event unless it's a release. 671 + * 672 + * The tablet only cleanly handles one button being held 673 + * at a time, and trying to hold multiple buttons 674 + * (particularly wheel+pad buttons) can result in sequences 675 + * of reports that look like imaginary presses and releases. 676 + * 677 + * This is an imperfect way to filter out some of these 678 + * reports. 679 + */ 680 + if (last_button_state != 0x00 && data[4] != 0x00) 681 + break; 682 + 683 + last_button_state = data[4]; 684 + break; 685 + } 686 + 687 + pad_report = (struct pad_report *)data; 688 + 689 + pad_report->report_id = CUSTOM_PAD_REPORT_ID; 690 + pad_report->btn_stylus = 0; 691 + pad_report->x = 0; 692 + pad_report->y = 0; 693 + pad_report->buttons = last_button_state; 694 + pad_report->top_wheel = top_wheel; 695 + pad_report->bottom_wheel = bottom_wheel; 696 + 697 + return sizeof(struct pad_report); 698 + } 699 + 700 + return 0; 701 + } 702 + 703 + HID_BPF_OPS(huion_kamvas16_gen3) = { 704 + .hid_device_event = (void *)hid_fix_event_huion_kamvas16_gen3, 705 + .hid_rdesc_fixup = (void *)hid_fix_rdesc_huion_kamvas16_gen3, 706 + }; 707 + 708 + SEC("syscall") 709 + int probe(struct hid_bpf_probe_args *ctx) 710 + { 711 + switch (ctx->rdesc_size) { 712 + case VENDOR_DESCRIPTOR_LENGTH: 713 + case TABLET_DESCRIPTOR_LENGTH: 714 + case WHEEL_DESCRIPTOR_LENGTH: 715 + ctx->retval = 0; 716 + break; 717 + default: 718 + ctx->retval = -EINVAL; 719 + } 720 + 721 + return 0; 722 + } 723 + 724 + char _license[] SEC("license") = "GPL";
+86
drivers/hid/bpf/progs/Logitech__SpaceNavigator.bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright (c) 2025 Curran Muhlberger 3 + */ 4 + 5 + #include "vmlinux.h" 6 + #include "hid_bpf.h" 7 + #include "hid_bpf_helpers.h" 8 + #include <bpf/bpf_tracing.h> 9 + 10 + #define VID_LOGITECH 0x046D 11 + #define PID_SPACENAVIGATOR 0xC626 12 + 13 + HID_BPF_CONFIG( 14 + HID_DEVICE(BUS_USB, HID_GROUP_ANY, VID_LOGITECH, PID_SPACENAVIGATOR) 15 + ); 16 + 17 + /* 18 + * The 3Dconnexion SpaceNavigator 3D Mouse is a multi-axis controller with 6 19 + * axes (grouped as X,Y,Z and Rx,Ry,Rz). Axis data is absolute, but the report 20 + * descriptor erroneously declares it to be relative. We fix the report 21 + * descriptor to mark both axis collections as absolute. 22 + * 23 + * The kernel attempted to fix this in commit 24985cf68612 (HID: support 24 + * Logitech/3DConnexion SpaceTraveler and SpaceNavigator), but the descriptor 25 + * data offsets are incorrect for at least some SpaceNavigator units. 26 + */ 27 + 28 + SEC(HID_BPF_RDESC_FIXUP) 29 + int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx) 30 + { 31 + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */); 32 + 33 + if (!data) 34 + return 0; /* EPERM check */ 35 + 36 + /* Offset of Input item in X,Y,Z and Rx,Ry,Rz collections for all known 37 + * firmware variants. 38 + * - 2009 model: X,Y,Z @ 32-33, Rx,Ry,Rz @ 49-50 (fixup originally 39 + * applied in kernel) 40 + * - 2016 model (size==228): X,Y,Z @ 36-37, Rx,Ry,Rz @ 53-54 41 + * 42 + * The descriptor size of the 2009 model is not known, and there is evidence 43 + * for at least two other variants (with sizes 202 & 217) besides the 2016 44 + * model, so we try all known offsets regardless of descriptor size. 45 + */ 46 + const u8 offsets[] = {32, 36, 49, 53}; 47 + 48 + for (size_t idx = 0; idx < ARRAY_SIZE(offsets); idx++) { 49 + u8 offset = offsets[idx]; 50 + 51 + /* if Input (Data,Var,Rel) , make it Input (Data,Var,Abs) */ 52 + if (data[offset] == 0x81 && data[offset + 1] == 0x06) 53 + data[offset + 1] = 0x02; 54 + } 55 + 56 + return 0; 57 + } 58 + 59 + HID_BPF_OPS(logitech_spacenavigator) = { 60 + .hid_rdesc_fixup = (void *)hid_fix_rdesc, 61 + }; 62 + 63 + SEC("syscall") 64 + int probe(struct hid_bpf_probe_args *ctx) 65 + { 66 + /* Ensure report descriptor size matches one of the known variants. */ 67 + if (ctx->rdesc_size != 202 && 68 + ctx->rdesc_size != 217 && 69 + ctx->rdesc_size != 228) { 70 + ctx->retval = -EINVAL; 71 + return 0; 72 + } 73 + 74 + /* Check whether the kernel has already applied the fix. */ 75 + if ((ctx->rdesc[32] == 0x81 && ctx->rdesc[33] == 0x02 && 76 + ctx->rdesc[49] == 0x81 && ctx->rdesc[50] == 0x02) || 77 + (ctx->rdesc[36] == 0x81 && ctx->rdesc[37] == 0x02 && 78 + ctx->rdesc[53] == 0x81 && ctx->rdesc[54] == 0x02)) 79 + ctx->retval = -EINVAL; 80 + else 81 + ctx->retval = 0; 82 + 83 + return 0; 84 + } 85 + 86 + char _license[] SEC("license") = "GPL";
+321
drivers/hid/bpf/progs/WALTOP__Batteryless-Tablet.bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright (c) 2025 Red Hat 3 + */ 4 + 5 + #include "vmlinux.h" 6 + #include "hid_bpf.h" 7 + #include "hid_bpf_helpers.h" 8 + #include <bpf/bpf_tracing.h> 9 + 10 + #define VID_WALTOP 0x172F 11 + #define PID_BATTERYLESS_TABLET 0x0505 12 + 13 + HID_BPF_CONFIG( 14 + HID_DEVICE(BUS_USB, HID_GROUP_ANY, VID_WALTOP, PID_BATTERYLESS_TABLET) 15 + ); 16 + 17 + #define EXPECTED_RDESC_SIZE 335 18 + #define PEN_REPORT_ID 16 19 + 20 + #define TIP_SWITCH BIT(0) 21 + #define BARREL_SWITCH BIT(1) 22 + #define SECONDARY_BARREL_SWITCH BIT(5) 23 + 24 + static __u8 last_button_state; 25 + 26 + static const __u8 fixed_rdesc[] = { 27 + 0x05, 0x01, // Usage Page (Generic Desktop) 28 + 0x09, 0x02, // Usage (Mouse) 29 + 0xa1, 0x01, // Collection (Application) 30 + 0x85, 0x01, // Report ID (1) 31 + 0x09, 0x01, // Usage (Pointer) 32 + 0xa1, 0x00, // Collection (Physical) 33 + 0x05, 0x09, // Usage Page (Button) 34 + 0x19, 0x01, // Usage Minimum (1) 35 + 0x29, 0x05, // Usage Maximum (5) 36 + 0x15, 0x00, // Logical Minimum (0) 37 + 0x25, 0x01, // Logical Maximum (1) 38 + 0x75, 0x01, // Report Size (1) 39 + 0x95, 0x05, // Report Count (5) 40 + 0x81, 0x02, // Input (Data,Var,Abs) 41 + 0x75, 0x03, // Report Size (3) 42 + 0x95, 0x01, // Report Count (1) 43 + 0x81, 0x03, // Input (Cnst,Var,Abs) 44 + 0x05, 0x01, // Usage Page (Generic Desktop) 45 + 0x09, 0x30, // Usage (X) 46 + 0x09, 0x31, // Usage (Y) 47 + 0x09, 0x38, // Usage (Wheel) 48 + 0x15, 0x81, // Logical Minimum (-127) 49 + 0x25, 0x7f, // Logical Maximum (127) 50 + 0x75, 0x08, // Report Size (8) 51 + 0x95, 0x03, // Report Count (3) 52 + 0x81, 0x06, // Input (Data,Var,Rel) 53 + 0x05, 0x0c, // Usage Page (Consumer) 54 + 0x15, 0x81, // Logical Minimum (-127) 55 + 0x25, 0x7f, // Logical Maximum (127) 56 + 0x75, 0x08, // Report Size (8) 57 + 0x95, 0x01, // Report Count (1) 58 + 0x0a, 0x38, 0x02, // Usage (AC Pan) 59 + 0x81, 0x06, // Input (Data,Var,Rel) 60 + 0xc0, // End Collection 61 + 0xc0, // End Collection 62 + 0x05, 0x0d, // Usage Page (Digitizers) 63 + 0x09, 0x02, // Usage (Pen) 64 + 0xa1, 0x01, // Collection (Application) 65 + 0x85, 0x02, // Report ID (2) 66 + 0x09, 0x20, // Usage (Stylus) 67 + 0xa1, 0x00, // Collection (Physical) 68 + 0x09, 0x00, // Usage (0x0000) 69 + 0x15, 0x00, // Logical Minimum (0) 70 + 0x26, 0xff, 0x00, // Logical Maximum (255) 71 + 0x75, 0x08, // Report Size (8) 72 + 0x95, 0x09, // Report Count (9) 73 + 0x81, 0x02, // Input (Data,Var,Abs) 74 + 0x09, 0x3f, // Usage (Azimuth) 75 + 0x09, 0x40, // Usage (Altitude) 76 + 0x15, 0x00, // Logical Minimum (0) 77 + 0x26, 0xff, 0x00, // Logical Maximum (255) 78 + 0x75, 0x08, // Report Size (8) 79 + 0x95, 0x02, // Report Count (2) 80 + 0xb1, 0x02, // Feature (Data,Var,Abs) 81 + 0xc0, // End Collection 82 + 0x85, 0x05, // Report ID (5) 83 + 0x05, 0x0d, // Usage Page (Digitizers) 84 + 0x09, 0x20, // Usage (Stylus) 85 + 0xa1, 0x00, // Collection (Physical) 86 + 0x09, 0x00, // Usage (0x0000) 87 + 0x15, 0x00, // Logical Minimum (0) 88 + 0x26, 0xff, 0x00, // Logical Maximum (255) 89 + 0x75, 0x08, // Report Size (8) 90 + 0x95, 0x07, // Report Count (7) 91 + 0x81, 0x02, // Input (Data,Var,Abs) 92 + 0xc0, // End Collection 93 + 0x85, 0x0a, // Report ID (10) 94 + 0x05, 0x0d, // Usage Page (Digitizers) 95 + 0x09, 0x20, // Usage (Stylus) 96 + 0xa1, 0x00, // Collection (Physical) 97 + 0x09, 0x00, // Usage (0x0000) 98 + 0x15, 0x00, // Logical Minimum (0) 99 + 0x26, 0xff, 0x00, // Logical Maximum (255) 100 + 0x75, 0x08, // Report Size (8) 101 + 0x95, 0x07, // Report Count (7) 102 + 0x81, 0x02, // Input (Data,Var,Abs) 103 + 0xc0, // End Collection 104 + 0x85, 0x10, // Report ID (16) 105 + 0x09, 0x20, // Usage (Stylus) 106 + 0xa1, 0x00, // Collection (Physical) 107 + 0x09, 0x42, // Usage (Tip Switch) 108 + 0x09, 0x44, // Usage (Barrel Switch) 109 + 0x09, 0x3c, // Usage (Invert) 110 + 0x09, 0x45, // Usage (Eraser) 111 + 0x09, 0x32, // Usage (In Range) 112 + 0x09, 0x5a, // Usage (Secondary Barrel Switch) <-- added 113 + 0x15, 0x00, // Logical Minimum (0) 114 + 0x25, 0x01, // Logical Maximum (1) 115 + 0x75, 0x01, // Report Size (1) 116 + 0x95, 0x06, // Report Count (6) <--- changed from 5 117 + 0x81, 0x02, // Input (Data,Var,Abs) 118 + 0x95, 0x02, // Report Count (2) <--- changed from 3 119 + 0x81, 0x03, // Input (Cnst,Var,Abs) 120 + 0x05, 0x01, // Usage Page (Generic Desktop) 121 + 0x09, 0x30, // Usage (X) 122 + 0x75, 0x10, // Report Size (16) 123 + 0x95, 0x01, // Report Count (1) 124 + 0xa4, // Push 125 + 0x55, 0x0d, // Unit Exponent (-3) 126 + 0x65, 0x33, // Unit (EnglishLinear: in³) 127 + 0x15, 0x00, // Logical Minimum (0) 128 + 0x26, 0x00, 0x7d, // Logical Maximum (32000) 129 + 0x35, 0x00, // Physical Minimum (0) 130 + 0x46, 0x00, 0x7d, // Physical Maximum (32000) 131 + 0x81, 0x02, // Input (Data,Var,Abs) 132 + 0x09, 0x31, // Usage (Y) 133 + 0x15, 0x00, // Logical Minimum (0) 134 + 0x26, 0x20, 0x4e, // Logical Maximum (20000) 135 + 0x35, 0x00, // Physical Minimum (0) 136 + 0x46, 0x20, 0x4e, // Physical Maximum (20000) 137 + 0x81, 0x02, // Input (Data,Var,Abs) 138 + 0x05, 0x0d, // Usage Page (Digitizers) 139 + 0x09, 0x30, // Usage (Tip Pressure) 140 + 0x15, 0x00, // Logical Minimum (0) 141 + 0x26, 0xff, 0x07, // Logical Maximum (2047) 142 + 0x35, 0x00, // Physical Minimum (0) 143 + 0x46, 0xff, 0x07, // Physical Maximum (2047) 144 + 0x81, 0x02, // Input (Data,Var,Abs) 145 + 0x05, 0x0d, // Usage Page (Digitizers) 146 + 0x09, 0x3d, // Usage (X Tilt) 147 + 0x09, 0x3e, // Usage (Y Tilt) 148 + 0x15, 0xc4, // Logical Minimum (-60) <- changed from -127 149 + 0x25, 0x3c, // Logical Maximum (60) <- changed from 127 150 + 0x75, 0x08, // Report Size (8) 151 + 0x95, 0x02, // Report Count (2) 152 + 0x81, 0x02, // Input (Data,Var,Abs) 153 + 0xc0, // End Collection 154 + 0xc0, // End Collection 155 + 0x05, 0x01, // Usage Page (Generic Desktop) 156 + 0x09, 0x06, // Usage (Keyboard) 157 + 0xa1, 0x01, // Collection (Application) 158 + 0x85, 0x0d, // Report ID (13) 159 + 0x05, 0x07, // Usage Page (Keyboard/Keypad) 160 + 0x19, 0xe0, // Usage Minimum (224) 161 + 0x29, 0xe7, // Usage Maximum (231) 162 + 0x15, 0x00, // Logical Minimum (0) 163 + 0x25, 0x01, // Logical Maximum (1) 164 + 0x75, 0x01, // Report Size (1) 165 + 0x95, 0x08, // Report Count (8) 166 + 0x81, 0x02, // Input (Data,Var,Abs) 167 + 0x75, 0x08, // Report Size (8) 168 + 0x95, 0x01, // Report Count (1) 169 + 0x81, 0x01, // Input (Cnst,Arr,Abs) 170 + 0x05, 0x07, // Usage Page (Keyboard/Keypad) 171 + 0x19, 0x00, // Usage Minimum (0) 172 + 0x29, 0x65, // Usage Maximum (101) 173 + 0x15, 0x00, // Logical Minimum (0) 174 + 0x25, 0x65, // Logical Maximum (101) 175 + 0x75, 0x08, // Report Size (8) 176 + 0x95, 0x05, // Report Count (5) 177 + 0x81, 0x00, // Input (Data,Arr,Abs) 178 + 0xc0, // End Collection 179 + 0x05, 0x0c, // Usage Page (Consumer) 180 + 0x09, 0x01, // Usage (Consumer Control) 181 + 0xa1, 0x01, // Collection (Application) 182 + 0x85, 0x0c, // Report ID (12) 183 + 0x09, 0xe9, // Usage (Volume Increment) 184 + 0x09, 0xea, // Usage (Volume Decrement) 185 + 0x09, 0xe2, // Usage (Mute) 186 + 0x15, 0x00, // Logical Minimum (0) 187 + 0x25, 0x01, // Logical Maximum (1) 188 + 0x75, 0x01, // Report Size (1) 189 + 0x95, 0x03, // Report Count (3) 190 + 0x81, 0x06, // Input (Data,Var,Rel) 191 + 0x75, 0x05, // Report Size (5) 192 + 0x95, 0x01, // Report Count (1) 193 + 0x81, 0x07, // Input (Cnst,Var,Rel) 194 + 0xc0, // End Collection 195 + }; 196 + 197 + static inline unsigned int bitwidth32(__u32 x) 198 + { 199 + return 32 - __builtin_clzg(x, 32); 200 + } 201 + 202 + static inline unsigned int floor_log2_32(__u32 x) 203 + { 204 + return bitwidth32(x) - 1; 205 + } 206 + 207 + /* Maps the interval [0, 2047] to itself using a scaled 208 + * approximation of the function log2(x+1). 209 + */ 210 + static unsigned int scaled_log2(__u16 v) 211 + { 212 + const unsigned int XMAX = 2047; 213 + const unsigned int YMAX = 11; /* log2(2048) = 11 */ 214 + 215 + unsigned int x = v + 1; 216 + unsigned int n = floor_log2_32(x); 217 + unsigned int b = 1 << n; 218 + 219 + /* Fixed-point fraction in [0, 1), linearly 220 + * interpolated using delta-y = 1 and 221 + * delta-x = (2b - b) = b. 222 + */ 223 + unsigned int frac = (x - b) << YMAX; 224 + unsigned int lerp = frac / b; 225 + unsigned int log2 = (n << YMAX) + lerp; 226 + 227 + return ((log2 * XMAX) / YMAX) >> YMAX; 228 + } 229 + 230 + SEC(HID_BPF_RDESC_FIXUP) 231 + int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx) 232 + { 233 + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */); 234 + 235 + if (!data) 236 + return 0; /* EPERM check */ 237 + 238 + __builtin_memcpy(data, fixed_rdesc, sizeof(fixed_rdesc)); 239 + 240 + return sizeof(fixed_rdesc); 241 + } 242 + 243 + SEC(HID_BPF_DEVICE_EVENT) 244 + int BPF_PROG(waltop_fix_events, struct hid_bpf_ctx *hctx) 245 + { 246 + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */); 247 + 248 + if (!data) 249 + return 0; /* EPERM check */ 250 + 251 + __u8 report_id = data[0]; 252 + 253 + if (report_id != PEN_REPORT_ID) 254 + return 0; 255 + 256 + /* On this tablet if the secondary barrel switch is pressed, 257 + * the tablet sends tip down and barrel down. Change this to 258 + * just secondary barrel down when there is no ambiguity. 259 + * 260 + * It's possible that there is a bug in the firmware and the 261 + * device intends to set invert + eraser instead (i.e. the 262 + * pysical button is an eraser button) but since 263 + * the pressure is always zero, said eraser button 264 + * would be useless anyway. 265 + * 266 + * So let's just change the button to secondary barrel down. 267 + */ 268 + 269 + __u8 tip_switch = data[1] & TIP_SWITCH; 270 + __u8 barrel_switch = data[1] & BARREL_SWITCH; 271 + 272 + __u8 tip_held = last_button_state & TIP_SWITCH; 273 + __u8 barrel_held = last_button_state & BARREL_SWITCH; 274 + 275 + if (tip_switch && barrel_switch && !tip_held && !barrel_held) { 276 + data[1] &= ~(TIP_SWITCH | BARREL_SWITCH); /* release tip and barrel */ 277 + data[1] |= SECONDARY_BARREL_SWITCH; /* set secondary barrel switch */ 278 + } 279 + 280 + last_button_state = data[1]; 281 + 282 + /* The pressure sensor on this tablet maps around half of the 283 + * logical pressure range into the interval [0-100]. Further 284 + * pressure causes the sensor value to increase exponentially 285 + * up to a maximum value of 2047. 286 + * 287 + * The values 12 and 102 were chosen to have an integer slope 288 + * with smooth transition between the two curves around the 289 + * value 100. 290 + */ 291 + 292 + __u16 pressure = (((__u16)data[6]) << 0) | (((__u16)data[7]) << 8); 293 + 294 + if (pressure <= 102) 295 + pressure *= 12; 296 + else 297 + pressure = scaled_log2(pressure); 298 + 299 + data[6] = pressure >> 0; 300 + data[7] = pressure >> 8; 301 + 302 + return 0; 303 + } 304 + 305 + HID_BPF_OPS(waltop_batteryless) = { 306 + .hid_device_event = (void *)waltop_fix_events, 307 + .hid_rdesc_fixup = (void *)hid_fix_rdesc, 308 + }; 309 + 310 + SEC("syscall") 311 + int probe(struct hid_bpf_probe_args *ctx) 312 + { 313 + if (ctx->rdesc_size == EXPECTED_RDESC_SIZE) 314 + ctx->retval = 0; 315 + else 316 + ctx->retval = -EINVAL; 317 + 318 + return 0; 319 + } 320 + 321 + char _license[] SEC("license") = "GPL";
+305
drivers/hid/bpf/progs/XPPen__Deco01V3.bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright (c) 2025 Red Hat 3 + */ 4 + 5 + #include "vmlinux.h" 6 + #include "hid_bpf.h" 7 + #include "hid_bpf_helpers.h" 8 + #include "hid_report_helpers.h" 9 + #include <bpf/bpf_tracing.h> 10 + 11 + #define VID_UGEE 0x28BD /* VID is shared with SinoWealth and Glorious and prob others */ 12 + #define PID_DECO_01_V3 0x0947 13 + 14 + HID_BPF_CONFIG( 15 + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_DECO_01_V3), 16 + ); 17 + 18 + /* 19 + * Default report descriptor reports: 20 + * - a report descriptor for the pad buttons, reported as key sequences 21 + * - a report descriptor for the pen 22 + * - a vendor-specific report descriptor 23 + * 24 + * The Pad report descriptor, see 25 + * https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/issues/54 26 + * 27 + * # Report descriptor length: 102 bytes 28 + * 0x05, 0x01, // Usage Page (Generic Desktop) 0 29 + * 0x09, 0x02, // Usage (Mouse) 2 30 + * 0xa1, 0x01, // Collection (Application) 4 31 + * 0x85, 0x09, // Report ID (9) 6 32 + * 0x09, 0x01, // Usage (Pointer) 8 33 + * 0xa1, 0x00, // Collection (Physical) 10 34 + * 0x05, 0x09, // Usage Page (Button) 12 35 + * 0x19, 0x01, // UsageMinimum (1) 14 36 + * 0x29, 0x03, // UsageMaximum (3) 16 37 + * 0x15, 0x00, // Logical Minimum (0) 18 38 + * 0x25, 0x01, // Logical Maximum (1) 20 39 + * 0x95, 0x03, // Report Count (3) 22 40 + * 0x75, 0x01, // Report Size (1) 24 41 + * 0x81, 0x02, // Input (Data,Var,Abs) 26 42 + * 0x95, 0x05, // Report Count (5) 28 43 + * 0x81, 0x01, // Input (Cnst,Arr,Abs) 30 44 + * 0x05, 0x01, // Usage Page (Generic Desktop) 32 45 + * 0x09, 0x30, // Usage (X) 34 46 + * 0x09, 0x31, // Usage (Y) 36 47 + * 0x26, 0xff, 0x7f, // Logical Maximum (32767) 38 48 + * 0x95, 0x02, // Report Count (2) 41 49 + * 0x75, 0x10, // Report Size (16) 43 50 + * 0x81, 0x02, // Input (Data,Var,Abs) 45 51 + * 0x05, 0x0d, // Usage Page (Digitizers) 47 52 + * 0x09, 0x30, // Usage (Tip Pressure) 49 53 + * 0x26, 0xff, 0x07, // Logical Maximum (2047) 51 54 + * 0x95, 0x01, // Report Count (1) 54 55 + * 0x75, 0x10, // Report Size (16) 56 56 + * 0x81, 0x02, // Input (Data,Var,Abs) 58 57 + * 0xc0, // End Collection 60 58 + * 0xc0, // End Collection 61 59 + * 0x05, 0x01, // Usage Page (Generic Desktop) 62 60 + * 0x09, 0x06, // Usage (Keyboard) 64 61 + * 0xa1, 0x01, // Collection (Application) 66 62 + * 0x85, 0x06, // Report ID (6) 68 63 + * 0x05, 0x07, // Usage Page (Keyboard/Keypad) 70 64 + * 0x19, 0xe0, // UsageMinimum (224) 72 65 + * 0x29, 0xe7, // UsageMaximum (231) 74 66 + * 0x15, 0x00, // Logical Minimum (0) 76 67 + * 0x25, 0x01, // Logical Maximum (1) 78 68 + * 0x75, 0x01, // Report Size (1) 80 69 + * 0x95, 0x08, // Report Count (8) 82 70 + * 0x81, 0x02, // Input (Data,Var,Abs) 84 71 + * 0x05, 0x07, // Usage Page (Keyboard/Keypad) 86 72 + * 0x19, 0x00, // UsageMinimum (0) 88 73 + * 0x29, 0xff, // UsageMaximum (255) 90 74 + * 0x26, 0xff, 0x00, // Logical Maximum (255) 92 75 + * 0x75, 0x08, // Report Size (8) 95 76 + * 0x95, 0x06, // Report Count (6) 97 77 + * 0x81, 0x00, // Input (Data,Arr,Abs) 99 78 + * 0xc0, // End Collection 101 79 + * 80 + * And key events for buttons top->bottom are: 81 + * Buttons released: 06 00 00 00 00 00 00 00 82 + * Button1: 06 00 05 00 00 00 00 00 -> b 83 + * Button2: 06 00 08 00 00 00 00 00 -> e 84 + * Button3: 06 04 00 00 00 00 00 00 -> LAlt 85 + * Button4: 06 00 2c 00 00 00 00 00 -> Space 86 + * Button5: 06 01 16 00 00 00 00 00 -> LControl + s 87 + * Button6: 06 01 1d 00 00 00 00 00 -> LControl + z 88 + * Button7: 06 01 57 00 00 00 00 00 -> LControl + Keypad Plus 89 + * Button8: 06 01 56 00 00 00 00 00 -> LControl + Keypad Dash 90 + * 91 + * When multiple buttons are pressed at the same time, the values used to 92 + * identify the buttons are identical, but they appear in different bytes of the 93 + * record. For example, when button 2 (0x08) and button 1 (0x05) are pressed, 94 + * this is the report: 95 + * 96 + * Buttons 2 and 1: 06 00 08 05 00 00 00 00 -> e + b 97 + * 98 + * Buttons 1, 2, 4, 5 and 6 can be matched by finding their values in the 99 + * report. 100 + * 101 + * Button 3 is pressed when the 3rd bit is 1. For example, pressing buttons 3 102 + * and 5 generates this report: 103 + * 104 + * Buttons 3 and 5: 06 05 16 00 00 00 00 00 -> LControl + LAlt + s 105 + * -- -- 106 + * | | 107 + * | `- Button 5 (0x16) 108 + * `- 0x05 = 0101. Button 3 is pressed 109 + * ^ 110 + * 111 + * pad_buttons contains a list of buttons that can be matched in 112 + * HID_BPF_DEVICE_EVENT. Button 3 as it has a dedicated bit. 113 + * 114 + * 115 + * The Pen report descriptor announces a wrong tilt range: 116 + * 117 + * Report descriptor length: 109 bytes 118 + * 0x05, 0x0d, // Usage Page (Digitizers) 0 119 + * 0x09, 0x02, // Usage (Pen) 2 120 + * 0xa1, 0x01, // Collection (Application) 4 121 + * 0x85, 0x07, // Report ID (7) 6 122 + * 0x09, 0x20, // Usage (Stylus) 8 123 + * 0xa1, 0x01, // Collection (Application) 10 124 + * 0x09, 0x42, // Usage (Tip Switch) 12 125 + * 0x09, 0x44, // Usage (Barrel Switch) 14 126 + * 0x09, 0x45, // Usage (Eraser) 16 127 + * 0x09, 0x3c, // Usage (Invert) 18 128 + * 0x15, 0x00, // Logical Minimum (0) 20 129 + * 0x25, 0x01, // Logical Maximum (1) 22 130 + * 0x75, 0x01, // Report Size (1) 24 131 + * 0x95, 0x04, // Report Count (4) 26 132 + * 0x81, 0x02, // Input (Data,Var,Abs) 28 133 + * 0x95, 0x01, // Report Count (1) 30 134 + * 0x81, 0x03, // Input (Cnst,Var,Abs) 32 135 + * 0x09, 0x32, // Usage (In Range) 34 136 + * 0x95, 0x01, // Report Count (1) 36 137 + * 0x81, 0x02, // Input (Data,Var,Abs) 38 138 + * 0x95, 0x02, // Report Count (2) 40 139 + * 0x81, 0x03, // Input (Cnst,Var,Abs) 42 140 + * 0x75, 0x10, // Report Size (16) 44 141 + * 0x95, 0x01, // Report Count (1) 46 142 + * 0x35, 0x00, // Physical Minimum (0) 48 143 + * 0xa4, // Push 50 144 + * 0x05, 0x01, // Usage Page (Generic Desktop) 51 145 + * 0x09, 0x30, // Usage (X) 53 146 + * 0x65, 0x13, // Unit (EnglishLinear: in) 55 147 + * 0x55, 0x0d, // Unit Exponent (-3) 57 148 + * 0x46, 0x10, 0x27, // Physical Maximum (10000) 59 149 + * 0x26, 0xff, 0x7f, // Logical Maximum (32767) 62 150 + * 0x81, 0x02, // Input (Data,Var,Abs) 65 151 + * 0x09, 0x31, // Usage (Y) 67 152 + * 0x46, 0x6a, 0x18, // Physical Maximum (6250) 69 153 + * 0x26, 0xff, 0x7f, // Logical Maximum (32767) 72 154 + * 0x81, 0x02, // Input (Data,Var,Abs) 75 155 + * 0xb4, // Pop 77 156 + * 0x09, 0x30, // Usage (X) 78 157 + * 0x45, 0x00, // Physical Maximum (0) 80 158 + * 0x26, 0xff, 0x3f, // Logical Maximum (16383) 82 159 + * 0x81, 0x42, // Input (Data,Var,Abs,Null) 85 160 + * 0x09, 0x3d, // Usage (Start) 87 161 + * 0x15, 0x81, // Logical Minimum (-127) 89 <- Change from -127 to -60 162 + * 0x25, 0x7f, // Logical Maximum (127) 91 <- Change from 127 to 60 163 + * 0x75, 0x08, // Report Size (8) 93 164 + * 0x95, 0x01, // Report Count (1) 95 165 + * 0x81, 0x02, // Input (Data,Var,Abs) 97 166 + * 0x09, 0x3e, // Usage (Select) 99 167 + * 0x15, 0x81, // Logical Minimum (-127) 101 <- Change from -127 to -60 168 + * 0x25, 0x7f, // Logical Maximum (127) 103 <- Change from 127 to 60 169 + * 0x81, 0x02, // Input (Data,Var,Abs) 105 170 + * 0xc0, // End Collection 107 171 + * 0xc0, // End Collection 108 172 + */ 173 + 174 + #define PEN_REPORT_DESCRIPTOR_LENGTH 109 175 + #define PAD_REPORT_DESCRIPTOR_LENGTH 102 176 + #define PAD_REPORT_LENGTH 8 177 + #define PAD_REPORT_ID 6 178 + #define PAD_NUM_BUTTONS 8 179 + 180 + static const __u8 fixed_rdesc_pad[] = { 181 + UsagePage_GenericDesktop 182 + Usage_GD_Keypad 183 + CollectionApplication( 184 + // Byte 0 in report is the report ID 185 + ReportId(PAD_REPORT_ID) 186 + ReportCount(1) 187 + ReportSize(8) 188 + UsagePage_Digitizers 189 + Usage_Dig_TabletFunctionKeys 190 + CollectionPhysical( 191 + // Byte 1 is the button state 192 + UsagePage_Button 193 + UsageMinimum_i8(0x01) 194 + UsageMaximum_i8(PAD_NUM_BUTTONS) 195 + LogicalMinimum_i8(0x0) 196 + LogicalMaximum_i8(0x1) 197 + ReportCount(PAD_NUM_BUTTONS) 198 + ReportSize(1) 199 + Input(Var|Abs) 200 + // Byte 2 in report - just exists so we get to be a tablet pad 201 + UsagePage_Digitizers 202 + Usage_Dig_BarrelSwitch // BTN_STYLUS 203 + ReportCount(1) 204 + ReportSize(1) 205 + Input(Var|Abs) 206 + ReportCount(7) // padding 207 + Input(Const) 208 + // Bytes 3/4 in report - just exists so we get to be a tablet pad 209 + UsagePage_GenericDesktop 210 + Usage_GD_X 211 + Usage_GD_Y 212 + ReportCount(2) 213 + ReportSize(8) 214 + Input(Var|Abs) 215 + // Byte 5-7 are padding so we match the original report lengtth 216 + ReportCount(3) 217 + ReportSize(8) 218 + Input(Const) 219 + ) 220 + ) 221 + }; 222 + 223 + SEC(HID_BPF_RDESC_FIXUP) 224 + int BPF_PROG(xppen_deco01v3_rdesc_fixup, struct hid_bpf_ctx *hctx) 225 + { 226 + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */); 227 + 228 + const __u8 wrong_logical_range[] = {0x15, 0x81, 0x25, 0x7f}; 229 + const __u8 correct_logical_range[] = {0x15, 0xc4, 0x25, 0x3c}; 230 + 231 + if (!data) 232 + return 0; /* EPERM check */ 233 + 234 + switch (hctx->size) { 235 + case PAD_REPORT_DESCRIPTOR_LENGTH: 236 + __builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad)); 237 + return sizeof(fixed_rdesc_pad); 238 + case PEN_REPORT_DESCRIPTOR_LENGTH: 239 + if (__builtin_memcmp(&data[89], wrong_logical_range, 240 + sizeof(wrong_logical_range)) == 0) 241 + __builtin_memcpy(&data[89], correct_logical_range, 242 + sizeof(correct_logical_range)); 243 + if (__builtin_memcmp(&data[101], wrong_logical_range, 244 + sizeof(wrong_logical_range)) == 0) 245 + __builtin_memcpy(&data[101], correct_logical_range, 246 + sizeof(correct_logical_range)); 247 + break; 248 + } 249 + 250 + return 0; 251 + } 252 + 253 + SEC(HID_BPF_DEVICE_EVENT) 254 + int BPF_PROG(xppen_deco01v3_device_event, struct hid_bpf_ctx *hctx) 255 + { 256 + static const __u8 pad_buttons[] = { 0x05, 0x08, 0x00, 0x2c, 0x16, 0x1d, 0x57, 0x56 }; 257 + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, PAD_REPORT_LENGTH /* size */); 258 + 259 + if (!data) 260 + return 0; /* EPERM check */ 261 + 262 + if (data[0] == PAD_REPORT_ID) { 263 + __u8 button_mask = 0; 264 + size_t d, b; 265 + 266 + /* data[1] stores the status of BTN_2 in the 3rd bit*/ 267 + if (data[1] & BIT(2)) 268 + button_mask |= BIT(2); 269 + 270 + /* The rest of the descriptor stores the buttons as in pad_buttons */ 271 + for (d = 2; d < 8; d++) { 272 + for (b = 0; b < sizeof(pad_buttons); b++) { 273 + if (data[d] != 0 && data[d] == pad_buttons[b]) 274 + button_mask |= BIT(b); 275 + } 276 + } 277 + 278 + __u8 report[8] = {PAD_REPORT_ID, button_mask, 0x00}; 279 + 280 + __builtin_memcpy(data, report, sizeof(report)); 281 + } 282 + return 0; 283 + } 284 + 285 + HID_BPF_OPS(xppen_deco01v3) = { 286 + .hid_rdesc_fixup = (void *)xppen_deco01v3_rdesc_fixup, 287 + .hid_device_event = (void *)xppen_deco01v3_device_event, 288 + }; 289 + 290 + SEC("syscall") 291 + int probe(struct hid_bpf_probe_args *ctx) 292 + { 293 + switch (ctx->rdesc_size) { 294 + case PAD_REPORT_DESCRIPTOR_LENGTH: 295 + case PEN_REPORT_DESCRIPTOR_LENGTH: 296 + ctx->retval = 0; 297 + break; 298 + default: 299 + ctx->retval = -EINVAL; 300 + } 301 + 302 + return 0; 303 + } 304 + 305 + char _license[] SEC("license") = "GPL";
+359
drivers/hid/bpf/progs/XPPen__Deco02.bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include "vmlinux.h" 4 + #include "hid_bpf.h" 5 + #include "hid_bpf_helpers.h" 6 + #include "hid_report_helpers.h" 7 + #include <bpf/bpf_tracing.h> 8 + 9 + #define VID_UGEE 0x28BD 10 + #define PID_DECO_02 0x0803 11 + 12 + HID_BPF_CONFIG( 13 + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_DECO_02), 14 + ); 15 + 16 + /* 17 + * Devices are: 18 + * - Pad input, including pen (This is the only one we are interested in) 19 + * - Pen input as mouse 20 + * - Vendor 21 + * 22 + * Descriptors on main device are: 23 + * - 7: Pen 24 + * - 6: Vendor settings? Unclear 25 + * - 3: Keyboard (This is what we want to modify) 26 + * - 5: Feature report 27 + * 28 + * This creates three event nodes: 29 + * - XP-PEN DECO 02 Stylus 30 + * - XP-PEN DECO 02 31 + * - XP-PEN DECO 02 Keyboard (Again, what we want to modify) 32 + * 33 + * # Report descriptor length: 188 bytes 34 + * # 0x05, 0x0d, // Usage Page (Digitizers) 0 35 + * # 0x09, 0x02, // Usage (Pen) 2 36 + * # 0xa1, 0x01, // Collection (Application) 4 37 + * # 0x85, 0x07, // Report ID (7) 6 38 + * # 0x09, 0x20, // Usage (Stylus) 8 39 + * # 0xa1, 0x00, // Collection (Physical) 10 40 + * # 0x09, 0x42, // Usage (Tip Switch) 12 41 + * # 0x09, 0x44, // Usage (Barrel Switch) 14 42 + * # 0x09, 0x45, // Usage (Eraser) 16 43 + * # 0x09, 0x3c, // Usage (Invert) 18 44 + * # 0x09, 0x32, // Usage (In Range) 20 45 + * # 0x15, 0x00, // Logical Minimum (0) 22 46 + * # 0x25, 0x01, // Logical Maximum (1) 24 47 + * # 0x75, 0x01, // Report Size (1) 26 48 + * # 0x95, 0x05, // Report Count (5) 28 49 + * # 0x81, 0x02, // Input (Data,Var,Abs) 30 50 + * # 0x95, 0x03, // Report Count (3) 32 51 + * # 0x81, 0x03, // Input (Cnst,Var,Abs) 34 52 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 36 53 + * # 0x09, 0x30, // Usage (X) 38 54 + * # 0x15, 0x00, // Logical Minimum (0) 40 55 + * # 0x26, 0x50, 0x57, // Logical Maximum (22352) 42 56 + * # 0x55, 0x0d, // Unit Exponent (-3) 45 57 + * # 0x65, 0x13, // Unit (EnglishLinear: in) 47 58 + * # 0x35, 0x00, // Physical Minimum (0) 49 59 + * # 0x46, 0x50, 0x57, // Physical Maximum (22352) 51 60 + * # 0x75, 0x10, // Report Size (16) 54 61 + * # 0x95, 0x01, // Report Count (1) 56 62 + * # 0x81, 0x02, // Input (Data,Var,Abs) 58 63 + * # 0x09, 0x31, // Usage (Y) 60 64 + * # 0x15, 0x00, // Logical Minimum (0) 62 65 + * # 0x26, 0x92, 0x36, // Logical Maximum (13970) 64 66 + * # 0x55, 0x0d, // Unit Exponent (-3) 67 67 + * # 0x65, 0x13, // Unit (EnglishLinear: in) 69 68 + * # 0x35, 0x00, // Physical Minimum (0) 71 69 + * # 0x46, 0x92, 0x36, // Physical Maximum (13970) 73 70 + * # 0x75, 0x10, // Report Size (16) 76 71 + * # 0x95, 0x01, // Report Count (1) 78 72 + * # 0x81, 0x02, // Input (Data,Var,Abs) 80 73 + * # 0x05, 0x0d, // Usage Page (Digitizers) 82 74 + * # 0x09, 0x30, // Usage (Tip Pressure) 84 75 + * # 0x15, 0x00, // Logical Minimum (0) 86 76 + * # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 88 77 + * # 0x75, 0x10, // Report Size (16) 91 78 + * # 0x95, 0x01, // Report Count (1) 93 79 + * # 0x81, 0x02, // Input (Data,Var,Abs) 95 80 + * # 0xc0, // End Collection 97 81 + * # 0xc0, // End Collection 98 82 + * # 0x09, 0x0e, // Usage (Device Configuration) 99 83 + * # 0xa1, 0x01, // Collection (Application) 101 84 + * # 0x85, 0x05, // Report ID (5) 103 85 + * # 0x09, 0x23, // Usage (Device Settings) 105 86 + * # 0xa1, 0x02, // Collection (Logical) 107 87 + * # 0x09, 0x52, // Usage (Inputmode) 109 88 + * # 0x09, 0x53, // Usage (Device Index) 111 89 + * # 0x25, 0x0a, // Logical Maximum (10) 113 90 + * # 0x75, 0x08, // Report Size (8) 115 91 + * # 0x95, 0x02, // Report Count (2) 117 92 + * # 0xb1, 0x02, // Feature (Data,Var,Abs) 119 93 + * # 0xc0, // End Collection 121 94 + * # 0xc0, // End Collection 122 95 + * # 0x05, 0x0c, // Usage Page (Consumer Devices) 123 96 + * # 0x09, 0x36, // Usage (Function Buttons) 125 97 + * # 0xa1, 0x00, // Collection (Physical) 127 98 + * # 0x85, 0x06, // Report ID (6) 129 99 + * # 0x05, 0x09, // Usage Page (Button) 131 100 + * # 0x19, 0x01, // Usage Minimum (1) 133 101 + * # 0x29, 0x20, // Usage Maximum (32) 135 102 + * # 0x15, 0x00, // Logical Minimum (0) 137 103 + * # 0x25, 0x01, // Logical Maximum (1) 139 104 + * # 0x95, 0x20, // Report Count (32) 141 105 + * # 0x75, 0x01, // Report Size (1) 143 106 + * # 0x81, 0x02, // Input (Data,Var,Abs) 145 107 + * # 0xc0, // End Collection 147 108 + * # 0x05, 0x01, // Usage Page (Generic Desktop) 148 109 + * # 0x09, 0x06, // Usage (Keyboard) 150 110 + * # 0xa1, 0x01, // Collection (Application) 152 111 + * # 0x85, 0x03, // Report ID (3) 154 112 + * # 0x05, 0x07, // Usage Page (Keyboard) 156 113 + * # 0x19, 0xe0, // Usage Minimum (224) 158 114 + * # 0x29, 0xe7, // Usage Maximum (231) 160 115 + * # 0x15, 0x00, // Logical Minimum (0) 162 116 + * # 0x25, 0x01, // Logical Maximum (1) 164 117 + * # 0x75, 0x01, // Report Size (1) 166 118 + * # 0x95, 0x08, // Report Count (8) 168 119 + * # 0x81, 0x02, // Input (Data,Var,Abs) 170 120 + * # 0x05, 0x07, // Usage Page (Keyboard) 172 121 + * # 0x19, 0x00, // Usage Minimum (0) 174 122 + * # 0x29, 0xff, // Usage Maximum (255) 176 123 + * # 0x26, 0xff, 0x00, // Logical Maximum (255) 178 124 + * # 0x75, 0x08, // Report Size (8) 181 125 + * # 0x95, 0x06, // Report Count (6) 183 126 + * # 0x81, 0x00, // Input (Data,Arr,Abs) 185 127 + * # 0xc0, // End Collection 187 128 + * 129 + * Key events; top to bottom: 130 + * Buttons released: 03 00 00 00 00 00 00 00 131 + * Button1: 03 00 05 00 00 00 00 00 -> 'b and B' 132 + * Button2: 03 00 2c 00 00 00 00 00 -> 'Spacebar' 133 + * Button3: 03 00 08 00 00 00 00 00 -> 'e and E' 134 + * Button4: 03 00 0c 00 00 00 00 00 -> 'i and I' 135 + * Button5: 03 05 1d 00 00 00 00 00 -> LeftControl + LeftAlt + 'z and Z' 136 + * Button6: 03 01 16 00 00 00 00 00 -> LeftControl + 's and S' 137 + * 138 + * Dial Events: 139 + * Clockwise: 03 01 2e 00 00 00 00 00 -> LeftControl + '= and +' 140 + * Anticlockwise: 03 01 2d 00 00 00 00 00 -> LeftControl + '- and (underscore)' 141 + * 142 + * NOTE: Input event descriptions begin at byte 2, and progressively build 143 + * towards byte 7 as each new key is pressed maintaining the press order. 144 + * For example: 145 + * BTN1 followed by BTN2 is 03 00 05 2c 00 00 00 00 146 + * BTN2 followed by BTN1 is 03 00 2c 05 00 00 00 00 147 + * 148 + * Releasing a button causes its byte to be freed, and the next item in the list 149 + * is pushed forwards. Dial events are released immediately after an event is 150 + * registered (i.e. after each "click"), so will continually appear pushed 151 + * backwards in the report. 152 + * 153 + * When a button with a modifier key is pressed, the button identifier stacks in 154 + * an abnormal way, where the highest modifier byte always supersedes others. 155 + * In these cases, the button with the higher modifier is always last. 156 + * For example: 157 + * BTN6 followed by BTN5 is 03 05 1d 16 00 00 00 00 158 + * BTN5 followed by BTN6 is 03 05 1d 16 00 00 00 00 159 + * BTN5 followed by BTN1 is 03 05 05 1d 00 00 00 00 160 + * 161 + * For three button presses in order, demonstrating strictly above rules: 162 + * BTN6, BTN1, BTN5 is 03 05 05 1d 16 00 00 00 163 + * BTN5, BTN1, BTN6 is 03 05 05 1d 16 00 00 00 164 + * 165 + * In short, when BTN5/6 are pressed, the order of operations is lost, as they 166 + * will always float to the end when pressed in combination with others. 167 + * 168 + * Fortunately, all states are recorded in the same way, with no overlaps. 169 + * Byte 1 can be used as a spare for the wheel, since this is for mod keys. 170 + */ 171 + 172 + #define RDESC_SIZE_PAD 188 173 + #define REPORT_SIZE_PAD 8 174 + #define REPORT_ID_BUTTONS 3 175 + #define PAD_BUTTON_COUNT 6 176 + #define RDESC_KEYBOARD_OFFSET 148 177 + 178 + static const __u8 fixed_rdesc_pad[] = { 179 + /* Copy of pen descriptor to avoid losing functionality */ 180 + UsagePage_Digitizers 181 + Usage_Dig_Pen 182 + CollectionApplication( 183 + ReportId(7) 184 + Usage_Dig_Stylus 185 + CollectionPhysical( 186 + Usage_Dig_TipSwitch 187 + Usage_Dig_BarrelSwitch 188 + Usage_Dig_Eraser 189 + Usage_Dig_Invert 190 + Usage_Dig_InRange 191 + LogicalMinimum_i8(0) 192 + LogicalMaximum_i8(1) 193 + ReportSize(1) 194 + ReportCount(5) 195 + Input(Var|Abs) 196 + ReportCount(3) 197 + Input(Const) /* Input (Const, Var, Abs) */ 198 + UsagePage_GenericDesktop 199 + Usage_GD_X 200 + LogicalMinimum_i16(0) 201 + LogicalMaximum_i16(22352) 202 + UnitExponent(-3) 203 + Unit(in) /* (EnglishLinear: in) */ 204 + PhysicalMinimum_i16(0) 205 + PhysicalMaximum_i16(22352) 206 + ReportSize(16) 207 + ReportCount(1) 208 + Input(Var|Abs) 209 + Usage_GD_Y 210 + LogicalMinimum_i16(0) 211 + LogicalMaximum_i16(13970) 212 + UnitExponent(-3) 213 + Unit(in) /* (EnglishLinear: in) */ 214 + PhysicalMinimum_i16(0) 215 + PhysicalMaximum_i16(13970) 216 + ReportSize(16) 217 + ReportCount(1) 218 + Input(Var|Abs) 219 + UsagePage_Digitizers 220 + Usage_Dig_TipPressure 221 + LogicalMinimum_i16(0) 222 + LogicalMaximum_i16(8191) 223 + ReportSize(16) 224 + ReportCount(1) 225 + Input(Var|Abs) 226 + ) 227 + ) 228 + 229 + /* FIXES BEGIN */ 230 + UsagePage_GenericDesktop 231 + Usage_GD_Keypad 232 + CollectionApplication( 233 + ReportId(REPORT_ID_BUTTONS) /* Retain original ID on byte 0 */ 234 + ReportCount(1) 235 + ReportSize(REPORT_SIZE_PAD) 236 + UsagePage_Digitizers 237 + Usage_Dig_TabletFunctionKeys 238 + CollectionPhysical( 239 + /* Byte 1: Dial state */ 240 + UsagePage_GenericDesktop 241 + Usage_GD_Dial 242 + LogicalMinimum_i8(-1) 243 + LogicalMaximum_i8(1) 244 + ReportCount(1) 245 + ReportSize(REPORT_SIZE_PAD) 246 + Input(Var|Rel) 247 + /* Byte 2: Button state */ 248 + UsagePage_Button 249 + ReportSize(1) 250 + ReportCount(PAD_BUTTON_COUNT) 251 + UsageMinimum_i8(0x01) 252 + UsageMaximum_i8(PAD_BUTTON_COUNT) /* Number of buttons */ 253 + LogicalMinimum_i8(0x0) 254 + LogicalMaximum_i8(0x1) 255 + Input(Var|Abs) 256 + /* Byte 3: Exists to be tablet pad */ 257 + UsagePage_Digitizers 258 + Usage_Dig_BarrelSwitch 259 + ReportCount(1) 260 + ReportSize(1) 261 + Input(Var|Abs) 262 + ReportCount(7) /* Padding, to fill full report space */ 263 + Input(Const) 264 + /* Byte 4/5: Exists to be a tablet pad */ 265 + UsagePage_GenericDesktop 266 + Usage_GD_X 267 + Usage_GD_Y 268 + ReportCount(2) 269 + ReportSize(8) 270 + Input(Var|Abs) 271 + /* Bytes 6/7: Padding, to match original length */ 272 + ReportCount(2) 273 + ReportSize(8) 274 + Input(Const) 275 + ) 276 + FixedSizeVendorReport(RDESC_SIZE_PAD) 277 + ) 278 + }; 279 + 280 + SEC(HID_BPF_RDESC_FIXUP) 281 + int BPF_PROG(xppen_deco02_rdesc_fixup, struct hid_bpf_ctx *hctx) 282 + { 283 + __u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE); 284 + 285 + if (!data) 286 + return 0; /* EPERM Check */ 287 + 288 + if (hctx->size == RDESC_SIZE_PAD) { 289 + __builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad)); 290 + return sizeof(fixed_rdesc_pad); 291 + } 292 + 293 + return 0; 294 + } 295 + 296 + SEC(HID_BPF_DEVICE_EVENT) 297 + int BPF_PROG(xppen_deco02_device_event, struct hid_bpf_ctx *hctx) 298 + { 299 + __u8 *data = hid_bpf_get_data(hctx, 0, REPORT_SIZE_PAD); 300 + 301 + if (!data || data[0] != REPORT_ID_BUTTONS) 302 + return 0; /* EPERM or wrong report */ 303 + 304 + __u8 dial_code = 0; 305 + __u8 button_mask = 0; 306 + size_t d; 307 + 308 + /* Start from 2; 0 is report ID, 1 is modifier keys, replaced by dial */ 309 + for (d = 2; d < 8; d++) { 310 + switch (data[d]) { 311 + case 0x2e: 312 + dial_code = 1; 313 + break; 314 + case 0x2d: 315 + dial_code = -1; 316 + break; 317 + /* below are buttons, top to bottom */ 318 + case 0x05: 319 + button_mask |= BIT(0); 320 + break; 321 + case 0x2c: 322 + button_mask |= BIT(1); 323 + break; 324 + case 0x08: 325 + button_mask |= BIT(2); 326 + break; 327 + case 0x0c: 328 + button_mask |= BIT(3); 329 + break; 330 + case 0x1d: 331 + button_mask |= BIT(4); 332 + break; 333 + case 0x16: 334 + button_mask |= BIT(05); 335 + break; 336 + default: 337 + break; 338 + } 339 + } 340 + 341 + __u8 report[8] = { REPORT_ID_BUTTONS, dial_code, button_mask, 0x00 }; 342 + 343 + __builtin_memcpy(data, report, sizeof(report)); 344 + return 0; 345 + } 346 + 347 + HID_BPF_OPS(xppen_deco02) = { 348 + .hid_rdesc_fixup = (void *)xppen_deco02_rdesc_fixup, 349 + .hid_device_event = (void *)xppen_deco02_device_event, 350 + }; 351 + 352 + SEC("syscall") 353 + int probe(struct hid_bpf_probe_args *ctx) 354 + { 355 + ctx->retval = ctx->rdesc_size != RDESC_SIZE_PAD ? -EINVAL : 0; 356 + return 0; 357 + } 358 + 359 + char _license[] SEC("license") = "GPL";
+7 -3
drivers/hid/bpf/progs/hid_report_helpers.h
··· 143 143 * report with Report ID 0xac of the given size in bytes. 144 144 * The size is inclusive of the 1 byte Report ID prefix. 145 145 * 146 - * HID-BPF requires that at least one report has 147 - * the same size as the original report from the device. 146 + * The kernel discards any HID reports that are larger 147 + * than the largest report in a HID report descriptor. 148 + * Thus at least one report must have (at least) 149 + * the same size as the largest original report from 150 + * the device. 148 151 * The easy way to ensure that is to add this 149 152 * macro as the last element of your CollectionApplication 150 153 * other reports can be of any size less than this. ··· 298 295 #define Usage_GD_SystemSpeakerMute Usage_i8(0xa7) 299 296 #define Usage_GD_SystemHibernate Usage_i8(0xa8) 300 297 #define Usage_GD_SystemMicrophoneMute Usage_i8(0xa9) 298 + #define Usage_GD_SystemAccessibilityBinding Usage_i8(0xaa) 301 299 #define Usage_GD_SystemDisplayInvert Usage_i8(0xb0) 302 300 #define Usage_GD_SystemDisplayInternal Usage_i8(0xb1) 303 301 #define Usage_GD_SystemDisplayExternal Usage_i8(0xb2) ··· 2673 2669 #define Usage_BS_iDeviceName Usage_i8(0x88) 2674 2670 #define Usage_BS_iDeviceChemistry Usage_i8(0x89) 2675 2671 #define Usage_BS_ManufacturerData Usage_i8(0x8a) 2676 - #define Usage_BS_Rechargable Usage_i8(0x8b) 2672 + #define Usage_BS_Rechargeable Usage_i8(0x8b) 2677 2673 #define Usage_BS_WarningCapacityLimit Usage_i8(0x8c) 2678 2674 #define Usage_BS_CapacityGranularity1 Usage_i8(0x8d) 2679 2675 #define Usage_BS_CapacityGranularity2 Usage_i8(0x8e)
+21
drivers/hid/hid-evision.c
··· 18 18 struct hid_field *field, struct hid_usage *usage, 19 19 unsigned long **bit, int *max) 20 20 { 21 + /* mapping only applies to USB_DEVICE_ID_EVISION_ICL01 */ 22 + if (hdev->product != USB_DEVICE_ID_EVISION_ICL01) 23 + return 0; 24 + 21 25 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) 22 26 return 0; 23 27 ··· 41 37 return 0; 42 38 } 43 39 40 + #define REP_DSC_SIZE 236 41 + #define USAGE_MAX_INDEX 59 42 + 43 + static const __u8 *evision_report_fixup(struct hid_device *hdev, __u8 *rdesc, 44 + unsigned int *rsize) 45 + { 46 + if (hdev->product == USB_DEVICE_ID_EV_TELINK_RECEIVER && 47 + *rsize == REP_DSC_SIZE && rdesc[USAGE_MAX_INDEX] == 0x29 && 48 + rdesc[USAGE_MAX_INDEX + 1] == 3) { 49 + hid_info(hdev, "fixing EVision:TeLink Receiver report descriptor\n"); 50 + rdesc[USAGE_MAX_INDEX + 1] = 5; // change usage max from 3 to 5 51 + } 52 + return rdesc; 53 + } 54 + 44 55 static const struct hid_device_id evision_devices[] = { 45 56 { HID_USB_DEVICE(USB_VENDOR_ID_EVISION, USB_DEVICE_ID_EVISION_ICL01) }, 57 + { HID_USB_DEVICE(USB_VENDOR_ID_EVISION, USB_DEVICE_ID_EV_TELINK_RECEIVER) }, 46 58 { } 47 59 }; 48 60 MODULE_DEVICE_TABLE(hid, evision_devices); ··· 67 47 .name = "evision", 68 48 .id_table = evision_devices, 69 49 .input_mapping = evision_input_mapping, 50 + .report_fixup = evision_report_fixup, 70 51 }; 71 52 module_hid_driver(evision_driver); 72 53
+9
drivers/hid/hid-generic.c
··· 70 70 return hid_hw_start(hdev, HID_CONNECT_DEFAULT); 71 71 } 72 72 73 + static int hid_generic_reset_resume(struct hid_device *hdev) 74 + { 75 + if (hdev->claimed & HID_CLAIMED_INPUT) 76 + hidinput_reset_resume(hdev); 77 + 78 + return 0; 79 + } 80 + 73 81 static const struct hid_device_id hid_table[] = { 74 82 { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, HID_ANY_ID, HID_ANY_ID) }, 75 83 { } ··· 89 81 .id_table = hid_table, 90 82 .match = hid_generic_match, 91 83 .probe = hid_generic_probe, 84 + .reset_resume = hid_generic_reset_resume, 92 85 }; 93 86 module_hid_driver(hid_generic); 94 87
+5
drivers/hid/hid-ids.h
··· 477 477 #define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118 478 478 479 479 #define USB_VENDOR_ID_EVISION 0x320f 480 + #define USB_DEVICE_ID_EV_TELINK_RECEIVER 0x226f 480 481 #define USB_DEVICE_ID_EVISION_ICL01 0x5041 481 482 482 483 #define USB_VENDOR_ID_FFBEAST 0x045b ··· 882 881 #define USB_DEVICE_ID_LOGITECH_DUAL_ACTION 0xc216 883 882 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218 884 883 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219 884 + #define USB_DEVICE_ID_LOGITECH_G13 0xc21c 885 885 #define USB_DEVICE_ID_LOGITECH_G15_LCD 0xc222 886 886 #define USB_DEVICE_ID_LOGITECH_G11 0xc225 887 887 #define USB_DEVICE_ID_LOGITECH_G15_V2_LCD 0xc227 ··· 918 916 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1 0xc539 919 917 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1 0xc53f 920 918 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2 0xc543 919 + #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_3 0xc547 920 + #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_4 0xc54d 921 921 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a 922 922 #define USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER 0xc548 923 923 #define USB_DEVICE_ID_SPACETRAVELLER 0xc623 ··· 1425 1421 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW 0x0933 1426 1422 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078 1427 1423 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO 0x091b 1424 + #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_24_PRO 0x092d 1428 1425 #define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074 1429 1426 #define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071 1430 1427 #define USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720 0x0055
+24 -1
drivers/hid/hid-input.c
··· 878 878 879 879 switch (usage->hid) { 880 880 /* These usage IDs map directly to the usage codes. */ 881 - case HID_GD_X: case HID_GD_Y: case HID_GD_Z: 881 + case HID_GD_X: case HID_GD_Y: 882 882 case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: 883 883 if (field->flags & HID_MAIN_ITEM_RELATIVE) 884 884 map_rel(usage->hid & 0xf); 885 885 else 886 886 map_abs_clear(usage->hid & 0xf); 887 + break; 888 + 889 + case HID_GD_Z: 890 + /* HID_GD_Z is mapped to ABS_DISTANCE for stylus/pen */ 891 + if (field->flags & HID_MAIN_ITEM_RELATIVE) { 892 + map_rel(usage->hid & 0xf); 893 + } else { 894 + if (field->application == HID_DG_PEN || 895 + field->physical == HID_DG_PEN || 896 + field->logical == HID_DG_STYLUS || 897 + field->physical == HID_DG_STYLUS || 898 + field->application == HID_DG_DIGITIZER) 899 + map_abs_clear(ABS_DISTANCE); 900 + else 901 + map_abs_clear(usage->hid & 0xf); 902 + } 887 903 break; 888 904 889 905 case HID_GD_WHEEL: ··· 2415 2399 cancel_work_sync(&hid->led_work); 2416 2400 } 2417 2401 EXPORT_SYMBOL_GPL(hidinput_disconnect); 2402 + 2403 + void hidinput_reset_resume(struct hid_device *hid) 2404 + { 2405 + /* renegotiate host-device shared state after reset */ 2406 + hidinput_change_resolution_multipliers(hid); 2407 + } 2408 + EXPORT_SYMBOL_GPL(hidinput_reset_resume); 2418 2409 2419 2410 #ifdef CONFIG_HID_KUNIT_TEST 2420 2411 #include "hid-input-test.c"
+463 -18
drivers/hid/hid-lg-g15.c
··· 26 26 #define LG_G510_FEATURE_BACKLIGHT_RGB 0x05 27 27 #define LG_G510_FEATURE_POWER_ON_RGB 0x06 28 28 29 + #define LG_G510_INPUT_MACRO_KEYS 0x03 30 + #define LG_G510_INPUT_KBD_BACKLIGHT 0x04 31 + 32 + #define LG_G13_INPUT_REPORT 0x01 33 + #define LG_G13_FEATURE_M_KEYS_LEDS 0x05 34 + #define LG_G13_FEATURE_BACKLIGHT_RGB 0x07 35 + #define LG_G13_BACKLIGHT_HW_ON_BIT 23 36 + 37 + /** 38 + * g13_input_report.keybits[] is not 32-bit aligned, so we can't use the bitops macros. 39 + * 40 + * @ary: Pointer to array of u8s 41 + * @b: Bit index into ary, LSB first. Not range checked. 42 + */ 43 + #define TEST_BIT(ary, b) ((1 << ((b) & 7)) & (ary)[(b) >> 3]) 44 + 29 45 enum lg_g15_model { 46 + LG_G13, 30 47 LG_G15, 31 48 LG_G15_V2, 32 49 LG_G510, ··· 60 43 LG_G15_MACRO_PRESET3, 61 44 LG_G15_MACRO_RECORD, 62 45 LG_G15_LED_MAX 46 + }; 47 + 48 + struct g13_input_report { 49 + u8 report_id; /* Report ID is always set to 1. */ 50 + u8 joy_x, joy_y; 51 + u8 keybits[5]; 63 52 }; 64 53 65 54 struct lg_g15_led { ··· 86 63 struct mutex mutex; 87 64 struct work_struct work; 88 65 struct input_dev *input; 66 + struct input_dev *input_js; /* Separate joystick device for G13. */ 89 67 struct hid_device *hdev; 90 68 enum lg_g15_model model; 91 69 struct lg_g15_led leds[LG_G15_LED_MAX]; 92 70 bool game_mode_enabled; 71 + bool backlight_disabled; /* true == HW backlight toggled *OFF* */ 93 72 }; 73 + 74 + /********* G13 LED functions ***********/ 75 + /* 76 + * G13 retains no state across power cycles, and always powers up with the backlight on, 77 + * color #5AFF6E, all macro key LEDs off. 78 + */ 79 + static int lg_g13_get_leds_state(struct lg_g15_data *g15) 80 + { 81 + u8 * const tbuf = g15->transfer_buf; 82 + int ret, high; 83 + 84 + /* RGB backlight. */ 85 + ret = hid_hw_raw_request(g15->hdev, LG_G13_FEATURE_BACKLIGHT_RGB, 86 + tbuf, 5, 87 + HID_FEATURE_REPORT, HID_REQ_GET_REPORT); 88 + if (ret != 5) { 89 + hid_err(g15->hdev, "Error getting backlight brightness: %d\n", ret); 90 + return (ret < 0) ? ret : -EIO; 91 + } 92 + 93 + /* Normalize RGB intensities against the highest component. */ 94 + high = max3(tbuf[1], tbuf[2], tbuf[3]); 95 + if (high) { 96 + g15->leds[LG_G15_KBD_BRIGHTNESS].red = 97 + DIV_ROUND_CLOSEST(tbuf[1] * 255, high); 98 + g15->leds[LG_G15_KBD_BRIGHTNESS].green = 99 + DIV_ROUND_CLOSEST(tbuf[2] * 255, high); 100 + g15->leds[LG_G15_KBD_BRIGHTNESS].blue = 101 + DIV_ROUND_CLOSEST(tbuf[3] * 255, high); 102 + g15->leds[LG_G15_KBD_BRIGHTNESS].brightness = high; 103 + } else { 104 + g15->leds[LG_G15_KBD_BRIGHTNESS].red = 255; 105 + g15->leds[LG_G15_KBD_BRIGHTNESS].green = 255; 106 + g15->leds[LG_G15_KBD_BRIGHTNESS].blue = 255; 107 + g15->leds[LG_G15_KBD_BRIGHTNESS].brightness = 0; 108 + } 109 + 110 + /* Macro LEDs. */ 111 + ret = hid_hw_raw_request(g15->hdev, LG_G13_FEATURE_M_KEYS_LEDS, 112 + tbuf, 5, 113 + HID_FEATURE_REPORT, HID_REQ_GET_REPORT); 114 + if (ret != 5) { 115 + hid_err(g15->hdev, "Error getting macro LED brightness: %d\n", ret); 116 + return (ret < 0) ? ret : -EIO; 117 + } 118 + 119 + for (int i = LG_G15_MACRO_PRESET1; i < LG_G15_LED_MAX; ++i) 120 + g15->leds[i].brightness = !!(tbuf[1] & (1 << (i - LG_G15_MACRO_PRESET1))); 121 + 122 + /* 123 + * Bit 23 of g13_input_report.keybits[] contains the backlight's 124 + * current HW toggle state. Retrieve it from the device. 125 + */ 126 + ret = hid_hw_raw_request(g15->hdev, LG_G13_INPUT_REPORT, 127 + tbuf, sizeof(struct g13_input_report), 128 + HID_INPUT_REPORT, HID_REQ_GET_REPORT); 129 + if (ret != sizeof(struct g13_input_report)) { 130 + hid_err(g15->hdev, "Error getting backlight on/off state: %d\n", ret); 131 + return (ret < 0) ? ret : -EIO; 132 + } 133 + g15->backlight_disabled = 134 + !TEST_BIT(((struct g13_input_report *) tbuf)->keybits, 135 + LG_G13_BACKLIGHT_HW_ON_BIT); 136 + 137 + return 0; 138 + } 139 + 140 + static int lg_g13_kbd_led_write(struct lg_g15_data *g15, 141 + struct lg_g15_led *g15_led, 142 + enum led_brightness brightness) 143 + { 144 + struct mc_subled const * const subleds = g15_led->mcdev.subled_info; 145 + u8 * const tbuf = g15->transfer_buf; 146 + int ret; 147 + 148 + guard(mutex)(&g15->mutex); 149 + 150 + led_mc_calc_color_components(&g15_led->mcdev, brightness); 151 + 152 + tbuf[0] = 5; 153 + tbuf[1] = subleds[0].brightness; 154 + tbuf[2] = subleds[1].brightness; 155 + tbuf[3] = subleds[2].brightness; 156 + tbuf[4] = 0; 157 + 158 + ret = hid_hw_raw_request(g15->hdev, LG_G13_FEATURE_BACKLIGHT_RGB, 159 + tbuf, 5, 160 + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); 161 + if (ret != 5) { 162 + hid_err(g15->hdev, "Error setting backlight brightness: %d\n", ret); 163 + return (ret < 0) ? ret : -EIO; 164 + } 165 + 166 + g15_led->brightness = brightness; 167 + return 0; 168 + } 169 + 170 + static int lg_g13_kbd_led_set(struct led_classdev *led_cdev, enum led_brightness brightness) 171 + { 172 + struct led_classdev_mc *mc = lcdev_to_mccdev(led_cdev); 173 + struct lg_g15_led *g15_led = 174 + container_of(mc, struct lg_g15_led, mcdev); 175 + struct lg_g15_data *g15 = dev_get_drvdata(led_cdev->dev->parent); 176 + 177 + /* Ignore LED off on unregister / keyboard unplug */ 178 + if (led_cdev->flags & LED_UNREGISTERING) 179 + return 0; 180 + 181 + return lg_g13_kbd_led_write(g15, g15_led, brightness); 182 + } 183 + 184 + static enum led_brightness lg_g13_kbd_led_get(struct led_classdev *led_cdev) 185 + { 186 + struct led_classdev_mc const * const mc = lcdev_to_mccdev(led_cdev); 187 + struct lg_g15_led const *g15_led = 188 + container_of(mc, struct lg_g15_led, mcdev); 189 + 190 + return g15_led->brightness; 191 + } 192 + 193 + static int lg_g13_mkey_led_set(struct led_classdev *led_cdev, enum led_brightness brightness) 194 + { 195 + struct lg_g15_led *g15_led = 196 + container_of(led_cdev, struct lg_g15_led, cdev); 197 + struct lg_g15_data *g15 = dev_get_drvdata(led_cdev->dev->parent); 198 + int i, ret; 199 + u8 * const tbuf = g15->transfer_buf; 200 + u8 val, mask = 0; 201 + 202 + /* Ignore LED off on unregister / keyboard unplug */ 203 + if (led_cdev->flags & LED_UNREGISTERING) 204 + return 0; 205 + 206 + guard(mutex)(&g15->mutex); 207 + 208 + for (i = LG_G15_MACRO_PRESET1; i < LG_G15_LED_MAX; ++i) { 209 + if (i == g15_led->led) 210 + val = brightness; 211 + else 212 + val = g15->leds[i].brightness; 213 + 214 + if (val) 215 + mask |= 1 << (i - LG_G15_MACRO_PRESET1); 216 + } 217 + 218 + tbuf[0] = 5; 219 + tbuf[1] = mask; 220 + tbuf[2] = 0; 221 + tbuf[3] = 0; 222 + tbuf[4] = 0; 223 + 224 + ret = hid_hw_raw_request(g15->hdev, LG_G13_FEATURE_M_KEYS_LEDS, 225 + tbuf, 5, 226 + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); 227 + if (ret != 5) { 228 + hid_err(g15->hdev, "Error setting LED brightness: %d\n", ret); 229 + return (ret < 0) ? ret : -EIO; 230 + } 231 + 232 + g15_led->brightness = brightness; 233 + return 0; 234 + } 235 + 236 + static enum led_brightness lg_g13_mkey_led_get(struct led_classdev *led_cdev) 237 + { 238 + /* 239 + * G13 doesn't change macro key LEDs behind our back, so they're 240 + * whatever we last set them to. 241 + */ 242 + struct lg_g15_led *g15_led = 243 + container_of(led_cdev, struct lg_g15_led, cdev); 244 + 245 + return g15_led->brightness; 246 + } 94 247 95 248 /******** G15 and G15 v2 LED functions ********/ 96 249 ··· 425 226 g15->leds[i].blue = 255; 426 227 g15->leds[i].brightness = 0; 427 228 } 229 + 230 + if (i) 231 + return 0; 232 + 233 + ret = hid_hw_raw_request(g15->hdev, LG_G510_INPUT_KBD_BACKLIGHT, 234 + g15->transfer_buf, 2, 235 + HID_INPUT_REPORT, HID_REQ_GET_REPORT); 236 + if (ret != 2) { 237 + /* This can happen when a KVM switch is used, so only warn. */ 238 + hid_warn(g15->hdev, "Error getting backlight state: %d\n", ret); 239 + return 0; 240 + } 241 + 242 + g15->backlight_disabled = g15->transfer_buf[1] & 0x04; 428 243 429 244 return 0; 430 245 } ··· 603 390 int ret; 604 391 605 392 switch (g15->model) { 393 + case LG_G13: 394 + return lg_g13_get_leds_state(g15); 606 395 case LG_G15: 607 396 case LG_G15_V2: 608 397 return lg_g15_update_led_brightness(g15); ··· 631 416 } 632 417 633 418 /******** Input functions ********/ 419 + 420 + /* Table mapping keybits[] bit positions to event codes. */ 421 + /* Note: Indices are discontinuous to aid readability. */ 422 + static const u16 g13_keys_for_bits[] = { 423 + /* Main keypad - keys G1 - G22 */ 424 + [0] = KEY_MACRO1, 425 + [1] = KEY_MACRO2, 426 + [2] = KEY_MACRO3, 427 + [3] = KEY_MACRO4, 428 + [4] = KEY_MACRO5, 429 + [5] = KEY_MACRO6, 430 + [6] = KEY_MACRO7, 431 + [7] = KEY_MACRO8, 432 + [8] = KEY_MACRO9, 433 + [9] = KEY_MACRO10, 434 + [10] = KEY_MACRO11, 435 + [11] = KEY_MACRO12, 436 + [12] = KEY_MACRO13, 437 + [13] = KEY_MACRO14, 438 + [14] = KEY_MACRO15, 439 + [15] = KEY_MACRO16, 440 + [16] = KEY_MACRO17, 441 + [17] = KEY_MACRO18, 442 + [18] = KEY_MACRO19, 443 + [19] = KEY_MACRO20, 444 + [20] = KEY_MACRO21, 445 + [21] = KEY_MACRO22, 446 + 447 + /* LCD menu buttons. */ 448 + [24] = KEY_KBD_LCD_MENU5, /* "Next page" button */ 449 + [25] = KEY_KBD_LCD_MENU1, /* Left-most */ 450 + [26] = KEY_KBD_LCD_MENU2, 451 + [27] = KEY_KBD_LCD_MENU3, 452 + [28] = KEY_KBD_LCD_MENU4, /* Right-most */ 453 + 454 + /* Macro preset and record buttons; have red LEDs under them. */ 455 + [29] = KEY_MACRO_PRESET1, 456 + [30] = KEY_MACRO_PRESET2, 457 + [31] = KEY_MACRO_PRESET3, 458 + [32] = KEY_MACRO_RECORD_START, 459 + 460 + /* 33-35 handled by joystick device. */ 461 + 462 + /* Backlight toggle. */ 463 + [37] = KEY_LIGHTS_TOGGLE, 464 + }; 465 + 466 + #define G13_JS_KEYBITS_OFFSET 33 467 + 468 + static const u16 g13_keys_for_bits_js[] = { 469 + /* Joystick buttons */ 470 + /* These keybits are at bit indices 33, 34, and 35. */ 471 + BTN_BASE, /* Left side */ 472 + BTN_BASE2, /* Bottom side */ 473 + BTN_THUMB, /* Stick depress */ 474 + }; 475 + 476 + static int lg_g13_event(struct lg_g15_data *g15, u8 const *data) 477 + { 478 + struct g13_input_report const * const rep = (struct g13_input_report *) data; 479 + int i, val; 480 + bool backlight_disabled; 481 + 482 + /* 483 + * Main macropad and menu keys. 484 + * Emit key events defined for each bit position. 485 + */ 486 + for (i = 0; i < ARRAY_SIZE(g13_keys_for_bits); ++i) { 487 + if (g13_keys_for_bits[i]) { 488 + val = TEST_BIT(rep->keybits, i); 489 + input_report_key(g15->input, g13_keys_for_bits[i], val); 490 + } 491 + } 492 + input_sync(g15->input); 493 + 494 + /* 495 + * Joystick. 496 + * Emit button and deflection events. 497 + */ 498 + for (i = 0; i < ARRAY_SIZE(g13_keys_for_bits_js); ++i) { 499 + val = TEST_BIT(rep->keybits, i + G13_JS_KEYBITS_OFFSET); 500 + input_report_key(g15->input_js, g13_keys_for_bits_js[i], val); 501 + } 502 + input_report_abs(g15->input_js, ABS_X, rep->joy_x); 503 + input_report_abs(g15->input_js, ABS_Y, rep->joy_y); 504 + input_sync(g15->input_js); 505 + 506 + /* 507 + * Bit 23 of keybits[] reports the current backlight on/off state. If 508 + * it has changed from the last cached value, apply an update. 509 + */ 510 + backlight_disabled = !TEST_BIT(rep->keybits, LG_G13_BACKLIGHT_HW_ON_BIT); 511 + if (backlight_disabled ^ g15->backlight_disabled) { 512 + led_classdev_notify_brightness_hw_changed( 513 + &g15->leds[LG_G15_KBD_BRIGHTNESS].mcdev.led_cdev, 514 + backlight_disabled 515 + ? 0 : g15->leds[LG_G15_KBD_BRIGHTNESS].brightness); 516 + g15->backlight_disabled = backlight_disabled; 517 + } 518 + 519 + return 0; 520 + } 634 521 635 522 /* On the G15 Mark I Logitech has been quite creative with which bit is what */ 636 523 static void lg_g15_handle_lcd_menu_keys(struct lg_g15_data *g15, u8 *data) ··· 866 549 867 550 static int lg_g510_leds_event(struct lg_g15_data *g15, u8 *data) 868 551 { 552 + struct lg_g15_led *g15_led = &g15->leds[LG_G15_KBD_BRIGHTNESS]; 869 553 bool backlight_disabled; 554 + 555 + backlight_disabled = data[1] & 0x04; 556 + if (backlight_disabled == g15->backlight_disabled) 557 + return 0; 558 + 559 + led_classdev_notify_brightness_hw_changed( 560 + &g15_led->mcdev.led_cdev, 561 + backlight_disabled ? 0 : g15_led->brightness); 562 + 563 + g15->backlight_disabled = backlight_disabled; 870 564 871 565 /* 872 566 * The G510 ignores backlight updates when the backlight is turned off 873 567 * through the light toggle button on the keyboard, to work around this 874 568 * we queue a workitem to sync values when the backlight is turned on. 875 569 */ 876 - backlight_disabled = data[1] & 0x04; 877 570 if (!backlight_disabled) 878 571 schedule_work(&g15->work); 879 572 ··· 899 572 return 0; 900 573 901 574 switch (g15->model) { 575 + case LG_G13: 576 + if (data[0] == 0x01 && size == sizeof(struct g13_input_report)) 577 + return lg_g13_event(g15, data); 578 + break; 902 579 case LG_G15: 903 580 if (data[0] == 0x02 && size == 9) 904 581 return lg_g15_event(g15, data); ··· 919 588 break; 920 589 case LG_G510: 921 590 case LG_G510_USB_AUDIO: 922 - if (data[0] == 0x03 && size == 5) 591 + if (data[0] == LG_G510_INPUT_MACRO_KEYS && size == 5) 923 592 return lg_g510_event(g15, data); 924 - if (data[0] == 0x04 && size == 2) 593 + if (data[0] == LG_G510_INPUT_KBD_BACKLIGHT && size == 2) 925 594 return lg_g510_leds_event(g15, data); 926 595 break; 927 596 } ··· 947 616 { 948 617 int i; 949 618 struct mc_subled *subled_info; 619 + struct lg_g15_led * const gled = &g15->leds[index]; 950 620 951 - g15->leds[index].mcdev.led_cdev.brightness_set_blocking = 952 - lg_g510_kbd_led_set; 953 - g15->leds[index].mcdev.led_cdev.brightness_get = 954 - lg_g510_kbd_led_get; 955 - g15->leds[index].mcdev.led_cdev.max_brightness = 255; 956 - g15->leds[index].mcdev.num_colors = 3; 621 + if (g15->model == LG_G13) { 622 + gled->mcdev.led_cdev.brightness_set_blocking = 623 + lg_g13_kbd_led_set; 624 + gled->mcdev.led_cdev.brightness_get = 625 + lg_g13_kbd_led_get; 626 + gled->mcdev.led_cdev.flags = LED_BRIGHT_HW_CHANGED; 627 + } else { 628 + gled->mcdev.led_cdev.brightness_set_blocking = 629 + lg_g510_kbd_led_set; 630 + gled->mcdev.led_cdev.brightness_get = 631 + lg_g510_kbd_led_get; 632 + if (index == LG_G15_KBD_BRIGHTNESS) 633 + g15->leds[index].mcdev.led_cdev.flags = LED_BRIGHT_HW_CHANGED; 634 + } 635 + gled->mcdev.led_cdev.max_brightness = 255; 636 + gled->mcdev.num_colors = 3; 957 637 958 638 subled_info = devm_kcalloc(&g15->hdev->dev, 3, sizeof(*subled_info), GFP_KERNEL); 959 639 if (!subled_info) ··· 974 632 switch (i + 1) { 975 633 case LED_COLOR_ID_RED: 976 634 subled_info[i].color_index = LED_COLOR_ID_RED; 977 - subled_info[i].intensity = g15->leds[index].red; 635 + subled_info[i].intensity = gled->red; 978 636 break; 979 637 case LED_COLOR_ID_GREEN: 980 638 subled_info[i].color_index = LED_COLOR_ID_GREEN; 981 - subled_info[i].intensity = g15->leds[index].green; 639 + subled_info[i].intensity = gled->green; 982 640 break; 983 641 case LED_COLOR_ID_BLUE: 984 642 subled_info[i].color_index = LED_COLOR_ID_BLUE; 985 - subled_info[i].intensity = g15->leds[index].blue; 643 + subled_info[i].intensity = gled->blue; 986 644 break; 987 645 } 988 646 subled_info[i].channel = i; 989 647 } 990 - g15->leds[index].mcdev.subled_info = subled_info; 648 + gled->mcdev.subled_info = subled_info; 991 649 } 992 650 993 651 static int lg_g15_register_led(struct lg_g15_data *g15, int i, const char *name) ··· 998 656 g15->leds[i].cdev.name = name; 999 657 1000 658 switch (g15->model) { 659 + case LG_G13: 660 + if (i < LG_G15_BRIGHTNESS_MAX) { 661 + /* RGB backlight. */ 662 + lg_g15_setup_led_rgb(g15, i); 663 + ret = devm_led_classdev_multicolor_register_ext(&g15->hdev->dev, 664 + &g15->leds[i].mcdev, 665 + NULL); 666 + } else { 667 + /* Macro keys */ 668 + g15->leds[i].cdev.brightness_set_blocking = lg_g13_mkey_led_set; 669 + g15->leds[i].cdev.brightness_get = lg_g13_mkey_led_get; 670 + g15->leds[i].cdev.max_brightness = 1; 671 + 672 + ret = devm_led_classdev_register(&g15->hdev->dev, 673 + &g15->leds[i].cdev); 674 + } 675 + break; 1001 676 case LG_G15: 1002 677 case LG_G15_V2: 1003 678 g15->leds[i].cdev.brightness_get = lg_g15_led_get; ··· 1061 702 } 1062 703 1063 704 /* Common input device init code shared between keyboards and Z-10 speaker handling */ 1064 - static void lg_g15_init_input_dev(struct hid_device *hdev, struct input_dev *input, 1065 - const char *name) 705 + static void lg_g15_init_input_dev_core(struct hid_device *hdev, struct input_dev *input, 706 + char const *name) 1066 707 { 1067 - int i; 1068 - 1069 708 input->name = name; 1070 709 input->phys = hdev->phys; 1071 710 input->uniq = hdev->uniq; ··· 1074 717 input->dev.parent = &hdev->dev; 1075 718 input->open = lg_g15_input_open; 1076 719 input->close = lg_g15_input_close; 720 + } 721 + 722 + static void lg_g15_init_input_dev(struct hid_device *hdev, struct input_dev *input, 723 + const char *name) 724 + { 725 + int i; 726 + 727 + lg_g15_init_input_dev_core(hdev, input, name); 1077 728 1078 729 /* Keys below the LCD, intended for controlling a menu on the LCD */ 1079 730 for (i = 0; i < 5; i++) 1080 731 input_set_capability(input, EV_KEY, KEY_KBD_LCD_MENU1 + i); 732 + } 733 + 734 + static void lg_g13_init_input_dev(struct hid_device *hdev, 735 + struct input_dev *input, const char *name, 736 + struct input_dev *input_js, const char *name_js) 737 + { 738 + /* Macropad. */ 739 + lg_g15_init_input_dev_core(hdev, input, name); 740 + for (int i = 0; i < ARRAY_SIZE(g13_keys_for_bits); ++i) { 741 + if (g13_keys_for_bits[i]) 742 + input_set_capability(input, EV_KEY, g13_keys_for_bits[i]); 743 + } 744 + 745 + /* OBTW, we're a joystick, too... */ 746 + lg_g15_init_input_dev_core(hdev, input_js, name_js); 747 + for (int i = 0; i < ARRAY_SIZE(g13_keys_for_bits_js); ++i) 748 + input_set_capability(input_js, EV_KEY, g13_keys_for_bits_js[i]); 749 + 750 + input_set_capability(input_js, EV_ABS, ABS_X); 751 + input_set_abs_params(input_js, ABS_X, 0, 255, 0, 0); 752 + input_set_capability(input_js, EV_ABS, ABS_Y); 753 + input_set_abs_params(input_js, ABS_Y, 0, 255, 0, 0); 1081 754 } 1082 755 1083 756 static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id) ··· 1126 739 unsigned int connect_mask = 0; 1127 740 bool has_ff000000 = false; 1128 741 struct lg_g15_data *g15; 1129 - struct input_dev *input; 742 + struct input_dev *input, *input_js; 1130 743 struct hid_report *rep; 1131 744 int ret, i, gkeys = 0; 1132 745 ··· 1165 778 hid_set_drvdata(hdev, (void *)g15); 1166 779 1167 780 switch (g15->model) { 781 + case LG_G13: 782 + /* 783 + * The G13 has an analog thumbstick with nearby buttons. Some 784 + * libraries and applications are known to ignore devices that 785 + * don't "look like" a joystick, and a device with two ABS axes 786 + * and 25+ macro keys would confuse them. 787 + * 788 + * Create an additional input device dedicated to appear as a 789 + * simplified joystick (two ABS axes, three BTN buttons). 790 + */ 791 + input_js = devm_input_allocate_device(&hdev->dev); 792 + if (!input_js) 793 + return -ENOMEM; 794 + g15->input_js = input_js; 795 + input_set_drvdata(input_js, hdev); 796 + 797 + connect_mask = HID_CONNECT_HIDRAW; 798 + gkeys = 25; 799 + break; 1168 800 case LG_G15: 1169 801 INIT_WORK(&g15->work, lg_g15_leds_changed_work); 1170 802 /* ··· 1265 859 goto error_hw_stop; 1266 860 1267 861 return 0; /* All done */ 862 + } else if (g15->model == LG_G13) { 863 + static char const * const g13_led_names[] = { 864 + /* Backlight is shared between LCD and keys. */ 865 + "g13:rgb:kbd_backlight", 866 + NULL, /* Keep in sync with led_type enum */ 867 + "g13:red:macro_preset_1", 868 + "g13:red:macro_preset_2", 869 + "g13:red:macro_preset_3", 870 + "g13:red:macro_record", 871 + }; 872 + lg_g13_init_input_dev(hdev, 873 + input, "Logitech G13 Gaming Keypad", 874 + input_js, "Logitech G13 Thumbstick"); 875 + ret = input_register_device(input); 876 + if (ret) 877 + goto error_hw_stop; 878 + ret = input_register_device(input_js); 879 + if (ret) 880 + goto error_hw_stop; 881 + 882 + for (i = 0; i < ARRAY_SIZE(g13_led_names); ++i) { 883 + if (g13_led_names[i]) { 884 + ret = lg_g15_register_led(g15, i, g13_led_names[i]); 885 + if (ret) 886 + goto error_hw_stop; 887 + } 888 + } 889 + led_classdev_notify_brightness_hw_changed( 890 + &g15->leds[LG_G15_KBD_BRIGHTNESS].mcdev.led_cdev, 891 + g15->backlight_disabled 892 + ? 0 : g15->leds[LG_G15_KBD_BRIGHTNESS].brightness); 893 + return 0; 1268 894 } 1269 895 1270 896 /* Setup and register input device */ ··· 1341 903 } 1342 904 1343 905 static const struct hid_device_id lg_g15_devices[] = { 906 + /* 907 + * The G13 is a macropad-only device with an LCD, LED backlighing, 908 + * and joystick. 909 + */ 910 + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 911 + USB_DEVICE_ID_LOGITECH_G13), 912 + .driver_data = LG_G13 }, 1344 913 /* The G11 is a G15 without the LCD, treat it as a G15 */ 1345 914 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 1346 915 USB_DEVICE_ID_LOGITECH_G11),
+149 -43
drivers/hid/hid-logitech-dj.c
··· 116 116 recvr_type_dj, 117 117 recvr_type_hidpp, 118 118 recvr_type_gaming_hidpp, 119 + recvr_type_gaming_hidpp_ls_1_3, 119 120 recvr_type_mouse_only, 120 121 recvr_type_27mhz, 121 122 recvr_type_bluetooth, ··· 149 148 struct kfifo notif_fifo; 150 149 unsigned long last_query; /* in jiffies */ 151 150 bool ready; 151 + bool dj_mode; 152 152 enum recvr_type type; 153 153 unsigned int unnumbered_application; 154 154 spinlock_t lock; ··· 211 209 0x75, 0x03, /* REPORT SIZE (3) */ 212 210 0x91, 0x01, /* OUTPUT (Constant) */ 213 211 0xC0 212 + }; 213 + 214 + /* Gaming Keyboard descriptor (1) */ 215 + static const char kbd_lightspeed_1_3_descriptor[] = { 216 + 0x05, 0x01, /* Usage Page (Generic Desktop) */ 217 + 0x09, 0x06, /* Usage (Keyboard) */ 218 + 0xA1, 0x01, /* Collection (Application) */ 219 + 0x85, 0x01, /* Report ID (1) */ 220 + 0x05, 0x07, /* Usage Page (Kbrd/Keypad) */ 221 + 0x19, 0xE0, /* Usage Minimum (0xE0) */ 222 + 0x29, 0xE7, /* Usage Maximum (0xE7) */ 223 + 0x15, 0x00, /* Logical Minimum (0) */ 224 + 0x25, 0x01, /* Logical Maximum (1) */ 225 + 0x75, 0x01, /* Report Size (1) */ 226 + 0x95, 0x08, /* Report Count (8) */ 227 + 0x81, 0x02, /* Input (Data,Var) */ 228 + 0x95, 0x70, /* Report Count (112) */ 229 + 0x19, 0x04, /* Usage Minimum (0x04) */ 230 + 0x29, 0x73, /* Usage Maximum (0x73) */ 231 + 0x81, 0x02, /* Input (Data,Var,Abs) */ 232 + 0x95, 0x05, /* Report Count (5) */ 233 + 0x19, 0x87, /* Usage Minimum (0x87) */ 234 + 0x29, 0x8B, /* Usage Maximum (0x8B) */ 235 + 0x81, 0x02, /* Input (Data,Var,Abs) */ 236 + 0x95, 0x03, /* Report Count (3) */ 237 + 0x19, 0x90, /* Usage Minimum (0x90) */ 238 + 0x29, 0x92, /* Usage Maximum (0x92) */ 239 + 0x81, 0x02, /* Input (Data,Var,Abs) */ 240 + 0x95, 0x05, /* Report Count (5) */ 241 + 0x85, 0x0E, /* Report ID (14) */ 242 + 0x05, 0x08, /* Usage Page (LEDs) */ 243 + 0x19, 0x01, /* Usage Minimum (Num Lock) */ 244 + 0x29, 0x05, /* Usage Maximum (Kana) */ 245 + 0x91, 0x02, /* Output (Data,Var,Abs) */ 246 + 0x95, 0x01, /* Report Count (1) */ 247 + 0x75, 0x03, /* Report Size (3) */ 248 + 0x91, 0x03, /* Output (Const,Var,Abs) */ 249 + 0xC0, /* End Collection */ 214 250 }; 215 251 216 252 /* Mouse descriptor (2) */ ··· 455 415 0xC0, /* END_COLLECTION */ 456 416 }; 457 417 418 + /* Gaming Mouse descriptor with vendor data (2) */ 419 + static const char mse_high_res_ls_1_3_descriptor[] = { 420 + 0x05, 0x01, /* Usage Page (Generic Desktop) */ 421 + 0x09, 0x02, /* Usage (Mouse) */ 422 + 0xA1, 0x01, /* Collection (Application) */ 423 + 0x85, 0x02, /* Report ID (2) */ 424 + 0x09, 0x01, /* Usage (Pointer) */ 425 + 0xA1, 0x00, /* Collection (Physical) */ 426 + 0x95, 0x10, /* Report Count (16) */ 427 + 0x75, 0x01, /* Report Size (1) */ 428 + 0x15, 0x00, /* Logical Minimum (0) */ 429 + 0x25, 0x01, /* Logical Maximum (1) */ 430 + 0x05, 0x09, /* Usage Page (Button) */ 431 + 0x19, 0x01, /* Usage Minimum (0x01) */ 432 + 0x29, 0x10, /* Usage Maximum (0x10) */ 433 + 0x81, 0x02, /* Input (Data,Var,Abs) */ 434 + 0x95, 0x02, /* Report Count (2) */ 435 + 0x75, 0x10, /* Report Size (16) */ 436 + 0x16, 0x01, 0x80, /* Logical Minimum (-32767) */ 437 + 0x26, 0xFF, 0x7F, /* Logical Maximum (32767) */ 438 + 0x05, 0x01, /* Usage Page (Generic Desktop) */ 439 + 0x09, 0x30, /* Usage (X) */ 440 + 0x09, 0x31, /* Usage (Y) */ 441 + 0x81, 0x06, /* Input (Data,Var,Rel) */ 442 + 0x95, 0x01, /* Report Count (1) */ 443 + 0x75, 0x08, /* Report Size (8) */ 444 + 0x15, 0x81, /* Logical Minimum (-127) */ 445 + 0x25, 0x7F, /* Logical Maximum (127) */ 446 + 0x09, 0x38, /* Usage (Wheel) */ 447 + 0x81, 0x06, /* Input (Data,Var,Rel) */ 448 + 0x95, 0x01, /* Report Count (1) */ 449 + 0x05, 0x0C, /* Usage Page (Consumer) */ 450 + 0x0A, 0x38, 0x02, /* Usage (AC Pan) */ 451 + 0x81, 0x06, /* Input (Data,Var,Rel) */ 452 + 0xC0, /* End Collection */ 453 + 0x06, 0x00, 0xFF, /* Usage Page (Vendor Defined 0xFF00) */ 454 + 0x09, 0xF1, /* Usage (0xF1) */ 455 + 0x75, 0x08, /* Report Size (8) */ 456 + 0x95, 0x05, /* Report Count (5) */ 457 + 0x15, 0x00, /* Logical Minimum (0) */ 458 + 0x26, 0xFF, 0x00, /* Logical Maximum (255) */ 459 + 0x81, 0x00, /* Input (Data,Array,Abs) */ 460 + 0xC0, /* End Collection */ 461 + }; 462 + 458 463 /* Consumer Control descriptor (3) */ 459 464 static const char consumer_descriptor[] = { 460 465 0x05, 0x0C, /* USAGE_PAGE (Consumer Devices) */ ··· 605 520 /* Maximum size of all defined hid reports in bytes (including report id) */ 606 521 #define MAX_REPORT_SIZE 8 607 522 608 - /* Make sure all descriptors are present here */ 523 + /* Make sure the largest of each descriptor type is present here */ 609 524 #define MAX_RDESC_SIZE \ 610 - (sizeof(kbd_descriptor) + \ 525 + (sizeof(kbd_lightspeed_1_3_descriptor) +\ 611 526 sizeof(mse_bluetooth_descriptor) + \ 612 527 sizeof(mse5_bluetooth_descriptor) + \ 613 528 sizeof(consumer_descriptor) + \ ··· 642 557 static const struct hid_ll_driver logi_dj_ll_driver; 643 558 644 559 static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev); 560 + static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, 561 + unsigned int timeout); 645 562 static void delayedwork_callback(struct work_struct *work); 646 563 647 564 static LIST_HEAD(dj_hdev_list); ··· 892 805 struct dj_workitem workitem; 893 806 unsigned long flags; 894 807 int count; 895 - int retval; 896 808 897 809 dbg_hid("%s\n", __func__); 898 810 ··· 928 842 logi_dj_recv_destroy_djhid_device(djrcv_dev, &workitem); 929 843 break; 930 844 case WORKITEM_TYPE_UNKNOWN: 931 - retval = logi_dj_recv_query_paired_devices(djrcv_dev); 932 - if (retval) { 933 - hid_err(djrcv_dev->hidpp, "%s: logi_dj_recv_query_paired_devices error: %d\n", 934 - __func__, retval); 935 - } 845 + if (!djrcv_dev->dj_mode) 846 + logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); 847 + 848 + logi_dj_recv_query_paired_devices(djrcv_dev); 936 849 break; 937 850 case WORKITEM_TYPE_EMPTY: 938 851 dbg_hid("%s: device list is empty\n", __func__); ··· 1324 1239 1325 1240 djrcv_dev->last_query = jiffies; 1326 1241 1327 - if (djrcv_dev->type != recvr_type_dj) 1328 - return logi_dj_recv_query_hidpp_devices(djrcv_dev); 1242 + if (!djrcv_dev->dj_mode) 1243 + return 0; 1244 + 1245 + if (djrcv_dev->type != recvr_type_dj) { 1246 + retval = logi_dj_recv_query_hidpp_devices(djrcv_dev); 1247 + goto out; 1248 + } 1329 1249 1330 1250 dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL); 1331 1251 if (!dj_report) ··· 1340 1250 dj_report->report_type = REPORT_TYPE_CMD_GET_PAIRED_DEVICES; 1341 1251 retval = logi_dj_recv_send_report(djrcv_dev, dj_report); 1342 1252 kfree(dj_report); 1253 + out: 1254 + if (retval < 0) 1255 + hid_err(djrcv_dev->hidpp, "%s error:%d\n", __func__, retval); 1256 + 1343 1257 return retval; 1344 1258 } 1345 1259 ··· 1369 1275 (u8)timeout; 1370 1276 1371 1277 retval = logi_dj_recv_send_report(djrcv_dev, dj_report); 1278 + if (retval) 1279 + goto out; 1372 1280 1373 1281 /* 1374 1282 * Ugly sleep to work around a USB 3.0 bug when the receiver is ··· 1379 1283 * 50 msec should gives enough time to the receiver to be ready. 1380 1284 */ 1381 1285 msleep(50); 1382 - 1383 - if (retval) { 1384 - kfree(dj_report); 1385 - return retval; 1386 - } 1387 1286 } 1388 1287 1389 1288 /* ··· 1404 1313 HIDPP_REPORT_SHORT_LENGTH, HID_OUTPUT_REPORT, 1405 1314 HID_REQ_SET_REPORT); 1406 1315 1316 + out: 1407 1317 kfree(dj_report); 1318 + 1319 + if (retval < 0) 1320 + hid_err(hdev, "%s error:%d\n", __func__, retval); 1321 + 1322 + djrcv_dev->dj_mode = retval >= 0; 1408 1323 return retval; 1409 1324 } 1410 1325 ··· 1471 1374 return -EINVAL; 1472 1375 1473 1376 if (djrcv_dev->type != recvr_type_dj && count >= 2) { 1377 + unsigned char led_report_id = 0; 1378 + 1474 1379 if (!djrcv_dev->keyboard) { 1475 1380 hid_warn(hid, "Received REPORT_TYPE_LEDS request before the keyboard interface was enumerated\n"); 1476 1381 return 0; 1477 1382 } 1383 + 1384 + /* This Lightspeed receiver expects LED reports with report ID 1 */ 1385 + if (djrcv_dev->type == recvr_type_gaming_hidpp_ls_1_3) 1386 + led_report_id = 1; 1387 + 1478 1388 /* usbhid overrides the report ID and ignores the first byte */ 1479 - return hid_hw_raw_request(djrcv_dev->keyboard, 0, buf, count, 1389 + return hid_hw_raw_request(djrcv_dev->keyboard, led_report_id, buf, count, 1480 1390 report_type, reqtype); 1481 1391 } 1482 1392 ··· 1530 1426 if (djdev->reports_supported & STD_KEYBOARD) { 1531 1427 dbg_hid("%s: sending a kbd descriptor, reports_supported: %llx\n", 1532 1428 __func__, djdev->reports_supported); 1533 - rdcat(rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor)); 1429 + if (djdev->dj_receiver_dev->type == recvr_type_gaming_hidpp_ls_1_3) 1430 + rdcat(rdesc, &rsize, kbd_lightspeed_1_3_descriptor, 1431 + sizeof(kbd_lightspeed_1_3_descriptor)); 1432 + else 1433 + rdcat(rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor)); 1534 1434 } 1535 1435 1536 1436 if (djdev->reports_supported & STD_MOUSE) { ··· 1544 1436 djdev->dj_receiver_dev->type == recvr_type_mouse_only) 1545 1437 rdcat(rdesc, &rsize, mse_high_res_descriptor, 1546 1438 sizeof(mse_high_res_descriptor)); 1439 + else if (djdev->dj_receiver_dev->type == recvr_type_gaming_hidpp_ls_1_3) 1440 + rdcat(rdesc, &rsize, mse_high_res_ls_1_3_descriptor, 1441 + sizeof(mse_high_res_ls_1_3_descriptor)); 1547 1442 else if (djdev->dj_receiver_dev->type == recvr_type_27mhz) 1548 1443 rdcat(rdesc, &rsize, mse_27mhz_descriptor, 1549 1444 sizeof(mse_27mhz_descriptor)); ··· 1806 1695 } 1807 1696 /* 1808 1697 * Mouse-only receivers send unnumbered mouse data. The 27 MHz 1809 - * receiver uses 6 byte packets, the nano receiver 8 bytes. 1698 + * receiver uses 6 byte packets, the nano receiver 8 bytes, 1699 + * the lightspeed receiver (Pro X Superlight) 13 bytes. 1810 1700 */ 1811 1701 if (djrcv_dev->unnumbered_application == HID_GD_MOUSE && 1812 - size <= 8) { 1813 - u8 mouse_report[9]; 1702 + size <= 13){ 1703 + u8 mouse_report[14]; 1814 1704 1815 1705 /* Prepend report id */ 1816 1706 mouse_report[0] = REPORT_TYPE_MOUSE; ··· 1888 1776 case recvr_type_dj: no_dj_interfaces = 3; break; 1889 1777 case recvr_type_hidpp: no_dj_interfaces = 2; break; 1890 1778 case recvr_type_gaming_hidpp: no_dj_interfaces = 3; break; 1779 + case recvr_type_gaming_hidpp_ls_1_3: no_dj_interfaces = 3; break; 1891 1780 case recvr_type_mouse_only: no_dj_interfaces = 2; break; 1892 1781 case recvr_type_27mhz: no_dj_interfaces = 2; break; 1893 1782 case recvr_type_bluetooth: no_dj_interfaces = 2; break; ··· 1947 1834 } 1948 1835 1949 1836 if (has_hidpp) { 1950 - retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); 1951 - if (retval < 0) { 1952 - hid_err(hdev, "%s: logi_dj_recv_switch_to_dj_mode returned error:%d\n", 1953 - __func__, retval); 1954 - goto switch_to_dj_mode_fail; 1955 - } 1837 + /* 1838 + * This can fail with a KVM. Ignore errors to let the probe 1839 + * succeed, logi_dj_recv_queue_unknown_work will retry later. 1840 + */ 1841 + logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); 1956 1842 } 1957 1843 1958 1844 /* This is enabling the polling urb on the IN endpoint */ ··· 1969 1857 spin_lock_irqsave(&djrcv_dev->lock, flags); 1970 1858 djrcv_dev->ready = true; 1971 1859 spin_unlock_irqrestore(&djrcv_dev->lock, flags); 1972 - retval = logi_dj_recv_query_paired_devices(djrcv_dev); 1973 - if (retval < 0) { 1974 - hid_err(hdev, "%s: logi_dj_recv_query_paired_devices error:%d\n", 1975 - __func__, retval); 1976 - /* 1977 - * This can happen with a KVM, let the probe succeed, 1978 - * logi_dj_recv_queue_unknown_work will retry later. 1979 - */ 1980 - } 1860 + /* This too can fail with a KVM, ignore errors. */ 1861 + logi_dj_recv_query_paired_devices(djrcv_dev); 1981 1862 } 1982 1863 1983 1864 return 0; 1984 1865 1985 1866 llopen_failed: 1986 - switch_to_dj_mode_fail: 1987 1867 hid_hw_stop(hdev); 1988 1868 1989 1869 hid_hw_start_fail: ··· 1986 1882 #ifdef CONFIG_PM 1987 1883 static int logi_dj_reset_resume(struct hid_device *hdev) 1988 1884 { 1989 - int retval; 1990 1885 struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); 1991 1886 1992 1887 if (!djrcv_dev || djrcv_dev->hidpp != hdev) 1993 1888 return 0; 1994 1889 1995 - retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); 1996 - if (retval < 0) { 1997 - hid_err(hdev, "%s: logi_dj_recv_switch_to_dj_mode returned error:%d\n", 1998 - __func__, retval); 1999 - } 2000 - 1890 + logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); 2001 1891 return 0; 2002 1892 } 2003 1893 #endif ··· 2085 1987 HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 2086 1988 USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2), 2087 1989 .driver_data = recvr_type_gaming_hidpp}, 1990 + { /* Logitech lightspeed receiver (0xc547) */ 1991 + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 1992 + USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_3), 1993 + .driver_data = recvr_type_gaming_hidpp_ls_1_3}, 1994 + { /* Logitech lightspeed receiver (0xc54d) */ 1995 + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 1996 + USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_4), 1997 + .driver_data = recvr_type_gaming_hidpp_ls_1_3}, 2088 1998 2089 1999 { /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */ 2090 2000 HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
+9 -3
drivers/hid/hid-logitech-hidpp.c
··· 352 352 353 353 do { 354 354 ret = __do_hidpp_send_message_sync(hidpp, message, response); 355 - if (ret != HIDPP20_ERROR_BUSY) 355 + if (response->report_id == REPORT_ID_HIDPP_SHORT && 356 + ret != HIDPP_ERROR_BUSY) 357 + break; 358 + if ((response->report_id == REPORT_ID_HIDPP_LONG || 359 + response->report_id == REPORT_ID_HIDPP_VERY_LONG) && 360 + ret != HIDPP20_ERROR_BUSY) 356 361 break; 357 362 358 - dbg_hid("%s:got busy hidpp 2.0 error %02X, retrying\n", __func__, ret); 363 + dbg_hid("%s:got busy hidpp error %02X, retrying\n", __func__, ret); 359 364 } while (--max_retries); 360 365 361 366 mutex_unlock(&hidpp->send_mutex); ··· 976 971 } 977 972 978 973 /* the device might not be connected */ 979 - if (ret == HIDPP_ERROR_RESOURCE_ERROR) 974 + if (ret == HIDPP_ERROR_RESOURCE_ERROR || 975 + ret == HIDPP_ERROR_UNKNOWN_DEVICE) 980 976 return -EIO; 981 977 982 978 if (ret > 0) {
+3 -2
drivers/hid/hid-nintendo.c
··· 819 819 #define JC_INPUT_REPORT_MAX_DELTA 17 820 820 #define JC_SUBCMD_TX_OFFSET_MS 4 821 821 #define JC_SUBCMD_VALID_DELTA_REQ 3 822 - #define JC_SUBCMD_RATE_MAX_ATTEMPTS 500 822 + #define JC_SUBCMD_RATE_MAX_ATTEMPTS 25 823 823 #define JC_SUBCMD_RATE_LIMITER_USB_MS 20 824 824 #define JC_SUBCMD_RATE_LIMITER_BT_MS 60 825 825 #define JC_SUBCMD_RATE_LIMITER_MS(ctlr) ((ctlr)->hdev->bus == BUS_USB ? JC_SUBCMD_RATE_LIMITER_USB_MS : JC_SUBCMD_RATE_LIMITER_BT_MS) ··· 2648 2648 init_waitqueue_head(&ctlr->wait); 2649 2649 spin_lock_init(&ctlr->lock); 2650 2650 ctlr->rumble_queue = alloc_workqueue("hid-nintendo-rumble_wq", 2651 - WQ_FREEZABLE | WQ_MEM_RECLAIM, 0); 2651 + WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU, 2652 + 0); 2652 2653 if (!ctlr->rumble_queue) { 2653 2654 ret = -ENOMEM; 2654 2655 goto err;
+19
drivers/hid/hid-uclogic-core.c
··· 362 362 data[8] = pressure_low_byte; 363 363 data[9] = pressure_high_byte; 364 364 } 365 + if (size == 12 && pen->fragmented_hires2) { 366 + // 00 00 when on the left side, 01 00 in the right 367 + // we move these to the end of the x coord (u16) to create a correct x coord (u32) 368 + u8 lsb_low_byte = data[10]; 369 + u8 lsb_high_byte = data[11]; 370 + 371 + // shift everything right by 2 bytes, to make space for the moved lsb 372 + data[11] = data[9]; 373 + data[10] = data[8]; 374 + data[9] = data[7]; 375 + data[8] = data[6]; 376 + data[7] = data[5]; 377 + data[6] = data[4]; 378 + 379 + data[4] = lsb_low_byte; 380 + data[5] = lsb_high_byte; 381 + } 365 382 /* If we need to emulate in-range detection */ 366 383 if (pen->inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) { 367 384 /* Set in-range bit */ ··· 621 604 USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) }, 622 605 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, 623 606 USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO) }, 607 + { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, 608 + USB_DEVICE_ID_UGEE_XPPEN_TABLET_24_PRO) }, 624 609 { } 625 610 }; 626 611 MODULE_DEVICE_TABLE(hid, uclogic_devices);
+36 -11
drivers/hid/hid-uclogic-params.c
··· 1123 1123 return -EINVAL; 1124 1124 1125 1125 pen_x_lm = get_unaligned_le16(str_desc + 2); 1126 + if (str_desc_size > 12) 1127 + pen_x_lm += (u8)str_desc[12] << 16; 1128 + 1126 1129 pen_y_lm = get_unaligned_le16(str_desc + 4); 1127 1130 frame_num_buttons = str_desc[6]; 1128 1131 *frame_type = str_desc[7]; ··· 1537 1534 } 1538 1535 1539 1536 /* 1540 - * uclogic_params_init_ugee_xppen_pro_22r() - Initializes a UGEE XP-Pen Pro 22R tablet device. 1537 + * uclogic_params_init_ugee_xppen_pro() - Initializes a UGEE XP-Pen Pro tablet device. 1541 1538 * 1542 1539 * @hdev: The HID device of the tablet interface to initialize and get 1543 1540 * parameters from. Cannot be NULL. ··· 1548 1545 * Returns: 1549 1546 * Zero, if successful. A negative errno code on error. 1550 1547 */ 1551 - static int uclogic_params_init_ugee_xppen_pro_22r(struct uclogic_params *params, 1552 - struct hid_device *hdev, 1553 - const u8 rdesc_frame_arr[], 1554 - const size_t rdesc_frame_size) 1548 + static int uclogic_params_init_ugee_xppen_pro(struct uclogic_params *params, 1549 + struct hid_device *hdev, 1550 + const u8 rdesc_pen_arr[], 1551 + const size_t rdesc_pen_size, 1552 + const u8 rdesc_frame_arr[], 1553 + const size_t rdesc_frame_size, 1554 + size_t str_desc_len) 1555 1555 { 1556 1556 int rc = 0; 1557 1557 struct usb_interface *iface; 1558 1558 __u8 bInterfaceNumber; 1559 - const int str_desc_len = 12; 1560 1559 u8 *str_desc = NULL; 1561 1560 __u8 *rdesc_pen = NULL; 1562 1561 s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; ··· 1621 1616 1622 1617 /* Initialize the pen interface */ 1623 1618 rdesc_pen = uclogic_rdesc_template_apply( 1624 - uclogic_rdesc_ugee_v2_pen_template_arr, 1625 - uclogic_rdesc_ugee_v2_pen_template_size, 1619 + rdesc_pen_arr, 1620 + rdesc_pen_size, 1626 1621 desc_params, ARRAY_SIZE(desc_params)); 1627 1622 if (!rdesc_pen) { 1628 1623 rc = -ENOMEM; ··· 1630 1625 } 1631 1626 1632 1627 p.pen.desc_ptr = rdesc_pen; 1633 - p.pen.desc_size = uclogic_rdesc_ugee_v2_pen_template_size; 1628 + p.pen.desc_size = rdesc_pen_size; 1634 1629 p.pen.id = 0x02; 1635 1630 p.pen.subreport_list[0].value = 0xf0; 1636 1631 p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID; ··· 1977 1972 break; 1978 1973 case VID_PID(USB_VENDOR_ID_UGEE, 1979 1974 USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO): 1980 - rc = uclogic_params_init_ugee_xppen_pro_22r(&p, 1975 + rc = uclogic_params_init_ugee_xppen_pro(&p, 1981 1976 hdev, 1977 + uclogic_rdesc_ugee_v2_pen_template_arr, 1978 + uclogic_rdesc_ugee_v2_pen_template_size, 1982 1979 uclogic_rdesc_xppen_artist_22r_pro_frame_arr, 1983 - uclogic_rdesc_xppen_artist_22r_pro_frame_size); 1980 + uclogic_rdesc_xppen_artist_22r_pro_frame_size, 1981 + 12); 1982 + if (rc != 0) 1983 + goto cleanup; 1984 + 1985 + break; 1986 + case VID_PID(USB_VENDOR_ID_UGEE, 1987 + USB_DEVICE_ID_UGEE_XPPEN_TABLET_24_PRO): 1988 + rc = uclogic_params_init_ugee_xppen_pro(&p, 1989 + hdev, 1990 + uclogic_rdesc_xppen_artist_24_pro_pen_template_arr, 1991 + uclogic_rdesc_xppen_artist_24_pro_pen_template_size, 1992 + uclogic_rdesc_xppen_artist_24_pro_frame_arr, 1993 + uclogic_rdesc_xppen_artist_24_pro_frame_size, 1994 + 14); 1995 + 1996 + // The 24 Pro has a fragmented X Coord. 1997 + p.pen.fragmented_hires2 = true; 1998 + 1984 1999 if (rc != 0) 1985 2000 goto cleanup; 1986 2001
+5
drivers/hid/hid-uclogic-params.h
··· 103 103 * Only valid if "id" is not zero. 104 104 */ 105 105 bool tilt_y_flipped; 106 + /* 107 + * True, if reports include fragmented high resolution X coords. 108 + * This moves bytes 10-11 to the LSB of the X coordinate. 109 + */ 110 + bool fragmented_hires2; 106 111 }; 107 112 108 113 /*
+125
drivers/hid/hid-uclogic-rdesc.c
··· 1237 1237 const size_t uclogic_rdesc_xppen_artist_22r_pro_frame_size = 1238 1238 sizeof(uclogic_rdesc_xppen_artist_22r_pro_frame_arr); 1239 1239 1240 + /* Fixed report descriptor template for XP-PEN 24 Pro reports 1241 + * Mostly identical to uclogic_rdesc_ugee_v2_pen_template_arr except that the X coordinate has to be 1242 + * 32-bits instead of 16-bits. 1243 + */ 1244 + const __u8 uclogic_rdesc_xppen_artist_24_pro_pen_template_arr[] = { 1245 + 0x05, 0x0d, /* Usage Page (Digitizers), */ 1246 + 0x09, 0x01, /* Usage (Digitizer), */ 1247 + 0xa1, 0x01, /* Collection (Application), */ 1248 + 0x85, 0x02, /* Report ID (2), */ 1249 + 0x09, 0x20, /* Usage (Stylus), */ 1250 + 0xa1, 0x00, /* Collection (Physical), */ 1251 + 0x09, 0x42, /* Usage (Tip Switch), */ 1252 + 0x09, 0x44, /* Usage (Barrel Switch), */ 1253 + 0x09, 0x46, /* Usage (Tablet Pick), */ 1254 + 0x75, 0x01, /* Report Size (1), */ 1255 + 0x95, 0x03, /* Report Count (3), */ 1256 + 0x14, /* Logical Minimum (0), */ 1257 + 0x25, 0x01, /* Logical Maximum (1), */ 1258 + 0x81, 0x02, /* Input (Variable), */ 1259 + 0x95, 0x02, /* Report Count (2), */ 1260 + 0x81, 0x03, /* Input (Constant, Variable), */ 1261 + 0x09, 0x32, /* Usage (In Range), */ 1262 + 0x95, 0x01, /* Report Count (1), */ 1263 + 0x81, 0x02, /* Input (Variable), */ 1264 + 0x95, 0x02, /* Report Count (2), */ 1265 + 0x81, 0x03, /* Input (Constant, Variable), */ 1266 + 0x75, 0x10, /* Report Size (16), */ 1267 + 0x95, 0x01, /* Report Count (1), */ 1268 + 0x35, 0x00, /* Physical Minimum (0), */ 1269 + 0xa4, /* Push, */ 1270 + 0x05, 0x01, /* Usage Page (Desktop), */ 1271 + 0x09, 0x30, /* Usage (X), */ 1272 + 0x65, 0x13, /* Unit (Inch), */ 1273 + 0x55, 0x0d, /* Unit Exponent (-3), */ 1274 + 0x27, UCLOGIC_RDESC_PEN_PH(X_LM), 1275 + /* Logical Maximum (PLACEHOLDER), */ 1276 + 0x47, UCLOGIC_RDESC_PEN_PH(X_PM), 1277 + /* Physical Maximum (PLACEHOLDER), */ 1278 + 0x75, 0x20, /* Report Size (32), */ 1279 + 0x81, 0x02, /* Input (Variable), */ 1280 + 0x75, 0x10, /* Report Size (16), */ 1281 + 0x09, 0x31, /* Usage (Y), */ 1282 + 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), 1283 + /* Logical Maximum (PLACEHOLDER), */ 1284 + 0x47, UCLOGIC_RDESC_PEN_PH(Y_PM), 1285 + /* Physical Maximum (PLACEHOLDER), */ 1286 + 0x81, 0x02, /* Input (Variable), */ 1287 + 0xb4, /* Pop, */ 1288 + 0x09, 0x30, /* Usage (Tip Pressure), */ 1289 + 0x45, 0x00, /* Physical Maximum (0), */ 1290 + 0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), 1291 + /* Logical Maximum (PLACEHOLDER), */ 1292 + 0x75, 0x0D, /* Report Size (13), */ 1293 + 0x95, 0x01, /* Report Count (1), */ 1294 + 0x81, 0x02, /* Input (Variable), */ 1295 + 0x75, 0x01, /* Report Size (1), */ 1296 + 0x95, 0x03, /* Report Count (3), */ 1297 + 0x81, 0x01, /* Input (Constant), */ 1298 + 0x09, 0x3d, /* Usage (X Tilt), */ 1299 + 0x35, 0xC3, /* Physical Minimum (-61), */ 1300 + 0x45, 0x3C, /* Physical Maximum (60), */ 1301 + 0x15, 0xC3, /* Logical Minimum (-61), */ 1302 + 0x25, 0x3C, /* Logical Maximum (60), */ 1303 + 0x75, 0x08, /* Report Size (8), */ 1304 + 0x95, 0x01, /* Report Count (1), */ 1305 + 0x81, 0x02, /* Input (Variable), */ 1306 + 0x09, 0x3e, /* Usage (Y Tilt), */ 1307 + 0x35, 0xC3, /* Physical Minimum (-61), */ 1308 + 0x45, 0x3C, /* Physical Maximum (60), */ 1309 + 0x15, 0xC3, /* Logical Minimum (-61), */ 1310 + 0x25, 0x3C, /* Logical Maximum (60), */ 1311 + 0x81, 0x02, /* Input (Variable), */ 1312 + 0xc0, /* End Collection, */ 1313 + 0xc0, /* End Collection */ 1314 + }; 1315 + const size_t uclogic_rdesc_xppen_artist_24_pro_pen_template_size = 1316 + sizeof(uclogic_rdesc_xppen_artist_24_pro_pen_template_arr); 1317 + 1318 + /* Fixed report descriptor for XP-Pen Arist 24 Pro frame */ 1319 + const __u8 uclogic_rdesc_xppen_artist_24_pro_frame_arr[] = { 1320 + 0x05, 0x01, /* Usage Page (Desktop), */ 1321 + 0x09, 0x07, /* Usage (Keypad), */ 1322 + 0xA1, 0x01, /* Collection (Application), */ 1323 + 0x85, UCLOGIC_RDESC_V1_FRAME_ID, 1324 + /* Report ID (Virtual report), */ 1325 + 0x05, 0x0D, /* Usage Page (Digitizer), */ 1326 + 0x09, 0x39, /* Usage (Tablet Function Keys), */ 1327 + 0xA0, /* Collection (Physical), */ 1328 + 0x14, /* Logical Minimum (0), */ 1329 + 0x25, 0x01, /* Logical Maximum (1), */ 1330 + 0x75, 0x01, /* Report Size (1), */ 1331 + 0x95, 0x08, /* Report Count (8), */ 1332 + 0x81, 0x01, /* Input (Constant), */ 1333 + 0x05, 0x09, /* Usage Page (Button), */ 1334 + 0x19, 0x01, /* Usage Minimum (01h), */ 1335 + 0x29, 0x14, /* Usage Maximum (14h), */ 1336 + 0x95, 0x14, /* Report Count (20), */ 1337 + 0x81, 0x02, /* Input (Variable), */ 1338 + 0x95, 0x14, /* Report Count (20), */ 1339 + 0x81, 0x01, /* Input (Constant), */ 1340 + 0x05, 0x01, /* Usage Page (Desktop), */ 1341 + 0x09, 0x38, /* Usage (Wheel), */ 1342 + 0x75, 0x08, /* Report Size (8), */ 1343 + 0x95, 0x01, /* Report Count (1), */ 1344 + 0x15, 0xFF, /* Logical Minimum (-1), */ 1345 + 0x25, 0x08, /* Logical Maximum (8), */ 1346 + 0x81, 0x06, /* Input (Variable, Relative), */ 1347 + 0x05, 0x0C, /* Usage Page (Consumer Devices), */ 1348 + 0x0A, 0x38, 0x02, /* Usage (AC PAN), */ 1349 + 0x95, 0x01, /* Report Count (1), */ 1350 + 0x81, 0x06, /* Input (Variable, Relative), */ 1351 + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ 1352 + 0x75, 0x08, /* Report Size (8), */ 1353 + 0x95, 0x01, /* Report Count (1), */ 1354 + 0x81, 0x02, /* Input (Variable), */ 1355 + 0x75, 0x01, /* Report Size (1), */ 1356 + 0x95, 16, /* Report Count (16), */ 1357 + 0x81, 0x01, /* Input (Constant), */ 1358 + 0xC0, /* End Collection */ 1359 + 0xC0, /* End Collection */ 1360 + }; 1361 + 1362 + const size_t uclogic_rdesc_xppen_artist_24_pro_frame_size = 1363 + sizeof(uclogic_rdesc_xppen_artist_24_pro_frame_arr); 1364 + 1240 1365 /** 1241 1366 * uclogic_rdesc_template_apply() - apply report descriptor parameters to a 1242 1367 * report descriptor template, creating a report descriptor. Copies the
+8
drivers/hid/hid-uclogic-rdesc.h
··· 214 214 extern const __u8 uclogic_rdesc_xppen_artist_22r_pro_frame_arr[]; 215 215 extern const size_t uclogic_rdesc_xppen_artist_22r_pro_frame_size; 216 216 217 + /* Fixed report descriptor for XP-Pen Arist 24 Pro frame */ 218 + extern const __u8 uclogic_rdesc_xppen_artist_24_pro_pen_template_arr[]; 219 + extern const size_t uclogic_rdesc_xppen_artist_24_pro_pen_template_size; 220 + 221 + /* Fixed report descriptor for XP-Pen Arist 24 Pro frame */ 222 + extern const __u8 uclogic_rdesc_xppen_artist_24_pro_frame_arr[]; 223 + extern const size_t uclogic_rdesc_xppen_artist_24_pro_frame_size; 224 + 217 225 #endif /* _HID_UCLOGIC_RDESC_H */
+105 -66
drivers/hid/hid-winwing.c
··· 37 37 struct hid_device *hdev; 38 38 __u8 *report_buf; 39 39 struct mutex lock; 40 + int map_more_buttons; 40 41 unsigned int num_leds; 41 42 struct winwing_led leds[]; 42 43 }; ··· 82 81 int ret; 83 82 int i; 84 83 85 - size_t data_size = struct_size(data, leds, 3); 86 - 87 - data = devm_kzalloc(&hdev->dev, data_size, GFP_KERNEL); 84 + data = hid_get_drvdata(hdev); 88 85 89 86 if (!data) 90 - return -ENOMEM; 87 + return -EINVAL; 91 88 92 89 data->report_buf = devm_kmalloc(&hdev->dev, MAX_REPORT, GFP_KERNEL); 93 90 ··· 105 106 "%s::%s", 106 107 dev_name(&input->dev), 107 108 info->led_name); 109 + 108 110 if (!led->cdev.name) 109 111 return -ENOMEM; 110 112 ··· 114 114 return ret; 115 115 } 116 116 117 - hid_set_drvdata(hdev, data); 118 - 119 117 return ret; 118 + } 119 + 120 + static int winwing_map_button(int button, int map_more_buttons) 121 + { 122 + if (button < 1) 123 + return KEY_RESERVED; 124 + 125 + if (button > 112) 126 + return KEY_RESERVED; 127 + 128 + if (button <= 16) { 129 + /* 130 + * Grip buttons [1 .. 16] are mapped to 131 + * key codes BTN_TRIGGER .. BTN_DEAD 132 + */ 133 + return (button - 1) + BTN_JOYSTICK; 134 + } 135 + 136 + if (button >= 65) { 137 + /* 138 + * Base buttons [65 .. 112] are mapped to 139 + * key codes BTN_TRIGGER_HAPPY17 .. KEY_MAX 140 + */ 141 + return (button - 65) + BTN_TRIGGER_HAPPY17; 142 + } 143 + 144 + if (!map_more_buttons) { 145 + /* 146 + * Not mapping numbers [33 .. 64] which 147 + * are not assigned to any real buttons 148 + */ 149 + if (button >= 33) 150 + return KEY_RESERVED; 151 + /* 152 + * Grip buttons [17 .. 32] are mapped to 153 + * BTN_TRIGGER_HAPPY1 .. BTN_TRIGGER_HAPPY16 154 + */ 155 + return (button - 17) + BTN_TRIGGER_HAPPY1; 156 + } 157 + 158 + if (button >= 49) { 159 + /* 160 + * Grip buttons [49 .. 64] are mapped to 161 + * BTN_TRIGGER_HAPPY1 .. BTN_TRIGGER_HAPPY16 162 + */ 163 + return (button - 49) + BTN_TRIGGER_HAPPY1; 164 + } 165 + 166 + /* 167 + * Grip buttons [17 .. 44] are mapped to 168 + * key codes KEY_MACRO1 .. KEY_MACRO28; 169 + * also mapping numbers [45 .. 48] which 170 + * are not assigned to any real buttons. 171 + */ 172 + return (button - 17) + KEY_MACRO1; 173 + } 174 + 175 + static int winwing_input_mapping(struct hid_device *hdev, 176 + struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, 177 + unsigned long **bit, int *max) 178 + { 179 + struct winwing_drv_data *data; 180 + int code = KEY_RESERVED; 181 + int button = 0; 182 + 183 + data = hid_get_drvdata(hdev); 184 + 185 + if (!data) 186 + return -EINVAL; 187 + 188 + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON) 189 + return 0; 190 + 191 + if (field->application != HID_GD_JOYSTICK) 192 + return 0; 193 + 194 + /* Button numbers start with 1 */ 195 + button = usage->hid & HID_USAGE; 196 + 197 + code = winwing_map_button(button, data->map_more_buttons); 198 + 199 + hid_map_usage(hi, usage, bit, max, EV_KEY, code); 200 + 201 + return 1; 120 202 } 121 203 122 204 static int winwing_probe(struct hid_device *hdev, 123 205 const struct hid_device_id *id) 124 206 { 207 + struct winwing_drv_data *data; 208 + size_t data_size = struct_size(data, leds, 3); 125 209 int ret; 126 210 127 211 ret = hid_parse(hdev); ··· 213 129 hid_err(hdev, "parse failed\n"); 214 130 return ret; 215 131 } 132 + 133 + data = devm_kzalloc(&hdev->dev, data_size, GFP_KERNEL); 134 + 135 + if (!data) 136 + return -ENOMEM; 137 + 138 + data->map_more_buttons = id->driver_data; 139 + 140 + hid_set_drvdata(hdev, data); 216 141 217 142 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 218 143 if (ret) { ··· 245 152 return ret; 246 153 } 247 154 248 - static const __u8 original_rdesc_buttons[] = { 249 - 0x05, 0x09, 0x19, 0x01, 0x29, 0x6F, 250 - 0x15, 0x00, 0x25, 0x01, 0x35, 0x00, 251 - 0x45, 0x01, 0x75, 0x01, 0x95, 0x6F, 252 - 0x81, 0x02, 0x75, 0x01, 0x95, 0x01, 253 - 0x81, 0x01 254 - }; 255 - 256 - /* 257 - * HID report descriptor shows 111 buttons, which exceeds maximum 258 - * number of buttons (80) supported by Linux kernel HID subsystem. 259 - * 260 - * This module skips numbers 32-63, unused on some throttle grips. 261 - */ 262 - 263 - static const __u8 *winwing_report_fixup(struct hid_device *hdev, __u8 *rdesc, 264 - unsigned int *rsize) 265 - { 266 - int sig_length = sizeof(original_rdesc_buttons); 267 - int unused_button_numbers = 32; 268 - 269 - if (*rsize < 34) 270 - return rdesc; 271 - 272 - if (memcmp(rdesc + 8, original_rdesc_buttons, sig_length) == 0) { 273 - 274 - /* Usage Maximum */ 275 - rdesc[13] -= unused_button_numbers; 276 - 277 - /* Report Count for buttons */ 278 - rdesc[25] -= unused_button_numbers; 279 - 280 - /* Report Count for padding [HID1_11, 6.2.2.9] */ 281 - rdesc[31] += unused_button_numbers; 282 - 283 - hid_info(hdev, "winwing descriptor fixed\n"); 284 - } 285 - 286 - return rdesc; 287 - } 288 - 289 - static int winwing_raw_event(struct hid_device *hdev, 290 - struct hid_report *report, u8 *raw_data, int size) 291 - { 292 - if (size >= 15) { 293 - /* Skip buttons 32 .. 63 */ 294 - memmove(raw_data + 5, raw_data + 9, 6); 295 - 296 - /* Clear the padding */ 297 - memset(raw_data + 11, 0, 4); 298 - } 299 - 300 - return 0; 301 - } 302 - 303 155 static const struct hid_device_id winwing_devices[] = { 304 - { HID_USB_DEVICE(0x4098, 0xbe62) }, /* TGRIP-18 */ 305 - { HID_USB_DEVICE(0x4098, 0xbe68) }, /* TGRIP-16EX */ 156 + { HID_USB_DEVICE(0x4098, 0xbd65), .driver_data = 1 }, /* TGRIP-15E */ 157 + { HID_USB_DEVICE(0x4098, 0xbd64), .driver_data = 1 }, /* TGRIP-15EX */ 158 + { HID_USB_DEVICE(0x4098, 0xbe68), .driver_data = 0 }, /* TGRIP-16EX */ 159 + { HID_USB_DEVICE(0x4098, 0xbe62), .driver_data = 0 }, /* TGRIP-18 */ 306 160 {} 307 161 }; 308 162 ··· 258 218 static struct hid_driver winwing_driver = { 259 219 .name = "winwing", 260 220 .id_table = winwing_devices, 261 - .probe = winwing_probe, 262 221 .input_configured = winwing_input_configured, 263 - .report_fixup = winwing_report_fixup, 264 - .raw_event = winwing_raw_event, 222 + .input_mapping = winwing_input_mapping, 223 + .probe = winwing_probe, 265 224 }; 266 225 module_hid_driver(winwing_driver); 267 226
+58 -43
drivers/hid/intel-ish-hid/ipc/ipc.c
··· 481 481 return ret; 482 482 } 483 483 484 + static void ish_send_reset_notify_ack(struct ishtp_device *dev) 485 + { 486 + /* Read reset ID */ 487 + u32 reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF; 488 + 489 + /* 490 + * Set HOST2ISH.ILUP. Apparently we need this BEFORE sending 491 + * RESET_NOTIFY_ACK - FW will be checking for it 492 + */ 493 + ish_set_host_rdy(dev); 494 + /* Send RESET_NOTIFY_ACK (with reset_id) */ 495 + ipc_send_mng_msg(dev, MNG_RESET_NOTIFY_ACK, &reset_id, sizeof(u32)); 496 + } 497 + 484 498 #define TIME_SLICE_FOR_FW_RDY_MS 100 485 499 #define TIME_SLICE_FOR_INPUT_RDY_MS 100 486 500 #define TIMEOUT_FOR_FW_RDY_MS 2000 ··· 510 496 */ 511 497 static int ish_fw_reset_handler(struct ishtp_device *dev) 512 498 { 513 - uint32_t reset_id; 514 499 unsigned long flags; 515 500 int ret; 516 - 517 - /* Read reset ID */ 518 - reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF; 519 501 520 502 /* Clear IPC output queue */ 521 503 spin_lock_irqsave(&dev->wr_processing_spinlock, flags); ··· 530 520 531 521 /* Send clock sync at once after reset */ 532 522 ishtp_dev->prev_sync = 0; 533 - 534 - /* 535 - * Set HOST2ISH.ILUP. Apparently we need this BEFORE sending 536 - * RESET_NOTIFY_ACK - FW will be checking for it 537 - */ 538 - ish_set_host_rdy(dev); 539 - /* Send RESET_NOTIFY_ACK (with reset_id) */ 540 - ipc_send_mng_msg(dev, MNG_RESET_NOTIFY_ACK, &reset_id, 541 - sizeof(uint32_t)); 542 523 543 524 /* Wait for ISH FW'es ILUP and ISHTP_READY */ 544 525 ret = timed_wait_for_timeout(dev, WAIT_FOR_FW_RDY, ··· 564 563 if (!rv) { 565 564 /* ISH is ILUP & ISHTP-ready. Restart ISHTP */ 566 565 msleep_interruptible(TIMEOUT_FOR_HW_RDY_MS); 567 - ishtp_dev->recvd_hw_ready = 1; 568 - wake_up_interruptible(&ishtp_dev->wait_hw_ready); 569 566 570 567 /* ISHTP notification in IPC_RESET sequence completion */ 571 568 if (!work_pending(work)) ··· 624 625 break; 625 626 626 627 case MNG_RESET_NOTIFY: 627 - if (!ishtp_dev) { 628 - ishtp_dev = dev; 629 - } 630 - schedule_work(&fw_reset_work); 631 - break; 628 + ish_send_reset_notify_ack(ishtp_dev); 629 + fallthrough; 632 630 633 631 case MNG_RESET_NOTIFY_ACK: 634 632 dev->recvd_hw_ready = 1; 635 633 wake_up_interruptible(&dev->wait_hw_ready); 634 + if (!work_pending(&fw_reset_work)) 635 + queue_work(dev->unbound_wq, &fw_reset_work); 636 636 break; 637 637 } 638 638 } ··· 728 730 * ish_wakeup() - wakeup ishfw from waiting-for-host state 729 731 * @dev: ishtp device pointer 730 732 * 731 - * Set the dma enable bit and send a void message to FW, 733 + * Set the dma enable bit and send a IPC RESET message to FW, 732 734 * it wil wakeup FW from waiting-for-host state. 735 + * 736 + * Return: 0 for success else error code. 733 737 */ 734 - static void ish_wakeup(struct ishtp_device *dev) 738 + static int ish_wakeup(struct ishtp_device *dev) 735 739 { 740 + int ret; 741 + 736 742 /* Set dma enable bit */ 737 743 ish_reg_write(dev, IPC_REG_ISH_RMP2, IPC_RMP2_DMA_ENABLED); 738 744 739 745 /* 740 - * Send 0 IPC message so that ISH FW wakes up if it was already 746 + * Send IPC RESET message so that ISH FW wakes up if it was already 741 747 * asleep. 742 748 */ 743 - ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, IPC_DRBL_BUSY_BIT); 749 + ret = ish_ipc_reset(dev); 744 750 745 751 /* Flush writes to doorbell and REMAP2 */ 746 752 ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS); 753 + 754 + return ret; 747 755 } 748 756 749 757 /** ··· 798 794 pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr); 799 795 800 796 /* Now we can enable ISH DMA operation and wakeup ISHFW */ 801 - ish_wakeup(dev); 802 - 803 - return 0; 797 + return ish_wakeup(dev); 804 798 } 799 + 800 + #define RECVD_HW_READY_TIMEOUT (10 * HZ) 805 801 806 802 /** 807 803 * _ish_ipc_reset() - IPC reset ··· 837 833 } 838 834 839 835 wait_event_interruptible_timeout(dev->wait_hw_ready, 840 - dev->recvd_hw_ready, 2 * HZ); 836 + dev->recvd_hw_ready, 837 + RECVD_HW_READY_TIMEOUT); 841 838 if (!dev->recvd_hw_ready) { 842 839 dev_err(dev->devc, "Timed out waiting for HW ready\n"); 843 840 rv = -ENODEV; ··· 862 857 set_host_ready(dev); 863 858 864 859 /* After that we can enable ISH DMA operation and wakeup ISHFW */ 865 - ish_wakeup(dev); 866 - 867 - /* wait for FW-initiated reset flow */ 868 - if (!dev->recvd_hw_ready) 869 - wait_event_interruptible_timeout(dev->wait_hw_ready, 870 - dev->recvd_hw_ready, 871 - 10 * HZ); 872 - 873 - if (!dev->recvd_hw_ready) { 874 - dev_err(dev->devc, 875 - "[ishtp-ish]: Timed out waiting for FW-initiated reset\n"); 876 - return -ENODEV; 877 - } 878 - 879 - return 0; 860 + return ish_wakeup(dev); 880 861 } 881 862 882 863 /** ··· 924 933 .dma_no_cache_snooping = _dma_no_cache_snooping 925 934 }; 926 935 936 + static void ishtp_free_workqueue(void *wq) 937 + { 938 + destroy_workqueue(wq); 939 + } 940 + 941 + static struct workqueue_struct *devm_ishtp_alloc_workqueue(struct device *dev) 942 + { 943 + struct workqueue_struct *wq; 944 + 945 + wq = alloc_workqueue("ishtp_unbound_%d", WQ_UNBOUND, 0, dev->id); 946 + if (!wq) 947 + return NULL; 948 + 949 + if (devm_add_action_or_reset(dev, ishtp_free_workqueue, wq)) 950 + return NULL; 951 + 952 + return wq; 953 + } 954 + 927 955 /** 928 956 * ish_dev_init() -Initialize ISH devoce 929 957 * @pdev: PCI device ··· 961 951 sizeof(struct ishtp_device) + sizeof(struct ish_hw), 962 952 GFP_KERNEL); 963 953 if (!dev) 954 + return NULL; 955 + 956 + dev->unbound_wq = devm_ishtp_alloc_workqueue(&pdev->dev); 957 + if (!dev->unbound_wq) 964 958 return NULL; 965 959 966 960 dev->devc = &pdev->dev; ··· 996 982 list_add_tail(&tx_buf->link, &dev->wr_free_list); 997 983 } 998 984 985 + ishtp_dev = dev; 999 986 ret = devm_work_autocancel(&pdev->dev, &fw_reset_work, fw_reset_work_fn); 1000 987 if (ret) { 1001 988 dev_err(dev->devc, "Failed to initialise FW reset work\n");
+26 -5
drivers/hid/intel-ish-hid/ipc/pci-ish.c
··· 147 147 148 148 static inline bool ish_should_leave_d0i3(struct pci_dev *pdev) 149 149 { 150 + struct ishtp_device *dev = pci_get_drvdata(pdev); 151 + u32 fwsts = dev->ops->get_fw_status(dev); 152 + 153 + if (dev->suspend_flag || !IPC_IS_ISH_ILUP(fwsts)) 154 + return false; 155 + 150 156 return !pm_resume_via_firmware() || pdev->device == PCI_DEVICE_ID_INTEL_ISH_CHV; 151 157 } 152 158 ··· 283 277 { 284 278 struct pci_dev *pdev = to_pci_dev(ish_resume_device); 285 279 struct ishtp_device *dev = pci_get_drvdata(pdev); 286 - uint32_t fwsts = dev->ops->get_fw_status(dev); 287 280 288 - if (ish_should_leave_d0i3(pdev) && !dev->suspend_flag 289 - && IPC_IS_ISH_ILUP(fwsts)) { 281 + if (ish_should_leave_d0i3(pdev)) { 290 282 if (device_may_wakeup(&pdev->dev)) 291 283 disable_irq_wake(pdev->irq); 292 284 ··· 388 384 ish_resume_device = device; 389 385 dev->resume_flag = 1; 390 386 391 - schedule_work(&resume_work); 387 + /* If ISH resume from D3, reset ishtp clients before return */ 388 + if (!ish_should_leave_d0i3(pdev)) 389 + ishtp_reset_handler(dev); 390 + 391 + queue_work(dev->unbound_wq, &resume_work); 392 392 393 393 return 0; 394 394 } 395 395 396 - static SIMPLE_DEV_PM_OPS(ish_pm_ops, ish_suspend, ish_resume); 396 + static int __maybe_unused ish_freeze(struct device *device) 397 + { 398 + struct pci_dev *pdev = to_pci_dev(device); 399 + 400 + return pci_save_state(pdev); 401 + } 402 + 403 + static const struct dev_pm_ops __maybe_unused ish_pm_ops = { 404 + .suspend = pm_sleep_ptr(ish_suspend), 405 + .resume = pm_sleep_ptr(ish_resume), 406 + .freeze = pm_sleep_ptr(ish_freeze), 407 + .restore = pm_sleep_ptr(ish_resume), 408 + .poweroff = pm_sleep_ptr(ish_suspend), 409 + }; 397 410 398 411 static ssize_t base_version_show(struct device *cdev, 399 412 struct device_attribute *attr, char *buf)
+11 -4
drivers/hid/intel-ish-hid/ishtp-hid-client.c
··· 757 757 struct ishtp_cl *hid_ishtp_cl = client_data->hid_ishtp_cl; 758 758 759 759 if (ishtp_wait_resume(ishtp_get_ishtp_device(hid_ishtp_cl))) { 760 - client_data->suspended = false; 761 - wake_up_interruptible(&client_data->ishtp_resume_wait); 760 + /* 761 + * Clear the suspended flag only when the connection is established. 762 + * If the connection is not established, the suspended flag will be cleared after 763 + * the connection is made. 764 + */ 765 + if (ishtp_get_connection_state(hid_ishtp_cl) == ISHTP_CL_CONNECTED) { 766 + client_data->suspended = false; 767 + wake_up_interruptible(&client_data->ishtp_resume_wait); 768 + } 762 769 } else { 763 770 hid_ishtp_trace(client_data, "hid client: wait for resume timed out"); 764 771 dev_err(cl_data_to_dev(client_data), "wait for resume timed out"); ··· 867 860 hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, 868 861 hid_ishtp_cl); 869 862 870 - schedule_work(&client_data->work); 863 + queue_work(ishtp_get_workqueue(cl_device), &client_data->work); 871 864 872 865 return 0; 873 866 } ··· 909 902 910 903 hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, 911 904 hid_ishtp_cl); 912 - schedule_work(&client_data->resume_work); 905 + queue_work(ishtp_get_workqueue(cl_device), &client_data->resume_work); 913 906 return 0; 914 907 } 915 908
+17 -1
drivers/hid/intel-ish-hid/ishtp/bus.c
··· 541 541 return; 542 542 543 543 if (device->event_cb) 544 - schedule_work(&device->event_work); 544 + queue_work(device->ishtp_dev->unbound_wq, &device->event_work); 545 545 } 546 546 547 547 /** ··· 875 875 return device->ishtp_dev->devc; 876 876 } 877 877 EXPORT_SYMBOL(ishtp_get_pci_device); 878 + 879 + /** 880 + * ishtp_get_workqueue - Retrieve the workqueue associated with an ISHTP device 881 + * @cl_device: Pointer to the ISHTP client device structure 882 + * 883 + * Returns the workqueue_struct pointer (unbound_wq) associated with the given 884 + * ISHTP client device. This workqueue is typically used for scheduling work 885 + * related to the device. 886 + * 887 + * Return: Pointer to struct workqueue_struct. 888 + */ 889 + struct workqueue_struct *ishtp_get_workqueue(struct ishtp_cl_device *cl_device) 890 + { 891 + return cl_device->ishtp_dev->unbound_wq; 892 + } 893 + EXPORT_SYMBOL(ishtp_get_workqueue); 878 894 879 895 /** 880 896 * ishtp_trace_callback() - Return trace callback
+6
drivers/hid/intel-ish-hid/ishtp/client.c
··· 1261 1261 } 1262 1262 EXPORT_SYMBOL(ishtp_set_connection_state); 1263 1263 1264 + int ishtp_get_connection_state(struct ishtp_cl *cl) 1265 + { 1266 + return cl->state; 1267 + } 1268 + EXPORT_SYMBOL(ishtp_get_connection_state); 1269 + 1264 1270 void ishtp_cl_set_fw_client_id(struct ishtp_cl *cl, int fw_client_id) 1265 1271 { 1266 1272 cl->fw_client_id = fw_client_id;
+2 -2
drivers/hid/intel-ish-hid/ishtp/hbm.c
··· 573 573 574 574 /* Start firmware loading process if it has loader capability */ 575 575 if (version_res->host_version_supported & ISHTP_SUPPORT_CAP_LOADER) 576 - schedule_work(&dev->work_fw_loader); 576 + queue_work(dev->unbound_wq, &dev->work_fw_loader); 577 577 578 578 dev->version.major_version = HBM_MAJOR_VERSION; 579 579 dev->version.minor_version = HBM_MINOR_VERSION; ··· 864 864 dev->rd_msg_fifo_tail = (dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) % 865 865 (RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE); 866 866 spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags); 867 - schedule_work(&dev->bh_hbm_work); 867 + queue_work(dev->unbound_wq, &dev->bh_hbm_work); 868 868 eoi: 869 869 return; 870 870 }
+3
drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h
··· 175 175 struct hbm_version version; 176 176 int transfer_path; /* Choice of transfer path: IPC or DMA */ 177 177 178 + /* Alloc a dedicated unbound workqueue for ishtp device */ 179 + struct workqueue_struct *unbound_wq; 180 + 178 181 /* work structure for scheduling firmware loading tasks */ 179 182 struct work_struct work_fw_loader; 180 183 /* waitq for waiting for command response from the firmware loader */
-2
drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
··· 344 344 if (try_recover(qcdev)) 345 345 qcdev->state = QUICKI2C_DISABLED; 346 346 347 - pm_runtime_mark_last_busy(qcdev->dev); 348 347 pm_runtime_put_autosuspend(qcdev->dev); 349 348 350 349 return IRQ_HANDLED; ··· 734 735 /* Enable runtime power management */ 735 736 pm_runtime_use_autosuspend(qcdev->dev); 736 737 pm_runtime_set_autosuspend_delay(qcdev->dev, DEFAULT_AUTO_SUSPEND_DELAY_MS); 737 - pm_runtime_mark_last_busy(qcdev->dev); 738 738 pm_runtime_put_noidle(qcdev->dev); 739 739 pm_runtime_put_autosuspend(qcdev->dev); 740 740
-1
drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c
··· 72 72 break; 73 73 } 74 74 75 - pm_runtime_mark_last_busy(qcdev->dev); 76 75 pm_runtime_put_autosuspend(qcdev->dev); 77 76 78 77 return ret;
-2
drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
··· 339 339 if (try_recover(qsdev)) 340 340 qsdev->state = QUICKSPI_DISABLED; 341 341 342 - pm_runtime_mark_last_busy(qsdev->dev); 343 342 pm_runtime_put_autosuspend(qsdev->dev); 344 343 345 344 return IRQ_HANDLED; ··· 673 674 /* Enable runtime power management */ 674 675 pm_runtime_use_autosuspend(qsdev->dev); 675 676 pm_runtime_set_autosuspend_delay(qsdev->dev, DEFAULT_AUTO_SUSPEND_DELAY_MS); 676 - pm_runtime_mark_last_busy(qsdev->dev); 677 677 pm_runtime_put_noidle(qsdev->dev); 678 678 pm_runtime_put_autosuspend(qsdev->dev); 679 679
-1
drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c
··· 71 71 break; 72 72 } 73 73 74 - pm_runtime_mark_last_busy(qsdev->dev); 75 74 pm_runtime_put_autosuspend(qsdev->dev); 76 75 77 76 return ret;
+1
include/linux/hid.h
··· 984 984 extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report); 985 985 extern int hidinput_connect(struct hid_device *hid, unsigned int force); 986 986 extern void hidinput_disconnect(struct hid_device *); 987 + void hidinput_reset_resume(struct hid_device *hid); 987 988 988 989 struct hid_field *hid_find_field(struct hid_device *hdev, unsigned int report_type, 989 990 unsigned int application, unsigned int usage);
+3
include/linux/intel-ish-client-if.h
··· 87 87 ishtp_print_log ishtp_trace_callback(struct ishtp_cl_device *cl_device); 88 88 /* Get device pointer of PCI device for DMA acces */ 89 89 struct device *ishtp_get_pci_device(struct ishtp_cl_device *cl_device); 90 + /* Get the ISHTP workqueue */ 91 + struct workqueue_struct *ishtp_get_workqueue(struct ishtp_cl_device *cl_device); 90 92 91 93 struct ishtp_cl *ishtp_cl_allocate(struct ishtp_cl_device *cl_device); 92 94 void ishtp_cl_free(struct ishtp_cl *cl); ··· 109 107 void ishtp_set_tx_ring_size(struct ishtp_cl *cl, int size); 110 108 void ishtp_set_rx_ring_size(struct ishtp_cl *cl, int size); 111 109 void ishtp_set_connection_state(struct ishtp_cl *cl, int state); 110 + int ishtp_get_connection_state(struct ishtp_cl *cl); 112 111 void ishtp_cl_set_fw_client_id(struct ishtp_cl *cl, int fw_client_id); 113 112 114 113 void ishtp_put_device(struct ishtp_cl_device *cl_dev);
+71
tools/testing/selftests/hid/tests/test_tablet.py
··· 452 452 def __init__(self, x, y): 453 453 self.x = x 454 454 self.y = y 455 + self.distance = -10 455 456 self.tipswitch = False 456 457 self.tippressure = 15 457 458 self.azimuth = 0 ··· 474 473 for i in [ 475 474 "x", 476 475 "y", 476 + "distance", 477 477 "tippressure", 478 478 "azimuth", 479 479 "width", ··· 556 554 pen.tipswitch = False 557 555 pen.tippressure = 0 558 556 pen.azimuth = 0 557 + pen.distance = 0 559 558 pen.inrange = False 560 559 pen.width = 0 561 560 pen.height = 0 ··· 870 867 touching and erasing if the tablet doesn't enforce the Windows 871 868 state machine.""" 872 869 self._test_states(state_list, scribble, allow_intermediate_states=True) 870 + 871 + @pytest.mark.skip_if_uhdev( 872 + lambda uhdev: "Z" not in uhdev.fields, 873 + "Device not compatible, missing Z usage", 874 + ) 875 + @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"]) 876 + @pytest.mark.parametrize( 877 + "state_list", 878 + [pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()], 879 + ) 880 + def test_z_reported_as_distance(self, state_list, scribble): 881 + """Verify stylus Z values are reported as ABS_DISTANCE.""" 882 + self._test_states(state_list, scribble, allow_intermediate_states=False) 883 + 884 + uhdev = self.uhdev 885 + evdev = uhdev.get_evdev() 886 + p = Pen(0, 0) 887 + uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE, None) 888 + p = Pen(100, 200) 889 + uhdev.move_to(p, PenState.PEN_IS_IN_RANGE, None) 890 + p.distance = -1 891 + events = self.post(uhdev, p, None) 892 + assert evdev.value[libevdev.EV_ABS.ABS_DISTANCE] == -1 873 893 874 894 875 895 class GXTP_pen(PenDigitizer): ··· 1318 1292 return rs 1319 1293 1320 1294 1295 + class Wacom_2d1f_014b(PenDigitizer): 1296 + """ 1297 + Pen that reports distance values with HID_GD_Z usage. 1298 + """ 1299 + def __init__( 1300 + self, 1301 + name, 1302 + rdesc_str=None, 1303 + rdesc=None, 1304 + application="Pen", 1305 + physical="Stylus", 1306 + input_info=(BusType.USB, 0x2D1F, 0x014B), 1307 + evdev_name_suffix=None, 1308 + ): 1309 + super().__init__( 1310 + name, rdesc_str, rdesc, application, physical, input_info, evdev_name_suffix 1311 + ) 1312 + 1313 + def match_evdev_rule(self, application, evdev): 1314 + # there are 2 nodes created by the device, only one matters 1315 + return evdev.name.endswith("Stylus") 1316 + 1317 + def event(self, pen, test_button): 1318 + # this device reports the distance through Z 1319 + pen.z = pen.distance 1320 + 1321 + return super().event(pen, test_button) 1322 + 1323 + 1321 1324 ################################################################################ 1322 1325 # 1323 1326 # Windows 7 compatible devices ··· 1558 1503 "uhid test HUION Huion Tablet_GT1902", 1559 1504 rdesc="05 0d 09 02 a1 01 85 0a 09 20 a1 01 09 42 09 44 09 43 09 3c 09 45 15 00 25 01 75 01 95 06 81 02 09 32 75 01 95 01 81 02 81 03 05 01 09 30 09 31 55 0d 65 33 26 ff 7f 35 00 46 00 08 75 10 95 02 81 02 05 0d 09 30 26 ff 3f 75 10 95 01 81 02 09 3d 09 3e 15 a6 25 5a 75 08 95 02 81 02 c0 c0 05 0d 09 04 a1 01 85 04 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 56 55 00 65 00 27 ff ff ff 7f 95 01 75 20 81 02 09 54 25 7f 95 01 75 08 81 02 75 08 95 08 81 03 85 05 09 55 25 0a 75 08 95 01 b1 02 06 00 ff 09 c5 85 06 15 00 26 ff 00 75 08 96 00 01 b1 02 c0", 1560 1505 input_info=(BusType.USB, 0x256C, 0x006B), 1506 + ) 1507 + 1508 + 1509 + ################################################################################ 1510 + # 1511 + # Devices Reporting Distance 1512 + # 1513 + ################################################################################ 1514 + 1515 + 1516 + class TestWacom_2d1f_014b(BaseTest.TestTablet): 1517 + def create_device(self): 1518 + return Wacom_2d1f_014b( 1519 + "uhid test Wacom 2d1f_014b", 1520 + rdesc="05 0d 09 02 a1 01 85 02 09 20 a1 00 09 42 09 44 09 45 09 3c 09 5a 09 32 15 00 25 01 75 01 95 06 81 02 95 02 81 03 05 01 09 30 26 88 3e 46 88 3e 65 11 55 0d 75 10 95 01 81 02 09 31 26 60 53 46 60 53 81 02 05 0d 09 30 26 ff 0f 45 00 65 00 55 00 81 02 06 00 ff 09 04 75 08 26 ff 00 46 ff 00 65 11 55 0e 81 02 05 0d 09 3d 75 10 16 d8 dc 26 28 23 36 d8 dc 46 28 23 65 14 81 02 09 3e 81 02 05 01 09 32 16 01 ff 25 00 36 01 ff 45 00 65 11 81 02 05 0d 09 56 15 00 27 ff ff 00 00 35 00 47 ff ff 00 00 66 01 10 55 0c 81 02 45 00 65 00 55 00 c0 09 00 75 08 26 ff 00 b1 12 85 03 09 00 95 12 b1 12 85 05 09 00 95 04 b1 02 85 06 09 00 95 24 b1 02 85 16 09 00 15 00 26 ff 00 95 06 b1 02 85 17 09 00 95 0c b1 02 85 19 09 00 95 01 b1 02 85 0a 09 00 75 08 95 01 15 10 26 ff 00 b1 02 85 1e 09 00 95 10 b1 02 c0 06 00 ff 09 00 a1 01 85 09 05 0d 09 20 a1 00 09 00 15 00 26 ff 00 75 08 95 10 81 02 c0 09 00 95 03 b1 12 c0 06 00 ff 09 02 a1 01 85 07 09 00 96 09 01 b1 02 85 08 09 00 95 03 81 02 09 00 b1 02 85 0e 09 00 96 0a 01 b1 02 c0 05 0d 09 02 a1 01 85 1a 09 20 a1 00 09 42 09 44 09 45 09 3c 09 5a 09 32 15 00 25 01 75 01 95 06 81 02 09 38 25 03 75 02 95 01 81 02 05 01 09 30 26 88 3e 46 88 3e 65 11 55 0d 75 10 95 01 81 02 09 31 26 60 53 46 60 53 81 02 05 0d 09 30 26 ff 0f 46 b0 0f 66 11 e1 55 02 81 02 06 00 ff 09 04 75 08 26 ff 00 46 ff 00 65 11 55 0e 81 02 05 0d 09 3d 75 10 16 d8 dc 26 28 23 36 d8 dc 46 28 23 65 14 81 02 09 3e 81 02 05 01 09 32 16 01 ff 25 00 36 01 ff 45 00 65 11 81 02 05 0d 09 56 15 00 27 ff ff 00 00 35 00 47 ff ff 00 00 66 01 10 55 0c 81 02 45 00 65 00 55 00 c0 c0 06 00 ff 09 00 a1 01 85 1b 05 0d 09 20 a1 00 09 00 26 ff 00 75 08 95 10 81 02 c0 c0", 1521 + input_info=(BusType.USB, 0x2D1F, 0x014B), 1561 1522 )