From 7ee6033fa45e5be4a8f37e7ed6bdc869ab0c56cb Mon Sep 17 00:00:00 2001 From: Daniel Samson <12231216+daniel-samson@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:27:47 +0100 Subject: [PATCH] =?UTF-8?q?usb-hid:=20echo=20typed=20characters=20to=20the?= =?UTF-8?q?=20log=20=E2=80=94=20a=20simple=20keyboard=20check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was no way to confirm a keyboard actually registers keys on real hardware (enumeration binding the driver only proves the device came up). The keyboard driver now echoes each decoded printable character (and newline) to its log: type a known phrase and read it back from usb-hid-keyboard.log, or watch it appear live on screen in a -Ddiagnose boot (where the kernel console is a log sink). It exercises the whole path — HID report -> diff -> layout -> character — not just enumeration, and works identically for a keyboard behind a hub. A usb-key-echo QEMU case injects a phrase via QMP send-key and asserts it echoes (stable across repeated runs). Full suite 92/92. --- system/drivers/usb-hid/keyboard.zig | 9 +++++++++ test/qemu_test.py | 15 +++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/system/drivers/usb-hid/keyboard.zig b/system/drivers/usb-hid/keyboard.zig index cbb95cb..325b92d 100644 --- a/system/drivers/usb-hid/keyboard.zig +++ b/system/drivers/usb-hid/keyboard.zig @@ -148,6 +148,15 @@ pub fn main(init: runtime.process.Init) void { .character = character, .modifiers = modifier_word, }); + // Echo the character to the log — a simple end-to-end + // keyboard check on real hardware: type a known phrase, + // then read it back from usb-hid-keyboard.log (or watch + // it appear live on screen in a -Ddiagnose boot, where + // the kernel console is a log sink). Printable ASCII and + // newline only; other keys are left to the input service. + if (character == '\n' or (character >= 0x20 and character < 0x7F)) { + _ = runtime.system.write(&[1]u8{@intCast(character)}); + } } }, .released => { diff --git a/test/qemu_test.py b/test/qemu_test.py index 66308ba..e321ec8 100644 --- a/test/qemu_test.py +++ b/test/qemu_test.py @@ -461,6 +461,21 @@ CASES = [ # usb-kbd/usb-mouse ride the default boot xHCI bus (see qemu_args). "expect": r"(?=[\s\S]*usb-hid-keyboard: ok)(?=[\s\S]*usb-hid-mouse: ok)", "fail": r"DANOS-TEST-RESULT: FAIL"}, + # Keyboard echo: inject a known phrase via QMP send-key; the usb-hid-keyboard + # driver decodes it and echoes each character to the log (the simple + # real-hardware keyboard check — type a phrase, read it back off the stick, + # or watch it live on screen in a -Ddiagnose boot). Proves the whole path: + # HID report -> decode -> layout -> character. + {"name": "usb-key-echo", + "build_case": "usb-hid", + "smp": 4, + "timeout": 150, + "qmp_sequence": [ + {"delay": 8, "command": "send-key", "arguments": {"keys": [{"type": "qcode", "data": c}]}} + for c in ["k", "e", "y", "t", "e", "s", "t"] + ], + "expect": r"keytest", + "fail": r"DANOS-TEST-RESULT: FAIL"}, # USB hub (B4a/B4b, docs/usb-hub.md): a USB2 hub on the xHCI bus with a # keyboard behind it (a STATIC boot topology — no hot-plug event needed). # B4a: the hub enumerates and powers its downstream ports. B4b extends the