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