Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/Assertions.h>
28#include <AK/ByteBuffer.h>
29#include <AK/Types.h>
30#include <Kernel/Arch/i386/CPU.h>
31#include <Kernel/Devices/KeyboardDevice.h>
32#include <Kernel/TTY/VirtualConsole.h>
33#include <LibBareMetal/IO.h>
34
35//#define KEYBOARD_DEBUG
36
37namespace Kernel {
38
39#define IRQ_KEYBOARD 1
40#define I8042_BUFFER 0x60
41#define I8042_STATUS 0x64
42#define I8042_ACK 0xFA
43#define I8042_BUFFER_FULL 0x01
44#define I8042_WHICH_BUFFER 0x20
45#define I8042_MOUSE_BUFFER 0x20
46#define I8042_KEYBOARD_BUFFER 0x00
47
48char* map;
49char* shift_map;
50char* alt_map;
51char* altgr_map;
52
53static const char en_map[0x80] = {
54 0,
55 '\033',
56 '1',
57 '2',
58 '3',
59 '4',
60 '5',
61 '6',
62 '7',
63 '8',
64 '9',
65 '0',
66 '-',
67 '=',
68 0x08,
69 '\t',
70 'q',
71 'w',
72 'e',
73 'r',
74 't',
75 'y',
76 'u',
77 'i',
78 'o',
79 'p',
80 '[',
81 ']',
82 '\n',
83 0,
84 'a',
85 's',
86 'd',
87 'f',
88 'g',
89 'h',
90 'j',
91 'k',
92 'l',
93 ';',
94 '\'',
95 '`',
96 0,
97 '\\',
98 'z',
99 'x',
100 'c',
101 'v',
102 'b',
103 'n',
104 'm',
105 ',',
106 '.',
107 '/',
108 0,
109 '*',
110 0,
111 ' ',
112 0,
113 0,
114 //60
115 0,
116 0,
117 0,
118 0,
119 0,
120 0,
121 0,
122 0,
123 0,
124 0,
125 //70
126 0,
127 0,
128 0,
129 0,
130 '-',
131 0,
132 0,
133 0,
134 '+',
135 0,
136 //80
137 0,
138 0,
139 0,
140 0,
141 0,
142 0,
143 '\\',
144 0,
145 0,
146 0,
147};
148
149static const char en_shift_map[0x80] = {
150 0,
151 '\033',
152 '!',
153 '@',
154 '#',
155 '$',
156 '%',
157 '^',
158 '&',
159 '*',
160 '(',
161 ')',
162 '_',
163 '+',
164 0x08,
165 '\t',
166 'Q',
167 'W',
168 'E',
169 'R',
170 'T',
171 'Y',
172 'U',
173 'I',
174 'O',
175 'P',
176 '{',
177 '}',
178 '\n',
179 0,
180 'A',
181 'S',
182 'D',
183 'F',
184 'G',
185 'H',
186 'J',
187 'K',
188 'L',
189 ':',
190 '"',
191 '~',
192 0,
193 '|',
194 'Z',
195 'X',
196 'C',
197 'V',
198 'B',
199 'N',
200 'M',
201 '<',
202 '>',
203 '?',
204 0,
205 '*',
206 0,
207 ' ',
208 0,
209 0,
210 //60
211 0,
212 0,
213 0,
214 0,
215 0,
216 0,
217 0,
218 0,
219 0,
220 0,
221 //70
222 0,
223 0,
224 0,
225 0,
226 '-',
227 0,
228 0,
229 0,
230 '+',
231 0,
232 //80
233 0,
234 0,
235 0,
236 0,
237 0,
238 0,
239 '|',
240 0,
241 0,
242 0,
243};
244
245static const char numpad_map[13] = { '7', '8', '9', 0, '4', '5', '6', 0, '1', '2', '3', '0', ',' };
246
247static const KeyCode unshifted_key_map[0x80] = {
248 Key_Invalid,
249 Key_Escape,
250 Key_1,
251 Key_2,
252 Key_3,
253 Key_4,
254 Key_5,
255 Key_6,
256 Key_7,
257 Key_8,
258 Key_9,
259 Key_0,
260 Key_Minus,
261 Key_Equal,
262 Key_Backspace,
263 Key_Tab, //15
264 Key_Q,
265 Key_W,
266 Key_E,
267 Key_R,
268 Key_T,
269 Key_Y,
270 Key_U,
271 Key_I,
272 Key_O,
273 Key_P,
274 Key_LeftBracket,
275 Key_RightBracket,
276 Key_Return, // 28
277 Key_Control, // 29
278 Key_A,
279 Key_S,
280 Key_D,
281 Key_F,
282 Key_G,
283 Key_H,
284 Key_J,
285 Key_K,
286 Key_L,
287 Key_Semicolon,
288 Key_Apostrophe,
289 Key_Backtick,
290 Key_LeftShift, // 42
291 Key_Backslash,
292 Key_Z,
293 Key_X,
294 Key_C,
295 Key_V,
296 Key_B,
297 Key_N,
298 Key_M,
299 Key_Comma,
300 Key_Period,
301 Key_Slash,
302 Key_RightShift, // 54
303 Key_Asterisk,
304 Key_Alt, // 56
305 Key_Space, // 57
306 Key_CapsLock, // 58
307 Key_F1,
308 Key_F2,
309 Key_F3,
310 Key_F4,
311 Key_F5,
312 Key_F6,
313 Key_F7,
314 Key_F8,
315 Key_F9,
316 Key_F10,
317 Key_NumLock,
318 Key_Invalid, // 70
319 Key_Home,
320 Key_Up,
321 Key_PageUp,
322 Key_Minus,
323 Key_Left,
324 Key_Invalid,
325 Key_Right, // 77
326 Key_Plus,
327 Key_End,
328 Key_Down, // 80
329 Key_PageDown,
330 Key_Invalid,
331 Key_Delete, // 83
332 Key_Invalid,
333 Key_Invalid,
334 Key_Backslash,
335 Key_F11,
336 Key_F12,
337 Key_Invalid,
338 Key_Invalid,
339 Key_Logo,
340};
341
342static const KeyCode shifted_key_map[0x100] = {
343 Key_Invalid,
344 Key_Escape,
345 Key_ExclamationPoint,
346 Key_AtSign,
347 Key_Hashtag,
348 Key_Dollar,
349 Key_Percent,
350 Key_Circumflex,
351 Key_Ampersand,
352 Key_Asterisk,
353 Key_LeftParen,
354 Key_RightParen,
355 Key_Underscore,
356 Key_Plus,
357 Key_Backspace,
358 Key_Tab,
359 Key_Q,
360 Key_W,
361 Key_E,
362 Key_R,
363 Key_T,
364 Key_Y,
365 Key_U,
366 Key_I,
367 Key_O,
368 Key_P,
369 Key_LeftBrace,
370 Key_RightBrace,
371 Key_Return,
372 Key_Control,
373 Key_A,
374 Key_S,
375 Key_D,
376 Key_F,
377 Key_G,
378 Key_H,
379 Key_J,
380 Key_K,
381 Key_L,
382 Key_Colon,
383 Key_DoubleQuote,
384 Key_Tilde,
385 Key_LeftShift, // 42
386 Key_Pipe,
387 Key_Z,
388 Key_X,
389 Key_C,
390 Key_V,
391 Key_B,
392 Key_N,
393 Key_M,
394 Key_LessThan,
395 Key_GreaterThan,
396 Key_QuestionMark,
397 Key_RightShift, // 54
398 Key_Asterisk,
399 Key_Alt,
400 Key_Space, // 57
401 Key_CapsLock, // 58
402 Key_F1,
403 Key_F2,
404 Key_F3,
405 Key_F4,
406 Key_F5,
407 Key_F6,
408 Key_F7,
409 Key_F8,
410 Key_F9,
411 Key_F10,
412 Key_NumLock,
413 Key_Invalid, // 70
414 Key_Home,
415 Key_Up,
416 Key_PageUp,
417 Key_Minus,
418 Key_Left,
419 Key_Invalid,
420 Key_Right, // 77
421 Key_Plus,
422 Key_End,
423 Key_Down, // 80
424 Key_PageDown,
425 Key_Invalid,
426 Key_Delete, // 83
427 Key_Invalid,
428 Key_Invalid,
429 Key_Pipe,
430 Key_F11,
431 Key_F12,
432 Key_Invalid,
433 Key_Invalid,
434 Key_Logo,
435};
436
437static const KeyCode numpad_key_map[13] = { Key_7, Key_8, Key_9, Key_Invalid, Key_4, Key_5, Key_6, Key_Invalid, Key_1, Key_2, Key_3, Key_0, Key_Comma };
438
439void KeyboardDevice::key_state_changed(u8 raw, bool pressed)
440{
441 KeyCode key = (m_modifiers & Mod_Shift) ? shifted_key_map[raw] : unshifted_key_map[raw];
442 char character = (m_modifiers & Mod_Shift) ? shift_map[raw] : (m_modifiers & Mod_Alt) ? alt_map[raw] : (m_modifiers & Mod_AltGr) ? altgr_map[raw] : map[raw];
443
444 if (key == Key_NumLock && pressed)
445 m_num_lock_on = !m_num_lock_on;
446
447 if (m_num_lock_on && !m_has_e0_prefix) {
448 if (raw >= 0x47 && raw <= 0x53) {
449 u8 index = raw - 0x47;
450 KeyCode newKey = numpad_key_map[index];
451
452 if (newKey != Key_Invalid) {
453 key = newKey;
454 character = numpad_map[index];
455 }
456 }
457 } else {
458 if (m_has_e0_prefix) {
459 if (key == Key_Slash) {
460 character = '/'; // On Turkish-QWERTY Keyboard Key_Slash mapped to '.' char, if e0 prefix is true remap to '/' char
461 }
462 }
463 }
464
465 if (key == Key_CapsLock && pressed)
466 m_caps_lock_on = !m_caps_lock_on;
467
468 if (m_caps_lock_on && (m_modifiers == 0 || m_modifiers == Mod_Shift)) {
469 if (character >= 'a' && character <= 'z')
470 character &= ~0x20;
471 else if (character >= 'A' && character <= 'Z')
472 character |= 0x20;
473 }
474
475 Event event;
476 event.key = key;
477 event.character = static_cast<u8>(character);
478 event.flags = m_modifiers;
479 if (pressed)
480 event.flags |= Is_Press;
481 if (m_client)
482 m_client->on_key_pressed(event);
483 m_queue.enqueue(event);
484
485 m_has_e0_prefix = false;
486}
487
488void KeyboardDevice::handle_irq(RegisterState&)
489{
490 for (;;) {
491 u8 status = IO::in8(I8042_STATUS);
492 if (!(((status & I8042_WHICH_BUFFER) == I8042_KEYBOARD_BUFFER) && (status & I8042_BUFFER_FULL)))
493 return;
494 u8 raw = IO::in8(I8042_BUFFER);
495 u8 ch = raw & 0x7f;
496 bool pressed = !(raw & 0x80);
497
498 if (raw == 0xe0) {
499 m_has_e0_prefix = true;
500 return;
501 }
502
503#ifdef KEYBOARD_DEBUG
504 dbgprintf("Keyboard::handle_irq: %b %s\n", ch, pressed ? "down" : "up");
505#endif
506 switch (ch) {
507 case 0x38:
508 if (m_has_e0_prefix)
509 update_modifier(Mod_AltGr, pressed);
510 else
511 update_modifier(Mod_Alt, pressed);
512 break;
513 case 0x1d:
514 update_modifier(Mod_Ctrl, pressed);
515 break;
516 case 0x5b:
517 update_modifier(Mod_Logo, pressed);
518 break;
519 case 0x2a:
520 case 0x36:
521 update_modifier(Mod_Shift, pressed);
522 break;
523 }
524 switch (ch) {
525 case I8042_ACK:
526 break;
527 default:
528 if (m_modifiers & Mod_Alt) {
529 switch (map[ch]) {
530 case '1':
531 case '2':
532 case '3':
533 case '4':
534 VirtualConsole::switch_to(map[ch] - '0' - 1);
535 break;
536 default:
537 key_state_changed(ch, pressed);
538 break;
539 }
540 } else {
541 key_state_changed(ch, pressed);
542 }
543 }
544 }
545}
546
547static KeyboardDevice* s_the;
548
549KeyboardDevice& KeyboardDevice::the()
550{
551 ASSERT(s_the);
552 return *s_the;
553}
554
555KeyboardDevice::KeyboardDevice()
556 : IRQHandler(IRQ_KEYBOARD)
557 , CharacterDevice(85, 1)
558{
559 s_the = this;
560
561 KeyboardDevice::set_maps(en_map, en_shift_map, en_map, en_map);
562
563 // Empty the buffer of any pending data.
564 // I don't care what you've been pressing until now!
565 while (IO::in8(I8042_STATUS) & I8042_BUFFER_FULL)
566 IO::in8(I8042_BUFFER);
567
568 enable_irq();
569}
570
571KeyboardDevice::~KeyboardDevice()
572{
573}
574
575bool KeyboardDevice::can_read(const FileDescription&) const
576{
577 return !m_queue.is_empty();
578}
579
580ssize_t KeyboardDevice::read(FileDescription&, u8* buffer, ssize_t size)
581{
582 ssize_t nread = 0;
583 while (nread < size) {
584 if (m_queue.is_empty())
585 break;
586 // Don't return partial data frames.
587 if ((size - nread) < (ssize_t)sizeof(Event))
588 break;
589 auto event = m_queue.dequeue();
590 memcpy(buffer, &event, sizeof(Event));
591 nread += sizeof(Event);
592 }
593 return nread;
594}
595
596ssize_t KeyboardDevice::write(FileDescription&, const u8*, ssize_t)
597{
598 return 0;
599}
600
601KeyboardClient::~KeyboardClient()
602{
603}
604
605void KeyboardDevice::set_maps(const char* n_map, const char* n_shift_map, const char* n_alt_map, const char* n_altgr_map)
606{
607 kfree(map);
608 kfree(shift_map);
609 kfree(alt_map);
610 kfree(altgr_map);
611
612 map = (char*)kmalloc(0x80);
613 shift_map = (char*)kmalloc(0x80);
614 alt_map = (char*)kmalloc(0x80);
615 altgr_map = (char*)kmalloc(0x80);
616
617 for (int i = 0; i < 0x80; i++) {
618 map[i] = n_map[i];
619 shift_map[i] = n_shift_map[i];
620 alt_map[i] = n_alt_map[i];
621 altgr_map[i] = n_altgr_map[i];
622 }
623}
624
625}