reorg: move input-protocol to library/protocol + direct import

input-protocol -> library/protocol/input/input-protocol.zig. Its five
consumers (usb-hid keyboard/mouse, ps2 keyboard/mouse, the input service) now
import the module directly and alias it input_protocol, replacing the
runtime.input_protocol re-export (deleted) and the inconsistent local `protocol`
aliases. runtime.input (the client) still imports the module by name.

zig build + test green; input, acpi-ps2, usb-hid pass.
This commit is contained in:
Daniel Samson
2026-07-22 20:54:53 +01:00
parent 25cc4d610e
commit 07c901c18c
8 changed files with 37 additions and 34 deletions
+6 -1
View File
@@ -375,7 +375,7 @@ pub fn build(b: *std.Build) void {
// module the same way vfs-protocol is. Shared by the input service, the runtime's
// `input` helper (subscribe/publish), and every source and subscriber.
const input_protocol_module = b.addModule("input-protocol", .{
.root_source_file = b.path("system/services/input/protocol.zig"),
.root_source_file = b.path("library/protocol/input/input-protocol.zig"),
});
// The danos-native user-space runtime: system_call wrappers, the C-convention
@@ -547,7 +547,9 @@ pub fn build(b: *std.Build) void {
const vfstest_exe = addUserBinary(b, kernel_target, runtime_module, mmio_module, xkeyboard_config_module, acpi_ids_module, "vfs-test", "system/services/vfs-test/vfs-test.zig");
const ps2_bus_exe = addUserBinary(b, kernel_target, runtime_module, mmio_module, xkeyboard_config_module, acpi_ids_module, "ps2-bus", "system/drivers/ps2-bus/ps2-bus.zig");
const ps2_keyboard_exe = addUserBinary(b, kernel_target, runtime_module, mmio_module, xkeyboard_config_module, acpi_ids_module, "ps2-keyboard", "system/drivers/ps2-bus/keyboard.zig");
programModule(ps2_keyboard_exe).addImport("input-protocol", input_protocol_module);
const ps2_mouse_exe = addUserBinary(b, kernel_target, runtime_module, mmio_module, xkeyboard_config_module, acpi_ids_module, "ps2-mouse", "system/drivers/ps2-bus/mouse.zig");
programModule(ps2_mouse_exe).addImport("input-protocol", input_protocol_module);
const usb_xhci_bus_exe = addUserBinary(b, kernel_target, runtime_module, mmio_module, xkeyboard_config_module, acpi_ids_module, "usb-xhci-bus", "system/drivers/usb-xhci-bus/usb-xhci-bus.zig");
// The xHCI bus driver builds chapter-9 requests and decodes descriptors from
// usb-abi, and reports each interface's (class,subclass,protocol) identity via
@@ -561,9 +563,11 @@ pub fn build(b: *std.Build) void {
const usb_hid_keyboard_exe = addUserBinary(b, kernel_target, runtime_module, mmio_module, xkeyboard_config_module, acpi_ids_module, "usb-hid-keyboard", "system/drivers/usb-hid/keyboard.zig");
programModule(usb_hid_keyboard_exe).addImport("usb", usb_module);
programModule(usb_hid_keyboard_exe).addImport("usb-abi", usb_abi_module);
programModule(usb_hid_keyboard_exe).addImport("input-protocol", input_protocol_module);
const usb_hid_mouse_exe = addUserBinary(b, kernel_target, runtime_module, mmio_module, xkeyboard_config_module, acpi_ids_module, "usb-hid-mouse", "system/drivers/usb-hid/mouse.zig");
programModule(usb_hid_mouse_exe).addImport("usb", usb_module);
programModule(usb_hid_mouse_exe).addImport("usb-abi", usb_abi_module);
programModule(usb_hid_mouse_exe).addImport("input-protocol", input_protocol_module);
// The USB mass-storage class driver: opens its device via runtime.usb, drives it
// with Bulk-Only Transport + SCSI, and serves the block protocol under `.block`.
const usb_storage_exe = addUserBinary(b, kernel_target, runtime_module, mmio_module, xkeyboard_config_module, acpi_ids_module, "usb-storage", "system/drivers/usb-storage/usb-storage.zig");
@@ -614,6 +618,7 @@ pub fn build(b: *std.Build) void {
// The input service and its exercisers: the fan-out server, a hardware-free synthetic
// source, and a subscriber that doubles as the `input` test's oracle. See docs/input.md.
const input_exe = addUserBinary(b, kernel_target, runtime_module, mmio_module, xkeyboard_config_module, acpi_ids_module, "input", "system/services/input/input.zig");
programModule(input_exe).addImport("input-protocol", input_protocol_module);
const input_source_exe = addUserBinary(b, kernel_target, runtime_module, mmio_module, xkeyboard_config_module, acpi_ids_module, "input-source", "system/services/input-source/input-source.zig");
const input_test_exe = addUserBinary(b, kernel_target, runtime_module, mmio_module, xkeyboard_config_module, acpi_ids_module, "input-test", "system/services/input-test/input-test.zig");
const args_echo_exe = addUserBinary(b, kernel_target, runtime_module, mmio_module, xkeyboard_config_module, acpi_ids_module, "args-echo", "system/services/args-echo/args-echo.zig");
-2
View File
@@ -30,8 +30,6 @@ pub const power_protocol = @import("power-protocol");
/// Keyboard-event listening (subscribe/next) and broadcasting (publish), over the input
/// service. See library/runtime/input.zig and system/services/input/.
pub const input = @import("input.zig");
/// The input wire protocol (shared with the input service and its clients).
pub const input_protocol = @import("input-protocol");
/// POSIX-style file API: open/read/write/lseek/stat/close.
/// C stdio: fopen/fread/fwrite/fseek/ftell/fclose over unistd.
/// Device access for drivers: enumerate/claim/mmioMap.
+9 -9
View File
@@ -21,7 +21,7 @@ const ps2 = @import("ps2-library.zig");
const scancode = @import("scancode.zig");
const device = runtime.device;
const ipc = runtime.ipc;
const protocol = runtime.input_protocol;
const input_protocol = @import("input-protocol");
/// Look up the ps2-bus service, retrying while the bus (which spawned us before
/// registering) is still coming up.
@@ -46,7 +46,7 @@ fn characterFor(layout: *const xkb.Layout, usage: u8, modifiers: scancode.Modifi
.control = modifiers.control,
});
if (mapping.character) |character| return character;
return switch (@as(protocol.Keycode, @enumFromInt(usage))) {
return switch (@as(input_protocol.Keycode, @enumFromInt(usage))) {
.enter, .keypad_enter => '\n',
.tab => '\t',
.backspace => 0x08,
@@ -58,9 +58,9 @@ fn characterFor(layout: *const xkb.Layout, usage: u8, modifiers: scancode.Modifi
/// The input protocol's modifier word for a snapshot.
fn modifierWord(modifiers: scancode.ModifierSnapshot) u32 {
var word: u32 = 0;
if (modifiers.shift) word |= protocol.modifier_shift;
if (modifiers.control) word |= protocol.modifier_control;
if (modifiers.alt) word |= protocol.modifier_alt;
if (modifiers.shift) word |= input_protocol.modifier_shift;
if (modifiers.control) word |= input_protocol.modifier_control;
if (modifiers.alt) word |= input_protocol.modifier_alt;
return word;
}
@@ -133,7 +133,7 @@ pub fn main(init: runtime.process.Init) void {
switch (transition.action) {
.pressed => {
_ = source.publishKeyboardEvent(.{
.kind = @intFromEnum(protocol.EventKind.key_down),
.kind = @intFromEnum(input_protocol.EventKind.key_down),
.keycode = key.usage,
.character = 0,
.modifiers = modifiers,
@@ -141,7 +141,7 @@ pub fn main(init: runtime.process.Init) void {
const character = characterFor(layout, key.usage, transition.modifiers);
if (character != 0) {
_ = source.publishKeyboardEvent(.{
.kind = @intFromEnum(protocol.EventKind.key_press),
.kind = @intFromEnum(input_protocol.EventKind.key_press),
.keycode = key.usage,
.character = character,
.modifiers = modifiers,
@@ -154,7 +154,7 @@ pub fn main(init: runtime.process.Init) void {
const character = characterFor(layout, key.usage, transition.modifiers);
if (character != 0) {
_ = source.publishKeyboardEvent(.{
.kind = @intFromEnum(protocol.EventKind.key_press),
.kind = @intFromEnum(input_protocol.EventKind.key_press),
.keycode = key.usage,
.character = character,
.modifiers = modifiers,
@@ -163,7 +163,7 @@ pub fn main(init: runtime.process.Init) void {
},
.released => {
_ = source.publishKeyboardEvent(.{
.kind = @intFromEnum(protocol.EventKind.key_up),
.kind = @intFromEnum(input_protocol.EventKind.key_up),
.keycode = key.usage,
.character = 0,
.modifiers = modifiers,
+7 -7
View File
@@ -20,7 +20,7 @@ const ps2 = @import("ps2-library.zig");
const mouse_packet = @import("mouse-packet.zig");
const device = runtime.device;
const ipc = runtime.ipc;
const protocol = runtime.input_protocol;
const input_protocol = @import("input-protocol");
/// Look up the ps2-bus service, retrying while the bus (which spawned us before
/// registering) is still coming up.
@@ -36,9 +36,9 @@ fn lookupBus() ?ipc.Handle {
/// The protocol's pressed-button bitmask for a packet.
fn buttonMask(packet: mouse_packet.Packet) u32 {
var mask: u32 = 0;
if (packet.left) mask |= protocol.mouse_button_left;
if (packet.right) mask |= protocol.mouse_button_right;
if (packet.middle) mask |= protocol.mouse_button_middle;
if (packet.left) mask |= input_protocol.mouse_button_left;
if (packet.right) mask |= input_protocol.mouse_button_right;
if (packet.middle) mask |= input_protocol.mouse_button_middle;
return mask;
}
@@ -104,9 +104,9 @@ pub fn main(init: runtime.process.Init) void {
// A button transition per changed button, carrying the new whole mask.
const changed = buttons ^ new_buttons;
for ([_]u32{ protocol.mouse_button_left, protocol.mouse_button_right, protocol.mouse_button_middle }) |button| {
for ([_]u32{ input_protocol.mouse_button_left, input_protocol.mouse_button_right, input_protocol.mouse_button_middle }) |button| {
if (changed & button == 0) continue;
const kind: protocol.MouseEventKind = if (new_buttons & button != 0) .button_down else .button_up;
const kind: input_protocol.MouseEventKind = if (new_buttons & button != 0) .button_down else .button_up;
_ = source.publishMouseEvent(.{
.kind = @intFromEnum(kind),
.button = button,
@@ -121,7 +121,7 @@ pub fn main(init: runtime.process.Init) void {
if (packet.dx != 0 or packet.dy != 0) {
_ = source.publishMouseEvent(.{
.kind = @intFromEnum(protocol.MouseEventKind.motion),
.kind = @intFromEnum(input_protocol.MouseEventKind.motion),
.button = 0,
.dx = packet.dx,
.dy = packet.dy,
+1 -1
View File
@@ -22,7 +22,7 @@ const xkb = @import("xkeyboard-config");
const hid = @import("hid-report.zig");
const ipc = runtime.ipc;
const process = runtime.process;
const input_protocol = runtime.input_protocol;
const input_protocol = @import("input-protocol");
// The modifier state a character lookup needs — derived from the report's
// modifier byte, plus the driver-tracked caps-lock toggle.
+1 -1
View File
@@ -17,7 +17,7 @@ const usb_abi = @import("usb-abi");
const hid = @import("hid-report.zig");
const ipc = runtime.ipc;
const process = runtime.process;
const input_protocol = runtime.input_protocol;
const input_protocol = @import("input-protocol");
// The current pressed-button bitmask in input-protocol terms.
fn buttonMask(buttons: u8) u32 {
+13 -13
View File
@@ -21,7 +21,7 @@
const std = @import("std");
const runtime = @import("runtime");
const protocol = runtime.input_protocol;
const input_protocol = @import("input-protocol");
const ipc = runtime.ipc;
const system = runtime.system;
@@ -32,7 +32,7 @@ const Subscriber = struct {
used: bool = false,
endpoint: ipc.Handle = 0,
task_id: u32 = 0,
/// Which device classes this subscriber wants (an OR of protocol.device_*). An event
/// Which device classes this subscriber wants (an OR of input_protocol.device_*). An event
/// is delivered only if its device's bit is set here.
device_mask: u32 = 0,
};
@@ -74,9 +74,9 @@ fn addSubscriber(endpoint: ipc.Handle, task_id: u32, device_mask: u32) bool {
/// Push `event` to every subscriber whose interest mask includes its device class.
/// `ipc.send` never blocks, so a slow or dead subscriber cannot stall delivery to others.
fn broadcast(event: protocol.InputEvent) void {
fn broadcast(event: input_protocol.InputEvent) void {
const bytes = std.mem.asBytes(&event);
const bit = protocol.deviceBit(event.device);
const bit = input_protocol.deviceBit(event.device);
for (&subscribers) |*sub| {
if (sub.used and sub.device_mask & bit != 0) _ = ipc.send(sub.endpoint, bytes);
}
@@ -88,20 +88,20 @@ fn broadcast(event: protocol.InputEvent) void {
fn handle(message: []const u8, got: ipc.Received, out: []u8) usize {
const reply = struct {
fn write(buffer: []u8, status: i32) usize {
const header = protocol.Reply{ .status = status };
@memcpy(buffer[0..protocol.reply_size], std.mem.asBytes(&header));
return protocol.reply_size;
const header = input_protocol.Reply{ .status = status };
@memcpy(buffer[0..input_protocol.reply_size], std.mem.asBytes(&header));
return input_protocol.reply_size;
}
};
if (message.len < protocol.request_size) return reply.write(out, -1);
const request = std.mem.bytesToValue(protocol.Request, message[0..protocol.request_size]);
if (message.len < input_protocol.request_size) return reply.write(out, -1);
const request = std.mem.bytesToValue(input_protocol.Request, message[0..input_protocol.request_size]);
switch (@as(protocol.Operation, @enumFromInt(request.operation))) {
switch (@as(input_protocol.Operation, @enumFromInt(request.operation))) {
.subscribe => {
const endpoint = got.cap orelse return reply.write(out, -1); // no endpoint passed
// A zero mask means "everything" (a subscriber that named no class still wants input).
const mask = if (request.device_mask == 0) protocol.device_all else request.device_mask;
const mask = if (request.device_mask == 0) input_protocol.device_all else request.device_mask;
pruneDeadSubscribers();
if (!addSubscriber(endpoint, @intCast(got.badge), mask)) return reply.write(out, -1); // table full
return reply.write(out, 0);
@@ -124,9 +124,9 @@ pub fn main() void {
}
_ = system.write("/system/services/input: ready\n");
var reply_buffer: [protocol.reply_size]u8 = undefined;
var reply_buffer: [input_protocol.reply_size]u8 = undefined;
var reply_len: usize = 0;
var receive: [protocol.request_size]u8 = undefined;
var receive: [input_protocol.request_size]u8 = undefined;
while (true) {
const got = ipc.replyWait(endpoint, reply_buffer[0..reply_len], &receive, null);
// Only synchronous client requests (subscribe/publish) arrive here; nothing sends