From a7ff74cdf2835625282491242ede57b05ceaa782 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Wed, 11 Mar 2015 15:10:52 +0100 Subject: Add pckbd driver. --- README.md | 2 +- src/common/include/proto/keyboard.h | 20 ++++++ src/kernel/Makefile | 2 +- src/kernel/core/kmain.c | 4 +- src/kernel/dev/pckbd.c | 136 ++++++++++++++++++++++++++++++++++++ src/kernel/include/dev/pckbd.h | 7 ++ src/sysbin/giosrv/main.c | 44 +++++++++++- 7 files changed, 210 insertions(+), 5 deletions(-) create mode 100644 src/common/include/proto/keyboard.h create mode 100644 src/kernel/dev/pckbd.c create mode 100644 src/kernel/include/dev/pckbd.h 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 +#include + +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 +#include #include #include #include @@ -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 + +#include +#include +#include + +#include + +#include + +#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 + +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 #include +#include + #include +// ---- 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 :*/ -- cgit v1.2.3