forked from ReKernel/ReKernel
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathkeyboard.c
More file actions
executable file
·95 lines (81 loc) · 2.43 KB
/
keyboard.c
File metadata and controls
executable file
·95 lines (81 loc) · 2.43 KB
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
#include "keyboard.h"
#include "idt.h"
#include "pic.h"
#include "vga.h"
#define KB_DATA_PORT 0x60
#define KB_STATUS_PORT 0x64
/* US QWERTY scancode set 1 — 0 = non-printable */
static const char sc_ascii[58] = {
0, 0,
'1','2','3','4','5','6','7','8','9','0','-','=','\b',
'\t','q','w','e','r','t','y','u','i','o','p','[',']','\n',
0, /* left ctrl */
'a','s','d','f','g','h','j','k','l',';','\'','`',
0, /* left shift */
'\\','z','x','c','v','b','n','m',',','.','/',
0, /* right shift */
'*',
0, /* alt */
' '
};
static const char sc_ascii_shift[58] = {
0, 0,
'!','@','#','$','%','^','&','*','(',')','_','+','\b',
'\t','Q','W','E','R','T','Y','U','I','O','P','{','}','\n',
0,
'A','S','D','F','G','H','J','K','L',':','"','~',
0,
'|','Z','X','C','V','B','N','M','<','>','?',
0,'*',0,' '
};
/* Ring buffer */
#define KB_BUF_SIZE 256
static volatile char kb_buf[KB_BUF_SIZE];
static volatile uint32_t kb_head = 0;
static volatile uint32_t kb_tail = 0;
static uint8_t shift_held = 0;
static uint8_t caps_lock = 0;
static void keyboard_irq_handler(registers_t *regs) {
(void)regs;
/* Always read the scancode to clear the interrupt */
uint8_t sc = inb(KB_DATA_PORT);
/* Key release */
if (sc & 0x80) {
uint8_t rel = sc & 0x7F;
if (rel == 0x2A || rel == 0x36) shift_held = 0;
return;
}
if (sc == 0x2A || sc == 0x36) { shift_held = 1; return; }
if (sc == 0x3A) { caps_lock = !caps_lock; return; }
if (sc < 58 && sc_ascii[sc]) {
char c = shift_held ? sc_ascii_shift[sc] : sc_ascii[sc];
if (caps_lock) {
if (c >= 'a' && c <= 'z') c -= 32;
else if (c >= 'A' && c <= 'Z') c += 32;
}
uint32_t next = (kb_head + 1) % KB_BUF_SIZE;
if (next != kb_tail) {
kb_buf[kb_head] = c;
kb_head = next;
}
}
}
void keyboard_init(void) {
/* Drain stale bytes from keyboard controller before enabling IRQ */
while (inb(KB_STATUS_PORT) & 0x01)
inb(KB_DATA_PORT);
idt_register_handler(33, keyboard_irq_handler);
pic_unmask_irq(1);
}
char keyboard_poll(void) {
if (kb_head == kb_tail) return 0;
char c = kb_buf[kb_tail];
kb_tail = (kb_tail + 1) % KB_BUF_SIZE;
return c;
}
char keyboard_getchar(void) {
char c;
while (!(c = keyboard_poll()))
__asm__ volatile ("hlt");
return c;
}