Add keyboard and an x86 driver

This commit is contained in:
Sam Tebbs 2020-07-14 21:52:54 +01:00
parent b8a47d6e08
commit 73d0b2fd3d
6 changed files with 780 additions and 0 deletions

View file

@ -17,9 +17,11 @@ const vga = @import("vga.zig");
const mem = @import("../../mem.zig");
const multiboot = @import("multiboot.zig");
const vmm = @import("../../vmm.zig");
const keyboard = @import("keyboard.zig");
const Serial = @import("../../serial.zig").Serial;
const panic = @import("../../panic.zig").panic;
const TTY = @import("../../tty.zig").TTY;
const Keyboard = @import("../../keyboard.zig").Keyboard;
const MemProfile = mem.MemProfile;
/// The virtual end of the kernel code.
@ -449,6 +451,23 @@ pub fn initMem(mb_info: BootPayload) Allocator.Error!MemProfile {
};
}
///
/// Initialise the keyboard that may depend on the chipset or architecture in general.
/// x86 initialises the keyboard connected to the PS/2 port
///
/// Arguments:
/// IN allocator: *std.mem.Allocator - The allocator to use if necessary
///
/// Return: *Keyboard
/// The initialised PS/2 keyboard
///
/// Error: std.mem.Allocator.Error
/// OutOfMemory - There wasn't enough memory to allocate what was needed
///
pub fn initKeyboard(allocator: *Allocator) Allocator.Error!*Keyboard {
return keyboard.init(allocator);
}
///
/// Initialise a 32bit kernel stack used for creating a task.
/// Currently only support fn () noreturn functions for the entry point.

View file

@ -0,0 +1,369 @@
const builtin = @import("builtin");
const build_options = @import("build_options");
const std = @import("std");
const Allocator = std.mem.Allocator;
const testing = std.testing;
const irq = @import("irq.zig");
const pic = @import("pic.zig");
const arch = if (builtin.is_test) @import(build_options.arch_mock_path ++ "arch_mock.zig") else @import("arch.zig");
const log = if (builtin.is_test) @import(build_options.arch_mock_path ++ "log_mock.zig") else @import("../../log.zig");
const panic = @import("../../panic.zig").panic;
const kb = @import("../../keyboard.zig");
const Keyboard = kb.Keyboard;
const KeyPosition = kb.KeyPosition;
const KeyAction = kb.KeyAction;
/// The initialised keyboard
var keyboard: *Keyboard = undefined;
/// The number of keys pressed without a corresponding release
var pressed_keys: usize = 0;
/// If we're in the middle of a special key sequence (e.g. print_screen and arrow keys)
var special_sequence = false;
/// The number of release scan codes expected before registering a release event
/// This is used in special sequences since they end in a certain number of release scan codes
var expected_releases: usize = 0;
/// If a print_screen press is being processed
var on_print_screen = false;
///
/// Read a byte from the keyboard buffer
///
/// Return: u8
/// The byte waiting in the keyboard buffer
///
fn readKeyboardBuffer() u8 {
return arch.inb(0x60);
}
///
/// Parse a keyboard scan code and return the associated keyboard action.
/// Some keys require a specific sequence of scan codes so this function acts as a state machine
///
/// Arguments:
/// IN scan_code: u8 - The scan code from the keyboard
///
/// Return: ?KeyAction
/// The keyboard action resulting from processing the scan code, or null if the scan code doesn't result in a finished keyboard action
///
fn parseScanCode(scan_code: u8) ?KeyAction {
var released = false;
// The print screen key requires special processing since it uses a unique byte sequence
if (on_print_screen or scan_code >= 128) {
released = true;
if (special_sequence or on_print_screen) {
// Special sequences are followed by a certain number of release scan codes that should be ignored. Update the expected number
if (expected_releases >= 1) {
expected_releases -= 1;
return null;
}
} else {
if (pressed_keys == 0) {
// A special sequence is started by a lone key release scan code
special_sequence = true;
return null;
}
}
}
// Cut off the top bit, which denotes that the key was released
const key_code = @truncate(u7, scan_code);
var key_pos: ?KeyPosition = null;
if (special_sequence or on_print_screen) {
if (!released) {
// Most special sequences are followed by an extra key release byte
expected_releases = 1;
}
switch (key_code) {
72 => key_pos = KeyPosition.UP_ARROW,
75 => key_pos = KeyPosition.LEFT_ARROW,
77 => key_pos = KeyPosition.RIGHT_ARROW,
80 => key_pos = KeyPosition.DOWN_ARROW,
// First byte sent for the pause key
29 => return null,
42 => {
// The print screen key is followed by five extra key release bytes
key_pos = KeyPosition.PRINT_SCREEN;
if (!released) {
on_print_screen = true;
expected_releases = 5;
}
},
// Second and final byte sent for the pause key
69 => {
// The pause key is followed by two extra key release bytes
key_pos = KeyPosition.PAUSE;
if (!released) {
expected_releases = 2;
}
},
82 => key_pos = KeyPosition.INSERT,
71 => key_pos = KeyPosition.HOME,
73 => key_pos = KeyPosition.PAGE_UP,
83 => key_pos = KeyPosition.DELETE,
79 => key_pos = KeyPosition.END,
81 => key_pos = KeyPosition.PAGE_DOWN,
53 => key_pos = KeyPosition.KEYPAD_SLASH,
28 => key_pos = KeyPosition.KEYPAD_ENTER,
56 => key_pos = KeyPosition.RIGHT_ALT,
91 => key_pos = KeyPosition.SPECIAL,
else => return null,
}
}
key_pos = key_pos orelse switch (key_code) {
1 => KeyPosition.ESC,
// Number keys and second row
2...28 => @intToEnum(KeyPosition, @enumToInt(KeyPosition.ONE) + (key_code - 2)),
29 => KeyPosition.LEFT_CTRL,
30...40 => @intToEnum(KeyPosition, @enumToInt(KeyPosition.A) + (key_code - 30)),
41 => KeyPosition.BACKTICK,
42 => KeyPosition.LEFT_SHIFT,
43 => KeyPosition.HASH,
44...54 => @intToEnum(KeyPosition, @enumToInt(KeyPosition.Z) + (key_code - 44)),
55 => KeyPosition.KEYPAD_ASTERISK,
56 => KeyPosition.LEFT_ALT,
57 => KeyPosition.SPACE,
58 => KeyPosition.CAPS_LOCK,
59...68 => @intToEnum(KeyPosition, @enumToInt(KeyPosition.F1) + (key_code - 59)),
69 => KeyPosition.NUM_LOCK,
70 => KeyPosition.SCROLL_LOCK,
71...73 => @intToEnum(KeyPosition, @enumToInt(KeyPosition.KEYPAD_7) + (key_code - 71)),
74 => KeyPosition.KEYPAD_MINUS,
75...77 => @intToEnum(KeyPosition, @enumToInt(KeyPosition.KEYPAD_4) + (key_code - 75)),
78 => KeyPosition.KEYPAD_PLUS,
79...81 => @intToEnum(KeyPosition, @enumToInt(KeyPosition.KEYPAD_1) + (key_code - 79)),
82 => KeyPosition.KEYPAD_0,
83 => KeyPosition.KEYPAD_DOT,
86 => KeyPosition.BACKSLASH,
87 => KeyPosition.F11,
88 => KeyPosition.F12,
else => null,
};
if (key_pos) |k| {
// If we're releasing a key decrement the number of keys pressed, else increment it
if (!released) {
pressed_keys += 1;
} else {
pressed_keys -= 1;
// Releasing a special key means we are no longer on that special key
special_sequence = false;
}
return KeyAction{ .position = k, .released = released };
}
return null;
}
///
/// Register a keyboard action. Should only be called in response to a keyboard IRQ
///
/// Arguments:
/// IN ctx: *arch.CpuState - The state of the CPU when the keyboard action occurred
///
/// Return: usize
/// The stack pointer value to use when returning from the interrupt
///
fn onKeyEvent(ctx: *arch.CpuState) usize {
const scan_code = readKeyboardBuffer();
if (parseScanCode(scan_code)) |action| {
if (!keyboard.writeKey(action)) {
std.log.notice(.x86_keyboard, "No room for keyboard action {}\n", .{action});
}
}
return @ptrToInt(ctx);
}
///
/// Initialise the PS/2 keyboard
///
/// Arguments:
/// IN allocator: *Allocator - The allocator to use to create the keyboard instance
///
/// Return: *Keyboard
/// The keyboard created
///
/// Error: std.mem.Allocator.Error
/// OutOfMemory - There isn't enough memory to allocate the keyboard instance
///
pub fn init(allocator: *Allocator) Allocator.Error!*Keyboard {
irq.registerIrq(pic.IRQ_KEYBOARD, onKeyEvent) catch |e| {
panic(@errorReturnTrace(), "Failed to register keyboard IRQ: {}\n", .{e});
};
keyboard = try allocator.create(Keyboard);
keyboard.* = Keyboard.init();
return keyboard;
}
fn testResetGlobals() void {
pressed_keys = 0;
special_sequence = false;
expected_releases = 0;
on_print_screen = false;
}
test "parseScanCode" {
testResetGlobals();
// Test basic keys
const basic_keys = &[_]?KeyPosition{
KeyPosition.ESC,
KeyPosition.ONE,
KeyPosition.TWO,
KeyPosition.THREE,
KeyPosition.FOUR,
KeyPosition.FIVE,
KeyPosition.SIX,
KeyPosition.SEVEN,
KeyPosition.EIGHT,
KeyPosition.NINE,
KeyPosition.ZERO,
KeyPosition.HYPHEN,
KeyPosition.EQUALS,
KeyPosition.BACKSPACE,
KeyPosition.TAB,
KeyPosition.Q,
KeyPosition.W,
KeyPosition.E,
KeyPosition.R,
KeyPosition.T,
KeyPosition.Y,
KeyPosition.U,
KeyPosition.I,
KeyPosition.O,
KeyPosition.P,
KeyPosition.LEFT_BRACKET,
KeyPosition.RIGHT_BRACKET,
KeyPosition.ENTER,
KeyPosition.LEFT_CTRL,
KeyPosition.A,
KeyPosition.S,
KeyPosition.D,
KeyPosition.F,
KeyPosition.G,
KeyPosition.H,
KeyPosition.J,
KeyPosition.K,
KeyPosition.L,
KeyPosition.SEMICOLON,
KeyPosition.APOSTROPHE,
KeyPosition.BACKTICK,
KeyPosition.LEFT_SHIFT,
KeyPosition.HASH,
KeyPosition.Z,
KeyPosition.X,
KeyPosition.C,
KeyPosition.V,
KeyPosition.B,
KeyPosition.N,
KeyPosition.M,
KeyPosition.COMMA,
KeyPosition.DOT,
KeyPosition.FORWARD_SLASH,
KeyPosition.RIGHT_SHIFT,
KeyPosition.KEYPAD_ASTERISK,
KeyPosition.LEFT_ALT,
KeyPosition.SPACE,
KeyPosition.CAPS_LOCK,
KeyPosition.F1,
KeyPosition.F2,
KeyPosition.F3,
KeyPosition.F4,
KeyPosition.F5,
KeyPosition.F6,
KeyPosition.F7,
KeyPosition.F8,
KeyPosition.F9,
KeyPosition.F10,
KeyPosition.NUM_LOCK,
KeyPosition.SCROLL_LOCK,
KeyPosition.KEYPAD_7,
KeyPosition.KEYPAD_8,
KeyPosition.KEYPAD_9,
KeyPosition.KEYPAD_MINUS,
KeyPosition.KEYPAD_4,
KeyPosition.KEYPAD_5,
KeyPosition.KEYPAD_6,
KeyPosition.KEYPAD_PLUS,
KeyPosition.KEYPAD_1,
KeyPosition.KEYPAD_2,
KeyPosition.KEYPAD_3,
KeyPosition.KEYPAD_0,
KeyPosition.KEYPAD_DOT,
null,
null,
KeyPosition.BACKSLASH,
KeyPosition.F11,
KeyPosition.F12,
};
comptime var scan_code = 1;
inline for (basic_keys) |key| {
var res = parseScanCode(scan_code);
if (key) |k| {
const r = res orelse unreachable;
testing.expectEqual(k, r.position);
testing.expectEqual(false, r.released);
testing.expectEqual(pressed_keys, 1);
}
testing.expectEqual(on_print_screen, false);
testing.expectEqual(special_sequence, false);
testing.expectEqual(expected_releases, 0);
// Test release scan code for key
if (key) |k| {
res = parseScanCode(scan_code | 128);
const r = res orelse unreachable;
testing.expectEqual(k, r.position);
testing.expectEqual(true, r.released);
testing.expectEqual(pressed_keys, 0);
testing.expectEqual(on_print_screen, false);
testing.expectEqual(special_sequence, false);
testing.expectEqual(expected_releases, 0);
}
scan_code += 1;
}
// Test the special keys
// 'simple' sepcial keys consist of one release byte, a key then an extra release byte
const simple_special_keys = &[_]?KeyPosition{
KeyPosition.UP_ARROW,
KeyPosition.LEFT_ARROW,
KeyPosition.RIGHT_ARROW,
KeyPosition.DOWN_ARROW,
KeyPosition.INSERT,
KeyPosition.HOME,
KeyPosition.PAGE_UP,
KeyPosition.DELETE,
KeyPosition.END,
KeyPosition.PAGE_DOWN,
KeyPosition.KEYPAD_SLASH,
KeyPosition.KEYPAD_ENTER,
KeyPosition.RIGHT_ALT,
KeyPosition.SPECIAL,
};
const simple_special_codes = &[_]u8{ 72, 75, 77, 80, 82, 71, 73, 83, 79, 81, 53, 28, 56, 91 };
for (simple_special_keys) |key, i| {
testing.expectEqual(parseScanCode(128), null);
testing.expectEqual(pressed_keys, 0);
testing.expectEqual(on_print_screen, false);
testing.expectEqual(special_sequence, true);
testing.expectEqual(expected_releases, 0);
var res = parseScanCode(simple_special_codes[i]) orelse unreachable;
testing.expectEqual(false, res.released);
testing.expectEqual(key, res.position);
testing.expectEqual(pressed_keys, 1);
testing.expectEqual(on_print_screen, false);
testing.expectEqual(special_sequence, true);
testing.expectEqual(expected_releases, 1);
testing.expectEqual(parseScanCode(128), null);
testing.expectEqual(pressed_keys, 1);
testing.expectEqual(on_print_screen, false);
testing.expectEqual(special_sequence, true);
testing.expectEqual(expected_releases, 0);
res = parseScanCode(simple_special_codes[i] | 128) orelse unreachable;
testing.expectEqual(true, res.released);
testing.expectEqual(key, res.position);
testing.expectEqual(pressed_keys, 0);
testing.expectEqual(on_print_screen, false);
testing.expectEqual(special_sequence, false);
testing.expectEqual(expected_releases, 0);
}
}

View file

@ -543,6 +543,7 @@ const FreeListAllocator = struct {
}
test "resize" {
std.debug.warn("", .{});
const size = 1024;
var region = try testing.allocator.alloc(u8, size);
defer testing.allocator.free(region);

354
src/kernel/keyboard.zig Normal file
View file

@ -0,0 +1,354 @@
const std = @import("std");
const testing = std.testing;
const ArrayList = std.ArrayList;
const Allocator = std.mem.Allocator;
const arch = @import("arch.zig").internals;
/// An arbitrary number of keys to remember before dropping any more that arrive. Is a power of two so we can use nice overflowing addition
pub const QUEUE_SIZE = 32;
/// The position of a key on a keyboard using the qwerty layout. This does not determine the key pressed, just the position on the keyboard.
pub const KeyPosition = enum(u7) {
ESC,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
PRINT_SCREEN,
SCROLL_LOCK,
PAUSE,
BACKTICK,
ONE,
TWO,
THREE,
FOUR,
FIVE,
SIX,
SEVEN,
EIGHT,
NINE,
ZERO,
HYPHEN,
EQUALS,
BACKSPACE,
TAB,
Q,
W,
E,
R,
T,
Y,
U,
I,
O,
P,
LEFT_BRACKET,
RIGHT_BRACKET,
ENTER,
CAPS_LOCK,
A,
S,
D,
F,
G,
H,
J,
K,
L,
SEMICOLON,
APOSTROPHE,
HASH,
LEFT_SHIFT,
BACKSLASH,
Z,
X,
C,
V,
B,
N,
M,
COMMA,
DOT,
FORWARD_SLASH,
RIGHT_SHIFT,
LEFT_CTRL,
SPECIAL,
LEFT_ALT,
SPACE,
RIGHT_ALT,
FN,
SPECIAL2,
RIGHT_CTRL,
INSERT,
HOME,
PAGE_UP,
DELETE,
END,
PAGE_DOWN,
LEFT_ARROW,
UP_ARROW,
DOWN_ARROW,
RIGHT_ARROW,
NUM_LOCK,
KEYPAD_SLASH,
KEYPAD_ASTERISK,
KEYPAD_MINUS,
KEYPAD_7,
KEYPAD_8,
KEYPAD_9,
KEYPAD_PLUS,
KEYPAD_4,
KEYPAD_5,
KEYPAD_6,
KEYPAD_1,
KEYPAD_2,
KEYPAD_3,
KEYPAD_ENTER,
KEYPAD_0,
KEYPAD_DOT,
};
/// A keyboard action, either a press or release
pub const KeyAction = struct {
/// The position of the key
position: KeyPosition,
/// Whether it was a release or press
released: bool,
};
/// The type used to index the keyboard queue
const QueueIndex = std.meta.IntType(false, std.math.log2(QUEUE_SIZE));
/// A keyboard buffer that stores keyboard actions. This corresponds to a single hardware keyboard
pub const Keyboard = struct {
/// A circular queue storing key presses until full
queue: [QUEUE_SIZE]KeyAction,
/// The front of the queue i.e. the next item to be dequeued
queue_front: QueueIndex,
/// The end of the queue i.e. where the next item is enqueued
queue_end: QueueIndex,
///
/// Initialise a keyboard with an empty key buffer
///
/// Return: Keyboard
/// They keyboard created
///
pub fn init() Keyboard {
return .{
.queue = [_]KeyAction{undefined} ** QUEUE_SIZE,
.queue_front = 0,
.queue_end = 0,
};
}
///
/// Check if the keyboard queue is empty
///
/// Arguments:
/// self: *const Keyboard - The keyboard to check
///
/// Return: bool
/// True if the keyboard queue is empty, else false
///
pub fn isEmpty(self: *const Keyboard) bool {
return self.queue_end == self.queue_front;
}
///
/// Check if the keyboard queue is full
///
/// Arguments:
/// self: *const Keyboard - The keyboard to check
///
/// Return: bool
/// True if the keyboard queue is full, else false
///
pub fn isFull(self: *const Keyboard) bool {
var end_plus_one: QueueIndex = undefined;
// This is a circular queue so overflow is allowed
_ = @addWithOverflow(QueueIndex, self.queue_end, 1, &end_plus_one);
return end_plus_one == self.queue_front;
}
///
/// Add a keyboard action to the keyboard's queue
///
/// Arguments:
/// self: *Keyboard - The keyboard whose queue it should be added to
/// key: KeyAction - The action to add
///
/// Return: bool
/// True if there was room for the key, else false
///
pub fn writeKey(self: *Keyboard, key: KeyAction) bool {
if (!self.isFull()) {
self.queue[self.queue_end] = key;
_ = @addWithOverflow(QueueIndex, self.queue_end, 1, &self.queue_end);
return true;
}
return false;
}
///
/// Read and remove the next key from the keyboard's queue
///
/// Arguments:
/// self: *Keyboard - The keyboard to get and remove the key from
///
/// Return: ?KeyAction
/// The first keyboard action in the queue, else null if there were none
///
pub fn readKey(self: *Keyboard) ?KeyAction {
if (self.isEmpty()) return null;
const key = self.queue[self.queue_front];
_ = @addWithOverflow(QueueIndex, self.queue_front, 1, &self.queue_front);
return key;
}
test "init" {
const keyboard = Keyboard.init();
testing.expectEqual(keyboard.queue_front, 0);
testing.expectEqual(keyboard.queue_end, 0);
}
test "isEmpty" {
var keyboard = Keyboard.init();
testing.expect(keyboard.isEmpty());
keyboard.queue_end += 1;
testing.expect(!keyboard.isEmpty());
keyboard.queue_front += 1;
testing.expect(keyboard.isEmpty());
keyboard.queue_end = std.math.maxInt(QueueIndex);
keyboard.queue_front = 0;
testing.expect(!keyboard.isEmpty());
keyboard.queue_front = std.math.maxInt(QueueIndex);
testing.expect(keyboard.isEmpty());
}
test "isFull" {
var keyboard = Keyboard.init();
testing.expect(!keyboard.isFull());
keyboard.queue_end += 1;
testing.expect(!keyboard.isFull());
keyboard.queue_front += 1;
testing.expect(!keyboard.isFull());
keyboard.queue_end = 0;
testing.expect(keyboard.isFull());
keyboard.queue_front = 0;
keyboard.queue_end = std.math.maxInt(QueueIndex);
testing.expect(keyboard.isFull());
}
test "writeKey" {
var keyboard = Keyboard.init();
comptime var i = 0;
inline while (i < QUEUE_SIZE - 1) : (i += 1) {
testing.expectEqual(keyboard.writeKey(.{
.position = @intToEnum(KeyPosition, i),
.released = false,
}), true);
testing.expectEqual(keyboard.queue[i].position, @intToEnum(KeyPosition, i));
testing.expectEqual(keyboard.queue_end, i + 1);
testing.expectEqual(keyboard.queue_front, 0);
}
testing.expectEqual(keyboard.writeKey(.{
.position = @intToEnum(KeyPosition, 33),
.released = false,
}), false);
testing.expect(keyboard.isFull());
}
test "readKey" {
var keyboard = Keyboard.init();
comptime var i = 0;
inline while (i < QUEUE_SIZE - 1) : (i += 1) {
testing.expectEqual(keyboard.writeKey(.{
.position = @intToEnum(KeyPosition, i),
.released = false,
}), true);
}
i = 0;
inline while (i < QUEUE_SIZE - 1) : (i += 1) {
testing.expectEqual(keyboard.readKey().?.position, @intToEnum(KeyPosition, i));
testing.expectEqual(keyboard.queue_end, QUEUE_SIZE - 1);
testing.expectEqual(keyboard.queue_front, i + 1);
}
testing.expect(keyboard.isEmpty());
testing.expectEqual(keyboard.readKey(), null);
}
};
/// The registered keyboards
var keyboards: ArrayList(*Keyboard) = undefined;
///
/// Get the keyboard associated with an ID
///
/// Arguments:
/// id: usize - The ID of the keyboard to get
///
/// Return: ?*Keyboard
/// The keyboard associated with the ID, or null if there isn't one
///
pub fn getKeyboard(id: usize) ?*Keyboard {
if (keyboards.items.len <= id) {
return null;
}
return keyboards.items[id];
}
///
/// Add a keyboard to list of known keyboards
///
/// Arguments:
/// kb: *Keyboard - The keyboard to add
///
/// Error: std.mem.Allocator.Error
/// OutOfMemory - Adding the keyboard to the list failed due to there not being enough memory free
///
pub fn addKeyboard(kb: *Keyboard) Allocator.Error!void {
try keyboards.append(kb);
}
///
/// Initialise the keyboard system and the architecture's keyboard
///
/// Arguments:
/// allocator: *std.mem.Allocator - The allocator to initialise the keyboard list and architecture keyboard with
///
/// Return: ?*Keyboard
/// The architecture keyboard found, else null if one wasn't detected
///
/// Error: std.mem.Allocator.Error
/// OutOfMemory - There wasn't enough memory to initialise the keyboard list or the architecture keyboard
///
pub fn init(allocator: *Allocator) Allocator.Error!?*Keyboard {
keyboards = ArrayList(*Keyboard).init(allocator);
return arch.initKeyboard(allocator);
}
test "" {
_ = Keyboard.init();
}

View file

@ -17,6 +17,7 @@ const heap = @import("heap.zig");
const scheduler = @import("scheduler.zig");
const vfs = @import("filesystem/vfs.zig");
const initrd = @import("filesystem/initrd.zig");
const keyboard = @import("keyboard.zig");
comptime {
if (!is_test) {
@ -92,6 +93,12 @@ export fn kmain(boot_payload: arch.BootPayload) void {
};
tty.init(&kernel_heap.allocator, boot_payload);
var arch_kb = keyboard.init(&fixed_allocator.allocator) catch |e| {
panic_root.panic(@errorReturnTrace(), "Failed to inititalise keyboard: {}\n", .{e});
};
if (arch_kb) |kb| {
keyboard.addKeyboard(kb) catch |e| panic_root.panic(@errorReturnTrace(), "Failed to add architecture keyboard: {}\n", .{e});
}
scheduler.init(&kernel_heap.allocator) catch |e| {
panic_root.panic(@errorReturnTrace(), "Failed to initialise scheduler: {}\n", .{e});
@ -171,6 +178,31 @@ fn initStage2() noreturn {
else => {},
}
const kb = keyboard.getKeyboard(0) orelse unreachable;
var shift = false;
while (true) {
if (kb.readKey()) |key| {
if (key.released) {
if (key.position == keyboard.KeyPosition.LEFT_SHIFT) {
shift = false;
}
continue;
}
var char: ?u8 = switch (key.position) {
keyboard.KeyPosition.LEFT_SHIFT, keyboard.KeyPosition.RIGHT_SHIFT => blk: {
shift = true;
break :blk null;
},
keyboard.KeyPosition.Q => if (shift) @as(u8, 'Q') else @as(u8, 'q'),
keyboard.KeyPosition.W => if (shift) @as(u8, 'W') else @as(u8, 'w'),
else => null,
};
if (char) |ch| {
tty.print("{c}", .{ch});
}
}
}
// Can't return for now, later this can return maybe
arch.spinWait();
}

View file

@ -8,6 +8,7 @@ const vmm = @import("vmm_mock.zig");
const paging = @import("paging_mock.zig");
const Serial = @import("../../../src/kernel/serial.zig").Serial;
const TTY = @import("../../../src/kernel/tty.zig").TTY;
const Keyboard = @import("../../../src/kernel/keyboard.zig").Keyboard;
pub const task = @import("task_mock.zig");
@ -142,6 +143,10 @@ pub fn initTaskStack(entry_point: usize, allocator: *Allocator) Allocator.Error!
return ret;
}
pub fn initKeyboard(allocator: *Allocator) Allocator.Error!?*Keyboard {
return null;
}
pub fn init(mem_profile: *const MemProfile) void {
// I'll get back to this as this doesn't effect the current testing.
// When I come on to the mem.zig testing, I'll fix :)