WIP: ps2 bus driver

This commit is contained in:
Daniel Samson
2026-07-11 04:19:03 +01:00
parent e499f500c3
commit b42d572d78
8 changed files with 221 additions and 16 deletions
+12
View File
@@ -0,0 +1,12 @@
//! PS/2 Keyboard Driver
const std = @import("std");
const runtime = @import("runtime");
const ps2 = @import("root.zig");
const device = runtime.device;
pub fn main() void {
// TBD
_ = runtime.system.write("system/drivers/ps2-bus/keyboard: ok\n");
while (true) runtime.system.sleep(1000);
}
+11
View File
@@ -0,0 +1,11 @@
//! PS/2 Mouse Driver
const std = @import("std");
const runtime = @import("runtime");
const ps2 = @import("root.zig");
const device = runtime.device;
pub fn main() void {
// TBD
_ = runtime.system.write("system/drivers/ps2-bus/mouse: ok\n");
while (true) runtime.system.sleep(1000);
}
+55
View File
@@ -0,0 +1,55 @@
//! The PS/2 Controller is located on the mainboard.
//! In the early days the controller was a single chip (Intel 8042).
//! As of today it is part of the Advanced Integrated Peripheral.
//!
//! It shows up in the device discovery as:
//! KBD_ [acpi_device] hid=PNP0303 (PS/2 Keyboard)
//! - io_port 0x60 len 0x1
//! - io_port 0x64 len 0x1
//! - irq 0x1 len 0x1
//! MOU_ [acpi_device] hid=PNP0F13 (PS/2 Mouse)
//! - irq 0xc len 0x1
const std = @import("std");
const runtime = @import("runtime");
const ps2 = @import("root.zig");
const device = runtime.device;
pub fn main() void {
const buffer = runtime.allocator().alloc(device.DeviceDescriptor, 64) catch {
_ = runtime.system.write("system/drivers/ps2-bus: out of memory\n");
return;
};
const keyboardDeviceDescriptor = device.findDeviceDescriptorByHid(buffer, "PNP0303");
if (keyboardDeviceDescriptor != null) {
// load keyboard driver
_ = runtime.system.write("system/drivers/ps2-bus: found keyboard DeviceDescriptor\n");
_ = runtime.system.write("system/drivers/ps2-bus: probing controller\n");
if (!device.claim(keyboardDeviceDescriptor.?.id)) {
_ = runtime.system.write("system/drivers/ps2-bus: unable to claim controller \n");
return;
}
ps2.disablePorts(keyboardDeviceDescriptor.?);
ps2.flushOutputBuffer(keyboardDeviceDescriptor.?);
} else {
_ = runtime.system.write("system/drivers/ps2-bus: no keyboard\n");
}
const mouseDeviceDescriptor = device.findDeviceDescriptorByHid(buffer, "PNP0F13");
if (mouseDeviceDescriptor != null) {
// load mouse driver
_ = runtime.system.write("system/drivers/ps2-bus: found mouse DeviceDescriptor\n");
} else {
_ = runtime.system.write("system/drivers/ps2-bus: no mouse\n");
}
_ = runtime.system.write("system/drivers/ps2-bus: ok\n");
while (true) runtime.system.sleep(1000);
}
pub const panic = runtime.panic;
comptime {
_ = &runtime.start._start;
}
+87
View File
@@ -0,0 +1,87 @@
//! shared definitions between the different PS/2 drivers
const runtime = @import("runtime");
const device = runtime.device;
/// PS-2 io ports:
/// The PS/2 Controller itself uses 2 IO ports (usually, IO ports 0x60 and 0x64). Like many IO
/// ports, reads and writes may access different internal registers.
///
/// Historical note: The PC-XT PPI had used port 0x61 to reset the keyboard interrupt request
/// signal (among other unrelated functions). Port 0x61 has no keyboard related functions on AT and
/// PS/2 compatibles.
///
/// The Data Port (typically IO Port 0x60) is used for reading data that was received from a PS/2
/// device or from the PS/2 controller itself and writing data to a PS/2 device or to the PS/2
/// controller itself.
// Access type: Read/Write
pub const dataPort = 0x60;
// Access type: Read
pub const statusRegisterPort = 0x64;
// Access type: Write
pub const CommandRegisterPort = 0x64;
const spin_limit: u32 = 5000;
fn waitWritable(id: u64, cmd_index: u64) bool {
var tries: u32 = 0;
while (tries < spin_limit) : (tries += 1) {
if (status(id, cmd_index) & 0x02 == 0) return true; // IBF clear -> ok to write
}
return false; // timed out
}
fn waitReadable(id: u64, cmd_index: u64) bool {
var tries: u32 = 0;
while (tries < spin_limit) : (tries += 1) {
if (status(id, cmd_index) & 0x01 != 0) return true; // OBF set -> data ready
}
return false;
}
fn scanResourcesIndexes(d: device.DeviceDescriptor) struct { data_port_resource_index: u64, command_or_status_resource_index: u64 } {
const resources = d.resources;
const total_resources = d.resource_count;
var data_port_resource_index: ?u64 = null;
var command_or_status_resource_index: ?u64 = null;
for (resources, 0..total_resources) |resource, resource_index| {
if (resource.kind == @intFromEnum(device.ResourceKind.io_port) and resource.start == dataPort) {
data_port_resource_index = @intCast(resource_index);
} else if (resource.kind == @intFromEnum(device.ResourceKind.io_port) and resource.start == statusRegisterPort) {
command_or_status_resource_index = @intCast(resource_index);
}
}
return .{ .data_port_resource_index = data_port_resource_index orelse 0, .command_or_status_resource_index = command_or_status_resource_index orelse 0 };
}
fn status(id: u64, cmd_index: u64) u8 {
return @intCast(device.ioRead(id, cmd_index, 0, 1) orelse 0);
}
fn sendCommand(id: u64, cmd_index: u64, byte: u8) bool {
// wait IBF clear
if (!waitWritable(id, cmd_index)) return false;
return device.ioWrite(id, cmd_index, 0, 1, byte);
}
fn readData(id: u64, data_index: u64) u8 {
// wait OBF set
if (!waitReadable(id, data_index)) return null;
return @intCast(device.ioRead(id, data_index, 0, 1) orelse 0);
}
pub fn disablePorts(d: device.DeviceDescriptor) void {
const indexes = scanResourcesIndexes(d);
// disable port 1 (keyboard)
_ = sendCommand(d.id, indexes.data_port_resource_index, 0xAD);
// disable port 2 (aux/mouse)
_ = sendCommand(d.id, indexes.command_or_status_resource_index, 0xA7);
}
pub fn flushOutputBuffer(d: device.DeviceDescriptor) void {
const indexes = scanResourcesIndexes(d);
// flush any stale byte the controller buffered
_ = device.ioRead(d.id, indexes.data_port_resource_index, 0, 1);
}