diff --git a/system/devices/usb-ids.zig b/system/devices/usb-ids.zig index 470fc95..d1d907d 100644 --- a/system/devices/usb-ids.zig +++ b/system/devices/usb-ids.zig @@ -70,6 +70,53 @@ pub const Class = enum(u8) { _, }; +/// A human-readable name for a device/interface class code, for logs. Unknown +/// codes fall through to "class 0xNN". +pub fn className(class: u8) []const u8 { + return switch (@as(Class, @enumFromInt(class))) { + .per_interface => "per-interface", + .audio => "Audio", + .communications => "Communications", + .hid => "HID", + .physical => "Physical", + .image => "Image", + .printer => "Printer", + .mass_storage => "Mass Storage", + .hub => "Hub", + .cdc_data => "CDC Data", + .smart_card => "Smart Card", + .content_security => "Content Security", + .video => "Video", + .personal_healthcare => "Personal Healthcare", + .audio_video => "Audio/Video", + .billboard => "Billboard", + .type_c_bridge => "Type-C Bridge", + .bulk_display => "Bulk Display", + .mctp => "MCTP", + .i3c => "I3C", + .diagnostic => "Diagnostic", + .wireless_controller => "Wireless Controller", + .miscellaneous => "Miscellaneous", + .application_specific => "Application-specific", + .vendor_specific => "Vendor-specific", + _ => "Unknown", + }; +} + +/// A fuller name for a HID interface's (subclass, protocol): "HID boot keyboard" +/// / "HID boot mouse", else just the class name. Used to make input devices +/// recognizable in logs. +pub fn interfaceName(class: u8, subclass: u8, protocol: u8) []const u8 { + if (@as(Class, @enumFromInt(class)) == .hid and subclass == @intFromEnum(hid.SubClass.boot)) { + return switch (@as(hid.Protocol, @enumFromInt(protocol))) { + .keyboard => "HID boot keyboard", + .mouse => "HID boot mouse", + else => "HID", + }; + } + return className(class); +} + // Subclass and protocol codes qualified by Class.hub. Hubs have no subclass codes; the // protocol distinguishes the hub's transaction-translator arrangement. pub const hub = struct { diff --git a/system/drivers/usb-xhci-bus/usb-xhci-bus.zig b/system/drivers/usb-xhci-bus/usb-xhci-bus.zig index c2c5f8b..767cb31 100644 --- a/system/drivers/usb-xhci-bus/usb-xhci-bus.zig +++ b/system/drivers/usb-xhci-bus/usb-xhci-bus.zig @@ -230,8 +230,9 @@ fn bringUpPort(manager: runtime.ipc.Handle, engine: *library.Controller, port: u std.log.info("port {d} enumeration failed", .{port}); return; } - std.log.info("port {d} device vendor 0x{x:0>4} product 0x{x:0>4}, {d} interface(s)", .{ + std.log.info("port {d} device: {s} vendor 0x{x:0>4} product 0x{x:0>4}, {d} interface(s)", .{ port, + usb_ids.className(usb_device.device_descriptor.device_class), usb_device.device_descriptor.vendor_id, usb_device.device_descriptor.product_id, usb_device.interface_count, @@ -279,8 +280,9 @@ fn bringUpBehindHub(manager: runtime.ipc.Handle, engine: *library.Controller, hu std.log.info("hub slot {d} port {d}: enumeration failed", .{ hub.slot_id, port }); return; } - std.log.info("hub slot {d} port {d} device vendor 0x{x:0>4} product 0x{x:0>4}, {d} interface(s)", .{ + std.log.info("hub slot {d} port {d} device: {s} vendor 0x{x:0>4} product 0x{x:0>4}, {d} interface(s)", .{ hub.slot_id, port, + usb_ids.className(usb_device.device_descriptor.device_class), usb_device.device_descriptor.vendor_id, usb_device.device_descriptor.product_id, usb_device.interface_count, @@ -387,9 +389,10 @@ fn reportInterface(manager: runtime.ipc.Handle, port: u32, interface: library.In std.log.info("child report for port {d} interface {d} failed", .{ port, interface.number }); return null; }; - std.log.info("port {d} interface {d} class {d}/{d}/{d} registered as device {d}", .{ + std.log.info("port {d} interface {d}: {s} ({d}/{d}/{d}) registered as device {d}", .{ port, interface.number, + usb_ids.interfaceName(interface.class, interface.subclass, interface.protocol), interface.class, interface.subclass, interface.protocol, diff --git a/test/qemu_test.py b/test/qemu_test.py index e321ec8..025bd92 100644 --- a/test/qemu_test.py +++ b/test/qemu_test.py @@ -494,7 +494,7 @@ CASES = [ # B4a: the hub powers its ports. B4b: the keyboard behind it enumerates # (route string + TT) and binds usb-hid-keyboard. "expect": r"(?s)(?=.*hub slot \d+: \d+ downstream ports powered)" - r"(?=.*hub slot \d+ port \d+ device vendor 0x0627)" + r"(?=.*hub slot \d+ port \d+ device:.*vendor 0x0627)" r"(?=.*usb-hid-keyboard: ok \(device 3)", "fail": r"DANOS-TEST-RESULT: FAIL"}, # USB mass storage end to end: the boot usb-storage device (the FAT32 image, @@ -676,7 +676,7 @@ CASES = [ "-device", "usb-hub,bus=xhci2.0,port=1", "-device", "usb-hub,bus=xhci2.0,port=1.1", "-device", "usb-kbd,bus=xhci2.0,port=1.1.1"], - "expect": r"(?s)(?=.*hub slot \d+ port \d+ device vendor 0x0409)" + "expect": r"(?s)(?=.*hub slot \d+ port \d+ device:.*vendor 0x0409)" r"(?=.*usb-hid-keyboard: ok \(device 3)", "fail": r"DANOS-TEST-RESULT: FAIL"}, # Hub-downstream disconnect (B4c): device_del the keyboard behind the hub;