diff options
Diffstat (limited to 'kc/core')
| -rw-r--r-- | kc/core/Makefile | 2 | ||||
| -rw-r--r-- | kc/core/i8042.c | 183 | ||||
| -rw-r--r-- | kc/core/i8042.h | 17 | ||||
| -rw-r--r-- | kc/core/input.h | 21 | ||||
| -rw-r--r-- | kc/core/kc_main.c | 2 | ||||
| -rw-r--r-- | kc/core/task.c | 32 |
6 files changed, 252 insertions, 5 deletions
diff --git a/kc/core/Makefile b/kc/core/Makefile index 8a9c9fd..7abf20b 100644 --- a/kc/core/Makefile +++ b/kc/core/Makefile @@ -14,7 +14,7 @@ GOBJS := entry_x86_64.o reloc_x86_64.o dynamic_x86_64.o \ kprintf.o serial.o port.o mmu.o kc_main.o memory.o memset.o memcpy.o \ memmove.o memcmp.o cpu.o vm_tree.o exceptions.o panic.o msr.o task.o \ cpu_task.o irq.o kcc_memory.o string.o pic8259.o pic8259_isr.o \ - pit8253.o page_early.o page_stack.o kstdio.o video.o + pit8253.o page_early.o page_stack.o kstdio.o video.o i8042.o IOBJS := # __attribute__((interrupt)) requires -mgeneral-regs-only diff --git a/kc/core/i8042.c b/kc/core/i8042.c new file mode 100644 index 0000000..0ba12dc --- /dev/null +++ b/kc/core/i8042.c @@ -0,0 +1,183 @@ +#include "input.h" +#include "port.h" +#include "i8042.h" +#include "pic8259.h" +#include <lib/kstdio.h> + +static void i8042_init(void); +static void i8042_enable(void) {} +static void i8042_disable(void) {} + +static int i8042_append_callback(input_callback func) {(void)func; return 0;} +static void i8042_delete_callback(input_callback func) {(void)func;} + +const struct input_source i8042_input_source = +{ + "i8042", + i8042_init, + i8042_enable, + i8042_disable, + + i8042_append_callback, + i8042_delete_callback, +}; + +#define PS2_STATUS 0x64 +#define PS2_COMMAND 0x64 +#define PS2_DATA 0x60 +#define PS2_IRQ 1 + +static void i8042_disable_ports() +{ + outb(PS2_COMMAND, 0xad); + outb(PS2_COMMAND, 0xa7); +} + +static uint8_t i8042_command(int c) +{ + outb(PS2_COMMAND, c); + return (uint8_t)c; +} + +static uint8_t i8042_status() +{ + return inb(PS2_STATUS); +} + +static bool i8042_read(uint8_t *b) +{ + if (i8042_status() & 1) + { + (b != NULL) ? *b = inb(PS2_DATA) : inb(PS2_DATA); + return true; + } + + return false; +} + +static void i8042_flush() +{ + while(i8042_status() & 1) + { + i8042_read(NULL); + } +} + +static int i8042_callback(uint8_t irq) +{ + (void)irq; + i8042_flush(); + return 0; +} + + +#define I8042_MAX_TRIES 4096 + +static bool i8042_write(uint8_t b) +{ + for (int i = 0; i < I8042_MAX_TRIES; i++) + { + if (i8042_status() & 2) + { + continue; + } + + outb(PS2_DATA, b); + return true; + } + + return false; +} + +static void i8042_set_config(void) +{ + bool channel_a_enable = false; + bool channel_b_enable = false; + + bool maybe_dual_channel = false; + bool is_dual_channel = false; + i8042_command(0x20); + uint8_t config_byte; + i8042_read(&config_byte); + kprintf("i8042: current config: %#0.2x\n", config_byte); + config_byte &= 0xfc; + if (config_byte & (0x1 << 5)) + { + maybe_dual_channel = true; + } + config_byte |= 0x01; + kprintf("i8042: new config: %#0.2x\n", config_byte); + i8042_command(0x60); + i8042_write(config_byte); + i8042_command(0xaa); + uint8_t bist_result; + if (i8042_read(&bist_result) && bist_result != 0x55) + { + kprintf("i8042: warning: error self-testing device. aborting.\n"); + return; + } + + if (maybe_dual_channel) + { + i8042_command(0xa8); + i8042_command(0x20); + uint8_t config_byte; + if (i8042_read(&config_byte) && config_byte & (0x1 << 5)) + { + kprintf("i8042: single-channel controller detected\n"); + } + else + { + kprintf("i8042: dual-channel controller detected\n"); + is_dual_channel = true; + } + } + + outb(PS2_COMMAND, 0xab); + if (inb(PS2_DATA) != 0x00) + { + kprintf("i8042: failed testing port a\n"); + } + else + { + channel_a_enable = true; + } + if (is_dual_channel) + { + outb(PS2_COMMAND, 0xa9); + if (inb(PS2_DATA) != 0x00) + { + kprintf("i8042: failed testing port b\n"); + } + else + { + channel_b_enable = true; + } + i8042_disable_ports(); + } + + if (channel_a_enable) + { + outb(PS2_COMMAND, 0xae); + i8042_write(0xff); + if(inb(PS2_DATA) == 0xfa && inb(PS2_DATA) == 0xaa) + { + kprintf("i8042: detected device on channel, type %#0.2x\n", inb(PS2_DATA)); + } + } + + i8042_flush(); + (void)channel_b_enable; +} + +static void i8042_init(void) +{ + i8042_disable_ports(); + i8042_flush(); + i8042_set_config(); + + pic8259_irq_install(PS2_IRQ, i8042_callback); + pic8259_irq_unmask(PS2_IRQ); +} + + diff --git a/kc/core/i8042.h b/kc/core/i8042.h new file mode 100644 index 0000000..80a6c92 --- /dev/null +++ b/kc/core/i8042.h @@ -0,0 +1,17 @@ +#pragma once + +#include "input.h" + +#define I8042_DATA_PORT 0x60 +#define I8042_STATUS_PORT 0x64 +#define I8042_COMMAND_PORT 0x64 + +#define I8042_OUT_DATA 0x1 +#define I8042_IN_DATA 0x2 +#define I8042_SYSTEM 0x4 +#define I8042_DATA_IS_COMMAND 0x8 +#define I8042_ERR_TIMEOUT 0x40 +#define I8042_ERR_PARITY 0x80 + +extern const struct input_source i8042_input_source; + diff --git a/kc/core/input.h b/kc/core/input.h new file mode 100644 index 0000000..b796fdf --- /dev/null +++ b/kc/core/input.h @@ -0,0 +1,21 @@ +#pragma once + +typedef int (*input_callback)(void); + +struct input_callback_list +{ + input_callback func; + struct input_callback_list *next; +}; + +struct input_source +{ + const char *name; + void (*init)(void); + void (*enable)(void); + void (*disable)(void); + + int (*append_callback)(input_callback func); + void (*delete_callback)(input_callback func); +}; + diff --git a/kc/core/kc_main.c b/kc/core/kc_main.c index 382b59a..9a84727 100644 --- a/kc/core/kc_main.c +++ b/kc/core/kc_main.c @@ -7,6 +7,7 @@ #include "pit8253.h" #include "cpu/irq.h" #include "video.h" +#include "i8042.h" #include <kernel/entry.h> #include <lib/kstdio.h> @@ -31,6 +32,7 @@ unsigned long kc_main(struct kc_boot_data *data) pic8259_init(); pit8253_timer_source.init(); pit8253_timer_source.set_frequency(1); + i8042_input_source.init(); task_init(); return 0; diff --git a/kc/core/task.c b/kc/core/task.c index 0bdeaac..6c73f89 100644 --- a/kc/core/task.c +++ b/kc/core/task.c @@ -6,6 +6,7 @@ #include "cpu/irq.h" #include "cpu/mmu.h" #include "pit8253.h" +#include "port.h" #include <stdatomic.h> #include <stdbool.h> @@ -67,6 +68,27 @@ static void idle_thread_entry(void) } } +#define PS2INPUT 0x60 +#define PS2STATUS 0x64 +#define PS2STATUS_IBF 0x1 + +static void keyboard_input_loop(void) +{ + bool has_bytes = true; + while (has_bytes) + { + has_bytes = inb(PS2STATUS) & PS2STATUS_IBF; + if (has_bytes) + { + kprintf("read byte from keyboard input: %hhd\n", inb(PS2INPUT)); + } + else + { + kprintf("no bytes in keyboard input\n"); + } + } +} + static void sleepy_thread_entry(void) { int thread_slept_count = 0; @@ -75,8 +97,10 @@ static void sleepy_thread_entry(void) { sleep_thread(1000000000); thread_slept_count++; - kprintf("thread slept for approximately %d seconds (just 1 more second please)\n", thread_slept_count); + //keyboard_input_loop(); } + + (void)thread_slept_count; } static void create_interrupt_stack(size_t size) @@ -304,8 +328,8 @@ static void sleep_thread_until(uint64_t nanoseconds) return; } - kprintf("time elapsed is now %ld\r\n", timesource->nanoseconds_elapsed()); - kprintf("thread will now sleep until %ld\r\n", nanoseconds); +// kprintf("time elapsed is now %ld\r\n", timesource->nanoseconds_elapsed()); +// kprintf("thread will now sleep until %ld\r\n", nanoseconds); current_thread->sleep_expiration = nanoseconds; current_thread->next = sleeping_threads; sleeping_threads = current_thread; @@ -370,7 +394,7 @@ static int sleeping_thread_callback(uint64_t nanoseconds) if (this_thread->sleep_expiration <= nanoseconds) { - kprintf("thread awakened: %p\n", this_thread); + //kprintf("thread awakened: %p\n", this_thread); this_thread->sleep_expiration = 0; unblock_thread(this_thread); } |
