summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-04-29 10:36:54 -0400
committerFreya Murphy <freya@freyacat.org>2025-04-29 10:36:54 -0400
commit5d52bae4a9e42d5d53f397f0088fd4879e2ff02d (patch)
treec9f8d79d6b355f1a4d73cbdddd97004a8cb6401d
parentdispatch(): wait for a process to schedule (diff)
downloadcomus-5d52bae4a9e42d5d53f397f0088fd4879e2ff02d.tar.gz
comus-5d52bae4a9e42d5d53f397f0088fd4879e2ff02d.tar.bz2
comus-5d52bae4a9e42d5d53f397f0088fd4879e2ff02d.zip
ps2
-rw-r--r--kernel/cpu/idt.c3
-rw-r--r--kernel/drivers.c2
-rw-r--r--kernel/drivers/ps2.c296
-rw-r--r--kernel/include/comus/drivers/ps2.h49
-rw-r--r--kernel/include/comus/keycodes.h143
5 files changed, 493 insertions, 0 deletions
diff --git a/kernel/cpu/idt.c b/kernel/cpu/idt.c
index d071d29..2eab7ec 100644
--- a/kernel/cpu/idt.c
+++ b/kernel/cpu/idt.c
@@ -2,6 +2,7 @@
#include <comus/memory.h>
#include <comus/asm.h>
#include <comus/cpu.h>
+#include <comus/drivers/ps2.h>
#include <comus/drivers/pit.h>
#include <comus/procs.h>
#include <comus/memory.h>
@@ -185,8 +186,10 @@ void idt_pic_timer(void)
void idt_pic_keyboard(void)
{
+ ps2kb_recv();
}
void idt_pic_mouse(void)
{
+ ps2mouse_recv();
}
diff --git a/kernel/drivers.c b/kernel/drivers.c
index 98bf1bd..3d6ec10 100644
--- a/kernel/drivers.c
+++ b/kernel/drivers.c
@@ -1,6 +1,7 @@
#include <comus/drivers.h>
#include <comus/drivers/acpi.h>
#include <comus/drivers/uart.h>
+#include <comus/drivers/ps2.h>
#include <comus/drivers/pci.h>
#include <comus/drivers/ata.h>
#include <comus/drivers/gpu.h>
@@ -11,6 +12,7 @@ void drivers_init(void)
{
pit_set_divider(1193); // 1ms
uart_init();
+ ps2_init();
pci_init();
ata_init();
acpi_init(mboot_get_rsdp());
diff --git a/kernel/drivers/ps2.c b/kernel/drivers/ps2.c
new file mode 100644
index 0000000..5c18b5b
--- /dev/null
+++ b/kernel/drivers/ps2.c
@@ -0,0 +1,296 @@
+#include <comus/drivers/ps2.h>
+#include <comus/keycodes.h>
+#include <comus/asm.h>
+#include <lib.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 uint8_t scancodes[] = {
+ KEY_NONE, KEY_F9, KEY_NONE, KEY_F5, KEY_F3,
+ KEY_F1, KEY_F2, KEY_F12, KEY_NONE, KEY_F10,
+ KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_BACKTICK,
+ KEY_NONE, KEY_NONE, KEY_L_ALT, KEY_L_SHIFT, KEY_NONE,
+ KEY_L_CTRL, KEY_Q, KEY_1, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_Z, KEY_S, KEY_A, KEY_W,
+ KEY_2, KEY_NONE, KEY_NONE, KEY_C, KEY_X,
+ KEY_D, KEY_E, KEY_4, KEY_3, KEY_NONE,
+ KEY_NONE, KEY_SPACE, KEY_V, KEY_F, KEY_T,
+ KEY_R, KEY_5, KEY_NONE, KEY_NONE, KEY_N,
+ KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_M, KEY_J,
+ KEY_U, KEY_7, KEY_8, KEY_NONE, KEY_NONE,
+ KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0,
+ KEY_9, KEY_NONE, KEY_NONE, KEY_PERIOD, KEY_SLASH,
+ KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_QUOTE, KEY_NONE, KEY_L_BRACE,
+ KEY_EQUAL, KEY_NONE, KEY_NONE, KEY_CAPS_LOCK, KEY_R_SHIFT,
+ KEY_ENTER, KEY_R_BRACE, KEY_NONE, KEY_BACKSLASH, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_BACKSPACE, KEY_NONE, KEY_NONE,
+ KEY_NP_1, KEY_NONE, KEY_NP_4, KEY_NP_7, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_NP_0, KEY_NP_PERIOD, KEY_NP_2,
+ KEY_NP_5, KEY_NP_6, KEY_NP_8, KEY_ESCAPE, KEY_NUM_LOCK,
+ KEY_F11, KEY_NP_PLUS, KEY_NP_3, KEY_NP_MINUS, KEY_NP_ASTERISK,
+ KEY_NP_9, KEY_SCROLL_LOCK, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_F7,
+};
+static uint8_t scancodes_ext[] = {
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_UNKNOWN, KEY_R_ALT, KEY_PRINT_SCREEN, KEY_NONE,
+ KEY_R_CTRL, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_L_META, KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE,
+ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_R_META,
+ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_MENU, KEY_UNKNOWN, KEY_NONE,
+ KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE,
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NP_SLASH,
+ KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE,
+ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NP_ENTER, KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_END, KEY_NONE, KEY_LEFT, KEY_HOME, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_INSERT, KEY_DELETE, KEY_DOWN,
+ KEY_NONE, KEY_RIGHT, KEY_UP, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_PAGE_DOWN, KEY_NONE, KEY_NONE,
+ KEY_PAGE_UP, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE,
+};
+
+// ctrl
+static bool has_kbd = false;
+static bool has_mouse = false;
+
+// kbd
+static struct keycode last_keycode = {
+ .key = KEY_NONE,
+ .flags = 0,
+};
+static bool state_keyup = false;
+static bool state_ext = false;
+
+// mouse
+static struct mouse_event last_mouse_ev = {
+ .updated = false,
+ .lmb = false,
+ .mmb = false,
+ .rmb = false,
+ .relx = 0,
+ .rely = 0,
+};
+static uint8_t first_b, second_b, third_b;
+
+static uint8_t ps2ctrl_in_status(void)
+{
+ return inb(0x64);
+}
+
+static uint8_t ps2ctrl_in(void)
+{
+ while ((ps2ctrl_in_status() & STATUS_OUT_BUF) == 0) {
+ io_wait();
+ }
+ return inb(0x60);
+}
+
+static void ps2ctrl_out_cmd(uint8_t cmd)
+{
+ while ((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) {
+ io_wait();
+ }
+ outb(0x64, cmd);
+}
+
+static void ps2ctrl_out_data(uint8_t data)
+{
+ while ((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) {
+ io_wait();
+ }
+ outb(0x60, data);
+}
+
+static void ps2ctrl_set_port2(void)
+{
+ outb(0x64, 0xD4);
+}
+
+static int ps2kb_init(void)
+{
+ uint8_t result;
+
+ ps2ctrl_out_data(0xFF);
+ if ((result = ps2ctrl_in()) != 0xFA)
+ return 1;
+
+ if ((result = ps2ctrl_in()) != 0xAA)
+ return 1;
+
+ ps2ctrl_out_data(0xF4);
+ if ((result = ps2ctrl_in()) != 0xFA)
+ return 1;
+
+ has_kbd = true;
+ return 0;
+}
+
+static int ps2mouse_init(void)
+{
+ uint8_t result;
+
+ ps2ctrl_set_port2();
+ ps2ctrl_out_data(0xFF);
+ if ((result = ps2ctrl_in()) != 0xFA)
+ return 1;
+
+ if ((result = ps2ctrl_in()) != 0xAA)
+ return 1;
+
+ ps2ctrl_set_port2();
+ ps2ctrl_out_data(0xF4);
+
+ has_mouse = true;
+ return 0;
+}
+
+void ps2kb_recv(void)
+{
+ uint8_t code;
+
+ if (!has_kbd)
+ return;
+
+ 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 <= 0x84) {
+ 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 (!has_kbd)
+ return last_keycode;
+
+ code = last_keycode;
+ last_keycode.key = KEY_NONE;
+ last_keycode.flags = 0;
+ return code;
+}
+
+void ps2mouse_recv(void)
+{
+ static uint8_t packet_num = 0;
+ uint8_t code;
+
+ if (!has_mouse)
+ return;
+
+ code = ps2ctrl_in();
+ switch (packet_num) {
+ case 0:
+ first_b = code;
+ break;
+ case 1:
+ second_b = code;
+ break;
+ case 2: {
+ int state, d;
+
+ third_b = code;
+ state = first_b;
+ d = second_b;
+ last_mouse_ev.relx = d - ((state << 4) & 0x100);
+ d = third_b;
+ last_mouse_ev.rely = d - ((state << 3) & 0x100);
+
+ last_mouse_ev.lmb = first_b & 0x01;
+ last_mouse_ev.rmb = first_b & 0x02;
+ last_mouse_ev.mmb = first_b & 0x04;
+ last_mouse_ev.updated = true;
+ break;
+ }
+ }
+
+ packet_num += 1;
+ packet_num %= 3;
+}
+
+struct mouse_event ps2mouse_get(void)
+{
+ struct mouse_event event = last_mouse_ev;
+ last_mouse_ev.updated = false;
+ return event;
+}
+
+int ps2_init(void)
+{
+ uint8_t result;
+
+ cli();
+
+ inb(0x60);
+
+ // self-test
+ ps2ctrl_out_cmd(0xAA);
+ if ((result = ps2ctrl_in()) != 0x55) {
+ WARN("PS/2 Controller failed to initalize.");
+ return 1;
+ }
+
+ // 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);
+ if ((result != ps2ctrl_in()) != 0x01) {
+ WARN("PS/2 port 2 not supported");
+ return 1;
+ }
+
+ ps2ctrl_out_cmd(0xA8);
+
+ ps2kb_init();
+ ps2mouse_init();
+ sti();
+ return 0;
+}
diff --git a/kernel/include/comus/drivers/ps2.h b/kernel/include/comus/drivers/ps2.h
new file mode 100644
index 0000000..6e594e9
--- /dev/null
+++ b/kernel/include/comus/drivers/ps2.h
@@ -0,0 +1,49 @@
+/**
+ * @file ps2.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * PS/2 Mouse & Keyboard
+ */
+
+#ifndef PS2_H_
+#define PS2_H_
+
+#include <comus/keycodes.h>
+#include <stdbool.h>
+
+struct mouse_event {
+ bool updated;
+ bool lmb;
+ bool rmb;
+ bool mmb;
+ int relx;
+ int rely;
+};
+
+/**
+ * Initalize the ps2 controller
+ */
+int ps2_init(void);
+
+/**
+ * Recieve input from ps2 keyboard during interrupt
+ */
+void ps2kb_recv(void);
+
+/**
+ * Return last read keycode
+ */
+struct keycode ps2kb_get(void);
+
+/**
+ * Recieve input from ps2 mouse during interrupt
+ */
+void ps2mouse_recv(void);
+
+/**
+ * Return last read mouse event
+ */
+struct mouse_event ps2mouse_get(void);
+
+#endif /* ps2.h */
diff --git a/kernel/include/comus/keycodes.h b/kernel/include/comus/keycodes.h
new file mode 100644
index 0000000..8930937
--- /dev/null
+++ b/kernel/include/comus/keycodes.h
@@ -0,0 +1,143 @@
+/**
+ * @file keycodes.h
+ *
+ * @author Tristan Miller <trimill@trimill.xyz>
+ *
+ * Kernel keycodes
+ */
+
+#ifndef KEYCODES_H_
+#define KEYCODES_H_
+
+struct keycode {
+ char key;
+ char flags;
+};
+
+#define KC_FLAG_KEY_DOWN 0x01
+#define KC_FLAG_KEY_UP 0x02
+#define KC_FLAG_ERROR 0x04
+
+#define KEY_NONE 0x00
+#define KEY_UNKNOWN 0x01
+
+#define KEY_ESCAPE 0x10
+#define KEY_1 0x11
+#define KEY_2 0x12
+#define KEY_3 0x13
+#define KEY_4 0x14
+#define KEY_5 0x15
+#define KEY_6 0x16
+#define KEY_7 0x17
+#define KEY_8 0x18
+#define KEY_9 0x19
+#define KEY_0 0x1A
+#define KEY_MINUS 0x1B
+#define KEY_EQUAL 0x1C
+#define KEY_BACKSPACE 0x1D
+#define KEY_L_SHIFT 0x1E
+#define KEY_R_SHIFT 0x1F
+
+#define KEY_TAB 0x20
+#define KEY_Q 0x21
+#define KEY_W 0x22
+#define KEY_E 0x23
+#define KEY_R 0x24
+#define KEY_T 0x25
+#define KEY_Y 0x26
+#define KEY_U 0x27
+#define KEY_I 0x28
+#define KEY_O 0x29
+#define KEY_P 0x2A
+#define KEY_L_BRACE 0x2B
+#define KEY_R_BRACE 0x2C
+#define KEY_BACKSLASH 0x2D
+#define KEY_L_CTRL 0x2E
+#define KEY_R_CTRL 0x2F
+
+#define KEY_CAPS_LOCK 0x30
+#define KEY_A 0x31
+#define KEY_S 0x32
+#define KEY_D 0x33
+#define KEY_F 0x34
+#define KEY_G 0x35
+#define KEY_H 0x36
+#define KEY_J 0x37
+#define KEY_K 0x38
+#define KEY_L 0x39
+#define KEY_SEMICOLON 0x3A
+#define KEY_QUOTE 0x3B
+#define KEY_ENTER 0x3C
+#define KEY_MENU 0x3D
+#define KEY_L_ALT 0x3E
+#define KEY_R_ALT 0x3F
+
+#define KEY_SPACE 0x40
+#define KEY_Z 0x41
+#define KEY_X 0x42
+#define KEY_C 0x43
+#define KEY_V 0x44
+#define KEY_B 0x45
+#define KEY_N 0x46
+#define KEY_M 0x47
+#define KEY_COMMA 0x48
+#define KEY_PERIOD 0x49
+#define KEY_SLASH 0x4A
+#define KEY_BACKTICK 0x4B
+#define KEY_NUM_LOCK 0x4C
+#define KEY_SCROLL_LOCK 0x4D
+#define KEY_L_META 0x4E
+#define KEY_R_META 0x4F
+
+#define KEY_NP_SLASH 0x50
+#define KEY_NP_7 0x51
+#define KEY_NP_8 0x52
+#define KEY_NP_9 0x53
+#define KEY_NP_ASTERISK 0x54
+#define KEY_NP_4 0x55
+#define KEY_NP_5 0x56
+#define KEY_NP_6 0x57
+#define KEY_NP_MINUS 0x58
+#define KEY_NP_1 0x59
+#define KEY_NP_2 0x5A
+#define KEY_NP_3 0x5B
+#define KEY_NP_PLUS 0x5C
+#define KEY_NP_0 0x5D
+#define KEY_NP_PERIOD 0x5E
+#define KEY_NP_ENTER 0x5F
+
+#define KEY_PRINT_SCREEN 0x60
+#define KEY_PAUSE 0x61
+#define KEY_INSERT 0x62
+#define KEY_HOME 0x63
+#define KEY_PAGE_UP 0x64
+#define KEY_DELETE 0x65
+#define KEY_END 0x66
+#define KEY_PAGE_DOWN 0x67
+#define KEY_UP 0x68
+#define KEY_DOWN 0x69
+#define KEY_LEFT 0x6A
+#define KEY_RIGHT 0x6B
+// #define _ 0x6C
+// #define _ 0x6D
+// #define _ 0x6E
+// #define _ 0x6F
+
+#define KEY_F1 0x70
+#define KEY_F2 0x71
+#define KEY_F3 0x72
+#define KEY_F4 0x73
+#define KEY_F5 0x74
+#define KEY_F6 0x75
+#define KEY_F7 0x76
+#define KEY_F8 0x77
+#define KEY_F9 0x78
+#define KEY_F10 0x79
+#define KEY_F11 0x7A
+#define KEY_F12 0x7B
+// #define _ 0x7C
+// #define _ 0x7D
+// #define _ 0x7E
+// #define _ 0x7F
+
+#endif /* keycodes */