xref: /openbmc/u-boot/drivers/input/i8042.c (revision 8cb78722)
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 	if (kbd_input_empty() == 0)
702 		return -1;
703 
704 	out8(I8042_COMMAND_REG, 0x60);
705 	if (kbd_input_empty() == 0)
706 		return -1;
707 
708 	out8(I8042_DATA_REG, 0xf4);
709 	if (kbd_input_empty() == 0)
710 		return -1;
711 
712 	return 0;
713 }
714