Orion
Barry Keyboard/Mouse drivers + POSIX names for structs 1628fcf (2 years, 4 months ago)diff --git a/drivers/keyboard/keyboard.c b/drivers/keyboard/keyboard.c new file mode 100644 index 0000000..5ef3c6f --- /dev/null +++ b/drivers/keyboard/keyboard.c @@ -0,0 +1,108 @@ +/* + * This file implements a keyboard driver. It generates the /dev/kbd device + * file, which can be read and returns a structure of the keyboard data. This + * driver produces raw keyboard data, not parsed text. + */ + +#include <sys/kbd.h> +#include "../drivers.h" +#include "../../task/task.h" +#include "../../proc/proc.h" +#include "../../io.h" + +void tty_keypress(unsigned char key); +size_t kbd_read(File *file, char *buf, size_t size, off_t offset); + +FileOps kbdFileOps = { + .read = kbd_read, +}; + +Driver kbdDriver = { + .major = 10, + .ops = &kbdFileOps, + .next = NULL, +}; + +TaskQueue keyWait; + +/* Ring buffer for keys */ +struct KeyBuffer { + int start, end; + char key[1024]; +} keyBuf; + +/* Add a key to the key buffer */ +static void +add_to_buf(char key) +{ + /* No more space in buffer */ + int start = (keyBuf.start + sizeof(keyBuf.key) - 1) + % sizeof(keyBuf.key); + if (keyBuf.end == start) + return; + + keyBuf.key[keyBuf.end] = key; + keyBuf.end++; + keyBuf.end %= sizeof(keyBuf.key); +} + +/* Get a key from the key buffer */ +static char +get_from_buf(void) +{ + /* Nothing to read */ + if (keyBuf.start == keyBuf.end) + return 0x00; + + char key = keyBuf.key[keyBuf.start]; + keyBuf.start++; + keyBuf.start %= sizeof(keyBuf.key); + return key; +} + +/* Handle the keyboard interrupt */ +static void +keyboard_handler(InterruptFrame *frame) +{ + unsigned char key; + int i; + for (i = 0; i < 1000; i++) { + if ((inb(0x64) & 1) == 0) + continue; + key = inb(0x60); + break; + } + if (i == 1000) + return; + add_to_buf(key); + tty_keypress(key); + + for (Task *tmp = keyWait.start; tmp; tmp = tmp->next) + unblock_task(pop_from_queue(&keyWait)); +} + +/* Initialise the keyboard */ +void +init_kbd(void) +{ + register_driver(&kbdDriver); + mknod("/dev/kbd", S_IFCHR | 0666, MKDEV(kbdDriver.major, 0)); + register_interrupt(1, keyboard_handler); +} + +size_t +kbd_read(File *file, char *buf, size_t size, off_t offset) +{ + char c; + size_t count = 0; + while (count < size) { + c = get_from_buf(); + if (!c) { + add_to_queue(&keyWait, current); + block_task(WAITING_FOR_IO); + } + *(buf + count) = c; + count++; + } + return count; +}