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