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