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