2 * This file is part of the libpayload project.
4 * Copyright (C) 2008 Advanced Micro Devices, Inc.
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
30 #include <libpayload-config.h>
31 #include <libpayload.h>
34 #define I8042_CMD_READ_MODE 0x20
35 #define I8042_CMD_WRITE_MODE 0x60
37 #define I8042_MODE_XLATE 0x40
41 const unsigned short map[4][0x57];
44 static struct layout_maps *map;
46 static struct layout_maps keyboard_layouts[] = {
47 #ifdef CONFIG_PC_KEYBOARD_LAYOUT_US
48 { .country = "us", .map = {
50 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
51 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09,
52 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,
53 0x6F, 0x70, 0x5B, 0x5D, 0x0A, 0x00, 0x61, 0x73,
54 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B,
55 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
56 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A,
57 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
58 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
59 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
60 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00
63 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E,
64 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x00,
65 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
66 0x4F, 0x50, 0x7B, 0x7D, 0x0A, 0x00, 0x41, 0x53,
67 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A,
68 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
69 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A,
70 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
71 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
72 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
73 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00
76 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
77 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09,
78 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,
79 0x6F, 0x70, 0x5B, 0x5D, 0x0A, 0x00, 0x61, 0x73,
80 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B,
81 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
82 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A,
83 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
84 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
85 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
86 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00
89 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E,
90 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x00,
91 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
92 0x4F, 0x50, 0x7B, 0x7D, 0x0A, 0x00, 0x41, 0x53,
93 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A,
94 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
95 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 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
103 #ifdef CONFIG_PC_KEYBOARD_LAYOUT_DE
104 { .country = "de", .map = {
106 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
107 0x37, 0x38, 0x39, 0x30, 0x00, 0x27, 0x08, 0x09,
108 0x71, 0x77, 0x65, 0x72, 0x74, 0x7A, 0x75, 0x69,
109 0x6F, 0x70, 0x00, 0x2B, 0x0A, 0x00, 0x61, 0x73,
110 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x00,
111 0x00, 0x5E, 0x00, 0x23, 0x79, 0x78, 0x63, 0x76,
112 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2D, 0x00, 0x2A,
113 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
114 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
115 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
116 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x3C
119 0x00, 0x1B, 0x21, 0x22, 0xA7, 0x24, 0x25, 0x26,
120 0x2F, 0x28, 0x29, 0x3D, 0x3F, 0x60, 0x08, 0x00,
121 0x51, 0x57, 0x45, 0x52, 0x54, 0x5A, 0x55, 0x49,
122 0x4F, 0x50, 0x00, 0x2A, 0x0A, 0x00, 0x41, 0x53,
123 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x00,
124 0x00, 0x7E, 0x00, 0x27, 0x59, 0x58, 0x43, 0x56,
125 0x42, 0x4E, 0x4D, 0x3B, 0x3A, 0x5F, 0x00, 0x2A,
126 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
127 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
128 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
129 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x3E
132 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
133 0x7B, 0x5B, 0x5D, 0x7D, 0x5C, 0x3D, 0x08, 0x09,
134 0x40, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,
135 0x6F, 0x70, 0x5B, 0x7E, 0x0A, 0x00, 0x61, 0x73,
136 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B,
137 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
138 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A,
139 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
140 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
141 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
142 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x7C
146 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E,
147 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x00,
148 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
149 0x4F, 0x50, 0x7B, 0x7D, 0x0A, 0x00, 0x41, 0x53,
150 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A,
151 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
152 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A,
153 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
154 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
155 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
156 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00
162 #define MOD_SHIFT (1 << 0)
163 #define MOD_CTRL (1 << 1)
164 #define MOD_CAPSLOCK (1 << 2)
165 #define MOD_ALT (1 << 3)
167 static void keyboard_cmd(unsigned char cmd, unsigned char val)
170 /* wait until keyboard controller accepts cmds: */
171 while (inb(0x64) & 2);
173 while (inb(0x64) & 2);
176 int keyboard_havechar(void)
178 unsigned char c = inb(0x64);
179 return (c == 0xFF) ? 0 : c & 1;
182 unsigned char keyboard_get_scancode(void)
184 unsigned char ch = 0;
186 if (keyboard_havechar())
192 int keyboard_getchar(void)
194 static int modifier = 0;
199 while (!keyboard_havechar()) ;
201 ch = keyboard_get_scancode();
206 modifier |= MOD_SHIFT;
210 modifier &= ~MOD_SHIFT;
216 modifier &= ~MOD_ALT;
219 modifier |= MOD_CTRL;
222 modifier &= ~MOD_CTRL;
225 if (modifier & MOD_CAPSLOCK) {
226 modifier &= ~MOD_CAPSLOCK;
227 keyboard_cmd(0xed, (0 << 2));
229 modifier |= MOD_CAPSLOCK;
230 keyboard_cmd(0xed, (1 << 2));
235 if (!(ch & 0x80) && ch < 0x57) {
237 (modifier & MOD_SHIFT) ^ (modifier & MOD_CAPSLOCK) ? 1 : 0;
239 if (modifier & MOD_ALT)
242 ret = map->map[shift][ch];
244 if (modifier & MOD_CTRL) {
250 /* vulcan nerve pinch */
251 if ((modifier & MOD_ALT) && reset_handler)
262 static int keyboard_wait_read(void)
266 while(retries-- && !(inb(0x64) & 0x01))
269 return (retries <= 0) ? -1 : 0;
272 static int keyboard_wait_write(void)
276 while(retries-- && (inb(0x64) & 0x02))
279 return (retries <= 0) ? -1 : 0;
282 static unsigned char keyboard_get_mode(void)
284 outb(I8042_CMD_READ_MODE, 0x64);
285 keyboard_wait_read();
289 static void keyboard_set_mode(unsigned char mode)
291 outb(I8042_CMD_WRITE_MODE, 0x64);
292 keyboard_wait_write();
297 * Set keyboard layout
298 * @param country string describing the keyboard layout language.
299 * Valid values are "us", "de".
302 int keyboard_set_layout(char *country)
306 for (i=0; i<ARRAY_SIZE(keyboard_layouts); i++) {
307 if (strncmp(keyboard_layouts[i].country, country,
308 strlen(keyboard_layouts[i].country)))
311 /* Found, changing keyboard layout */
312 map = &keyboard_layouts[i];
316 /* Nothing found, not changed */
320 static struct console_input_driver cons = {
321 .havekey = keyboard_havechar,
322 .getchar = keyboard_getchar
325 void keyboard_init(void)
328 map = &keyboard_layouts[0];
330 /* If 0x64 returns 0xff, then we have no keyboard
333 if (inb(0x64) == 0xFF)
336 /* Empty keyboard buffer */
337 while (keyboard_havechar()) keyboard_getchar();
339 /* Read the current mode */
340 mode = keyboard_get_mode();
342 /* Turn on scancode translate mode so that we can
343 use the scancode set 1 tables */
345 mode |= I8042_MODE_XLATE;
347 /* Write the new mode */
348 keyboard_set_mode(mode);
350 console_add_input_driver(&cons);