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