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