aboutsummaryrefslogtreecommitdiff
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
parent5e9251bd48acafff575ed1c740e4dc05ec175508 (diff)
downloadkogata-a7ff74cdf2835625282491242ede57b05ceaa782.tar.gz
kogata-a7ff74cdf2835625282491242ede57b05ceaa782.zip
Add pckbd driver.
-rw-r--r--README.md2
-rw-r--r--src/common/include/proto/keyboard.h20
-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
-rw-r--r--src/sysbin/giosrv/main.c44
7 files changed, 210 insertions, 5 deletions
diff --git a/README.md b/README.md
index 742cc37..441ca65 100644
--- a/README.md
+++ b/README.md
@@ -112,7 +112,7 @@ running the tests):
### Plans for soon
-* Write device drivers : VESA, keyboard, FAT (or EXT2 ?)
+* Write device drivers : keyboard, FAT (or EXT2 ?)
* Work on userland : init, terminal emulator, shell
* GUI server with help from kernel for framebuffer management
diff --git a/src/common/include/proto/keyboard.h b/src/common/include/proto/keyboard.h
new file mode 100644
index 0000000..044946d
--- /dev/null
+++ b/src/common/include/proto/keyboard.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <stdint.h>
+#include <stddef.h>
+
+typedef struct {
+ uint16_t scancode;
+ uint16_t type;
+} kbd_event_t;
+
+#define KBD_EVENT_KEYRELEASE 0
+#define KBD_EVENT_KEYPRESS 1
+
+#define IOCTL_KBD_SET_LEDS 10
+
+#define KBD_LED_SCROLLLOCK 1
+#define KBD_LED_NUMLOCK 1
+#define KBD_LED_CAPSLOCK 4
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/
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 :*/
diff --git a/src/sysbin/giosrv/main.c b/src/sysbin/giosrv/main.c
index b38d1c7..c161bd6 100644
--- a/src/sysbin/giosrv/main.c
+++ b/src/sysbin/giosrv/main.c
@@ -6,8 +6,12 @@
#include <debug.h>
#include <user_region.h>
+#include <proto/keyboard.h>
+
#include <gip.h>
+// ---- GIP server
+
typedef struct {
fb_info_t mode;
fd_t fd;
@@ -37,24 +41,52 @@ gip_handler_callbacks_t giosrv_cb = {
.fd_error = fd_error,
};
+giosrv_t srv;
+
+// ---- KBD listener
+
+typedef struct {
+ fd_t fd;
+ kbd_event_t ev;
+} kbd_listner_t;
+
+kbd_listner_t kbd;
+
+void kbd_handle_event(mainloop_fd_t *fd);
+void kbd_on_error(mainloop_fd_t *fd);
+
int main(int argc, char **argv) {
dbg_print("[giosrv] Starting up.\n");
- giosrv_t srv;
+ // ---- Keyboard setup
+ kbd.fd = open("io:/input/pckbd", FM_READ);
+ if (kbd.fd == 0) PANIC("Could not open keyboard");
+
+ mainloop_fd_t kh;
+ memset(&kh, 0, sizeof(kh));
+ kh.fd = kbd.fd;
+ kh.on_error = kbd_on_error;
+ mainloop_expect(&kh, &kbd.ev, sizeof(kbd_event_t), kbd_handle_event);
+
+ mainloop_add_fd(&kh);
+
+ // ---- VESA setup
srv.fd = open("io:/display/vesa", FM_IOCTL | FM_READ | FM_WRITE | FM_MMAP);
if (srv.fd == 0) PANIC("Could not open fbdev");
-
int r = ioctl(srv.fd, IOCTL_FB_GET_INFO, &srv.mode);
ASSERT(r == 1);
dbg_printf("[giosrv] Running on FB %dx%d\n", srv.mode.width, srv.mode.height);
+ // ---- GIP server setup
gip_handler_t *h = new_gip_handler(&giosrv_cb, &srv);
ASSERT(h != 0);
h->mainloop_item.fd = 1;
mainloop_add_fd(&h->mainloop_item);
+
+ // ---- Enter main loop
mainloop_run();
dbg_printf("[giosrv] Main loop exited, terminating.\n");
@@ -120,4 +152,12 @@ void fd_error(gip_handler_t *h) {
// TODO
}
+void kbd_handle_event(mainloop_fd_t *fd) {
+ // TODO
+}
+
+void kbd_on_error(mainloop_fd_t *fd) {
+ // TODO
+}
+
/* vim: set ts=4 sw=4 tw=0 noet :*/