1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 5 * Copyright (c) 2015 Nahanni Systems Inc. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 35 #include <assert.h> 36 #include <stdbool.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <strings.h> 40 #include <pthread.h> 41 #include <pthread_np.h> 42 #include <unistd.h> 43 #include <fcntl.h> 44 45 #include "atkbdc.h" 46 #include "bhyverun.h" 47 #include "config.h" 48 #include "console.h" 49 #include "debug.h" 50 #include "ps2kbd.h" 51 52 /* keyboard device commands */ 53 #define PS2KC_RESET_DEV 0xff 54 #define PS2KC_DISABLE 0xf5 55 #define PS2KC_ENABLE 0xf4 56 #define PS2KC_SET_TYPEMATIC 0xf3 57 #define PS2KC_SEND_DEV_ID 0xf2 58 #define PS2KC_SET_SCANCODE_SET 0xf0 59 #define PS2KC_ECHO 0xee 60 #define PS2KC_SET_LEDS 0xed 61 62 #define PS2KC_BAT_SUCCESS 0xaa 63 #define PS2KC_ACK 0xfa 64 65 #define PS2KBD_FIFOSZ 16 66 67 #define PS2KBD_LAYOUT_BASEDIR "/usr/share/bhyve/kbdlayout/" 68 69 #define MAX_PATHNAME 256 70 71 struct fifo { 72 uint8_t buf[PS2KBD_FIFOSZ]; 73 int rindex; /* index to read from */ 74 int windex; /* index to write to */ 75 int num; /* number of bytes in the fifo */ 76 int size; /* size of the fifo */ 77 }; 78 79 struct ps2kbd_softc { 80 struct atkbdc_softc *atkbdc_sc; 81 pthread_mutex_t mtx; 82 83 bool enabled; 84 struct fifo fifo; 85 86 uint8_t curcmd; /* current command for next byte */ 87 }; 88 89 #define SCANCODE_E0_PREFIX 1 90 struct extended_translation { 91 uint32_t keysym; 92 uint8_t scancode; 93 int flags; 94 }; 95 96 /* 97 * FIXME: Pause/break and Print Screen/SysRq require special handling. 98 */ 99 static struct extended_translation extended_translations[128] = { 100 {0xff08, 0x66, 0}, /* Back space */ 101 {0xff09, 0x0d, 0}, /* Tab */ 102 {0xff0d, 0x5a, 0}, /* Return */ 103 {0xff1b, 0x76, 0}, /* Escape */ 104 {0xff50, 0x6c, SCANCODE_E0_PREFIX}, /* Home */ 105 {0xff51, 0x6b, SCANCODE_E0_PREFIX}, /* Left arrow */ 106 {0xff52, 0x75, SCANCODE_E0_PREFIX}, /* Up arrow */ 107 {0xff53, 0x74, SCANCODE_E0_PREFIX}, /* Right arrow */ 108 {0xff54, 0x72, SCANCODE_E0_PREFIX}, /* Down arrow */ 109 {0xff55, 0x7d, SCANCODE_E0_PREFIX}, /* PgUp */ 110 {0xff56, 0x7a, SCANCODE_E0_PREFIX}, /* PgDown */ 111 {0xff57, 0x69, SCANCODE_E0_PREFIX}, /* End */ 112 {0xff63, 0x70, SCANCODE_E0_PREFIX}, /* Ins */ 113 {0xff8d, 0x5a, SCANCODE_E0_PREFIX}, /* Keypad Enter */ 114 {0xffe1, 0x12, 0}, /* Left shift */ 115 {0xffe2, 0x59, 0}, /* Right shift */ 116 {0xffe3, 0x14, 0}, /* Left control */ 117 {0xffe4, 0x14, SCANCODE_E0_PREFIX}, /* Right control */ 118 /* {0xffe7, XXX}, Left meta */ 119 /* {0xffe8, XXX}, Right meta */ 120 {0xffe9, 0x11, 0}, /* Left alt */ 121 {0xfe03, 0x11, SCANCODE_E0_PREFIX}, /* AltGr */ 122 {0xffea, 0x11, SCANCODE_E0_PREFIX}, /* Right alt */ 123 {0xffeb, 0x1f, SCANCODE_E0_PREFIX}, /* Left Windows */ 124 {0xffec, 0x27, SCANCODE_E0_PREFIX}, /* Right Windows */ 125 {0xffbe, 0x05, 0}, /* F1 */ 126 {0xffbf, 0x06, 0}, /* F2 */ 127 {0xffc0, 0x04, 0}, /* F3 */ 128 {0xffc1, 0x0c, 0}, /* F4 */ 129 {0xffc2, 0x03, 0}, /* F5 */ 130 {0xffc3, 0x0b, 0}, /* F6 */ 131 {0xffc4, 0x83, 0}, /* F7 */ 132 {0xffc5, 0x0a, 0}, /* F8 */ 133 {0xffc6, 0x01, 0}, /* F9 */ 134 {0xffc7, 0x09, 0}, /* F10 */ 135 {0xffc8, 0x78, 0}, /* F11 */ 136 {0xffc9, 0x07, 0}, /* F12 */ 137 {0xffff, 0x71, SCANCODE_E0_PREFIX}, /* Del */ 138 {0xff14, 0x7e, 0}, /* ScrollLock */ 139 /* NumLock and Keypads*/ 140 {0xff7f, 0x77, 0}, /* NumLock */ 141 {0xffaf, 0x4a, SCANCODE_E0_PREFIX}, /* Keypad slash */ 142 {0xffaa, 0x7c, 0}, /* Keypad asterisk */ 143 {0xffad, 0x7b, 0}, /* Keypad minus */ 144 {0xffab, 0x79, 0}, /* Keypad plus */ 145 {0xffb7, 0x6c, 0}, /* Keypad 7 */ 146 {0xff95, 0x6c, 0}, /* Keypad home */ 147 {0xffb8, 0x75, 0}, /* Keypad 8 */ 148 {0xff97, 0x75, 0}, /* Keypad up arrow */ 149 {0xffb9, 0x7d, 0}, /* Keypad 9 */ 150 {0xff9a, 0x7d, 0}, /* Keypad PgUp */ 151 {0xffb4, 0x6b, 0}, /* Keypad 4 */ 152 {0xff96, 0x6b, 0}, /* Keypad left arrow */ 153 {0xffb5, 0x73, 0}, /* Keypad 5 */ 154 {0xff9d, 0x73, 0}, /* Keypad empty */ 155 {0xffb6, 0x74, 0}, /* Keypad 6 */ 156 {0xff98, 0x74, 0}, /* Keypad right arrow */ 157 {0xffb1, 0x69, 0}, /* Keypad 1 */ 158 {0xff9c, 0x69, 0}, /* Keypad end */ 159 {0xffb2, 0x72, 0}, /* Keypad 2 */ 160 {0xff99, 0x72, 0}, /* Keypad down arrow */ 161 {0xffb3, 0x7a, 0}, /* Keypad 3 */ 162 {0xff9b, 0x7a, 0}, /* Keypad PgDown */ 163 {0xffb0, 0x70, 0}, /* Keypad 0 */ 164 {0xff9e, 0x70, 0}, /* Keypad ins */ 165 {0xffae, 0x71, 0}, /* Keypad . */ 166 {0xff9f, 0x71, 0}, /* Keypad del */ 167 {0, 0, 0} /* Terminator */ 168 }; 169 170 /* ASCII to type 2 scancode lookup table */ 171 static uint8_t ascii_translations[128] = { 172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 176 0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52, 177 0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a, 178 0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d, 179 0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a, 180 0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34, 181 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44, 182 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d, 183 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e, 184 0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34, 185 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44, 186 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d, 187 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00, 188 }; 189 190 /* ScanCode set1 to set2 lookup table */ 191 static const uint8_t keyset1to2_translations[128] = { 192 0, 0x76, 0x16, 0x1E, 0x26, 0x25, 0x2e, 0x36, 193 0x3d, 0x3e, 0x46, 0x45, 0x4e, 0x55, 0x66, 0x0d, 194 0x15, 0x1d, 0x24, 0x2d, 0x2c, 0x35, 0x3c, 0x43, 195 0x44, 0x4d, 0x54, 0x5b, 0x5a, 0x14, 0x1c, 0x1b, 196 0x23, 0x2b, 0x34, 0x33, 0x3b, 0x42, 0x4b, 0x4c, 197 0x52, 0x0e, 0x12, 0x5d, 0x1a, 0x22, 0x21, 0x2a, 198 0x32, 0x31, 0x3a, 0x41, 0x49, 0x4a, 0x59, 0x7c, 199 0x11, 0x29, 0x58, 0x05, 0x06, 0x04, 0x0c, 0x03, 200 0x0b, 0x83, 0x0a, 0x01, 0x09, 0x77, 0x7e, 0x6c, 201 0x75, 0x7d, 0x7b, 0x6b, 0x73, 0x74, 0x79, 0x69, 202 0x72, 0x7a, 0x70, 0x71, 0x84, 0x60, 0x61, 0x78, 203 0x07, 0x0f, 0x17, 0x1f, 0x27, 0x2f, 0x37, 0x3f, 204 0x47, 0x4f, 0x56, 0x5e, 0x08, 0x10, 0x18, 0x20, 205 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x57, 0x6f, 206 0x13, 0x19, 0x39, 0x51, 0x53, 0x5c, 0x5f, 0x62, 207 0x63, 0x64, 0x65, 0x67, 0x68, 0x6a, 0x6d, 0x6e, 208 }; 209 210 static void 211 fifo_init(struct ps2kbd_softc *sc) 212 { 213 struct fifo *fifo; 214 215 fifo = &sc->fifo; 216 fifo->size = sizeof(((struct fifo *)0)->buf); 217 } 218 219 static void 220 fifo_reset(struct ps2kbd_softc *sc) 221 { 222 struct fifo *fifo; 223 224 fifo = &sc->fifo; 225 bzero(fifo, sizeof(struct fifo)); 226 fifo->size = sizeof(((struct fifo *)0)->buf); 227 } 228 229 static void 230 fifo_put(struct ps2kbd_softc *sc, uint8_t val) 231 { 232 struct fifo *fifo; 233 234 fifo = &sc->fifo; 235 if (fifo->num < fifo->size) { 236 fifo->buf[fifo->windex] = val; 237 fifo->windex = (fifo->windex + 1) % fifo->size; 238 fifo->num++; 239 } 240 } 241 242 static int 243 fifo_get(struct ps2kbd_softc *sc, uint8_t *val) 244 { 245 struct fifo *fifo; 246 247 fifo = &sc->fifo; 248 if (fifo->num > 0) { 249 *val = fifo->buf[fifo->rindex]; 250 fifo->rindex = (fifo->rindex + 1) % fifo->size; 251 fifo->num--; 252 return (0); 253 } 254 255 return (-1); 256 } 257 258 int 259 ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val) 260 { 261 int retval; 262 263 pthread_mutex_lock(&sc->mtx); 264 retval = fifo_get(sc, val); 265 pthread_mutex_unlock(&sc->mtx); 266 267 return (retval); 268 } 269 270 void 271 ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val) 272 { 273 pthread_mutex_lock(&sc->mtx); 274 if (sc->curcmd) { 275 switch (sc->curcmd) { 276 case PS2KC_SET_TYPEMATIC: 277 fifo_put(sc, PS2KC_ACK); 278 break; 279 case PS2KC_SET_SCANCODE_SET: 280 fifo_put(sc, PS2KC_ACK); 281 break; 282 case PS2KC_SET_LEDS: 283 fifo_put(sc, PS2KC_ACK); 284 break; 285 default: 286 EPRINTLN("Unhandled ps2 keyboard current " 287 "command byte 0x%02x", val); 288 break; 289 } 290 sc->curcmd = 0; 291 } else { 292 switch (val) { 293 case 0x00: 294 fifo_put(sc, PS2KC_ACK); 295 break; 296 case PS2KC_RESET_DEV: 297 fifo_reset(sc); 298 fifo_put(sc, PS2KC_ACK); 299 fifo_put(sc, PS2KC_BAT_SUCCESS); 300 break; 301 case PS2KC_DISABLE: 302 sc->enabled = false; 303 fifo_put(sc, PS2KC_ACK); 304 break; 305 case PS2KC_ENABLE: 306 sc->enabled = true; 307 fifo_reset(sc); 308 fifo_put(sc, PS2KC_ACK); 309 break; 310 case PS2KC_SET_TYPEMATIC: 311 sc->curcmd = val; 312 fifo_put(sc, PS2KC_ACK); 313 break; 314 case PS2KC_SEND_DEV_ID: 315 fifo_put(sc, PS2KC_ACK); 316 fifo_put(sc, 0xab); 317 fifo_put(sc, 0x83); 318 break; 319 case PS2KC_SET_SCANCODE_SET: 320 sc->curcmd = val; 321 fifo_put(sc, PS2KC_ACK); 322 break; 323 case PS2KC_ECHO: 324 fifo_put(sc, PS2KC_ECHO); 325 break; 326 case PS2KC_SET_LEDS: 327 sc->curcmd = val; 328 fifo_put(sc, PS2KC_ACK); 329 break; 330 default: 331 EPRINTLN("Unhandled ps2 keyboard command " 332 "0x%02x", val); 333 break; 334 } 335 } 336 pthread_mutex_unlock(&sc->mtx); 337 } 338 339 /* 340 * Translate keysym to type 2 scancode and insert into keyboard buffer. 341 */ 342 static void 343 ps2kbd_keysym_queue(struct ps2kbd_softc *sc, 344 int down, uint32_t keysym, uint32_t keycode) 345 { 346 const struct extended_translation *trans; 347 int e0_prefix, found; 348 uint8_t code; 349 350 assert(pthread_mutex_isowned_np(&sc->mtx)); 351 352 if (keycode) { 353 code = keyset1to2_translations[(uint8_t)(keycode & 0x7f)]; 354 e0_prefix = ((keycode & 0x80) ? SCANCODE_E0_PREFIX : 0); 355 found = 1; 356 } else { 357 found = 0; 358 if (keysym < 0x80) { 359 code = ascii_translations[keysym]; 360 e0_prefix = 0; 361 found = 1; 362 } else { 363 for (trans = &extended_translations[0]; 364 trans->keysym != 0; trans++) { 365 if (keysym == trans->keysym) { 366 code = trans->scancode; 367 e0_prefix = trans->flags & SCANCODE_E0_PREFIX; 368 found = 1; 369 break; 370 } 371 } 372 } 373 } 374 375 if (!found) { 376 EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym); 377 return; 378 } 379 380 if (e0_prefix) 381 fifo_put(sc, 0xe0); 382 if (!down) 383 fifo_put(sc, 0xf0); 384 fifo_put(sc, code); 385 } 386 387 static void 388 ps2kbd_event(int down, uint32_t keysym, uint32_t keycode, void *arg) 389 { 390 struct ps2kbd_softc *sc = arg; 391 int fifo_full; 392 393 pthread_mutex_lock(&sc->mtx); 394 if (!sc->enabled) { 395 pthread_mutex_unlock(&sc->mtx); 396 return; 397 } 398 fifo_full = sc->fifo.num == PS2KBD_FIFOSZ; 399 ps2kbd_keysym_queue(sc, down, keysym, keycode); 400 pthread_mutex_unlock(&sc->mtx); 401 402 if (!fifo_full) 403 atkbdc_event(sc->atkbdc_sc, 1); 404 } 405 406 static void 407 ps2kbd_update_extended_translation(uint32_t keycode, uint32_t scancode, uint32_t prefix) 408 { 409 int i = 0; 410 411 do { 412 if (extended_translations[i].keysym == keycode) 413 break; 414 } while (extended_translations[++i].keysym); 415 416 if (i == (sizeof(extended_translations) / sizeof(struct extended_translation) - 1)) 417 return; 418 419 if (!extended_translations[i].keysym) { 420 extended_translations[i].keysym = keycode; 421 422 extended_translations[i+1].keysym = 0; 423 extended_translations[i+1].scancode = 0; 424 extended_translations[i+1].flags = 0; 425 } 426 427 extended_translations[i].scancode = (uint8_t)(scancode & 0xff); 428 extended_translations[i].flags = (prefix ? SCANCODE_E0_PREFIX : 0); 429 } 430 431 static void 432 ps2kbd_setkbdlayout(void) 433 { 434 int err; 435 int fd; 436 char path[MAX_PATHNAME]; 437 char *buf, *next, *line; 438 struct stat sb; 439 ssize_t sz; 440 uint8_t ascii; 441 uint32_t keycode, scancode, prefix; 442 443 snprintf(path, MAX_PATHNAME, PS2KBD_LAYOUT_BASEDIR"%s", get_config_value("keyboard.layout") ); 444 445 err = stat(path, &sb); 446 if (err) 447 return; 448 449 buf = (char *)malloc(sizeof(char) * sb.st_size); 450 if (buf == NULL) 451 return; 452 453 fd = open(path, O_RDONLY); 454 if (fd == -1) 455 goto out; 456 457 sz = read(fd, buf, sb.st_size); 458 459 close(fd); 460 461 if (sz < 0 || sz != sb.st_size) 462 goto out; 463 464 next = buf; 465 while ((line = strsep(&next, "\n")) != NULL) { 466 if (sscanf(line, "'%c',%x;", &ascii, &scancode) == 2) { 467 if (ascii < 0x80) 468 ascii_translations[ascii] = (uint8_t)(scancode & 0xff); 469 } else if (sscanf(line, "%x,%x,%x;", &keycode, &scancode, &prefix) == 3 ) { 470 ps2kbd_update_extended_translation(keycode, scancode, prefix); 471 } else if (sscanf(line, "%x,%x;", &keycode, &scancode) == 2) { 472 if (keycode < 0x80) 473 ascii_translations[(uint8_t)(keycode & 0xff)] = (uint8_t)(scancode & 0xff); 474 else 475 ps2kbd_update_extended_translation(keycode, scancode, 0); 476 } 477 } 478 479 out: 480 free(buf); 481 } 482 483 struct ps2kbd_softc * 484 ps2kbd_init(struct atkbdc_softc *atkbdc_sc) 485 { 486 struct ps2kbd_softc *sc; 487 488 if (get_config_value("keyboard.layout") != NULL) 489 ps2kbd_setkbdlayout(); 490 491 sc = calloc(1, sizeof (struct ps2kbd_softc)); 492 pthread_mutex_init(&sc->mtx, NULL); 493 fifo_init(sc); 494 sc->atkbdc_sc = atkbdc_sc; 495 496 console_kbd_register(ps2kbd_event, sc, 1); 497 498 return (sc); 499 } 500 501