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