aboutsummaryrefslogtreecommitdiff
path: root/kernel/drivers/keyboard.c
blob: 79cd57986d3433257838f8a546abf6907fc5ed17 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// MIT License, Copyright (c) 2020 Marvin Borner

#include <cpu.h>
#include <def.h>
#include <errno.h>
#include <fs.h>
#include <interrupts.h>
#include <keyboard.h>
#include <mem.h>
#include <print.h>
#include <proc.h>
#include <stack.h>
#include <str.h>
#include <sys.h>

static struct event_keyboard *event = NULL;
static struct stack *queue = NULL;
static u32 dev_id = 0;

static int state = 0;
static int merged = 0;
static void keyboard_handler(struct regs *r)
{
	UNUSED(r);
	int scancode = inb(0x60);

	// TODO: Support more than two-byte scancodes
	if (scancode == 0xe0) {
		merged = 0xe0;
		state = 1;
		return;
	} else {
		merged = scancode << 8 | merged;
	}

	// TODO: "Merge" scancode to linux keycode?
	/* printf("%x %x = %x\n", scancode, state ? 0xe0 : 0, merged); */

	event = malloc(sizeof(*event));
	event->magic = KEYBOARD_MAGIC;
	event->press = (scancode & 0x80) == 0;
	event->scancode = event->press ? scancode : scancode & ~0x80;
	stack_push_bot(queue, event);

	state = 0;
	merged = 0;

	proc_enable_waiting(dev_id, PROC_WAIT_DEV);
}

/*static void keyboard_acknowledge(void)
{
	while (inb(0x60) != 0xfa)
		;
}

static void keyboard_rate(void)
{
	outb(0x60, 0xF3);
	keyboard_acknowledge();
	outb(0x60, 0x0); // Rate{00000} Delay{00} 0
}*/

static s32 keyboard_read(void *buf, u32 offset, u32 count, struct device *dev)
{
	UNUSED(dev);
	if (stack_empty(queue))
		return -EINVAL;

	struct event_keyboard *e = stack_pop(queue);
	memcpy(buf, (u8 *)e + offset, MIN(count, sizeof(*e)));
	free(e);
	return MIN(count, sizeof(*e));
}

static s32 keyboard_ready(void)
{
	return !stack_empty(queue);
}

void keyboard_reset(void)
{
	stack_clear(queue);
}

void keyboard_install(void)
{
	//keyboard_rate(); TODO: Fix keyboard rate?
	irq_install_handler(1, keyboard_handler);

	queue = stack_new();
	struct device *dev = zalloc(sizeof(*dev));
	dev->name = strdup("kbd");
	dev->type = DEV_CHAR;
	dev->read = keyboard_read;
	dev->ready = keyboard_ready;
	device_add(dev);
	dev_id = dev->id;
}