summaryrefslogtreecommitdiff
path: root/kc
diff options
context:
space:
mode:
authorAda Christine <adachristine18@gmail.com>2023-02-14 00:02:55 +0000
committerAda Christine <adachristine18@gmail.com>2023-02-14 00:02:55 +0000
commitec04c40823f1a4265be8a6f81cbf5776dc2b2495 (patch)
treef4a5f5e2301ec3ac15773fadf658315689a74ceb /kc
parent6cdf57afc0a1da4abec33527cc70626d704ba565 (diff)
ps2 driver
Diffstat (limited to 'kc')
-rw-r--r--kc/core/Makefile2
-rw-r--r--kc/core/i8042.c183
-rw-r--r--kc/core/i8042.h17
-rw-r--r--kc/core/input.h21
-rw-r--r--kc/core/kc_main.c2
-rw-r--r--kc/core/task.c32
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);
}