//! ACPI / PnP hardware-ID (`_HID`) names: the flat analog of pci-class.zig for //! `acpi_device` nodes. Unlike PCI, ACPI has no class/subclass/prog-IF taxonomy — a //! device's identity *is* its `_HID` string (`PNP0303` simply means "PS/2 keyboard"), //! so this is a plain id <-> name registry rather than a hierarchical decoder. //! The well-known PnP/ACPI IDs; vendor-specific ids (e.g. `QEMU0002`, `INTC1234`) have //! no standard name and decode to nothing. Pure reference data, so it is shared by //! kernel discovery (the device-tree dump) and any user-space driver or tool. //! //! Code that means a specific device names the `HardwareId` variant instead of its //! `_HID` string — `HardwareId.ps2_keyboard.hid()` reads without a registry lookup, //! where a bare `"PNP0303"` does not. const std = @import("std"); /// The common standard PnP/ACPI hardware IDs, as named values. Prefix ranges hint at /// the grouping (PNP03xx keyboards, PNP0Fxx pointing devices, PNP0Cxx ACPI /// power/thermal, PNP0Axx buses), but there is no formal hierarchy — hence a flat /// enum over a flat registry. pub const HardwareId = enum { programmable_interrupt_controller, system_timer, high_precision_event_timer, dma_controller, ps2_keyboard, parallel_port, ecp_parallel_port, serial_port, floppy_disk_controller, system_speaker, pci_bus, generic_container, /// The second id the ACPI spec assigns the same "Generic Container Device" name. generic_container_extended, pci_express_root_bridge, real_time_clock, system_board, motherboard_reserved_resources, math_coprocessor, acpi_system_board, embedded_controller, control_method_battery, fan, power_button, lid, sleep_button, pci_interrupt_link, microsoft_ps2_mouse, ps2_mouse, ac_adapter, processor_device, processor_aggregator, processor_container, const Entry = struct { hid: []const u8, name: []const u8 }; /// The registry row for this id: its `_HID` string and human-readable name. fn entry(self: HardwareId) Entry { return switch (self) { .programmable_interrupt_controller => .{ .hid = "PNP0000", .name = "Programmable Interrupt Controller (PIC)" }, .system_timer => .{ .hid = "PNP0100", .name = "System Timer (PIT)" }, .high_precision_event_timer => .{ .hid = "PNP0103", .name = "High Precision Event Timer (HPET)" }, .dma_controller => .{ .hid = "PNP0200", .name = "DMA Controller" }, .ps2_keyboard => .{ .hid = "PNP0303", .name = "PS/2 Keyboard" }, .parallel_port => .{ .hid = "PNP0400", .name = "Standard LPT Parallel Port" }, .ecp_parallel_port => .{ .hid = "PNP0401", .name = "ECP Parallel Port" }, .serial_port => .{ .hid = "PNP0501", .name = "16550A-compatible Serial Port" }, .floppy_disk_controller => .{ .hid = "PNP0700", .name = "PC Floppy Disk Controller" }, .system_speaker => .{ .hid = "PNP0800", .name = "System Speaker" }, .pci_bus => .{ .hid = "PNP0A03", .name = "PCI Bus" }, .generic_container => .{ .hid = "PNP0A05", .name = "Generic Container Device" }, .generic_container_extended => .{ .hid = "PNP0A06", .name = "Generic Container Device" }, .pci_express_root_bridge => .{ .hid = "PNP0A08", .name = "PCI Express Root Bridge" }, .real_time_clock => .{ .hid = "PNP0B00", .name = "Real-Time Clock (RTC)" }, .system_board => .{ .hid = "PNP0C01", .name = "System Board" }, .motherboard_reserved_resources => .{ .hid = "PNP0C02", .name = "Motherboard Reserved Resources" }, .math_coprocessor => .{ .hid = "PNP0C04", .name = "Math Coprocessor" }, .acpi_system_board => .{ .hid = "PNP0C08", .name = "ACPI System Board" }, .embedded_controller => .{ .hid = "PNP0C09", .name = "ACPI Embedded Controller" }, .control_method_battery => .{ .hid = "PNP0C0A", .name = "ACPI Control Method Battery" }, .fan => .{ .hid = "PNP0C0B", .name = "ACPI Fan" }, .power_button => .{ .hid = "PNP0C0C", .name = "ACPI Power Button" }, .lid => .{ .hid = "PNP0C0D", .name = "ACPI Lid" }, .sleep_button => .{ .hid = "PNP0C0E", .name = "ACPI Sleep Button" }, .pci_interrupt_link => .{ .hid = "PNP0C0F", .name = "PCI Interrupt Link Device" }, .microsoft_ps2_mouse => .{ .hid = "PNP0F03", .name = "Microsoft PS/2 Mouse" }, .ps2_mouse => .{ .hid = "PNP0F13", .name = "PS/2 Mouse" }, .ac_adapter => .{ .hid = "ACPI0003", .name = "AC Adapter" }, .processor_device => .{ .hid = "ACPI0007", .name = "Processor Device" }, .processor_aggregator => .{ .hid = "ACPI000C", .name = "Processor Aggregator" }, .processor_container => .{ .hid = "ACPI0010", .name = "Processor Container" }, }; } /// This id's `_HID` string (e.g. `.ps2_keyboard` -> "PNP0303"). pub fn hid(self: HardwareId) []const u8 { return self.entry().hid; } /// This id's human-readable name (e.g. `.ps2_keyboard` -> "PS/2 Keyboard"). pub fn description(self: HardwareId) []const u8 { return self.entry().name; } /// The named value for a `_HID` string, or null if it is not a known standard /// id (vendor-specific ids are not in the registry). pub fn fromHid(hid_string: []const u8) ?HardwareId { for (std.enums.values(HardwareId)) |id| { if (std.mem.eql(u8, id.hid(), hid_string)) return id; } return null; } }; /// The human-readable name for a `_HID` string, or "" if it is not a known standard /// id (vendor-specific ids have no registry name — callers just print the raw HID). pub fn description(hid: []const u8) []const u8 { return (HardwareId.fromHid(hid) orelse return "").description(); } test "decodes standard PnP/ACPI ids and leaves the rest alone" { const eq = std.testing.expectEqualStrings; try eq("PS/2 Keyboard", description("PNP0303")); try eq("PS/2 Mouse", description("PNP0F13")); try eq("PCI Express Root Bridge", description("PNP0A08")); try eq("Real-Time Clock (RTC)", description("PNP0B00")); try eq("", description("QEMU0002")); // vendor-specific: no standard name try eq("", description("")); // no HID at all } test "named values round-trip through their _HID strings" { const testing = std.testing; try testing.expectEqualStrings("PNP0303", HardwareId.ps2_keyboard.hid()); try testing.expectEqual(@as(?HardwareId, .ps2_mouse), HardwareId.fromHid("PNP0F13")); try testing.expectEqual(@as(?HardwareId, null), HardwareId.fromHid("QEMU0002")); for (std.enums.values(HardwareId)) |id| { try testing.expectEqual(@as(?HardwareId, id), HardwareId.fromHid(id.hid())); } }