//! 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 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 = 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 = protocol.Hello{ .role = @intFromEnum(role), .device_id = device_id }; var reply: [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 < protocol.reply_size or std.mem.bytesToValue(protocol.HelloReply, reply[0..protocol.reply_size]).status != 0) { std.log.info("hello refused", .{}); return null; } std.log.info("hello acknowledged", .{}); return manager; }