Notify dispatch and GPE handlers (M21.2)
The AML interpreter now handles the Notify opcode (0x86, previously unhandled): it resolves the target device, evaluates the code, and records the pair in a bounded per-evaluate queue the caller drains with takeNotifications. A host unit test with hand-encoded AML — a method that issues Notify(DEV_, 0x80) — proves the device and code come back; aml.zig joins the zig build test loop so the interpreter is covered on the host. The acpi service's SCI handler now services general-purpose events too: for each set-and-enabled GPE bit it evaluates the \_GPE._Lxx (level) or _Exx (edge) handler method, drains the Notify queue that produced, and publishes a domain event per notified device — PNP0C0A battery, ACPI0003 AC, PNP0C0D lid, else generic notify — then clears the status bit and acks. The embedded controller's _Qxx queries are out of scope (hardware track). QEMU raises no GPEs on this config, so the QEMU suite is the regression net (the power button still works with GPE servicing in the path); correctness is the unit test. Suite 59/59.
This commit is contained in:
@@ -30,19 +30,19 @@ fn writeLine(comptime fmt: []const u8, arguments: anytype) void {
|
||||
/// attaches, or null if nothing was spawned.
|
||||
fn spawnIdentifiedDriver(controller: ps2.Controller, port: ps2.Port) ?ps2.DeviceType {
|
||||
const device_type = controller.identifyDevice(port) orelse {
|
||||
writeLine("system/drivers/ps2-bus: identify timed out on port {s}\n", .{@tagName(port)});
|
||||
writeLine("/system/drivers/ps2-bus: identify timed out on port {s}\n", .{@tagName(port)});
|
||||
return null;
|
||||
};
|
||||
const driver_name = device_type.driverName() orelse {
|
||||
writeLine("system/drivers/ps2-bus: unrecognized device on port {s}\n", .{@tagName(port)});
|
||||
writeLine("/system/drivers/ps2-bus: unrecognized device on port {s}\n", .{@tagName(port)});
|
||||
return null;
|
||||
};
|
||||
const hid = device_type.hid() orelse "";
|
||||
if (runtime.system.spawnWithArguments(driver_name, &.{hid}) != null) {
|
||||
writeLine("system/drivers/ps2-bus: port {s} is a {s}, spawned {s}\n", .{ @tagName(port), hid, driver_name });
|
||||
writeLine("/system/drivers/ps2-bus: port {s} is a {s}, spawned {s}\n", .{ @tagName(port), hid, driver_name });
|
||||
return device_type;
|
||||
}
|
||||
writeLine("system/drivers/ps2-bus: failed to spawn {s}\n", .{driver_name});
|
||||
writeLine("/system/drivers/ps2-bus: failed to spawn {s}\n", .{driver_name});
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ fn handleAttach(message: []const u8, got: ipc.Received, out: []u8) usize {
|
||||
const device_type = maybe_type orelse continue;
|
||||
if (@intFromEnum(device_type) != request.device_type) continue;
|
||||
port_endpoints[port_index] = endpoint;
|
||||
writeLine("system/drivers/ps2-bus: {s} driver attached\n", .{@tagName(device_type)});
|
||||
writeLine("/system/drivers/ps2-bus: {s} driver attached\n", .{@tagName(device_type)});
|
||||
return reply.write(out, .ok);
|
||||
}
|
||||
return reply.write(out, .no_such_device);
|
||||
@@ -91,7 +91,7 @@ fn handleAttach(message: []const u8, got: ipc.Received, out: []u8) usize {
|
||||
|
||||
pub fn main() void {
|
||||
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: out of memory\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: out of memory\n");
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -103,16 +103,16 @@ pub fn main() void {
|
||||
// is on which port is decided later by identify, not by this HID.
|
||||
const maybe_controller_device_descriptor = device.findDeviceDescriptorByHid(buffer, acpi_ids.HardwareId.ps2_keyboard.hid());
|
||||
if (maybe_controller_device_descriptor) |controller_device_descriptor| {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: found PS/2 controller\n");
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: initializing controller\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: found PS/2 controller\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: initializing controller\n");
|
||||
|
||||
if (!device.claim(controller_device_descriptor.id)) {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: unable to claim controller \n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: unable to claim controller \n");
|
||||
return;
|
||||
}
|
||||
|
||||
const controller = ps2.Controller.init(controller_device_descriptor) orelse {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: controller is missing its IO ports\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: controller is missing its IO ports\n");
|
||||
return;
|
||||
};
|
||||
maybe_controller = controller;
|
||||
@@ -123,7 +123,7 @@ pub fn main() void {
|
||||
controller.flushOutputBuffer();
|
||||
|
||||
const current = controller.readConfigurationByte() orelse {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: controller configuration timed out\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: controller configuration timed out\n");
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -132,49 +132,49 @@ pub fn main() void {
|
||||
ps2.configuration_first_port_translation);
|
||||
|
||||
if (controller.writeConfigurationByte(update) == null) {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: controller configuration timed out\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: controller configuration timed out\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (controller.performSelfTest()) |reply| {
|
||||
if (reply != ps2.response_controller_test_passed) {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: perform controller self test failed\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: perform controller self test failed\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: controller self test timed out\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: controller self test timed out\n");
|
||||
return;
|
||||
}
|
||||
|
||||
has_two_channels = controller.hasTwoChannels() orelse {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: controller channels timed out\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: controller channels timed out\n");
|
||||
return;
|
||||
};
|
||||
|
||||
if (has_two_channels) {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: has two channels\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: has two channels\n");
|
||||
// keep the bus quiet until we have tested the ports and are ready to use them
|
||||
controller.disablePort(.two);
|
||||
} else {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: has one channel\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: has one channel\n");
|
||||
}
|
||||
|
||||
// interface tests: always test port 1, test port 2 only if it exists
|
||||
const port_one_works = (controller.testPort(.one) orelse {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: port 1 test timed out\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: port 1 test timed out\n");
|
||||
return;
|
||||
}) == ps2.response_port_test_passed;
|
||||
|
||||
var port_two_works = false;
|
||||
if (has_two_channels) {
|
||||
port_two_works = (controller.testPort(.two) orelse {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: port 2 test timed out\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: port 2 test timed out\n");
|
||||
return;
|
||||
}) == ps2.response_port_test_passed;
|
||||
}
|
||||
|
||||
if (!port_one_works and !port_two_works) {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: no usable ports\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: no usable ports\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -188,16 +188,16 @@ pub fn main() void {
|
||||
// abort bring-up of the other one
|
||||
if (port_one_works) {
|
||||
if (controller.resetDevice(.one)) |passed| {
|
||||
if (!passed) _ = runtime.system.write("system/drivers/ps2-bus: port 1 device reset failed\n");
|
||||
if (!passed) _ = runtime.system.write("/system/drivers/ps2-bus: port 1 device reset failed\n");
|
||||
} else {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: port 1 device reset timed out\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: port 1 device reset timed out\n");
|
||||
}
|
||||
}
|
||||
if (port_two_works) {
|
||||
if (controller.resetDevice(.two)) |passed| {
|
||||
if (!passed) _ = runtime.system.write("system/drivers/ps2-bus: port 2 device reset failed\n");
|
||||
if (!passed) _ = runtime.system.write("/system/drivers/ps2-bus: port 2 device reset failed\n");
|
||||
} else {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: port 2 device reset timed out\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: port 2 device reset timed out\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,13 +207,13 @@ pub fn main() void {
|
||||
if (port_one_works) port_device_types[@intFromEnum(ps2.Port.one)] = spawnIdentifiedDriver(controller, .one);
|
||||
if (port_two_works) port_device_types[@intFromEnum(ps2.Port.two)] = spawnIdentifiedDriver(controller, .two);
|
||||
} else {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: no PS/2 controller found\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: no PS/2 controller found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const controller = maybe_controller.?;
|
||||
const interrupt_index = maybe_interrupt_index orelse {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: controller is missing its IRQ\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: controller is missing its IRQ\n");
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -221,11 +221,11 @@ pub fn main() void {
|
||||
// well-known id so the children can find it, the way input subscribers find
|
||||
// the input service.
|
||||
const endpoint = ipc.createIpcEndpoint() orelse {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: no endpoint\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: no endpoint\n");
|
||||
return;
|
||||
};
|
||||
if (!ipc.register(.ps2_bus, endpoint)) {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: register failed\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: register failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ pub fn main() void {
|
||||
// let the controller raise them — an interrupt with nobody bound is lost.
|
||||
controller.drainOutputBuffer();
|
||||
if (!device.irqBind(controller.device_id, interrupt_index, endpoint)) {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: irq_bind failed\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: irq_bind failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -253,21 +253,21 @@ pub fn main() void {
|
||||
.gsi = descriptor.resources[auxiliary_index].start,
|
||||
};
|
||||
} else {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: auxiliary irq_bind failed\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: auxiliary irq_bind failed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var configuration = controller.readConfigurationByte() orelse {
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: controller configuration timed out\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: controller configuration timed out\n");
|
||||
return;
|
||||
};
|
||||
if (port_device_types[@intFromEnum(ps2.Port.one)] != null) configuration |= ps2.Port.one.interruptBit();
|
||||
if (maybe_auxiliary_interrupt != null) configuration |= ps2.Port.two.interruptBit();
|
||||
_ = controller.writeConfigurationByte(configuration);
|
||||
|
||||
_ = runtime.system.write("system/drivers/ps2-bus: ok\n");
|
||||
_ = runtime.system.write("/system/drivers/ps2-bus: ok\n");
|
||||
|
||||
// The forwarding loop: an IRQ1 notification drains the output buffer, routing
|
||||
// each byte to the attached driver of the port it came from; a client message
|
||||
|
||||
Reference in New Issue
Block a user