//! The "device" library domain (library/device): what a driver author imports. //! The flat reference data (device-abi, pci-class, acpi-ids, usb-abi, usb-ids), //! typed MMIO access, the driver-side client libraries (driver, pci, usb, //! block), the AML interpreter, and the data-driven device registry. const std = @import("std"); pub fn build(b: *std.Build) void { const kernel = b.dependency("kernel", .{}); const protocol = b.dependency("protocol", .{}); const csv = b.dependency("csv", .{}); const abi = kernel.module("abi"); const system_call = kernel.module("system-call"); const ipc = kernel.module("ipc"); const time = kernel.module("time"); // A driver finds the bus it attaches to by name — `/protocol/device-manager`, // `/protocol/usb-transfer`, `/protocol/block` // (docs/os-development/protocol-namespace.md). const channel = kernel.module("channel"); // The devices sub-project's public interface (the flat wire types), // importable by user space, unlike the kernel-internal device model it // also feeds (system/kernel/device-model.zig). const device_abi = b.addModule("device-abi", .{ .root_source_file = b.path("model/device-abi.zig"), }); // PCI class-code decoding (class/subclass/prog-IF -> names). Pure reference // data, shared by kernel discovery and any user-space PCI tool. const pci_class = b.addModule("pci-class", .{ .root_source_file = b.path("pci/pci-class.zig"), }); // ACPI/PnP hardware-ID (_HID) names — the flat analog of pci-class. _ = b.addModule("acpi-ids", .{ .root_source_file = b.path("acpi/acpi-ids.zig"), }); // The AML interpreter, a build module so the ring-3 acpi service can run // the same parser the kernel does (docs/discovery.md). Pure Zig, no kernel // imports — one source, two builds. _ = b.addModule("aml", .{ .root_source_file = b.path("acpi/aml/aml.zig"), }); // The USB device-framework wire ABI (chapter-9 set-up packets, standard + // class requests, descriptors) and the USB class-code taxonomy. const usb_abi = b.addModule("usb-abi", .{ .root_source_file = b.path("usb/usb-abi.zig"), }); const usb_ids = b.addModule("usb-ids", .{ .root_source_file = b.path("usb/usb-ids.zig"), }); // Typed volatile MMIO register access + memory-ordering barriers, for // drivers on top of an mmio_map grant. Depends only on `builtin`. const mmio = b.addModule("mmio", .{ .root_source_file = b.path("mmio/mmio.zig"), }); // The driver author's interface: device access + the device-manager hello // handshake, folded together. const driver = b.addModule("driver", .{ .root_source_file = b.path("driver/driver.zig"), .imports = &.{ .{ .name = "abi", .module = abi }, .{ .name = "channel", .module = channel }, .{ .name = "device-abi", .module = device_abi }, .{ .name = "envelope", .module = protocol.module("envelope") }, .{ .name = "system-call", .module = system_call }, .{ .name = "ipc", .module = ipc }, .{ .name = "time", .module = time }, .{ .name = "device-manager-protocol", .module = protocol.module("device-manager-protocol") }, }, }); // A device driver's view of its claimed PCI function: config-space header // fields, BAR decode + map, capability walks (legacy + extended), MSI/MSI-X // programming, power state, and function-level reset — the generic PCI // mechanics every leaf PCI driver used to re-derive inline. _ = b.addModule("pci", .{ .root_source_file = b.path("pci/pci.zig"), .imports = &.{ .{ .name = "driver", .module = driver }, .{ .name = "mmio", .module = mmio }, .{ .name = "pci-class", .module = pci_class }, .{ .name = "time", .module = time }, }, }); // The USB class-driver transfer client: open a device on the xHCI bus and // drive it (control / interrupt / bulk). Re-exports usb-abi / usb-ids as // usb.abi / usb.ids for a single USB import. _ = b.addModule("usb", .{ .root_source_file = b.path("usb/usb.zig"), .imports = &.{ .{ .name = "channel", .module = channel }, .{ .name = "envelope", .module = protocol.module("envelope") }, .{ .name = "ipc", .module = ipc }, .{ .name = "time", .module = time }, .{ .name = "usb-transfer-protocol", .module = protocol.module("usb-transfer-protocol") }, .{ .name = "usb-abi", .module = usb_abi }, .{ .name = "usb-ids", .module = usb_ids }, }, }); // The block-device client — a device type, so it lives here. _ = b.addModule("block", .{ .root_source_file = b.path("block/block.zig"), .imports = &.{ .{ .name = "channel", .module = channel }, .{ .name = "envelope", .module = protocol.module("envelope") }, .{ .name = "ipc", .module = ipc }, .{ .name = "time", .module = time }, .{ .name = "block-protocol", .module = protocol.module("block-protocol") }, }, }); // The device registry: parse /system/configuration/devices.csv into match rules and bind a // reported device to a driver. Pure logic (no hardware, no syscalls), so it // unit-tests on the host; the device manager imports it. _ = b.addModule("device-registry", .{ .root_source_file = b.path("registry/device-registry.zig"), .imports = &.{.{ .name = "csv", .module = csv.module("csv") }}, }); // Standalone `zig build test` for this domain alone; the root build keeps // its aggregate test step. const test_step = b.step("test", "Run the device library unit tests"); for ([_][]const u8{ "model/device-abi.zig", // wire-type sizes "pci/pci-class.zig", // class/subclass/prog-IF name decoding "acpi/acpi-ids.zig", // _HID name decoding "acpi/aml/aml.zig", // AML parse + interpret, incl. Notify dispatch "usb/usb-abi.zig", // wire sizes + bit packings + set-up packet encodings "usb/usb-ids.zig", // class/subclass/protocol code assignments "mmio/mmio.zig", // barriers assemble + registers round-trip }) |root| { const device_tests = b.addTest(.{ .root_module = b.createModule(.{ .root_source_file = b.path(root), .target = b.resolveTargetQuery(.{}), }), }); test_step.dependOn(&b.addRunArtifact(device_tests).step); } // The registry needs its csv import wired, so it doesn't fit the loop. const registry_tests = b.addTest(.{ .root_module = b.createModule(.{ .root_source_file = b.path("registry/device-registry.zig"), .target = b.resolveTargetQuery(.{}), .imports = &.{.{ .name = "csv", .module = csv.module("csv") }}, }), }); test_step.dependOn(&b.addRunArtifact(registry_tests).step); }