Turn acpi-ids.zig's flat name table into a HardwareId enum modeled on ps2-library's Port: one entry() switch holds the registry (variant -> _HID string + human-readable name), with hid(), description(), and fromHid() methods. The free description(hid) lookup the kernel's device-tree dump uses survives, implemented over the enum, and a new test round-trips every variant through fromHid. Callers now name the device instead of quoting its id: - ps2-library's DeviceType.hid() and ps2-bus's descriptor lookups use HardwareId.ps2_keyboard / .ps2_mouse. - device-manager's driverFor parses the HID once with fromHid and switches on named values. - acpi.zig's isPciRootNode carried the same ids twice, as strings and as packed-EISA integers (0x030AD041/0x080AD041); both branches now decode to the string form and answer through one isPciRootHid helper using .pci_bus / .pci_express_root_bridge. - build.zig threads the acpi-ids module (previously kernel-only) into every user binary, like xkeyboard-config.
82 lines
3.5 KiB
Zig
82 lines
3.5 KiB
Zig
//! /system/services/device-manager — the ring-3 process that turns the device
|
|
//! tree into a running system. The kernel enumerates the hardware and enforces the
|
|
//! claim capability (mechanism); this decides *which driver serves which device*
|
|
//! and, eventually, spawns it (policy). Keeping that split in user space is the
|
|
//! whole point of the microkernel: the manager is an ordinary, restartable process
|
|
//! with no special privilege — it uses the same `device_*` system calls any process
|
|
//! could ([drivers.md](../../../docs/drivers.md), [driver-model.md]).
|
|
//!
|
|
//! Increment 2 (this file): enumerate /system/devices, *match* each device to a
|
|
//! driver, and *spawn* it with `system_spawn` — the kernel loads the named binary
|
|
//! from the initial-ramdisk as a fresh ring-3 process. On QEMU this discovers the
|
|
//! HPET, decides `hpet` serves it, and brings that driver all the way up. (The
|
|
//! kernel still auto-spawns the whole initial-ramdisk at boot; increment 3 removes
|
|
//! that redundancy so the manager is the sole owner of driver spawning.)
|
|
const std = @import("std");
|
|
const runtime = @import("runtime");
|
|
const acpi_ids = @import("acpi-ids");
|
|
const device = runtime.device;
|
|
const system = runtime.system;
|
|
|
|
/// Format one whole log line and emit it in a single `debug_write`, so output
|
|
/// from the drivers this manager starts (which run concurrently) can never land
|
|
/// in the middle of it.
|
|
fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
|
|
var line: [128]u8 = undefined;
|
|
_ = runtime.system.write(std.fmt.bufPrint(&line, fmt, arguments) catch return);
|
|
}
|
|
|
|
/// The driver that serves each device — the policy table. In a fuller system
|
|
/// this comes from the drivers describing what they bind (or a manifest under
|
|
/// /system/drivers); for now it is a small static map, which is enough to prove the
|
|
/// manager reads the tree and decides. `null` = no driver for this class yet.
|
|
fn driverFor(d: device.DeviceDescriptor) ?[]const u8 {
|
|
// detect device via DeviceClass
|
|
if (d.class == @intFromEnum(device.DeviceClass.timer)) return "hpet";
|
|
// detect device via hid
|
|
const hid = d.hid[0..@intCast(d.hid_len)];
|
|
const id = acpi_ids.HardwareId.fromHid(hid) orelse return null;
|
|
return switch (id) {
|
|
.ps2_keyboard, .ps2_mouse => "ps2-bus",
|
|
else => null,
|
|
};
|
|
}
|
|
|
|
|
|
pub fn main() void {
|
|
// Enumerate into a heap buffer (too big for the one-page user stack).
|
|
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch {
|
|
_ = runtime.system.write("device-manager: out of memory\n");
|
|
return;
|
|
};
|
|
const total = device.enumerate(buffer);
|
|
const count = @min(total, buffer.len);
|
|
|
|
var matched: usize = 0;
|
|
for (buffer[0..count]) |descriptor| {
|
|
const driver_name = driverFor(descriptor) orelse continue;
|
|
matched += 1;
|
|
if (!system.isProcessRunning(driver_name)) {
|
|
if (runtime.system.spawn(driver_name) != null) {
|
|
writeLine("device-manager: spawned {s}\n", .{driver_name});
|
|
} else {
|
|
writeLine("device-manager: failed to spawn {s}\n", .{driver_name});
|
|
}
|
|
} else {
|
|
writeLine("device-manager: already spawned {s}\n", .{driver_name});
|
|
}
|
|
}
|
|
|
|
if (matched == 0) {
|
|
_ = runtime.system.write("device-manager: no matchable devices\n");
|
|
return;
|
|
}
|
|
_ = runtime.system.write("device-manager: ok\n");
|
|
while (true) runtime.system.sleep(1000);
|
|
}
|
|
|
|
pub const panic = runtime.panic;
|
|
comptime {
|
|
_ = &runtime.start._start; // pull the runtime entry shim into the image
|
|
}
|