summaryrefslogtreecommitdiff
path: root/kernel/src/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/src/drivers')
-rw-r--r--kernel/src/drivers/ps2ctrl.c99
-rw-r--r--kernel/src/drivers/ps2ctrl.h14
-rw-r--r--kernel/src/drivers/ps2kb.c130
-rw-r--r--kernel/src/drivers/ps2kb.h15
-rw-r--r--kernel/src/drivers/ps2mouse.c89
-rw-r--r--kernel/src/drivers/ps2mouse.h18
6 files changed, 365 insertions, 0 deletions
diff --git a/kernel/src/drivers/ps2ctrl.c b/kernel/src/drivers/ps2ctrl.c
new file mode 100644
index 0000000..527435d
--- /dev/null
+++ b/kernel/src/drivers/ps2ctrl.c
@@ -0,0 +1,99 @@
+#include <panic.h>
+#include <sys.h>
+
+#include "print.h"
+#include "ps2ctrl.h"
+#include "interrupt/pic.h"
+
+#define STATUS_OUT_BUF ((uint8_t)0x01)
+#define STATUS_IN_BUF ((uint8_t)0x02)
+
+#define CONFIG_INT_0 ((uint8_t)0x01)
+#define CONFIG_INT_1 ((uint8_t)0x02)
+#define CONFIG_SYS ((uint8_t)0x04)
+#define CONFIG_CLOCK_0 ((uint8_t)0x10)
+#define CONFIG_CLOCK_1 ((uint8_t)0x20)
+#define CONFIG_TRANS ((uint8_t)0x40)
+
+static bool is_init = false;
+
+uint8_t ps2ctrl_in(void) {
+ while((ps2ctrl_in_status() & STATUS_OUT_BUF) == 0) {
+ io_wait();
+ }
+ return inb(0x60);
+}
+
+uint8_t ps2ctrl_in_status(void) {
+ return inb(0x64);
+}
+
+void ps2ctrl_out_cmd(uint8_t cmd) {
+ while((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) {
+ io_wait();
+ }
+ outb(0x64, cmd);
+}
+
+void ps2ctrl_out_data(uint8_t data) {
+ while((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) {
+ io_wait();
+ }
+ outb(0x60, data);
+}
+
+void ps2ctrl_set_port2(void) {
+ outb(0x64, 0xD4);
+}
+
+void ps2ctrl_init(void) {
+
+ debugk("Loading PS/2 Controller");
+
+ is_init = false;
+
+ pic_mask(1); // keyboard
+ pic_mask(12); // mouse
+
+ inb(0x60);
+
+ // self-test
+ ps2ctrl_out_cmd(0xAA);
+ uint8_t response = ps2ctrl_in();
+ if(response != 0x55) {
+ errork("PS/2 controller failed to initialize");
+ return;
+ }
+
+ // set config
+ ps2ctrl_out_cmd(0x20);
+ uint8_t config = ps2ctrl_in();
+ config = (config | CONFIG_INT_0 | CONFIG_INT_1) & ~CONFIG_TRANS;
+ // config = 0xFF;
+ ps2ctrl_out_cmd(0x60);
+ ps2ctrl_out_data(config);
+
+ // enable port 0
+ ps2ctrl_out_cmd(0xAE);
+
+ // enable port 2
+ ps2ctrl_out_cmd(0xA9);
+ response = ps2ctrl_in();
+ if (response == 0x01) {
+ errork("PS/2 port 2 not supported");
+ return;
+ }
+
+ ps2ctrl_out_cmd(0xA8);
+
+ is_init = true;
+
+ pic_unmask(1);
+ pic_unmask(12);
+
+ succek("Loaded PS/2 Controller");
+}
+
+bool ps2ctrl_is_init(void) {
+ return is_init;
+}
diff --git a/kernel/src/drivers/ps2ctrl.h b/kernel/src/drivers/ps2ctrl.h
new file mode 100644
index 0000000..a674c57
--- /dev/null
+++ b/kernel/src/drivers/ps2ctrl.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+uint8_t ps2ctrl_in(void);
+uint8_t ps2ctrl_in_status(void);
+void ps2ctrl_out_cmd(uint8_t cmd);
+void ps2ctrl_out_data(uint8_t data);
+void ps2ctrl_set_port2(void);
+
+void ps2ctrl_init(void);
+
+bool ps2ctrl_is_init(void);
diff --git a/kernel/src/drivers/ps2kb.c b/kernel/src/drivers/ps2kb.c
new file mode 100644
index 0000000..dec0b87
--- /dev/null
+++ b/kernel/src/drivers/ps2kb.c
@@ -0,0 +1,130 @@
+#include <panic.h>
+#include <sys.h>
+
+#include "print.h"
+#include "ps2kb.h"
+#include "ps2ctrl.h"
+#include "interrupt/pic.h"
+
+#define BUFFER_LEN 16
+
+#define KEYCODE_ARRAY_LEN 0x84
+
+static uint8_t scancodes[] = {
+// 00/08 01/09 02/0A 03/0B 04/0C 05/0D 06/0E 07/0F
+/*00*/ KEY_NONE, KEY_F9, KEY_NONE, KEY_F5, KEY_F3, KEY_F1, KEY_F2, KEY_F12,
+/*08*/ KEY_NONE, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_BACKTICK, KEY_NONE,
+/*10*/ KEY_NONE, KEY_L_ALT, KEY_L_SHIFT, KEY_NONE, KEY_L_CTRL, KEY_Q, KEY_1, KEY_NONE,
+/*18*/ KEY_NONE, KEY_NONE, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KEY_NONE,
+/*20*/ KEY_NONE, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KEY_NONE,
+/*28*/ KEY_NONE, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KEY_NONE,
+/*30*/ KEY_NONE, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KEY_NONE,
+/*38*/ KEY_NONE, KEY_NONE, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KEY_NONE,
+/*40*/ KEY_NONE, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KEY_NONE,
+/*48*/ KEY_NONE, KEY_PERIOD, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_NONE,
+/*50*/ KEY_NONE, KEY_NONE, KEY_QUOTE, KEY_NONE, KEY_L_BRACE, KEY_EQUAL, KEY_NONE, KEY_NONE,
+/*58*/ KEY_CAPS_LOCK, KEY_R_SHIFT, KEY_ENTER, KEY_R_BRACE, KEY_NONE, KEY_BACKSLASH, KEY_NONE, KEY_NONE,
+/*60*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_BACKSPACE, KEY_NONE,
+/*68*/ KEY_NONE, KEY_NP_1, KEY_NONE, KEY_NP_4, KEY_NP_7, KEY_NONE, KEY_NONE, KEY_NONE,
+/*70*/ KEY_NP_0, KEY_NP_PERIOD, KEY_NP_2, KEY_NP_5, KEY_NP_6, KEY_NP_8, KEY_ESCAPE, KEY_NUM_LOCK,
+/*78*/ KEY_F11, KEY_NP_PLUS, KEY_NP_3, KEY_NP_MINUS, KEY_NP_ASTERISK, KEY_NP_9, KEY_SCROLL_LOCK, KEY_NONE,
+/*80*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_F7,
+};
+static uint8_t scancodes_ext[] = {
+// 00/08 01/09 02/0A 03/0B 04/0C 05/0D 06/0E 07/0F
+/*00*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*08*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*10*/ KEY_UNKNOWN, KEY_R_ALT, KEY_PRINT_SCREEN, KEY_NONE, KEY_R_CTRL, KEY_UNKNOWN, KEY_NONE, KEY_NONE,
+/*18*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_L_META,
+/*20*/ KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_R_META,
+/*28*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_MENU,
+/*30*/ KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN,
+/*38*/ KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN,
+/*40*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*48*/ KEY_UNKNOWN, KEY_NONE, KEY_NP_SLASH, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE,
+/*50*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*58*/ KEY_NONE, KEY_NONE, KEY_NP_ENTER, KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE,
+/*60*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+/*68*/ KEY_NONE, KEY_END, KEY_NONE, KEY_LEFT, KEY_HOME, KEY_NONE, KEY_NONE, KEY_NONE,
+/*70*/ KEY_INSERT, KEY_DELETE, KEY_DOWN, KEY_NONE, KEY_RIGHT, KEY_UP, KEY_NONE, KEY_NONE,
+/*78*/ KEY_NONE, KEY_NONE, KEY_PAGE_DOWN, KEY_NONE, KEY_NONE, KEY_PAGE_UP, KEY_NONE, KEY_NONE,
+/*80*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+};
+
+static struct Keycode last_keycode;
+
+static bool is_init = false;
+static bool state_keyup = false;
+static bool state_ext = false;
+
+void ps2kb_init(void) {
+
+ debugk("Loading PS/2 Keyboard");
+
+ is_init = false;
+ pic_mask(1);
+
+ uint8_t result;
+
+ ps2ctrl_out_data(0xFF);
+ result = ps2ctrl_in();
+ if(result != 0xFA) {
+ errork("Failed to reset PS/2 keyboard: expected 0xFA, got 0x%X\n", result);
+ return;
+ }
+ result = ps2ctrl_in();
+ if(result != 0xAA) {
+ errork("Failed to reset PS/2 keyboard: expected 0xAA, got 0x%X\n", result);
+ return;
+ }
+
+ ps2ctrl_out_data(0xF4);
+ result = ps2ctrl_in();
+ if(result != 0xFA) {
+ errork("Failed to enable PS/2 keyboard: expected 0xFA, got 0x%X\n", result);
+ return;
+ }
+
+ succek("PS/2 Keyboard has has been loaded");
+
+ pic_unmask(1);
+ is_init = true;
+}
+
+void ps2kb_recv(void) {
+ if(!ps2ctrl_is_init() || !is_init) {
+ inb(0x60);
+ return;
+ }
+ uint8_t code = ps2ctrl_in();
+ if (code == 0x00 || code == 0x0F) {
+ last_keycode.key = KEY_NONE;
+ last_keycode.flags = KC_FLAG_ERROR;
+ } else if(code == 0xF0) {
+ state_keyup = true;
+ } else if(code == 0xE0) {
+ state_ext = true;
+ } else if(code <= KEYCODE_ARRAY_LEN) {
+ uint8_t *scancode_table = state_ext ? scancodes_ext : scancodes;
+ uint8_t keycode = scancode_table[code];
+ if(keycode != KEY_NONE) {
+ last_keycode.key = keycode;
+ last_keycode.flags = state_keyup ? KC_FLAG_KEY_UP : KC_FLAG_KEY_DOWN;
+ }
+ state_keyup = false;
+ state_ext = false;
+ }
+}
+
+struct Keycode ps2kb_get(void) {
+ struct Keycode code;
+ if(is_init) {
+ code = last_keycode;
+ } else {
+ code.key = KEY_NONE;
+ code.flags = KC_FLAG_ERROR;
+ }
+ last_keycode.key = KEY_NONE;
+ last_keycode.flags = 0;
+ return code;
+}
diff --git a/kernel/src/drivers/ps2kb.h b/kernel/src/drivers/ps2kb.h
new file mode 100644
index 0000000..1aaefb2
--- /dev/null
+++ b/kernel/src/drivers/ps2kb.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <keycodes.h>
+
+struct Keycode {
+ uint8_t key;
+ uint8_t flags;
+};
+
+void ps2kb_init(void);
+
+void ps2kb_recv(void);
+struct Keycode ps2kb_get(void);
diff --git a/kernel/src/drivers/ps2mouse.c b/kernel/src/drivers/ps2mouse.c
new file mode 100644
index 0000000..01e10cc
--- /dev/null
+++ b/kernel/src/drivers/ps2mouse.c
@@ -0,0 +1,89 @@
+#include <panic.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys.h>
+
+#include "print.h"
+#include "ps2mouse.h"
+#include "drivers/ps2ctrl.h"
+#include "interrupt/pic.h"
+
+static bool is_init = false;
+
+static struct MouseEvent last_event;
+static uint8_t first_b, second_b, third_b;
+
+void ps2mouse_init(void) {
+
+ debugk("Loading PS/2 Mouse");
+
+ is_init = false;
+ pic_mask(12);
+
+ uint8_t result;
+
+ ps2ctrl_set_port2();
+ ps2ctrl_out_data(0xFF);
+ result = ps2ctrl_in();
+ if (result != 0xFA) {
+ errork("Failed to reset PS/2 mouse: expected 0xFA, got 0x%X", result);
+ return;
+ }
+ result = ps2ctrl_in();
+ if (result != 0xAA) {
+ errork("Failed to reset PS/2 mouse: expected 0xAA, got 0x%X", result);
+ return;
+ }
+
+ ps2ctrl_set_port2();
+ ps2ctrl_out_data(0xF4);
+
+ pic_unmask(12);
+ is_init = true;
+
+ succek("PS/2 Mouse has has been loaded");
+}
+
+static uint8_t packet_num = 0;
+void ps2mouse_recv(void) {
+ if (!ps2ctrl_is_init() || !is_init) {
+ inb(0x60);
+ return;
+ }
+
+ uint8_t packet = ps2ctrl_in();
+ switch (packet_num) {
+ case 0:
+ first_b = packet;
+ break;
+ case 1:
+ second_b = packet;
+ break;
+ case 2: {
+ third_b = packet;
+
+ int state, d;
+ state = first_b;
+ d = second_b;
+ last_event.relx = d - ((state << 4) & 0x100);
+ d = third_b;
+ last_event.rely = d - ((state << 3) & 0x100);
+
+ last_event.lmb = first_b & 0x01;
+ last_event.rmb = first_b & 0x02;
+ last_event.mmb = first_b & 0x04;
+ last_event.updated = true;
+ break;
+ }
+ }
+
+ packet_num += 1;
+ packet_num %= 3;
+
+}
+
+struct MouseEvent ps2mouse_get(void) {
+ struct MouseEvent event = last_event;
+ last_event.updated = false;
+ return event;
+}
diff --git a/kernel/src/drivers/ps2mouse.h b/kernel/src/drivers/ps2mouse.h
new file mode 100644
index 0000000..9cd4818
--- /dev/null
+++ b/kernel/src/drivers/ps2mouse.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct MouseEvent {
+ bool updated;
+ bool lmb;
+ bool rmb;
+ bool mmb;
+ int relx;
+ int rely;
+};
+
+void ps2mouse_init(void);
+
+void ps2mouse_recv(void);
+struct MouseEvent ps2mouse_get(void);