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