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

selftests: hid: import hid-tools wacom tests

These tests have been developed in the hid-tools[0] tree for a while.
Now that we have a proper selftests/hid kernel entry and that the tests
are more reliable, it is time to directly include those in the kernel
tree.

[0] https://gitlab.freedesktop.org/libevdev/hid-tools

Cc: Jason Gerecke <killertofu@gmail.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

+2215
+1
tools/testing/selftests/hid/Makefile
··· 11 11 TEST_PROGS += hid-mouse.sh 12 12 TEST_PROGS += hid-multitouch.sh 13 13 TEST_PROGS += hid-tablet.sh 14 + TEST_PROGS += hid-wacom.sh 14 15 15 16 CXX ?= $(CROSS_COMPILE)g++ 16 17
+3
tools/testing/selftests/hid/config
··· 20 20 CONFIG_HID_BPF=y 21 21 CONFIG_INPUT_EVDEV=y 22 22 CONFIG_UHID=y 23 + CONFIG_USB=y 24 + CONFIG_USB_HID=y 23 25 CONFIG_HID_MULTITOUCH=y 26 + CONFIG_HID_WACOM=y
+7
tools/testing/selftests/hid/hid-wacom.sh
··· 1 + #!/bin/sh 2 + # SPDX-License-Identifier: GPL-2.0 3 + # Runs tests for the HID subsystem 4 + 5 + export TARGET=test_wacom_generic.py 6 + 7 + bash ./run-hid-tools-tests.sh
+1360
tools/testing/selftests/hid/tests/descriptors_wacom.py
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + # fmt: off 4 + wacom_pth660_v145 = [ 5 + 0x05, 0x01, # . Usage Page (Desktop), 6 + 0x09, 0x02, # . Usage (Mouse), 7 + 0xA1, 0x01, # . Collection (Application), 8 + 0x85, 0x01, # . Report ID (1), 9 + 0x09, 0x01, # . Usage (Pointer), 10 + 0xA1, 0x00, # . Collection (Physical), 11 + 0x05, 0x09, # . Usage Page (Button), 12 + 0x19, 0x01, # . Usage Minimum (01h), 13 + 0x29, 0x03, # . Usage Maximum (03h), 14 + 0x15, 0x00, # . Logical Minimum (0), 15 + 0x25, 0x01, # . Logical Maximum (1), 16 + 0x75, 0x01, # . Report Size (1), 17 + 0x95, 0x03, # . Report Count (3), 18 + 0x81, 0x02, # . Input (Variable), 19 + 0x75, 0x01, # . Report Size (1), 20 + 0x95, 0x05, # . Report Count (5), 21 + 0x81, 0x03, # . Input (Constant, Variable), 22 + 0x05, 0x01, # . Usage Page (Desktop), 23 + 0x09, 0x30, # . Usage (X), 24 + 0x09, 0x31, # . Usage (Y), 25 + 0x15, 0x81, # . Logical Minimum (-127), 26 + 0x25, 0x7F, # . Logical Maximum (127), 27 + 0x75, 0x08, # . Report Size (8), 28 + 0x95, 0x02, # . Report Count (2), 29 + 0x81, 0x06, # . Input (Variable, Relative), 30 + 0xC0, # . End Collection, 31 + 0xC0, # . End Collection, 32 + 0x06, 0x0D, 0xFF, # . Usage Page (FF0Dh), 33 + 0x09, 0x01, # . Usage (01h), 34 + 0xA1, 0x01, # . Collection (Application), 35 + 0x85, 0x10, # . Report ID (16), 36 + 0x09, 0x20, # . Usage (20h), 37 + 0xA1, 0x00, # . Collection (Physical), 38 + 0x09, 0x42, # . Usage (42h), 39 + 0x09, 0x44, # . Usage (44h), 40 + 0x09, 0x5A, # . Usage (5Ah), 41 + 0x09, 0x45, # . Usage (45h), 42 + 0x09, 0x3C, # . Usage (3Ch), 43 + 0x09, 0x32, # . Usage (32h), 44 + 0x09, 0x36, # . Usage (36h), 45 + 0x15, 0x00, # . Logical Minimum (0), 46 + 0x25, 0x01, # . Logical Maximum (1), 47 + 0x75, 0x01, # . Report Size (1), 48 + 0x95, 0x07, # . Report Count (7), 49 + 0x81, 0x02, # . Input (Variable), 50 + 0x95, 0x01, # . Report Count (1), 51 + 0x81, 0x03, # . Input (Constant, Variable), 52 + 0x0A, 0x30, 0x01, # . Usage (0130h), 53 + 0x65, 0x11, # . Unit (Centimeter), 54 + 0x55, 0x0D, # . Unit Exponent (13), 55 + 0x35, 0x00, # . Physical Minimum (0), 56 + 0x47, 0x80, 0x57, 0x00, 0x00, # . Physical Maximum (22400), 57 + 0x15, 0x00, # . Logical Minimum (0), 58 + 0x27, 0x00, 0xAF, 0x00, 0x00, # . Logical Maximum (44800), 59 + 0x75, 0x18, # . Report Size (24), 60 + 0x95, 0x01, # . Report Count (1), 61 + 0x81, 0x02, # . Input (Variable), 62 + 0x0A, 0x31, 0x01, # . Usage (0131h), 63 + 0x47, 0xD0, 0x39, 0x00, 0x00, # . Physical Maximum (14800), 64 + 0x27, 0xA0, 0x73, 0x00, 0x00, # . Logical Maximum (29600), 65 + 0x81, 0x02, # . Input (Variable), 66 + 0x09, 0x30, # . Usage (30h), 67 + 0x55, 0x00, # . Unit Exponent (0), 68 + 0x65, 0x00, # . Unit, 69 + 0x15, 0x00, # . Logical Minimum (0), 70 + 0x26, 0xFF, 0x1F, # . Logical Maximum (8191), # !!! Errata: Missing Physical Max = 0 71 + 0x75, 0x10, # . Report Size (16), 72 + 0x81, 0x02, # . Input (Variable), 73 + 0x09, 0x3D, # . Usage (3Dh), 74 + 0x09, 0x3E, # . Usage (3Eh), 75 + 0x65, 0x14, # . Unit (Degrees), 76 + 0x55, 0x00, # . Unit Exponent (0), 77 + 0x35, 0xC0, # . Physical Minimum (-64), 78 + 0x45, 0x3F, # . Physical Maximum (63), 79 + 0x15, 0xC0, # . Logical Minimum (-64), 80 + 0x25, 0x3F, # . Logical Maximum (63), 81 + 0x75, 0x08, # . Report Size (8), 82 + 0x95, 0x02, # . Report Count (2), 83 + 0x81, 0x02, # . Input (Variable), 84 + 0x09, 0x41, # . Usage (41h), 85 + 0x65, 0x14, # . Unit (Degrees), 86 + 0x55, 0x00, # . Unit Exponent (0), 87 + 0x36, 0x4C, 0xFF, # . Physical Minimum (-180), 88 + 0x46, 0xB3, 0x00, # . Physical Maximum (179), 89 + 0x16, 0x7C, 0xFC, # . Logical Minimum (-900), 90 + 0x26, 0x83, 0x03, # . Logical Maximum (899), 91 + 0x75, 0x10, # . Report Size (16), 92 + 0x95, 0x01, # . Report Count (1), 93 + 0x81, 0x0A, # . Input (Variable, Wrap), 94 + 0x0A, 0x03, 0x0D, # . Usage (0D03h), 95 + 0x65, 0x00, # . Unit, 96 + 0x55, 0x00, # . Unit Exponent (0), 97 + 0x15, 0x00, # . Logical Minimum (0), 98 + 0x26, 0xFF, 0x07, # . Logical Maximum (2047), # !!! Errata: Missing Physical Min/Max = 0 99 + 0x75, 0x10, # . Report Size (16), 100 + 0x95, 0x01, # . Report Count (1), 101 + 0x81, 0x02, # . Input (Variable), 102 + 0x0A, 0x32, 0x01, # . Usage (0132h), 103 + 0x15, 0x00, # . Logical Minimum (0), 104 + 0x25, 0x3F, # . Logical Maximum (63), 105 + 0x75, 0x08, # . Report Size (8), 106 + 0x95, 0x01, # . Report Count (1), 107 + 0x81, 0x02, # . Input (Variable), 108 + 0x09, 0x5B, # . Usage (5Bh), 109 + 0x09, 0x5C, # . Usage (5Ch), 110 + 0x17, 0x00, 0x00, 0x00, 0x80, # . Logical Minimum (-2147483648), 111 + 0x27, 0xFF, 0xFF, 0xFF, 0x7F, # . Logical Maximum (2147483647), 112 + 0x75, 0x20, # . Report Size (32), 113 + 0x95, 0x02, # . Report Count (2), 114 + 0x81, 0x02, # . Input (Variable), 115 + 0x09, 0x77, # . Usage (77h), 116 + 0x15, 0x00, # . Logical Minimum (0), 117 + 0x26, 0xFF, 0x0F, # . Logical Maximum (4095), 118 + 0x75, 0x10, # . Report Size (16), 119 + 0x95, 0x01, # . Report Count (1), 120 + 0x81, 0x02, # . Input (Variable), 121 + 0xC0, # . End Collection, 122 + 0x85, 0x11, # . Report ID (17), 123 + 0x09, 0x39, # . Usage (39h), 124 + 0xA1, 0x00, # . Collection (Physical), 125 + 0x1A, 0x10, 0x09, # . Usage Minimum (0910h), 126 + 0x2A, 0x17, 0x09, # . Usage Maximum (0917h), 127 + 0x15, 0x00, # . Logical Minimum (0), 128 + 0x25, 0x01, # . Logical Maximum (1), 129 + 0x75, 0x01, # . Report Size (1), 130 + 0x95, 0x08, # . Report Count (8), 131 + 0x81, 0x02, # . Input (Variable), 132 + 0x1A, 0x40, 0x09, # . Usage Minimum (0940h), 133 + 0x2A, 0x47, 0x09, # . Usage Maximum (0947h), 134 + 0x81, 0x02, # . Input (Variable), 135 + 0x0A, 0x95, 0x09, # . Usage (0995h), 136 + 0x95, 0x01, # . Report Count (1), 137 + 0x81, 0x02, # . Input (Variable), 138 + 0x95, 0x07, # . Report Count (7), 139 + 0x81, 0x03, # . Input (Constant, Variable), 140 + 0x0A, 0x38, 0x01, # . Usage (0138h), 141 + 0x65, 0x14, # . Unit (Degrees), 142 + 0x55, 0x00, # . Unit Exponent (0), 143 + 0x35, 0x00, # . Physical Minimum (0), 144 + 0x46, 0x67, 0x01, # . Physical Maximum (359), 145 + 0x15, 0x00, # . Logical Minimum (0), 146 + 0x25, 0x47, # . Logical Maximum (71), 147 + 0x75, 0x07, # . Report Size (7), 148 + 0x95, 0x01, # . Report Count (1), 149 + 0x81, 0x0A, # . Input (Variable, Wrap), 150 + 0x0A, 0x39, 0x01, # . Usage (0139h), 151 + 0x65, 0x00, # . Unit, 152 + 0x55, 0x00, # . Unit Exponent (0), 153 + 0x25, 0x01, # . Logical Maximum (1), # !!! Errata: Missing Physical Max = 0 154 + 0x75, 0x01, # . Report Size (1), 155 + 0x95, 0x01, # . Report Count (1), 156 + 0x81, 0x02, # . Input (Variable), 157 + 0x75, 0x08, # . Report Size (8), 158 + 0x95, 0x04, # . Report Count (4), 159 + 0x81, 0x03, # . Input (Constant, Variable), 160 + 0xC0, # . End Collection, 161 + 0x85, 0x13, # . Report ID (19), 162 + 0x0A, 0x13, 0x10, # . Usage (1013h), 163 + 0xA1, 0x00, # . Collection (Physical), 164 + 0x0A, 0x3B, 0x04, # . Usage (043Bh), 165 + 0x15, 0x00, # . Logical Minimum (0), 166 + 0x25, 0x64, # . Logical Maximum (100), 167 + 0x75, 0x07, # . Report Size (7), 168 + 0x95, 0x01, # . Report Count (1), 169 + 0x81, 0x02, # . Input (Variable), 170 + 0x0A, 0x04, 0x04, # . Usage (0404h), 171 + 0x25, 0x01, # . Logical Maximum (1), 172 + 0x75, 0x01, # . Report Size (1), 173 + 0x81, 0x02, # . Input (Variable), 174 + 0x0A, 0x52, 0x04, # . Usage (0452h), 175 + 0x15, 0x00, # . Logical Minimum (0), 176 + 0x25, 0x01, # . Logical Maximum (1), 177 + 0x75, 0x01, # . Report Size (1), 178 + 0x95, 0x01, # . Report Count (1), 179 + 0x81, 0x02, # . Input (Variable), 180 + 0x95, 0x06, # . Report Count (6), 181 + 0x81, 0x03, # . Input (Constant, Variable), 182 + 0x0A, 0x54, 0x04, # . Usage (0454h), 183 + 0x95, 0x01, # . Report Count (1), 184 + 0x81, 0x02, # . Input (Variable), 185 + 0x75, 0x08, # . Report Size (8), 186 + 0x95, 0x06, # . Report Count (6), 187 + 0x81, 0x03, # . Input (Constant, Variable), 188 + 0xC0, # . End Collection, 189 + 0x09, 0x0E, # . Usage (0Eh), 190 + 0xA1, 0x02, # . Collection (Logical), 191 + 0x15, 0x00, # . Logical Minimum (0), 192 + 0x85, 0x02, # . Report ID (2), 193 + 0x09, 0x01, # . Usage (01h), 194 + 0x75, 0x08, # . Report Size (8), 195 + 0x25, 0x01, # . Logical Maximum (1), 196 + 0x95, 0x01, # . Report Count (1), 197 + 0xB1, 0x02, # . Feature (Variable), 198 + 0x85, 0x03, # . Report ID (3), 199 + 0x0A, 0x03, 0x10, # . Usage (1003h), 200 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 201 + 0x95, 0x01, # . Report Count (1), 202 + 0xB1, 0x02, # . Feature (Variable), 203 + 0x85, 0x04, # . Report ID (4), 204 + 0x0A, 0x04, 0x10, # . Usage (1004h), 205 + 0x25, 0x01, # . Logical Maximum (1), 206 + 0x95, 0x01, # . Report Count (1), 207 + 0xB1, 0x02, # . Feature (Variable), 208 + 0x85, 0x07, # . Report ID (7), 209 + 0x0A, 0x09, 0x10, # . Usage (1009h), 210 + 0x25, 0x02, # . Logical Maximum (2), 211 + 0x95, 0x01, # . Report Count (1), 212 + 0xB1, 0x02, # . Feature (Variable), 213 + 0x95, 0x01, # . Report Count (1), 214 + 0xB1, 0x03, # . Feature (Constant, Variable), 215 + 0x0A, 0x07, 0x10, # . Usage (1007h), 216 + 0x09, 0x00, # . Usage (00h), 217 + 0x0A, 0x08, 0x10, # . Usage (1008h), 218 + 0x09, 0x00, # . Usage (00h), 219 + 0x09, 0x00, # . Usage (00h), 220 + 0x09, 0x00, # . Usage (00h), 221 + 0x27, 0xFF, 0xFF, 0x00, 0x00, # . Logical Maximum (65535), 222 + 0x75, 0x10, # . Report Size (16), 223 + 0x95, 0x06, # . Report Count (6), 224 + 0xB1, 0x02, # . Feature (Variable), 225 + 0x75, 0x08, # . Report Size (8), 226 + 0x95, 0x01, # . Report Count (1), 227 + 0xB1, 0x03, # . Feature (Constant, Variable), 228 + 0x85, 0x0C, # . Report ID (12), 229 + 0x0A, 0x30, 0x0D, # . Usage (0D30h), 230 + 0x0A, 0x31, 0x0D, # . Usage (0D31h), 231 + 0x0A, 0x32, 0x0D, # . Usage (0D32h), 232 + 0x0A, 0x33, 0x0D, # . Usage (0D33h), # !!! Errata: Missing Non-zero Physical Max 233 + 0x65, 0x11, # . Unit (Centimeter), 234 + 0x55, 0x0D, # . Unit Exponent (13), 235 + 0x75, 0x10, # . Report Size (16), 236 + 0x95, 0x04, # . Report Count (4), 237 + 0xB1, 0x03, # . Feature (Constant, Variable), 238 + 0x85, 0x0D, # . Report ID (13), 239 + 0x65, 0x00, # . Unit, 240 + 0x55, 0x00, # . Unit Exponent (0), 241 + 0x0A, 0x0D, 0x10, # . Usage (100Dh), 242 + 0x15, 0x00, # . Logical Minimum (0), 243 + 0x25, 0x01, # . Logical Maximum (1), 244 + 0x75, 0x08, # . Report Size (8), 245 + 0x95, 0x01, # . Report Count (1), 246 + 0xB1, 0x02, # . Feature (Variable), 247 + 0x85, 0x14, # . Report ID (20), 248 + 0x0A, 0x14, 0x10, # . Usage (1014h), 249 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 250 + 0x95, 0x0D, # . Report Count (13), 251 + 0xB1, 0x02, # . Feature (Variable), 252 + 0x85, 0x31, # . Report ID (49), 253 + 0x0A, 0x31, 0x10, # . Usage (1031h), 254 + 0x25, 0x64, # . Logical Maximum (100), 255 + 0x95, 0x05, # . Report Count (5), 256 + 0xB1, 0x02, # . Feature (Variable), 257 + 0x85, 0x32, # . Report ID (50), 258 + 0x0A, 0x31, 0x10, # . Usage (1031h), 259 + 0x25, 0x64, # . Logical Maximum (100), 260 + 0x95, 0x01, # . Report Count (1), 261 + 0xB1, 0x02, # . Feature (Variable), 262 + 0x0A, 0x32, 0x10, # . Usage (1032h), 263 + 0x25, 0x03, # . Logical Maximum (3), 264 + 0xB1, 0x02, # . Feature (Variable), 265 + 0x85, 0x34, # . Report ID (52), 266 + 0x0A, 0x34, 0x10, # . Usage (1034h), 267 + 0x25, 0x01, # . Logical Maximum (1), 268 + 0x95, 0x04, # . Report Count (4), 269 + 0xB1, 0x02, # . Feature (Variable), 270 + 0x85, 0x35, # . Report ID (53), 271 + 0x0A, 0x35, 0x10, # . Usage (1035h), 272 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 273 + 0x95, 0x0A, # . Report Count (10), 274 + 0xB1, 0x02, # . Feature (Variable), 275 + 0x85, 0x36, # . Report ID (54), 276 + 0x0A, 0x35, 0x10, # . Usage (1035h), 277 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 278 + 0x96, 0x01, 0x01, # . Report Count (257), 279 + 0xB1, 0x02, # . Feature (Variable), 280 + 0x85, 0xCC, # . Report ID (204), 281 + 0x0A, 0xCC, 0x10, # . Usage (10CCh), 282 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 283 + 0x95, 0x02, # . Report Count (2), 284 + 0xB1, 0x02, # . Feature (Variable), 285 + 0xC0, # . End Collection, 286 + 0x0A, 0xAC, 0x10, # . Usage (10ACh), 287 + 0xA1, 0x02, # . Collection (Logical), 288 + 0x15, 0x00, # . Logical Minimum (0), 289 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 290 + 0x75, 0x08, # . Report Size (8), 291 + 0x85, 0xAC, # . Report ID (172), 292 + 0x09, 0x00, # . Usage (00h), 293 + 0x95, 0xBF, # . Report Count (191), 294 + 0x81, 0x02, # . Input (Variable), 295 + 0x85, 0x33, # . Report ID (51), 296 + 0x09, 0x00, # . Usage (00h), 297 + 0x95, 0x12, # . Report Count (18), 298 + 0xB1, 0x02, # . Feature (Variable), 299 + 0x85, 0x64, # . Report ID (100), 300 + 0x09, 0x00, # . Usage (00h), 301 + 0x95, 0x0C, # . Report Count (12), 302 + 0xB1, 0x02, # . Feature (Variable), 303 + 0x85, 0x15, # . Report ID (21), 304 + 0x09, 0x00, # . Usage (00h), 305 + 0x95, 0x0E, # . Report Count (14), 306 + 0xB1, 0x02, # . Feature (Variable), 307 + 0x85, 0x12, # . Report ID (18), 308 + 0x09, 0x00, # . Usage (00h), 309 + 0x95, 0x04, # . Report Count (4), 310 + 0xB1, 0x02, # . Feature (Variable), 311 + 0x85, 0x16, # . Report ID (22), 312 + 0x09, 0x00, # . Usage (00h), 313 + 0x95, 0x0E, # . Report Count (14), 314 + 0xB1, 0x02, # . Feature (Variable), 315 + 0x85, 0x40, # . Report ID (64), 316 + 0x09, 0x00, # . Usage (00h), 317 + 0x95, 0x01, # . Report Count (1), 318 + 0xB1, 0x02, # . Feature (Variable), 319 + 0x85, 0x41, # . Report ID (65), 320 + 0x09, 0x00, # . Usage (00h), 321 + 0x95, 0x01, # . Report Count (1), 322 + 0xB1, 0x02, # . Feature (Variable), 323 + 0x85, 0x42, # . Report ID (66), 324 + 0x09, 0x00, # . Usage (00h), 325 + 0x95, 0x04, # . Report Count (4), 326 + 0xB1, 0x02, # . Feature (Variable), 327 + 0x85, 0x43, # . Report ID (67), 328 + 0x09, 0x00, # . Usage (00h), 329 + 0x95, 0x0D, # . Report Count (13), 330 + 0xB1, 0x02, # . Feature (Variable), 331 + 0x85, 0x44, # . Report ID (68), 332 + 0x09, 0x00, # . Usage (00h), 333 + 0x95, 0x3F, # . Report Count (63), 334 + 0xB1, 0x02, # . Feature (Variable), 335 + 0x85, 0x45, # . Report ID (69), 336 + 0x09, 0x00, # . Usage (00h), 337 + 0x95, 0x20, # . Report Count (32), 338 + 0xB1, 0x02, # . Feature (Variable), 339 + 0x85, 0x60, # . Report ID (96), 340 + 0x09, 0x00, # . Usage (00h), 341 + 0x95, 0x3F, # . Report Count (63), 342 + 0xB1, 0x02, # . Feature (Variable), 343 + 0x85, 0x61, # . Report ID (97), 344 + 0x09, 0x00, # . Usage (00h), 345 + 0x95, 0x3E, # . Report Count (62), 346 + 0xB1, 0x02, # . Feature (Variable), 347 + 0x85, 0x62, # . Report ID (98), 348 + 0x09, 0x00, # . Usage (00h), 349 + 0x95, 0x3E, # . Report Count (62), 350 + 0xB1, 0x02, # . Feature (Variable), 351 + 0xC0, # . End Collection, 352 + 0x85, 0xD0, # . Report ID (208), 353 + 0x09, 0x01, # . Usage (01h), 354 + 0x96, 0x08, 0x00, # . Report Count (8), 355 + 0xB1, 0x02, # . Feature (Variable), 356 + 0x85, 0xD1, # . Report ID (209), 357 + 0x09, 0x01, # . Usage (01h), 358 + 0x96, 0x04, 0x01, # . Report Count (260), 359 + 0xB1, 0x02, # . Feature (Variable), 360 + 0x85, 0xD2, # . Report ID (210), 361 + 0x09, 0x01, # . Usage (01h), 362 + 0x96, 0x04, 0x01, # . Report Count (260), 363 + 0xB1, 0x02, # . Feature (Variable), 364 + 0x85, 0xD3, # . Report ID (211), 365 + 0x09, 0x01, # . Usage (01h), 366 + 0x96, 0x04, 0x00, # . Report Count (4), 367 + 0xB1, 0x02, # . Feature (Variable), 368 + 0x85, 0xD4, # . Report ID (212), 369 + 0x09, 0x01, # . Usage (01h), 370 + 0x96, 0x04, 0x00, # . Report Count (4), 371 + 0xB1, 0x02, # . Feature (Variable), 372 + 0x85, 0xD5, # . Report ID (213), 373 + 0x09, 0x01, # . Usage (01h), 374 + 0x96, 0x04, 0x00, # . Report Count (4), 375 + 0xB1, 0x02, # . Feature (Variable), 376 + 0x85, 0xD6, # . Report ID (214), 377 + 0x09, 0x01, # . Usage (01h), 378 + 0x96, 0x04, 0x00, # . Report Count (4), 379 + 0xB1, 0x02, # . Feature (Variable), 380 + 0x85, 0xD7, # . Report ID (215), 381 + 0x09, 0x01, # . Usage (01h), 382 + 0x96, 0x08, 0x00, # . Report Count (8), 383 + 0xB1, 0x02, # . Feature (Variable), 384 + 0x85, 0xD8, # . Report ID (216), 385 + 0x09, 0x01, # . Usage (01h), 386 + 0x96, 0x0C, 0x00, # . Report Count (12), 387 + 0xB1, 0x02, # . Feature (Variable), 388 + 0x85, 0xD9, # . Report ID (217), 389 + 0x09, 0x01, # . Usage (01h), 390 + 0x96, 0x00, 0x0A, # . Report Count (2560), 391 + 0xB1, 0x02, # . Feature (Variable), 392 + 0x85, 0xDA, # . Report ID (218), 393 + 0x09, 0x01, # . Usage (01h), 394 + 0x96, 0x04, 0x04, # . Report Count (1028), 395 + 0xB1, 0x02, # . Feature (Variable), 396 + 0x85, 0xDB, # . Report ID (219), 397 + 0x09, 0x01, # . Usage (01h), 398 + 0x96, 0x06, 0x00, # . Report Count (6), 399 + 0xB1, 0x02, # . Feature (Variable), 400 + 0x85, 0xDC, # . Report ID (220), 401 + 0x09, 0x01, # . Usage (01h), 402 + 0x96, 0x02, 0x00, # . Report Count (2), 403 + 0xB1, 0x02, # . Feature (Variable), 404 + 0x85, 0xDD, # . Report ID (221), 405 + 0x09, 0x01, # . Usage (01h), 406 + 0x96, 0x04, 0x00, # . Report Count (4), 407 + 0xB1, 0x02, # . Feature (Variable), 408 + 0x85, 0xDE, # . Report ID (222), 409 + 0x09, 0x01, # . Usage (01h), 410 + 0x96, 0x04, 0x00, # . Report Count (4), 411 + 0xB1, 0x02, # . Feature (Variable), 412 + 0x85, 0xDF, # . Report ID (223), 413 + 0x09, 0x01, # . Usage (01h), 414 + 0x96, 0x22, 0x00, # . Report Count (34), 415 + 0xB1, 0x02, # . Feature (Variable), 416 + 0x85, 0xE0, # . Report ID (224), 417 + 0x09, 0x01, # . Usage (01h), 418 + 0x96, 0x01, 0x00, # . Report Count (1), 419 + 0xB1, 0x02, # . Feature (Variable), 420 + 0x85, 0xE1, # . Report ID (225), 421 + 0x09, 0x01, # . Usage (01h), 422 + 0x96, 0x02, 0x00, # . Report Count (2), 423 + 0xB1, 0x02, # . Feature (Variable), 424 + 0x85, 0xE2, # . Report ID (226), 425 + 0x09, 0x01, # . Usage (01h), 426 + 0x96, 0x02, 0x00, # . Report Count (2), 427 + 0xB1, 0x02, # . Feature (Variable), 428 + 0x85, 0xE3, # . Report ID (227), 429 + 0x09, 0x01, # . Usage (01h), 430 + 0x96, 0x02, 0x00, # . Report Count (2), 431 + 0xB1, 0x02, # . Feature (Variable), 432 + 0x85, 0xE4, # . Report ID (228), 433 + 0x09, 0x01, # . Usage (01h), 434 + 0x96, 0xFF, 0x01, # . Report Count (511), 435 + 0xB1, 0x02, # . Feature (Variable), 436 + 0xC0 # . End Collection 437 + ] 438 + # fmt: on 439 + 440 + # Report ID (20), Usage (1014h), Report Count (13) -> 15 441 + wacom_pth660_v150 = wacom_pth660_v145.copy() 442 + wacom_pth660_v150[0x2CB] = 0x0F 443 + 444 + # fmt: off 445 + wacom_pth860_v145 = [ 446 + 0x05, 0x01, # . Usage Page (Desktop), 447 + 0x09, 0x02, # . Usage (Mouse), 448 + 0xA1, 0x01, # . Collection (Application), 449 + 0x85, 0x01, # . Report ID (1), 450 + 0x09, 0x01, # . Usage (Pointer), 451 + 0xA1, 0x00, # . Collection (Physical), 452 + 0x05, 0x09, # . Usage Page (Button), 453 + 0x19, 0x01, # . Usage Minimum (01h), 454 + 0x29, 0x03, # . Usage Maximum (03h), 455 + 0x15, 0x00, # . Logical Minimum (0), 456 + 0x25, 0x01, # . Logical Maximum (1), 457 + 0x75, 0x01, # . Report Size (1), 458 + 0x95, 0x03, # . Report Count (3), 459 + 0x81, 0x02, # . Input (Variable), 460 + 0x95, 0x05, # . Report Count (5), 461 + 0x81, 0x03, # . Input (Constant, Variable), 462 + 0x05, 0x01, # . Usage Page (Desktop), 463 + 0x09, 0x30, # . Usage (X), 464 + 0x09, 0x31, # . Usage (Y), 465 + 0x15, 0x80, # . Logical Minimum (-128), 466 + 0x25, 0x7F, # . Logical Maximum (127), 467 + 0x75, 0x08, # . Report Size (8), 468 + 0x95, 0x02, # . Report Count (2), 469 + 0x81, 0x06, # . Input (Variable, Relative), 470 + 0xC0, # . End Collection, 471 + 0xC0, # . End Collection, 472 + 0x06, 0x0D, 0xFF, # . Usage Page (FF0Dh), 473 + 0x09, 0x01, # . Usage (01h), 474 + 0xA1, 0x01, # . Collection (Application), 475 + 0x85, 0x10, # . Report ID (16), 476 + 0x09, 0x20, # . Usage (20h), 477 + 0xA1, 0x00, # . Collection (Physical), 478 + 0x09, 0x42, # . Usage (42h), 479 + 0x09, 0x44, # . Usage (44h), 480 + 0x09, 0x5A, # . Usage (5Ah), 481 + 0x09, 0x45, # . Usage (45h), 482 + 0x09, 0x3C, # . Usage (3Ch), 483 + 0x09, 0x32, # . Usage (32h), 484 + 0x09, 0x36, # . Usage (36h), 485 + 0x15, 0x00, # . Logical Minimum (0), 486 + 0x25, 0x01, # . Logical Maximum (1), 487 + 0x75, 0x01, # . Report Size (1), 488 + 0x95, 0x07, # . Report Count (7), 489 + 0x81, 0x02, # . Input (Variable), 490 + 0x95, 0x01, # . Report Count (1), 491 + 0x81, 0x03, # . Input (Constant, Variable), 492 + 0x0A, 0x30, 0x01, # . Usage (0130h), 493 + 0x65, 0x11, # . Unit (Centimeter), 494 + 0x55, 0x0D, # . Unit Exponent (13), 495 + 0x35, 0x00, # . Physical Minimum (0), 496 + 0x47, 0x7C, 0x79, 0x00, 0x00, # . Physical Maximum (31100), 497 + 0x15, 0x00, # . Logical Minimum (0), 498 + 0x27, 0xF8, 0xF2, 0x00, 0x00, # . Logical Maximum (62200), 499 + 0x75, 0x18, # . Report Size (24), 500 + 0x95, 0x01, # . Report Count (1), 501 + 0x81, 0x02, # . Input (Variable), 502 + 0x0A, 0x31, 0x01, # . Usage (0131h), 503 + 0x47, 0x60, 0x54, 0x00, 0x00, # . Physical Maximum (21600), 504 + 0x27, 0xC0, 0xA8, 0x00, 0x00, # . Logical Maximum (43200), 505 + 0x81, 0x02, # . Input (Variable), 506 + 0x09, 0x30, # . Usage (30h), # !!! Errata: Missing Physical Max = 0 507 + 0x55, 0x00, # . Unit Exponent (0), 508 + 0x65, 0x00, # . Unit, 509 + 0x15, 0x00, # . Logical Minimum (0), 510 + 0x26, 0xFF, 0x1F, # . Logical Maximum (8191), 511 + 0x75, 0x10, # . Report Size (16), 512 + 0x81, 0x02, # . Input (Variable), 513 + 0x09, 0x3D, # . Usage (3Dh), 514 + 0x09, 0x3E, # . Usage (3Eh), 515 + 0x65, 0x14, # . Unit (Degrees), 516 + 0x55, 0x00, # . Unit Exponent (0), 517 + 0x35, 0xC0, # . Physical Minimum (-64), 518 + 0x45, 0x3F, # . Physical Maximum (63), 519 + 0x15, 0xC0, # . Logical Minimum (-64), 520 + 0x25, 0x3F, # . Logical Maximum (63), 521 + 0x75, 0x08, # . Report Size (8), 522 + 0x95, 0x02, # . Report Count (2), 523 + 0x81, 0x02, # . Input (Variable), 524 + 0x09, 0x41, # . Usage (41h), 525 + 0x65, 0x14, # . Unit (Degrees), 526 + 0x55, 0x00, # . Unit Exponent (0), 527 + 0x36, 0x4C, 0xFF, # . Physical Minimum (-180), 528 + 0x46, 0xB3, 0x00, # . Physical Maximum (179), 529 + 0x16, 0x7C, 0xFC, # . Logical Minimum (-900), 530 + 0x26, 0x83, 0x03, # . Logical Maximum (899), 531 + 0x75, 0x10, # . Report Size (16), 532 + 0x95, 0x01, # . Report Count (1), 533 + 0x81, 0x0A, # . Input (Variable, Wrap), 534 + 0x0A, 0x03, 0x0D, # . Usage (0D03h), 535 + 0x65, 0x00, # . Unit, 536 + 0x55, 0x00, # . Unit Exponent (0), 537 + 0x15, 0x00, # . Logical Minimum (0), 538 + 0x26, 0xFF, 0x07, # . Logical Maximum (2047), # !!! Errata: Missing Physical Min/Max = 0 539 + 0x75, 0x10, # . Report Size (16), 540 + 0x95, 0x01, # . Report Count (1), 541 + 0x81, 0x02, # . Input (Variable), 542 + 0x0A, 0x32, 0x01, # . Usage (0132h), 543 + 0x15, 0x00, # . Logical Minimum (0), 544 + 0x25, 0x3F, # . Logical Maximum (63), 545 + 0x75, 0x08, # . Report Size (8), 546 + 0x95, 0x01, # . Report Count (1), 547 + 0x81, 0x02, # . Input (Variable), 548 + 0x09, 0x5B, # . Usage (5Bh), 549 + 0x09, 0x5C, # . Usage (5Ch), 550 + 0x17, 0x00, 0x00, 0x00, 0x80, # . Logical Minimum (-2147483648), 551 + 0x27, 0xFF, 0xFF, 0xFF, 0x7F, # . Logical Maximum (2147483647), 552 + 0x75, 0x20, # . Report Size (32), 553 + 0x95, 0x02, # . Report Count (2), 554 + 0x81, 0x02, # . Input (Variable), 555 + 0x09, 0x77, # . Usage (77h), 556 + 0x16, 0x00, 0x00, # . Logical Minimum (0), 557 + 0x26, 0xFF, 0x0F, # . Logical Maximum (4095), 558 + 0x75, 0x10, # . Report Size (16), 559 + 0x95, 0x01, # . Report Count (1), 560 + 0x81, 0x02, # . Input (Variable), 561 + 0xC0, # . End Collection, 562 + 0x85, 0x11, # . Report ID (17), 563 + 0x09, 0x39, # . Usage (39h), 564 + 0xA1, 0x00, # . Collection (Physical), 565 + 0x1A, 0x10, 0x09, # . Usage Minimum (0910h), 566 + 0x2A, 0x17, 0x09, # . Usage Maximum (0917h), 567 + 0x15, 0x00, # . Logical Minimum (0), 568 + 0x25, 0x01, # . Logical Maximum (1), 569 + 0x75, 0x01, # . Report Size (1), 570 + 0x95, 0x08, # . Report Count (8), 571 + 0x81, 0x02, # . Input (Variable), 572 + 0x1A, 0x40, 0x09, # . Usage Minimum (0940h), 573 + 0x2A, 0x47, 0x09, # . Usage Maximum (0947h), 574 + 0x81, 0x02, # . Input (Variable), 575 + 0x0A, 0x95, 0x09, # . Usage (0995h), 576 + 0x95, 0x01, # . Report Count (1), 577 + 0x81, 0x02, # . Input (Variable), 578 + 0x95, 0x07, # . Report Count (7), 579 + 0x81, 0x03, # . Input (Constant, Variable), 580 + 0x0A, 0x38, 0x01, # . Usage (0138h), 581 + 0x65, 0x14, # . Unit (Degrees), 582 + 0x55, 0x00, # . Unit Exponent (0), 583 + 0x35, 0x00, # . Physical Minimum (0), 584 + 0x46, 0x67, 0x01, # . Physical Maximum (359), 585 + 0x15, 0x00, # . Logical Minimum (0), 586 + 0x25, 0x47, # . Logical Maximum (71), 587 + 0x75, 0x07, # . Report Size (7), 588 + 0x95, 0x01, # . Report Count (1), 589 + 0x81, 0x0A, # . Input (Variable, Wrap), 590 + 0x0A, 0x39, 0x01, # . Usage (0139h), 591 + 0x65, 0x00, # . Unit, 592 + 0x55, 0x00, # . Unit Exponent (0), 593 + 0x25, 0x01, # . Logical Maximum (1), # !!! Errata: Missing Physical Max = 0 594 + 0x75, 0x01, # . Report Size (1), 595 + 0x95, 0x01, # . Report Count (1), 596 + 0x81, 0x02, # . Input (Variable), 597 + 0x75, 0x08, # . Report Size (8), 598 + 0x95, 0x04, # . Report Count (4), 599 + 0x81, 0x03, # . Input (Constant, Variable), 600 + 0xC0, # . End Collection, 601 + 0x85, 0x13, # . Report ID (19), 602 + 0x0A, 0x13, 0x10, # . Usage (1013h), 603 + 0xA1, 0x00, # . Collection (Physical), 604 + 0x0A, 0x3B, 0x04, # . Usage (043Bh), 605 + 0x15, 0x00, # . Logical Minimum (0), 606 + 0x25, 0x64, # . Logical Maximum (100), 607 + 0x75, 0x07, # . Report Size (7), 608 + 0x95, 0x01, # . Report Count (1), 609 + 0x81, 0x02, # . Input (Variable), 610 + 0x0A, 0x04, 0x04, # . Usage (0404h), 611 + 0x25, 0x01, # . Logical Maximum (1), 612 + 0x75, 0x01, # . Report Size (1), 613 + 0x81, 0x02, # . Input (Variable), 614 + 0x0A, 0x52, 0x04, # . Usage (0452h), 615 + 0x15, 0x00, # . Logical Minimum (0), 616 + 0x25, 0x01, # . Logical Maximum (1), 617 + 0x75, 0x01, # . Report Size (1), 618 + 0x95, 0x01, # . Report Count (1), 619 + 0x81, 0x02, # . Input (Variable), 620 + 0x95, 0x06, # . Report Count (6), 621 + 0x81, 0x03, # . Input (Constant, Variable), 622 + 0x0A, 0x54, 0x04, # . Usage (0454h), 623 + 0x95, 0x01, # . Report Count (1), 624 + 0x81, 0x02, # . Input (Variable), 625 + 0x75, 0x08, # . Report Size (8), 626 + 0x95, 0x06, # . Report Count (6), 627 + 0x81, 0x03, # . Input (Constant, Variable), 628 + 0xC0, # . End Collection, 629 + 0x09, 0x0E, # . Usage (0Eh), 630 + 0xA1, 0x02, # . Collection (Logical), 631 + 0x15, 0x00, # . Logical Minimum (0), 632 + 0x85, 0x02, # . Report ID (2), 633 + 0x09, 0x01, # . Usage (01h), 634 + 0x75, 0x08, # . Report Size (8), 635 + 0x25, 0x01, # . Logical Maximum (1), 636 + 0x95, 0x01, # . Report Count (1), 637 + 0xB1, 0x02, # . Feature (Variable), 638 + 0x85, 0x03, # . Report ID (3), 639 + 0x0A, 0x03, 0x10, # . Usage (1003h), 640 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 641 + 0x95, 0x01, # . Report Count (1), 642 + 0xB1, 0x02, # . Feature (Variable), 643 + 0x85, 0x04, # . Report ID (4), 644 + 0x0A, 0x04, 0x10, # . Usage (1004h), 645 + 0x25, 0x01, # . Logical Maximum (1), 646 + 0x95, 0x01, # . Report Count (1), 647 + 0xB1, 0x02, # . Feature (Variable), 648 + 0x85, 0x07, # . Report ID (7), 649 + 0x0A, 0x09, 0x10, # . Usage (1009h), 650 + 0x25, 0x02, # . Logical Maximum (2), 651 + 0x95, 0x01, # . Report Count (1), 652 + 0xB1, 0x02, # . Feature (Variable), 653 + 0x95, 0x01, # . Report Count (1), 654 + 0xB1, 0x03, # . Feature (Constant, Variable), 655 + 0x0A, 0x07, 0x10, # . Usage (1007h), 656 + 0x09, 0x00, # . Usage (00h), 657 + 0x0A, 0x08, 0x10, # . Usage (1008h), 658 + 0x09, 0x00, # . Usage (00h), 659 + 0x09, 0x00, # . Usage (00h), 660 + 0x09, 0x00, # . Usage (00h), 661 + 0x27, 0xFF, 0xFF, 0x00, 0x00, # . Logical Maximum (65535), 662 + 0x75, 0x10, # . Report Size (16), 663 + 0x95, 0x06, # . Report Count (6), 664 + 0xB1, 0x02, # . Feature (Variable), 665 + 0x75, 0x08, # . Report Size (8), 666 + 0x95, 0x01, # . Report Count (1), 667 + 0xB1, 0x03, # . Feature (Constant, Variable), 668 + 0x85, 0x0C, # . Report ID (12), 669 + 0x0A, 0x30, 0x0D, # . Usage (0D30h), 670 + 0x0A, 0x31, 0x0D, # . Usage (0D31h), 671 + 0x0A, 0x32, 0x0D, # . Usage (0D32h), 672 + 0x0A, 0x33, 0x0D, # . Usage (0D33h), # !!! Errata: Missing Non-zero Physical Max 673 + 0x65, 0x11, # . Unit (Centimeter), 674 + 0x55, 0x0D, # . Unit Exponent (13), 675 + 0x75, 0x10, # . Report Size (16), 676 + 0x95, 0x04, # . Report Count (4), 677 + 0xB1, 0x03, # . Feature (Constant, Variable), 678 + 0x85, 0x0D, # . Report ID (13), 679 + 0x65, 0x00, # . Unit, 680 + 0x55, 0x00, # . Unit Exponent (0), 681 + 0x0A, 0x0D, 0x10, # . Usage (100Dh), 682 + 0x15, 0x00, # . Logical Minimum (0), 683 + 0x25, 0x01, # . Logical Maximum (1), 684 + 0x75, 0x08, # . Report Size (8), 685 + 0x95, 0x01, # . Report Count (1), 686 + 0xB1, 0x02, # . Feature (Variable), 687 + 0x85, 0x14, # . Report ID (20), 688 + 0x0A, 0x14, 0x10, # . Usage (1014h), 689 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 690 + 0x95, 0x0D, # . Report Count (13), 691 + 0xB1, 0x02, # . Feature (Variable), 692 + 0x85, 0x31, # . Report ID (49), 693 + 0x0A, 0x31, 0x10, # . Usage (1031h), 694 + 0x25, 0x64, # . Logical Maximum (100), 695 + 0x95, 0x05, # . Report Count (5), 696 + 0xB1, 0x02, # . Feature (Variable), 697 + 0x85, 0x32, # . Report ID (50), 698 + 0x0A, 0x31, 0x10, # . Usage (1031h), 699 + 0x25, 0x64, # . Logical Maximum (100), 700 + 0x95, 0x01, # . Report Count (1), 701 + 0xB1, 0x02, # . Feature (Variable), 702 + 0x0A, 0x32, 0x10, # . Usage (1032h), 703 + 0x25, 0x03, # . Logical Maximum (3), 704 + 0xB1, 0x02, # . Feature (Variable), 705 + 0x85, 0x34, # . Report ID (52), 706 + 0x0A, 0x34, 0x10, # . Usage (1034h), 707 + 0x25, 0x01, # . Logical Maximum (1), 708 + 0x95, 0x04, # . Report Count (4), 709 + 0xB1, 0x02, # . Feature (Variable), 710 + 0x85, 0x35, # . Report ID (53), 711 + 0x0A, 0x35, 0x10, # . Usage (1035h), 712 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 713 + 0x95, 0x0A, # . Report Count (10), 714 + 0xB1, 0x02, # . Feature (Variable), 715 + 0x85, 0x36, # . Report ID (54), 716 + 0x0A, 0x35, 0x10, # . Usage (1035h), 717 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 718 + 0x96, 0x01, 0x01, # . Report Count (257), 719 + 0xB1, 0x02, # . Feature (Variable), 720 + 0x85, 0xCC, # . Report ID (204), 721 + 0x0A, 0xCC, 0x10, # . Usage (10CCh), 722 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 723 + 0x95, 0x02, # . Report Count (2), 724 + 0xB1, 0x02, # . Feature (Variable), 725 + 0xC0, # . End Collection, 726 + 0x0A, 0xAC, 0x10, # . Usage (10ACh), 727 + 0xA1, 0x02, # . Collection (Logical), 728 + 0x15, 0x00, # . Logical Minimum (0), 729 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 730 + 0x75, 0x08, # . Report Size (8), 731 + 0x85, 0xAC, # . Report ID (172), 732 + 0x09, 0x00, # . Usage (00h), 733 + 0x95, 0xBF, # . Report Count (191), 734 + 0x81, 0x02, # . Input (Variable), 735 + 0x85, 0x33, # . Report ID (51), 736 + 0x09, 0x00, # . Usage (00h), 737 + 0x95, 0x12, # . Report Count (18), 738 + 0xB1, 0x02, # . Feature (Variable), 739 + 0x85, 0x64, # . Report ID (100), 740 + 0x09, 0x00, # . Usage (00h), 741 + 0x95, 0x0C, # . Report Count (12), 742 + 0xB1, 0x02, # . Feature (Variable), 743 + 0x85, 0x15, # . Report ID (21), 744 + 0x09, 0x00, # . Usage (00h), 745 + 0x95, 0x0E, # . Report Count (14), 746 + 0xB1, 0x02, # . Feature (Variable), 747 + 0x85, 0x12, # . Report ID (18), 748 + 0x09, 0x00, # . Usage (00h), 749 + 0x95, 0x04, # . Report Count (4), 750 + 0xB1, 0x02, # . Feature (Variable), 751 + 0x85, 0x16, # . Report ID (22), 752 + 0x09, 0x00, # . Usage (00h), 753 + 0x95, 0x0E, # . Report Count (14), 754 + 0xB1, 0x02, # . Feature (Variable), 755 + 0x85, 0x40, # . Report ID (64), 756 + 0x09, 0x00, # . Usage (00h), 757 + 0x95, 0x01, # . Report Count (1), 758 + 0xB1, 0x02, # . Feature (Variable), 759 + 0x85, 0x41, # . Report ID (65), 760 + 0x09, 0x00, # . Usage (00h), 761 + 0x95, 0x01, # . Report Count (1), 762 + 0xB1, 0x02, # . Feature (Variable), 763 + 0x85, 0x42, # . Report ID (66), 764 + 0x09, 0x00, # . Usage (00h), 765 + 0x95, 0x04, # . Report Count (4), 766 + 0xB1, 0x02, # . Feature (Variable), 767 + 0x85, 0x43, # . Report ID (67), 768 + 0x09, 0x00, # . Usage (00h), 769 + 0x95, 0x0D, # . Report Count (13), 770 + 0xB1, 0x02, # . Feature (Variable), 771 + 0x85, 0x44, # . Report ID (68), 772 + 0x09, 0x00, # . Usage (00h), 773 + 0x95, 0x3F, # . Report Count (63), 774 + 0xB1, 0x02, # . Feature (Variable), 775 + 0x85, 0x45, # . Report ID (69), 776 + 0x09, 0x00, # . Usage (00h), 777 + 0x95, 0x20, # . Report Count (32), 778 + 0xB1, 0x02, # . Feature (Variable), 779 + 0x85, 0x60, # . Report ID (96), 780 + 0x09, 0x00, # . Usage (00h), 781 + 0x95, 0x3F, # . Report Count (63), 782 + 0xB1, 0x02, # . Feature (Variable), 783 + 0x85, 0x61, # . Report ID (97), 784 + 0x09, 0x00, # . Usage (00h), 785 + 0x95, 0x3E, # . Report Count (62), 786 + 0xB1, 0x02, # . Feature (Variable), 787 + 0x85, 0x62, # . Report ID (98), 788 + 0x09, 0x00, # . Usage (00h), 789 + 0x95, 0x3E, # . Report Count (62), 790 + 0xB1, 0x02, # . Feature (Variable), 791 + 0xC0, # . End Collection, 792 + 0x85, 0xD0, # . Report ID (208), 793 + 0x09, 0x01, # . Usage (01h), 794 + 0x96, 0x08, 0x00, # . Report Count (8), 795 + 0xB1, 0x02, # . Feature (Variable), 796 + 0x85, 0xD1, # . Report ID (209), 797 + 0x09, 0x01, # . Usage (01h), 798 + 0x96, 0x04, 0x01, # . Report Count (260), 799 + 0xB1, 0x02, # . Feature (Variable), 800 + 0x85, 0xD2, # . Report ID (210), 801 + 0x09, 0x01, # . Usage (01h), 802 + 0x96, 0x04, 0x01, # . Report Count (260), 803 + 0xB1, 0x02, # . Feature (Variable), 804 + 0x85, 0xD3, # . Report ID (211), 805 + 0x09, 0x01, # . Usage (01h), 806 + 0x96, 0x04, 0x00, # . Report Count (4), 807 + 0xB1, 0x02, # . Feature (Variable), 808 + 0x85, 0xD4, # . Report ID (212), 809 + 0x09, 0x01, # . Usage (01h), 810 + 0x96, 0x04, 0x00, # . Report Count (4), 811 + 0xB1, 0x02, # . Feature (Variable), 812 + 0x85, 0xD5, # . Report ID (213), 813 + 0x09, 0x01, # . Usage (01h), 814 + 0x96, 0x04, 0x00, # . Report Count (4), 815 + 0xB1, 0x02, # . Feature (Variable), 816 + 0x85, 0xD6, # . Report ID (214), 817 + 0x09, 0x01, # . Usage (01h), 818 + 0x96, 0x04, 0x00, # . Report Count (4), 819 + 0xB1, 0x02, # . Feature (Variable), 820 + 0x85, 0xD7, # . Report ID (215), 821 + 0x09, 0x01, # . Usage (01h), 822 + 0x96, 0x08, 0x00, # . Report Count (8), 823 + 0xB1, 0x02, # . Feature (Variable), 824 + 0x85, 0xD8, # . Report ID (216), 825 + 0x09, 0x01, # . Usage (01h), 826 + 0x96, 0x0C, 0x00, # . Report Count (12), 827 + 0xB1, 0x02, # . Feature (Variable), 828 + 0x85, 0xD9, # . Report ID (217), 829 + 0x09, 0x01, # . Usage (01h), 830 + 0x96, 0x00, 0x0A, # . Report Count (2560), 831 + 0xB1, 0x02, # . Feature (Variable), 832 + 0x85, 0xDA, # . Report ID (218), 833 + 0x09, 0x01, # . Usage (01h), 834 + 0x96, 0x04, 0x04, # . Report Count (1028), 835 + 0xB1, 0x02, # . Feature (Variable), 836 + 0x85, 0xDB, # . Report ID (219), 837 + 0x09, 0x01, # . Usage (01h), 838 + 0x96, 0x06, 0x00, # . Report Count (6), 839 + 0xB1, 0x02, # . Feature (Variable), 840 + 0x85, 0xDC, # . Report ID (220), 841 + 0x09, 0x01, # . Usage (01h), 842 + 0x96, 0x02, 0x00, # . Report Count (2), 843 + 0xB1, 0x02, # . Feature (Variable), 844 + 0x85, 0xDD, # . Report ID (221), 845 + 0x09, 0x01, # . Usage (01h), 846 + 0x96, 0x04, 0x00, # . Report Count (4), 847 + 0xB1, 0x02, # . Feature (Variable), 848 + 0x85, 0xDE, # . Report ID (222), 849 + 0x09, 0x01, # . Usage (01h), 850 + 0x96, 0x04, 0x00, # . Report Count (4), 851 + 0xB1, 0x02, # . Feature (Variable), 852 + 0x85, 0xDF, # . Report ID (223), 853 + 0x09, 0x01, # . Usage (01h), 854 + 0x96, 0x22, 0x00, # . Report Count (34), 855 + 0xB1, 0x02, # . Feature (Variable), 856 + 0x85, 0xE0, # . Report ID (224), 857 + 0x09, 0x01, # . Usage (01h), 858 + 0x96, 0x01, 0x00, # . Report Count (1), 859 + 0xB1, 0x02, # . Feature (Variable), 860 + 0x85, 0xE1, # . Report ID (225), 861 + 0x09, 0x01, # . Usage (01h), 862 + 0x96, 0x02, 0x00, # . Report Count (2), 863 + 0xB1, 0x02, # . Feature (Variable), 864 + 0x85, 0xE2, # . Report ID (226), 865 + 0x09, 0x01, # . Usage (01h), 866 + 0x96, 0x02, 0x00, # . Report Count (2), 867 + 0xB1, 0x02, # . Feature (Variable), 868 + 0x85, 0xE3, # . Report ID (227), 869 + 0x09, 0x01, # . Usage (01h), 870 + 0x96, 0x02, 0x00, # . Report Count (2), 871 + 0xB1, 0x02, # . Feature (Variable), 872 + 0x85, 0xE4, # . Report ID (228), 873 + 0x09, 0x01, # . Usage (01h), 874 + 0x96, 0xFF, 0x01, # . Report Count (511), 875 + 0xB1, 0x02, # . Feature (Variable), 876 + 0xC0 # . End Collection 877 + ] 878 + # fmt: on 879 + 880 + # Report ID (20), Usage (1014h), Report Count (13) -> 15 881 + wacom_pth860_v150 = wacom_pth860_v145.copy() 882 + wacom_pth860_v150[0x2CA] = 0x0F 883 + 884 + # fmt: off 885 + wacom_pth460_v105 = [ 886 + 0x06, 0x0D, 0xFF, # . Usage Page (FF0Dh), 887 + 0x09, 0x01, # . Usage (01h), 888 + 0xA1, 0x01, # . Collection (Application), 889 + 0x85, 0x10, # . Report ID (16), 890 + 0x09, 0x20, # . Usage (20h), 891 + 0x35, 0x00, # . Physical Minimum (0), 892 + 0x45, 0x00, # . Physical Maximum (0), 893 + 0x15, 0x00, # . Logical Minimum (0), 894 + 0x25, 0x01, # . Logical Maximum (1), 895 + 0xA1, 0x00, # . Collection (Physical), 896 + 0x09, 0x42, # . Usage (42h), 897 + 0x09, 0x44, # . Usage (44h), 898 + 0x09, 0x5A, # . Usage (5Ah), 899 + 0x09, 0x45, # . Usage (45h), 900 + 0x09, 0x3C, # . Usage (3Ch), 901 + 0x09, 0x32, # . Usage (32h), 902 + 0x09, 0x36, # . Usage (36h), 903 + 0x25, 0x01, # . Logical Maximum (1), 904 + 0x75, 0x01, # . Report Size (1), 905 + 0x95, 0x07, # . Report Count (7), 906 + 0x81, 0x02, # . Input (Variable), 907 + 0x95, 0x01, # . Report Count (1), 908 + 0x81, 0x03, # . Input (Constant, Variable), 909 + 0x0A, 0x30, 0x01, # . Usage (0130h), 910 + 0x65, 0x11, # . Unit (Centimeter), 911 + 0x55, 0x0D, # . Unit Exponent (13), 912 + 0x47, 0x58, 0x3E, 0x00, 0x00, # . Physical Maximum (15960), 913 + 0x27, 0xB0, 0x7C, 0x00, 0x00, # . Logical Maximum (31920), 914 + 0x75, 0x18, # . Report Size (24), 915 + 0x95, 0x01, # . Report Count (1), 916 + 0x81, 0x02, # . Input (Variable), 917 + 0x0A, 0x31, 0x01, # . Usage (0131h), 918 + 0x47, 0xF7, 0x26, 0x00, 0x00, # . Physical Maximum (9975), 919 + 0x27, 0xEE, 0x4D, 0x00, 0x00, # . Logical Maximum (19950), 920 + 0x81, 0x02, # . Input (Variable), 921 + 0x09, 0x30, # . Usage (30h), 922 + 0x55, 0x00, # . Unit Exponent (0), 923 + 0x65, 0x00, # . Unit, 924 + 0x26, 0xFF, 0x1F, # . Logical Maximum (8191), # !!! Errata: Missing Physical Max = 0 925 + 0x75, 0x10, # . Report Size (16), 926 + 0x81, 0x02, # . Input (Variable), 927 + 0x09, 0x3D, # . Usage (3Dh), 928 + 0x09, 0x3E, # . Usage (3Eh), 929 + 0x65, 0x14, # . Unit (Degrees), 930 + 0x55, 0x00, # . Unit Exponent (0), 931 + 0x35, 0xC0, # . Physical Minimum (-64), 932 + 0x45, 0x3F, # . Physical Maximum (63), 933 + 0x15, 0xC0, # . Logical Minimum (-64), 934 + 0x25, 0x3F, # . Logical Maximum (63), 935 + 0x75, 0x08, # . Report Size (8), 936 + 0x95, 0x02, # . Report Count (2), 937 + 0x81, 0x02, # . Input (Variable), 938 + 0x09, 0x41, # . Usage (41h), 939 + 0x65, 0x14, # . Unit (Degrees), 940 + 0x55, 0x00, # . Unit Exponent (0), 941 + 0x36, 0x4C, 0xFF, # . Physical Minimum (-180), 942 + 0x46, 0xB3, 0x00, # . Physical Maximum (179), 943 + 0x16, 0x7C, 0xFC, # . Logical Minimum (-900), 944 + 0x26, 0x83, 0x03, # . Logical Maximum (899), 945 + 0x75, 0x10, # . Report Size (16), 946 + 0x95, 0x01, # . Report Count (1), 947 + 0x81, 0x0A, # . Input (Variable, Wrap), 948 + 0x0A, 0x03, 0x0D, # . Usage (0D03h), 949 + 0x65, 0x00, # . Unit, 950 + 0x55, 0x00, # . Unit Exponent (0), 951 + 0x35, 0x00, # . Physical Minimum (0), 952 + 0x45, 0x00, # . Physical Maximum (0), 953 + 0x15, 0x00, # . Logical Minimum (0), 954 + 0x26, 0xFF, 0x07, # . Logical Maximum (2047), 955 + 0x81, 0x02, # . Input (Variable), 956 + 0x0A, 0x32, 0x01, # . Usage (0132h), 957 + 0x25, 0x3F, # . Logical Maximum (63), 958 + 0x75, 0x08, # . Report Size (8), 959 + 0x95, 0x01, # . Report Count (1), 960 + 0x81, 0x02, # . Input (Variable), 961 + 0x09, 0x5B, # . Usage (5Bh), 962 + 0x09, 0x5C, # . Usage (5Ch), 963 + 0x17, 0x00, 0x00, 0x00, 0x80, # . Logical Minimum (-2147483648), 964 + 0x27, 0xFF, 0xFF, 0xFF, 0x7F, # . Logical Maximum (2147483647), 965 + 0x75, 0x20, # . Report Size (32), 966 + 0x95, 0x02, # . Report Count (2), 967 + 0x81, 0x02, # . Input (Variable), 968 + 0x09, 0x77, # . Usage (77h), 969 + 0x15, 0x00, # . Logical Minimum (0), 970 + 0x26, 0xFF, 0x0F, # . Logical Maximum (4095), 971 + 0x75, 0x10, # . Report Size (16), 972 + 0x95, 0x01, # . Report Count (1), 973 + 0x81, 0x02, # . Input (Variable), 974 + 0xC0, # . End Collection, 975 + 0x85, 0x11, # . Report ID (17), 976 + 0x65, 0x00, # . Unit, 977 + 0x55, 0x00, # . Unit Exponent (0), 978 + 0x35, 0x00, # . Physical Minimum (0), 979 + 0x45, 0x00, # . Physical Maximum (0), 980 + 0x09, 0x39, # . Usage (39h), 981 + 0xA1, 0x00, # . Collection (Physical), 982 + 0x09, 0x39, # . Usage (39h), 983 + 0xA1, 0x00, # . Collection (Physical), 984 + 0x35, 0x00, # . Physical Minimum (0), 985 + 0x45, 0x00, # . Physical Maximum (0), 986 + 0x15, 0x00, # . Logical Minimum (0), 987 + 0x1A, 0x10, 0x09, # . Usage Minimum (0910h), 988 + 0x2A, 0x15, 0x09, # . Usage Maximum (0915h), 989 + 0x15, 0x00, # . Logical Minimum (0), 990 + 0x25, 0x01, # . Logical Maximum (1), 991 + 0x75, 0x01, # . Report Size (1), 992 + 0x95, 0x06, # . Report Count (6), 993 + 0x81, 0x02, # . Input (Variable), 994 + 0x95, 0x02, # . Report Count (2), 995 + 0x81, 0x03, # . Input (Constant, Variable), 996 + 0xC0, # . End Collection, 997 + 0x75, 0x08, # . Report Size (8), 998 + 0x95, 0x01, # . Report Count (1), 999 + 0x81, 0x03, # . Input (Constant, Variable), 1000 + 0x09, 0x39, # . Usage (39h), 1001 + 0xA1, 0x00, # . Collection (Physical), 1002 + 0x35, 0x00, # . Physical Minimum (0), 1003 + 0x45, 0x00, # . Physical Maximum (0), 1004 + 0x0A, 0x95, 0x09, # . Usage (0995h), 1005 + 0x15, 0x00, # . Logical Minimum (0), 1006 + 0x25, 0x01, # . Logical Maximum (1), 1007 + 0x75, 0x01, # . Report Size (1), 1008 + 0x95, 0x01, # . Report Count (1), 1009 + 0x81, 0x02, # . Input (Variable), 1010 + 0x95, 0x07, # . Report Count (7), 1011 + 0x81, 0x03, # . Input (Constant, Variable), 1012 + 0xC0, # . End Collection, 1013 + 0x09, 0x39, # . Usage (39h), 1014 + 0xA1, 0x00, # . Collection (Physical), 1015 + 0x35, 0x00, # . Physical Minimum (0), 1016 + 0x15, 0x00, # . Logical Minimum (0), 1017 + 0x0A, 0x38, 0x01, # . Usage (0138h), 1018 + 0x65, 0x14, # . Unit (Degrees), 1019 + 0x55, 0x00, # . Unit Exponent (0), 1020 + 0x35, 0x00, # . Physical Minimum (0), 1021 + 0x46, 0x67, 0x01, # . Physical Maximum (359), 1022 + 0x15, 0x00, # . Logical Minimum (0), 1023 + 0x25, 0x47, # . Logical Maximum (71), 1024 + 0x75, 0x07, # . Report Size (7), 1025 + 0x95, 0x01, # . Report Count (1), 1026 + 0x81, 0x4A, # . Input (Variable, Wrap, Null State), 1027 + 0x0A, 0x39, 0x01, # . Usage (0139h), 1028 + 0x65, 0x00, # . Unit, 1029 + 0x55, 0x00, # . Unit Exponent (0), 1030 + 0x45, 0x00, # . Physical Maximum (0), 1031 + 0x25, 0x01, # . Logical Maximum (1), 1032 + 0x75, 0x01, # . Report Size (1), 1033 + 0x95, 0x01, # . Report Count (1), 1034 + 0x81, 0x02, # . Input (Variable), 1035 + 0xC0, # . End Collection, 1036 + 0x75, 0x08, # . Report Size (8), 1037 + 0x95, 0x04, # . Report Count (4), 1038 + 0x81, 0x03, # . Input (Constant, Variable), 1039 + 0xC0, # . End Collection, 1040 + 0x85, 0x13, # . Report ID (19), 1041 + 0x65, 0x00, # . Unit, 1042 + 0x55, 0x00, # . Unit Exponent (0), 1043 + 0x35, 0x00, # . Physical Minimum (0), 1044 + 0x45, 0x00, # . Physical Maximum (0), 1045 + 0x0A, 0x13, 0x10, # . Usage (1013h), 1046 + 0xA1, 0x00, # . Collection (Physical), 1047 + 0x0A, 0x13, 0x10, # . Usage (1013h), 1048 + 0xA1, 0x00, # . Collection (Physical), 1049 + 0x35, 0x00, # . Physical Minimum (0), 1050 + 0x45, 0x00, # . Physical Maximum (0), 1051 + 0x15, 0x00, # . Logical Minimum (0), 1052 + 0x0A, 0x3B, 0x04, # . Usage (043Bh), 1053 + 0x15, 0x00, # . Logical Minimum (0), 1054 + 0x25, 0x64, # . Logical Maximum (100), 1055 + 0x75, 0x07, # . Report Size (7), 1056 + 0x95, 0x01, # . Report Count (1), 1057 + 0x81, 0x02, # . Input (Variable), 1058 + 0x0A, 0x04, 0x04, # . Usage (0404h), 1059 + 0x25, 0x01, # . Logical Maximum (1), 1060 + 0x75, 0x01, # . Report Size (1), 1061 + 0x81, 0x02, # . Input (Variable), 1062 + 0xC0, # . End Collection, 1063 + 0x0A, 0x13, 0x10, # . Usage (1013h), 1064 + 0xA1, 0x00, # . Collection (Physical), 1065 + 0x35, 0x00, # . Physical Minimum (0), 1066 + 0x45, 0x00, # . Physical Maximum (0), 1067 + 0x0A, 0x52, 0x04, # . Usage (0452h), 1068 + 0x15, 0x00, # . Logical Minimum (0), 1069 + 0x25, 0x01, # . Logical Maximum (1), 1070 + 0x75, 0x01, # . Report Size (1), 1071 + 0x95, 0x01, # . Report Count (1), 1072 + 0x81, 0x02, # . Input (Variable), 1073 + 0x0A, 0x41, 0x04, # . Usage (0441h), 1074 + 0x15, 0x00, # . Logical Minimum (0), 1075 + 0x25, 0x07, # . Logical Maximum (7), 1076 + 0x75, 0x03, # . Report Size (3), 1077 + 0x95, 0x02, # . Report Count (2), 1078 + 0x81, 0x02, # . Input (Variable), 1079 + 0x0A, 0x54, 0x04, # . Usage (0454h), 1080 + 0x15, 0x00, # . Logical Minimum (0), 1081 + 0x25, 0x01, # . Logical Maximum (1), 1082 + 0x75, 0x01, # . Report Size (1), 1083 + 0x95, 0x01, # . Report Count (1), 1084 + 0x81, 0x02, # . Input (Variable), 1085 + 0xC0, # . End Collection, 1086 + 0x0A, 0x13, 0x10, # . Usage (1013h), 1087 + 0xA1, 0x00, # . Collection (Physical), 1088 + 0x35, 0x00, # . Physical Minimum (0), 1089 + 0x45, 0x00, # . Physical Maximum (0), 1090 + 0x15, 0x00, # . Logical Minimum (0), 1091 + 0x0A, 0x3C, 0x04, # . Usage (043Ch), 1092 + 0x55, 0x00, # . Unit Exponent (0), 1093 + 0x65, 0x00, # . Unit, 1094 + 0x15, 0xFB, # . Logical Minimum (-5), 1095 + 0x25, 0x32, # . Logical Maximum (50), 1096 + 0x75, 0x08, # . Report Size (8), 1097 + 0x95, 0x01, # . Report Count (1), 1098 + 0x81, 0x02, # . Input (Variable), 1099 + 0xC0, # . End Collection, 1100 + 0x0A, 0x13, 0x10, # . Usage (1013h), 1101 + 0xA1, 0x00, # . Collection (Physical), 1102 + 0x35, 0x00, # . Physical Minimum (0), 1103 + 0x45, 0x00, # . Physical Maximum (0), 1104 + 0x15, 0x00, # . Logical Minimum (0), 1105 + 0x0A, 0x3D, 0x04, # . Usage (043Dh), 1106 + 0x55, 0x00, # . Unit Exponent (0), 1107 + 0x65, 0x00, # . Unit, 1108 + 0x15, 0x00, # . Logical Minimum (0), 1109 + 0x26, 0xFF, 0x0F, # . Logical Maximum (4095), 1110 + 0x75, 0x10, # . Report Size (16), 1111 + 0x95, 0x01, # . Report Count (1), 1112 + 0x81, 0x02, # . Input (Variable), 1113 + 0xC0, # . End Collection, 1114 + 0x75, 0x08, # . Report Size (8), 1115 + 0x95, 0x03, # . Report Count (3), 1116 + 0x81, 0x03, # . Input (Constant, Variable), 1117 + 0xC0, # . End Collection, 1118 + 0x09, 0x0E, # . Usage (0Eh), 1119 + 0xA1, 0x02, # . Collection (Logical), 1120 + 0x85, 0x02, # . Report ID (2), 1121 + 0x0A, 0x02, 0x10, # . Usage (1002h), 1122 + 0x15, 0x02, # . Logical Minimum (2), 1123 + 0x25, 0x02, # . Logical Maximum (2), 1124 + 0x75, 0x08, # . Report Size (8), 1125 + 0x95, 0x01, # . Report Count (1), 1126 + 0xB1, 0x02, # . Feature (Variable), 1127 + 0x85, 0x03, # . Report ID (3), 1128 + 0x0A, 0x03, 0x10, # . Usage (1003h), 1129 + 0x15, 0x00, # . Logical Minimum (0), 1130 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 1131 + 0x95, 0x01, # . Report Count (1), 1132 + 0xB1, 0x02, # . Feature (Variable), 1133 + 0x85, 0x04, # . Report ID (4), 1134 + 0x0A, 0x04, 0x10, # . Usage (1004h), 1135 + 0x15, 0x00, # . Logical Minimum (0), 1136 + 0x25, 0x01, # . Logical Maximum (1), 1137 + 0x95, 0x01, # . Report Count (1), 1138 + 0xB1, 0x02, # . Feature (Variable), 1139 + 0x85, 0x07, # . Report ID (7), 1140 + 0x0A, 0x09, 0x10, # . Usage (1009h), 1141 + 0x15, 0x00, # . Logical Minimum (0), 1142 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 1143 + 0x95, 0x01, # . Report Count (1), 1144 + 0xB1, 0x02, # . Feature (Variable), 1145 + 0xB1, 0x03, # . Feature (Constant, Variable), 1146 + 0x0A, 0x07, 0x10, # . Usage (1007h), 1147 + 0x09, 0x00, # . Usage (00h), 1148 + 0x0A, 0x08, 0x10, # . Usage (1008h), 1149 + 0x09, 0x00, # . Usage (00h), 1150 + 0x09, 0x00, # . Usage (00h), 1151 + 0x09, 0x00, # . Usage (00h), 1152 + 0x27, 0xFF, 0xFF, 0x00, 0x00, # . Logical Maximum (65535), 1153 + 0x75, 0x10, # . Report Size (16), 1154 + 0x95, 0x06, # . Report Count (6), 1155 + 0xB1, 0x02, # . Feature (Variable), 1156 + 0x09, 0x00, # . Usage (00h), 1157 + 0x25, 0x00, # . Logical Maximum (0), 1158 + 0x75, 0x08, # . Report Size (8), 1159 + 0x95, 0x01, # . Report Count (1), 1160 + 0xB1, 0x03, # . Feature (Constant, Variable), 1161 + 0x85, 0x0C, # . Report ID (12), 1162 + 0x0A, 0x30, 0x0D, # . Usage (0D30h), 1163 + 0x0A, 0x31, 0x0D, # . Usage (0D31h), 1164 + 0x0A, 0x32, 0x0D, # . Usage (0D32h), 1165 + 0x0A, 0x33, 0x0D, # . Usage (0D33h), 1166 + 0x65, 0x11, # . Unit (Centimeter), 1167 + 0x55, 0x0D, # . Unit Exponent (13), 1168 + 0x35, 0x00, # . Physical Minimum (0), 1169 + 0x46, 0xC8, 0x00, # . Physical Maximum (200), 1170 + 0x15, 0x00, # . Logical Minimum (0), 1171 + 0x26, 0x90, 0x01, # . Logical Maximum (400), 1172 + 0x75, 0x10, # . Report Size (16), 1173 + 0x95, 0x04, # . Report Count (4), 1174 + 0xB1, 0x02, # . Feature (Variable), 1175 + 0x85, 0x0D, # . Report ID (13), 1176 + 0x0A, 0x0D, 0x10, # . Usage (100Dh), 1177 + 0x65, 0x00, # . Unit, 1178 + 0x55, 0x00, # . Unit Exponent (0), 1179 + 0x45, 0x00, # . Physical Maximum (0), 1180 + 0x25, 0x01, # . Logical Maximum (1), 1181 + 0x75, 0x08, # . Report Size (8), 1182 + 0x95, 0x01, # . Report Count (1), 1183 + 0xB1, 0x02, # . Feature (Variable), 1184 + 0x85, 0x14, # . Report ID (20), 1185 + 0x0A, 0x14, 0x10, # . Usage (1014h), 1186 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 1187 + 0x95, 0x0D, # . Report Count (13), 1188 + 0xB1, 0x02, # . Feature (Variable), 1189 + 0x85, 0xCC, # . Report ID (204), 1190 + 0x0A, 0xCC, 0x10, # . Usage (10CCh), 1191 + 0x95, 0x02, # . Report Count (2), 1192 + 0xB1, 0x02, # . Feature (Variable), 1193 + 0xC0, # . End Collection, 1194 + 0x09, 0x0E, # . Usage (0Eh), 1195 + 0xA1, 0x02, # . Collection (Logical), 1196 + 0x85, 0x31, # . Report ID (49), 1197 + 0x0A, 0x31, 0x10, # . Usage (1031h), 1198 + 0x25, 0x64, # . Logical Maximum (100), 1199 + 0x95, 0x03, # . Report Count (3), 1200 + 0xB1, 0x02, # . Feature (Variable), 1201 + 0x95, 0x02, # . Report Count (2), 1202 + 0xB1, 0x03, # . Feature (Constant, Variable), 1203 + 0xC0, # . End Collection, 1204 + 0x0A, 0xAC, 0x10, # . Usage (10ACh), 1205 + 0xA1, 0x02, # . Collection (Logical), 1206 + 0x15, 0x00, # . Logical Minimum (0), 1207 + 0x26, 0xFF, 0x00, # . Logical Maximum (255), 1208 + 0x75, 0x08, # . Report Size (8), 1209 + 0x85, 0xAC, # . Report ID (172), 1210 + 0x09, 0x00, # . Usage (00h), 1211 + 0x96, 0xBF, 0x00, # . Report Count (191), 1212 + 0x81, 0x02, # . Input (Variable), 1213 + 0x85, 0x15, # . Report ID (21), 1214 + 0x09, 0x00, # . Usage (00h), 1215 + 0x95, 0x0E, # . Report Count (14), 1216 + 0xB1, 0x02, # . Feature (Variable), 1217 + 0x85, 0x33, # . Report ID (51), 1218 + 0x09, 0x00, # . Usage (00h), 1219 + 0x95, 0x12, # . Report Count (18), 1220 + 0xB1, 0x02, # . Feature (Variable), 1221 + 0x85, 0x44, # . Report ID (68), 1222 + 0x09, 0x00, # . Usage (00h), 1223 + 0x95, 0x04, # . Report Count (4), 1224 + 0xB1, 0x02, # . Feature (Variable), 1225 + 0x85, 0x45, # . Report ID (69), 1226 + 0x09, 0x00, # . Usage (00h), 1227 + 0x95, 0x20, # . Report Count (32), 1228 + 0xB1, 0x02, # . Feature (Variable), 1229 + 0x85, 0x60, # . Report ID (96), 1230 + 0x09, 0x00, # . Usage (00h), 1231 + 0x95, 0x3F, # . Report Count (63), 1232 + 0xB1, 0x02, # . Feature (Variable), 1233 + 0x85, 0x61, # . Report ID (97), 1234 + 0x09, 0x00, # . Usage (00h), 1235 + 0x95, 0x3E, # . Report Count (62), 1236 + 0xB1, 0x02, # . Feature (Variable), 1237 + 0x85, 0x62, # . Report ID (98), 1238 + 0x09, 0x00, # . Usage (00h), 1239 + 0x95, 0x3E, # . Report Count (62), 1240 + 0xB1, 0x02, # . Feature (Variable), 1241 + 0x85, 0x65, # . Report ID (101), 1242 + 0x09, 0x00, # . Usage (00h), 1243 + 0x95, 0x04, # . Report Count (4), 1244 + 0xB1, 0x02, # . Feature (Variable), 1245 + 0x85, 0x66, # . Report ID (102), 1246 + 0x09, 0x00, # . Usage (00h), 1247 + 0x95, 0x04, # . Report Count (4), 1248 + 0xB1, 0x02, # . Feature (Variable), 1249 + 0x85, 0x67, # . Report ID (103), 1250 + 0x09, 0x00, # . Usage (00h), 1251 + 0x95, 0x04, # . Report Count (4), 1252 + 0xB1, 0x02, # . Feature (Variable), 1253 + 0x85, 0x68, # . Report ID (104), 1254 + 0x09, 0x00, # . Usage (00h), 1255 + 0x95, 0x11, # . Report Count (17), 1256 + 0xB1, 0x02, # . Feature (Variable), 1257 + 0x85, 0x6F, # . Report ID (111), 1258 + 0x09, 0x00, # . Usage (00h), 1259 + 0x95, 0x3E, # . Report Count (62), 1260 + 0xB1, 0x02, # . Feature (Variable), 1261 + 0x85, 0xCD, # . Report ID (205), 1262 + 0x09, 0x00, # . Usage (00h), 1263 + 0x95, 0x02, # . Report Count (2), 1264 + 0xB1, 0x02, # . Feature (Variable), 1265 + 0x85, 0x16, # . Report ID (22), 1266 + 0x09, 0x00, # . Usage (00h), 1267 + 0x95, 0x0E, # . Report Count (14), 1268 + 0xB1, 0x02, # . Feature (Variable), 1269 + 0x85, 0x35, # . Report ID (53), 1270 + 0x09, 0x00, # . Usage (00h), 1271 + 0x95, 0x0A, # . Report Count (10), 1272 + 0xB1, 0x02, # . Feature (Variable), 1273 + 0xC0, # . End Collection, 1274 + 0x85, 0xD1, # . Report ID (209), 1275 + 0x09, 0x01, # . Usage (01h), 1276 + 0x96, 0x04, 0x01, # . Report Count (260), 1277 + 0xB1, 0x02, # . Feature (Variable), 1278 + 0x85, 0xD2, # . Report ID (210), 1279 + 0x09, 0x01, # . Usage (01h), 1280 + 0x96, 0x04, 0x01, # . Report Count (260), 1281 + 0xB1, 0x02, # . Feature (Variable), 1282 + 0x85, 0xD3, # . Report ID (211), 1283 + 0x09, 0x01, # . Usage (01h), 1284 + 0x96, 0x04, 0x00, # . Report Count (4), 1285 + 0xB1, 0x02, # . Feature (Variable), 1286 + 0x85, 0xD4, # . Report ID (212), 1287 + 0x09, 0x01, # . Usage (01h), 1288 + 0x96, 0x04, 0x00, # . Report Count (4), 1289 + 0xB1, 0x02, # . Feature (Variable), 1290 + 0x85, 0xD5, # . Report ID (213), 1291 + 0x09, 0x01, # . Usage (01h), 1292 + 0x96, 0x04, 0x00, # . Report Count (4), 1293 + 0xB1, 0x02, # . Feature (Variable), 1294 + 0x85, 0xD6, # . Report ID (214), 1295 + 0x09, 0x01, # . Usage (01h), 1296 + 0x96, 0x04, 0x00, # . Report Count (4), 1297 + 0xB1, 0x02, # . Feature (Variable), 1298 + 0x85, 0xD7, # . Report ID (215), 1299 + 0x09, 0x01, # . Usage (01h), 1300 + 0x96, 0x08, 0x00, # . Report Count (8), 1301 + 0xB1, 0x02, # . Feature (Variable), 1302 + 0x85, 0xD8, # . Report ID (216), 1303 + 0x09, 0x01, # . Usage (01h), 1304 + 0x96, 0x0C, 0x00, # . Report Count (12), 1305 + 0xB1, 0x02, # . Feature (Variable), 1306 + 0x85, 0xD9, # . Report ID (217), 1307 + 0x09, 0x01, # . Usage (01h), 1308 + 0x96, 0x00, 0x0A, # . Report Count (2560), 1309 + 0xB1, 0x02, # . Feature (Variable), 1310 + 0x85, 0xDA, # . Report ID (218), 1311 + 0x09, 0x01, # . Usage (01h), 1312 + 0x96, 0x04, 0x04, # . Report Count (1028), 1313 + 0xB1, 0x02, # . Feature (Variable), 1314 + 0x85, 0xDB, # . Report ID (219), 1315 + 0x09, 0x01, # . Usage (01h), 1316 + 0x96, 0x06, 0x00, # . Report Count (6), 1317 + 0xB1, 0x02, # . Feature (Variable), 1318 + 0x85, 0xDC, # . Report ID (220), 1319 + 0x09, 0x01, # . Usage (01h), 1320 + 0x96, 0x02, 0x00, # . Report Count (2), 1321 + 0xB1, 0x02, # . Feature (Variable), 1322 + 0x85, 0xDD, # . Report ID (221), 1323 + 0x09, 0x01, # . Usage (01h), 1324 + 0x96, 0x04, 0x00, # . Report Count (4), 1325 + 0xB1, 0x02, # . Feature (Variable), 1326 + 0x85, 0xDE, # . Report ID (222), 1327 + 0x09, 0x01, # . Usage (01h), 1328 + 0x96, 0x04, 0x00, # . Report Count (4), 1329 + 0xB1, 0x02, # . Feature (Variable), 1330 + 0x85, 0xDF, # . Report ID (223), 1331 + 0x09, 0x01, # . Usage (01h), 1332 + 0x96, 0x22, 0x00, # . Report Count (34), 1333 + 0xB1, 0x02, # . Feature (Variable), 1334 + 0x85, 0xE0, # . Report ID (224), 1335 + 0x09, 0x01, # . Usage (01h), 1336 + 0x96, 0x01, 0x00, # . Report Count (1), 1337 + 0xB1, 0x02, # . Feature (Variable), 1338 + 0x85, 0xE1, # . Report ID (225), 1339 + 0x09, 0x01, # . Usage (01h), 1340 + 0x96, 0x02, 0x00, # . Report Count (2), 1341 + 0xB1, 0x02, # . Feature (Variable), 1342 + 0x85, 0xE2, # . Report ID (226), 1343 + 0x09, 0x01, # . Usage (01h), 1344 + 0x96, 0x02, 0x00, # . Report Count (2), 1345 + 0xB1, 0x02, # . Feature (Variable), 1346 + 0x85, 0xE3, # . Report ID (227), 1347 + 0x09, 0x01, # . Usage (01h), 1348 + 0x96, 0x02, 0x00, # . Report Count (2), 1349 + 0xB1, 0x02, # . Feature (Variable), 1350 + 0x85, 0xE4, # . Report ID (228), 1351 + 0x09, 0x01, # . Usage (01h), 1352 + 0x96, 0xFF, 0x01, # . Report Count (511), 1353 + 0xB1, 0x02, # . Feature (Variable), 1354 + 0x85, 0xCB, # . Report ID (203), 1355 + 0x09, 0x01, # . Usage (01h), 1356 + 0x96, 0x1F, 0x00, # . Report Count (31), 1357 + 0xB1, 0x02, # . Feature (Variable), 1358 + 0xC0 # . End Collection 1359 + ] 1360 + # fmt: on
+844
tools/testing/selftests/hid/tests/test_wacom_generic.py
··· 1 + #!/bin/env python3 2 + # SPDX-License-Identifier: GPL-2.0 3 + # -*- coding: utf-8 -*- 4 + # 5 + # Copyright (c) 2017 Benjamin Tissoires <benjamin.tissoires@gmail.com> 6 + # Copyright (c) 2017 Red Hat, Inc. 7 + # Copyright (c) 2020 Wacom Technology Corp. 8 + # 9 + # Authors: 10 + # Jason Gerecke <jason.gerecke@wacom.com> 11 + 12 + """ 13 + Tests for the Wacom driver generic codepath. 14 + 15 + This module tests the function of the Wacom driver's generic codepath. 16 + The generic codepath is used by devices which are not explicitly listed 17 + in the driver's device table. It uses the device's HID descriptor to 18 + decode reports sent by the device. 19 + """ 20 + 21 + from .descriptors_wacom import ( 22 + wacom_pth660_v145, 23 + wacom_pth660_v150, 24 + wacom_pth860_v145, 25 + wacom_pth860_v150, 26 + wacom_pth460_v105, 27 + ) 28 + 29 + import attr 30 + from enum import Enum 31 + from hidtools.hut import HUT 32 + from hidtools.hid import HidUnit 33 + from . import base 34 + import libevdev 35 + import pytest 36 + 37 + import logging 38 + 39 + logger = logging.getLogger("hidtools.test.wacom") 40 + 41 + KERNEL_MODULE = ("wacom", "wacom") 42 + 43 + 44 + class ProximityState(Enum): 45 + """ 46 + Enumeration of allowed proximity states. 47 + """ 48 + 49 + # Tool is not able to be sensed by the device 50 + OUT = 0 51 + 52 + # Tool is close enough to be sensed, but some data may be invalid 53 + # or inaccurate 54 + IN_PROXIMITY = 1 55 + 56 + # Tool is close enough to be sensed with high accuracy. All data 57 + # valid. 58 + IN_RANGE = 2 59 + 60 + def fill(self, reportdata): 61 + """Fill a report with approrpiate HID properties/values.""" 62 + reportdata.inrange = self in [ProximityState.IN_RANGE] 63 + reportdata.wacomsense = self in [ 64 + ProximityState.IN_PROXIMITY, 65 + ProximityState.IN_RANGE, 66 + ] 67 + 68 + 69 + class ReportData: 70 + """ 71 + Placeholder for HID report values. 72 + """ 73 + 74 + pass 75 + 76 + 77 + @attr.s 78 + class Buttons: 79 + """ 80 + Stylus button state. 81 + 82 + Describes the state of each of the buttons / "side switches" that 83 + may be present on a stylus. Buttons set to 'None' indicate the 84 + state is "unchanged" since the previous event. 85 + """ 86 + 87 + primary = attr.ib(default=None) 88 + secondary = attr.ib(default=None) 89 + tertiary = attr.ib(default=None) 90 + 91 + @staticmethod 92 + def clear(): 93 + """Button object with all states cleared.""" 94 + return Buttons(False, False, False) 95 + 96 + def fill(self, reportdata): 97 + """Fill a report with approrpiate HID properties/values.""" 98 + reportdata.barrelswitch = int(self.primary or 0) 99 + reportdata.secondarybarrelswitch = int(self.secondary or 0) 100 + reportdata.b3 = int(self.tertiary or 0) 101 + 102 + 103 + @attr.s 104 + class ToolID: 105 + """ 106 + Stylus tool identifiers. 107 + 108 + Contains values used to identify a specific stylus, e.g. its serial 109 + number and tool-type identifier. Values of ``0`` may sometimes be 110 + used for the out-of-range condition. 111 + """ 112 + 113 + serial = attr.ib() 114 + tooltype = attr.ib() 115 + 116 + @staticmethod 117 + def clear(): 118 + """ToolID object with all fields cleared.""" 119 + return ToolID(0, 0) 120 + 121 + def fill(self, reportdata): 122 + """Fill a report with approrpiate HID properties/values.""" 123 + reportdata.transducerserialnumber = self.serial & 0xFFFFFFFF 124 + reportdata.serialhi = (self.serial >> 32) & 0xFFFFFFFF 125 + reportdata.tooltype = self.tooltype 126 + 127 + 128 + @attr.s 129 + class PhysRange: 130 + """ 131 + Range of HID physical values, with units. 132 + """ 133 + 134 + unit = attr.ib() 135 + min_size = attr.ib() 136 + max_size = attr.ib() 137 + 138 + CENTIMETER = HidUnit.from_string("SILinear: cm") 139 + DEGREE = HidUnit.from_string("EnglishRotation: deg") 140 + 141 + def contains(self, field): 142 + """ 143 + Check if the physical size of the provided field is in range. 144 + 145 + Compare the physical size described by the provided HID field 146 + against the range of sizes described by this object. This is 147 + an exclusive range comparison (e.g. 0 cm is not within the 148 + range 0 cm - 5 cm) and exact unit comparison (e.g. 1 inch is 149 + not within the range 0 cm - 5 cm). 150 + """ 151 + phys_size = (field.physical_max - field.physical_min) * 10 ** (field.unit_exp) 152 + return ( 153 + field.unit == self.unit.value 154 + and phys_size > self.min_size 155 + and phys_size < self.max_size 156 + ) 157 + 158 + 159 + class BaseTablet(base.UHIDTestDevice): 160 + """ 161 + Skeleton object for all kinds of tablet devices. 162 + """ 163 + 164 + def __init__(self, rdesc, name=None, info=None): 165 + assert rdesc is not None 166 + super().__init__(name, "Pen", input_info=info, rdesc=rdesc) 167 + self.buttons = Buttons.clear() 168 + self.toolid = ToolID.clear() 169 + self.proximity = ProximityState.OUT 170 + self.offset = 0 171 + self.ring = -1 172 + self.ek0 = False 173 + 174 + def match_evdev_rule(self, application, evdev): 175 + """ 176 + Filter out evdev nodes based on the requested application. 177 + 178 + The Wacom driver may create several device nodes for each USB 179 + interface device. It is crucial that we run tests with the 180 + expected device node or things will obviously go off the rails. 181 + Use the Wacom driver's usual naming conventions to apply a 182 + sensible default filter. 183 + """ 184 + if application in ["Pen", "Pad"]: 185 + return evdev.name.endswith(application) 186 + else: 187 + return True 188 + 189 + def create_report( 190 + self, x, y, pressure, buttons=None, toolid=None, proximity=None, reportID=None 191 + ): 192 + """ 193 + Return an input report for this device. 194 + 195 + :param x: absolute x 196 + :param y: absolute y 197 + :param pressure: pressure 198 + :param buttons: stylus button state. Use ``None`` for unchanged. 199 + :param toolid: tool identifiers. Use ``None`` for unchanged. 200 + :param proximity: a ProximityState indicating the sensor's ability 201 + to detect and report attributes of this tool. Use ``None`` 202 + for unchanged. 203 + :param reportID: the numeric report ID for this report, if needed 204 + """ 205 + if buttons is not None: 206 + self.buttons = buttons 207 + buttons = self.buttons 208 + 209 + if toolid is not None: 210 + self.toolid = toolid 211 + toolid = self.toolid 212 + 213 + if proximity is not None: 214 + self.proximity = proximity 215 + proximity = self.proximity 216 + 217 + reportID = reportID or self.default_reportID 218 + 219 + report = ReportData() 220 + report.x = x 221 + report.y = y 222 + report.tippressure = pressure 223 + report.tipswitch = pressure > 0 224 + buttons.fill(report) 225 + proximity.fill(report) 226 + toolid.fill(report) 227 + 228 + return super().create_report(report, reportID=reportID) 229 + 230 + def create_report_heartbeat(self, reportID): 231 + """ 232 + Return a heartbeat input report for this device. 233 + 234 + Heartbeat reports generally contain battery status information, 235 + among other things. 236 + """ 237 + report = ReportData() 238 + report.wacombatterycharging = 1 239 + return super().create_report(report, reportID=reportID) 240 + 241 + def create_report_pad(self, reportID, ring, ek0): 242 + report = ReportData() 243 + 244 + if ring is not None: 245 + self.ring = ring 246 + ring = self.ring 247 + 248 + if ek0 is not None: 249 + self.ek0 = ek0 250 + ek0 = self.ek0 251 + 252 + if ring >= 0: 253 + report.wacomtouchring = ring 254 + report.wacomtouchringstatus = 1 255 + else: 256 + report.wacomtouchring = 0x7F 257 + report.wacomtouchringstatus = 0 258 + 259 + report.wacomexpresskey00 = ek0 260 + return super().create_report(report, reportID=reportID) 261 + 262 + def event(self, x, y, pressure, buttons=None, toolid=None, proximity=None): 263 + """ 264 + Send an input event on the default report ID. 265 + 266 + :param x: absolute x 267 + :param y: absolute y 268 + :param buttons: stylus button state. Use ``None`` for unchanged. 269 + :param toolid: tool identifiers. Use ``None`` for unchanged. 270 + :param proximity: a ProximityState indicating the sensor's ability 271 + to detect and report attributes of this tool. Use ``None`` 272 + for unchanged. 273 + """ 274 + r = self.create_report(x, y, pressure, buttons, toolid, proximity) 275 + self.call_input_event(r) 276 + return [r] 277 + 278 + def event_heartbeat(self, reportID): 279 + """ 280 + Send a heartbeat event on the requested report ID. 281 + """ 282 + r = self.create_report_heartbeat(reportID) 283 + self.call_input_event(r) 284 + return [r] 285 + 286 + def event_pad(self, reportID, ring=None, ek0=None): 287 + """ 288 + Send a pad event on the requested report ID. 289 + """ 290 + r = self.create_report_pad(reportID, ring, ek0) 291 + self.call_input_event(r) 292 + return [r] 293 + 294 + def get_report(self, req, rnum, rtype): 295 + if rtype != self.UHID_FEATURE_REPORT: 296 + return (1, []) 297 + 298 + rdesc = None 299 + for v in self.parsed_rdesc.feature_reports.values(): 300 + if v.report_ID == rnum: 301 + rdesc = v 302 + 303 + if rdesc is None: 304 + return (1, []) 305 + 306 + result = (1, []) 307 + result = self.create_report_offset(rdesc) or result 308 + return result 309 + 310 + def create_report_offset(self, rdesc): 311 + require = [ 312 + "Wacom Offset Left", 313 + "Wacom Offset Top", 314 + "Wacom Offset Right", 315 + "Wacom Offset Bottom", 316 + ] 317 + if not set(require).issubset(set([f.usage_name for f in rdesc])): 318 + return None 319 + 320 + report = ReportData() 321 + report.wacomoffsetleft = self.offset 322 + report.wacomoffsettop = self.offset 323 + report.wacomoffsetright = self.offset 324 + report.wacomoffsetbottom = self.offset 325 + r = rdesc.create_report([report], None) 326 + return (0, r) 327 + 328 + 329 + class OpaqueTablet(BaseTablet): 330 + """ 331 + Bare-bones opaque tablet with a minimum of features. 332 + 333 + A tablet stripped down to its absolute core. It is capable of 334 + reporting X/Y position and if the pen is in contact. No pressure, 335 + no barrel switches, no eraser. Notably it *does* report an "In 336 + Range" flag, but this is only because the Wacom driver expects 337 + one to function properly. The device uses only standard HID usages, 338 + not any of Wacom's vendor-defined pages. 339 + """ 340 + 341 + # fmt: off 342 + report_descriptor = [ 343 + 0x05, 0x0D, # . Usage Page (Digitizer), 344 + 0x09, 0x01, # . Usage (Digitizer), 345 + 0xA1, 0x01, # . Collection (Application), 346 + 0x85, 0x01, # . Report ID (1), 347 + 0x09, 0x20, # . Usage (Stylus), 348 + 0xA1, 0x00, # . Collection (Physical), 349 + 0x09, 0x42, # . Usage (Tip Switch), 350 + 0x09, 0x32, # . Usage (In Range), 351 + 0x15, 0x00, # . Logical Minimum (0), 352 + 0x25, 0x01, # . Logical Maximum (1), 353 + 0x75, 0x01, # . Report Size (1), 354 + 0x95, 0x02, # . Report Count (2), 355 + 0x81, 0x02, # . Input (Variable), 356 + 0x95, 0x06, # . Report Count (6), 357 + 0x81, 0x03, # . Input (Constant, Variable), 358 + 0x05, 0x01, # . Usage Page (Desktop), 359 + 0x09, 0x30, # . Usage (X), 360 + 0x27, 0x80, 0x3E, 0x00, 0x00, # . Logical Maximum (16000), 361 + 0x47, 0x80, 0x3E, 0x00, 0x00, # . Physical Maximum (16000), 362 + 0x65, 0x11, # . Unit (Centimeter), 363 + 0x55, 0x0D, # . Unit Exponent (13), 364 + 0x75, 0x10, # . Report Size (16), 365 + 0x95, 0x01, # . Report Count (1), 366 + 0x81, 0x02, # . Input (Variable), 367 + 0x09, 0x31, # . Usage (Y), 368 + 0x27, 0x28, 0x23, 0x00, 0x00, # . Logical Maximum (9000), 369 + 0x47, 0x28, 0x23, 0x00, 0x00, # . Physical Maximum (9000), 370 + 0x81, 0x02, # . Input (Variable), 371 + 0xC0, # . End Collection, 372 + 0xC0, # . End Collection, 373 + ] 374 + # fmt: on 375 + 376 + def __init__(self, rdesc=report_descriptor, name=None, info=(0x3, 0x056A, 0x9999)): 377 + super().__init__(rdesc, name, info) 378 + self.default_reportID = 1 379 + 380 + 381 + class OpaqueCTLTablet(BaseTablet): 382 + """ 383 + Opaque tablet similar to something in the CTL product line. 384 + 385 + A pen-only tablet with most basic features you would expect from 386 + an actual device. Position, eraser, pressure, barrel buttons. 387 + Uses the Wacom vendor-defined usage page. 388 + """ 389 + 390 + # fmt: off 391 + report_descriptor = [ 392 + 0x06, 0x0D, 0xFF, # . Usage Page (Vnd Wacom Emr), 393 + 0x09, 0x01, # . Usage (Digitizer), 394 + 0xA1, 0x01, # . Collection (Application), 395 + 0x85, 0x10, # . Report ID (16), 396 + 0x09, 0x20, # . Usage (Stylus), 397 + 0x35, 0x00, # . Physical Minimum (0), 398 + 0x45, 0x00, # . Physical Maximum (0), 399 + 0x15, 0x00, # . Logical Minimum (0), 400 + 0x25, 0x01, # . Logical Maximum (1), 401 + 0xA1, 0x00, # . Collection (Physical), 402 + 0x09, 0x42, # . Usage (Tip Switch), 403 + 0x09, 0x44, # . Usage (Barrel Switch), 404 + 0x09, 0x5A, # . Usage (Secondary Barrel Switch), 405 + 0x09, 0x45, # . Usage (Eraser), 406 + 0x09, 0x3C, # . Usage (Invert), 407 + 0x09, 0x32, # . Usage (In Range), 408 + 0x09, 0x36, # . Usage (In Proximity), 409 + 0x25, 0x01, # . Logical Maximum (1), 410 + 0x75, 0x01, # . Report Size (1), 411 + 0x95, 0x07, # . Report Count (7), 412 + 0x81, 0x02, # . Input (Variable), 413 + 0x95, 0x01, # . Report Count (1), 414 + 0x81, 0x03, # . Input (Constant, Variable), 415 + 0x0A, 0x30, 0x01, # . Usage (X), 416 + 0x65, 0x11, # . Unit (Centimeter), 417 + 0x55, 0x0D, # . Unit Exponent (13), 418 + 0x47, 0x80, 0x3E, 0x00, 0x00, # . Physical Maximum (16000), 419 + 0x27, 0x80, 0x3E, 0x00, 0x00, # . Logical Maximum (16000), 420 + 0x75, 0x18, # . Report Size (24), 421 + 0x95, 0x01, # . Report Count (1), 422 + 0x81, 0x02, # . Input (Variable), 423 + 0x0A, 0x31, 0x01, # . Usage (Y), 424 + 0x47, 0x28, 0x23, 0x00, 0x00, # . Physical Maximum (9000), 425 + 0x27, 0x28, 0x23, 0x00, 0x00, # . Logical Maximum (9000), 426 + 0x81, 0x02, # . Input (Variable), 427 + 0x09, 0x30, # . Usage (Tip Pressure), 428 + 0x55, 0x00, # . Unit Exponent (0), 429 + 0x65, 0x00, # . Unit, 430 + 0x47, 0x00, 0x00, 0x00, 0x00, # . Physical Maximum (0), 431 + 0x26, 0xFF, 0x0F, # . Logical Maximum (4095), 432 + 0x75, 0x10, # . Report Size (16), 433 + 0x81, 0x02, # . Input (Variable), 434 + 0x75, 0x08, # . Report Size (8), 435 + 0x95, 0x06, # . Report Count (6), 436 + 0x81, 0x03, # . Input (Constant, Variable), 437 + 0x0A, 0x32, 0x01, # . Usage (Z), 438 + 0x25, 0x3F, # . Logical Maximum (63), 439 + 0x75, 0x08, # . Report Size (8), 440 + 0x95, 0x01, # . Report Count (1), 441 + 0x81, 0x02, # . Input (Variable), 442 + 0x09, 0x5B, # . Usage (Transducer Serial Number), 443 + 0x09, 0x5C, # . Usage (Transducer Serial Number Hi), 444 + 0x17, 0x00, 0x00, 0x00, 0x80, # . Logical Minimum (-2147483648), 445 + 0x27, 0xFF, 0xFF, 0xFF, 0x7F, # . Logical Maximum (2147483647), 446 + 0x75, 0x20, # . Report Size (32), 447 + 0x95, 0x02, # . Report Count (2), 448 + 0x81, 0x02, # . Input (Variable), 449 + 0x09, 0x77, # . Usage (Tool Type), 450 + 0x15, 0x00, # . Logical Minimum (0), 451 + 0x26, 0xFF, 0x0F, # . Logical Maximum (4095), 452 + 0x75, 0x10, # . Report Size (16), 453 + 0x95, 0x01, # . Report Count (1), 454 + 0x81, 0x02, # . Input (Variable), 455 + 0xC0, # . End Collection, 456 + 0xC0 # . End Collection 457 + ] 458 + # fmt: on 459 + 460 + def __init__(self, rdesc=report_descriptor, name=None, info=(0x3, 0x056A, 0x9999)): 461 + super().__init__(rdesc, name, info) 462 + self.default_reportID = 16 463 + 464 + 465 + class PTHX60_Pen(BaseTablet): 466 + """ 467 + Pen interface of a PTH-660 / PTH-860 / PTH-460 tablet. 468 + 469 + This generation of devices are nearly identical to each other, though 470 + the PTH-460 uses a slightly different descriptor construction (splits 471 + the pad among several physical collections) 472 + """ 473 + 474 + def __init__(self, rdesc=None, name=None, info=None): 475 + super().__init__(rdesc, name, info) 476 + self.default_reportID = 16 477 + 478 + 479 + class BaseTest: 480 + class TestTablet(base.BaseTestCase.TestUhid): 481 + kernel_modules = [KERNEL_MODULE] 482 + 483 + def sync_and_assert_events( 484 + self, report, expected_events, auto_syn=True, strict=False 485 + ): 486 + """ 487 + Assert we see the expected events in response to a report. 488 + """ 489 + uhdev = self.uhdev 490 + syn_event = self.syn_event 491 + if auto_syn: 492 + expected_events.append(syn_event) 493 + actual_events = uhdev.next_sync_events() 494 + self.debug_reports(report, uhdev, actual_events) 495 + if strict: 496 + self.assertInputEvents(expected_events, actual_events) 497 + else: 498 + self.assertInputEventsIn(expected_events, actual_events) 499 + 500 + def get_usages(self, uhdev): 501 + def get_report_usages(report): 502 + application = report.application 503 + for field in report.fields: 504 + if field.usages is not None: 505 + for usage in field.usages: 506 + yield (field, usage, application) 507 + else: 508 + yield (field, field.usage, application) 509 + 510 + desc = uhdev.parsed_rdesc 511 + reports = [ 512 + *desc.input_reports.values(), 513 + *desc.feature_reports.values(), 514 + *desc.output_reports.values(), 515 + ] 516 + for report in reports: 517 + for usage in get_report_usages(report): 518 + yield usage 519 + 520 + def assertName(self, uhdev): 521 + """ 522 + Assert that the name is as we expect. 523 + 524 + The Wacom driver applies a number of decorations to the name 525 + provided by the hardware. We cannot rely on the definition of 526 + this assertion from the base class to work properly. 527 + """ 528 + evdev = uhdev.get_evdev() 529 + expected_name = uhdev.name + " Pen" 530 + if "wacom" not in expected_name.lower(): 531 + expected_name = "Wacom " + expected_name 532 + assert evdev.name == expected_name 533 + 534 + def test_descriptor_physicals(self): 535 + """ 536 + Verify that all HID usages which should have a physical range 537 + actually do, and those which shouldn't don't. Also verify that 538 + the associated unit is correct and within a sensible range. 539 + """ 540 + 541 + def usage_id(page_name, usage_name): 542 + page = HUT.usage_page_from_name(page_name) 543 + return (page.page_id << 16) | page[usage_name].usage 544 + 545 + required = { 546 + usage_id("Generic Desktop", "X"): PhysRange( 547 + PhysRange.CENTIMETER, 5, 150 548 + ), 549 + usage_id("Generic Desktop", "Y"): PhysRange( 550 + PhysRange.CENTIMETER, 5, 150 551 + ), 552 + usage_id("Digitizers", "X Tilt"): PhysRange(PhysRange.DEGREE, 90, 180), 553 + usage_id("Digitizers", "Y Tilt"): PhysRange(PhysRange.DEGREE, 90, 180), 554 + usage_id("Digitizers", "Twist"): PhysRange(PhysRange.DEGREE, 358, 360), 555 + usage_id("Wacom", "X Tilt"): PhysRange(PhysRange.DEGREE, 90, 180), 556 + usage_id("Wacom", "Y Tilt"): PhysRange(PhysRange.DEGREE, 90, 180), 557 + usage_id("Wacom", "Twist"): PhysRange(PhysRange.DEGREE, 358, 360), 558 + usage_id("Wacom", "X"): PhysRange(PhysRange.CENTIMETER, 5, 150), 559 + usage_id("Wacom", "Y"): PhysRange(PhysRange.CENTIMETER, 5, 150), 560 + usage_id("Wacom", "Wacom TouchRing"): PhysRange( 561 + PhysRange.DEGREE, 358, 360 562 + ), 563 + usage_id("Wacom", "Wacom Offset Left"): PhysRange( 564 + PhysRange.CENTIMETER, 0, 0.5 565 + ), 566 + usage_id("Wacom", "Wacom Offset Top"): PhysRange( 567 + PhysRange.CENTIMETER, 0, 0.5 568 + ), 569 + usage_id("Wacom", "Wacom Offset Right"): PhysRange( 570 + PhysRange.CENTIMETER, 0, 0.5 571 + ), 572 + usage_id("Wacom", "Wacom Offset Bottom"): PhysRange( 573 + PhysRange.CENTIMETER, 0, 0.5 574 + ), 575 + } 576 + for field, usage, application in self.get_usages(self.uhdev): 577 + if application == usage_id("Generic Desktop", "Mouse"): 578 + # Ignore the vestigial Mouse collection which exists 579 + # on Wacom tablets only for backwards compatibility. 580 + continue 581 + 582 + expect_physical = usage in required 583 + 584 + phys_set = field.physical_min != 0 or field.physical_max != 0 585 + assert phys_set == expect_physical 586 + 587 + unit_set = field.unit != 0 588 + assert unit_set == expect_physical 589 + 590 + if unit_set: 591 + assert required[usage].contains(field) 592 + 593 + def test_prop_direct(self): 594 + """ 595 + Todo: Verify that INPUT_PROP_DIRECT is set on display devices. 596 + """ 597 + pass 598 + 599 + def test_prop_pointer(self): 600 + """ 601 + Todo: Verify that INPUT_PROP_POINTER is set on opaque devices. 602 + """ 603 + pass 604 + 605 + 606 + class TestOpaqueTablet(BaseTest.TestTablet): 607 + def create_device(self): 608 + return OpaqueTablet() 609 + 610 + def test_sanity(self): 611 + """ 612 + Bring a pen into contact with the tablet, then remove it. 613 + 614 + Ensure that we get the basic tool/touch/motion events that should 615 + be sent by the driver. 616 + """ 617 + uhdev = self.uhdev 618 + 619 + self.sync_and_assert_events( 620 + uhdev.event( 621 + 100, 622 + 200, 623 + pressure=300, 624 + buttons=Buttons.clear(), 625 + toolid=ToolID(serial=1, tooltype=1), 626 + proximity=ProximityState.IN_RANGE, 627 + ), 628 + [ 629 + libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 1), 630 + libevdev.InputEvent(libevdev.EV_ABS.ABS_X, 100), 631 + libevdev.InputEvent(libevdev.EV_ABS.ABS_Y, 200), 632 + libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1), 633 + ], 634 + ) 635 + 636 + self.sync_and_assert_events( 637 + uhdev.event(110, 220, pressure=0), 638 + [ 639 + libevdev.InputEvent(libevdev.EV_ABS.ABS_X, 110), 640 + libevdev.InputEvent(libevdev.EV_ABS.ABS_Y, 220), 641 + libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 0), 642 + ], 643 + ) 644 + 645 + self.sync_and_assert_events( 646 + uhdev.event( 647 + 120, 648 + 230, 649 + pressure=0, 650 + toolid=ToolID.clear(), 651 + proximity=ProximityState.OUT, 652 + ), 653 + [ 654 + libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 0), 655 + ], 656 + ) 657 + 658 + self.sync_and_assert_events( 659 + uhdev.event(130, 240, pressure=0), [], auto_syn=False, strict=True 660 + ) 661 + 662 + 663 + class TestOpaqueCTLTablet(TestOpaqueTablet): 664 + def create_device(self): 665 + return OpaqueCTLTablet() 666 + 667 + def test_buttons(self): 668 + """ 669 + Test that the barrel buttons (side switches) work as expected. 670 + 671 + Press and release each button individually to verify that we get 672 + the expected events. 673 + """ 674 + uhdev = self.uhdev 675 + 676 + self.sync_and_assert_events( 677 + uhdev.event( 678 + 100, 679 + 200, 680 + pressure=0, 681 + buttons=Buttons.clear(), 682 + toolid=ToolID(serial=1, tooltype=1), 683 + proximity=ProximityState.IN_RANGE, 684 + ), 685 + [ 686 + libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 1), 687 + libevdev.InputEvent(libevdev.EV_ABS.ABS_X, 100), 688 + libevdev.InputEvent(libevdev.EV_ABS.ABS_Y, 200), 689 + libevdev.InputEvent(libevdev.EV_MSC.MSC_SERIAL, 1), 690 + ], 691 + ) 692 + 693 + self.sync_and_assert_events( 694 + uhdev.event(100, 200, pressure=0, buttons=Buttons(primary=True)), 695 + [ 696 + libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 1), 697 + libevdev.InputEvent(libevdev.EV_MSC.MSC_SERIAL, 1), 698 + ], 699 + ) 700 + 701 + self.sync_and_assert_events( 702 + uhdev.event(100, 200, pressure=0, buttons=Buttons(primary=False)), 703 + [ 704 + libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 0), 705 + libevdev.InputEvent(libevdev.EV_MSC.MSC_SERIAL, 1), 706 + ], 707 + ) 708 + 709 + self.sync_and_assert_events( 710 + uhdev.event(100, 200, pressure=0, buttons=Buttons(secondary=True)), 711 + [ 712 + libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS2, 1), 713 + libevdev.InputEvent(libevdev.EV_MSC.MSC_SERIAL, 1), 714 + ], 715 + ) 716 + 717 + self.sync_and_assert_events( 718 + uhdev.event(100, 200, pressure=0, buttons=Buttons(secondary=False)), 719 + [ 720 + libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS2, 0), 721 + libevdev.InputEvent(libevdev.EV_MSC.MSC_SERIAL, 1), 722 + ], 723 + ) 724 + 725 + 726 + PTHX60_Devices = [ 727 + {"rdesc": wacom_pth660_v145, "info": (0x3, 0x056A, 0x0357)}, 728 + {"rdesc": wacom_pth660_v150, "info": (0x3, 0x056A, 0x0357)}, 729 + {"rdesc": wacom_pth860_v145, "info": (0x3, 0x056A, 0x0358)}, 730 + {"rdesc": wacom_pth860_v150, "info": (0x3, 0x056A, 0x0358)}, 731 + {"rdesc": wacom_pth460_v105, "info": (0x3, 0x056A, 0x0392)}, 732 + ] 733 + 734 + PTHX60_Names = [ 735 + "PTH-660/v145", 736 + "PTH-660/v150", 737 + "PTH-860/v145", 738 + "PTH-860/v150", 739 + "PTH-460/v105", 740 + ] 741 + 742 + 743 + class TestPTHX60_Pen(TestOpaqueCTLTablet): 744 + @pytest.fixture( 745 + autouse=True, scope="class", params=PTHX60_Devices, ids=PTHX60_Names 746 + ) 747 + def set_device_params(self, request): 748 + request.cls.device_params = request.param 749 + 750 + def create_device(self): 751 + return PTHX60_Pen(**self.device_params) 752 + 753 + @pytest.mark.xfail 754 + def test_descriptor_physicals(self): 755 + # XFAIL: Various documented errata 756 + super().test_descriptor_physicals() 757 + 758 + def test_heartbeat_spurious(self): 759 + """ 760 + Test that the heartbeat report does not send spurious events. 761 + """ 762 + uhdev = self.uhdev 763 + 764 + self.sync_and_assert_events( 765 + uhdev.event( 766 + 100, 767 + 200, 768 + pressure=300, 769 + buttons=Buttons.clear(), 770 + toolid=ToolID(serial=1, tooltype=0x822), 771 + proximity=ProximityState.IN_RANGE, 772 + ), 773 + [ 774 + libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 1), 775 + libevdev.InputEvent(libevdev.EV_ABS.ABS_X, 100), 776 + libevdev.InputEvent(libevdev.EV_ABS.ABS_Y, 200), 777 + libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1), 778 + ], 779 + ) 780 + 781 + # Exactly zero events: not even a SYN 782 + self.sync_and_assert_events( 783 + uhdev.event_heartbeat(19), [], auto_syn=False, strict=True 784 + ) 785 + 786 + self.sync_and_assert_events( 787 + uhdev.event(110, 200, pressure=300), 788 + [ 789 + libevdev.InputEvent(libevdev.EV_ABS.ABS_X, 110), 790 + ], 791 + ) 792 + 793 + def test_empty_pad_sync(self): 794 + self.empty_pad_sync(num=3, denom=16, reverse=True) 795 + 796 + def empty_pad_sync(self, num, denom, reverse): 797 + """ 798 + Test that multiple pad collections do not trigger empty syncs. 799 + """ 800 + 801 + def offset_rotation(value): 802 + """ 803 + Offset touchring rotation values by the same factor as the 804 + Linux kernel. Tablets historically don't use the same origin 805 + as HID, and it sometimes changes from tablet to tablet... 806 + """ 807 + evdev = self.uhdev.get_evdev() 808 + info = evdev.absinfo[libevdev.EV_ABS.ABS_WHEEL] 809 + delta = info.maximum - info.minimum + 1 810 + if reverse: 811 + value = info.maximum - value 812 + value += num * delta // denom 813 + if value > info.maximum: 814 + value -= delta 815 + elif value < info.minimum: 816 + value += delta 817 + return value 818 + 819 + uhdev = self.uhdev 820 + uhdev.application = "Pad" 821 + evdev = uhdev.get_evdev() 822 + 823 + print(evdev.name) 824 + self.sync_and_assert_events( 825 + uhdev.event_pad(reportID=17, ring=0, ek0=1), 826 + [ 827 + libevdev.InputEvent(libevdev.EV_KEY.BTN_0, 1), 828 + libevdev.InputEvent(libevdev.EV_ABS.ABS_WHEEL, offset_rotation(0)), 829 + libevdev.InputEvent(libevdev.EV_ABS.ABS_MISC, 15), 830 + ], 831 + ) 832 + 833 + self.sync_and_assert_events( 834 + uhdev.event_pad(reportID=17, ring=1, ek0=1), 835 + [libevdev.InputEvent(libevdev.EV_ABS.ABS_WHEEL, offset_rotation(1))], 836 + ) 837 + 838 + self.sync_and_assert_events( 839 + uhdev.event_pad(reportID=17, ring=2, ek0=0), 840 + [ 841 + libevdev.InputEvent(libevdev.EV_ABS.ABS_WHEEL, offset_rotation(2)), 842 + libevdev.InputEvent(libevdev.EV_KEY.BTN_0, 0), 843 + ], 844 + )