aboutsummaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2015-03-11 15:10:52 +0100
committerAlex Auvolat <alex@adnab.me>2015-03-11 15:10:52 +0100
commita7ff74cdf2835625282491242ede57b05ceaa782 (patch)
tree77e2ad6c814c1812412a6816f0a4875e68dbfbf3 /src/kernel
parent5e9251bd48acafff575ed1c740e4dc05ec175508 (diff)
downloadkogata-a7ff74cdf2835625282491242ede57b05ceaa782.tar.gz
kogata-a7ff74cdf2835625282491242ede57b05ceaa782.zip
Add pckbd driver.
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/Makefile2
-rw-r--r--src/kernel/core/kmain.c4
-rw-r--r--src/kernel/dev/pckbd.c136
-rw-r--r--src/kernel/include/dev/pckbd.h7
4 files changed, 147 insertions, 2 deletions
diff --git a/src/kernel/Makefile b/src/kernel/Makefile
index 78aa057..1082b29 100644
--- a/src/kernel/Makefile
+++ b/src/kernel/Makefile
@@ -4,7 +4,7 @@ OBJ = core/loader.o core/dbglog.o \
core/frame.o core/paging.o core/freemem.o core/region.o core/kmalloc.o \
core/worker.o core/prng.o \
user/vfs.o user/nullfs.o user/process.o user/elf.o user/syscall.o user/ipc.o user/pager.o \
- dev/pci.o dev/pciide.o dev/v86.o dev/v86asm.o dev/vesa.o \
+ dev/pci.o dev/pciide.o dev/v86.o dev/v86asm.o dev/vesa.o dev/pckbd.o \
fs/iso9660.o
LIB = ../common/libc/libc.lib ../common/libkogata/libkogata.lib ../common/libalgo/libalgo.lib
diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c
index 96c3cc1..005f449 100644
--- a/src/kernel/core/kmain.c
+++ b/src/kernel/core/kmain.c
@@ -25,6 +25,7 @@
#include <prng.h>
+#include <dev/pckbd.h>
#include <dev/pci.h>
#include <dev/pciide.h>
#include <dev/vesa.h>
@@ -150,9 +151,10 @@ void kernel_init_stage2(void* data) {
TEST_PLACEHOLDER_AFTER_DEVFS;
// Scan for devices
+ pckbd_setup(iofs);
+ vesa_detect(iofs);
pci_setup();
pciide_detect(iofs);
- vesa_detect(iofs);
// Register FS drivers
register_iso9660_driver();
diff --git a/src/kernel/dev/pckbd.c b/src/kernel/dev/pckbd.c
new file mode 100644
index 0000000..a911b85
--- /dev/null
+++ b/src/kernel/dev/pckbd.c
@@ -0,0 +1,136 @@
+#include <string.h>
+
+#include <idt.h>
+#include <nullfs.h>
+#include <thread.h>
+
+#include <dev/pckbd.h>
+
+#include <proto/keyboard.h>
+
+#define PCKBD_BUF_LEN 16
+
+kbd_event_t pckbd_buf[PCKBD_BUF_LEN];
+int pckbd_buf_used = 0;
+bool pckbd_escaped = false;
+
+void irq1_handler(registers_t *regs) {
+ uint8_t scancode = inb(0x60);
+ if (scancode == 0xE0) {
+ pckbd_escaped = true;
+ } else {
+ kbd_event_t ev;
+ if (scancode & 0x80) {
+ if (pckbd_escaped) {
+ ev.scancode = scancode;
+ ev.type = KBD_EVENT_KEYRELEASE;
+ } else {
+ ev.scancode = scancode & 0x7F;
+ ev.type = KBD_EVENT_KEYRELEASE;
+ }
+ } else {
+ if (pckbd_escaped) {
+ ev.scancode = scancode | 0x80;
+ ev.type = KBD_EVENT_KEYPRESS;
+ } else {
+ ev.scancode = scancode;
+ ev.type = KBD_EVENT_KEYPRESS;
+ }
+ }
+
+ if (pckbd_buf_used < PCKBD_BUF_LEN) {
+ pckbd_buf[pckbd_buf_used++] = ev;
+
+ resume_on(&pckbd_buf);
+ }
+
+ pckbd_escaped = false;
+ }
+}
+
+// ---- VFS operations
+
+bool pckbd_open(fs_node_t *n, int mode);
+size_t pckbd_read(fs_handle_t *h, size_t offset, size_t len, char *buf);
+int pckbd_poll(fs_handle_t *h, void** out_wait_obj);
+void pckbd_close(fs_handle_t *h);
+int pckbd_ioctl(fs_handle_t *h, int command, void* data);
+bool pckbd_stat(fs_node_t *n, stat_t *st);
+
+fs_node_ops_t pckbd_ops = {
+ .open = pckbd_open,
+ .read = pckbd_read,
+ .write = 0,
+ .readdir = 0,
+ .poll = pckbd_poll,
+ .close = pckbd_close,
+ .ioctl = pckbd_ioctl,
+ .stat = pckbd_stat,
+ .walk = 0,
+ .delete = 0,
+ .move = 0,
+ .create = 0,
+ .dispose = 0,
+};
+
+void pckbd_setup(fs_t *iofs) {
+ idt_set_irq_handler(IRQ1, &irq1_handler);
+
+ nullfs_add_node(iofs, "/input/pckbd", 0, &pckbd_ops, 0);
+}
+
+bool pckbd_open(fs_node_t *n, int mode) {
+ return (mode == FM_READ);
+}
+
+size_t pckbd_read(fs_handle_t *h, size_t offset, size_t len, char *buf) {
+ int ret = 0;
+
+ int st = enter_critical(CL_NOINT);
+
+ while (len - ret >= sizeof(kbd_event_t) && pckbd_buf_used > 0) {
+ memcpy(buf + ret, &pckbd_buf[0], sizeof(kbd_event_t));
+
+ for (int i = 1; i < pckbd_buf_used; i++) {
+ pckbd_buf[i-1] = pckbd_buf[i];
+ }
+ pckbd_buf_used--;
+
+ ret += sizeof(kbd_event_t);
+ }
+
+ exit_critical(st);
+
+ return ret;
+}
+
+int pckbd_poll(fs_handle_t *h, void** out_wait_obj) {
+ *out_wait_obj = &pckbd_buf;
+
+ return (pckbd_buf_used > 0 ? SEL_READ : 0);
+}
+
+void pckbd_close(fs_handle_t *h) {
+ return; // nothing to do
+}
+
+int pckbd_ioctl(fs_handle_t *h, int command, void* data) {
+ if (command == IOCTL_KBD_SET_LEDS) {
+ uint8_t leds = (uint32_t)data & 0x07;
+
+ outb(0x60, leds);
+
+ return 1;
+ }
+ return 0;
+}
+
+bool pckbd_stat(fs_node_t *n, stat_t *st) {
+ st->type = FT_CHARDEV;
+ st->size = 0;
+ st->access = FM_READ;
+
+ return true;
+}
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/kernel/include/dev/pckbd.h b/src/kernel/include/dev/pckbd.h
new file mode 100644
index 0000000..7205bb1
--- /dev/null
+++ b/src/kernel/include/dev/pckbd.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <vfs.h>
+
+void pckbd_setup(fs_t *iofs);
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/