xref: /openbmc/u-boot/drivers/input/i8042.c (revision dcbf825714e27a4c39edcc36c7623b37bc40040a)
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 #include <common.h>
11 #include <dm.h>
12 #include <errno.h>
13 #include <i8042.h>
14 #include <input.h>
15 #include <keyboard.h>
16 #include <asm/io.h>
17 
18 /* defines */
19 #define in8(p)		inb(p)
20 #define out8(p, v)	outb(v, p)
21 
22 /* locals */
23 struct i8042_kbd_priv {
24 	bool extended;	/* true if an extended keycode is expected next */
25 };
26 
27 static unsigned char ext_key_map[] = {
28 	0x1c, /* keypad enter */
29 	0x1d, /* right control */
30 	0x35, /* keypad slash */
31 	0x37, /* print screen */
32 	0x38, /* right alt */
33 	0x46, /* break */
34 	0x47, /* editpad home */
35 	0x48, /* editpad up */
36 	0x49, /* editpad pgup */
37 	0x4b, /* editpad left */
38 	0x4d, /* editpad right */
39 	0x4f, /* editpad end */
40 	0x50, /* editpad dn */
41 	0x51, /* editpad pgdn */
42 	0x52, /* editpad ins */
43 	0x53, /* editpad del */
44 	0x00  /* map end */
45 	};
46 
47 static int kbd_input_empty(void)
48 {
49 	int kbd_timeout = KBD_TIMEOUT * 1000;
50 
51 	while ((in8(I8042_STS_REG) & STATUS_IBF) && kbd_timeout--)
52 		udelay(1);
53 
54 	return kbd_timeout != -1;
55 }
56 
57 static int kbd_output_full(void)
58 {
59 	int kbd_timeout = KBD_TIMEOUT * 1000;
60 
61 	while (((in8(I8042_STS_REG) & STATUS_OBF) == 0) && kbd_timeout--)
62 		udelay(1);
63 
64 	return kbd_timeout != -1;
65 }
66 
67 /**
68  * check_leds() - Check the keyboard LEDs and update them it needed
69  *
70  * @ret:	Value to return
71  * @return value of @ret
72  */
73 static int i8042_kbd_update_leds(struct udevice *dev, int leds)
74 {
75 	kbd_input_empty();
76 	out8(I8042_DATA_REG, CMD_SET_KBD_LED);
77 	kbd_input_empty();
78 	out8(I8042_DATA_REG, leds & 0x7);
79 
80 	return 0;
81 }
82 
83 static int kbd_write(int reg, int value)
84 {
85 	if (!kbd_input_empty())
86 		return -1;
87 	out8(reg, value);
88 
89 	return 0;
90 }
91 
92 static int kbd_read(int reg)
93 {
94 	if (!kbd_output_full())
95 		return -1;
96 
97 	return in8(reg);
98 }
99 
100 static int kbd_cmd_read(int cmd)
101 {
102 	if (kbd_write(I8042_CMD_REG, cmd))
103 		return -1;
104 
105 	return kbd_read(I8042_DATA_REG);
106 }
107 
108 static int kbd_cmd_write(int cmd, int data)
109 {
110 	if (kbd_write(I8042_CMD_REG, cmd))
111 		return -1;
112 
113 	return kbd_write(I8042_DATA_REG, data);
114 }
115 
116 static int kbd_reset(void)
117 {
118 	int config;
119 
120 	/* controller self test */
121 	if (kbd_cmd_read(CMD_SELF_TEST) != KBC_TEST_OK)
122 		goto err;
123 
124 	/* keyboard reset */
125 	if (kbd_write(I8042_DATA_REG, CMD_RESET_KBD) ||
126 	    kbd_read(I8042_DATA_REG) != KBD_ACK ||
127 	    kbd_read(I8042_DATA_REG) != KBD_POR)
128 		goto err;
129 
130 	/* set AT translation and disable irq */
131 	config = kbd_cmd_read(CMD_RD_CONFIG);
132 	if (config == -1)
133 		goto err;
134 
135 	config |= CONFIG_AT_TRANS;
136 	config &= ~(CONFIG_KIRQ_EN | CONFIG_MIRQ_EN);
137 	if (kbd_cmd_write(CMD_WR_CONFIG, config))
138 		goto err;
139 
140 	/* enable keyboard */
141 	if (kbd_write(I8042_CMD_REG, CMD_KBD_EN) ||
142 	    !kbd_input_empty())
143 		goto err;
144 
145 	return 0;
146 err:
147 	debug("%s: Keyboard failure\n", __func__);
148 	return -1;
149 }
150 
151 static int kbd_controller_present(void)
152 {
153 	return in8(I8042_STS_REG) != 0xff;
154 }
155 
156 /*
157  * Implement a weak default function for boards that optionally
158  * need to skip the i8042 initialization.
159  *
160  * TODO(sjg@chromium.org): Use device tree for this?
161  */
162 int __weak board_i8042_skip(void)
163 {
164 	/* As default, don't skip */
165 	return 0;
166 }
167 
168 void i8042_flush(void)
169 {
170 	int timeout;
171 
172 	/*
173 	 * The delay is to give the keyboard controller some time
174 	 * to fill the next byte.
175 	 */
176 	while (1) {
177 		timeout = 100;	/* wait for no longer than 100us */
178 		while (timeout > 0 && !(in8(I8042_STS_REG) & STATUS_OBF)) {
179 			udelay(1);
180 			timeout--;
181 		}
182 
183 		/* Try to pull next byte if not timeout */
184 		if (in8(I8042_STS_REG) & STATUS_OBF)
185 			in8(I8042_DATA_REG);
186 		else
187 			break;
188 	}
189 }
190 
191 int i8042_disable(void)
192 {
193 	if (kbd_input_empty() == 0)
194 		return -1;
195 
196 	/* Disable keyboard */
197 	out8(I8042_CMD_REG, CMD_KBD_DIS);
198 
199 	if (kbd_input_empty() == 0)
200 		return -1;
201 
202 	return 0;
203 }
204 
205 static int i8042_kbd_check(struct input_config *input)
206 {
207 	struct i8042_kbd_priv *priv = dev_get_priv(input->dev);
208 
209 	if ((in8(I8042_STS_REG) & STATUS_OBF) == 0) {
210 		return 0;
211 	} else {
212 		bool release = false;
213 		int scan_code;
214 		int i;
215 
216 		scan_code = in8(I8042_DATA_REG);
217 		if (scan_code == 0xfa) {
218 			return 0;
219 		} else if (scan_code == 0xe0) {
220 			priv->extended = true;
221 			return 0;
222 		}
223 		if (scan_code & 0x80) {
224 			scan_code &= 0x7f;
225 			release = true;
226 		}
227 		if (priv->extended) {
228 			priv->extended = false;
229 			for (i = 0; ext_key_map[i]; i++) {
230 				if (ext_key_map[i] == scan_code) {
231 					scan_code = 0x60 + i;
232 					break;
233 				}
234 			}
235 			/* not found ? */
236 			if (!ext_key_map[i])
237 				return 0;
238 		}
239 
240 		input_add_keycode(input, scan_code, release);
241 		return 1;
242 	}
243 }
244 
245 /* i8042_kbd_init - reset keyboard and init state flags */
246 static int i8042_start(struct udevice *dev)
247 {
248 	struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev);
249 	struct input_config *input = &uc_priv->input;
250 	int keymap, try;
251 	char *penv;
252 	int ret;
253 
254 	if (!kbd_controller_present() || board_i8042_skip()) {
255 		debug("i8042 keyboard controller is not present\n");
256 		return -ENOENT;
257 	}
258 
259 	/* Init keyboard device (default US layout) */
260 	keymap = KBD_US;
261 	penv = getenv("keymap");
262 	if (penv != NULL) {
263 		if (strncmp(penv, "de", 3) == 0)
264 			keymap = KBD_GER;
265 	}
266 
267 	for (try = 0; kbd_reset() != 0; try++) {
268 		if (try >= KBD_RESET_TRIES)
269 			return -1;
270 	}
271 
272 	ret = input_add_tables(input, keymap == KBD_GER);
273 	if (ret)
274 		return ret;
275 
276 	i8042_kbd_update_leds(dev, NORMAL);
277 	debug("%s: started\n", __func__);
278 
279 	return 0;
280 }
281 
282 /**
283  * Set up the i8042 keyboard. This is called by the stdio device handler
284  *
285  * We want to do this init when the keyboard is actually used rather than
286  * at start-up, since keyboard input may not currently be selected.
287  *
288  * Once the keyboard starts there will be a period during which we must
289  * wait for the keyboard to init. We do this only when a key is first
290  * read - see kbd_wait_for_fifo_init().
291  *
292  * @return 0 if ok, -ve on error
293  */
294 static int i8042_kbd_probe(struct udevice *dev)
295 {
296 	struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev);
297 	struct stdio_dev *sdev = &uc_priv->sdev;
298 	struct input_config *input = &uc_priv->input;
299 	int ret;
300 
301 	/* Register the device. i8042_start() will be called soon */
302 	input->dev = dev;
303 	input->read_keys = i8042_kbd_check;
304 	input_allow_repeats(input, true);
305 	strcpy(sdev->name, "i8042-kbd");
306 	ret = input_stdio_register(sdev);
307 	if (ret) {
308 		debug("%s: input_stdio_register() failed\n", __func__);
309 		return ret;
310 	}
311 	debug("%s: ready\n", __func__);
312 
313 	return 0;
314 }
315 
316 static const struct keyboard_ops i8042_kbd_ops = {
317 	.start	= i8042_start,
318 	.update_leds	= i8042_kbd_update_leds,
319 };
320 
321 static const struct udevice_id i8042_kbd_ids[] = {
322 	{ .compatible = "intel,i8042-keyboard" },
323 	{ }
324 };
325 
326 U_BOOT_DRIVER(i8042_kbd) = {
327 	.name	= "i8042_kbd",
328 	.id	= UCLASS_KEYBOARD,
329 	.of_match = i8042_kbd_ids,
330 	.probe = i8042_kbd_probe,
331 	.ops	= &i8042_kbd_ops,
332 	.priv_auto_alloc_size = sizeof(struct i8042_kbd_priv),
333 };
334