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