88 lines
3.3 KiB
Zig
88 lines
3.3 KiB
Zig
//! 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);
|
|
}
|