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