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 <i8042.h> 12 #include <input.h> 13 #include <asm/io.h> 14 15 /* defines */ 16 #define in8(p) inb(p) 17 #define out8(p, v) outb(v, p) 18 19 /* locals */ 20 static struct input_config config; 21 static bool extended; 22 23 static unsigned char ext_key_map[] = { 24 0x1c, /* keypad enter */ 25 0x1d, /* right control */ 26 0x35, /* keypad slash */ 27 0x37, /* print screen */ 28 0x38, /* right alt */ 29 0x46, /* break */ 30 0x47, /* editpad home */ 31 0x48, /* editpad up */ 32 0x49, /* editpad pgup */ 33 0x4b, /* editpad left */ 34 0x4d, /* editpad right */ 35 0x4f, /* editpad end */ 36 0x50, /* editpad dn */ 37 0x51, /* editpad pgdn */ 38 0x52, /* editpad ins */ 39 0x53, /* editpad del */ 40 0x00 /* map end */ 41 }; 42 43 static int kbd_input_empty(void) 44 { 45 int kbd_timeout = KBD_TIMEOUT * 1000; 46 47 while ((in8(I8042_STS_REG) & STATUS_IBF) && kbd_timeout--) 48 udelay(1); 49 50 return kbd_timeout != -1; 51 } 52 53 static int kbd_output_full(void) 54 { 55 int kbd_timeout = KBD_TIMEOUT * 1000; 56 57 while (((in8(I8042_STS_REG) & STATUS_OBF) == 0) && kbd_timeout--) 58 udelay(1); 59 60 return kbd_timeout != -1; 61 } 62 63 static void kbd_led_set(int flags) 64 { 65 kbd_input_empty(); 66 out8(I8042_DATA_REG, CMD_SET_KBD_LED); 67 kbd_input_empty(); 68 out8(I8042_DATA_REG, flags & 0x7); 69 } 70 71 static int kbd_write(int reg, int value) 72 { 73 if (!kbd_input_empty()) 74 return -1; 75 out8(reg, value); 76 77 return 0; 78 } 79 80 static int kbd_read(int reg) 81 { 82 if (!kbd_output_full()) 83 return -1; 84 85 return in8(reg); 86 } 87 88 static int kbd_cmd_read(int cmd) 89 { 90 if (kbd_write(I8042_CMD_REG, cmd)) 91 return -1; 92 93 return kbd_read(I8042_DATA_REG); 94 } 95 96 static int kbd_cmd_write(int cmd, int data) 97 { 98 if (kbd_write(I8042_CMD_REG, cmd)) 99 return -1; 100 101 return kbd_write(I8042_DATA_REG, data); 102 } 103 104 static int kbd_reset(void) 105 { 106 int config; 107 108 /* controller self test */ 109 if (kbd_cmd_read(CMD_SELF_TEST) != KBC_TEST_OK) 110 goto err; 111 112 /* keyboard reset */ 113 if (kbd_write(I8042_DATA_REG, CMD_RESET_KBD) || 114 kbd_read(I8042_DATA_REG) != KBD_ACK || 115 kbd_read(I8042_DATA_REG) != KBD_POR) 116 goto err; 117 118 /* set AT translation and disable irq */ 119 config = kbd_cmd_read(CMD_RD_CONFIG); 120 if (config == -1) 121 goto err; 122 123 config |= CONFIG_AT_TRANS; 124 config &= ~(CONFIG_KIRQ_EN | CONFIG_MIRQ_EN); 125 if (kbd_cmd_write(CMD_WR_CONFIG, config)) 126 goto err; 127 128 /* enable keyboard */ 129 if (kbd_write(I8042_CMD_REG, CMD_KBD_EN) || 130 !kbd_input_empty()) 131 goto err; 132 133 return 0; 134 err: 135 debug("%s: Keyboard failure\n", __func__); 136 return -1; 137 } 138 139 static int kbd_controller_present(void) 140 { 141 return in8(I8042_STS_REG) != 0xff; 142 } 143 144 /* 145 * Implement a weak default function for boards that optionally 146 * need to skip the i8042 initialization. 147 */ 148 int __weak board_i8042_skip(void) 149 { 150 /* As default, don't skip */ 151 return 0; 152 } 153 154 void i8042_flush(void) 155 { 156 int timeout; 157 158 /* 159 * The delay is to give the keyboard controller some time 160 * to fill the next byte. 161 */ 162 while (1) { 163 timeout = 100; /* wait for no longer than 100us */ 164 while (timeout > 0 && !(in8(I8042_STS_REG) & STATUS_OBF)) { 165 udelay(1); 166 timeout--; 167 } 168 169 /* Try to pull next byte if not timeout */ 170 if (in8(I8042_STS_REG) & STATUS_OBF) 171 in8(I8042_DATA_REG); 172 else 173 break; 174 } 175 } 176 177 int i8042_disable(void) 178 { 179 if (kbd_input_empty() == 0) 180 return -1; 181 182 /* Disable keyboard */ 183 out8(I8042_CMD_REG, CMD_KBD_DIS); 184 185 if (kbd_input_empty() == 0) 186 return -1; 187 188 return 0; 189 } 190 191 static int i8042_kbd_check(struct input_config *input) 192 { 193 if ((in8(I8042_STS_REG) & STATUS_OBF) == 0) { 194 return 0; 195 } else { 196 bool release = false; 197 int scan_code; 198 int i; 199 200 scan_code = in8(I8042_DATA_REG); 201 if (scan_code == 0xfa) { 202 return 0; 203 } else if (scan_code == 0xe0) { 204 extended = true; 205 return 0; 206 } 207 if (scan_code & 0x80) { 208 scan_code &= 0x7f; 209 release = true; 210 } 211 if (extended) { 212 extended = false; 213 for (i = 0; ext_key_map[i]; i++) { 214 if (ext_key_map[i] == scan_code) { 215 scan_code = 0x60 + i; 216 break; 217 } 218 } 219 /* not found ? */ 220 if (!ext_key_map[i]) 221 return 0; 222 } 223 224 input_add_keycode(&config, scan_code, release); 225 return 1; 226 } 227 } 228 229 /* i8042_kbd_init - reset keyboard and init state flags */ 230 int i8042_kbd_init(void) 231 { 232 int keymap, try; 233 char *penv; 234 int ret; 235 236 if (!kbd_controller_present() || board_i8042_skip()) { 237 debug("i8042 keyboard controller is not present\n"); 238 return -1; 239 } 240 241 /* Init keyboard device (default US layout) */ 242 keymap = KBD_US; 243 penv = getenv("keymap"); 244 if (penv != NULL) { 245 if (strncmp(penv, "de", 3) == 0) 246 keymap = KBD_GER; 247 } 248 249 for (try = 0; kbd_reset() != 0; try++) { 250 if (try >= KBD_RESET_TRIES) 251 return -1; 252 } 253 254 ret = input_init(&config, keymap == KBD_GER); 255 if (ret) 256 return ret; 257 config.read_keys = i8042_kbd_check; 258 input_allow_repeats(&config, true); 259 260 kbd_led_set(NORMAL); 261 262 return 0; 263 } 264 265 /** 266 * check_leds() - Check the keyboard LEDs and update them it needed 267 * 268 * @ret: Value to return 269 * @return value of @ret 270 */ 271 static int check_leds(int ret) 272 { 273 int leds; 274 275 leds = input_leds_changed(&config); 276 if (leds >= 0) 277 kbd_led_set(leds); 278 279 return ret; 280 } 281 282 /* i8042_tstc - test if keyboard input is available */ 283 int i8042_tstc(struct stdio_dev *dev) 284 { 285 return check_leds(input_tstc(&config)); 286 } 287 288 /* i8042_getc - wait till keyboard input is available */ 289 int i8042_getc(struct stdio_dev *dev) 290 { 291 return check_leds(input_getc(&config)); 292 } 293