BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / blob / 1628fcfdfdf2978ed9ccac96ee7d13bb3dc43a01 / drivers / keyboard / keyboard.c

// Related

Orion

Barry Keyboard/Mouse drivers + POSIX names for structs 1628fcf (2 years, 4 months ago)
/*
 * 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;
}