From cb8a12eed029e4aefa62a6c035f6927c84362218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Wed, 19 Jan 2022 21:22:12 +0200 Subject: [PATCH] Set up ps/2 controller --- kernel.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 2 deletions(-) diff --git a/kernel.c b/kernel.c index b8afa6f..ab9219a 100644 --- a/kernel.c +++ b/kernel.c @@ -87,6 +87,12 @@ void terminal_putentryat(char c, uint8_t color, size_t x, size_t y) void terminal_putchar(char c) { + if (c == '\n') { + terminal_row++; + terminal_column = 0; + return; + } + terminal_putentryat(c, terminal_color, terminal_column, terminal_row); if (++terminal_column == VGA_WIDTH) { terminal_column = 0; @@ -106,11 +112,133 @@ void terminal_writestring(const char* data) terminal_write(data, strlen(data)); } +// (out|in)port from sortix, Copyright (c) 2014, 2015 Jonas 'Sortie' Termansen. +void outport8(uint16_t port, uint8_t value) +{ + asm volatile ("outb %1, %0" : : "dN" (port), "a" (value)); +} + +uint8_t inport8(uint16_t port) +{ + uint8_t result; + asm volatile("inb %1, %0" : "=a" (result) : "dN" (port)); + return result; +} + +void command_8042(uint8_t command) { + outport8(0x64, command); +} + +uint8_t status_8042(void) { + return inport8(0x64); +} + +uint8_t read_8042(void) { + return inport8(0x60); +} + +void write_8042(uint8_t data) { + outport8(0x60, data); +} + +bool translation_initially; +bool single_channel = false; + +uint8_t read_config_8042(void) { + command_8042(0x20); + return read_8042(); +} + +void write_config_8042(uint8_t config) { + command_8042(0x60); + write_8042(config); +} + +void init_8042(void) { + // Disable devices + command_8042(0xad); + command_8042(0xa7); + + // Flush output buffer + while (status_8042() & (1<<0)) + (void) read_8042(); + + // Read configuration + uint8_t config = read_config_8042(); + translation_initially = config & (1<<6); + single_channel = !(config & (1<<5)); + + // Disable IRQ + config &= ~(1<<0); + config &= ~(1<<1); + command_8042(0x60); + write_8042(config); + + // Self test + terminal_writestring("8042 self-test... "); + command_8042(0xaa); + while (!(status_8042() & (1<<0))); + if (read_8042() != 0x55) + terminal_writestring("failed\n"); + else + terminal_writestring("ok\n"); + // Some controllers need this + command_8042(0x60); + write_8042(config); + + // Determine number of channels + if (!single_channel) { + command_8042(0xae); + single_channel = read_config_8042() & (1<<5); + if (!single_channel) + command_8042(0xa7); + } + if (single_channel) + terminal_writestring("Single-channel ps/2 controller\n"); + else + terminal_writestring("Dual-channel ps/2 controller\n"); + + // Test channels + terminal_writestring("Testing channel 1... "); + command_8042(0xab); + if (read_8042() != 0) + terminal_writestring("failed\n"); + else + terminal_writestring("ok\n"); + if (!single_channel) { + terminal_writestring("Testing channel 2... "); + command_8042(0xa9); + if (read_8042() != 0) + terminal_writestring("failed\n"); + else + terminal_writestring("ok\n"); + } + + // Enable devices + command_8042(0xae); + if (!single_channel) + command_8042(0xa8); +} + +void enable_translation(void) { + uint8_t config = read_config_8042(); + config |= 1<<6; + write_config_8042(config); +} + +void disable_translation(void) { + uint8_t config = read_config_8042(); + config &= ~(1<<6); + write_config_8042(config); +} + void kernel_main(void) { /* Initialize terminal interface */ terminal_initialize(); - /* Newline support is left as an exercise. */ - terminal_writestring("Hello, kernel World!\n"); + init_8042(); + if (single_channel) + + terminal_writestring("\nHanging\n"); }