WIP: ps2 bus driver
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -162,6 +162,7 @@ fn system_call(state: *architecture.CpuState) void {
|
||||
.msi_bind => systemMsiBind(state),
|
||||
.io_read => systemIoRead(state),
|
||||
.io_write => systemIoWrite(state),
|
||||
.clock => systemClock(state),
|
||||
_ => fail(state),
|
||||
}
|
||||
}
|
||||
@@ -316,6 +317,15 @@ fn systemIoWrite(state: *architecture.CpuState) void {
|
||||
architecture.setSystemCallResult(state, 0);
|
||||
}
|
||||
|
||||
/// clock() -> nanoseconds since boot: a monotonic time source. The kernel already owns
|
||||
/// the scheduling timer and computes this for preemption, so surfacing it is pure
|
||||
/// mechanism — no policy (wall-clock time, calendars, timezones are a user-space
|
||||
/// service layered on top). It lets a driver bound a poll loop by real time instead of
|
||||
/// a spin count, and time short delays.
|
||||
fn systemClock(state: *architecture.CpuState) void {
|
||||
architecture.setSystemCallResult(state, architecture.nanos());
|
||||
}
|
||||
|
||||
/// dma_alloc(len, flags) -> vaddr (rax), paddr (rdx): grant `len` bytes (rounded up to
|
||||
/// whole pages) of DMA-capable memory — physically contiguous, zeroed, pinned, and
|
||||
/// strong-uncacheable (coherent) — mapping it into the caller's DMA arena and handing
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
//! kernel still auto-spawns the whole initial-ramdisk at boot; increment 3 removes
|
||||
//! that redundancy so the manager is the sole owner of driver spawning.)
|
||||
|
||||
const std = @import("std");
|
||||
const runtime = @import("runtime");
|
||||
const device = runtime.device;
|
||||
|
||||
@@ -20,8 +21,13 @@ const device = runtime.device;
|
||||
/// this comes from the drivers describing what they bind (or a manifest under
|
||||
/// /system/drivers); for now it is a small static map, which is enough to prove the
|
||||
/// manager reads the tree and decides. `null` = no driver for this class yet.
|
||||
fn driverFor(class: u64) ?[]const u8 {
|
||||
if (class == @intFromEnum(device.DeviceClass.timer)) return "hpet"; // the HPET
|
||||
fn driverFor(d: device.DeviceDescriptor) ?[]const u8 {
|
||||
// detect device via DeviceClass
|
||||
if (d.class == @intFromEnum(device.DeviceClass.timer)) return "hpet";
|
||||
// detect device via hid
|
||||
const hid = d.hid[0..@intCast(d.hid_len)];
|
||||
if (std.mem.eql(u8, hid, "PNP0303") or std.mem.eql(u8, hid, "PNP0F13")) return "ps2-bus";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -34,10 +40,9 @@ pub fn main() void {
|
||||
const total = device.enumerate(buffer);
|
||||
const count = @min(total, buffer.len);
|
||||
|
||||
var matched: usize = 0;
|
||||
for (buffer[0..count]) |descriptor| {
|
||||
const driver_name = driverFor(descriptor.class) orelse continue;
|
||||
matched += 1;
|
||||
const driver_name = driverFor(descriptor) orelse continue;
|
||||
|
||||
if (runtime.system.spawn(driver_name)) {
|
||||
_ = runtime.system.write("device-manager: spawned ");
|
||||
_ = runtime.system.write(driver_name);
|
||||
@@ -49,10 +54,6 @@ pub fn main() void {
|
||||
}
|
||||
}
|
||||
|
||||
if (matched == 0) {
|
||||
_ = runtime.system.write("device-manager: no matchable devices\n");
|
||||
return;
|
||||
}
|
||||
_ = runtime.system.write("device-manager: ok\n");
|
||||
while (true) runtime.system.sleep(1000);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user