]> git.dujemihanovic.xyz Git - nameless-os.git/commitdiff
Merge branch 'ps2-driver' into mm origin/mm
authorDuje Mihanović <duje.mihanovic@skole.hr>
Mon, 22 Aug 2022 20:11:21 +0000 (22:11 +0200)
committerDuje Mihanović <duje.mihanovic@skole.hr>
Mon, 22 Aug 2022 20:11:21 +0000 (22:11 +0200)
boot/x86/stage3/Makefile
kernel/Makefile
kernel/drivers/Makefile
kernel/drivers/input/Makefile [new file with mode: 0644]
kernel/drivers/input/ps2.c [new file with mode: 0644]
kernel/include/arch/x86/bitflags.h [new file with mode: 0644]
kernel/include/arch/x86/input/ps2.h [new file with mode: 0644]
kernel/kernel/kernel.c

index cfe2189dbef18e5152972d6b01d4e354fa759d31..25b026536ea4baf52c26b68a6ee9413f33fc85f6 100644 (file)
@@ -3,7 +3,7 @@ STAGE3_OBJ = loader.o elf.o paging.o prekernel.o
 ASFLAGS_BASE = -f elf -g dwarf2 -DGIT_REVISION=\"$(GIT_REV)\"
 CFLAGS_BASE = -ffreestanding -nostdlib -DGIT_REVISION=\"$(GIT_REV)\" -g \
              -Og
-LDFLAGS_BASE = -ffreestanding -nostdlib -g -lgcc -T stage3.ld -flto
+LDFLAGS_BASE = -ffreestanding -nostdlib -g -lgcc -T stage3.ld
 
 default: LOADER.BIN loader.elf
 
index b510e802636d9de0a49ce5ce27d0d10dd85f6948..8bb12d83f070c44c38e33bdaf5001336f6844c46 100644 (file)
@@ -6,7 +6,7 @@ ASFLAGS_BASE = -f elf -g dwarf2
 CFLAGS_BASE = -fgnu89-inline -ffreestanding -nostdlib -Iinclude \
              -Iinclude/arch/x86 -g -DGIT_COMMIT=\"$(GIT_REV)\" \
              -Og
-LDFLAGS_BASE = -ffreestanding -nostdlib -lgcc -g -flto -T arch/x86/linker.ld
+LDFLAGS_BASE = -ffreestanding -nostdlib -lgcc -g -T arch/x86/linker.ld
 
 kernel.elf kernel.dbg: $(KERNEL_OBJ)
        $(REAL_CC) $(LDFLAGS_BASE) $(LDFLAGS) $^ -o $@
index 76d86aafc1e4d8bd2975fed141cb7c34d08cdcac..c7a361936c166a7416490209c77811a908cb6ca8 100644 (file)
@@ -1 +1,2 @@
+include drivers/input/Makefile
 include drivers/irq/Makefile
diff --git a/kernel/drivers/input/Makefile b/kernel/drivers/input/Makefile
new file mode 100644 (file)
index 0000000..7577b52
--- /dev/null
@@ -0,0 +1 @@
+KERNEL_OBJ += drivers/input/ps2.o
diff --git a/kernel/drivers/input/ps2.c b/kernel/drivers/input/ps2.c
new file mode 100644 (file)
index 0000000..ab4be5c
--- /dev/null
@@ -0,0 +1,201 @@
+#include <tty.h>
+#include <io.h>
+#include <input/ps2.h>
+#include <bitflags.h>
+#include <irq/interrupt.h>
+
+static int was_released = 0, is_caps = 0;
+
+int ps2_keyb_handler()
+{
+       uint8_t scancode = inb(PS2_DATA_PORT);
+       if (was_released) {
+               was_released = 0;
+               return 0;
+       }
+
+       if (scancode == 0xf0) {
+               was_released = 1;
+               uint8_t scancode = inb(PS2_DATA_PORT);
+               if (scancode == 0x12) {
+                       is_caps = 0;
+               }
+               return 0;
+       } else {
+               if (scancode == 0x12) {
+                       is_caps = 1;
+                       return 0;
+               }
+               if (!is_caps) {
+                       kprintc(scancodes[scancode], 0);
+               } else {
+                       kprintc(scancodes[scancode] - ('a'-'A'), 0);
+               }
+       }
+       return 0;
+}
+
+int ps2_initialize()
+{
+       uint8_t ccb, is_2channel, port_1_test, port_2_test;
+
+       kprint("ps2: Begin initializing PS/2 controller\n", 0);
+       outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_DISABLE);
+       ps2_input_wait();
+       outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_1_DISABLE);
+       ps2_input_wait();
+       inb(PS2_DATA_PORT);
+
+       outb(PS2_CMD_STS_PORT, PS2_CMD_READ_CCB);
+       ps2_output_wait();
+       ccb = inb(PS2_DATA_PORT);
+
+       CLEAR(ccb, 0);
+       CLEAR(ccb, 1);
+       CLEAR(ccb, 6);
+
+       ps2_input_wait();
+       outb(PS2_CMD_STS_PORT, PS2_CMD_WRITE_CCB);
+       ps2_input_wait();
+       outb(PS2_DATA_PORT, ccb);
+
+       ps2_input_wait();
+       outb(PS2_CMD_STS_PORT, PS2_CMD_CONTROLLER_TEST);
+       ps2_output_wait();
+       if (inb(PS2_DATA_PORT) != PS2_CONTROLLER_GOOD) {
+               kprint("ps2: Controller self test failed, exiting!\n", 0);
+               return -1;
+       };
+
+       ps2_input_wait();
+       outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_ENABLE);
+       ps2_input_wait();
+       outb(PS2_CMD_STS_PORT, PS2_CMD_READ_CCB);
+       ps2_output_wait();
+       ccb = inb(PS2_DATA_PORT);
+
+       if (ccb & PORT_2_CLK != PORT_2_CLK) {
+               is_2channel = 0;
+               kprint("ps2: Controller is single-channel\n", 0);
+       } else {
+               is_2channel = 1;
+               kprint("ps2: Controller is dual-channel\n", 0);
+               ps2_input_wait();
+               outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_DISABLE);
+       }
+
+       ps2_input_wait();
+       outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_1_TEST);
+       ps2_output_wait();
+
+       if (inb(PS2_DATA_PORT) != 0) {
+               port_1_test = 0;
+               kprint("ps2: Port 1 test failed!\n", 0);
+               if (!is_2channel) {
+                       kprint("ps2: No functional port, exiting!\n", 0);
+                       return -1;
+               }
+       } else port_1_test = 1;
+
+       ps2_input_wait();
+       if (is_2channel) {
+               outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_TEST);
+               ps2_output_wait();
+
+               if (inb(PS2_DATA_PORT) != 0) {
+                       port_2_test = 0;
+                       kprint("ps2: Port 2 test failed!", 0);
+                       if (!port_1_test) {
+                               kprint("ps2: No functional port, exiting!\n", 0);
+                               return -1;
+                       }
+               } else port_2_test = 1;
+       }
+
+       if (port_1_test) { ps2_input_wait(); outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_1_ENABLE); }
+       if (port_2_test) { ps2_input_wait(); outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_ENABLE); }
+
+       int dev_1_test, dev_2_test;
+
+       if (port_1_test) {
+               uint8_t resp;
+
+               do {
+                       ps2_input_wait();
+                       outb(PS2_DATA_PORT, PS2_DEV_RESET);
+                       ps2_output_wait();
+                       resp = inb(PS2_DATA_PORT);
+               } while (resp == RESEND);
+
+               if (resp == SELF_TEST_BAD || resp == SELF_TEST_BAD_2) {
+                       dev_1_test = 0;
+                       kprint("ps2: Port 1 device self test failed!\n", 0);
+                       if (!port_2_test) {
+                               kprint("ps2: No functioning devices, exiting!\n", 0);
+                               return -1;
+                       }
+               } else { dev_1_test = 1; kprint("ps2: Port 1 device test successful\n", 0); }
+       }
+
+       inb(PS2_DATA_PORT);
+       ps2_input_wait();
+
+       if (port_2_test) {
+               uint8_t resp;
+
+               do {
+                       ps2_input_wait();
+                       outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_WRITE);
+                       ps2_input_wait();
+                       outb(PS2_DATA_PORT, PS2_DEV_RESET);
+                       ps2_output_wait();
+                       resp = inb(PS2_DATA_PORT);
+               } while (resp == RESEND);
+
+               if (resp == SELF_TEST_BAD || resp == SELF_TEST_BAD_2) {
+                       dev_2_test = 0;
+                       kprint("ps2: Port 2 device self test failed!\n", 0);
+                       if (!dev_1_test) {
+                               kprint("ps2: No functioning devices, exiting!\n", 0);
+                               return -1;
+                       }
+               } else { dev_2_test = 1; kprint("ps2: Port 2 device test successful\n", 0); }
+       }
+
+       inb(PS2_DATA_PORT);
+       inb(PS2_DATA_PORT);
+       ps2_input_wait();
+       outb(PS2_CMD_STS_PORT, PS2_CMD_READ_CCB);
+       ps2_output_wait();
+       ccb = inb(PS2_DATA_PORT);
+
+       SET(ccb, PORT_1_IRQ);
+
+       ps2_input_wait();
+       outb(PS2_CMD_STS_PORT, PS2_CMD_WRITE_CCB);
+       ps2_input_wait();
+       outb(PS2_DATA_PORT, ccb);
+
+       if (dev_1_test) register_interrupt(33, &ps2_keyb_handler);
+
+       if (dev_2_test && dev_1_test) return 1;
+       else return 0;
+}
+
+void ps2_output_wait()
+{
+       uint8_t status;
+       status = inb(PS2_CMD_STS_PORT);
+
+       while (!IS_SET(status, OUT_STATUS)) status = inb(PS2_CMD_STS_PORT);
+       return;
+}
+
+void ps2_input_wait()
+{
+       uint8_t status;
+       status = inb(PS2_CMD_STS_PORT);
+
+       while (IS_SET(status, IN_STATUS)) status = inb(PS2_CMD_STS_PORT);
+       return;
+}
diff --git a/kernel/include/arch/x86/bitflags.h b/kernel/include/arch/x86/bitflags.h
new file mode 100644 (file)
index 0000000..377f730
--- /dev/null
@@ -0,0 +1,9 @@
+/* Common bit flag ops */
+#ifndef BITFLAGS_H
+#define BITFLAGS_H
+
+#define SET(flags, flag) flags |= (1 << flag)
+#define CLEAR(flags, flag) flags &= ~(1 << flag)
+#define IS_SET(flags, flag) (flags & (1 << flag) == (1 << flag))
+
+#endif
diff --git a/kernel/include/arch/x86/input/ps2.h b/kernel/include/arch/x86/input/ps2.h
new file mode 100644 (file)
index 0000000..55858bf
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef X86_INPUT_PS2_H
+#define X86_INPUT_PS2_H
+
+/* port constants */
+#define PS2_DATA_PORT 0x60
+#define PS2_CMD_STS_PORT 0x64
+
+/* command constants */
+#define PS2_CMD_PORT_2_DISABLE 0xA7
+#define PS2_CMD_PORT_1_DISABLE 0xAD
+#define PS2_CMD_PORT_2_ENABLE 0xA8
+#define PS2_CMD_PORT_1_ENABLE 0xAE
+#define PS2_CMD_READ_CCB 0x20
+#define PS2_CMD_WRITE_CCB 0x60
+#define PS2_CMD_CONTROLLER_TEST 0xAA
+#define PS2_CMD_PORT_1_TEST 0xAB
+#define PS2_CMD_PORT_2_TEST 0xA9
+#define PS2_CMD_PORT_2_WRITE 0xD4
+
+#define PS2_DEV_RESET 0xFF
+
+#define PS2_CONTROLLER_GOOD 0x55
+#define PS2_CONTROLLER_BAD 0xFC
+
+enum PS2_CCB {
+       PORT_1_IRQ = 0,
+       PORT_2_IRQ,
+       SYSTEM_FLAG,
+       ZERO,
+       PORT_1_CLK,
+       PORT_2_CLK,
+       PORT_1_TRANSL,
+       ZERO2
+};
+
+enum PS2_STATUS {
+       OUT_STATUS = 0,
+       IN_STATUS,
+       STS_SYSTEM_FLAG,
+       CMD_DATA,
+       UNKNOWN,
+       UNKNOWN2,
+       TIMEOUT_ERROR,
+       PARITY_ERROR
+};
+
+enum PS2_SPECIAL {
+       SELF_TEST_GOOD = 0xAA,
+       SELF_TEST_BAD = 0xFC,
+       SELF_TEST_BAD_2 = 0xFD,
+       ACK = 0xFA,
+       RESEND = 0xFE
+};
+
+static const char scancodes[] = {
+       /* letters */
+       [0x15] = 'q',
+       [0x1d] = 'w',
+       [0x24] = 'e',
+       [0x2d] = 'r',
+       [0x2c] = 't',
+       [0x35] = 'y',
+       [0x3c] = 'u',
+       [0x43] = 'i',
+       [0x44] = 'o',
+       [0x4d] = 'p',
+       [0x1c] = 'a',
+       [0x1b] = 's',
+       [0x23] = 'd',
+       [0x2b] = 'f',
+       [0x34] = 'g',
+       [0x33] = 'h',
+       [0x3b] = 'j',
+       [0x42] = 'k',
+       [0x4b] = 'l',
+       [0x1a] = 'z',
+       [0x22] = 'x',
+       [0x21] = 'c',
+       [0x2a] = 'v',
+       [0x32] = 'b',
+       [0x31] = 'n',
+       [0x3a] = 'm',
+
+       /* numbers */
+       [0x45] = '0',
+       [0x16] = '1',
+       [0x1e] = '2',
+       [0x26] = '3',
+       [0x25] = '4',
+       [0x2e] = '5',
+       [0x36] = '6',
+       [0x3d] = '7',
+       [0x3e] = '8',
+       [0x46] = '9',
+
+       /* special */
+       [0x29] = ' '
+};
+
+extern int ps2_initialize();
+extern void ps2_input_wait();
+extern void ps2_output_wait();
+
+#endif
index 64e64ae45b01f0c805018aa51bac6bb868439a39..b198fcf49e4fc6b034c5d7e987bd8e1729680b6a 100644 (file)
@@ -3,6 +3,7 @@
 #include <irq/idt.h>
 #include <irq/interrupt.h>
 #include <irq/i8259a.h>
+#include <input/ps2.h>
 #include <stdint.h>
 #include <mm/paging.h>
 #include <panic.h>
@@ -92,6 +93,18 @@ void kmain(struct e820_map *mmap, int mmap_size)
        pic_init(0x20, 0x28);
        pic_mask_all();
        asm volatile ("sti");
+       kprint("Initializing PS/2...\n", VGA_LIGHT_GRAY, VGA_BLACK);
+       int ret = ps2_initialize();
+       switch (ret) {
+       case -1:
+               kprint("No PS/2 devices found or something is faulty\n", VGA_LIGHT_GRAY, VGA_BLACK);
+               break;
+       case 0:
+               kprint("One PS/2 device found\n", VGA_LIGHT_GRAY, VGA_BLACK);
+               break;
+       case 1:
+               kprint("Two PS/2 devices found\n", VGA_LIGHT_GRAY, VGA_BLACK);
+       }
        kprint("All done\n", VGA_LIGHT_GRAY, VGA_BLACK);
        while(1);
 }