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