-
Notifications
You must be signed in to change notification settings - Fork 0
/
keyboard.c
493 lines (442 loc) · 10.5 KB
/
keyboard.c
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
#include "keyboard.h"
#include "io.h"
#include "interrupt.h"
#include "common.h"
#include "pic.h"
//calls pic_acknowledge function
#define KBD_DATA_PORT 0x60
#define KBD_BUFFER_SIZE 512
/* Alphabet */
#define KBD_SC_A 0x1e
#define KBD_SC_B 0x30
#define KBD_SC_C 0x2e
#define KBD_SC_D 0x20
#define KBD_SC_E 0x12
#define KBD_SC_F 0x21
#define KBD_SC_G 0x22
#define KBD_SC_H 0x23
#define KBD_SC_I 0x17
#define KBD_SC_J 0x24
#define KBD_SC_K 0x25
#define KBD_SC_L 0x26
#define KBD_SC_M 0x32
#define KBD_SC_N 0x31
#define KBD_SC_O 0x18
#define KBD_SC_P 0x19
#define KBD_SC_Q 0x10
#define KBD_SC_R 0x13
#define KBD_SC_S 0x1f
#define KBD_SC_T 0x14
#define KBD_SC_U 0x16
#define KBD_SC_V 0x2f
#define KBD_SC_W 0x11
#define KBD_SC_X 0x2d
#define KBD_SC_Y 0x15
#define KBD_SC_Z 0x2c
/* Numeric keys */
#define KBD_SC_1 0x02
#define KBD_SC_2 0x03
#define KBD_SC_3 0x04
#define KBD_SC_4 0x05
#define KBD_SC_5 0x06
#define KBD_SC_6 0x07
#define KBD_SC_7 0x08
#define KBD_SC_8 0x09
#define KBD_SC_9 0x0a
#define KBD_SC_0 0x0b
/* Special keys */
#define KBD_SC_ENTER 0x1c
#define KBD_SC_SPACE 0x39
#define KBD_SC_BS 0x0e
#define KBD_SC_LSHIFT 0x2a
#define KBD_SC_RSHIFT 0x36
#define KBD_SC_DASH 0x0c
#define KBD_SC_EQUALS 0x0d
#define KBD_SC_LBRACKET 0x1a
#define KBD_SC_RBRACKET 0x1b
#define KBD_SC_BSLASH 0x2b
#define KBD_SC_SCOLON 0x27
#define KBD_SC_QUOTE 0x28
#define KBD_SC_COMMA 0x33
#define KBD_SC_DOT 0x34
#define KBD_SC_FSLASH 0x35
#define KBD_SC_TILDE 0x29
#define KBD_SC_CAPSLOCK 0x3a
#define KBD_SC_TAB 0x0f
static uint8_t is_lshift_down = 0;
static uint8_t is_rshift_down = 0;
static uint8_t is_caps_lock_pressed = 0;
struct kbd_buffer {
uint8_t buffer[KBD_BUFFER_SIZE];
uint8_t *head;
uint8_t *tail;
uint32_t count;
};
typedef struct kbd_buffer kbd_buffer_t;
static kbd_buffer_t kbd_buffer;
static vnode_t kbd_vnode;
static vnodeops_t kbd_vnodeops;
/* function declarations */
static char kbd_scan_code_to_ascii(uint8_t sc);
static uint8_t kbd_read_scan_code(void);
static void keyboard_handle_interrupt(cpu_state_t state,
idt_info_t info,
stack_state_t exec)
{
UNUSED_ARGUMENT(state);
UNUSED_ARGUMENT(info);
UNUSED_ARGUMENT(exec);
/* DO NOT MODIFY kbd_buffer.head in this function,
* it will introcude race conditions!
*/
if (kbd_buffer.count < KBD_BUFFER_SIZE) {
*kbd_buffer.tail++ = kbd_read_scan_code();
++kbd_buffer.count;
if (kbd_buffer.tail == kbd_buffer.buffer + KBD_BUFFER_SIZE) {
kbd_buffer.tail = kbd_buffer.buffer;
}
}
pic_acknowledge();
}
static int kbd_open(vnode_t *n)
{
UNUSED_ARGUMENT(n);
return 0;
}
static int kbd_lookup(vnode_t *d, char const *n, vnode_t *o)
{
UNUSED_ARGUMENT(d);
UNUSED_ARGUMENT(n);
UNUSED_ARGUMENT(o);
return -1;
}
static int kbd_read(vnode_t *n, void *buf, size_t count)
{
UNUSED_ARGUMENT(n);
/* DO NOT MODIFY kbd_buffer.tail or kbd_buffer.count in this function,
* it will introcude race conditions!
*/
char ch;
int i = 0;
char *b = buf;
while (count > 0) {
while (kbd_buffer.head != kbd_buffer.tail) {
ch = kbd_scan_code_to_ascii(*kbd_buffer.head++);
if (kbd_buffer.head == kbd_buffer.buffer + KBD_BUFFER_SIZE) {
kbd_buffer.head = kbd_buffer.buffer;
}
if (ch != -1) {
b[i] = ch;
++i;
--count;
}
}
}
return i;
}
static int kbd_write(vnode_t *n, char const *name, size_t count)
{
UNUSED_ARGUMENT(n);
UNUSED_ARGUMENT(name);
UNUSED_ARGUMENT(count);
return -1;
}
static int kbd_getattr(vnode_t *n, vattr_t *a)
{
UNUSED_ARGUMENT(n);
UNUSED_ARGUMENT(a);
return -1;
}
uint32_t kbd_init(void)
{
register_interrupt_handler(KBD_INT_IDX, keyboard_handle_interrupt);
kbd_buffer.count = 0;
kbd_buffer.head = kbd_buffer.buffer;
kbd_buffer.tail = kbd_buffer.buffer;
kbd_vnodeops.vn_open = &kbd_open;
kbd_vnodeops.vn_lookup = &kbd_lookup;
kbd_vnodeops.vn_read = &kbd_read;
kbd_vnodeops.vn_write = &kbd_write;
kbd_vnodeops.vn_getattr = &kbd_getattr;
kbd_vnode.v_op = &kbd_vnodeops;
kbd_vnode.v_data = 0;
return 0;
}
int kbd_get_vnode(vnode_t *out)
{
out->v_op = kbd_vnode.v_op;
out->v_data = kbd_vnode.v_data;
return 0;
}
static void toggle_left_shift(void)
{
is_lshift_down = is_lshift_down ? 0 : 1;
}
static void toggle_right_shift(void)
{
is_rshift_down = is_rshift_down ? 0 : 1;
}
static void toggle_caps_lock(void)
{
is_caps_lock_pressed = is_caps_lock_pressed ? 0 : 1;
}
static char handle_caps_lock(uint8_t ch)
{
if (ch >= 'a' && ch <= 'z') {
return ch + 'A' - 'a';
}
return ch;
}
static char handle_shift(uint8_t ch)
{
/* Alphabetic characters */
if (ch >= 'a' && ch <= 'z') {
return ch + 'A' - 'a';
}
/* Number characters */
switch (ch) {
case '0':
return ')';
case '1':
return '!';
case '2':
return '@';
case '3':
return '#';
case '4':
return '$';
case '5':
return '%';
case '6':
return '^';
case '7':
return '&';
case '8':
return '*';
case '9':
return '(';
default:
break;
}
/* Special charachters */
switch (ch) {
case '-':
return '_';
case '=':
return '+';
case '[':
return '{';
case ']':
return '}';
case '\\':
return '|';
case ';':
return ':';
case '\'':
return '\"';
case ',':
return '<';
case '.':
return '>';
case '/':
return '?';
case '`':
return '~';
}
return ch;
}
uint8_t kbd_read_scan_code(void)
{
return inb(KBD_DATA_PORT);
}
static char kbd_scan_code_to_ascii(uint8_t scan_code)
{
char ch = -1;
if (scan_code & 0x80) {
scan_code &= 0x7F; /* clear the bit set by key break */
switch (scan_code) {
case KBD_SC_LSHIFT:
toggle_left_shift();
break;
case KBD_SC_RSHIFT:
toggle_right_shift();
break;
case KBD_SC_CAPSLOCK:
toggle_caps_lock();
break;
default:
break;
}
return -1;
}
switch (scan_code) {
case KBD_SC_A:
ch = 'a';
break;
case KBD_SC_B:
ch = 'b';
break;
case KBD_SC_C:
ch = 'c';
break;
case KBD_SC_D:
ch = 'd';
break;
case KBD_SC_E:
ch = 'e';
break;
case KBD_SC_F:
ch = 'f';
break;
case KBD_SC_G:
ch = 'g';
break;
case KBD_SC_H:
ch = 'h';
break;
case KBD_SC_I:
ch = 'i';
break;
case KBD_SC_J:
ch = 'j';
break;
case KBD_SC_K:
ch = 'k';
break;
case KBD_SC_L:
ch = 'l';
break;
case KBD_SC_M:
ch = 'm';
break;
case KBD_SC_N:
ch = 'n';
break;
case KBD_SC_O:
ch = 'o';
break;
case KBD_SC_P:
ch = 'p';
break;
case KBD_SC_Q:
ch = 'q';
break;
case KBD_SC_R:
ch = 'r';
break;
case KBD_SC_S:
ch = 's';
break;
case KBD_SC_T:
ch = 't';
break;
case KBD_SC_U:
ch = 'u';
break;
case KBD_SC_V:
ch = 'v';
break;
case KBD_SC_W:
ch = 'w';
break;
case KBD_SC_X:
ch = 'x';
break;
case KBD_SC_Y:
ch = 'y';
break;
case KBD_SC_Z:
ch = 'z';
break;
case KBD_SC_0:
ch = '0';
break;
case KBD_SC_1:
ch = '1';
break;
case KBD_SC_2:
ch = '2';
break;
case KBD_SC_3:
ch = '3';
break;
case KBD_SC_4:
ch = '4';
break;
case KBD_SC_5:
ch = '5';
break;
case KBD_SC_6:
ch = '6';
break;
case KBD_SC_7:
ch = '7';
break;
case KBD_SC_8:
ch = '8';
break;
case KBD_SC_9:
ch = '9';
break;
case KBD_SC_ENTER:
ch = '\n';
break;
case KBD_SC_SPACE:
ch = ' ';
break;
case KBD_SC_BS:
ch = 8;
break;
case KBD_SC_DASH:
ch = '-';
break;
case KBD_SC_EQUALS:
ch = '=';
break;
case KBD_SC_LBRACKET:
ch = '[';
break;
case KBD_SC_RBRACKET:
ch = ']';
break;
case KBD_SC_BSLASH:
ch = '\\';
break;
case KBD_SC_SCOLON:
ch = ';';
break;
case KBD_SC_QUOTE:
ch = '\'';
break;
case KBD_SC_COMMA:
ch = ',';
break;
case KBD_SC_DOT:
ch = '.';
break;
case KBD_SC_FSLASH:
ch = '/';
break;
case KBD_SC_TILDE:
ch = '`';
break;
case KBD_SC_TAB:
ch = '\t';
break;
case KBD_SC_LSHIFT:
toggle_left_shift();
break;
case KBD_SC_RSHIFT:
toggle_right_shift();
break;
default:
return -1;
}
if (is_caps_lock_pressed) {
ch = handle_caps_lock(ch);
}
if (is_lshift_down || is_rshift_down) {
ch = handle_shift(ch);
}
return ch;
}