1 /* 2 * (C) Copyright 2002 ELTEC Elektronik AG 3 * Frank Gottschling <fgottschling@eltec.de> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 /* i8042.c - Intel 8042 keyboard driver routines */ 9 10 /* includes */ 11 12 #include <common.h> 13 #include <i8042.h> 14 15 /* defines */ 16 17 #ifdef CONFIG_CONSOLE_CURSOR 18 extern void console_cursor(int state); 19 static int blinkCount = CONFIG_SYS_CONSOLE_BLINK_COUNT; 20 static int cursor_state; 21 #endif 22 23 /* locals */ 24 25 static int kbd_input = -1; /* no input yet */ 26 static int kbd_mapping = KBD_US; /* default US keyboard */ 27 static int kbd_flags = NORMAL; /* after reset */ 28 static int kbd_state; /* unshift code */ 29 30 static void kbd_conv_char(unsigned char scan_code); 31 static void kbd_led_set(void); 32 static void kbd_normal(unsigned char scan_code); 33 static void kbd_shift(unsigned char scan_code); 34 static void kbd_ctrl(unsigned char scan_code); 35 static void kbd_num(unsigned char scan_code); 36 static void kbd_caps(unsigned char scan_code); 37 static void kbd_scroll(unsigned char scan_code); 38 static void kbd_alt(unsigned char scan_code); 39 static int kbd_input_empty(void); 40 static int kbd_reset(void); 41 42 static unsigned char kbd_fct_map[144] = { 43 /* kbd_fct_map table for scan code */ 44 0, AS, AS, AS, AS, AS, AS, AS, /* scan 0- 7 */ 45 AS, AS, AS, AS, AS, AS, AS, AS, /* scan 8- F */ 46 AS, AS, AS, AS, AS, AS, AS, AS, /* scan 10-17 */ 47 AS, AS, AS, AS, AS, CN, AS, AS, /* scan 18-1F */ 48 AS, AS, AS, AS, AS, AS, AS, AS, /* scan 20-27 */ 49 AS, AS, SH, AS, AS, AS, AS, AS, /* scan 28-2F */ 50 AS, AS, AS, AS, AS, AS, SH, AS, /* scan 30-37 */ 51 AS, AS, CP, 0, 0, 0, 0, 0, /* scan 38-3F */ 52 0, 0, 0, 0, 0, NM, ST, ES, /* scan 40-47 */ 53 ES, ES, ES, ES, ES, ES, ES, ES, /* scan 48-4F */ 54 ES, ES, ES, ES, 0, 0, AS, 0, /* scan 50-57 */ 55 0, 0, 0, 0, 0, 0, 0, 0, /* scan 58-5F */ 56 0, 0, 0, 0, 0, 0, 0, 0, /* scan 60-67 */ 57 0, 0, 0, 0, 0, 0, 0, 0, /* scan 68-6F */ 58 AS, 0, 0, AS, 0, 0, AS, 0, /* scan 70-77 */ 59 0, AS, 0, 0, 0, AS, 0, 0, /* scan 78-7F */ 60 AS, CN, AS, AS, AK, ST, EX, EX, /* enhanced */ 61 AS, EX, EX, AS, EX, AS, EX, EX /* enhanced */ 62 }; 63 64 static unsigned char kbd_key_map[2][5][144] = { 65 { /* US keyboard */ 66 { /* unshift code */ 67 0, 0x1b, '1', '2', '3', '4', '5', '6', /* scan 0- 7 */ 68 '7', '8', '9', '0', '-', '=', 0x08, '\t', /* scan 8- F */ 69 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', /* scan 10-17 */ 70 'o', 'p', '[', ']', '\r', CN, 'a', 's', /* scan 18-1F */ 71 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* scan 20-27 */ 72 '\'', '`', SH, '\\', 'z', 'x', 'c', 'v', /* scan 28-2F */ 73 'b', 'n', 'm', ',', '.', '/', SH, '*', /* scan 30-37 */ 74 ' ', ' ', CP, 0, 0, 0, 0, 0, /* scan 38-3F */ 75 0, 0, 0, 0, 0, NM, ST, '7', /* scan 40-47 */ 76 '8', '9', '-', '4', '5', '6', '+', '1', /* scan 48-4F */ 77 '2', '3', '0', '.', 0, 0, 0, 0, /* scan 50-57 */ 78 0, 0, 0, 0, 0, 0, 0, 0, /* scan 58-5F */ 79 0, 0, 0, 0, 0, 0, 0, 0, /* scan 60-67 */ 80 0, 0, 0, 0, 0, 0, 0, 0, /* scan 68-6F */ 81 0, 0, 0, 0, 0, 0, 0, 0, /* scan 70-77 */ 82 0, 0, 0, 0, 0, 0, 0, 0, /* scan 78-7F */ 83 '\r', CN, '/', '*', ' ', ST, 'F', 'A', /* extended */ 84 0, 'D', 'C', 0, 'B', 0, '@', 'P' /* extended */ 85 }, 86 { /* shift code */ 87 0, 0x1b, '!', '@', '#', '$', '%', '^', /* scan 0- 7 */ 88 '&', '*', '(', ')', '_', '+', 0x08, '\t', /* scan 8- F */ 89 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', /* scan 10-17 */ 90 'O', 'P', '{', '}', '\r', CN, 'A', 'S', /* scan 18-1F */ 91 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', /* scan 20-27 */ 92 '"', '~', SH, '|', 'Z', 'X', 'C', 'V', /* scan 28-2F */ 93 'B', 'N', 'M', '<', '>', '?', SH, '*', /* scan 30-37 */ 94 ' ', ' ', CP, 0, 0, 0, 0, 0, /* scan 38-3F */ 95 0, 0, 0, 0, 0, NM, ST, '7', /* scan 40-47 */ 96 '8', '9', '-', '4', '5', '6', '+', '1', /* scan 48-4F */ 97 '2', '3', '0', '.', 0, 0, 0, 0, /* scan 50-57 */ 98 0, 0, 0, 0, 0, 0, 0, 0, /* scan 58-5F */ 99 0, 0, 0, 0, 0, 0, 0, 0, /* scan 60-67 */ 100 0, 0, 0, 0, 0, 0, 0, 0, /* scan 68-6F */ 101 0, 0, 0, 0, 0, 0, 0, 0, /* scan 70-77 */ 102 0, 0, 0, 0, 0, 0, 0, 0, /* scan 78-7F */ 103 '\r', CN, '/', '*', ' ', ST, 'F', 'A', /* extended */ 104 0, 'D', 'C', 0, 'B', 0, '@', 'P' /* extended */ 105 }, 106 { /* control code */ 107 0xff, 0x1b, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, /* scan 0- 7 */ 108 0x1e, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, '\t', /* scan 8- F */ 109 0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x15, 0x09, /* scan 10-17 */ 110 0x0f, 0x10, 0x1b, 0x1d, '\r', CN, 0x01, 0x13, /* scan 18-1F */ 111 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0c, 0xff, /* scan 20-27 */ 112 0xff, 0x1c, SH, 0xff, 0x1a, 0x18, 0x03, 0x16, /* scan 28-2F */ 113 0x02, 0x0e, 0x0d, 0xff, 0xff, 0xff, SH, 0xff, /* scan 30-37 */ 114 0xff, 0xff, CP, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38-3F */ 115 0xff, 0xff, 0xff, 0xff, 0xff, NM, ST, 0xff, /* scan 40-47 */ 116 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 48-4F */ 117 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 50-57 */ 118 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58-5F */ 119 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60-67 */ 120 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68-6F */ 121 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70-77 */ 122 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78-7F */ 123 '\r', CN, '/', '*', ' ', ST, 0xff, 0xff, /* extended */ 124 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff /* extended */ 125 }, 126 { /* non numeric code */ 127 0, 0x1b, '1', '2', '3', '4', '5', '6', /* scan 0- 7 */ 128 '7', '8', '9', '0', '-', '=', 0x08, '\t', /* scan 8- F */ 129 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', /* scan 10-17 */ 130 'o', 'p', '[', ']', '\r', CN, 'a', 's', /* scan 18-1F */ 131 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* scan 20-27 */ 132 '\'', '`', SH, '\\', 'z', 'x', 'c', 'v', /* scan 28-2F */ 133 'b', 'n', 'm', ',', '.', '/', SH, '*', /* scan 30-37 */ 134 ' ', ' ', CP, 0, 0, 0, 0, 0, /* scan 38-3F */ 135 0, 0, 0, 0, 0, NM, ST, 'w', /* scan 40-47 */ 136 'x', 'y', 'l', 't', 'u', 'v', 'm', 'q', /* scan 48-4F */ 137 'r', 's', 'p', 'n', 0, 0, 0, 0, /* scan 50-57 */ 138 0, 0, 0, 0, 0, 0, 0, 0, /* scan 58-5F */ 139 0, 0, 0, 0, 0, 0, 0, 0, /* scan 60-67 */ 140 0, 0, 0, 0, 0, 0, 0, 0, /* scan 68-6F */ 141 0, 0, 0, 0, 0, 0, 0, 0, /* scan 70-77 */ 142 0, 0, 0, 0, 0, 0, 0, 0, /* scan 78-7F */ 143 '\r', CN, '/', '*', ' ', ST, 'F', 'A', /* extended */ 144 0, 'D', 'C', 0, 'B', 0, '@', 'P' /* extended */ 145 }, 146 { /* right alt mode - not used in US keyboard */ 147 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 0 - 7 */ 148 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 8 - F */ 149 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 10 -17 */ 150 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 18 -1F */ 151 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 20 -27 */ 152 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 28 -2F */ 153 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 30 -37 */ 154 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38 -3F */ 155 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 40 -47 */ 156 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 48 -4F */ 157 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 50 -57 */ 158 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58 -5F */ 159 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60 -67 */ 160 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68 -6F */ 161 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70 -77 */ 162 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78 -7F */ 163 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* extended */ 164 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff /* extended */ 165 } 166 }, 167 { /* german keyboard */ 168 { /* unshift code */ 169 0, 0x1b, '1', '2', '3', '4', '5', '6', /* scan 0- 7 */ 170 '7', '8', '9', '0', 0xe1, '\'', 0x08, '\t', /* scan 8- F */ 171 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', /* scan 10-17 */ 172 'o', 'p', 0x81, '+', '\r', CN, 'a', 's', /* scan 18-1F */ 173 'd', 'f', 'g', 'h', 'j', 'k', 'l', 0x94, /* scan 20-27 */ 174 0x84, '^', SH, '#', 'y', 'x', 'c', 'v', /* scan 28-2F */ 175 'b', 'n', 'm', ',', '.', '-', SH, '*', /* scan 30-37 */ 176 ' ', ' ', CP, 0, 0, 0, 0, 0, /* scan 38-3F */ 177 0, 0, 0, 0, 0, NM, ST, '7', /* scan 40-47 */ 178 '8', '9', '-', '4', '5', '6', '+', '1', /* scan 48-4F */ 179 '2', '3', '0', ',', 0, 0, '<', 0, /* scan 50-57 */ 180 0, 0, 0, 0, 0, 0, 0, 0, /* scan 58-5F */ 181 0, 0, 0, 0, 0, 0, 0, 0, /* scan 60-67 */ 182 0, 0, 0, 0, 0, 0, 0, 0, /* scan 68-6F */ 183 0, 0, 0, 0, 0, 0, 0, 0, /* scan 70-77 */ 184 0, 0, 0, 0, 0, 0, 0, 0, /* scan 78-7F */ 185 '\r', CN, '/', '*', ' ', ST, 'F', 'A', /* extended */ 186 0, 'D', 'C', 0, 'B', 0, '@', 'P' /* extended */ 187 }, 188 { /* shift code */ 189 0, 0x1b, '!', '"', 0x15, '$', '%', '&', /* scan 0- 7 */ 190 '/', '(', ')', '=', '?', '`', 0x08, '\t', /* scan 8- F */ 191 'Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I', /* scan 10-17 */ 192 'O', 'P', 0x9a, '*', '\r', CN, 'A', 'S', /* scan 18-1F */ 193 'D', 'F', 'G', 'H', 'J', 'K', 'L', 0x99, /* scan 20-27 */ 194 0x8e, 0xf8, SH, '\'', 'Y', 'X', 'C', 'V', /* scan 28-2F */ 195 'B', 'N', 'M', ';', ':', '_', SH, '*', /* scan 30-37 */ 196 ' ', ' ', CP, 0, 0, 0, 0, 0, /* scan 38-3F */ 197 0, 0, 0, 0, 0, NM, ST, '7', /* scan 40-47 */ 198 '8', '9', '-', '4', '5', '6', '+', '1', /* scan 48-4F */ 199 '2', '3', '0', ',', 0, 0, '>', 0, /* scan 50-57 */ 200 0, 0, 0, 0, 0, 0, 0, 0, /* scan 58-5F */ 201 0, 0, 0, 0, 0, 0, 0, 0, /* scan 60-67 */ 202 0, 0, 0, 0, 0, 0, 0, 0, /* scan 68-6F */ 203 0, 0, 0, 0, 0, 0, 0, 0, /* scan 70-77 */ 204 0, 0, 0, 0, 0, 0, 0, 0, /* scan 78-7F */ 205 '\r', CN, '/', '*', ' ', ST, 'F', 'A', /* extended */ 206 0, 'D', 'C', 0, 'B', 0, '@', 'P' /* extended */ 207 }, 208 { /* control code */ 209 0xff, 0x1b, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, /* scan 0- 7 */ 210 0x1e, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, '\t', /* scan 8- F */ 211 0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x15, 0x09, /* scan 10-17 */ 212 0x0f, 0x10, 0x1b, 0x1d, '\r', CN, 0x01, 0x13, /* scan 18-1F */ 213 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0c, 0xff, /* scan 20-27 */ 214 0xff, 0x1c, SH, 0xff, 0x1a, 0x18, 0x03, 0x16, /* scan 28-2F */ 215 0x02, 0x0e, 0x0d, 0xff, 0xff, 0xff, SH, 0xff, /* scan 30-37 */ 216 0xff, 0xff, CP, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38-3F */ 217 0xff, 0xff, 0xff, 0xff, 0xff, NM, ST, 0xff, /* scan 40-47 */ 218 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 48-4F */ 219 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 50-57 */ 220 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58-5F */ 221 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60-67 */ 222 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68-6F */ 223 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70-77 */ 224 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78-7F */ 225 '\r', CN, '/', '*', ' ', ST, 0xff, 0xff, /* extended */ 226 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff /* extended */ 227 }, 228 { /* non numeric code */ 229 0, 0x1b, '1', '2', '3', '4', '5', '6', /* scan 0- 7 */ 230 '7', '8', '9', '0', 0xe1, '\'', 0x08, '\t', /* scan 8- F */ 231 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', /* scan 10-17 */ 232 'o', 'p', 0x81, '+', '\r', CN, 'a', 's', /* scan 18-1F */ 233 'd', 'f', 'g', 'h', 'j', 'k', 'l', 0x94, /* scan 20-27 */ 234 0x84, '^', SH, 0, 'y', 'x', 'c', 'v', /* scan 28-2F */ 235 'b', 'n', 'm', ',', '.', '-', SH, '*', /* scan 30-37 */ 236 ' ', ' ', CP, 0, 0, 0, 0, 0, /* scan 38-3F */ 237 0, 0, 0, 0, 0, NM, ST, 'w', /* scan 40-47 */ 238 'x', 'y', 'l', 't', 'u', 'v', 'm', 'q', /* scan 48-4F */ 239 'r', 's', 'p', 'n', 0, 0, '<', 0, /* scan 50-57 */ 240 0, 0, 0, 0, 0, 0, 0, 0, /* scan 58-5F */ 241 0, 0, 0, 0, 0, 0, 0, 0, /* scan 60-67 */ 242 0, 0, 0, 0, 0, 0, 0, 0, /* scan 68-6F */ 243 0, 0, 0, 0, 0, 0, 0, 0, /* scan 70-77 */ 244 0, 0, 0, 0, 0, 0, 0, 0, /* scan 78-7F */ 245 '\r', CN, '/', '*', ' ', ST, 'F', 'A', /* extended */ 246 0, 'D', 'C', 0, 'B', 0, '@', 'P' /* extended */ 247 }, 248 { /* Right alt mode - is used in German keyboard */ 249 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 0 - 7 */ 250 '{', '[', ']', '}', '\\', 0xff, 0xff, 0xff, /* scan 8 - F */ 251 '@', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 10 -17 */ 252 0xff, 0xff, 0xff, '~', 0xff, 0xff, 0xff, 0xff, /* scan 18 -1F */ 253 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 20 -27 */ 254 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 28 -2F */ 255 0xff, 0xff, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 30 -37 */ 256 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38 -3F */ 257 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 40 -47 */ 258 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 48 -4F */ 259 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, '|', 0xff, /* scan 50 -57 */ 260 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58 -5F */ 261 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60 -67 */ 262 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68 -6F */ 263 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70 -77 */ 264 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78 -7F */ 265 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* extended */ 266 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff /* extended */ 267 } 268 } 269 }; 270 271 static unsigned char ext_key_map[] = { 272 0x1c, /* keypad enter */ 273 0x1d, /* right control */ 274 0x35, /* keypad slash */ 275 0x37, /* print screen */ 276 0x38, /* right alt */ 277 0x46, /* break */ 278 0x47, /* editpad home */ 279 0x48, /* editpad up */ 280 0x49, /* editpad pgup */ 281 0x4b, /* editpad left */ 282 0x4d, /* editpad right */ 283 0x4f, /* editpad end */ 284 0x50, /* editpad dn */ 285 0x51, /* editpad pgdn */ 286 0x52, /* editpad ins */ 287 0x53, /* editpad del */ 288 0x00 /* map end */ 289 }; 290 291 /******************************************************************************/ 292 293 static int kbd_controller_present(void) 294 { 295 return in8(I8042_STATUS_REG) != 0xff; 296 } 297 298 /* 299 * Implement a weak default function for boards that optionally 300 * need to skip the i8042 initialization. 301 */ 302 int __weak board_i8042_skip(void) 303 { 304 /* As default, don't skip */ 305 return 0; 306 } 307 308 void i8042_flush(void) 309 { 310 int timeout; 311 312 /* 313 * The delay is to give the keyboard controller some time to fill the 314 * next byte. 315 */ 316 while (1) { 317 timeout = 100; /* wait for no longer than 100us */ 318 while (timeout > 0 && !(in8(I8042_STATUS_REG) & 0x01)) { 319 udelay(1); 320 timeout--; 321 } 322 323 /* Try to pull next byte if not timeout. */ 324 if (in8(I8042_STATUS_REG) & 0x01) 325 in8(I8042_DATA_REG); 326 else 327 break; 328 } 329 } 330 331 int i8042_disable(void) 332 { 333 if (kbd_input_empty() == 0) 334 return -1; 335 336 /* Disable keyboard */ 337 out8(I8042_COMMAND_REG, 0xad); 338 339 if (kbd_input_empty() == 0) 340 return -1; 341 342 return 0; 343 } 344 345 346 /******************************************************************************* 347 * 348 * i8042_kbd_init - reset keyboard and init state flags 349 */ 350 int i8042_kbd_init(void) 351 { 352 int keymap, try; 353 char *penv; 354 355 if (!kbd_controller_present() || board_i8042_skip()) 356 return -1; 357 358 /* Init keyboard device (default US layout) */ 359 keymap = KBD_US; 360 penv = getenv("keymap"); 361 if (penv != NULL) { 362 if (strncmp(penv, "de", 3) == 0) 363 keymap = KBD_GER; 364 } 365 366 for (try = 0; try < KBD_RESET_TRIES; try++) { 367 if (kbd_reset() == 0) { 368 kbd_mapping = keymap; 369 kbd_flags = NORMAL; 370 kbd_state = 0; 371 kbd_led_set(); 372 return 0; 373 } 374 } 375 return -1; 376 } 377 378 379 /******************************************************************************* 380 * 381 * i8042_tstc - test if keyboard input is available 382 * option: cursor blinking if called in a loop 383 */ 384 int i8042_tstc(struct stdio_dev *dev) 385 { 386 unsigned char scan_code = 0; 387 388 #ifdef CONFIG_CONSOLE_CURSOR 389 if (--blinkCount == 0) { 390 cursor_state ^= 1; 391 console_cursor(cursor_state); 392 blinkCount = CONFIG_SYS_CONSOLE_BLINK_COUNT; 393 udelay(10); 394 } 395 #endif 396 397 if ((in8(I8042_STATUS_REG) & 0x01) == 0) { 398 return 0; 399 } else { 400 scan_code = in8(I8042_DATA_REG); 401 if (scan_code == 0xfa) 402 return 0; 403 404 kbd_conv_char(scan_code); 405 406 if (kbd_input != -1) 407 return 1; 408 } 409 return 0; 410 } 411 412 413 /******************************************************************************* 414 * 415 * i8042_getc - wait till keyboard input is available 416 * option: turn on/off cursor while waiting 417 */ 418 int i8042_getc(struct stdio_dev *dev) 419 { 420 int ret_chr; 421 unsigned char scan_code; 422 423 while (kbd_input == -1) { 424 while ((in8(I8042_STATUS_REG) & 0x01) == 0) { 425 #ifdef CONFIG_CONSOLE_CURSOR 426 if (--blinkCount == 0) { 427 cursor_state ^= 1; 428 console_cursor(cursor_state); 429 blinkCount = CONFIG_SYS_CONSOLE_BLINK_COUNT; 430 } 431 udelay(10); 432 #endif 433 } 434 scan_code = in8(I8042_DATA_REG); 435 if (scan_code != 0xfa) 436 kbd_conv_char (scan_code); 437 } 438 ret_chr = kbd_input; 439 kbd_input = -1; 440 return ret_chr; 441 } 442 443 444 /******************************************************************************/ 445 446 static void kbd_conv_char(unsigned char scan_code) 447 { 448 if (scan_code == 0xe0) { 449 kbd_flags |= EXT; 450 return; 451 } 452 453 /* if high bit of scan_code, set break flag */ 454 if (scan_code & 0x80) 455 kbd_flags |= BRK; 456 else 457 kbd_flags &= ~BRK; 458 459 if ((scan_code == 0xe1) || (kbd_flags & E1)) { 460 if (scan_code == 0xe1) { 461 kbd_flags ^= BRK; /* reset the break flag */ 462 kbd_flags ^= E1; /* bitwise EXOR with E1 flag */ 463 } 464 return; 465 } 466 467 scan_code &= 0x7f; 468 469 if (kbd_flags & EXT) { 470 int i; 471 472 kbd_flags ^= EXT; 473 for (i = 0; ext_key_map[i]; i++) { 474 if (ext_key_map[i] == scan_code) { 475 scan_code = 0x80 + i; 476 break; 477 } 478 } 479 /* not found ? */ 480 if (!ext_key_map[i]) 481 return; 482 } 483 484 switch (kbd_fct_map[scan_code]) { 485 case AS: 486 kbd_normal(scan_code); 487 break; 488 case SH: 489 kbd_shift(scan_code); 490 break; 491 case CN: 492 kbd_ctrl(scan_code); 493 break; 494 case NM: 495 kbd_num(scan_code); 496 break; 497 case CP: 498 kbd_caps(scan_code); 499 break; 500 case ST: 501 kbd_scroll(scan_code); 502 break; 503 case AK: 504 kbd_alt(scan_code); 505 break; 506 } 507 return; 508 } 509 510 511 /******************************************************************************/ 512 513 static void kbd_normal(unsigned char scan_code) 514 { 515 unsigned char chr; 516 517 if ((kbd_flags & BRK) == NORMAL) { 518 chr = kbd_key_map[kbd_mapping][kbd_state][scan_code]; 519 if ((chr == 0xff) || (chr == 0x00)) 520 return; 521 522 /* if caps lock convert upper to lower */ 523 if (((kbd_flags & CAPS) == CAPS) && 524 (chr >= 'a' && chr <= 'z')) { 525 chr -= 'a' - 'A'; 526 } 527 kbd_input = chr; 528 } 529 } 530 531 532 /******************************************************************************/ 533 534 static void kbd_shift(unsigned char scan_code) 535 { 536 if ((kbd_flags & BRK) == BRK) { 537 kbd_state = AS; 538 kbd_flags &= (~SHIFT); 539 } else { 540 kbd_state = SH; 541 kbd_flags |= SHIFT; 542 } 543 } 544 545 546 /******************************************************************************/ 547 548 static void kbd_ctrl(unsigned char scan_code) 549 { 550 if ((kbd_flags & BRK) == BRK) { 551 kbd_state = AS; 552 kbd_flags &= (~CTRL); 553 } else { 554 kbd_state = CN; 555 kbd_flags |= CTRL; 556 } 557 } 558 559 560 /******************************************************************************/ 561 562 static void kbd_caps(unsigned char scan_code) 563 { 564 if ((kbd_flags & BRK) == NORMAL) { 565 kbd_flags ^= CAPS; 566 kbd_led_set(); /* update keyboard LED */ 567 } 568 } 569 570 571 /******************************************************************************/ 572 573 static void kbd_num(unsigned char scan_code) 574 { 575 if ((kbd_flags & BRK) == NORMAL) { 576 kbd_flags ^= NUM; 577 kbd_state = (kbd_flags & NUM) ? AS : NM; 578 kbd_led_set(); /* update keyboard LED */ 579 } 580 } 581 582 583 /******************************************************************************/ 584 585 static void kbd_scroll(unsigned char scan_code) 586 { 587 if ((kbd_flags & BRK) == NORMAL) { 588 kbd_flags ^= STP; 589 kbd_led_set(); /* update keyboard LED */ 590 if (kbd_flags & STP) 591 kbd_input = 0x13; 592 else 593 kbd_input = 0x11; 594 } 595 } 596 597 /******************************************************************************/ 598 599 static void kbd_alt(unsigned char scan_code) 600 { 601 if ((kbd_flags & BRK) == BRK) { 602 kbd_state = AS; 603 kbd_flags &= (~ALT); 604 } else { 605 kbd_state = AK; 606 kbd_flags &= ALT; 607 } 608 } 609 610 611 /******************************************************************************/ 612 613 static void kbd_led_set(void) 614 { 615 kbd_input_empty(); 616 out8(I8042_DATA_REG, 0xed); /* SET LED command */ 617 kbd_input_empty(); 618 out8(I8042_DATA_REG, (kbd_flags & 0x7)); /* LED bits only */ 619 } 620 621 622 /******************************************************************************/ 623 624 static int kbd_input_empty(void) 625 { 626 int kbdTimeout = KBD_TIMEOUT * 1000; 627 628 while ((in8(I8042_STATUS_REG) & I8042_STATUS_IN_DATA) && kbdTimeout--) 629 udelay(1); 630 631 return kbdTimeout != -1; 632 } 633 634 /******************************************************************************/ 635 636 static int wait_until_kbd_output_full(void) 637 { 638 int kbdTimeout = KBD_TIMEOUT * 1000; 639 640 while (((in8(I8042_STATUS_REG) & 0x01) == 0) && kbdTimeout--) 641 udelay(1); 642 643 return kbdTimeout != -1; 644 } 645 646 /******************************************************************************/ 647 648 static int kbd_reset(void) 649 { 650 /* KB Reset */ 651 if (kbd_input_empty() == 0) 652 return -1; 653 654 out8(I8042_DATA_REG, 0xff); 655 656 if (wait_until_kbd_output_full() == 0) 657 return -1; 658 659 if (in8(I8042_DATA_REG) != 0xfa) /* ACK */ 660 return -1; 661 662 if (wait_until_kbd_output_full() == 0) 663 return -1; 664 665 if (in8(I8042_DATA_REG) != 0xaa) /* Test Pass*/ 666 return -1; 667 668 if (kbd_input_empty() == 0) 669 return -1; 670 671 /* Set KBC mode */ 672 out8(I8042_COMMAND_REG, 0x60); 673 674 if (kbd_input_empty() == 0) 675 return -1; 676 677 out8(I8042_DATA_REG, 0x45); 678 679 if (kbd_input_empty() == 0) 680 return -1; 681 682 /* Enable Keyboard */ 683 out8(I8042_COMMAND_REG, 0xae); 684 if (kbd_input_empty() == 0) 685 return -1; 686 687 out8(I8042_COMMAND_REG, 0x60); 688 if (kbd_input_empty() == 0) 689 return -1; 690 691 out8(I8042_DATA_REG, 0xf4); 692 if (kbd_input_empty() == 0) 693 return -1; 694 695 return 0; 696 } 697