Decode ACPI _HID names in device discovery
The flat analog of pci-class for acpi_device nodes. ACPI has no class/subclass/prog-IF
taxonomy — a device's identity is its _HID string itself (PNP0303 *is* "PS/2
keyboard") — so this is a plain id -> name registry, not a hierarchical decoder.
New system/devices/acpi-ids.zig (module `acpi-ids`): the common standard PnP/ACPI
hardware IDs; vendor-specific ids (QEMU0002, etc.) have no registry name and print the
raw HID. Shared reference data like pci-class. The dump now names each _HID:
KBD_ [acpi_device] hid=PNP0303 (PS/2 Keyboard)
COM1 [acpi_device] hid=PNP0501 (16550A-compatible Serial Port)
RTC_ [acpi_device] hid=PNP0B00 (Real-Time Clock (RTC))
LNKA [acpi_device] hid=PNP0C0F (PCI Interrupt Link Device)
FWCF [acpi_device] hid=QEMU0002 (vendor-specific: raw HID)
Host test covers known ids and the unknown/empty fallthrough. Suite 41/41 plus host
tests.
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
//! 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 -> description registry rather than a hierarchical decoder.
|
||||
//! The well-known PnP/ACPI IDs; vendor-specific ids (e.g. `QEMU0002`, `INTC1234`) have
|
||||
//! no standard name and return "". Pure reference data, so it is shared by kernel
|
||||
//! discovery (the device-tree dump) and any user-space tool.
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const Entry = struct { hid: []const u8, name: []const u8 };
|
||||
|
||||
/// The common standard PnP/ACPI hardware IDs. 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 table.
|
||||
const table = [_]Entry{
|
||||
.{ .hid = "PNP0000", .name = "Programmable Interrupt Controller (PIC)" },
|
||||
.{ .hid = "PNP0100", .name = "System Timer (PIT)" },
|
||||
.{ .hid = "PNP0103", .name = "High Precision Event Timer (HPET)" },
|
||||
.{ .hid = "PNP0200", .name = "DMA Controller" },
|
||||
.{ .hid = "PNP0303", .name = "PS/2 Keyboard" },
|
||||
.{ .hid = "PNP0400", .name = "Standard LPT Parallel Port" },
|
||||
.{ .hid = "PNP0401", .name = "ECP Parallel Port" },
|
||||
.{ .hid = "PNP0501", .name = "16550A-compatible Serial Port" },
|
||||
.{ .hid = "PNP0700", .name = "PC Floppy Disk Controller" },
|
||||
.{ .hid = "PNP0800", .name = "System Speaker" },
|
||||
.{ .hid = "PNP0A03", .name = "PCI Bus" },
|
||||
.{ .hid = "PNP0A05", .name = "Generic Container Device" },
|
||||
.{ .hid = "PNP0A06", .name = "Generic Container Device" },
|
||||
.{ .hid = "PNP0A08", .name = "PCI Express Root Bridge" },
|
||||
.{ .hid = "PNP0B00", .name = "Real-Time Clock (RTC)" },
|
||||
.{ .hid = "PNP0C01", .name = "System Board" },
|
||||
.{ .hid = "PNP0C02", .name = "Motherboard Reserved Resources" },
|
||||
.{ .hid = "PNP0C04", .name = "Math Coprocessor" },
|
||||
.{ .hid = "PNP0C08", .name = "ACPI System Board" },
|
||||
.{ .hid = "PNP0C09", .name = "ACPI Embedded Controller" },
|
||||
.{ .hid = "PNP0C0A", .name = "ACPI Control Method Battery" },
|
||||
.{ .hid = "PNP0C0B", .name = "ACPI Fan" },
|
||||
.{ .hid = "PNP0C0C", .name = "ACPI Power Button" },
|
||||
.{ .hid = "PNP0C0D", .name = "ACPI Lid" },
|
||||
.{ .hid = "PNP0C0E", .name = "ACPI Sleep Button" },
|
||||
.{ .hid = "PNP0C0F", .name = "PCI Interrupt Link Device" },
|
||||
.{ .hid = "PNP0F03", .name = "Microsoft PS/2 Mouse" },
|
||||
.{ .hid = "PNP0F13", .name = "PS/2 Mouse" },
|
||||
.{ .hid = "ACPI0003", .name = "AC Adapter" },
|
||||
.{ .hid = "ACPI0007", .name = "Processor Device" },
|
||||
.{ .hid = "ACPI000C", .name = "Processor Aggregator" },
|
||||
.{ .hid = "ACPI0010", .name = "Processor Container" },
|
||||
};
|
||||
|
||||
/// The human-readable name for a `_HID`, 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 {
|
||||
for (table) |entry| {
|
||||
if (std.mem.eql(u8, entry.hid, hid)) return entry.name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
const std = @import("std");
|
||||
const device_abi = @import("device-abi");
|
||||
const pci_class = @import("pci-class");
|
||||
const acpi_ids = @import("acpi-ids");
|
||||
|
||||
/// The hardware primitives a discovery backend needs but can't express portably.
|
||||
/// The kernel injects an implementation (the architecture VMM + port I/O), so the device
|
||||
@@ -190,9 +191,14 @@ fn dumpNode(device: *const Device, depth: usize, emit: *const fn ([]const u8) vo
|
||||
|
||||
var buffer: [200]u8 = undefined;
|
||||
@memset(buffer[0..indent], ' ');
|
||||
const body = if (device.hid_len != 0)
|
||||
std.fmt.bufPrint(buffer[indent..], "{s} [{s}] hid={s}\n", .{ device.name(), @tagName(device.class), device.hid() }) catch return
|
||||
else
|
||||
const body = if (device.hid_len != 0) blk: {
|
||||
// Decode the _HID to a human name when it's a known standard PnP/ACPI id.
|
||||
const desc = acpi_ids.description(device.hid());
|
||||
break :blk if (desc.len != 0)
|
||||
std.fmt.bufPrint(buffer[indent..], "{s} [{s}] hid={s} ({s})\n", .{ device.name(), @tagName(device.class), device.hid(), desc }) catch return
|
||||
else
|
||||
std.fmt.bufPrint(buffer[indent..], "{s} [{s}] hid={s}\n", .{ device.name(), @tagName(device.class), device.hid() }) catch return;
|
||||
} else
|
||||
std.fmt.bufPrint(buffer[indent..], "{s} [{s}]\n", .{ device.name(), @tagName(device.class) }) catch return;
|
||||
emit(buffer[0 .. indent + body.len]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user