92 lines
4.2 KiB
Zig
92 lines
4.2 KiB
Zig
//! device-list — the `ps` analog for the device tree (docs/device-manager.md
|
|
//! M18.3): asks the device manager for the tree over IPC, prints it, then
|
|
//! subscribes and prints every published add/remove event. The manager is the
|
|
//! one answer to "what devices exist" for user space; nothing here touches a
|
|
//! device_* system call.
|
|
|
|
const std = @import("std");
|
|
const channel = @import("channel");
|
|
const envelope = @import("envelope");
|
|
const ipc = @import("ipc");
|
|
const time = @import("time");
|
|
const logging = @import("logging");
|
|
const device_manager_protocol = @import("device-manager-protocol");
|
|
|
|
fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
|
|
var line: [96]u8 = undefined;
|
|
_ = logging.write(std.fmt.bufPrint(&line, fmt, arguments) catch return);
|
|
}
|
|
|
|
pub fn main() void {
|
|
var manager: ?ipc.Handle = null;
|
|
var tries: u32 = 0;
|
|
while (manager == null and tries < 200) : (tries += 1) {
|
|
manager = channel.openEndpoint("device-manager");
|
|
if (manager == null) time.sleepMillis(20);
|
|
}
|
|
const h = manager orelse {
|
|
_ = logging.write("device-list: no device manager\n");
|
|
return;
|
|
};
|
|
|
|
// The snapshot — polled briefly, because at boot the bus drivers may still
|
|
// be scanning: an empty first answer usually just means "too early". This is
|
|
// the envelope's reserved `enumerate` verb, so the request is nothing but a
|
|
// header and the answer is one `ChildEntry` per record in the reply's tail —
|
|
// how many arrived is the reply's own length, which is why no count header
|
|
// says it a second time.
|
|
const Entry = device_manager_protocol.ChildEntry;
|
|
const enumerate = envelope.Header{ .operation = envelope.operation_enumerate };
|
|
var reply: [device_manager_protocol.message_maximum]u8 = undefined;
|
|
var count: usize = 0;
|
|
tries = 0;
|
|
while (tries < 20) : (tries += 1) {
|
|
const length = ipc.call(h, std.mem.asBytes(&enumerate), &reply) catch 0;
|
|
if (envelope.statusOf(reply[0..length])) |status| {
|
|
if (status.status == 0) {
|
|
const carried = @min(@as(usize, status.len), length - envelope.prefix_size);
|
|
count = carried / @sizeOf(Entry);
|
|
if (count != 0) break;
|
|
}
|
|
}
|
|
time.sleepMillis(100);
|
|
}
|
|
writeLine("device-list: {d} devices\n", .{count});
|
|
for (0..count) |index| {
|
|
const entry = std.mem.bytesToValue(Entry, reply[envelope.prefix_size + index * @sizeOf(Entry) ..][0..@sizeOf(Entry)]);
|
|
writeLine("device-list: device {d} port {d} identity {d}\n", .{ entry.parent, entry.bus_address, entry.identity });
|
|
}
|
|
|
|
// The subscription — the reserved `subscribe` verb: our endpoint rides as
|
|
// the call's capability, and events arrive as buffered packets carrying the
|
|
// same structs the bus drivers send, under the events' own numbering.
|
|
const endpoint = ipc.createIpcEndpoint() orelse {
|
|
_ = logging.write("device-list: no endpoint\n");
|
|
return;
|
|
};
|
|
const subscribe = envelope.Header{ .operation = envelope.operation_subscribe };
|
|
_ = ipc.callCap(h, std.mem.asBytes(&subscribe), &reply, endpoint) catch {
|
|
_ = logging.write("device-list: subscribe failed\n");
|
|
return;
|
|
};
|
|
_ = logging.write("device-list: subscribed\n");
|
|
|
|
var receive: [device_manager_protocol.message_maximum]u8 = undefined;
|
|
while (true) {
|
|
const got = ipc.replyWait(endpoint, &.{}, &receive, null);
|
|
if (!got.isMessage()) continue;
|
|
const packet = receive[0..got.len];
|
|
const event = device_manager_protocol.Protocol.eventOf(packet) orelse continue;
|
|
switch (event) {
|
|
.child_added => {
|
|
const added = device_manager_protocol.Protocol.decodeEvent(.child_added, packet) orelse continue;
|
|
writeLine("device-list: added (device {d} port {d})\n", .{ added.parent, added.bus_address });
|
|
},
|
|
.child_removed => {
|
|
const removed = device_manager_protocol.Protocol.decodeEvent(.child_removed, packet) orelse continue;
|
|
writeLine("device-list: removed (device {d} port {d})\n", .{ removed.parent, removed.bus_address });
|
|
},
|
|
}
|
|
}
|
|
}
|