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.h>
34 #define I8042_CMD_READ_MODE 0x20
35 #define I8042_CMD_WRITE_MODE 0x60
37 #define I8042_MODE_XLATE 0x40
39 static void (*reset_handler)(void) = NULL;
43 unsigned short map[4][0x57];
46 struct layout_maps *map;
48 struct layout_maps keyboard_layouts[] = {
49 #ifdef CONFIG_PC_KEYBOARD_LAYOUT_US
50 { .country = "us", .map = {
52 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
53 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09,
54 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,
55 0x6F, 0x70, 0x5B, 0x5D, 0x0A, 0x00, 0x61, 0x73,
56 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B,
57 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
58 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A,
59 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
60 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
61 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
62 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00
65 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E,
66 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x00,
67 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
68 0x4F, 0x50, 0x7B, 0x7D, 0x0A, 0x00, 0x41, 0x53,
69 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A,
70 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
71 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A,
72 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
73 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
74 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
75 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00
78 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
79 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09,
80 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,
81 0x6F, 0x70, 0x5B, 0x5D, 0x0A, 0x00, 0x61, 0x73,
82 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B,
83 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
84 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A,
85 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
86 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
87 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
88 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00
91 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E,
92 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x00,
93 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
94 0x4F, 0x50, 0x7B, 0x7D, 0x0A, 0x00, 0x41, 0x53,
95 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A,
96 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
97 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A,
98 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
99 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
100 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
101 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00
105 #ifdef CONFIG_PC_KEYBOARD_LAYOUT_DE
106 { .country = "de", .map = {
108 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
109 0x37, 0x38, 0x39, 0x30, 0x00, 0x27, 0x08, 0x09,
110 0x71, 0x77, 0x65, 0x72, 0x74, 0x7A, 0x75, 0x69,
111 0x6F, 0x70, 0x00, 0x2B, 0x0A, 0x00, 0x61, 0x73,
112 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x00,
113 0x00, 0x5E, 0x00, 0x23, 0x79, 0x78, 0x63, 0x76,
114 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2D, 0x00, 0x2A,
115 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
116 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
117 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
118 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x3C
121 0x00, 0x1B, 0x21, 0x22, 0xA7, 0x24, 0x25, 0x26,
122 0x2F, 0x28, 0x29, 0x3D, 0x3F, 0x60, 0x08, 0x00,
123 0x51, 0x57, 0x45, 0x52, 0x54, 0x5A, 0x55, 0x49,
124 0x4F, 0x50, 0x00, 0x2A, 0x0A, 0x00, 0x41, 0x53,
125 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x00,
126 0x00, 0x7E, 0x00, 0x27, 0x59, 0x58, 0x43, 0x56,
127 0x42, 0x4E, 0x4D, 0x3B, 0x3A, 0x5F, 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, 0x3E
134 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
135 0x7B, 0x5B, 0x5D, 0x7D, 0x5C, 0x3D, 0x08, 0x09,
136 0x40, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,
137 0x6F, 0x70, 0x5B, 0x7E, 0x0A, 0x00, 0x61, 0x73,
138 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B,
139 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
140 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A,
141 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
142 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
143 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
144 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x7C
148 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E,
149 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x00,
150 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
151 0x4F, 0x50, 0x7B, 0x7D, 0x0A, 0x00, 0x41, 0x53,
152 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A,
153 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
154 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A,
155 0x00, 0x20, 0x00, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5),
156 KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), 0x00, 0x00, KEY_HOME,
157 KEY_UP, KEY_NPAGE, 0x00, KEY_LEFT, 0x00, KEY_RIGHT, 0x00, KEY_END,
158 KEY_DOWN, KEY_PPAGE, 0x00, KEY_DC, 0x00, 0x00, 0x00
164 #define MOD_SHIFT (1 << 0)
165 #define MOD_CTRL (1 << 1)
166 #define MOD_CAPSLOCK (1 << 2)
167 #define MOD_ALT (1 << 3)
169 static void keyboard_cmd(unsigned char cmd, unsigned char val)
172 /* wait until keyboard controller accepts cmds: */
173 while (inb(0x64) & 2);
175 while (inb(0x64) & 2);
179 int keyboard_havechar(void)
181 unsigned char c = inb(0x64);
185 unsigned char keyboard_get_scancode(void)
187 unsigned char ch = 0;
189 if (keyboard_havechar())
195 int keyboard_getchar(void)
197 static int modifier = 0;
202 while (!keyboard_havechar()) ;
204 ch = keyboard_get_scancode();
209 modifier |= MOD_SHIFT;
213 modifier &= ~MOD_SHIFT;
219 modifier &= ~MOD_ALT;
222 modifier |= MOD_CTRL;
225 modifier &= ~MOD_CTRL;
228 if (modifier & MOD_CAPSLOCK) {
229 modifier &= ~MOD_CAPSLOCK;
230 keyboard_cmd(0xed, (0 << 2));
232 modifier |= MOD_CAPSLOCK;
233 keyboard_cmd(0xed, (1 << 2));
238 if (!(ch & 0x80) && ch < 0x57) {
240 (modifier & MOD_SHIFT) ^ (modifier & MOD_CAPSLOCK) ? 1 : 0;
242 if (modifier & MOD_ALT)
245 ret = map->map[shift][ch];
247 if (modifier & MOD_CTRL) {
253 /* vulcan nerve pinch */
254 if ((modifier & MOD_ALT) && reset_handler)
265 static int keyboard_wait_read(void)
269 while(timeout-- && !(inb(0x64) & 0x01))
272 return (timeout <= 0) ? -1 : 0;
275 static int keyboard_wait_write(void)
279 while(timeout-- && (inb(0x64) & 0x02))
282 return (timeout <= 0) ? -1 : 0;
285 static unsigned char keyboard_get_mode(void)
287 outb(I8042_CMD_READ_MODE, 0x64);
288 keyboard_wait_read();
292 static void keyboard_set_mode(unsigned char mode)
294 outb(I8042_CMD_WRITE_MODE, 0x64);
295 keyboard_wait_write();
300 * Set keyboard layout
301 * @param country string describing the keyboard layout language.
302 * Valid values are "us", "de".
305 int keyboard_set_layout(char *country)
309 for (i=0; i<ARRAY_SIZE(keyboard_layouts); i++) {
310 if (strncmp(keyboard_layouts[i].country, country,
311 strlen(keyboard_layouts[i].country)))
314 /* Found, changing keyboard layout */
315 map = &keyboard_layouts[i];
319 /* Nothing found, not changed */
323 int keyboard_add_reset_handler(void (*new_handler)(void))
325 reset_handler = new_handler;
330 void keyboard_init(void)
333 map = &keyboard_layouts[0];
335 /* Empty keyboard buffer */
336 while (keyboard_havechar()) keyboard_getchar();
338 /* Read the current mode */
339 mode = keyboard_get_mode();
341 /* Turn on scancode translate mode so that we can
342 use the scancode set 1 tables */
344 mode |= I8042_MODE_XLATE;
346 /* Write the new mode */
347 keyboard_set_mode(mode);