3 * Copyright (C) 2008 Advanced Micro Devices, Inc.
4 * Copyright (C) 2017 Patrick Rudolph <siro@das-labor.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <libpayload-config.h>
35 #include <libpayload.h>
40 #define debug(x...) printf(x)
42 #define debug(x...) do {} while (0)
45 #define POWER_BUTTON 0x90
46 #define MEDIA_KEY_PREFIX 0xE0
50 const unsigned short map
[4][0x59];
53 static struct layout_maps
*map
;
54 static int modifier
= 0;
55 int (*media_key_mapping_callback
)(char ch
);
57 static struct layout_maps keyboard_layouts
[] = {
58 #if CONFIG(LP_PC_KEYBOARD_LAYOUT_US)
59 { .country
= "us", .map
= {
61 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
62 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09,
63 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,
64 0x6F, 0x70, 0x5B, 0x5D, 0x0A, 0x00, 0x61, 0x73,
65 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B,
66 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
67 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A,
68 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
69 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME
,
70 KEY_UP
, KEY_NPAGE
, 0x00, KEY_LEFT
, 0x00, KEY_RIGHT
, 0x00, KEY_END
,
71 KEY_DOWN
, KEY_PPAGE
, 0x00, KEY_DC
, 0x00, 0x00, 0x00, KEY_F(11),
75 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E,
76 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x00,
77 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
78 0x4F, 0x50, 0x7B, 0x7D, 0x0A, 0x00, 0x41, 0x53,
79 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A,
80 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
81 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A,
82 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
83 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME
,
84 KEY_UP
, KEY_NPAGE
, 0x00, KEY_LEFT
, 0x00, KEY_RIGHT
, 0x00, KEY_END
,
85 KEY_DOWN
, KEY_PPAGE
, 0x00, KEY_DC
, 0x00, 0x00, 0x00, KEY_F(11),
89 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
90 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09,
91 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,
92 0x6F, 0x70, 0x5B, 0x5D, 0x0A, 0x00, 0x61, 0x73,
93 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B,
94 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
95 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A,
96 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
97 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME
,
98 KEY_UP
, KEY_NPAGE
, 0x00, KEY_LEFT
, 0x00, KEY_RIGHT
, 0x00, KEY_END
,
99 KEY_DOWN
, KEY_PPAGE
, 0x00, KEY_DC
, 0x00, 0x00, 0x00, KEY_F(11),
103 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E,
104 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x00,
105 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
106 0x4F, 0x50, 0x7B, 0x7D, 0x0A, 0x00, 0x41, 0x53,
107 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A,
108 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
109 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A,
110 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
111 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME
,
112 KEY_UP
, KEY_NPAGE
, 0x00, KEY_LEFT
, 0x00, KEY_RIGHT
, 0x00, KEY_END
,
113 KEY_DOWN
, KEY_PPAGE
, 0x00, KEY_DC
, 0x00, 0x00, 0x00, KEY_F(11),
118 #if CONFIG(LP_PC_KEYBOARD_LAYOUT_DE)
119 { .country
= "de", .map
= {
121 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
122 0x37, 0x38, 0x39, 0x30, 0x00, 0x27, 0x08, 0x09,
123 0x71, 0x77, 0x65, 0x72, 0x74, 0x7A, 0x75, 0x69,
124 0x6F, 0x70, 0x00, 0x2B, 0x0A, 0x00, 0x61, 0x73,
125 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x00,
126 0x00, 0x5E, 0x00, 0x23, 0x79, 0x78, 0x63, 0x76,
127 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2D, 0x00, 0x2A,
128 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
129 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME
,
130 KEY_UP
, KEY_NPAGE
, 0x00, KEY_LEFT
, 0x00, KEY_RIGHT
, 0x00, KEY_END
,
131 KEY_DOWN
, KEY_PPAGE
, 0x00, KEY_DC
, 0x00, 0x00, 0x3C, KEY_F(11),
135 0x00, 0x1B, 0x21, 0x22, 0xA7, 0x24, 0x25, 0x26,
136 0x2F, 0x28, 0x29, 0x3D, 0x3F, 0x60, 0x08, 0x00,
137 0x51, 0x57, 0x45, 0x52, 0x54, 0x5A, 0x55, 0x49,
138 0x4F, 0x50, 0x00, 0x2A, 0x0A, 0x00, 0x41, 0x53,
139 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x00,
140 0x00, 0x7E, 0x00, 0x27, 0x59, 0x58, 0x43, 0x56,
141 0x42, 0x4E, 0x4D, 0x3B, 0x3A, 0x5F, 0x00, 0x2A,
142 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
143 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME
,
144 KEY_UP
, KEY_NPAGE
, 0x00, KEY_LEFT
, 0x00, KEY_RIGHT
, 0x00, KEY_END
,
145 KEY_DOWN
, KEY_PPAGE
, 0x00, KEY_DC
, 0x00, 0x00, 0x3E, KEY_F(11),
149 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
150 0x7B, 0x5B, 0x5D, 0x7D, 0x5C, 0x3D, 0x08, 0x09,
151 0x40, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,
152 0x6F, 0x70, 0x5B, 0x7E, 0x0A, 0x00, 0x61, 0x73,
153 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B,
154 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
155 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A,
156 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
157 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME
,
158 KEY_UP
, KEY_NPAGE
, 0x00, KEY_LEFT
, 0x00, KEY_RIGHT
, 0x00, KEY_END
,
159 KEY_DOWN
, KEY_PPAGE
, 0x00, KEY_DC
, 0x00, 0x00, 0x7C, KEY_F(11),
164 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E,
165 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x00,
166 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
167 0x4F, 0x50, 0x7B, 0x7D, 0x0A, 0x00, 0x41, 0x53,
168 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A,
169 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
170 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A,
171 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
172 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME
,
173 KEY_UP
, KEY_NPAGE
, 0x00, KEY_LEFT
, 0x00, KEY_RIGHT
, 0x00, KEY_END
,
174 KEY_DOWN
, KEY_PPAGE
, 0x00, KEY_DC
, 0x00, 0x00, 0x00, KEY_F(11),
181 static void keyboard_drain_input(void)
183 while (i8042_data_ready_ps2())
184 (void)i8042_read_data_ps2();
187 static bool keyboard_cmd(unsigned char cmd
)
189 const uint64_t timeout_us
= cmd
== I8042_KBCMD_RESET
? 1*1000*1000 : 200*1000;
190 const uint64_t start_time
= timer_us(0);
192 i8042_write_data(cmd
);
195 if (!i8042_data_ready_ps2()) {
200 const uint8_t data
= i8042_read_data_ps2();
207 /* Warn only if we already disabled keyboard input. */
208 if (cmd
!= I8042_KBCMD_DEFAULT_DIS
)
209 debug("WARNING: Keyboard sent spurious 0x%02x.\n", data
);
212 } while (timer_us(start_time
) < timeout_us
);
214 debug("ERROR: Keyboard command timed out.\n");
218 static bool set_scancode_set(const unsigned char set
)
222 if (set
< 1 || set
> 3)
225 ret
= keyboard_cmd(I8042_KBCMD_SET_SCANCODE
);
227 debug("ERROR: Keyboard set scancode failed!\n");
231 ret
= keyboard_cmd(set
);
233 debug("ERROR: Keyboard scancode set#%u failed!\n", set
);
240 static bool keyboard_peek_echo_result(void)
242 const uint8_t ch
= i8042_peek_data_ps2();
243 return ch
== 0xee || ch
== 0xfe;
246 static enum keyboard_state
{
248 STATE_SIMPLIFIED_INIT
,
253 STATE_DISABLE_TRANSLATION
,
254 STATE_START_SELF_TEST
,
257 STATE_CONFIGURE_SET1
,
258 STATE_ENABLE_TRANSLATION
,
265 #define STATE_NAMES_ENTRY(name) [STATE_##name] = #name
266 static const char *const state_names
[] = {
267 STATE_NAMES_ENTRY(INIT
),
268 STATE_NAMES_ENTRY(SIMPLIFIED_INIT
),
269 STATE_NAMES_ENTRY(HOTPLUG
),
270 STATE_NAMES_ENTRY(HOTPLUG_ECHO
),
271 STATE_NAMES_ENTRY(DISABLE_SCAN
),
272 STATE_NAMES_ENTRY(DRAIN_INPUT
),
273 STATE_NAMES_ENTRY(DISABLE_TRANSLATION
),
274 STATE_NAMES_ENTRY(START_SELF_TEST
),
275 STATE_NAMES_ENTRY(SELF_TEST
),
276 STATE_NAMES_ENTRY(CONFIGURE
),
277 STATE_NAMES_ENTRY(CONFIGURE_SET1
),
278 STATE_NAMES_ENTRY(ENABLE_TRANSLATION
),
279 STATE_NAMES_ENTRY(ENABLE_SCAN
),
280 STATE_NAMES_ENTRY(RUNNING
),
281 STATE_NAMES_ENTRY(RUNNING_ECHO
),
282 STATE_NAMES_ENTRY(DETENTION
),
285 __attribute__((unused
))
286 static const char *state_name(enum keyboard_state state
)
288 if (state
>= ARRAY_SIZE(state_names
) || !state_names
[state
])
290 return state_names
[state
];
293 static uint64_t keyboard_time
;
294 static uint64_t state_time
;
296 static void keyboard_poll(void)
298 enum keyboard_state next_state
= keyboard_state
;
301 switch (keyboard_state
) {
304 /* Wait until keyboard_init() has been called. */
307 case STATE_SIMPLIFIED_INIT
:
308 /* On the first try, start opportunistically, do
309 the first steps at once and skip the self-test. */
310 (void)keyboard_cmd(I8042_KBCMD_DEFAULT_DIS
);
311 keyboard_drain_input();
312 (void)i8042_set_kbd_translation(false);
313 next_state
= STATE_CONFIGURE
;
317 if (timer_us(state_time
) > 1*1000*1000) {
318 i8042_write_data(I8042_KBCMD_ECHO
);
319 next_state
= STATE_HOTPLUG_ECHO
;
323 case STATE_HOTPLUG_ECHO
:
324 if (!i8042_data_ready_ps2()) {
325 if (timer_us(state_time
) > 200*1000)
326 next_state
= STATE_HOTPLUG
;
330 if (keyboard_peek_echo_result()) {
331 next_state
= STATE_DISABLE_SCAN
;
332 keyboard_time
= timer_us(0);
334 (void)i8042_read_data_ps2();
338 case STATE_DISABLE_SCAN
:
339 (void)keyboard_cmd(I8042_KBCMD_DEFAULT_DIS
);
340 next_state
= STATE_DRAIN_INPUT
;
343 case STATE_DRAIN_INPUT
:
344 /* Limit number of bytes drained per poll. */
345 for (i
= 0; i
< 50 && i8042_data_ready_ps2(); ++i
)
346 (void)i8042_read_data_ps2();
348 next_state
= STATE_DISABLE_TRANSLATION
;
351 case STATE_DISABLE_TRANSLATION
:
352 /* Be opportunistic and assume it's disabled on failure. */
353 (void)i8042_set_kbd_translation(false);
354 next_state
= STATE_START_SELF_TEST
;
357 case STATE_START_SELF_TEST
:
358 if (!keyboard_cmd(I8042_KBCMD_RESET
))
359 debug("ERROR: Keyboard self-test couldn't be started.\n");
360 /* We ignore errors and always move to the self-test state
361 which will simply try again if necessary. */
362 next_state
= STATE_SELF_TEST
;
365 case STATE_SELF_TEST
:
366 if (!i8042_data_ready_ps2()) {
367 if (timer_us(state_time
) > 5*1000*1000) {
368 debug("WARNING: Keyboard self-test timed out.\n");
369 next_state
= STATE_DISABLE_SCAN
;
374 const uint8_t self_test_result
= i8042_read_data_ps2();
375 switch (self_test_result
) {
377 debug("INFO: Keyboard self-test succeeded.\n");
378 next_state
= STATE_CONFIGURE
;
382 /* Failure. Try again. */
383 debug("WARNING: Keyboard self-test failed.\n");
384 next_state
= STATE_START_SELF_TEST
;
387 debug("WARNING: Keyboard self-test received spurious 0x%02x\n",
393 case STATE_CONFIGURE
:
394 if (set_scancode_set(2))
395 next_state
= STATE_ENABLE_TRANSLATION
;
397 next_state
= STATE_CONFIGURE_SET1
;
400 case STATE_CONFIGURE_SET1
:
401 if (!set_scancode_set(1)) {
402 debug("ERROR: Keyboard failed to set any scancode set.\n");
403 next_state
= STATE_DISABLE_SCAN
;
407 next_state
= STATE_ENABLE_SCAN
;
410 case STATE_ENABLE_TRANSLATION
:
411 if (i8042_set_kbd_translation(true) != 0) {
412 debug("ERROR: Keyboard controller set translation failed!\n");
413 next_state
= STATE_DISABLE_SCAN
;
417 next_state
= STATE_ENABLE_SCAN
;
420 case STATE_ENABLE_SCAN
:
421 if (!keyboard_cmd(I8042_KBCMD_EN
)) {
422 debug("ERROR: Keyboard enable scanning failed!\n");
423 next_state
= STATE_DISABLE_SCAN
;
427 next_state
= STATE_RUNNING
;
431 if (!i8042_data_ready_ps2()) {
432 if (timer_us(state_time
) > 500*1000) {
433 i8042_write_data(I8042_KBCMD_ECHO
);
434 next_state
= STATE_RUNNING_ECHO
;
437 state_time
= timer_us(0);
441 case STATE_RUNNING_ECHO
:
442 if (!i8042_data_ready_ps2()) {
443 if (timer_us(state_time
) > 200*1000) {
444 debug("INFO: Keyboard echo timed out.\n");
445 next_state
= STATE_HOTPLUG
;
450 if (keyboard_peek_echo_result()) {
451 (void)i8042_read_data_ps2();
452 next_state
= STATE_RUNNING
;
455 state_time
= timer_us(0);
458 case STATE_DETENTION
:
459 if (timer_us(state_time
) > 5*1000*1000)
460 next_state
= STATE_HOTPLUG
;
465 switch (next_state
) {
468 case STATE_HOTPLUG_ECHO
:
470 case STATE_RUNNING_ECHO
:
471 case STATE_DETENTION
:
474 if (timer_us(keyboard_time
) > 30*1000*1000)
475 next_state
= STATE_DETENTION
;
479 if (keyboard_state
!= next_state
) {
480 debug("INFO: Keyboard advancing state to '%s'.\n", state_name(next_state
));
481 keyboard_state
= next_state
;
482 state_time
= timer_us(0);
486 bool keyboard_havechar(void)
489 return i8042_data_ready_ps2() &&
490 (keyboard_state
== STATE_RUNNING
||
491 (keyboard_state
== STATE_RUNNING_ECHO
&& !keyboard_peek_echo_result()));
494 unsigned char keyboard_get_scancode(void)
498 while (!keyboard_havechar()) ;
500 ch
= i8042_read_data_ps2();
505 modifier
|= KB_MOD_SHIFT
;
509 modifier
&= ~KB_MOD_SHIFT
;
512 modifier
|= KB_MOD_ALT
;
515 modifier
&= ~KB_MOD_ALT
;
518 modifier
|= KB_MOD_CTRL
;
521 modifier
&= ~KB_MOD_CTRL
;
524 if (modifier
& KB_MOD_CAPSLOCK
) {
525 modifier
&= ~KB_MOD_CAPSLOCK
;
526 if (keyboard_cmd(I8042_KBCMD_SET_MODE_IND
))
527 keyboard_cmd(I8042_MODE_CAPS_LOCK_OFF
);
529 modifier
|= KB_MOD_CAPSLOCK
;
530 if (keyboard_cmd(I8042_KBCMD_SET_MODE_IND
))
531 keyboard_cmd(I8042_MODE_CAPS_LOCK_ON
);
539 int keyboard_getmodifier(void)
544 void initialize_keyboard_media_key_mapping_callback(int (*media_key_mapper
)(char))
546 media_key_mapping_callback
= media_key_mapper
;
549 int keyboard_getchar(void)
555 while (!keyboard_havechar()) ;
557 ch
= keyboard_get_scancode();
558 if ((media_key_mapping_callback
!= NULL
) && (ch
== MEDIA_KEY_PREFIX
)) {
559 ch
= keyboard_get_scancode();
560 return media_key_mapping_callback(ch
);
563 if (!(ch
& 0x80) && ch
< 0x59) {
565 (modifier
& KB_MOD_SHIFT
) ^ (modifier
& KB_MOD_CAPSLOCK
) ? 1 : 0;
567 if (modifier
& KB_MOD_ALT
)
570 ret
= map
->map
[shift
][ch
];
572 if (modifier
& KB_MOD_CTRL
) {
578 /* vulcan nerve pinch */
579 if ((modifier
& KB_MOD_ALT
) && reset_handler
)
595 * Set keyboard layout
596 * @param country string describing the keyboard layout language.
597 * Valid values are "us", "de".
600 int keyboard_set_layout(char *country
)
604 for (i
=0; i
<ARRAY_SIZE(keyboard_layouts
); i
++) {
605 if (strncmp(keyboard_layouts
[i
].country
, country
,
606 strlen(keyboard_layouts
[i
].country
)))
609 /* Found, changing keyboard layout */
610 map
= &keyboard_layouts
[i
];
614 /* Nothing found, not changed */
618 static struct console_input_driver cons
= {
619 .havekey
= (int (*)(void))keyboard_havechar
,
620 .getchar
= keyboard_getchar
,
621 .input_type
= CONSOLE_INPUT_TYPE_EC
,
624 void keyboard_init(void)
626 if (keyboard_state
!= STATE_INIT
)
629 map
= &keyboard_layouts
[0];
631 /* Initialized keyboard controller. */
632 if (!i8042_probe() || !i8042_has_ps2())
635 /* Enable first PS/2 port */
636 i8042_cmd(I8042_CMD_EN_KB
);
638 keyboard_state
= STATE_SIMPLIFIED_INIT
;
639 keyboard_time
= state_time
= timer_us(0);
641 console_add_input_driver(&cons
);
644 void keyboard_disconnect(void)
646 /* If 0x64 returns 0xff, then we have no keyboard
648 if (inb(0x64) == 0xFF)
651 if (!i8042_has_ps2())
654 /* Disable scanning */
655 keyboard_cmd(I8042_KBCMD_DEFAULT_DIS
);
656 keyboard_drain_input();
658 /* Nobody but us seems to still use scancode set #1.
659 So try to hand over with more modern settings. */
661 i8042_set_kbd_translation(CONFIG(LP_PC_KEYBOARD_TRANSLATION
));
663 /* Send keyboard disconnect command */
664 i8042_cmd(I8042_CMD_DIS_KB
);
666 /* Hand off with empty buffer */
667 keyboard_drain_input();
669 /* Release keyboard controller driver */
672 keyboard_state
= STATE_INIT
;