reorg: relocate device/service clients (C3/C4)
- device.zig + device-manager.zig -> library/device/driver/driver.zig (module
"driver"): the driver author's whole interface — device access (claim/mmioMap/
irqBind/...) plus the device-manager hello() handshake, folded into one import.
- block.zig -> library/device/block/block.zig (a device type).
- display.zig/input.zig -> library/client/{display,input}/ (userspace-service
clients — they talk to services, not the kernel).
build.zig module graph updated; the runtime shim now maps runtime.device and
runtime.device_manager onto "driver", so consumers stay untouched (migrated in C2).
zig build green; driver-restart, usb-storage, display-native, input pass.
This commit is contained in:
@@ -481,32 +481,31 @@ pub fn build(b: *std.Build) void {
|
|||||||
.root_source_file = b.path("library/kernel/start.zig"),
|
.root_source_file = b.path("library/kernel/start.zig"),
|
||||||
.imports = &.{ .{ .name = "process", .module = process_module }, .{ .name = "logging", .module = logging_module } },
|
.imports = &.{ .{ .name = "process", .module = process_module }, .{ .name = "logging", .module = logging_module } },
|
||||||
});
|
});
|
||||||
const device_module = b.addModule("device", .{
|
// The driver author's interface (library/device/driver): device access + the
|
||||||
.root_source_file = b.path("library/kernel/device.zig"),
|
// device-manager hello handshake, folded together.
|
||||||
|
const driver_module = b.addModule("driver", .{
|
||||||
|
.root_source_file = b.path("library/device/driver/driver.zig"),
|
||||||
.imports = &.{
|
.imports = &.{
|
||||||
.{ .name = "abi", .module = abi_module },
|
.{ .name = "abi", .module = abi_module },
|
||||||
.{ .name = "device-abi", .module = device_abi_module },
|
.{ .name = "device-abi", .module = device_abi_module },
|
||||||
.{ .name = "system-call", .module = system_call_module },
|
.{ .name = "system-call", .module = system_call_module },
|
||||||
},
|
|
||||||
});
|
|
||||||
const device_manager_client_module = b.addModule("device-manager", .{
|
|
||||||
.root_source_file = b.path("library/kernel/device-manager.zig"),
|
|
||||||
.imports = &.{
|
|
||||||
.{ .name = "ipc", .module = ipc_module },
|
.{ .name = "ipc", .module = ipc_module },
|
||||||
.{ .name = "time", .module = time_module },
|
.{ .name = "time", .module = time_module },
|
||||||
.{ .name = "device-manager-protocol", .module = device_manager_protocol_module },
|
.{ .name = "device-manager-protocol", .module = device_manager_protocol_module },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
// The block-device client — a device type, so library/device/block.
|
||||||
const block_client_module = b.addModule("block", .{
|
const block_client_module = b.addModule("block", .{
|
||||||
.root_source_file = b.path("library/kernel/block.zig"),
|
.root_source_file = b.path("library/device/block/block.zig"),
|
||||||
.imports = &.{
|
.imports = &.{
|
||||||
.{ .name = "ipc", .module = ipc_module },
|
.{ .name = "ipc", .module = ipc_module },
|
||||||
.{ .name = "time", .module = time_module },
|
.{ .name = "time", .module = time_module },
|
||||||
.{ .name = "block-protocol", .module = block_protocol_module },
|
.{ .name = "block-protocol", .module = block_protocol_module },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
// Userspace-service clients live in library/client (they talk to services, not the kernel).
|
||||||
const display_client_module = b.addModule("display", .{
|
const display_client_module = b.addModule("display", .{
|
||||||
.root_source_file = b.path("library/kernel/display.zig"),
|
.root_source_file = b.path("library/client/display/display.zig"),
|
||||||
.imports = &.{
|
.imports = &.{
|
||||||
.{ .name = "ipc", .module = ipc_module },
|
.{ .name = "ipc", .module = ipc_module },
|
||||||
.{ .name = "time", .module = time_module },
|
.{ .name = "time", .module = time_module },
|
||||||
@@ -514,7 +513,7 @@ pub fn build(b: *std.Build) void {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const input_client_module = b.addModule("input", .{
|
const input_client_module = b.addModule("input", .{
|
||||||
.root_source_file = b.path("library/kernel/input.zig"),
|
.root_source_file = b.path("library/client/input/input.zig"),
|
||||||
.imports = &.{
|
.imports = &.{
|
||||||
.{ .name = "ipc", .module = ipc_module },
|
.{ .name = "ipc", .module = ipc_module },
|
||||||
.{ .name = "time", .module = time_module },
|
.{ .name = "time", .module = time_module },
|
||||||
@@ -546,8 +545,7 @@ pub fn build(b: *std.Build) void {
|
|||||||
.{ .name = "logging", .module = logging_module },
|
.{ .name = "logging", .module = logging_module },
|
||||||
.{ .name = "file-system", .module = file_system_module },
|
.{ .name = "file-system", .module = file_system_module },
|
||||||
.{ .name = "start", .module = start_module },
|
.{ .name = "start", .module = start_module },
|
||||||
.{ .name = "device", .module = device_module },
|
.{ .name = "driver", .module = driver_module },
|
||||||
.{ .name = "device-manager", .module = device_manager_client_module },
|
|
||||||
.{ .name = "input", .module = input_client_module },
|
.{ .name = "input", .module = input_client_module },
|
||||||
.{ .name = "block", .module = block_client_module },
|
.{ .name = "block", .module = block_client_module },
|
||||||
.{ .name = "display", .module = display_client_module },
|
.{ .name = "display", .module = display_client_module },
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
//! User-space device access: enumerate the kernel's device table, claim a device,
|
//! library/device/driver — the driver author's interface: enumerate the kernel's device
|
||||||
//! map its MMIO, and bind its interrupt. A driver uses these to find and take
|
//! table, claim a device, map its MMIO, bind its interrupt (the claim is the capability the
|
||||||
//! ownership of its hardware; the claim is the capability the kernel checks before
|
//! kernel checks before mapping registers or routing an IRQ), and say `hello` to the device
|
||||||
//! mapping registers or routing an IRQ.
|
//! manager at startup. The whole kernel + manager surface a driver needs, in one import.
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const abi = @import("abi");
|
const abi = @import("abi");
|
||||||
const device_abi = @import("device-abi");
|
const device_abi = @import("device-abi");
|
||||||
const sc = @import("system-call");
|
const sc = @import("system-call");
|
||||||
|
const ipc = @import("ipc");
|
||||||
|
const time = @import("time");
|
||||||
|
const device_manager_protocol = @import("device-manager-protocol");
|
||||||
|
|
||||||
pub const DeviceDescriptor = device_abi.DeviceDescriptor;
|
pub const DeviceDescriptor = device_abi.DeviceDescriptor;
|
||||||
pub const ResourceDescriptor = device_abi.ResourceDescriptor;
|
pub const ResourceDescriptor = device_abi.ResourceDescriptor;
|
||||||
@@ -129,3 +132,42 @@ pub fn findDeviceDescriptorByHid(buffer: []DeviceDescriptor, hid_needle: []const
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- device-manager handshake (folded in from the former device-manager.zig) ---
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
|
||||||
|
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. Bus drivers keep the handle
|
||||||
|
/// to report children through; a driver that runs fine unsupervised discards it with `_ =`,
|
||||||
|
/// and one that requires supervision bails on null. Logs the outcome itself.
|
||||||
|
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;
|
||||||
|
time.sleepMillis(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;
|
||||||
|
}
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
//! 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");
|
|
||||||
const time = @import("time");
|
|
||||||
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;
|
|
||||||
time.sleepMillis(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;
|
|
||||||
}
|
|
||||||
@@ -20,9 +20,9 @@ pub const fs = @import("file-system");
|
|||||||
pub const start = @import("start");
|
pub const start = @import("start");
|
||||||
pub const panic = start.panic;
|
pub const panic = start.panic;
|
||||||
|
|
||||||
// Device / service clients (relocated to library/device and library/client in C3/C4).
|
// Device / service clients (now in library/device/driver, library/device/block, library/client).
|
||||||
pub const device = @import("device");
|
pub const device = @import("driver");
|
||||||
pub const device_manager = @import("device-manager");
|
pub const device_manager = @import("driver"); // hello() folded into driver
|
||||||
pub const input = @import("input");
|
pub const input = @import("input");
|
||||||
pub const block = @import("block");
|
pub const block = @import("block");
|
||||||
pub const display = @import("display");
|
pub const display = @import("display");
|
||||||
|
|||||||
Reference in New Issue
Block a user