Finish the direct-import convention: a protocol is now aliased to its module name in snake_case in every file that imports one — consumers and the runtime client wrappers alike. This kills the last of the alias variety (the generic `protocol`, plus `power` and `transfer`), so `device_manager_protocol.Hello` means the same thing everywhere and grepping a module name finds all its uses. Pure rename (identifier uses only; prose references left untouched via a guarded pattern). 14 files, 299/299 lines. zig build + test green; 16 QEMU cases pass (smoke, device-manager, driver-restart, device-list, pci-scan, usb-hid, usb-storage, display-service, display-native, display-reattach, input, acpi-ps2, vfs, fat-mount, power-button, orderly-shutdown).
60 lines
2.8 KiB
Zig
60 lines
2.8 KiB
Zig
//! Client side of the device-manager protocol (docs/device-manager.md): the
|
|
//! calls a supervised driver makes *to* the manager, as opposed to
|
|
//! `device-manager-protocol.zig`, which is the wire contract both sides share.
|
|
//!
|
|
//! Today this is just the hello handshake every spawned driver owes. The
|
|
//! manager arms a hello deadline when it spawns a driver
|
|
//! (system/services/device-manager/device-manager.zig): a driver that stays
|
|
//! silent past it is assumed wedged before `main` and stopped, so every driver
|
|
//! calls `hello` early in its startup. The retry-lookup-call-check this used to
|
|
//! be — copied byte-for-byte into each bus and class driver — lives here once.
|
|
|
|
const std = @import("std");
|
|
const ipc = @import("ipc.zig");
|
|
const system = @import("system.zig");
|
|
const device_manager_protocol = @import("device-manager-protocol");
|
|
|
|
/// What kind of driver is announcing itself (a bus that reports children, or a
|
|
/// leaf device). Re-exported so callers name it without importing the protocol.
|
|
pub const Role = device_manager_protocol.Role;
|
|
|
|
/// Endpoint lookups while the manager is still registering, and the pause
|
|
/// between them: 100 x 20 ms = ~2 s, comfortably inside the manager's 3 s hello
|
|
/// deadline (device-manager.zig `hello_deadline_ms`).
|
|
const lookup_attempts: u32 = 100;
|
|
const lookup_pause_ms: u64 = 20;
|
|
|
|
/// Say hello to the device manager and return its endpoint, or null if there is
|
|
/// no manager (best-effort standalone bring-up) or it refused the handshake
|
|
/// (version mismatch, unknown sender). Bus drivers keep the returned handle to
|
|
/// report children through; a driver that runs fine unsupervised discards it
|
|
/// with `_ =`, and a driver that requires supervision bails on null.
|
|
///
|
|
/// Logs the outcome itself (attribution is the kernel's, via the process's
|
|
/// binary path), so callers stay a single line.
|
|
pub fn hello(role: Role, device_id: u64) ?ipc.Handle {
|
|
var attempts: u32 = 0;
|
|
const manager = while (attempts < lookup_attempts) : (attempts += 1) {
|
|
if (ipc.lookup(.device_manager)) |handle| break handle;
|
|
system.sleep(lookup_pause_ms);
|
|
} else {
|
|
std.log.info("no device manager to hello", .{});
|
|
return null;
|
|
};
|
|
|
|
const message = device_manager_protocol.Hello{ .role = @intFromEnum(role), .device_id = device_id };
|
|
var reply: [device_manager_protocol.reply_size]u8 = undefined;
|
|
const length = ipc.call(manager, std.mem.asBytes(&message), &reply) catch {
|
|
std.log.info("hello call failed", .{});
|
|
return null;
|
|
};
|
|
if (length < device_manager_protocol.reply_size or
|
|
std.mem.bytesToValue(device_manager_protocol.HelloReply, reply[0..device_manager_protocol.reply_size]).status != 0)
|
|
{
|
|
std.log.info("hello refused", .{});
|
|
return null;
|
|
}
|
|
std.log.info("hello acknowledged", .{});
|
|
return manager;
|
|
}
|