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

selftests: hid: import hid-tools hid-core 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.

I haven't imported all of hid-tools, the python module, but only the
tests related to the kernel. We can rely on pip to fetch the latest
hid-tools release, and then run the tests directly from the tree.

This should now be easier to request tests when something is not behaving
properly in the HID subsystem.

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

Cc: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

+620 -1
+2
tools/testing/selftests/hid/Makefile
··· 5 5 include ../../../scripts/Makefile.arch 6 6 include ../../../scripts/Makefile.include 7 7 8 + TEST_PROGS := hid-core.sh 9 + 8 10 CXX ?= $(CROSS_COMPILE)g++ 9 11 10 12 HOSTPKG_CONFIG := pkg-config
+7
tools/testing/selftests/hid/hid-core.sh
··· 1 + #!/bin/sh 2 + # SPDX-License-Identifier: GPL-2.0 3 + # Runs tests for the HID subsystem 4 + 5 + export TARGET=test_hid_core.py 6 + 7 + bash ./run-hid-tools-tests.sh
+28
tools/testing/selftests/hid/run-hid-tools-tests.sh
··· 1 + #!/bin/sh 2 + # SPDX-License-Identifier: GPL-2.0 3 + # Runs tests for the HID subsystem 4 + 5 + if ! command -v python3 > /dev/null 2>&1; then 6 + echo "hid-tools: [SKIP] python3 not installed" 7 + exit 77 8 + fi 9 + 10 + if ! python3 -c "import pytest" > /dev/null 2>&1; then 11 + echo "hid: [SKIP/ pytest module not installed" 12 + exit 77 13 + fi 14 + 15 + if ! python3 -c "import pytest_tap" > /dev/null 2>&1; then 16 + echo "hid: [SKIP/ pytest_tap module not installed" 17 + exit 77 18 + fi 19 + 20 + if ! python3 -c "import hidtools" > /dev/null 2>&1; then 21 + echo "hid: [SKIP/ hid-tools module not installed" 22 + exit 77 23 + fi 24 + 25 + TARGET=${TARGET:=.} 26 + 27 + echo TAP version 13 28 + python3 -u -m pytest $PYTEST_XDIST ./tests/$TARGET --tap-stream --udevd
+2
tools/testing/selftests/hid/tests/__init__.py
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # Just to make sphinx-apidoc document this directory
+345
tools/testing/selftests/hid/tests/base.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 + 8 + import libevdev 9 + import os 10 + import pytest 11 + import time 12 + 13 + import logging 14 + 15 + from hidtools.device.base_device import BaseDevice, EvdevMatch, SysfsFile 16 + from pathlib import Path 17 + from typing import Final 18 + 19 + logger = logging.getLogger("hidtools.test.base") 20 + 21 + # application to matches 22 + application_matches: Final = { 23 + # pyright: ignore 24 + "Accelerometer": EvdevMatch( 25 + req_properties=[ 26 + libevdev.INPUT_PROP_ACCELEROMETER, 27 + ] 28 + ), 29 + "Game Pad": EvdevMatch( # in systemd, this is a lot more complex, but that will do 30 + requires=[ 31 + libevdev.EV_ABS.ABS_X, 32 + libevdev.EV_ABS.ABS_Y, 33 + libevdev.EV_ABS.ABS_RX, 34 + libevdev.EV_ABS.ABS_RY, 35 + libevdev.EV_KEY.BTN_START, 36 + ], 37 + excl_properties=[ 38 + libevdev.INPUT_PROP_ACCELEROMETER, 39 + ], 40 + ), 41 + "Joystick": EvdevMatch( # in systemd, this is a lot more complex, but that will do 42 + requires=[ 43 + libevdev.EV_ABS.ABS_RX, 44 + libevdev.EV_ABS.ABS_RY, 45 + libevdev.EV_KEY.BTN_START, 46 + ], 47 + excl_properties=[ 48 + libevdev.INPUT_PROP_ACCELEROMETER, 49 + ], 50 + ), 51 + "Key": EvdevMatch( 52 + requires=[ 53 + libevdev.EV_KEY.KEY_A, 54 + ], 55 + excl_properties=[ 56 + libevdev.INPUT_PROP_ACCELEROMETER, 57 + libevdev.INPUT_PROP_DIRECT, 58 + libevdev.INPUT_PROP_POINTER, 59 + ], 60 + ), 61 + "Mouse": EvdevMatch( 62 + requires=[ 63 + libevdev.EV_REL.REL_X, 64 + libevdev.EV_REL.REL_Y, 65 + libevdev.EV_KEY.BTN_LEFT, 66 + ], 67 + excl_properties=[ 68 + libevdev.INPUT_PROP_ACCELEROMETER, 69 + ], 70 + ), 71 + "Pad": EvdevMatch( 72 + requires=[ 73 + libevdev.EV_KEY.BTN_0, 74 + ], 75 + excludes=[ 76 + libevdev.EV_KEY.BTN_TOOL_PEN, 77 + libevdev.EV_KEY.BTN_TOUCH, 78 + libevdev.EV_ABS.ABS_DISTANCE, 79 + ], 80 + excl_properties=[ 81 + libevdev.INPUT_PROP_ACCELEROMETER, 82 + ], 83 + ), 84 + "Pen": EvdevMatch( 85 + requires=[ 86 + libevdev.EV_KEY.BTN_STYLUS, 87 + libevdev.EV_ABS.ABS_X, 88 + libevdev.EV_ABS.ABS_Y, 89 + ], 90 + excl_properties=[ 91 + libevdev.INPUT_PROP_ACCELEROMETER, 92 + ], 93 + ), 94 + "Stylus": EvdevMatch( 95 + requires=[ 96 + libevdev.EV_KEY.BTN_STYLUS, 97 + libevdev.EV_ABS.ABS_X, 98 + libevdev.EV_ABS.ABS_Y, 99 + ], 100 + excl_properties=[ 101 + libevdev.INPUT_PROP_ACCELEROMETER, 102 + ], 103 + ), 104 + "Touch Pad": EvdevMatch( 105 + requires=[ 106 + libevdev.EV_KEY.BTN_LEFT, 107 + libevdev.EV_ABS.ABS_X, 108 + libevdev.EV_ABS.ABS_Y, 109 + ], 110 + excludes=[libevdev.EV_KEY.BTN_TOOL_PEN, libevdev.EV_KEY.BTN_STYLUS], 111 + req_properties=[ 112 + libevdev.INPUT_PROP_POINTER, 113 + ], 114 + excl_properties=[ 115 + libevdev.INPUT_PROP_ACCELEROMETER, 116 + ], 117 + ), 118 + "Touch Screen": EvdevMatch( 119 + requires=[ 120 + libevdev.EV_KEY.BTN_TOUCH, 121 + libevdev.EV_ABS.ABS_X, 122 + libevdev.EV_ABS.ABS_Y, 123 + ], 124 + excludes=[libevdev.EV_KEY.BTN_TOOL_PEN, libevdev.EV_KEY.BTN_STYLUS], 125 + req_properties=[ 126 + libevdev.INPUT_PROP_DIRECT, 127 + ], 128 + excl_properties=[ 129 + libevdev.INPUT_PROP_ACCELEROMETER, 130 + ], 131 + ), 132 + } 133 + 134 + 135 + class UHIDTestDevice(BaseDevice): 136 + def __init__(self, name, application, rdesc_str=None, rdesc=None, input_info=None): 137 + super().__init__(name, application, rdesc_str, rdesc, input_info) 138 + self.application_matches = application_matches 139 + if name is None: 140 + name = f"uhid test {self.__class__.__name__}" 141 + if not name.startswith("uhid test "): 142 + name = "uhid test " + self.name 143 + self.name = name 144 + 145 + 146 + class BaseTestCase: 147 + class TestUhid(object): 148 + syn_event = libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) # type: ignore 149 + key_event = libevdev.InputEvent(libevdev.EV_KEY) # type: ignore 150 + abs_event = libevdev.InputEvent(libevdev.EV_ABS) # type: ignore 151 + rel_event = libevdev.InputEvent(libevdev.EV_REL) # type: ignore 152 + msc_event = libevdev.InputEvent(libevdev.EV_MSC.MSC_SCAN) # type: ignore 153 + 154 + # List of kernel modules to load before starting the test 155 + # if any module is not available (not compiled), the test will skip. 156 + # Each element is a tuple '(kernel driver name, kernel module)', 157 + # for example ("playstation", "hid-playstation") 158 + kernel_modules = [] 159 + 160 + def assertInputEventsIn(self, expected_events, effective_events): 161 + effective_events = effective_events.copy() 162 + for ev in expected_events: 163 + assert ev in effective_events 164 + effective_events.remove(ev) 165 + return effective_events 166 + 167 + def assertInputEvents(self, expected_events, effective_events): 168 + remaining = self.assertInputEventsIn(expected_events, effective_events) 169 + assert remaining == [] 170 + 171 + @classmethod 172 + def debug_reports(cls, reports, uhdev=None, events=None): 173 + data = [" ".join([f"{v:02x}" for v in r]) for r in reports] 174 + 175 + if uhdev is not None: 176 + human_data = [ 177 + uhdev.parsed_rdesc.format_report(r, split_lines=True) 178 + for r in reports 179 + ] 180 + try: 181 + human_data = [ 182 + f'\n\t {" " * h.index("/")}'.join(h.split("\n")) 183 + for h in human_data 184 + ] 185 + except ValueError: 186 + # '/' not found: not a numbered report 187 + human_data = ["\n\t ".join(h.split("\n")) for h in human_data] 188 + data = [f"{d}\n\t ====> {h}" for d, h in zip(data, human_data)] 189 + 190 + reports = data 191 + 192 + if len(reports) == 1: 193 + print("sending 1 report:") 194 + else: 195 + print(f"sending {len(reports)} reports:") 196 + for report in reports: 197 + print("\t", report) 198 + 199 + if events is not None: 200 + print("events received:", events) 201 + 202 + def create_device(self): 203 + raise Exception("please reimplement me in subclasses") 204 + 205 + def _load_kernel_module(self, kernel_driver, kernel_module): 206 + sysfs_path = Path("/sys/bus/hid/drivers") 207 + if kernel_driver is not None: 208 + sysfs_path /= kernel_driver 209 + else: 210 + # special case for when testing all available modules: 211 + # we don't know beforehand the name of the module from modinfo 212 + sysfs_path = Path("/sys/module") / kernel_module.replace("-", "_") 213 + if not sysfs_path.exists(): 214 + import subprocess 215 + 216 + ret = subprocess.run(["/usr/sbin/modprobe", kernel_module]) 217 + if ret.returncode != 0: 218 + pytest.skip( 219 + f"module {kernel_module} could not be loaded, skipping the test" 220 + ) 221 + 222 + @pytest.fixture() 223 + def load_kernel_module(self): 224 + for kernel_driver, kernel_module in self.kernel_modules: 225 + self._load_kernel_module(kernel_driver, kernel_module) 226 + yield 227 + 228 + @pytest.fixture() 229 + def new_uhdev(self, load_kernel_module): 230 + return self.create_device() 231 + 232 + def assertName(self, uhdev): 233 + evdev = uhdev.get_evdev() 234 + assert uhdev.name in evdev.name 235 + 236 + @pytest.fixture(autouse=True) 237 + def context(self, new_uhdev, request): 238 + try: 239 + with HIDTestUdevRule.instance(): 240 + with new_uhdev as self.uhdev: 241 + skip_cond = request.node.get_closest_marker("skip_if_uhdev") 242 + if skip_cond: 243 + test, message, *rest = skip_cond.args 244 + 245 + if test(self.uhdev): 246 + pytest.skip(message) 247 + 248 + self.uhdev.create_kernel_device() 249 + now = time.time() 250 + while not self.uhdev.is_ready() and time.time() - now < 5: 251 + self.uhdev.dispatch(1) 252 + if self.uhdev.get_evdev() is None: 253 + logger.warning( 254 + f"available list of input nodes: (default application is '{self.uhdev.application}')" 255 + ) 256 + logger.warning(self.uhdev.input_nodes) 257 + yield 258 + self.uhdev = None 259 + except PermissionError: 260 + pytest.skip("Insufficient permissions, run me as root") 261 + 262 + @pytest.fixture(autouse=True) 263 + def check_taint(self): 264 + # we are abusing SysfsFile here, it's in /proc, but meh 265 + taint_file = SysfsFile("/proc/sys/kernel/tainted") 266 + taint = taint_file.int_value 267 + 268 + yield 269 + 270 + assert taint_file.int_value == taint 271 + 272 + def test_creation(self): 273 + """Make sure the device gets processed by the kernel and creates 274 + the expected application input node. 275 + 276 + If this fail, there is something wrong in the device report 277 + descriptors.""" 278 + uhdev = self.uhdev 279 + assert uhdev is not None 280 + assert uhdev.get_evdev() is not None 281 + self.assertName(uhdev) 282 + assert len(uhdev.next_sync_events()) == 0 283 + assert uhdev.get_evdev() is not None 284 + 285 + 286 + class HIDTestUdevRule(object): 287 + _instance = None 288 + """ 289 + A context-manager compatible class that sets up our udev rules file and 290 + deletes it on context exit. 291 + 292 + This class is tailored to our test setup: it only sets up the udev rule 293 + on the **second** context and it cleans it up again on the last context 294 + removed. This matches the expected pytest setup: we enter a context for 295 + the session once, then once for each test (the first of which will 296 + trigger the udev rule) and once the last test exited and the session 297 + exited, we clean up after ourselves. 298 + """ 299 + 300 + def __init__(self): 301 + self.refs = 0 302 + self.rulesfile = None 303 + 304 + def __enter__(self): 305 + self.refs += 1 306 + if self.refs == 2 and self.rulesfile is None: 307 + self.create_udev_rule() 308 + self.reload_udev_rules() 309 + 310 + def __exit__(self, exc_type, exc_value, traceback): 311 + self.refs -= 1 312 + if self.refs == 0 and self.rulesfile: 313 + os.remove(self.rulesfile.name) 314 + self.reload_udev_rules() 315 + 316 + def reload_udev_rules(self): 317 + import subprocess 318 + 319 + subprocess.run("udevadm control --reload-rules".split()) 320 + subprocess.run("systemd-hwdb update".split()) 321 + 322 + def create_udev_rule(self): 323 + import tempfile 324 + 325 + os.makedirs("/run/udev/rules.d", exist_ok=True) 326 + with tempfile.NamedTemporaryFile( 327 + prefix="91-uhid-test-device-REMOVEME-", 328 + suffix=".rules", 329 + mode="w+", 330 + dir="/run/udev/rules.d", 331 + delete=False, 332 + ) as f: 333 + f.write( 334 + 'KERNELS=="*input*", ATTRS{name}=="*uhid test *", ENV{LIBINPUT_IGNORE_DEVICE}="1"\n' 335 + ) 336 + f.write( 337 + 'KERNELS=="*input*", ATTRS{name}=="*uhid test * System Multi Axis", ENV{ID_INPUT_TOUCHSCREEN}="", ENV{ID_INPUT_SYSTEM_MULTIAXIS}="1"\n' 338 + ) 339 + self.rulesfile = f 340 + 341 + @classmethod 342 + def instance(cls): 343 + if not cls._instance: 344 + cls._instance = HIDTestUdevRule() 345 + return cls._instance
+81
tools/testing/selftests/hid/tests/conftest.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 + 8 + import platform 9 + import pytest 10 + import re 11 + import resource 12 + import subprocess 13 + from .base import HIDTestUdevRule 14 + from pathlib import Path 15 + 16 + 17 + # See the comment in HIDTestUdevRule, this doesn't set up but it will clean 18 + # up once the last test exited. 19 + @pytest.fixture(autouse=True, scope="session") 20 + def udev_rules_session_setup(): 21 + with HIDTestUdevRule.instance(): 22 + yield 23 + 24 + 25 + @pytest.fixture(autouse=True, scope="session") 26 + def setup_rlimit(): 27 + resource.setrlimit(resource.RLIMIT_CORE, (0, 0)) 28 + 29 + 30 + @pytest.fixture(autouse=True, scope="session") 31 + def start_udevd(pytestconfig): 32 + if pytestconfig.getoption("udevd"): 33 + import subprocess 34 + 35 + with subprocess.Popen("/usr/lib/systemd/systemd-udevd") as proc: 36 + yield 37 + proc.kill() 38 + else: 39 + yield 40 + 41 + 42 + def pytest_configure(config): 43 + config.addinivalue_line( 44 + "markers", 45 + "skip_if_uhdev(condition, message): mark test to skip if the condition on the uhdev device is met", 46 + ) 47 + 48 + 49 + # Generate the list of modules and modaliases 50 + # for the tests that need to be parametrized with those 51 + def pytest_generate_tests(metafunc): 52 + if "usbVidPid" in metafunc.fixturenames: 53 + modules = ( 54 + Path("/lib/modules/") 55 + / platform.uname().release 56 + / "kernel" 57 + / "drivers" 58 + / "hid" 59 + ) 60 + 61 + modalias_re = re.compile(r"alias:\s+hid:b0003g.*v([0-9a-fA-F]+)p([0-9a-fA-F]+)") 62 + 63 + params = [] 64 + ids = [] 65 + for module in modules.glob("*.ko"): 66 + p = subprocess.run( 67 + ["modinfo", module], capture_output=True, check=True, encoding="utf-8" 68 + ) 69 + for line in p.stdout.split("\n"): 70 + m = modalias_re.match(line) 71 + if m is not None: 72 + vid, pid = m.groups() 73 + vid = int(vid, 16) 74 + pid = int(pid, 16) 75 + params.append([module.name.replace(".ko", ""), vid, pid]) 76 + ids.append(f"{module.name} {vid:04x}:{pid:04x}") 77 + metafunc.parametrize("usbVidPid", params, ids=ids) 78 + 79 + 80 + def pytest_addoption(parser): 81 + parser.addoption("--udevd", action="store_true", default=False)
+154
tools/testing/selftests/hid/tests/test_hid_core.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 + # 8 + # This program is free software: you can redistribute it and/or modify 9 + # it under the terms of the GNU General Public License as published by 10 + # the Free Software Foundation; either version 2 of the License, or 11 + # (at your option) any later version. 12 + # 13 + # This program is distributed in the hope that it will be useful, 14 + # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + # GNU General Public License for more details. 17 + # 18 + # You should have received a copy of the GNU General Public License 19 + # along with this program. If not, see <http://www.gnu.org/licenses/>. 20 + # 21 + 22 + # This is for generic devices 23 + 24 + from . import base 25 + import logging 26 + 27 + logger = logging.getLogger("hidtools.test.hid") 28 + 29 + 30 + class TestCollectionOverflow(base.BaseTestCase.TestUhid): 31 + """ 32 + Test class to test re-allocation of the HID collection stack in 33 + hid-core.c. 34 + """ 35 + 36 + def create_device(self): 37 + # fmt: off 38 + report_descriptor = [ 39 + 0x05, 0x01, # .Usage Page (Generic Desktop) 40 + 0x09, 0x02, # .Usage (Mouse) 41 + 0xa1, 0x01, # .Collection (Application) 42 + 0x09, 0x02, # ..Usage (Mouse) 43 + 0xa1, 0x02, # ..Collection (Logical) 44 + 0x09, 0x01, # ...Usage (Pointer) 45 + 0xa1, 0x00, # ...Collection (Physical) 46 + 0x05, 0x09, # ....Usage Page (Button) 47 + 0x19, 0x01, # ....Usage Minimum (1) 48 + 0x29, 0x03, # ....Usage Maximum (3) 49 + 0x15, 0x00, # ....Logical Minimum (0) 50 + 0x25, 0x01, # ....Logical Maximum (1) 51 + 0x75, 0x01, # ....Report Size (1) 52 + 0x95, 0x03, # ....Report Count (3) 53 + 0x81, 0x02, # ....Input (Data,Var,Abs) 54 + 0x75, 0x05, # ....Report Size (5) 55 + 0x95, 0x01, # ....Report Count (1) 56 + 0x81, 0x03, # ....Input (Cnst,Var,Abs) 57 + 0xa1, 0x02, # ....Collection (Logical) 58 + 0x09, 0x01, # .....Usage (Pointer) 59 + 0xa1, 0x02, # ....Collection (Logical) 60 + 0x09, 0x01, # .....Usage (Pointer) 61 + 0xa1, 0x02, # ....Collection (Logical) 62 + 0x09, 0x01, # .....Usage (Pointer) 63 + 0xa1, 0x02, # ....Collection (Logical) 64 + 0x09, 0x01, # .....Usage (Pointer) 65 + 0xa1, 0x02, # ....Collection (Logical) 66 + 0x09, 0x01, # .....Usage (Pointer) 67 + 0xa1, 0x02, # ....Collection (Logical) 68 + 0x09, 0x01, # .....Usage (Pointer) 69 + 0xa1, 0x02, # ....Collection (Logical) 70 + 0x09, 0x01, # .....Usage (Pointer) 71 + 0xa1, 0x02, # ....Collection (Logical) 72 + 0x09, 0x01, # .....Usage (Pointer) 73 + 0xa1, 0x02, # ....Collection (Logical) 74 + 0x09, 0x01, # .....Usage (Pointer) 75 + 0xa1, 0x02, # ....Collection (Logical) 76 + 0x09, 0x01, # .....Usage (Pointer) 77 + 0xa1, 0x02, # ....Collection (Logical) 78 + 0x09, 0x01, # .....Usage (Pointer) 79 + 0xa1, 0x02, # ....Collection (Logical) 80 + 0x09, 0x01, # .....Usage (Pointer) 81 + 0xa1, 0x02, # ....Collection (Logical) 82 + 0x09, 0x01, # .....Usage (Pointer) 83 + 0xa1, 0x02, # ....Collection (Logical) 84 + 0x09, 0x01, # .....Usage (Pointer) 85 + 0xa1, 0x02, # ....Collection (Logical) 86 + 0x09, 0x01, # .....Usage (Pointer) 87 + 0xa1, 0x02, # ....Collection (Logical) 88 + 0x09, 0x01, # .....Usage (Pointer) 89 + 0xa1, 0x02, # ....Collection (Logical) 90 + 0x09, 0x01, # .....Usage (Pointer) 91 + 0x05, 0x01, # .....Usage Page (Generic Desktop) 92 + 0x09, 0x30, # .....Usage (X) 93 + 0x09, 0x31, # .....Usage (Y) 94 + 0x15, 0x81, # .....Logical Minimum (-127) 95 + 0x25, 0x7f, # .....Logical Maximum (127) 96 + 0x75, 0x08, # .....Report Size (8) 97 + 0x95, 0x02, # .....Report Count (2) 98 + 0x81, 0x06, # .....Input (Data,Var,Rel) 99 + 0xa1, 0x02, # ...Collection (Logical) 100 + 0x85, 0x12, # ....Report ID (18) 101 + 0x09, 0x48, # ....Usage (Resolution Multiplier) 102 + 0x95, 0x01, # ....Report Count (1) 103 + 0x75, 0x02, # ....Report Size (2) 104 + 0x15, 0x00, # ....Logical Minimum (0) 105 + 0x25, 0x01, # ....Logical Maximum (1) 106 + 0x35, 0x01, # ....Physical Minimum (1) 107 + 0x45, 0x0c, # ....Physical Maximum (12) 108 + 0xb1, 0x02, # ....Feature (Data,Var,Abs) 109 + 0x85, 0x1a, # ....Report ID (26) 110 + 0x09, 0x38, # ....Usage (Wheel) 111 + 0x35, 0x00, # ....Physical Minimum (0) 112 + 0x45, 0x00, # ....Physical Maximum (0) 113 + 0x95, 0x01, # ....Report Count (1) 114 + 0x75, 0x10, # ....Report Size (16) 115 + 0x16, 0x01, 0x80, # ....Logical Minimum (-32767) 116 + 0x26, 0xff, 0x7f, # ....Logical Maximum (32767) 117 + 0x81, 0x06, # ....Input (Data,Var,Rel) 118 + 0xc0, # ...End Collection 119 + 0xc0, # ...End Collection 120 + 0xc0, # ...End Collection 121 + 0xc0, # ...End Collection 122 + 0xc0, # ...End Collection 123 + 0xc0, # ...End Collection 124 + 0xc0, # ...End Collection 125 + 0xc0, # ...End Collection 126 + 0xc0, # ...End Collection 127 + 0xc0, # ...End Collection 128 + 0xc0, # ...End Collection 129 + 0xc0, # ...End Collection 130 + 0xc0, # ...End Collection 131 + 0xc0, # ...End Collection 132 + 0xc0, # ...End Collection 133 + 0xc0, # ...End Collection 134 + 0xc0, # ...End Collection 135 + 0xc0, # ...End Collection 136 + 0xc0, # ...End Collection 137 + 0xc0, # ..End Collection 138 + 0xc0, # .End Collection 139 + ] 140 + # fmt: on 141 + return base.UHIDTestDevice( 142 + name=None, rdesc=report_descriptor, application="Mouse" 143 + ) 144 + 145 + def test_rdesc(self): 146 + """ 147 + This test can only check for negatives. If the kernel crashes, you 148 + know why. If this test passes, either the bug isn't present or just 149 + didn't get triggered. No way to know. 150 + 151 + For an explanation, see kernel patch 152 + HID: core: replace the collection tree pointers with indices 153 + """ 154 + pass
+1 -1
tools/testing/selftests/hid/vmtest.sh
··· 27 27 CONTAINER_IMAGE="registry.freedesktop.org/libevdev/hid-tools/fedora/37:2023-02-17.1" 28 28 29 29 TARGETS="${TARGETS:=$(basename ${SCRIPT_DIR})}" 30 - DEFAULT_COMMAND="make -C tools/testing/selftests TARGETS=${TARGETS} run_tests" 30 + DEFAULT_COMMAND="pip3 install hid-tools; make -C tools/testing/selftests TARGETS=${TARGETS} run_tests" 31 31 32 32 usage() 33 33 {