CFLAGS = -std=gnu89 -g -Iinclude/arch/x86 -ffreestanding -DGIT_COMMIT=\"$(GIT_REV)\"
-KERNEL_OBJ = kernel/entry.o kernel/arch/x86/tty/tty.o kernel/drivers/irq/i8259a.o kernel/arch/x86/irq/idt.o kernel/arch/x86/irq/sample_handler.o kernel/kernel.o
+KERNEL_OBJ = kernel/entry.o kernel/arch/x86/tty/tty.o kernel/drivers/irq/i8259a.o kernel/arch/x86/irq/idt.o kernel/arch/x86/irq/sample_handler.o kernel/drivers/input/ps2.o kernel/kernel.o
BOOTLOADER_OBJ = boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN
default: kernel/kernel.elf bootloader
kernel/arch/x86/irq/sample_handler.o: kernel/arch/x86/irq/sample_handler.c
$(CC) $(CFLAGS) -mgeneral-regs-only -c $< -o $@
+kernel/drivers/input/ps2.o: kernel/drivers/input/ps2.c
+
+kernel/kernel.o: kernel/kernel.c
+
kernel/kernel.elf: kernel/kernel.bin
$(CC) -ffreestanding -nostdlib -o $@ -T kernel/linker.ld ${KERNEL_OBJ} -Wl,--oformat=elf32-i386
i686-elf-objcopy --only-keep-debug kernel/kernel.elf kernel/kernel.dbg
--- /dev/null
+#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',
+
+ /* special */
+ [0x29] = ' '
+};
+
+extern int ps2_initialize();
+extern void ps2_input_wait();
+extern void ps2_output_wait();
+
+#endif
--- /dev/null
+#include <tty.h>
+#include <io.h>
+#include <input/ps2.h>
+#include <bitflags.h>
+
+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); }
+ }
+
+ if (port_2_test) {
+ int resp = RESEND;
+
+ while (resp == RESEND) {
+ 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);
+ }
+
+ 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 test successful\n", 0); }
+ }
+*/
+
+ 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_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;
+}
+#include <stdint.h>
#include <tty.h>
#include <io.h>
#include <irq/idt.h>
#include <irq/i8259a.h>
-#include <stdint.h>
+#include <input/ps2.h>
extern void double_fault(struct abort_frame *frame);
extern void keyb_handler(struct interrupt_frame *frame);
void kmain(void)
{
+ int ps2_success;
screen_clear();
kprint("Welcome to Nameless OS!\nRunning revision: ", 0);
kprint(GIT_COMMIT, 0);
kprint("\n", 0);
+ ps2_success = ps2_initialize();
+ switch (ps2_success) {
+ case -1:
+ kprint("No PS/2 devices found or working, we will have no input\n", 0);
+ break;
+ case 0:
+ kprint("Found one working PS/2 device\n", 0);
+ break;
+ case 1:
+ kprint("Found two working PS/2 devices\n", 0);
+ }
kprint("Preparing IDT...\n", 0);
idt_set_descriptor(idt, 0x8, 0x8, (uint32_t) double_fault, IDT_TRAP_GATE, 0x0);
idt_set_descriptor(idt, 0x21, 0x8, (uint32_t) keyb_handler, IDT_INTERRUPT_GATE, 0x0);