reorg: normalise every protocol alias to its module name
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).
This commit is contained in:
+22
-22
@@ -19,16 +19,16 @@ const std = @import("std");
|
|||||||
const runtime = @import("runtime");
|
const runtime = @import("runtime");
|
||||||
const ipc = runtime.ipc;
|
const ipc = runtime.ipc;
|
||||||
const system = runtime.system;
|
const system = runtime.system;
|
||||||
const protocol = @import("usb-transfer-protocol");
|
const usb_transfer_protocol = @import("usb-transfer-protocol");
|
||||||
|
|
||||||
/// The USB chapter-9 wire ABI and the class taxonomy, re-exported so a class driver reaches
|
/// The USB chapter-9 wire ABI and the class taxonomy, re-exported so a class driver reaches
|
||||||
/// the whole USB domain through its one `usb` import (`usb.abi.getDescriptor`, `usb.ids.Class`).
|
/// the whole USB domain through its one `usb` import (`usb.abi.getDescriptor`, `usb.ids.Class`).
|
||||||
pub const abi = @import("usb-abi");
|
pub const abi = @import("usb-abi");
|
||||||
pub const ids = @import("usb-ids");
|
pub const ids = @import("usb-ids");
|
||||||
|
|
||||||
pub const Endpoint = protocol.Endpoint;
|
pub const Endpoint = usb_transfer_protocol.Endpoint;
|
||||||
pub const InterruptReport = protocol.InterruptReport;
|
pub const InterruptReport = usb_transfer_protocol.InterruptReport;
|
||||||
pub const max_report_data = protocol.max_report_data;
|
pub const max_report_data = usb_transfer_protocol.max_report_data;
|
||||||
|
|
||||||
// Endpoint transfer types (EndpointDescriptor attributes), for `findEndpoint`.
|
// Endpoint transfer types (EndpointDescriptor attributes), for `findEndpoint`.
|
||||||
pub const transfer_type_bulk: u8 = 2;
|
pub const transfer_type_bulk: u8 = 2;
|
||||||
@@ -46,7 +46,7 @@ pub const Device = struct {
|
|||||||
protocol_code: u8,
|
protocol_code: u8,
|
||||||
interface_number: u8,
|
interface_number: u8,
|
||||||
endpoint_count: usize = 0,
|
endpoint_count: usize = 0,
|
||||||
endpoints: [protocol.max_reported_endpoints]Endpoint = undefined,
|
endpoints: [usb_transfer_protocol.max_reported_endpoints]Endpoint = undefined,
|
||||||
|
|
||||||
/// The interface's first endpoint of the given transfer type and direction
|
/// The interface's first endpoint of the given transfer type and direction
|
||||||
/// (`transfer_type_bulk` / `transfer_type_interrupt`), or null.
|
/// (`transfer_type_bulk` / `transfer_type_interrupt`), or null.
|
||||||
@@ -58,17 +58,17 @@ pub const Device = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn controlTransfer(self: *Device, setup: [8]u8, direction_in: bool, data: []u8) ?usize {
|
fn controlTransfer(self: *Device, setup: [8]u8, direction_in: bool, data: []u8) ?usize {
|
||||||
var request = protocol.ControlRequest{
|
var request = usb_transfer_protocol.ControlRequest{
|
||||||
.device_token = self.token,
|
.device_token = self.token,
|
||||||
.setup = setup,
|
.setup = setup,
|
||||||
.direction_in = @intFromBool(direction_in),
|
.direction_in = @intFromBool(direction_in),
|
||||||
.data_length = @intCast(data.len),
|
.data_length = @intCast(data.len),
|
||||||
};
|
};
|
||||||
if (!direction_in and data.len > 0) @memcpy(request.data[0..data.len], data);
|
if (!direction_in and data.len > 0) @memcpy(request.data[0..data.len], data);
|
||||||
var reply: [@sizeOf(protocol.ControlReply)]u8 = undefined;
|
var reply: [@sizeOf(usb_transfer_protocol.ControlReply)]u8 = undefined;
|
||||||
const length = ipc.call(self.bus, std.mem.asBytes(&request), &reply) catch return null;
|
const length = ipc.call(self.bus, std.mem.asBytes(&request), &reply) catch return null;
|
||||||
if (length < @sizeOf(protocol.ControlReply)) return null;
|
if (length < @sizeOf(usb_transfer_protocol.ControlReply)) return null;
|
||||||
const control_reply = std.mem.bytesToValue(protocol.ControlReply, reply[0..@sizeOf(protocol.ControlReply)]);
|
const control_reply = std.mem.bytesToValue(usb_transfer_protocol.ControlReply, reply[0..@sizeOf(usb_transfer_protocol.ControlReply)]);
|
||||||
if (control_reply.status != 0) return null;
|
if (control_reply.status != 0) return null;
|
||||||
const actual = @min(control_reply.actual_length, data.len);
|
const actual = @min(control_reply.actual_length, data.len);
|
||||||
if (direction_in and actual > 0) @memcpy(data[0..actual], control_reply.data[0..actual]);
|
if (direction_in and actual > 0) @memcpy(data[0..actual], control_reply.data[0..actual]);
|
||||||
@@ -89,30 +89,30 @@ pub const Device = struct {
|
|||||||
/// Begin periodic IN polling of an interrupt endpoint; reports flow back to
|
/// Begin periodic IN polling of an interrupt endpoint; reports flow back to
|
||||||
/// `self.endpoint` as asynchronous `InterruptReport` messages.
|
/// `self.endpoint` as asynchronous `InterruptReport` messages.
|
||||||
pub fn subscribeInterrupt(self: *Device, endpoint_address: u8, max_length: u16) bool {
|
pub fn subscribeInterrupt(self: *Device, endpoint_address: u8, max_length: u16) bool {
|
||||||
var request = protocol.InterruptSubscribeRequest{
|
var request = usb_transfer_protocol.InterruptSubscribeRequest{
|
||||||
.device_token = self.token,
|
.device_token = self.token,
|
||||||
.endpoint_address = endpoint_address,
|
.endpoint_address = endpoint_address,
|
||||||
.max_length = max_length,
|
.max_length = max_length,
|
||||||
};
|
};
|
||||||
var reply: [@sizeOf(protocol.InterruptSubscribeReply)]u8 = undefined;
|
var reply: [@sizeOf(usb_transfer_protocol.InterruptSubscribeReply)]u8 = undefined;
|
||||||
const length = ipc.call(self.bus, std.mem.asBytes(&request), &reply) catch return false;
|
const length = ipc.call(self.bus, std.mem.asBytes(&request), &reply) catch return false;
|
||||||
if (length < @sizeOf(protocol.InterruptSubscribeReply)) return false;
|
if (length < @sizeOf(usb_transfer_protocol.InterruptSubscribeReply)) return false;
|
||||||
return std.mem.bytesToValue(protocol.InterruptSubscribeReply, reply[0..@sizeOf(protocol.InterruptSubscribeReply)]).status == 0;
|
return std.mem.bytesToValue(usb_transfer_protocol.InterruptSubscribeReply, reply[0..@sizeOf(usb_transfer_protocol.InterruptSubscribeReply)]).status == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// One bulk transfer (IN or OUT per `endpoint_address`'s direction bit) to or
|
/// One bulk transfer (IN or OUT per `endpoint_address`'s direction bit) to or
|
||||||
/// from the caller's own DMA buffer at `physical`. Returns the bytes moved.
|
/// from the caller's own DMA buffer at `physical`. Returns the bytes moved.
|
||||||
pub fn bulk(self: *Device, endpoint_address: u8, physical: u64, length: u32) ?u32 {
|
pub fn bulk(self: *Device, endpoint_address: u8, physical: u64, length: u32) ?u32 {
|
||||||
var request = protocol.BulkRequest{
|
var request = usb_transfer_protocol.BulkRequest{
|
||||||
.device_token = self.token,
|
.device_token = self.token,
|
||||||
.physical_address = physical,
|
.physical_address = physical,
|
||||||
.length = length,
|
.length = length,
|
||||||
.endpoint_address = endpoint_address,
|
.endpoint_address = endpoint_address,
|
||||||
};
|
};
|
||||||
var reply: [@sizeOf(protocol.BulkReply)]u8 = undefined;
|
var reply: [@sizeOf(usb_transfer_protocol.BulkReply)]u8 = undefined;
|
||||||
const replied = ipc.call(self.bus, std.mem.asBytes(&request), &reply) catch return null;
|
const replied = ipc.call(self.bus, std.mem.asBytes(&request), &reply) catch return null;
|
||||||
if (replied < @sizeOf(protocol.BulkReply)) return null;
|
if (replied < @sizeOf(usb_transfer_protocol.BulkReply)) return null;
|
||||||
const bulk_reply = std.mem.bytesToValue(protocol.BulkReply, reply[0..@sizeOf(protocol.BulkReply)]);
|
const bulk_reply = std.mem.bytesToValue(usb_transfer_protocol.BulkReply, reply[0..@sizeOf(usb_transfer_protocol.BulkReply)]);
|
||||||
if (bulk_reply.status != 0) return null;
|
if (bulk_reply.status != 0) return null;
|
||||||
return bulk_reply.actual_length;
|
return bulk_reply.actual_length;
|
||||||
}
|
}
|
||||||
@@ -129,11 +129,11 @@ pub fn open(device_id: u64) ?Device {
|
|||||||
} else return null;
|
} else return null;
|
||||||
|
|
||||||
const endpoint = ipc.createIpcEndpoint() orelse return null;
|
const endpoint = ipc.createIpcEndpoint() orelse return null;
|
||||||
var request = protocol.OpenRequest{ .device_id = device_id };
|
var request = usb_transfer_protocol.OpenRequest{ .device_id = device_id };
|
||||||
var reply: [@sizeOf(protocol.OpenReply)]u8 = undefined;
|
var reply: [@sizeOf(usb_transfer_protocol.OpenReply)]u8 = undefined;
|
||||||
const result = ipc.callCap(bus, std.mem.asBytes(&request), &reply, endpoint) catch return null;
|
const result = ipc.callCap(bus, std.mem.asBytes(&request), &reply, endpoint) catch return null;
|
||||||
if (result.len < @sizeOf(protocol.OpenReply)) return null;
|
if (result.len < @sizeOf(usb_transfer_protocol.OpenReply)) return null;
|
||||||
const open_reply = std.mem.bytesToValue(protocol.OpenReply, reply[0..@sizeOf(protocol.OpenReply)]);
|
const open_reply = std.mem.bytesToValue(usb_transfer_protocol.OpenReply, reply[0..@sizeOf(usb_transfer_protocol.OpenReply)]);
|
||||||
if (open_reply.status != 0) return null;
|
if (open_reply.status != 0) return null;
|
||||||
|
|
||||||
var device = Device{
|
var device = Device{
|
||||||
@@ -144,7 +144,7 @@ pub fn open(device_id: u64) ?Device {
|
|||||||
.subclass = open_reply.interface_subclass,
|
.subclass = open_reply.interface_subclass,
|
||||||
.protocol_code = open_reply.interface_protocol,
|
.protocol_code = open_reply.interface_protocol,
|
||||||
.interface_number = open_reply.interface_number,
|
.interface_number = open_reply.interface_number,
|
||||||
.endpoint_count = @min(open_reply.endpoint_count, protocol.max_reported_endpoints),
|
.endpoint_count = @min(open_reply.endpoint_count, usb_transfer_protocol.max_reported_endpoints),
|
||||||
};
|
};
|
||||||
for (0..device.endpoint_count) |index| device.endpoints[index] = open_reply.endpoints[index];
|
for (0..device.endpoint_count) |index| device.endpoints[index] = open_reply.endpoints[index];
|
||||||
return device;
|
return device;
|
||||||
|
|||||||
+10
-10
@@ -10,7 +10,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const ipc = @import("ipc.zig");
|
const ipc = @import("ipc.zig");
|
||||||
const system = @import("system.zig");
|
const system = @import("system.zig");
|
||||||
const protocol = @import("block-protocol");
|
const block_protocol = @import("block-protocol");
|
||||||
|
|
||||||
pub const Geometry = struct { block_size: u32, block_count: u64 };
|
pub const Geometry = struct { block_size: u32, block_count: u64 };
|
||||||
|
|
||||||
@@ -19,11 +19,11 @@ pub const Device = struct {
|
|||||||
|
|
||||||
/// The device's block size and total block count.
|
/// The device's block size and total block count.
|
||||||
pub fn geometry(self: Device) ?Geometry {
|
pub fn geometry(self: Device) ?Geometry {
|
||||||
var request = protocol.Request{ .operation = @intFromEnum(protocol.Operation.geometry), .lba = 0, .count = 0, .physical = 0 };
|
var request = block_protocol.Request{ .operation = @intFromEnum(block_protocol.Operation.geometry), .lba = 0, .count = 0, .physical = 0 };
|
||||||
var reply: [protocol.reply_size]u8 = undefined;
|
var reply: [block_protocol.reply_size]u8 = undefined;
|
||||||
const n = ipc.call(self.endpoint, std.mem.asBytes(&request), &reply) catch return null;
|
const n = ipc.call(self.endpoint, std.mem.asBytes(&request), &reply) catch return null;
|
||||||
if (n < protocol.reply_size) return null;
|
if (n < block_protocol.reply_size) return null;
|
||||||
const result = std.mem.bytesToValue(protocol.Reply, reply[0..protocol.reply_size]);
|
const result = std.mem.bytesToValue(block_protocol.Reply, reply[0..block_protocol.reply_size]);
|
||||||
if (result.status != 0) return null;
|
if (result.status != 0) return null;
|
||||||
return .{ .block_size = result.block_size, .block_count = result.block_count };
|
return .{ .block_size = result.block_size, .block_count = result.block_count };
|
||||||
}
|
}
|
||||||
@@ -45,12 +45,12 @@ pub const Device = struct {
|
|||||||
return self.transfer(.flush, 0, 0, 0);
|
return self.transfer(.flush, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transfer(self: Device, operation: protocol.Operation, lba: u64, count: u32, physical: u64) bool {
|
fn transfer(self: Device, operation: block_protocol.Operation, lba: u64, count: u32, physical: u64) bool {
|
||||||
var request = protocol.Request{ .operation = @intFromEnum(operation), .lba = lba, .count = count, .physical = physical };
|
var request = block_protocol.Request{ .operation = @intFromEnum(operation), .lba = lba, .count = count, .physical = physical };
|
||||||
var reply: [protocol.reply_size]u8 = undefined;
|
var reply: [block_protocol.reply_size]u8 = undefined;
|
||||||
const n = ipc.call(self.endpoint, std.mem.asBytes(&request), &reply) catch return false;
|
const n = ipc.call(self.endpoint, std.mem.asBytes(&request), &reply) catch return false;
|
||||||
if (n < protocol.reply_size) return false;
|
if (n < block_protocol.reply_size) return false;
|
||||||
return std.mem.bytesToValue(protocol.Reply, reply[0..protocol.reply_size]).status == 0;
|
return std.mem.bytesToValue(block_protocol.Reply, reply[0..block_protocol.reply_size]).status == 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,11 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const ipc = @import("ipc.zig");
|
const ipc = @import("ipc.zig");
|
||||||
const system = @import("system.zig");
|
const system = @import("system.zig");
|
||||||
const protocol = @import("device-manager-protocol");
|
const device_manager_protocol = @import("device-manager-protocol");
|
||||||
|
|
||||||
/// What kind of driver is announcing itself (a bus that reports children, or a
|
/// 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.
|
/// leaf device). Re-exported so callers name it without importing the protocol.
|
||||||
pub const Role = protocol.Role;
|
pub const Role = device_manager_protocol.Role;
|
||||||
|
|
||||||
/// Endpoint lookups while the manager is still registering, and the pause
|
/// 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
|
/// between them: 100 x 20 ms = ~2 s, comfortably inside the manager's 3 s hello
|
||||||
@@ -42,14 +42,14 @@ pub fn hello(role: Role, device_id: u64) ?ipc.Handle {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const message = protocol.Hello{ .role = @intFromEnum(role), .device_id = device_id };
|
const message = device_manager_protocol.Hello{ .role = @intFromEnum(role), .device_id = device_id };
|
||||||
var reply: [protocol.reply_size]u8 = undefined;
|
var reply: [device_manager_protocol.reply_size]u8 = undefined;
|
||||||
const length = ipc.call(manager, std.mem.asBytes(&message), &reply) catch {
|
const length = ipc.call(manager, std.mem.asBytes(&message), &reply) catch {
|
||||||
std.log.info("hello call failed", .{});
|
std.log.info("hello call failed", .{});
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
if (length < protocol.reply_size or
|
if (length < device_manager_protocol.reply_size or
|
||||||
std.mem.bytesToValue(protocol.HelloReply, reply[0..protocol.reply_size]).status != 0)
|
std.mem.bytesToValue(device_manager_protocol.HelloReply, reply[0..device_manager_protocol.reply_size]).status != 0)
|
||||||
{
|
{
|
||||||
std.log.info("hello refused", .{});
|
std.log.info("hello refused", .{});
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+36
-36
@@ -6,7 +6,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const ipc = @import("ipc.zig");
|
const ipc = @import("ipc.zig");
|
||||||
const system = @import("system.zig");
|
const system = @import("system.zig");
|
||||||
const protocol = @import("display-protocol");
|
const display_protocol = @import("display-protocol");
|
||||||
|
|
||||||
/// The display's current mode, as `info()` reports it.
|
/// The display's current mode, as `info()` reports it.
|
||||||
pub const Info = struct {
|
pub const Info = struct {
|
||||||
@@ -36,43 +36,43 @@ fn service() ?ipc.Handle {
|
|||||||
|
|
||||||
/// Send one request, receive its reply; true on a zero status. `out` receives the reply
|
/// Send one request, receive its reply; true on a zero status. `out` receives the reply
|
||||||
/// so callers can read `info`/`layer` fields on success.
|
/// so callers can read `info`/`layer` fields on success.
|
||||||
fn transact(request: protocol.Request, out: *protocol.Reply) bool {
|
fn transact(request: display_protocol.Request, out: *display_protocol.Reply) bool {
|
||||||
const h = service() orelse return false;
|
const h = service() orelse return false;
|
||||||
var req = request;
|
var req = request;
|
||||||
var reply: [protocol.reply_size]u8 = undefined;
|
var reply: [display_protocol.reply_size]u8 = undefined;
|
||||||
const len = ipc.call(h, std.mem.asBytes(&req), &reply) catch return false;
|
const len = ipc.call(h, std.mem.asBytes(&req), &reply) catch return false;
|
||||||
if (len < protocol.reply_size) return false;
|
if (len < display_protocol.reply_size) return false;
|
||||||
out.* = std.mem.bytesToValue(protocol.Reply, reply[0..protocol.reply_size]);
|
out.* = std.mem.bytesToValue(display_protocol.Reply, reply[0..display_protocol.reply_size]);
|
||||||
return out.status == 0;
|
return out.status == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The display's current mode, or null if the service never came up.
|
/// The display's current mode, or null if the service never came up.
|
||||||
pub fn info() ?Info {
|
pub fn info() ?Info {
|
||||||
var reply: protocol.Reply = undefined;
|
var reply: display_protocol.Reply = undefined;
|
||||||
if (!transact(.{ .operation = @intFromEnum(protocol.Operation.info) }, &reply)) return null;
|
if (!transact(.{ .operation = @intFromEnum(display_protocol.Operation.info) }, &reply)) return null;
|
||||||
return .{ .width = reply.width, .height = reply.height, .pitch = reply.pitch, .format = reply.format };
|
return .{ .width = reply.width, .height = reply.height, .pitch = reply.pitch, .format = reply.format };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Composite the dirty layers and flush the frame to the screen.
|
/// Composite the dirty layers and flush the frame to the screen.
|
||||||
pub fn present() bool {
|
pub fn present() bool {
|
||||||
var reply: protocol.Reply = undefined;
|
var reply: display_protocol.Reply = undefined;
|
||||||
return transact(.{ .operation = @intFromEnum(protocol.Operation.present) }, &reply);
|
return transact(.{ .operation = @intFromEnum(display_protocol.Operation.present) }, &reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// One selectable display mode.
|
/// One selectable display mode.
|
||||||
pub const Mode = protocol.Mode;
|
pub const Mode = display_protocol.Mode;
|
||||||
|
|
||||||
/// Fill `out` with the resolutions the display can switch to; returns how many were written
|
/// Fill `out` with the resolutions the display can switch to; returns how many were written
|
||||||
/// (zero on the GOP floor, or if the service never came up).
|
/// (zero on the GOP floor, or if the service never came up).
|
||||||
pub fn modes(out: []Mode) usize {
|
pub fn modes(out: []Mode) usize {
|
||||||
const h = service() orelse return 0;
|
const h = service() orelse return 0;
|
||||||
var request = protocol.Request{ .operation = @intFromEnum(protocol.Operation.get_modes) };
|
var request = display_protocol.Request{ .operation = @intFromEnum(display_protocol.Operation.get_modes) };
|
||||||
var reply: [protocol.modes_reply_size]u8 = undefined;
|
var reply: [display_protocol.modes_reply_size]u8 = undefined;
|
||||||
const len = ipc.call(h, std.mem.asBytes(&request), &reply) catch return 0;
|
const len = ipc.call(h, std.mem.asBytes(&request), &reply) catch return 0;
|
||||||
if (len < protocol.modes_reply_size) return 0;
|
if (len < display_protocol.modes_reply_size) return 0;
|
||||||
const answer = std.mem.bytesToValue(protocol.ModesReply, reply[0..protocol.modes_reply_size]);
|
const answer = std.mem.bytesToValue(display_protocol.ModesReply, reply[0..display_protocol.modes_reply_size]);
|
||||||
if (answer.status != 0) return 0;
|
if (answer.status != 0) return 0;
|
||||||
const count = @min(@min(answer.count, protocol.max_modes), out.len);
|
const count = @min(@min(answer.count, display_protocol.max_modes), out.len);
|
||||||
for (0..count) |i| out[i] = answer.modes[i];
|
for (0..count) |i| out[i] = answer.modes[i];
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@@ -80,8 +80,8 @@ pub fn modes(out: []Mode) usize {
|
|||||||
/// Change the display resolution. Only a native backend that supports mode-setting honours it
|
/// Change the display resolution. Only a native backend that supports mode-setting honours it
|
||||||
/// (on the GOP floor it returns false); on success the display's `info()` reports the new mode.
|
/// (on the GOP floor it returns false); on success the display's `info()` reports the new mode.
|
||||||
pub fn setMode(width: u32, height: u32) bool {
|
pub fn setMode(width: u32, height: u32) bool {
|
||||||
var reply: protocol.Reply = undefined;
|
var reply: display_protocol.Reply = undefined;
|
||||||
const changed = transact(.{ .operation = @intFromEnum(protocol.Operation.set_mode), .width = width, .height = height }, &reply);
|
const changed = transact(.{ .operation = @intFromEnum(display_protocol.Operation.set_mode), .width = width, .height = height }, &reply);
|
||||||
if (changed) mode = null; // the cached mode is stale now
|
if (changed) mode = null; // the cached mode is stale now
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
@@ -100,7 +100,7 @@ fn cachedInfo() ?Info {
|
|||||||
/// client packs colours through this so it never has to know the byte order itself.
|
/// client packs colours through this so it never has to know the byte order itself.
|
||||||
pub fn color(r: u8, g: u8, b: u8) u32 {
|
pub fn color(r: u8, g: u8, b: u8) u32 {
|
||||||
const format = if (cachedInfo()) |i| i.format else 0;
|
const format = if (cachedInfo()) |i| i.format else 0;
|
||||||
return protocol.pack(format, r, g, b);
|
return display_protocol.pack(format, r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A handle to a server-owned layer: a positioned, z-ordered surface the client draws
|
/// A handle to a server-owned layer: a positioned, z-ordered surface the client draws
|
||||||
@@ -111,9 +111,9 @@ pub const Layer = struct {
|
|||||||
|
|
||||||
/// Fill a rectangle of this layer (layer-local coordinates) with a native `colour`.
|
/// Fill a rectangle of this layer (layer-local coordinates) with a native `colour`.
|
||||||
pub fn fill(self: Layer, x: i32, y: i32, w: u32, h: u32, colour: u32) bool {
|
pub fn fill(self: Layer, x: i32, y: i32, w: u32, h: u32, colour: u32) bool {
|
||||||
var reply: protocol.Reply = undefined;
|
var reply: display_protocol.Reply = undefined;
|
||||||
return transact(.{
|
return transact(.{
|
||||||
.operation = @intFromEnum(protocol.Operation.fill_rect),
|
.operation = @intFromEnum(display_protocol.Operation.fill_rect),
|
||||||
.layer = self.id,
|
.layer = self.id,
|
||||||
.x = @bitCast(x),
|
.x = @bitCast(x),
|
||||||
.y = @bitCast(y),
|
.y = @bitCast(y),
|
||||||
@@ -125,10 +125,10 @@ pub const Layer = struct {
|
|||||||
|
|
||||||
/// Copy a `w`×`h` tile of native pixels (row-major, little-endian bytes) into this
|
/// Copy a `w`×`h` tile of native pixels (row-major, little-endian bytes) into this
|
||||||
/// layer at (`x`, `y`). The tile rides inline in the request, so `w*h*4` must fit
|
/// layer at (`x`, `y`). The tile rides inline in the request, so `w*h*4` must fit
|
||||||
/// `protocol.maximum_payload`.
|
/// `display_protocol.maximum_payload`.
|
||||||
pub fn blitTile(self: Layer, x: i32, y: i32, w: u32, h: u32, pixels: []const u8) bool {
|
pub fn blitTile(self: Layer, x: i32, y: i32, w: u32, h: u32, pixels: []const u8) bool {
|
||||||
var request = protocol.Request{
|
var request = display_protocol.Request{
|
||||||
.operation = @intFromEnum(protocol.Operation.blit_tile),
|
.operation = @intFromEnum(display_protocol.Operation.blit_tile),
|
||||||
.layer = self.id,
|
.layer = self.id,
|
||||||
.x = @bitCast(x),
|
.x = @bitCast(x),
|
||||||
.y = @bitCast(y),
|
.y = @bitCast(y),
|
||||||
@@ -136,22 +136,22 @@ pub const Layer = struct {
|
|||||||
.height = h,
|
.height = h,
|
||||||
};
|
};
|
||||||
const header = std.mem.asBytes(&request);
|
const header = std.mem.asBytes(&request);
|
||||||
if (header.len + pixels.len > protocol.message_maximum) return false;
|
if (header.len + pixels.len > display_protocol.message_maximum) return false;
|
||||||
var buffer: [protocol.message_maximum]u8 = undefined;
|
var buffer: [display_protocol.message_maximum]u8 = undefined;
|
||||||
@memcpy(buffer[0..header.len], header);
|
@memcpy(buffer[0..header.len], header);
|
||||||
@memcpy(buffer[header.len..][0..pixels.len], pixels);
|
@memcpy(buffer[header.len..][0..pixels.len], pixels);
|
||||||
const h_svc = service() orelse return false;
|
const h_svc = service() orelse return false;
|
||||||
var reply: [protocol.reply_size]u8 = undefined;
|
var reply: [display_protocol.reply_size]u8 = undefined;
|
||||||
const len = ipc.call(h_svc, buffer[0 .. header.len + pixels.len], &reply) catch return false;
|
const len = ipc.call(h_svc, buffer[0 .. header.len + pixels.len], &reply) catch return false;
|
||||||
if (len < protocol.reply_size) return false;
|
if (len < display_protocol.reply_size) return false;
|
||||||
return std.mem.bytesToValue(protocol.Reply, reply[0..protocol.reply_size]).status == 0;
|
return std.mem.bytesToValue(display_protocol.Reply, reply[0..display_protocol.reply_size]).status == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move / restack / show or hide the layer.
|
/// Move / restack / show or hide the layer.
|
||||||
pub fn configure(self: Layer, x: i32, y: i32, z: u32, visible: bool) bool {
|
pub fn configure(self: Layer, x: i32, y: i32, z: u32, visible: bool) bool {
|
||||||
var reply: protocol.Reply = undefined;
|
var reply: display_protocol.Reply = undefined;
|
||||||
return transact(.{
|
return transact(.{
|
||||||
.operation = @intFromEnum(protocol.Operation.configure_layer),
|
.operation = @intFromEnum(display_protocol.Operation.configure_layer),
|
||||||
.layer = self.id,
|
.layer = self.id,
|
||||||
.x = @bitCast(x),
|
.x = @bitCast(x),
|
||||||
.y = @bitCast(y),
|
.y = @bitCast(y),
|
||||||
@@ -163,9 +163,9 @@ pub const Layer = struct {
|
|||||||
/// Mark a rectangle of this layer (layer-local) dirty for the next present — for when
|
/// Mark a rectangle of this layer (layer-local) dirty for the next present — for when
|
||||||
/// the layer's pixels changed without a drawing call the compositor already tracked.
|
/// the layer's pixels changed without a drawing call the compositor already tracked.
|
||||||
pub fn damage(self: Layer, x: i32, y: i32, w: u32, h: u32) bool {
|
pub fn damage(self: Layer, x: i32, y: i32, w: u32, h: u32) bool {
|
||||||
var reply: protocol.Reply = undefined;
|
var reply: display_protocol.Reply = undefined;
|
||||||
return transact(.{
|
return transact(.{
|
||||||
.operation = @intFromEnum(protocol.Operation.damage),
|
.operation = @intFromEnum(display_protocol.Operation.damage),
|
||||||
.layer = self.id,
|
.layer = self.id,
|
||||||
.x = @bitCast(x),
|
.x = @bitCast(x),
|
||||||
.y = @bitCast(y),
|
.y = @bitCast(y),
|
||||||
@@ -176,17 +176,17 @@ pub const Layer = struct {
|
|||||||
|
|
||||||
/// Release the layer and its surface.
|
/// Release the layer and its surface.
|
||||||
pub fn destroy(self: Layer) bool {
|
pub fn destroy(self: Layer) bool {
|
||||||
var reply: protocol.Reply = undefined;
|
var reply: display_protocol.Reply = undefined;
|
||||||
return transact(.{ .operation = @intFromEnum(protocol.Operation.destroy_layer), .layer = self.id }, &reply);
|
return transact(.{ .operation = @intFromEnum(display_protocol.Operation.destroy_layer), .layer = self.id }, &reply);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Create a server-owned layer of `w`×`h` pixels at screen (`x`, `y`) with stacking order
|
/// Create a server-owned layer of `w`×`h` pixels at screen (`x`, `y`) with stacking order
|
||||||
/// `z` (higher is nearer the front), initially visible. Returns a handle, or null.
|
/// `z` (higher is nearer the front), initially visible. Returns a handle, or null.
|
||||||
pub fn createLayer(x: i32, y: i32, w: u32, h: u32, z: u32) ?Layer {
|
pub fn createLayer(x: i32, y: i32, w: u32, h: u32, z: u32) ?Layer {
|
||||||
var reply: protocol.Reply = undefined;
|
var reply: display_protocol.Reply = undefined;
|
||||||
if (!transact(.{
|
if (!transact(.{
|
||||||
.operation = @intFromEnum(protocol.Operation.create_layer),
|
.operation = @intFromEnum(display_protocol.Operation.create_layer),
|
||||||
.x = @bitCast(x),
|
.x = @bitCast(x),
|
||||||
.y = @bitCast(y),
|
.y = @bitCast(y),
|
||||||
.width = w,
|
.width = w,
|
||||||
|
|||||||
+37
-37
@@ -13,11 +13,11 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const ipc = @import("ipc.zig");
|
const ipc = @import("ipc.zig");
|
||||||
const system = @import("system.zig");
|
const system = @import("system.zig");
|
||||||
const protocol = @import("vfs-protocol");
|
const vfs_protocol = @import("vfs-protocol");
|
||||||
|
|
||||||
/// The kind of a filesystem node — re-exported so a caller need not import the
|
/// The kind of a filesystem node — re-exported so a caller need not import the
|
||||||
/// wire protocol.
|
/// wire protocol.
|
||||||
pub const Kind = protocol.NodeKind;
|
pub const Kind = vfs_protocol.NodeKind;
|
||||||
|
|
||||||
/// A node's metadata (the answer to a status request).
|
/// A node's metadata (the answer to a status request).
|
||||||
pub const Attributes = struct {
|
pub const Attributes = struct {
|
||||||
@@ -54,9 +54,9 @@ pub const OpenOptions = struct {
|
|||||||
|
|
||||||
fn wireFlags(self: OpenOptions) u32 {
|
fn wireFlags(self: OpenOptions) u32 {
|
||||||
var f: u32 = 0;
|
var f: u32 = 0;
|
||||||
if (self.create) f |= protocol.create;
|
if (self.create) f |= vfs_protocol.create;
|
||||||
if (self.directory) f |= protocol.directory;
|
if (self.directory) f |= vfs_protocol.directory;
|
||||||
if (self.truncate) f |= protocol.truncate;
|
if (self.truncate) f |= vfs_protocol.truncate;
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -87,22 +87,22 @@ fn resolve(path: []const u8, flags: usize) ?Route {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Result = struct { reply: protocol.Reply, payload: []u8 };
|
const Result = struct { reply: vfs_protocol.Reply, payload: []u8 };
|
||||||
|
|
||||||
// One request/reply round trip: [Request header][send payload] -> backend ->
|
// One request/reply round trip: [Request header][send payload] -> backend ->
|
||||||
// [Reply header][receive payload]. The receive payload lands in `out`.
|
// [Reply header][receive payload]. The receive payload lands in `out`.
|
||||||
fn transact(h: ipc.Handle, request: protocol.Request, send: []const u8, out: []u8) ?Result {
|
fn transact(h: ipc.Handle, request: vfs_protocol.Request, send: []const u8, out: []u8) ?Result {
|
||||||
var message: [protocol.message_maximum]u8 = undefined;
|
var message: [vfs_protocol.message_maximum]u8 = undefined;
|
||||||
@memcpy(message[0..protocol.request_size], std.mem.asBytes(&request));
|
@memcpy(message[0..vfs_protocol.request_size], std.mem.asBytes(&request));
|
||||||
const slen = @min(send.len, protocol.maximum_payload);
|
const slen = @min(send.len, vfs_protocol.maximum_payload);
|
||||||
@memcpy(message[protocol.request_size..][0..slen], send[0..slen]);
|
@memcpy(message[vfs_protocol.request_size..][0..slen], send[0..slen]);
|
||||||
|
|
||||||
var rbuf: [protocol.message_maximum]u8 = undefined;
|
var rbuf: [vfs_protocol.message_maximum]u8 = undefined;
|
||||||
const n = ipc.call(h, message[0 .. protocol.request_size + slen], &rbuf) catch return null;
|
const n = ipc.call(h, message[0 .. vfs_protocol.request_size + slen], &rbuf) catch return null;
|
||||||
if (n < protocol.reply_size) return null;
|
if (n < vfs_protocol.reply_size) return null;
|
||||||
const reply = std.mem.bytesToValue(protocol.Reply, rbuf[0..protocol.reply_size]);
|
const reply = std.mem.bytesToValue(vfs_protocol.Reply, rbuf[0..vfs_protocol.reply_size]);
|
||||||
const rpl = @min(n - protocol.reply_size, out.len);
|
const rpl = @min(n - vfs_protocol.reply_size, out.len);
|
||||||
@memcpy(out[0..rpl], rbuf[protocol.reply_size..][0..rpl]);
|
@memcpy(out[0..rpl], rbuf[vfs_protocol.reply_size..][0..rpl]);
|
||||||
return .{ .reply = reply, .payload = out[0..rpl] };
|
return .{ .reply = reply, .payload = out[0..rpl] };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,8 +122,8 @@ pub const File = struct {
|
|||||||
self.offset += n;
|
self.offset += n;
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
const want: u32 = @intCast(@min(buffer.len, protocol.maximum_payload));
|
const want: u32 = @intCast(@min(buffer.len, vfs_protocol.maximum_payload));
|
||||||
const request = protocol.Request{ .operation = .read, .node = self.node, .offset = self.offset, .len = want, .flags = 0 };
|
const request = vfs_protocol.Request{ .operation = .read, .node = self.node, .offset = self.offset, .len = want, .flags = 0 };
|
||||||
const r = transact(h, request, &.{}, buffer) orelse return null;
|
const r = transact(h, request, &.{}, buffer) orelse return null;
|
||||||
if (r.reply.status != 0) return null;
|
if (r.reply.status != 0) return null;
|
||||||
self.offset += r.reply.len;
|
self.offset += r.reply.len;
|
||||||
@@ -136,8 +136,8 @@ pub const File = struct {
|
|||||||
/// are read-only).
|
/// are read-only).
|
||||||
pub fn write(self: *File, data: []const u8) ?usize {
|
pub fn write(self: *File, data: []const u8) ?usize {
|
||||||
const h = self.backend orelse return null;
|
const h = self.backend orelse return null;
|
||||||
const want: u32 = @intCast(@min(data.len, protocol.maximum_payload));
|
const want: u32 = @intCast(@min(data.len, vfs_protocol.maximum_payload));
|
||||||
const request = protocol.Request{ .operation = .write, .node = self.node, .offset = self.offset, .len = want, .flags = 0 };
|
const request = vfs_protocol.Request{ .operation = .write, .node = self.node, .offset = self.offset, .len = want, .flags = 0 };
|
||||||
const r = transact(h, request, data[0..want], &.{}) orelse return null;
|
const r = transact(h, request, data[0..want], &.{}) orelse return null;
|
||||||
if (r.reply.status != 0) return null;
|
if (r.reply.status != 0) return null;
|
||||||
self.offset += r.reply.len;
|
self.offset += r.reply.len;
|
||||||
@@ -167,11 +167,11 @@ pub const File = struct {
|
|||||||
const a = system.fsNodeStatus(self.node) orelse return null;
|
const a = system.fsNodeStatus(self.node) orelse return null;
|
||||||
return .{ .size = a.size, .kind = if (a.kind == system.file_kind_directory) .directory else .regular, .mtime = a.mtime };
|
return .{ .size = a.size, .kind = if (a.kind == system.file_kind_directory) .directory else .regular, .mtime = a.mtime };
|
||||||
};
|
};
|
||||||
const request = protocol.Request{ .operation = .status, .node = self.node, .offset = 0, .len = 0, .flags = 0 };
|
const request = vfs_protocol.Request{ .operation = .status, .node = self.node, .offset = 0, .len = 0, .flags = 0 };
|
||||||
var buffer: [@sizeOf(protocol.FileStatus)]u8 = undefined;
|
var buffer: [@sizeOf(vfs_protocol.FileStatus)]u8 = undefined;
|
||||||
const r = transact(h, request, &.{}, &buffer) orelse return null;
|
const r = transact(h, request, &.{}, &buffer) orelse return null;
|
||||||
if (r.reply.status != 0 or r.payload.len < @sizeOf(protocol.FileStatus)) return null;
|
if (r.reply.status != 0 or r.payload.len < @sizeOf(vfs_protocol.FileStatus)) return null;
|
||||||
const status = std.mem.bytesToValue(protocol.FileStatus, buffer[0..@sizeOf(protocol.FileStatus)]);
|
const status = std.mem.bytesToValue(vfs_protocol.FileStatus, buffer[0..@sizeOf(vfs_protocol.FileStatus)]);
|
||||||
return .{ .size = status.size, .kind = kindFromWire(status.kind), .mtime = status.mtime };
|
return .{ .size = status.size, .kind = kindFromWire(status.kind), .mtime = status.mtime };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ pub const File = struct {
|
|||||||
/// tokens are permanent — nothing to release.
|
/// tokens are permanent — nothing to release.
|
||||||
pub fn close(self: *File) void {
|
pub fn close(self: *File) void {
|
||||||
const h = self.backend orelse return;
|
const h = self.backend orelse return;
|
||||||
const request = protocol.Request{ .operation = .close, .node = self.node, .offset = 0, .len = 0, .flags = 0 };
|
const request = vfs_protocol.Request{ .operation = .close, .node = self.node, .offset = 0, .len = 0, .flags = 0 };
|
||||||
_ = transact(h, request, &.{}, &.{});
|
_ = transact(h, request, &.{}, &.{});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -191,7 +191,7 @@ pub fn open(path: []const u8, options: OpenOptions) ?File {
|
|||||||
.kernel => |token| return .{ .node = token, .backend = null },
|
.kernel => |token| return .{ .node = token, .backend = null },
|
||||||
.backend => |b| {
|
.backend => |b| {
|
||||||
const relative = route.backendPath();
|
const relative = route.backendPath();
|
||||||
const request = protocol.Request{ .operation = .open, .node = 0, .offset = 0, .len = @intCast(relative.len), .flags = options.wireFlags() };
|
const request = vfs_protocol.Request{ .operation = .open, .node = 0, .offset = 0, .len = @intCast(relative.len), .flags = options.wireFlags() };
|
||||||
const r = transact(b.handle, request, relative, &.{}) orelse return null;
|
const r = transact(b.handle, request, relative, &.{}) orelse return null;
|
||||||
if (r.reply.status != 0) return null;
|
if (r.reply.status != 0) return null;
|
||||||
return .{ .node = r.reply.node, .backend = b.handle };
|
return .{ .node = r.reply.node, .backend = b.handle };
|
||||||
@@ -246,15 +246,15 @@ pub const Directory = struct {
|
|||||||
self.cursor += 1;
|
self.cursor += 1;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
const request = protocol.Request{ .operation = .readdir, .node = self.node, .offset = self.cursor, .len = 0, .flags = 0 };
|
const request = vfs_protocol.Request{ .operation = .readdir, .node = self.node, .offset = self.cursor, .len = 0, .flags = 0 };
|
||||||
var buffer: [protocol.message_maximum]u8 = undefined;
|
var buffer: [vfs_protocol.message_maximum]u8 = undefined;
|
||||||
const r = transact(h, request, &.{}, &buffer) orelse return false;
|
const r = transact(h, request, &.{}, &buffer) orelse return false;
|
||||||
if (r.reply.status != 0 or r.reply.len == 0) return false; // error or EOF
|
if (r.reply.status != 0 or r.reply.len == 0) return false; // error or EOF
|
||||||
if (r.payload.len < protocol.directory_entry_size) return false;
|
if (r.payload.len < vfs_protocol.directory_entry_size) return false;
|
||||||
const header = std.mem.bytesToValue(protocol.DirectoryEntry, r.payload[0..protocol.directory_entry_size]);
|
const header = std.mem.bytesToValue(vfs_protocol.DirectoryEntry, r.payload[0..vfs_protocol.directory_entry_size]);
|
||||||
entry.kind = kindFromWire(header.kind);
|
entry.kind = kindFromWire(header.kind);
|
||||||
entry.size = header.size;
|
entry.size = header.size;
|
||||||
const source = r.payload[protocol.directory_entry_size..];
|
const source = r.payload[vfs_protocol.directory_entry_size..];
|
||||||
const nlen = @min(@min(@as(usize, header.name_len), source.len), entry.name_buffer.len);
|
const nlen = @min(@min(@as(usize, header.name_len), source.len), entry.name_buffer.len);
|
||||||
@memcpy(entry.name_buffer[0..nlen], source[0..nlen]);
|
@memcpy(entry.name_buffer[0..nlen], source[0..nlen]);
|
||||||
entry.name_len = nlen;
|
entry.name_len = nlen;
|
||||||
@@ -278,11 +278,11 @@ pub fn openDirectory(path: []const u8) ?Directory {
|
|||||||
// A path-based request that returns only a status (mkdir, unlink). Kernel-served
|
// A path-based request that returns only a status (mkdir, unlink). Kernel-served
|
||||||
// paths (the read-only /system) refuse mutation by construction: the resolve
|
// paths (the read-only /system) refuse mutation by construction: the resolve
|
||||||
// must land on a backend.
|
// must land on a backend.
|
||||||
fn pathOperation(operation: protocol.Operation, path: []const u8) bool {
|
fn pathOperation(operation: vfs_protocol.Operation, path: []const u8) bool {
|
||||||
const route = resolve(path, 0) orelse return false;
|
const route = resolve(path, 0) orelse return false;
|
||||||
if (route != .backend) return false;
|
if (route != .backend) return false;
|
||||||
const relative = route.backendPath();
|
const relative = route.backendPath();
|
||||||
const request = protocol.Request{ .operation = operation, .node = 0, .offset = 0, .len = @intCast(relative.len), .flags = 0 };
|
const request = vfs_protocol.Request{ .operation = operation, .node = 0, .offset = 0, .len = @intCast(relative.len), .flags = 0 };
|
||||||
const r = transact(route.backend.handle, request, relative, &.{}) orelse return false;
|
const r = transact(route.backend.handle, request, relative, &.{}) orelse return false;
|
||||||
return r.reply.status == 0;
|
return r.reply.status == 0;
|
||||||
}
|
}
|
||||||
@@ -329,12 +329,12 @@ pub fn rename(old_path: []const u8, new_path: []const u8) bool {
|
|||||||
const old_relative = old_route.backendPath();
|
const old_relative = old_route.backendPath();
|
||||||
const new_relative = new_route.backendPath();
|
const new_relative = new_route.backendPath();
|
||||||
const total = old_relative.len + 1 + new_relative.len;
|
const total = old_relative.len + 1 + new_relative.len;
|
||||||
if (total > protocol.maximum_payload) return false;
|
if (total > vfs_protocol.maximum_payload) return false;
|
||||||
var payload: [protocol.maximum_payload]u8 = undefined;
|
var payload: [vfs_protocol.maximum_payload]u8 = undefined;
|
||||||
@memcpy(payload[0..old_relative.len], old_relative);
|
@memcpy(payload[0..old_relative.len], old_relative);
|
||||||
payload[old_relative.len] = 0;
|
payload[old_relative.len] = 0;
|
||||||
@memcpy(payload[old_relative.len + 1 ..][0..new_relative.len], new_relative);
|
@memcpy(payload[old_relative.len + 1 ..][0..new_relative.len], new_relative);
|
||||||
const request = protocol.Request{ .operation = .rename, .node = 0, .offset = 0, .len = @intCast(total), .flags = 0 };
|
const request = vfs_protocol.Request{ .operation = .rename, .node = 0, .offset = 0, .len = @intCast(total), .flags = 0 };
|
||||||
const r = transact(old_route.backend.handle, request, payload[0..total], &.{}) orelse return false;
|
const r = transact(old_route.backend.handle, request, payload[0..total], &.{}) orelse return false;
|
||||||
return r.reply.status == 0;
|
return r.reply.status == 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-27
@@ -25,24 +25,24 @@ const std = @import("std");
|
|||||||
const abi = @import("abi");
|
const abi = @import("abi");
|
||||||
const ipc = @import("ipc.zig");
|
const ipc = @import("ipc.zig");
|
||||||
const system = @import("system.zig");
|
const system = @import("system.zig");
|
||||||
const protocol = @import("input-protocol");
|
const input_protocol = @import("input-protocol");
|
||||||
|
|
||||||
pub const DeviceKind = protocol.DeviceKind;
|
pub const DeviceKind = input_protocol.DeviceKind;
|
||||||
pub const InputEvent = protocol.InputEvent;
|
pub const InputEvent = input_protocol.InputEvent;
|
||||||
pub const KeyEvent = protocol.KeyEvent;
|
pub const KeyEvent = input_protocol.KeyEvent;
|
||||||
pub const MouseEvent = protocol.MouseEvent;
|
pub const MouseEvent = input_protocol.MouseEvent;
|
||||||
pub const JoystickEvent = protocol.JoystickEvent;
|
pub const JoystickEvent = input_protocol.JoystickEvent;
|
||||||
pub const EventKind = protocol.EventKind;
|
pub const EventKind = input_protocol.EventKind;
|
||||||
pub const MouseEventKind = protocol.MouseEventKind;
|
pub const MouseEventKind = input_protocol.MouseEventKind;
|
||||||
pub const JoystickEventKind = protocol.JoystickEventKind;
|
pub const JoystickEventKind = input_protocol.JoystickEventKind;
|
||||||
pub const Keycode = protocol.Keycode;
|
pub const Keycode = input_protocol.Keycode;
|
||||||
|
|
||||||
/// Interest masks re-exported so a caller can `subscribe(input.device_keyboard |
|
/// Interest masks re-exported so a caller can `subscribe(input.device_keyboard |
|
||||||
/// input.device_mouse)`.
|
/// input.device_mouse)`.
|
||||||
pub const device_keyboard = protocol.device_keyboard;
|
pub const device_keyboard = input_protocol.device_keyboard;
|
||||||
pub const device_mouse = protocol.device_mouse;
|
pub const device_mouse = input_protocol.device_mouse;
|
||||||
pub const device_joystick = protocol.device_joystick;
|
pub const device_joystick = input_protocol.device_joystick;
|
||||||
pub const device_all = protocol.device_all;
|
pub const device_all = input_protocol.device_all;
|
||||||
|
|
||||||
/// Look up the input service, retrying while it is still coming up. Both a subscriber and
|
/// Look up the input service, retrying while it is still coming up. Both a subscriber and
|
||||||
/// a source race the service's registration at boot, so both wait for it here rather than
|
/// a source race the service's registration at boot, so both wait for it here rather than
|
||||||
@@ -66,7 +66,7 @@ pub const Subscriber = struct {
|
|||||||
/// The endpoint the service delivers events to (created and owned by us; its handle
|
/// The endpoint the service delivers events to (created and owned by us; its handle
|
||||||
/// was handed to the service as a capability at subscribe time).
|
/// was handed to the service as a capability at subscribe time).
|
||||||
endpoint: ipc.Handle,
|
endpoint: ipc.Handle,
|
||||||
receive: [protocol.event_size]u8 = undefined,
|
receive: [input_protocol.event_size]u8 = undefined,
|
||||||
|
|
||||||
/// Block until the next event is pushed, and return it. Events arrive as asynchronous
|
/// Block until the next event is pushed, and return it. Events arrive as asynchronous
|
||||||
/// buffered messages (`ipc_send` from the service), so nothing is owed in reply — the
|
/// buffered messages (`ipc_send` from the service), so nothing is owed in reply — the
|
||||||
@@ -74,8 +74,8 @@ pub const Subscriber = struct {
|
|||||||
/// (there should be none), so callers can loop.
|
/// (there should be none), so callers can loop.
|
||||||
pub fn next(self: *Subscriber) ?InputEvent {
|
pub fn next(self: *Subscriber) ?InputEvent {
|
||||||
const got = ipc.replyWait(self.endpoint, &.{}, &self.receive, null);
|
const got = ipc.replyWait(self.endpoint, &.{}, &self.receive, null);
|
||||||
if (!got.isMessage() or got.len < protocol.event_size) return null;
|
if (!got.isMessage() or got.len < input_protocol.event_size) return null;
|
||||||
return std.mem.bytesToValue(InputEvent, self.receive[0..protocol.event_size]);
|
return std.mem.bytesToValue(InputEvent, self.receive[0..input_protocol.event_size]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,11 +86,11 @@ pub fn subscribe(device_mask: u32) ?Subscriber {
|
|||||||
const service = lookupService() orelse return null;
|
const service = lookupService() orelse return null;
|
||||||
const endpoint = ipc.createIpcEndpoint() orelse return null;
|
const endpoint = ipc.createIpcEndpoint() orelse return null;
|
||||||
|
|
||||||
var request = protocol.Request{ .operation = @intFromEnum(protocol.Operation.subscribe), .device_mask = device_mask };
|
var request = input_protocol.Request{ .operation = @intFromEnum(input_protocol.Operation.subscribe), .device_mask = device_mask };
|
||||||
var reply: [protocol.reply_size]u8 = undefined;
|
var reply: [input_protocol.reply_size]u8 = undefined;
|
||||||
const result = ipc.callCap(service, std.mem.asBytes(&request), &reply, endpoint) catch return null;
|
const result = ipc.callCap(service, std.mem.asBytes(&request), &reply, endpoint) catch return null;
|
||||||
if (result.len < protocol.reply_size) return null;
|
if (result.len < input_protocol.reply_size) return null;
|
||||||
if (std.mem.bytesToValue(protocol.Reply, reply[0..protocol.reply_size]).status != 0) return null;
|
if (std.mem.bytesToValue(input_protocol.Reply, reply[0..input_protocol.reply_size]).status != 0) return null;
|
||||||
return .{ .endpoint = endpoint };
|
return .{ .endpoint = endpoint };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,11 +149,11 @@ pub const Publisher = struct {
|
|||||||
service: ipc.Handle,
|
service: ipc.Handle,
|
||||||
|
|
||||||
fn publish(self: Publisher, event: InputEvent) bool {
|
fn publish(self: Publisher, event: InputEvent) bool {
|
||||||
var request = protocol.Request{ .operation = @intFromEnum(protocol.Operation.publish), .event = event };
|
var request = input_protocol.Request{ .operation = @intFromEnum(input_protocol.Operation.publish), .event = event };
|
||||||
var reply: [protocol.reply_size]u8 = undefined;
|
var reply: [input_protocol.reply_size]u8 = undefined;
|
||||||
const len = ipc.call(self.service, std.mem.asBytes(&request), &reply) catch return false;
|
const len = ipc.call(self.service, std.mem.asBytes(&request), &reply) catch return false;
|
||||||
if (len < protocol.reply_size) return false;
|
if (len < input_protocol.reply_size) return false;
|
||||||
return std.mem.bytesToValue(protocol.Reply, reply[0..protocol.reply_size]).status == 0;
|
return std.mem.bytesToValue(input_protocol.Reply, reply[0..input_protocol.reply_size]).status == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Broadcast a keyboard event to every subscriber that took keyboard events.
|
/// Broadcast a keyboard event to every subscriber that took keyboard events.
|
||||||
@@ -204,8 +204,8 @@ pub fn syntheticKeyEvent(step: usize) KeyEvent {
|
|||||||
pub fn syntheticMouseEvent(step: usize) MouseEvent {
|
pub fn syntheticMouseEvent(step: usize) MouseEvent {
|
||||||
return switch (step % 3) {
|
return switch (step % 3) {
|
||||||
0 => .{ .kind = @intFromEnum(MouseEventKind.motion), .button = 0, .dx = 1, .dy = 1, .scroll_x = 0, .scroll_y = 0, .buttons = 0 },
|
0 => .{ .kind = @intFromEnum(MouseEventKind.motion), .button = 0, .dx = 1, .dy = 1, .scroll_x = 0, .scroll_y = 0, .buttons = 0 },
|
||||||
1 => .{ .kind = @intFromEnum(MouseEventKind.button_down), .button = protocol.mouse_button_left, .dx = 0, .dy = 0, .scroll_x = 0, .scroll_y = 0, .buttons = protocol.mouse_button_left },
|
1 => .{ .kind = @intFromEnum(MouseEventKind.button_down), .button = input_protocol.mouse_button_left, .dx = 0, .dy = 0, .scroll_x = 0, .scroll_y = 0, .buttons = input_protocol.mouse_button_left },
|
||||||
else => .{ .kind = @intFromEnum(MouseEventKind.button_up), .button = protocol.mouse_button_left, .dx = 0, .dy = 0, .scroll_x = 0, .scroll_y = 0, .buttons = 0 },
|
else => .{ .kind = @intFromEnum(MouseEventKind.button_up), .button = input_protocol.mouse_button_left, .dx = 0, .dy = 0, .scroll_x = 0, .scroll_y = 0, .buttons = 0 },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const runtime = @import("runtime");
|
const runtime = @import("runtime");
|
||||||
const protocol = @import("device-manager-protocol");
|
const device_manager_protocol = @import("device-manager-protocol");
|
||||||
const device = runtime.device;
|
const device = runtime.device;
|
||||||
const pci_class = @import("pci-class");
|
const pci_class = @import("pci-class");
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ fn logFunction(bus: u64, dev: u64, function: u64, class_triple: u32) void {
|
|||||||
_ = runtime.system.write(text);
|
_ = runtime.system.write(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
var bridge_id: u64 = protocol.no_device;
|
var bridge_id: u64 = device_manager_protocol.no_device;
|
||||||
var ecam_base: usize = 0;
|
var ecam_base: usize = 0;
|
||||||
var ecam_physical: u64 = 0;
|
var ecam_physical: u64 = 0;
|
||||||
var start_bus: u64 = 0;
|
var start_bus: u64 = 0;
|
||||||
@@ -209,13 +209,13 @@ fn registerAndReport(bus: u64, dev: u64, function: u64, class_triple: u32) void
|
|||||||
std.log.info("register refused for {d}:{d}.{d}", .{ bus, dev, function });
|
std.log.info("register refused for {d}:{d}.{d}", .{ bus, dev, function });
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
const report = protocol.ChildAdded{
|
const report = device_manager_protocol.ChildAdded{
|
||||||
.parent = bridge_id,
|
.parent = bridge_id,
|
||||||
.bus_address = (bus << 8) | (dev << 3) | function,
|
.bus_address = (bus << 8) | (dev << 3) | function,
|
||||||
.identity = class_triple,
|
.identity = class_triple,
|
||||||
.device_id = registered,
|
.device_id = registered,
|
||||||
};
|
};
|
||||||
var reply: [protocol.message_maximum]u8 = undefined;
|
var reply: [device_manager_protocol.message_maximum]u8 = undefined;
|
||||||
_ = runtime.ipc.call(manager_handle, std.mem.asBytes(&report), &reply) catch {
|
_ = runtime.ipc.call(manager_handle, std.mem.asBytes(&report), &reply) catch {
|
||||||
std.log.info("child report for {d}:{d}.{d} failed", .{ bus, dev, function });
|
std.log.info("child report for {d}:{d}.{d} failed", .{ bus, dev, function });
|
||||||
};
|
};
|
||||||
@@ -235,7 +235,7 @@ pub fn main(init: runtime.process.Init) void {
|
|||||||
std.log.info("malformed bridge device id '{s}'", .{argument});
|
std.log.info("malformed bridge device id '{s}'", .{argument});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
runtime.service.run(protocol.message_maximum, .{
|
runtime.service.run(device_manager_protocol.message_maximum, .{
|
||||||
.init = initialise,
|
.init = initialise,
|
||||||
.on_message = onMessage,
|
.on_message = onMessage,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -15,11 +15,11 @@
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const runtime = @import("runtime");
|
const runtime = @import("runtime");
|
||||||
const protocol = @import("device-manager-protocol");
|
const device_manager_protocol = @import("device-manager-protocol");
|
||||||
const device = runtime.device;
|
const device = runtime.device;
|
||||||
const usb_ids = @import("usb-ids");
|
const usb_ids = @import("usb-ids");
|
||||||
const usb_abi = @import("usb-abi");
|
const usb_abi = @import("usb-abi");
|
||||||
const transfer = @import("usb-transfer-protocol");
|
const usb_transfer_protocol = @import("usb-transfer-protocol");
|
||||||
const library = @import("usb-xhci-library.zig");
|
const library = @import("usb-xhci-library.zig");
|
||||||
|
|
||||||
/// The controller engine (reset, rings, transfers), stood up in `initialise`.
|
/// The controller engine (reset, rings, transfers), stood up in `initialise`.
|
||||||
@@ -64,7 +64,7 @@ fn reportEndpointFor(device_token: u64) ?usize {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var controller_id: u64 = protocol.no_device;
|
var controller_id: u64 = device_manager_protocol.no_device;
|
||||||
|
|
||||||
/// Claim the assigned controller, find its register window, and hello the
|
/// Claim the assigned controller, find its register window, and hello the
|
||||||
/// manager. Any failure returns false: the process exits cleanly, which the
|
/// manager. Any failure returns false: the process exits cleanly, which the
|
||||||
@@ -300,11 +300,11 @@ fn tearDownHubDevice(manager: runtime.ipc.Handle, engine: *library.Controller, d
|
|||||||
const key = hubPortKey(dev.parent_slot, dev.parent_port);
|
const key = hubPortKey(dev.parent_slot, dev.parent_port);
|
||||||
for (dev.interfaces[0..dev.interface_count]) |*interface| {
|
for (dev.interfaces[0..dev.interface_count]) |*interface| {
|
||||||
if (interface.registered_device_id == 0) continue;
|
if (interface.registered_device_id == 0) continue;
|
||||||
const event = protocol.ChildRemoved{
|
const event = device_manager_protocol.ChildRemoved{
|
||||||
.parent = controller_id,
|
.parent = controller_id,
|
||||||
.bus_address = (@as(u64, key) << 8) | interface.number,
|
.bus_address = (@as(u64, key) << 8) | interface.number,
|
||||||
};
|
};
|
||||||
var reply: [protocol.message_maximum]u8 = undefined;
|
var reply: [device_manager_protocol.message_maximum]u8 = undefined;
|
||||||
_ = runtime.ipc.call(manager, std.mem.asBytes(&event), &reply) catch {};
|
_ = runtime.ipc.call(manager, std.mem.asBytes(&event), &reply) catch {};
|
||||||
interface.registered_device_id = 0;
|
interface.registered_device_id = 0;
|
||||||
}
|
}
|
||||||
@@ -330,11 +330,11 @@ fn tearDownPort(manager: runtime.ipc.Handle, engine: *library.Controller, port:
|
|||||||
std.log.info("port {d} disconnected", .{port});
|
std.log.info("port {d} disconnected", .{port});
|
||||||
for (usb_device.interfaces[0..usb_device.interface_count]) |*interface| {
|
for (usb_device.interfaces[0..usb_device.interface_count]) |*interface| {
|
||||||
if (interface.registered_device_id == 0) continue;
|
if (interface.registered_device_id == 0) continue;
|
||||||
const event = protocol.ChildRemoved{
|
const event = device_manager_protocol.ChildRemoved{
|
||||||
.parent = controller_id,
|
.parent = controller_id,
|
||||||
.bus_address = (@as(u64, port) << 8) | interface.number,
|
.bus_address = (@as(u64, port) << 8) | interface.number,
|
||||||
};
|
};
|
||||||
var reply: [protocol.message_maximum]u8 = undefined;
|
var reply: [device_manager_protocol.message_maximum]u8 = undefined;
|
||||||
_ = runtime.ipc.call(manager, std.mem.asBytes(&event), &reply) catch {
|
_ = runtime.ipc.call(manager, std.mem.asBytes(&event), &reply) catch {
|
||||||
std.log.info("child-removed report for port {d} interface {d} failed", .{ port, interface.number });
|
std.log.info("child-removed report for port {d} interface {d} failed", .{ port, interface.number });
|
||||||
};
|
};
|
||||||
@@ -371,13 +371,13 @@ fn reportInterface(manager: runtime.ipc.Handle, port: u32, interface: library.In
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const report = protocol.ChildAdded{
|
const report = device_manager_protocol.ChildAdded{
|
||||||
.parent = controller_id,
|
.parent = controller_id,
|
||||||
.bus_address = (@as(u64, port) << 8) | interface.number,
|
.bus_address = (@as(u64, port) << 8) | interface.number,
|
||||||
.identity = identity,
|
.identity = identity,
|
||||||
.device_id = registered,
|
.device_id = registered,
|
||||||
};
|
};
|
||||||
var reply: [protocol.message_maximum]u8 = undefined;
|
var reply: [device_manager_protocol.message_maximum]u8 = undefined;
|
||||||
_ = runtime.ipc.call(manager, std.mem.asBytes(&report), &reply) catch {
|
_ = runtime.ipc.call(manager, std.mem.asBytes(&report), &reply) catch {
|
||||||
std.log.info("child report for port {d} interface {d} failed", .{ port, interface.number });
|
std.log.info("child report for port {d} interface {d} failed", .{ port, interface.number });
|
||||||
return null;
|
return null;
|
||||||
@@ -401,10 +401,10 @@ fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?runtime
|
|||||||
if (message.len < 4) return 0;
|
if (message.len < 4) return 0;
|
||||||
const operation = std.mem.readInt(u32, message[0..4], .little);
|
const operation = std.mem.readInt(u32, message[0..4], .little);
|
||||||
return switch (operation) {
|
return switch (operation) {
|
||||||
@intFromEnum(transfer.Operation.open) => handleOpen(message, reply, capability),
|
@intFromEnum(usb_transfer_protocol.Operation.open) => handleOpen(message, reply, capability),
|
||||||
@intFromEnum(transfer.Operation.control) => handleControl(message, reply),
|
@intFromEnum(usb_transfer_protocol.Operation.control) => handleControl(message, reply),
|
||||||
@intFromEnum(transfer.Operation.interrupt_subscribe) => handleSubscribe(message, reply),
|
@intFromEnum(usb_transfer_protocol.Operation.interrupt_subscribe) => handleSubscribe(message, reply),
|
||||||
@intFromEnum(transfer.Operation.bulk) => handleBulk(message, reply),
|
@intFromEnum(usb_transfer_protocol.Operation.bulk) => handleBulk(message, reply),
|
||||||
else => 0,
|
else => 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -419,14 +419,14 @@ fn writeReply(reply: []u8, value: anytype) usize {
|
|||||||
/// endpoint (for interrupt reports), and answer with a device token + the
|
/// endpoint (for interrupt reports), and answer with a device token + the
|
||||||
/// interface's endpoints so the class driver need not re-read the config.
|
/// interface's endpoints so the class driver need not re-read the config.
|
||||||
fn handleOpen(message: []const u8, reply: []u8, capability: ?runtime.ipc.Handle) usize {
|
fn handleOpen(message: []const u8, reply: []u8, capability: ?runtime.ipc.Handle) usize {
|
||||||
if (message.len < @sizeOf(transfer.OpenRequest)) return writeReply(reply, transfer.OpenReply{ .status = -1, .endpoint_count = 0, .device_token = 0, .interface_class = 0, .interface_subclass = 0, .interface_protocol = 0, .interface_number = 0 });
|
if (message.len < @sizeOf(usb_transfer_protocol.OpenRequest)) return writeReply(reply, usb_transfer_protocol.OpenReply{ .status = -1, .endpoint_count = 0, .device_token = 0, .interface_class = 0, .interface_subclass = 0, .interface_protocol = 0, .interface_number = 0 });
|
||||||
const request = std.mem.bytesToValue(transfer.OpenRequest, message[0..@sizeOf(transfer.OpenRequest)]);
|
const request = std.mem.bytesToValue(usb_transfer_protocol.OpenRequest, message[0..@sizeOf(usb_transfer_protocol.OpenRequest)]);
|
||||||
const engine = if (controller) |*c| c else return writeReply(reply, transfer.OpenReply{ .status = -1, .endpoint_count = 0, .device_token = 0, .interface_class = 0, .interface_subclass = 0, .interface_protocol = 0, .interface_number = 0 });
|
const engine = if (controller) |*c| c else return writeReply(reply, usb_transfer_protocol.OpenReply{ .status = -1, .endpoint_count = 0, .device_token = 0, .interface_class = 0, .interface_subclass = 0, .interface_protocol = 0, .interface_number = 0 });
|
||||||
const found = engine.findInterface(request.device_id) orelse return writeReply(reply, transfer.OpenReply{ .status = -1, .endpoint_count = 0, .device_token = 0, .interface_class = 0, .interface_subclass = 0, .interface_protocol = 0, .interface_number = 0 });
|
const found = engine.findInterface(request.device_id) orelse return writeReply(reply, usb_transfer_protocol.OpenReply{ .status = -1, .endpoint_count = 0, .device_token = 0, .interface_class = 0, .interface_subclass = 0, .interface_protocol = 0, .interface_number = 0 });
|
||||||
|
|
||||||
if (capability) |endpoint| recordOpen(request.device_id, endpoint);
|
if (capability) |endpoint| recordOpen(request.device_id, endpoint);
|
||||||
|
|
||||||
var open_reply = transfer.OpenReply{
|
var open_reply = usb_transfer_protocol.OpenReply{
|
||||||
.status = 0,
|
.status = 0,
|
||||||
.endpoint_count = found.interface.endpoint_count,
|
.endpoint_count = found.interface.endpoint_count,
|
||||||
.device_token = request.device_id,
|
.device_token = request.device_id,
|
||||||
@@ -435,7 +435,7 @@ fn handleOpen(message: []const u8, reply: []u8, capability: ?runtime.ipc.Handle)
|
|||||||
.interface_protocol = found.interface.protocol,
|
.interface_protocol = found.interface.protocol,
|
||||||
.interface_number = found.interface.number,
|
.interface_number = found.interface.number,
|
||||||
};
|
};
|
||||||
const count = @min(found.interface.endpoint_count, transfer.max_reported_endpoints);
|
const count = @min(found.interface.endpoint_count, usb_transfer_protocol.max_reported_endpoints);
|
||||||
for (found.interface.endpoints[0..count], 0..) |endpoint, index| {
|
for (found.interface.endpoints[0..count], 0..) |endpoint, index| {
|
||||||
open_reply.endpoints[index] = .{
|
open_reply.endpoints[index] = .{
|
||||||
.address = endpoint.address,
|
.address = endpoint.address,
|
||||||
@@ -449,45 +449,45 @@ fn handleOpen(message: []const u8, reply: []u8, capability: ?runtime.ipc.Handle)
|
|||||||
|
|
||||||
/// control: one EP0 control transfer, small data inline both ways.
|
/// control: one EP0 control transfer, small data inline both ways.
|
||||||
fn handleControl(message: []const u8, reply: []u8) usize {
|
fn handleControl(message: []const u8, reply: []u8) usize {
|
||||||
if (message.len < @sizeOf(transfer.ControlRequest)) return writeReply(reply, transfer.ControlReply{ .status = -1, .actual_length = 0 });
|
if (message.len < @sizeOf(usb_transfer_protocol.ControlRequest)) return writeReply(reply, usb_transfer_protocol.ControlReply{ .status = -1, .actual_length = 0 });
|
||||||
const request = std.mem.bytesToValue(transfer.ControlRequest, message[0..@sizeOf(transfer.ControlRequest)]);
|
const request = std.mem.bytesToValue(usb_transfer_protocol.ControlRequest, message[0..@sizeOf(usb_transfer_protocol.ControlRequest)]);
|
||||||
const engine = if (controller) |*c| c else return writeReply(reply, transfer.ControlReply{ .status = -1, .actual_length = 0 });
|
const engine = if (controller) |*c| c else return writeReply(reply, usb_transfer_protocol.ControlReply{ .status = -1, .actual_length = 0 });
|
||||||
const found = engine.findInterface(request.device_token) orelse return writeReply(reply, transfer.ControlReply{ .status = -1, .actual_length = 0 });
|
const found = engine.findInterface(request.device_token) orelse return writeReply(reply, usb_transfer_protocol.ControlReply{ .status = -1, .actual_length = 0 });
|
||||||
|
|
||||||
const setup = std.mem.bytesToValue(usb_abi.Request, &request.setup);
|
const setup = std.mem.bytesToValue(usb_abi.Request, &request.setup);
|
||||||
const direction_in = request.direction_in != 0;
|
const direction_in = request.direction_in != 0;
|
||||||
const data_length = @min(request.data_length, transfer.max_inline_data);
|
const data_length = @min(request.data_length, usb_transfer_protocol.max_inline_data);
|
||||||
var data: [transfer.max_inline_data]u8 = undefined;
|
var data: [usb_transfer_protocol.max_inline_data]u8 = undefined;
|
||||||
if (!direction_in) @memcpy(data[0..data_length], request.data[0..data_length]);
|
if (!direction_in) @memcpy(data[0..data_length], request.data[0..data_length]);
|
||||||
|
|
||||||
const ok = engine.controlTransfer(found.device, setup, data[0..data_length], direction_in);
|
const ok = engine.controlTransfer(found.device, setup, data[0..data_length], direction_in);
|
||||||
var control_reply = transfer.ControlReply{ .status = if (ok) 0 else -1, .actual_length = if (ok) data_length else 0 };
|
var control_reply = usb_transfer_protocol.ControlReply{ .status = if (ok) 0 else -1, .actual_length = if (ok) data_length else 0 };
|
||||||
if (ok and direction_in) @memcpy(control_reply.data[0..data_length], data[0..data_length]);
|
if (ok and direction_in) @memcpy(control_reply.data[0..data_length], data[0..data_length]);
|
||||||
return writeReply(reply, control_reply);
|
return writeReply(reply, control_reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// interrupt_subscribe: arm periodic IN polling; reports flow back asynchronously.
|
/// interrupt_subscribe: arm periodic IN polling; reports flow back asynchronously.
|
||||||
fn handleSubscribe(message: []const u8, reply: []u8) usize {
|
fn handleSubscribe(message: []const u8, reply: []u8) usize {
|
||||||
if (message.len < @sizeOf(transfer.InterruptSubscribeRequest)) return writeReply(reply, transfer.InterruptSubscribeReply{ .status = -1 });
|
if (message.len < @sizeOf(usb_transfer_protocol.InterruptSubscribeRequest)) return writeReply(reply, usb_transfer_protocol.InterruptSubscribeReply{ .status = -1 });
|
||||||
const request = std.mem.bytesToValue(transfer.InterruptSubscribeRequest, message[0..@sizeOf(transfer.InterruptSubscribeRequest)]);
|
const request = std.mem.bytesToValue(usb_transfer_protocol.InterruptSubscribeRequest, message[0..@sizeOf(usb_transfer_protocol.InterruptSubscribeRequest)]);
|
||||||
const engine = if (controller) |*c| c else return writeReply(reply, transfer.InterruptSubscribeReply{ .status = -1 });
|
const engine = if (controller) |*c| c else return writeReply(reply, usb_transfer_protocol.InterruptSubscribeReply{ .status = -1 });
|
||||||
const found = engine.findInterface(request.device_token) orelse return writeReply(reply, transfer.InterruptSubscribeReply{ .status = -1 });
|
const found = engine.findInterface(request.device_token) orelse return writeReply(reply, usb_transfer_protocol.InterruptSubscribeReply{ .status = -1 });
|
||||||
const endpoint = library.Controller.endpointForAddress(found.interface, request.endpoint_address) orelse return writeReply(reply, transfer.InterruptSubscribeReply{ .status = -1 });
|
const endpoint = library.Controller.endpointForAddress(found.interface, request.endpoint_address) orelse return writeReply(reply, usb_transfer_protocol.InterruptSubscribeReply{ .status = -1 });
|
||||||
const report_endpoint = reportEndpointFor(request.device_token) orelse return writeReply(reply, transfer.InterruptSubscribeReply{ .status = -1 });
|
const report_endpoint = reportEndpointFor(request.device_token) orelse return writeReply(reply, usb_transfer_protocol.InterruptSubscribeReply{ .status = -1 });
|
||||||
const ok = engine.subscribeInterrupt(found.device, endpoint, request.device_token, report_endpoint);
|
const ok = engine.subscribeInterrupt(found.device, endpoint, request.device_token, report_endpoint);
|
||||||
return writeReply(reply, transfer.InterruptSubscribeReply{ .status = if (ok) 0 else -1 });
|
return writeReply(reply, usb_transfer_protocol.InterruptSubscribeReply{ .status = if (ok) 0 else -1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// bulk: one bulk transfer to/from the class driver's own DMA buffer (by physical
|
/// bulk: one bulk transfer to/from the class driver's own DMA buffer (by physical
|
||||||
/// address), so sector-sized data never crosses IPC.
|
/// address), so sector-sized data never crosses IPC.
|
||||||
fn handleBulk(message: []const u8, reply: []u8) usize {
|
fn handleBulk(message: []const u8, reply: []u8) usize {
|
||||||
if (message.len < @sizeOf(transfer.BulkRequest)) return writeReply(reply, transfer.BulkReply{ .status = -1, .actual_length = 0 });
|
if (message.len < @sizeOf(usb_transfer_protocol.BulkRequest)) return writeReply(reply, usb_transfer_protocol.BulkReply{ .status = -1, .actual_length = 0 });
|
||||||
const request = std.mem.bytesToValue(transfer.BulkRequest, message[0..@sizeOf(transfer.BulkRequest)]);
|
const request = std.mem.bytesToValue(usb_transfer_protocol.BulkRequest, message[0..@sizeOf(usb_transfer_protocol.BulkRequest)]);
|
||||||
const engine = if (controller) |*c| c else return writeReply(reply, transfer.BulkReply{ .status = -1, .actual_length = 0 });
|
const engine = if (controller) |*c| c else return writeReply(reply, usb_transfer_protocol.BulkReply{ .status = -1, .actual_length = 0 });
|
||||||
const found = engine.findInterface(request.device_token) orelse return writeReply(reply, transfer.BulkReply{ .status = -1, .actual_length = 0 });
|
const found = engine.findInterface(request.device_token) orelse return writeReply(reply, usb_transfer_protocol.BulkReply{ .status = -1, .actual_length = 0 });
|
||||||
const endpoint = library.Controller.endpointForAddress(found.interface, request.endpoint_address) orelse return writeReply(reply, transfer.BulkReply{ .status = -1, .actual_length = 0 });
|
const endpoint = library.Controller.endpointForAddress(found.interface, request.endpoint_address) orelse return writeReply(reply, usb_transfer_protocol.BulkReply{ .status = -1, .actual_length = 0 });
|
||||||
const transferred = engine.bulkTransfer(found.device, endpoint, request.physical_address, request.length);
|
const transferred = engine.bulkTransfer(found.device, endpoint, request.physical_address, request.length);
|
||||||
return writeReply(reply, transfer.BulkReply{ .status = if (transferred != null) 0 else -1, .actual_length = transferred orelse 0 });
|
return writeReply(reply, usb_transfer_protocol.BulkReply{ .status = if (transferred != null) 0 else -1, .actual_length = transferred orelse 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The poll timer landed: drain any interrupt reports off the event ring and push
|
/// The poll timer landed: drain any interrupt reports off the event ring and push
|
||||||
@@ -543,12 +543,12 @@ fn onNotification(badge: u64) void {
|
|||||||
if (serviced >= 32) break;
|
if (serviced >= 32) break;
|
||||||
}
|
}
|
||||||
while (engine.takeReport()) |report| {
|
while (engine.takeReport()) |report| {
|
||||||
var message = transfer.InterruptReport{
|
var message = usb_transfer_protocol.InterruptReport{
|
||||||
.device_token = report.device_token,
|
.device_token = report.device_token,
|
||||||
.endpoint_address = report.endpoint_address,
|
.endpoint_address = report.endpoint_address,
|
||||||
.length = @intCast(@min(report.length, transfer.max_report_data)),
|
.length = @intCast(@min(report.length, usb_transfer_protocol.max_report_data)),
|
||||||
};
|
};
|
||||||
const n = @min(report.length, transfer.max_report_data);
|
const n = @min(report.length, usb_transfer_protocol.max_report_data);
|
||||||
@memcpy(message.data[0..n], report.data[0..n]);
|
@memcpy(message.data[0..n], report.data[0..n]);
|
||||||
_ = runtime.ipc.send(report.report_endpoint, std.mem.asBytes(&message));
|
_ = runtime.ipc.send(report.report_endpoint, std.mem.asBytes(&message));
|
||||||
}
|
}
|
||||||
@@ -565,7 +565,7 @@ pub fn main(init: runtime.process.Init) void {
|
|||||||
std.log.info("malformed controller device id '{s}'", .{argument});
|
std.log.info("malformed controller device id '{s}'", .{argument});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
runtime.service.run(transfer.message_maximum, .{
|
runtime.service.run(usb_transfer_protocol.message_maximum, .{
|
||||||
.service = .usb_bus,
|
.service = .usb_bus,
|
||||||
.init = initialise,
|
.init = initialise,
|
||||||
.on_message = onMessage,
|
.on_message = onMessage,
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ const runtime = @import("runtime");
|
|||||||
const aml = @import("aml");
|
const aml = @import("aml");
|
||||||
const acpi_ids = @import("acpi-ids");
|
const acpi_ids = @import("acpi-ids");
|
||||||
const device = runtime.device;
|
const device = runtime.device;
|
||||||
const protocol = @import("device-manager-protocol");
|
const device_manager_protocol = @import("device-manager-protocol");
|
||||||
const power = @import("power-protocol");
|
const power_protocol = @import("power-protocol");
|
||||||
/// AML opcode/prefix bytes by name (`zero_opcode`, `byte_prefix`, …) — so the `_HID`
|
/// AML opcode/prefix bytes by name (`zero_opcode`, `byte_prefix`, …) — so the `_HID`
|
||||||
/// integer decode names the opcodes instead of bare 0x0A/0x0B/… (docs/coding-standards.md).
|
/// integer decode names the opcodes instead of bare 0x0A/0x0B/… (docs/coding-standards.md).
|
||||||
const opcodes = aml.opcodes;
|
const opcodes = aml.opcodes;
|
||||||
@@ -184,7 +184,7 @@ pub fn main(init: runtime.process.Init) void {
|
|||||||
readFadt(fadt);
|
readFadt(fadt);
|
||||||
s5_valid = readSleepS5(&persistent_namespace);
|
s5_valid = readSleepS5(&persistent_namespace);
|
||||||
|
|
||||||
runtime.service.run(power.message_maximum, .{
|
runtime.service.run(power_protocol.message_maximum, .{
|
||||||
.service = .power,
|
.service = .power,
|
||||||
.init = onInit,
|
.init = onInit,
|
||||||
.on_message = onMessage,
|
.on_message = onMessage,
|
||||||
@@ -215,9 +215,9 @@ fn onInit(endpoint: runtime.ipc.Handle) bool {
|
|||||||
else
|
else
|
||||||
std.log.info("reported {s} (device {d}, {d} resources)", .{ hid, entry.device_id, entry.resource_count });
|
std.log.info("reported {s} (device {d}, {d} resources)", .{ hid, entry.device_id, entry.resource_count });
|
||||||
if (manager) |h| {
|
if (manager) |h| {
|
||||||
var report = protocol.ChildAdded{ .parent = node_id, .bus_address = entry.device_id, .identity = 0, .device_id = entry.device_id };
|
var report = device_manager_protocol.ChildAdded{ .parent = node_id, .bus_address = entry.device_id, .identity = 0, .device_id = entry.device_id };
|
||||||
@memcpy(report.hid[0..entry.hid_len], entry.hid[0..entry.hid_len]);
|
@memcpy(report.hid[0..entry.hid_len], entry.hid[0..entry.hid_len]);
|
||||||
var reply: [protocol.message_maximum]u8 = undefined;
|
var reply: [device_manager_protocol.message_maximum]u8 = undefined;
|
||||||
_ = runtime.ipc.call(h, std.mem.asBytes(&report), &reply) catch {};
|
_ = runtime.ipc.call(h, std.mem.asBytes(&report), &reply) catch {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,8 +365,8 @@ fn publishNotify(node: *aml.Node, code: u64) void {
|
|||||||
// Map the notified device's _HID to a domain event where we recognize it.
|
// Map the notified device's _HID to a domain event where we recognize it.
|
||||||
var hid: [8]u8 = .{0} ** 8;
|
var hid: [8]u8 = .{0} ** 8;
|
||||||
if (readHid(node, &global_interpreter)) |h| hid = h;
|
if (readHid(node, &global_interpreter)) |h| hid = h;
|
||||||
const which: power.Event = if (std.mem.eql(u8, hid[0..7], "PNP0C0A")) .battery else if (std.mem.eql(u8, hid[0..7], "ACPI0003")) .ac else if (std.mem.eql(u8, hid[0..7], "PNP0C0D")) .lid else .notify;
|
const which: power_protocol.Event = if (std.mem.eql(u8, hid[0..7], "PNP0C0A")) .battery else if (std.mem.eql(u8, hid[0..7], "ACPI0003")) .ac else if (std.mem.eql(u8, hid[0..7], "PNP0C0D")) .lid else .notify;
|
||||||
var event = power.EventMessage{ .event = @intFromEnum(which), .code = @truncate(code) };
|
var event = power_protocol.EventMessage{ .event = @intFromEnum(which), .code = @truncate(code) };
|
||||||
event.hid = hid;
|
event.hid = hid;
|
||||||
std.log.info("power: notify {s} code {d}", .{ hid[0..7], code });
|
std.log.info("power: notify {s} code {d}", .{ hid[0..7], code });
|
||||||
publishEvent(std.mem.asBytes(&event));
|
publishEvent(std.mem.asBytes(&event));
|
||||||
@@ -380,7 +380,7 @@ fn writeHex2(out: []u8, n: u32) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn publishButton() void {
|
fn publishButton() void {
|
||||||
const event = power.EventMessage{ .event = @intFromEnum(power.Event.power_button) };
|
const event = power_protocol.EventMessage{ .event = @intFromEnum(power_protocol.Event.power_button) };
|
||||||
publishEvent(std.mem.asBytes(&event));
|
publishEvent(std.mem.asBytes(&event));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +429,7 @@ fn onNotification(badge: u64) void {
|
|||||||
fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?runtime.ipc.Handle) usize {
|
fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?runtime.ipc.Handle) usize {
|
||||||
if (message.len < 1) return 0;
|
if (message.len < 1) return 0;
|
||||||
switch (message[0]) {
|
switch (message[0]) {
|
||||||
@intFromEnum(power.Operation.subscribe) => {
|
@intFromEnum(power_protocol.Operation.subscribe) => {
|
||||||
var status: i32 = -1;
|
var status: i32 = -1;
|
||||||
if (capability) |handle| {
|
if (capability) |handle| {
|
||||||
for (&subscribers, 0..) |*slot, si| {
|
for (&subscribers, 0..) |*slot, si| {
|
||||||
@@ -441,20 +441,20 @@ fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?runtime
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const r = power.Reply{ .status = status };
|
const r = power_protocol.Reply{ .status = status };
|
||||||
@memcpy(reply[0..@sizeOf(power.Reply)], std.mem.asBytes(&r));
|
@memcpy(reply[0..@sizeOf(power_protocol.Reply)], std.mem.asBytes(&r));
|
||||||
return @sizeOf(power.Reply);
|
return @sizeOf(power_protocol.Reply);
|
||||||
},
|
},
|
||||||
@intFromEnum(power.Operation.shutdown) => {
|
@intFromEnum(power_protocol.Operation.shutdown) => {
|
||||||
// Honored only from a power subscriber — init, which has already run
|
// Honored only from a power subscriber — init, which has already run
|
||||||
// the stop sequence over everything else. The power service is
|
// the stop sequence over everything else. The power service is
|
||||||
// mechanism (write S5); deciding *when* to shut down and stopping
|
// mechanism (write S5); deciding *when* to shut down and stopping
|
||||||
// the rest of the system first is init's policy.
|
// the rest of the system first is init's policy.
|
||||||
const allowed = isSubscriber(sender);
|
const allowed = isSubscriber(sender);
|
||||||
const r = power.Reply{ .status = if (allowed) 0 else -1 };
|
const r = power_protocol.Reply{ .status = if (allowed) 0 else -1 };
|
||||||
@memcpy(reply[0..@sizeOf(power.Reply)], std.mem.asBytes(&r));
|
@memcpy(reply[0..@sizeOf(power_protocol.Reply)], std.mem.asBytes(&r));
|
||||||
if (allowed) enterS5();
|
if (allowed) enterS5();
|
||||||
return @sizeOf(power.Reply);
|
return @sizeOf(power_protocol.Reply);
|
||||||
},
|
},
|
||||||
else => return 0,
|
else => return 0,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const runtime = @import("runtime");
|
const runtime = @import("runtime");
|
||||||
const protocol = @import("device-manager-protocol");
|
const device_manager_protocol = @import("device-manager-protocol");
|
||||||
|
|
||||||
pub fn main(init: runtime.process.Init) void {
|
pub fn main(init: runtime.process.Init) void {
|
||||||
const argument = init.arguments.get(1) orelse return; // bare: stay silent
|
const argument = init.arguments.get(1) orelse return; // bare: stay silent
|
||||||
@@ -29,8 +29,8 @@ pub fn main(init: runtime.process.Init) void {
|
|||||||
if (manager == null) runtime.system.sleep(20);
|
if (manager == null) runtime.system.sleep(20);
|
||||||
}
|
}
|
||||||
const h = manager orelse return;
|
const h = manager orelse return;
|
||||||
const hello = protocol.Hello{ .role = @intFromEnum(protocol.Role.device), .device_id = assigned };
|
const hello = device_manager_protocol.Hello{ .role = @intFromEnum(device_manager_protocol.Role.device), .device_id = assigned };
|
||||||
var reply: [protocol.message_maximum]u8 = undefined;
|
var reply: [device_manager_protocol.message_maximum]u8 = undefined;
|
||||||
_ = runtime.ipc.call(h, std.mem.asBytes(&hello), &reply) catch return;
|
_ = runtime.ipc.call(h, std.mem.asBytes(&hello), &reply) catch return;
|
||||||
|
|
||||||
_ = runtime.system.write("crash-test: faulting now\n");
|
_ = runtime.system.write("crash-test: faulting now\n");
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const runtime = @import("runtime");
|
const runtime = @import("runtime");
|
||||||
const protocol = @import("device-manager-protocol");
|
const device_manager_protocol = @import("device-manager-protocol");
|
||||||
|
|
||||||
fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
|
fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
|
||||||
var line: [96]u8 = undefined;
|
var line: [96]u8 = undefined;
|
||||||
@@ -27,26 +27,26 @@ pub fn main() void {
|
|||||||
|
|
||||||
// The snapshot — polled briefly, because at boot the bus drivers may still
|
// The snapshot — polled briefly, because at boot the bus drivers may still
|
||||||
// be scanning: an empty first answer usually just means "too early".
|
// be scanning: an empty first answer usually just means "too early".
|
||||||
var reply: [protocol.message_maximum]u8 = undefined;
|
var reply: [device_manager_protocol.message_maximum]u8 = undefined;
|
||||||
var count: u32 = 0;
|
var count: u32 = 0;
|
||||||
var length: usize = 0;
|
var length: usize = 0;
|
||||||
tries = 0;
|
tries = 0;
|
||||||
while (tries < 20) : (tries += 1) {
|
while (tries < 20) : (tries += 1) {
|
||||||
const request = protocol.Enumerate{};
|
const request = device_manager_protocol.Enumerate{};
|
||||||
length = runtime.ipc.call(h, std.mem.asBytes(&request), &reply) catch 0;
|
length = runtime.ipc.call(h, std.mem.asBytes(&request), &reply) catch 0;
|
||||||
if (length >= @sizeOf(protocol.EnumerateReply)) {
|
if (length >= @sizeOf(device_manager_protocol.EnumerateReply)) {
|
||||||
count = std.mem.bytesToValue(protocol.EnumerateReply, reply[0..@sizeOf(protocol.EnumerateReply)]).count;
|
count = std.mem.bytesToValue(device_manager_protocol.EnumerateReply, reply[0..@sizeOf(device_manager_protocol.EnumerateReply)]).count;
|
||||||
if (count != 0) break;
|
if (count != 0) break;
|
||||||
}
|
}
|
||||||
runtime.system.sleep(100);
|
runtime.system.sleep(100);
|
||||||
}
|
}
|
||||||
writeLine("device-list: {d} devices\n", .{count});
|
writeLine("device-list: {d} devices\n", .{count});
|
||||||
var offset: usize = @sizeOf(protocol.EnumerateReply);
|
var offset: usize = @sizeOf(device_manager_protocol.EnumerateReply);
|
||||||
var index: u32 = 0;
|
var index: u32 = 0;
|
||||||
while (index < count and offset + @sizeOf(protocol.ChildEntry) <= length) : (index += 1) {
|
while (index < count and offset + @sizeOf(device_manager_protocol.ChildEntry) <= length) : (index += 1) {
|
||||||
const entry = std.mem.bytesToValue(protocol.ChildEntry, reply[offset..][0..@sizeOf(protocol.ChildEntry)]);
|
const entry = std.mem.bytesToValue(device_manager_protocol.ChildEntry, reply[offset..][0..@sizeOf(device_manager_protocol.ChildEntry)]);
|
||||||
writeLine("device-list: device {d} port {d} identity {d}\n", .{ entry.parent, entry.bus_address, entry.identity });
|
writeLine("device-list: device {d} port {d} identity {d}\n", .{ entry.parent, entry.bus_address, entry.identity });
|
||||||
offset += @sizeOf(protocol.ChildEntry);
|
offset += @sizeOf(device_manager_protocol.ChildEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The subscription: our endpoint rides as the call's capability; events
|
// The subscription: our endpoint rides as the call's capability; events
|
||||||
@@ -55,26 +55,26 @@ pub fn main() void {
|
|||||||
_ = runtime.system.write("device-list: no endpoint\n");
|
_ = runtime.system.write("device-list: no endpoint\n");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
const subscribe = protocol.Subscribe{};
|
const subscribe = device_manager_protocol.Subscribe{};
|
||||||
_ = runtime.ipc.callCap(h, std.mem.asBytes(&subscribe), &reply, endpoint) catch {
|
_ = runtime.ipc.callCap(h, std.mem.asBytes(&subscribe), &reply, endpoint) catch {
|
||||||
_ = runtime.system.write("device-list: subscribe failed\n");
|
_ = runtime.system.write("device-list: subscribe failed\n");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
_ = runtime.system.write("device-list: subscribed\n");
|
_ = runtime.system.write("device-list: subscribed\n");
|
||||||
|
|
||||||
var receive: [protocol.message_maximum]u8 = undefined;
|
var receive: [device_manager_protocol.message_maximum]u8 = undefined;
|
||||||
while (true) {
|
while (true) {
|
||||||
const got = runtime.ipc.replyWait(endpoint, &.{}, &receive, null);
|
const got = runtime.ipc.replyWait(endpoint, &.{}, &receive, null);
|
||||||
if (!got.isMessage() or got.len < 1) continue;
|
if (!got.isMessage() or got.len < 1) continue;
|
||||||
switch (receive[0]) {
|
switch (receive[0]) {
|
||||||
@intFromEnum(protocol.Operation.child_added) => {
|
@intFromEnum(device_manager_protocol.Operation.child_added) => {
|
||||||
if (got.len < protocol.child_added_size) continue;
|
if (got.len < device_manager_protocol.child_added_size) continue;
|
||||||
const event = std.mem.bytesToValue(protocol.ChildAdded, receive[0..protocol.child_added_size]);
|
const event = std.mem.bytesToValue(device_manager_protocol.ChildAdded, receive[0..device_manager_protocol.child_added_size]);
|
||||||
writeLine("device-list: added (device {d} port {d})\n", .{ event.parent, event.bus_address });
|
writeLine("device-list: added (device {d} port {d})\n", .{ event.parent, event.bus_address });
|
||||||
},
|
},
|
||||||
@intFromEnum(protocol.Operation.child_removed) => {
|
@intFromEnum(device_manager_protocol.Operation.child_removed) => {
|
||||||
if (got.len < protocol.child_removed_size) continue;
|
if (got.len < device_manager_protocol.child_removed_size) continue;
|
||||||
const event = std.mem.bytesToValue(protocol.ChildRemoved, receive[0..protocol.child_removed_size]);
|
const event = std.mem.bytesToValue(device_manager_protocol.ChildRemoved, receive[0..device_manager_protocol.child_removed_size]);
|
||||||
writeLine("device-list: removed (device {d} port {d})\n", .{ event.parent, event.bus_address });
|
writeLine("device-list: removed (device {d} port {d})\n", .{ event.parent, event.bus_address });
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const runtime = @import("runtime");
|
|||||||
const acpi_ids = @import("acpi-ids");
|
const acpi_ids = @import("acpi-ids");
|
||||||
const pci_class = @import("pci-class");
|
const pci_class = @import("pci-class");
|
||||||
const usb_ids = @import("usb-ids");
|
const usb_ids = @import("usb-ids");
|
||||||
const protocol = @import("device-manager-protocol");
|
const device_manager_protocol = @import("device-manager-protocol");
|
||||||
const device = runtime.device;
|
const device = runtime.device;
|
||||||
const system = runtime.system;
|
const system = runtime.system;
|
||||||
|
|
||||||
@@ -134,8 +134,8 @@ const Driver = struct {
|
|||||||
used: bool = false,
|
used: bool = false,
|
||||||
name_buffer: [64]u8 = undefined, // fits a full binary path (abi.maximum_process_name)
|
name_buffer: [64]u8 = undefined, // fits a full binary path (abi.maximum_process_name)
|
||||||
name_len: usize = 0,
|
name_len: usize = 0,
|
||||||
// The assigned device id (becomes argv[1]), or protocol.no_device.
|
// The assigned device id (becomes argv[1]), or device_manager_protocol.no_device.
|
||||||
device_id: u64 = protocol.no_device,
|
device_id: u64 = device_manager_protocol.no_device,
|
||||||
// Whether this driver speaks the protocol (hello expected, deadline
|
// Whether this driver speaks the protocol (hello expected, deadline
|
||||||
// enforced). Legacy drivers (e.g. ps2-bus) are supervised and restarted
|
// enforced). Legacy drivers (e.g. ps2-bus) are supervised and restarted
|
||||||
// but not yet required to hello.
|
// but not yet required to hello.
|
||||||
@@ -189,7 +189,7 @@ const Child = struct {
|
|||||||
parent: u64 = 0,
|
parent: u64 = 0,
|
||||||
bus_address: u64 = 0,
|
bus_address: u64 = 0,
|
||||||
identity: u64 = 0,
|
identity: u64 = 0,
|
||||||
// The kernel device id (registered by the reporter), or protocol.no_device.
|
// The kernel device id (registered by the reporter), or device_manager_protocol.no_device.
|
||||||
device_id: u64 = 0,
|
device_id: u64 = 0,
|
||||||
reporter: u32 = 0, // the reporting driver instance's process id
|
reporter: u32 = 0, // the reporting driver instance's process id
|
||||||
};
|
};
|
||||||
@@ -225,7 +225,7 @@ fn pruneChildrenOf(reporter: u32) void {
|
|||||||
if (child.used and child.reporter == reporter) {
|
if (child.used and child.reporter == reporter) {
|
||||||
std.log.info("child removed (device {d} port {d})", .{ child.parent, child.bus_address });
|
std.log.info("child removed (device {d} port {d})", .{ child.parent, child.bus_address });
|
||||||
child.used = false;
|
child.used = false;
|
||||||
const event = protocol.ChildRemoved{ .parent = child.parent, .bus_address = child.bus_address };
|
const event = device_manager_protocol.ChildRemoved{ .parent = child.parent, .bus_address = child.bus_address };
|
||||||
publishEvent(std.mem.asBytes(&event));
|
publishEvent(std.mem.asBytes(&event));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,7 +280,7 @@ fn spawnDriver(driver: *Driver) void {
|
|||||||
var id_text: [20]u8 = undefined;
|
var id_text: [20]u8 = undefined;
|
||||||
var arguments: [1][]const u8 = undefined;
|
var arguments: [1][]const u8 = undefined;
|
||||||
var argument_count: usize = 0;
|
var argument_count: usize = 0;
|
||||||
if (driver.device_id != protocol.no_device) {
|
if (driver.device_id != device_manager_protocol.no_device) {
|
||||||
arguments[0] = std.fmt.bufPrint(&id_text, "{d}", .{driver.device_id}) catch return;
|
arguments[0] = std.fmt.bufPrint(&id_text, "{d}", .{driver.device_id}) catch return;
|
||||||
argument_count = 1;
|
argument_count = 1;
|
||||||
}
|
}
|
||||||
@@ -298,7 +298,7 @@ fn spawnDriver(driver: *Driver) void {
|
|||||||
} else {
|
} else {
|
||||||
driver.state = .running;
|
driver.state = .running;
|
||||||
}
|
}
|
||||||
if (driver.device_id != protocol.no_device) {
|
if (driver.device_id != device_manager_protocol.no_device) {
|
||||||
std.log.info("spawned {s} for device {d}", .{ driver.name(), driver.device_id });
|
std.log.info("spawned {s} for device {d}", .{ driver.name(), driver.device_id });
|
||||||
} else {
|
} else {
|
||||||
std.log.info("spawned {s}", .{driver.name()});
|
std.log.info("spawned {s}", .{driver.name()});
|
||||||
@@ -390,7 +390,7 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
|
|||||||
// under the neutral name "discovery", spawned once at startup. It finds and
|
// under the neutral name "discovery", spawned once at startup. It finds and
|
||||||
// claims the acpi-tables (or devicetree-blob) node itself. Not a per-device
|
// claims the acpi-tables (or devicetree-blob) node itself. Not a per-device
|
||||||
// match — it is the discoverer, not a driver bound to one device.
|
// match — it is the discoverer, not a driver bound to one device.
|
||||||
addDriver("discovery", protocol.no_device, false);
|
addDriver("discovery", device_manager_protocol.no_device, false);
|
||||||
|
|
||||||
if (test_restart_mode) {
|
if (test_restart_mode) {
|
||||||
// The driver-restart scenario's fixture: claims device 0 (the tree
|
// The driver-restart scenario's fixture: claims device 0 (the tree
|
||||||
@@ -410,18 +410,18 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
|
|||||||
fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?runtime.ipc.Handle) usize {
|
fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?runtime.ipc.Handle) usize {
|
||||||
if (message.len < 1) return 0;
|
if (message.len < 1) return 0;
|
||||||
switch (message[0]) {
|
switch (message[0]) {
|
||||||
@intFromEnum(protocol.Operation.child_added) => return onChildAdded(message, reply, sender),
|
@intFromEnum(device_manager_protocol.Operation.child_added) => return onChildAdded(message, reply, sender),
|
||||||
@intFromEnum(protocol.Operation.child_removed) => return onChildRemoved(message, reply, sender),
|
@intFromEnum(device_manager_protocol.Operation.child_removed) => return onChildRemoved(message, reply, sender),
|
||||||
@intFromEnum(protocol.Operation.enumerate) => return onEnumerate(reply),
|
@intFromEnum(device_manager_protocol.Operation.enumerate) => return onEnumerate(reply),
|
||||||
@intFromEnum(protocol.Operation.subscribe) => return onSubscribe(reply, capability),
|
@intFromEnum(device_manager_protocol.Operation.subscribe) => return onSubscribe(reply, capability),
|
||||||
@intFromEnum(protocol.Operation.hello) => {},
|
@intFromEnum(device_manager_protocol.Operation.hello) => {},
|
||||||
else => return 0,
|
else => return 0,
|
||||||
}
|
}
|
||||||
if (message.len < protocol.hello_size) return 0;
|
if (message.len < device_manager_protocol.hello_size) return 0;
|
||||||
const hello = std.mem.bytesToValue(protocol.Hello, message[0..protocol.hello_size]);
|
const hello = std.mem.bytesToValue(device_manager_protocol.Hello, message[0..device_manager_protocol.hello_size]);
|
||||||
|
|
||||||
var status: i32 = 0;
|
var status: i32 = 0;
|
||||||
if (hello.version != protocol.version) {
|
if (hello.version != device_manager_protocol.version) {
|
||||||
status = -1;
|
status = -1;
|
||||||
std.log.info("refused hello (version {d}) from process {d}", .{ hello.version, sender });
|
std.log.info("refused hello (version {d}) from process {d}", .{ hello.version, sender });
|
||||||
} else if (driverByProcess(sender)) |driver| {
|
} else if (driverByProcess(sender)) |driver| {
|
||||||
@@ -439,26 +439,26 @@ fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?runtime
|
|||||||
status = -1;
|
status = -1;
|
||||||
std.log.info("hello from unknown process {d}", .{sender});
|
std.log.info("hello from unknown process {d}", .{sender});
|
||||||
}
|
}
|
||||||
const hello_reply = protocol.HelloReply{ .status = status };
|
const hello_reply = device_manager_protocol.HelloReply{ .status = status };
|
||||||
@memcpy(reply[0..protocol.reply_size], std.mem.asBytes(&hello_reply));
|
@memcpy(reply[0..device_manager_protocol.reply_size], std.mem.asBytes(&hello_reply));
|
||||||
return protocol.reply_size;
|
return device_manager_protocol.reply_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A bus driver reported a discovered device: mirror it, and in
|
/// A bus driver reported a discovered device: mirror it, and in
|
||||||
/// test-usb-restart mode kill the reporter once after its second child — the
|
/// test-usb-restart mode kill the reporter once after its second child — the
|
||||||
/// deterministic trigger for prune -> backoff -> respawn -> re-report.
|
/// deterministic trigger for prune -> backoff -> respawn -> re-report.
|
||||||
fn onChildAdded(message: []const u8, reply: []u8, sender: u32) usize {
|
fn onChildAdded(message: []const u8, reply: []u8, sender: u32) usize {
|
||||||
if (message.len < protocol.child_added_size) return 0;
|
if (message.len < device_manager_protocol.child_added_size) return 0;
|
||||||
const report = std.mem.bytesToValue(protocol.ChildAdded, message[0..protocol.child_added_size]);
|
const report = std.mem.bytesToValue(device_manager_protocol.ChildAdded, message[0..device_manager_protocol.child_added_size]);
|
||||||
var status: i32 = 0;
|
var status: i32 = 0;
|
||||||
if (driverByProcess(sender)) |driver| {
|
if (driverByProcess(sender)) |driver| {
|
||||||
if (!addChild(report.parent, report.bus_address, report.identity, report.device_id, sender)) status = -1;
|
if (!addChild(report.parent, report.bus_address, report.identity, report.device_id, sender)) status = -1;
|
||||||
std.log.info("child added (device {d} port {d}, identity {d}) by {s}", .{ report.parent, report.bus_address, report.identity, driver.name() });
|
std.log.info("child added (device {d} port {d}, identity {d}) by {s}", .{ report.parent, report.bus_address, report.identity, driver.name() });
|
||||||
if (status == 0) publishEvent(message[0..protocol.child_added_size]);
|
if (status == 0) publishEvent(message[0..device_manager_protocol.child_added_size]);
|
||||||
// Matching from reports (M19.3): a registered child whose identity
|
// Matching from reports (M19.3): a registered child whose identity
|
||||||
// names a driver gets one, once — re-reports after a bus restart
|
// names a driver gets one, once — re-reports after a bus restart
|
||||||
// dedupe on the registered id, exactly like the registrations do.
|
// dedupe on the registered id, exactly like the registrations do.
|
||||||
if (status == 0 and report.device_id != protocol.no_device) {
|
if (status == 0 and report.device_id != device_manager_protocol.no_device) {
|
||||||
if (pciDriverForIdentity(report.identity)) |child_driver| {
|
if (pciDriverForIdentity(report.identity)) |child_driver| {
|
||||||
if (!driverForDevice(report.device_id)) addDriver(child_driver, report.device_id, true);
|
if (!driverForDevice(report.device_id)) addDriver(child_driver, report.device_id, true);
|
||||||
}
|
}
|
||||||
@@ -472,15 +472,15 @@ fn onChildAdded(message: []const u8, reply: []u8, sender: u32) usize {
|
|||||||
const hid_len = std.mem.indexOfScalar(u8, &report.hid, 0) orelse report.hid.len;
|
const hid_len = std.mem.indexOfScalar(u8, &report.hid, 0) orelse report.hid.len;
|
||||||
if (hid_len != 0) {
|
if (hid_len != 0) {
|
||||||
if (hidDriverFor(report.hid[0..hid_len])) |hid_driver| {
|
if (hidDriverFor(report.hid[0..hid_len])) |hid_driver| {
|
||||||
if (!alreadySupervised(hid_driver)) addDriver(hid_driver, protocol.no_device, false);
|
if (!alreadySupervised(hid_driver)) addDriver(hid_driver, device_manager_protocol.no_device, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
status = -1;
|
status = -1;
|
||||||
}
|
}
|
||||||
const report_reply = protocol.ReportReply{ .status = status };
|
const report_reply = device_manager_protocol.ReportReply{ .status = status };
|
||||||
@memcpy(reply[0..@sizeOf(protocol.ReportReply)], std.mem.asBytes(&report_reply));
|
@memcpy(reply[0..@sizeOf(device_manager_protocol.ReportReply)], std.mem.asBytes(&report_reply));
|
||||||
if (test_pci_restart_mode and !test_usb_killed) {
|
if (test_pci_restart_mode and !test_usb_killed) {
|
||||||
if (driverByProcess(sender)) |driver| {
|
if (driverByProcess(sender)) |driver| {
|
||||||
if (std.mem.eql(u8, driver.name(), "pci-bus") and childCountOf(sender) >= 3) {
|
if (std.mem.eql(u8, driver.name(), "pci-bus") and childCountOf(sender) >= 3) {
|
||||||
@@ -508,14 +508,14 @@ fn onChildAdded(message: []const u8, reply: []u8, sender: u32) usize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return @sizeOf(protocol.ReportReply);
|
return @sizeOf(device_manager_protocol.ReportReply);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A bus driver reported a device gone (hot-unplug; no sender exists yet, but
|
/// A bus driver reported a device gone (hot-unplug; no sender exists yet, but
|
||||||
/// the handler is protocol-complete — death-pruning covers removal until then).
|
/// the handler is protocol-complete — death-pruning covers removal until then).
|
||||||
fn onChildRemoved(message: []const u8, reply: []u8, sender: u32) usize {
|
fn onChildRemoved(message: []const u8, reply: []u8, sender: u32) usize {
|
||||||
if (message.len < protocol.child_removed_size) return 0;
|
if (message.len < device_manager_protocol.child_removed_size) return 0;
|
||||||
const report = std.mem.bytesToValue(protocol.ChildRemoved, message[0..protocol.child_removed_size]);
|
const report = std.mem.bytesToValue(device_manager_protocol.ChildRemoved, message[0..device_manager_protocol.child_removed_size]);
|
||||||
var status: i32 = -1;
|
var status: i32 = -1;
|
||||||
for (&children) |*child| {
|
for (&children) |*child| {
|
||||||
if (child.used and child.parent == report.parent and child.bus_address == report.bus_address and child.reporter == sender) {
|
if (child.used and child.parent == report.parent and child.bus_address == report.bus_address and child.reporter == sender) {
|
||||||
@@ -524,25 +524,25 @@ fn onChildRemoved(message: []const u8, reply: []u8, sender: u32) usize {
|
|||||||
status = 0;
|
status = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const report_reply = protocol.ReportReply{ .status = status };
|
const report_reply = device_manager_protocol.ReportReply{ .status = status };
|
||||||
@memcpy(reply[0..@sizeOf(protocol.ReportReply)], std.mem.asBytes(&report_reply));
|
@memcpy(reply[0..@sizeOf(device_manager_protocol.ReportReply)], std.mem.asBytes(&report_reply));
|
||||||
return @sizeOf(protocol.ReportReply);
|
return @sizeOf(device_manager_protocol.ReportReply);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An application asked for the tree: the mirror, as a header plus entries.
|
/// An application asked for the tree: the mirror, as a header plus entries.
|
||||||
fn onEnumerate(reply: []u8) usize {
|
fn onEnumerate(reply: []u8) usize {
|
||||||
var count: u32 = 0;
|
var count: u32 = 0;
|
||||||
var offset: usize = @sizeOf(protocol.EnumerateReply);
|
var offset: usize = @sizeOf(device_manager_protocol.EnumerateReply);
|
||||||
for (&children) |*child| {
|
for (&children) |*child| {
|
||||||
if (!child.used) continue;
|
if (!child.used) continue;
|
||||||
if (offset + @sizeOf(protocol.ChildEntry) > reply.len) break;
|
if (offset + @sizeOf(device_manager_protocol.ChildEntry) > reply.len) break;
|
||||||
const entry = protocol.ChildEntry{ .parent = child.parent, .bus_address = child.bus_address, .identity = child.identity };
|
const entry = device_manager_protocol.ChildEntry{ .parent = child.parent, .bus_address = child.bus_address, .identity = child.identity };
|
||||||
@memcpy(reply[offset..][0..@sizeOf(protocol.ChildEntry)], std.mem.asBytes(&entry));
|
@memcpy(reply[offset..][0..@sizeOf(device_manager_protocol.ChildEntry)], std.mem.asBytes(&entry));
|
||||||
offset += @sizeOf(protocol.ChildEntry);
|
offset += @sizeOf(device_manager_protocol.ChildEntry);
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
const header = protocol.EnumerateReply{ .status = 0, .count = count };
|
const header = device_manager_protocol.EnumerateReply{ .status = 0, .count = count };
|
||||||
@memcpy(reply[0..@sizeOf(protocol.EnumerateReply)], std.mem.asBytes(&header));
|
@memcpy(reply[0..@sizeOf(device_manager_protocol.EnumerateReply)], std.mem.asBytes(&header));
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,9 +558,9 @@ fn onSubscribe(reply: []u8, capability: ?runtime.ipc.Handle) usize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const report_reply = protocol.ReportReply{ .status = status };
|
const report_reply = device_manager_protocol.ReportReply{ .status = status };
|
||||||
@memcpy(reply[0..@sizeOf(protocol.ReportReply)], std.mem.asBytes(&report_reply));
|
@memcpy(reply[0..@sizeOf(device_manager_protocol.ReportReply)], std.mem.asBytes(&report_reply));
|
||||||
return @sizeOf(protocol.ReportReply);
|
return @sizeOf(device_manager_protocol.ReportReply);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn onNotification(badge: u64) void {
|
fn onNotification(badge: u64) void {
|
||||||
@@ -579,7 +579,7 @@ pub fn main(init: runtime.process.Init) void {
|
|||||||
test_pci_restart_mode = std.mem.eql(u8, mode, "test-pci-restart");
|
test_pci_restart_mode = std.mem.eql(u8, mode, "test-pci-restart");
|
||||||
test_scanout_restart_mode = std.mem.eql(u8, mode, "test-scanout-restart");
|
test_scanout_restart_mode = std.mem.eql(u8, mode, "test-scanout-restart");
|
||||||
}
|
}
|
||||||
runtime.service.run(protocol.message_maximum, .{
|
runtime.service.run(device_manager_protocol.message_maximum, .{
|
||||||
.service = .device_manager,
|
.service = .device_manager,
|
||||||
.init = initialise,
|
.init = initialise,
|
||||||
.on_message = onMessage,
|
.on_message = onMessage,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const runtime = @import("runtime");
|
|||||||
const compositor = @import("compositor.zig");
|
const compositor = @import("compositor.zig");
|
||||||
const backend_mod = @import("backend.zig");
|
const backend_mod = @import("backend.zig");
|
||||||
|
|
||||||
const protocol = @import("display-protocol");
|
const display_protocol = @import("display-protocol");
|
||||||
const ipc = runtime.ipc;
|
const ipc = runtime.ipc;
|
||||||
const system = runtime.system;
|
const system = runtime.system;
|
||||||
const input = runtime.input;
|
const input = runtime.input;
|
||||||
@@ -326,7 +326,7 @@ fn attachScanout(stride: u32, width: u32, height: u32, format: u32, refresh_hz:
|
|||||||
.refresh_hz = refresh_hz,
|
.refresh_hz = refresh_hz,
|
||||||
.scanout = scanout,
|
.scanout = scanout,
|
||||||
} };
|
} };
|
||||||
background = protocol.pack(format, 0x20, 0x30, 0x48); // re-pack the wallpaper for the mode
|
background = display_protocol.pack(format, 0x20, 0x30, 0x48); // re-pack the wallpaper for the mode
|
||||||
updateFrameClock(); // the GOP floor's clock dies here — pace by the GPU's EDID now
|
updateFrameClock(); // the GOP floor's clock dies here — pace by the GPU's EDID now
|
||||||
addDamage(screenRect()); // the whole new surface must be painted
|
addDamage(screenRect()); // the whole new surface must be painted
|
||||||
pending_native_verify = true;
|
pending_native_verify = true;
|
||||||
@@ -389,8 +389,8 @@ fn modesetSelfCheck() void {
|
|||||||
/// backend surface — and reads the composited result back. Cleans up after itself.
|
/// backend surface — and reads the composited result back. Cleans up after itself.
|
||||||
fn selfCheck() void {
|
fn selfCheck() void {
|
||||||
const format = backend.info().format;
|
const format = backend.info().format;
|
||||||
const red = protocol.pack(format, 0xC0, 0x20, 0x20);
|
const red = display_protocol.pack(format, 0xC0, 0x20, 0x20);
|
||||||
const green = protocol.pack(format, 0x20, 0xC0, 0x20);
|
const green = display_protocol.pack(format, 0x20, 0xC0, 0x20);
|
||||||
const bottom = createLayer(100, 100, 80, 80, 0, true) orelse return fail_check("create");
|
const bottom = createLayer(100, 100, 80, 80, 0, true) orelse return fail_check("create");
|
||||||
const top = createLayer(140, 140, 80, 80, 1, true) orelse return fail_check("create");
|
const top = createLayer(140, 140, 80, 80, 1, true) orelse return fail_check("create");
|
||||||
_ = fillLayer(bottom, Rect.init(0, 0, 80, 80), red);
|
_ = fillLayer(bottom, Rect.init(0, 0, 80, 80), red);
|
||||||
@@ -559,7 +559,7 @@ fn startCursorTracking() void {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
cursor_layer = id;
|
cursor_layer = id;
|
||||||
_ = fillLayer(id, Rect.init(0, 0, cursor_size, cursor_size), protocol.pack(mode.format, 0xF0, 0xF0, 0xF0));
|
_ = fillLayer(id, Rect.init(0, 0, cursor_size, cursor_size), display_protocol.pack(mode.format, 0xF0, 0xF0, 0xF0));
|
||||||
present(); // show the cursor at its start position
|
present(); // show the cursor at its start position
|
||||||
|
|
||||||
_ = Thread.spawn(.{}, mouseListener, .{ mode.width, mode.height }) catch {
|
_ = Thread.spawn(.{}, mouseListener, .{ mode.width, mode.height }) catch {
|
||||||
@@ -575,7 +575,7 @@ fn initialise(endpoint: ipc.Handle) bool {
|
|||||||
// Pick the scanout backend (GOP today). It logs the reason on failure.
|
// Pick the scanout backend (GOP today). It logs the reason on failure.
|
||||||
backend = backend_mod.select() orelse return false;
|
backend = backend_mod.select() orelse return false;
|
||||||
const mode = backend.info();
|
const mode = backend.info();
|
||||||
background = protocol.pack(mode.format, 0x20, 0x30, 0x48); // a dark slate wallpaper
|
background = display_protocol.pack(mode.format, 0x20, 0x30, 0x48); // a dark slate wallpaper
|
||||||
|
|
||||||
// Clear the whole screen through the compose surface → present path (double buffering:
|
// Clear the whole screen through the compose surface → present path (double buffering:
|
||||||
// no direct-to-scanout drawing).
|
// no direct-to-scanout drawing).
|
||||||
@@ -596,7 +596,7 @@ fn initialise(endpoint: ipc.Handle) bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn writeReply(reply: []u8, value: protocol.Reply) usize {
|
fn writeReply(reply: []u8, value: display_protocol.Reply) usize {
|
||||||
const bytes = std.mem.asBytes(&value);
|
const bytes = std.mem.asBytes(&value);
|
||||||
@memcpy(reply[0..bytes.len], bytes);
|
@memcpy(reply[0..bytes.len], bytes);
|
||||||
return bytes.len;
|
return bytes.len;
|
||||||
@@ -612,61 +612,61 @@ fn fail(reply: []u8) usize {
|
|||||||
|
|
||||||
fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?ipc.Handle) usize {
|
fn onMessage(message: []const u8, reply: []u8, sender: u32, capability: ?ipc.Handle) usize {
|
||||||
_ = sender;
|
_ = sender;
|
||||||
if (message.len < protocol.request_size) return fail(reply);
|
if (message.len < display_protocol.request_size) return fail(reply);
|
||||||
const request = std.mem.bytesToValue(protocol.Request, message[0..protocol.request_size]);
|
const request = std.mem.bytesToValue(display_protocol.Request, message[0..display_protocol.request_size]);
|
||||||
const payload = message[protocol.request_size..];
|
const payload = message[display_protocol.request_size..];
|
||||||
// Switch on the raw operation value — an out-of-range one must fail cleanly, not
|
// Switch on the raw operation value — an out-of-range one must fail cleanly, not
|
||||||
// panic an `@enumFromInt`.
|
// panic an `@enumFromInt`.
|
||||||
switch (request.operation) {
|
switch (request.operation) {
|
||||||
@intFromEnum(protocol.Operation.info) => {
|
@intFromEnum(display_protocol.Operation.info) => {
|
||||||
const m = backend.info();
|
const m = backend.info();
|
||||||
return writeReply(reply, .{ .status = 0, .width = m.width, .height = m.height, .pitch = m.pitch, .format = m.format });
|
return writeReply(reply, .{ .status = 0, .width = m.width, .height = m.height, .pitch = m.pitch, .format = m.format });
|
||||||
},
|
},
|
||||||
@intFromEnum(protocol.Operation.create_layer) => {
|
@intFromEnum(display_protocol.Operation.create_layer) => {
|
||||||
// x/y are signed coordinates carried in the u32 wire fields — reinterpret the
|
// x/y are signed coordinates carried in the u32 wire fields — reinterpret the
|
||||||
// bits (@bitCast), don't range-check (@intCast) which a negative would fail.
|
// bits (@bitCast), don't range-check (@intCast) which a negative would fail.
|
||||||
const slot = createLayer(@bitCast(request.x), @bitCast(request.y), request.width, request.height, request.z, request.visible != 0) orelse return fail(reply);
|
const slot = createLayer(@bitCast(request.x), @bitCast(request.y), request.width, request.height, request.z, request.visible != 0) orelse return fail(reply);
|
||||||
return writeReply(reply, .{ .status = 0, .layer = slot });
|
return writeReply(reply, .{ .status = 0, .layer = slot });
|
||||||
},
|
},
|
||||||
@intFromEnum(protocol.Operation.configure_layer) => {
|
@intFromEnum(display_protocol.Operation.configure_layer) => {
|
||||||
return if (configureLayer(request.layer, @bitCast(request.x), @bitCast(request.y), request.z, request.visible != 0)) ok(reply) else fail(reply);
|
return if (configureLayer(request.layer, @bitCast(request.x), @bitCast(request.y), request.z, request.visible != 0)) ok(reply) else fail(reply);
|
||||||
},
|
},
|
||||||
@intFromEnum(protocol.Operation.destroy_layer) => {
|
@intFromEnum(display_protocol.Operation.destroy_layer) => {
|
||||||
return if (destroyLayer(request.layer)) ok(reply) else fail(reply);
|
return if (destroyLayer(request.layer)) ok(reply) else fail(reply);
|
||||||
},
|
},
|
||||||
@intFromEnum(protocol.Operation.fill_rect) => {
|
@intFromEnum(display_protocol.Operation.fill_rect) => {
|
||||||
const local = Rect.init(@bitCast(request.x), @bitCast(request.y), @intCast(request.width), @intCast(request.height));
|
const local = Rect.init(@bitCast(request.x), @bitCast(request.y), @intCast(request.width), @intCast(request.height));
|
||||||
return if (fillLayer(request.layer, local, request.colour)) ok(reply) else fail(reply);
|
return if (fillLayer(request.layer, local, request.colour)) ok(reply) else fail(reply);
|
||||||
},
|
},
|
||||||
@intFromEnum(protocol.Operation.blit_tile) => {
|
@intFromEnum(display_protocol.Operation.blit_tile) => {
|
||||||
return if (blitLayer(request.layer, @bitCast(request.x), @bitCast(request.y), request.width, request.height, payload)) ok(reply) else fail(reply);
|
return if (blitLayer(request.layer, @bitCast(request.x), @bitCast(request.y), request.width, request.height, payload)) ok(reply) else fail(reply);
|
||||||
},
|
},
|
||||||
@intFromEnum(protocol.Operation.damage) => {
|
@intFromEnum(display_protocol.Operation.damage) => {
|
||||||
const l = layerAt(request.layer) orelse return fail(reply);
|
const l = layerAt(request.layer) orelse return fail(reply);
|
||||||
const screen = Rect{ .x = l.x + @as(i32, @bitCast(request.x)), .y = l.y + @as(i32, @bitCast(request.y)), .w = @intCast(request.width), .h = @intCast(request.height) };
|
const screen = Rect{ .x = l.x + @as(i32, @bitCast(request.x)), .y = l.y + @as(i32, @bitCast(request.y)), .w = @intCast(request.width), .h = @intCast(request.height) };
|
||||||
addDamage(screen.intersect(layerScreenRect(l)));
|
addDamage(screen.intersect(layerScreenRect(l)));
|
||||||
return ok(reply);
|
return ok(reply);
|
||||||
},
|
},
|
||||||
@intFromEnum(protocol.Operation.present) => {
|
@intFromEnum(display_protocol.Operation.present) => {
|
||||||
// Scheduled, not immediate: the frame clock composites the accumulated damage
|
// Scheduled, not immediate: the frame clock composites the accumulated damage
|
||||||
// at the next tick, so back-to-back client presents coalesce into one frame.
|
// at the next tick, so back-to-back client presents coalesce into one frame.
|
||||||
schedulePresent();
|
schedulePresent();
|
||||||
return ok(reply);
|
return ok(reply);
|
||||||
},
|
},
|
||||||
@intFromEnum(protocol.Operation.attach_scanout) => {
|
@intFromEnum(display_protocol.Operation.attach_scanout) => {
|
||||||
return attachScanout(request.x, request.width, request.height, request.colour, request.y, capability, reply);
|
return attachScanout(request.x, request.width, request.height, request.colour, request.y, capability, reply);
|
||||||
},
|
},
|
||||||
@intFromEnum(protocol.Operation.set_mode) => {
|
@intFromEnum(display_protocol.Operation.set_mode) => {
|
||||||
if (!backend.setMode(request.width, request.height)) return fail(reply);
|
if (!backend.setMode(request.width, request.height)) return fail(reply);
|
||||||
addDamage(screenRect()); // repaint the whole screen at the new resolution
|
addDamage(screenRect()); // repaint the whole screen at the new resolution
|
||||||
present();
|
present();
|
||||||
return ok(reply);
|
return ok(reply);
|
||||||
},
|
},
|
||||||
@intFromEnum(protocol.Operation.get_modes) => {
|
@intFromEnum(display_protocol.Operation.get_modes) => {
|
||||||
var list: [4]backend_mod.Mode = undefined;
|
var list: [4]backend_mod.Mode = undefined;
|
||||||
const count = backend.modes(&list);
|
const count = backend.modes(&list);
|
||||||
var response = protocol.ModesReply{ .status = 0, .count = @intCast(count), .modes = undefined };
|
var response = display_protocol.ModesReply{ .status = 0, .count = @intCast(count), .modes = undefined };
|
||||||
for (0..protocol.max_modes) |i| {
|
for (0..display_protocol.max_modes) |i| {
|
||||||
response.modes[i] = if (i < count)
|
response.modes[i] = if (i < count)
|
||||||
.{ .width = list[i].width, .height = list[i].height }
|
.{ .width = list[i].width, .height = list[i].height }
|
||||||
else
|
else
|
||||||
@@ -692,7 +692,7 @@ fn onNotification(badge: u64) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() void {
|
pub fn main() void {
|
||||||
runtime.service.run(protocol.message_maximum, .{
|
runtime.service.run(display_protocol.message_maximum, .{
|
||||||
.service = .display,
|
.service = .display,
|
||||||
.init = initialise,
|
.init = initialise,
|
||||||
.on_message = onMessage,
|
.on_message = onMessage,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const runtime = @import("runtime");
|
const runtime = @import("runtime");
|
||||||
const power = @import("power-protocol");
|
const power_protocol = @import("power-protocol");
|
||||||
const build_options = @import("build_options");
|
const build_options = @import("build_options");
|
||||||
|
|
||||||
/// The system services init brings up at boot, in order, by binary path. This is
|
/// The system services init brings up at boot, in order, by binary path. This is
|
||||||
@@ -105,7 +105,7 @@ pub fn main() void {
|
|||||||
// and the handler below — folds away entirely when serial is off.
|
// and the handler below — folds away entirely when serial is off.
|
||||||
if (build_options.serial) _ = runtime.system.timerOnce(supervision_endpoint, 1000);
|
if (build_options.serial) _ = runtime.system.timerOnce(supervision_endpoint, 1000);
|
||||||
|
|
||||||
var receive: [power.message_maximum]u8 = undefined;
|
var receive: [power_protocol.message_maximum]u8 = undefined;
|
||||||
while (true) {
|
while (true) {
|
||||||
const got = runtime.ipc.replyWait(supervision_endpoint, &.{}, &receive, null);
|
const got = runtime.ipc.replyWait(supervision_endpoint, &.{}, &receive, null);
|
||||||
if (runtime.process.signalsFrom(got.badge)) |signals| {
|
if (runtime.process.signalsFrom(got.badge)) |signals| {
|
||||||
@@ -117,9 +117,9 @@ pub fn main() void {
|
|||||||
_ = runtime.system.timerOnce(supervision_endpoint, 1000);
|
_ = runtime.system.timerOnce(supervision_endpoint, 1000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (got.isMessage() and got.len >= 2 and receive[0] == @intFromEnum(power.Operation.event)) {
|
if (got.isMessage() and got.len >= 2 and receive[0] == @intFromEnum(power_protocol.Operation.event)) {
|
||||||
// A power event (the only buffered messages init receives).
|
// A power event (the only buffered messages init receives).
|
||||||
if (receive[1] == @intFromEnum(power.Event.power_button)) shutDown();
|
if (receive[1] == @intFromEnum(power_protocol.Event.power_button)) shutDown();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (got.isChildExit()) {
|
if (got.isChildExit()) {
|
||||||
@@ -171,8 +171,8 @@ fn subscribePower() void {
|
|||||||
// a `terminate` signal still drives shutdown. Silent so the no-ramdisk init
|
// a `terminate` signal still drives shutdown. Silent so the no-ramdisk init
|
||||||
// test's heartbeat marker is the next line written.
|
// test's heartbeat marker is the next line written.
|
||||||
const h = handle orelse return;
|
const h = handle orelse return;
|
||||||
const request = power.Subscribe{};
|
const request = power_protocol.Subscribe{};
|
||||||
var reply: [power.message_maximum]u8 = undefined;
|
var reply: [power_protocol.message_maximum]u8 = undefined;
|
||||||
_ = runtime.ipc.callCap(h, std.mem.asBytes(&request), &reply, supervision_endpoint) catch {};
|
_ = runtime.ipc.callCap(h, std.mem.asBytes(&request), &reply, supervision_endpoint) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,8 +192,8 @@ fn shutDown() void {
|
|||||||
if (child_ids[i] != 0) runtime.process.stop(child_ids[i], 2000, supervision_endpoint);
|
if (child_ids[i] != 0) runtime.process.stop(child_ids[i], 2000, supervision_endpoint);
|
||||||
}
|
}
|
||||||
if (runtime.ipc.lookup(.power)) |h| {
|
if (runtime.ipc.lookup(.power)) |h| {
|
||||||
const request = power.Shutdown{};
|
const request = power_protocol.Shutdown{};
|
||||||
var reply: [power.message_maximum]u8 = undefined;
|
var reply: [power_protocol.message_maximum]u8 = undefined;
|
||||||
_ = runtime.ipc.call(h, std.mem.asBytes(&request), &reply) catch {};
|
_ = runtime.ipc.call(h, std.mem.asBytes(&request), &reply) catch {};
|
||||||
}
|
}
|
||||||
// If S5 did not take, init has nothing left to do but idle.
|
// If S5 did not take, init has nothing left to do but idle.
|
||||||
|
|||||||
Reference in New Issue
Block a user