1300829Sgrehan/*- 2336189Saraujo * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3336189Saraujo * 4300829Sgrehan * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 5300829Sgrehan * Copyright (c) 2015 Nahanni Systems Inc. 6300829Sgrehan * All rights reserved. 7300829Sgrehan * 8300829Sgrehan * Redistribution and use in source and binary forms, with or without 9300829Sgrehan * modification, are permitted provided that the following conditions 10300829Sgrehan * are met: 11300829Sgrehan * 1. Redistributions of source code must retain the above copyright 12300829Sgrehan * notice, this list of conditions and the following disclaimer. 13300829Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 14300829Sgrehan * notice, this list of conditions and the following disclaimer in the 15300829Sgrehan * documentation and/or other materials provided with the distribution. 16300829Sgrehan * 17300829Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 18300829Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19300829Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20300829Sgrehan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21300829Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22300829Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23300829Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24300829Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25300829Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26300829Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27300829Sgrehan * SUCH DAMAGE. 28300829Sgrehan */ 29300829Sgrehan 30300829Sgrehan#include <sys/cdefs.h> 31300829Sgrehan__FBSDID("$FreeBSD: stable/11/usr.sbin/bhyve/ps2kbd.c 341758 2018-12-09 06:42:06Z araujo $"); 32300829Sgrehan 33300829Sgrehan#include <sys/types.h> 34300829Sgrehan 35300829Sgrehan#include <assert.h> 36300829Sgrehan#include <stdbool.h> 37300829Sgrehan#include <stdio.h> 38300829Sgrehan#include <stdlib.h> 39300829Sgrehan#include <strings.h> 40300829Sgrehan#include <pthread.h> 41300829Sgrehan#include <pthread_np.h> 42300829Sgrehan 43300829Sgrehan#include "atkbdc.h" 44300829Sgrehan#include "console.h" 45300829Sgrehan 46300829Sgrehan/* keyboard device commands */ 47300829Sgrehan#define PS2KC_RESET_DEV 0xff 48300829Sgrehan#define PS2KC_DISABLE 0xf5 49300829Sgrehan#define PS2KC_ENABLE 0xf4 50300829Sgrehan#define PS2KC_SET_TYPEMATIC 0xf3 51300829Sgrehan#define PS2KC_SEND_DEV_ID 0xf2 52300829Sgrehan#define PS2KC_SET_SCANCODE_SET 0xf0 53300829Sgrehan#define PS2KC_ECHO 0xee 54300829Sgrehan#define PS2KC_SET_LEDS 0xed 55300829Sgrehan 56300829Sgrehan#define PS2KC_BAT_SUCCESS 0xaa 57300829Sgrehan#define PS2KC_ACK 0xfa 58300829Sgrehan 59300829Sgrehan#define PS2KBD_FIFOSZ 16 60300829Sgrehan 61300829Sgrehanstruct fifo { 62300829Sgrehan uint8_t buf[PS2KBD_FIFOSZ]; 63300829Sgrehan int rindex; /* index to read from */ 64300829Sgrehan int windex; /* index to write to */ 65300829Sgrehan int num; /* number of bytes in the fifo */ 66300829Sgrehan int size; /* size of the fifo */ 67300829Sgrehan}; 68300829Sgrehan 69300829Sgrehanstruct ps2kbd_softc { 70300829Sgrehan struct atkbdc_softc *atkbdc_sc; 71300829Sgrehan pthread_mutex_t mtx; 72300829Sgrehan 73300829Sgrehan bool enabled; 74300829Sgrehan struct fifo fifo; 75300829Sgrehan 76300829Sgrehan uint8_t curcmd; /* current command for next byte */ 77300829Sgrehan}; 78300829Sgrehan 79341758Saraujo#define SCANCODE_E0_PREFIX 1 80341758Saraujostruct extended_translation { 81341758Saraujo uint32_t keysym; 82341758Saraujo uint8_t scancode; 83341758Saraujo int flags; 84341758Saraujo}; 85341758Saraujo 86341758Saraujo/* 87341758Saraujo * FIXME: Pause/break and Print Screen/SysRq require special handling. 88341758Saraujo */ 89341758Saraujostatic const struct extended_translation extended_translations[] = { 90341758Saraujo {0xff08, 0x66}, /* Back space */ 91341758Saraujo {0xff09, 0x0d}, /* Tab */ 92341758Saraujo {0xff0d, 0x5a}, /* Return */ 93341758Saraujo {0xff1b, 0x76}, /* Escape */ 94341758Saraujo {0xff50, 0x6c, SCANCODE_E0_PREFIX}, /* Home */ 95341758Saraujo {0xff51, 0x6b, SCANCODE_E0_PREFIX}, /* Left arrow */ 96341758Saraujo {0xff52, 0x75, SCANCODE_E0_PREFIX}, /* Up arrow */ 97341758Saraujo {0xff53, 0x74, SCANCODE_E0_PREFIX}, /* Right arrow */ 98341758Saraujo {0xff54, 0x72, SCANCODE_E0_PREFIX}, /* Down arrow */ 99341758Saraujo {0xff55, 0x7d, SCANCODE_E0_PREFIX}, /* PgUp */ 100341758Saraujo {0xff56, 0x7a, SCANCODE_E0_PREFIX}, /* PgDown */ 101341758Saraujo {0xff57, 0x69, SCANCODE_E0_PREFIX}, /* End */ 102341758Saraujo {0xff63, 0x70, SCANCODE_E0_PREFIX}, /* Ins */ 103341758Saraujo {0xff8d, 0x5a, SCANCODE_E0_PREFIX}, /* Keypad Enter */ 104341758Saraujo {0xffe1, 0x12}, /* Left shift */ 105341758Saraujo {0xffe2, 0x59}, /* Right shift */ 106341758Saraujo {0xffe3, 0x14}, /* Left control */ 107341758Saraujo {0xffe4, 0x14, SCANCODE_E0_PREFIX}, /* Right control */ 108341758Saraujo /* {0xffe7, XXX}, Left meta */ 109341758Saraujo /* {0xffe8, XXX}, Right meta */ 110341758Saraujo {0xffe9, 0x11}, /* Left alt */ 111341758Saraujo {0xfe03, 0x11, SCANCODE_E0_PREFIX}, /* AltGr */ 112341758Saraujo {0xffea, 0x11, SCANCODE_E0_PREFIX}, /* Right alt */ 113341758Saraujo {0xffeb, 0x1f, SCANCODE_E0_PREFIX}, /* Left Windows */ 114341758Saraujo {0xffec, 0x27, SCANCODE_E0_PREFIX}, /* Right Windows */ 115341758Saraujo {0xffbe, 0x05}, /* F1 */ 116341758Saraujo {0xffbf, 0x06}, /* F2 */ 117341758Saraujo {0xffc0, 0x04}, /* F3 */ 118341758Saraujo {0xffc1, 0x0c}, /* F4 */ 119341758Saraujo {0xffc2, 0x03}, /* F5 */ 120341758Saraujo {0xffc3, 0x0b}, /* F6 */ 121341758Saraujo {0xffc4, 0x83}, /* F7 */ 122341758Saraujo {0xffc5, 0x0a}, /* F8 */ 123341758Saraujo {0xffc6, 0x01}, /* F9 */ 124341758Saraujo {0xffc7, 0x09}, /* F10 */ 125341758Saraujo {0xffc8, 0x78}, /* F11 */ 126341758Saraujo {0xffc9, 0x07}, /* F12 */ 127341758Saraujo {0xffff, 0x71, SCANCODE_E0_PREFIX}, /* Del */ 128341758Saraujo {0xff14, 0x7e}, /* ScrollLock */ 129341758Saraujo /* NumLock and Keypads*/ 130341758Saraujo {0xff7f, 0x77}, /* NumLock */ 131341758Saraujo {0xffaf, 0x4a, SCANCODE_E0_PREFIX}, /* Keypad slash */ 132341758Saraujo {0xffaa, 0x7c}, /* Keypad asterisk */ 133341758Saraujo {0xffad, 0x7b}, /* Keypad minus */ 134341758Saraujo {0xffab, 0x79}, /* Keypad plus */ 135341758Saraujo {0xffb7, 0x6c}, /* Keypad 7 */ 136341758Saraujo {0xff95, 0x6c}, /* Keypad home */ 137341758Saraujo {0xffb8, 0x75}, /* Keypad 8 */ 138341758Saraujo {0xff97, 0x75}, /* Keypad up arrow */ 139341758Saraujo {0xffb9, 0x7d}, /* Keypad 9 */ 140341758Saraujo {0xff9a, 0x7d}, /* Keypad PgUp */ 141341758Saraujo {0xffb4, 0x6b}, /* Keypad 4 */ 142341758Saraujo {0xff96, 0x6b}, /* Keypad left arrow */ 143341758Saraujo {0xffb5, 0x73}, /* Keypad 5 */ 144341758Saraujo {0xff9d, 0x73}, /* Keypad empty */ 145341758Saraujo {0xffb6, 0x74}, /* Keypad 6 */ 146341758Saraujo {0xff98, 0x74}, /* Keypad right arrow */ 147341758Saraujo {0xffb1, 0x69}, /* Keypad 1 */ 148341758Saraujo {0xff9c, 0x69}, /* Keypad end */ 149341758Saraujo {0xffb2, 0x72}, /* Keypad 2 */ 150341758Saraujo {0xff99, 0x72}, /* Keypad down arrow */ 151341758Saraujo {0xffb3, 0x7a}, /* Keypad 3 */ 152341758Saraujo {0xff9b, 0x7a}, /* Keypad PgDown */ 153341758Saraujo {0xffb0, 0x70}, /* Keypad 0 */ 154341758Saraujo {0xff9e, 0x70}, /* Keypad ins */ 155341758Saraujo {0xffae, 0x71}, /* Keypad . */ 156341758Saraujo {0xff9f, 0x71}, /* Keypad del */ 157341758Saraujo {0, 0, 0} /* Terminator */ 158341758Saraujo}; 159341758Saraujo 160341758Saraujo/* ASCII to type 2 scancode lookup table */ 161341758Saraujostatic const uint8_t ascii_translations[128] = { 162341758Saraujo 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 163341758Saraujo 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 164341758Saraujo 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 165341758Saraujo 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 166341758Saraujo 0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52, 167341758Saraujo 0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a, 168341758Saraujo 0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d, 169341758Saraujo 0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a, 170341758Saraujo 0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34, 171341758Saraujo 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44, 172341758Saraujo 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d, 173341758Saraujo 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e, 174341758Saraujo 0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34, 175341758Saraujo 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44, 176341758Saraujo 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d, 177341758Saraujo 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00, 178341758Saraujo}; 179341758Saraujo 180300829Sgrehanstatic void 181300829Sgrehanfifo_init(struct ps2kbd_softc *sc) 182300829Sgrehan{ 183300829Sgrehan struct fifo *fifo; 184300829Sgrehan 185300829Sgrehan fifo = &sc->fifo; 186300829Sgrehan fifo->size = sizeof(((struct fifo *)0)->buf); 187300829Sgrehan} 188300829Sgrehan 189300829Sgrehanstatic void 190300829Sgrehanfifo_reset(struct ps2kbd_softc *sc) 191300829Sgrehan{ 192300829Sgrehan struct fifo *fifo; 193300829Sgrehan 194300829Sgrehan fifo = &sc->fifo; 195300829Sgrehan bzero(fifo, sizeof(struct fifo)); 196300829Sgrehan fifo->size = sizeof(((struct fifo *)0)->buf); 197300829Sgrehan} 198300829Sgrehan 199300829Sgrehanstatic void 200300829Sgrehanfifo_put(struct ps2kbd_softc *sc, uint8_t val) 201300829Sgrehan{ 202300829Sgrehan struct fifo *fifo; 203300829Sgrehan 204300829Sgrehan fifo = &sc->fifo; 205300829Sgrehan if (fifo->num < fifo->size) { 206300829Sgrehan fifo->buf[fifo->windex] = val; 207300829Sgrehan fifo->windex = (fifo->windex + 1) % fifo->size; 208300829Sgrehan fifo->num++; 209300829Sgrehan } 210300829Sgrehan} 211300829Sgrehan 212300829Sgrehanstatic int 213300829Sgrehanfifo_get(struct ps2kbd_softc *sc, uint8_t *val) 214300829Sgrehan{ 215300829Sgrehan struct fifo *fifo; 216300829Sgrehan 217300829Sgrehan fifo = &sc->fifo; 218300829Sgrehan if (fifo->num > 0) { 219300829Sgrehan *val = fifo->buf[fifo->rindex]; 220300829Sgrehan fifo->rindex = (fifo->rindex + 1) % fifo->size; 221300829Sgrehan fifo->num--; 222300829Sgrehan return (0); 223300829Sgrehan } 224300829Sgrehan 225300829Sgrehan return (-1); 226300829Sgrehan} 227300829Sgrehan 228300829Sgrehanint 229300829Sgrehanps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val) 230300829Sgrehan{ 231300829Sgrehan int retval; 232300829Sgrehan 233300829Sgrehan pthread_mutex_lock(&sc->mtx); 234300829Sgrehan retval = fifo_get(sc, val); 235300829Sgrehan pthread_mutex_unlock(&sc->mtx); 236300829Sgrehan 237300829Sgrehan return (retval); 238300829Sgrehan} 239300829Sgrehan 240300829Sgrehanvoid 241300829Sgrehanps2kbd_write(struct ps2kbd_softc *sc, uint8_t val) 242300829Sgrehan{ 243300829Sgrehan pthread_mutex_lock(&sc->mtx); 244300829Sgrehan if (sc->curcmd) { 245300829Sgrehan switch (sc->curcmd) { 246300829Sgrehan case PS2KC_SET_TYPEMATIC: 247300829Sgrehan fifo_put(sc, PS2KC_ACK); 248300829Sgrehan break; 249300829Sgrehan case PS2KC_SET_SCANCODE_SET: 250300829Sgrehan fifo_put(sc, PS2KC_ACK); 251300829Sgrehan break; 252300829Sgrehan case PS2KC_SET_LEDS: 253300829Sgrehan fifo_put(sc, PS2KC_ACK); 254300829Sgrehan break; 255300829Sgrehan default: 256300829Sgrehan fprintf(stderr, "Unhandled ps2 keyboard current " 257300829Sgrehan "command byte 0x%02x\n", val); 258300829Sgrehan break; 259300829Sgrehan } 260300829Sgrehan sc->curcmd = 0; 261300829Sgrehan } else { 262300829Sgrehan switch (val) { 263300829Sgrehan case 0x00: 264300829Sgrehan fifo_put(sc, PS2KC_ACK); 265300829Sgrehan break; 266300829Sgrehan case PS2KC_RESET_DEV: 267300829Sgrehan fifo_reset(sc); 268300829Sgrehan fifo_put(sc, PS2KC_ACK); 269300829Sgrehan fifo_put(sc, PS2KC_BAT_SUCCESS); 270300829Sgrehan break; 271300829Sgrehan case PS2KC_DISABLE: 272300829Sgrehan sc->enabled = false; 273300829Sgrehan fifo_put(sc, PS2KC_ACK); 274300829Sgrehan break; 275300829Sgrehan case PS2KC_ENABLE: 276300829Sgrehan sc->enabled = true; 277300829Sgrehan fifo_reset(sc); 278300829Sgrehan fifo_put(sc, PS2KC_ACK); 279300829Sgrehan break; 280300829Sgrehan case PS2KC_SET_TYPEMATIC: 281300829Sgrehan sc->curcmd = val; 282300829Sgrehan fifo_put(sc, PS2KC_ACK); 283300829Sgrehan break; 284300829Sgrehan case PS2KC_SEND_DEV_ID: 285300829Sgrehan fifo_put(sc, PS2KC_ACK); 286300829Sgrehan fifo_put(sc, 0xab); 287300829Sgrehan fifo_put(sc, 0x83); 288300829Sgrehan break; 289300829Sgrehan case PS2KC_SET_SCANCODE_SET: 290300829Sgrehan sc->curcmd = val; 291300829Sgrehan fifo_put(sc, PS2KC_ACK); 292300829Sgrehan break; 293300829Sgrehan case PS2KC_ECHO: 294300829Sgrehan fifo_put(sc, PS2KC_ECHO); 295300829Sgrehan break; 296300829Sgrehan case PS2KC_SET_LEDS: 297300829Sgrehan sc->curcmd = val; 298300829Sgrehan fifo_put(sc, PS2KC_ACK); 299300829Sgrehan break; 300300829Sgrehan default: 301300829Sgrehan fprintf(stderr, "Unhandled ps2 keyboard command " 302300829Sgrehan "0x%02x\n", val); 303300829Sgrehan break; 304300829Sgrehan } 305300829Sgrehan } 306300829Sgrehan pthread_mutex_unlock(&sc->mtx); 307300829Sgrehan} 308300829Sgrehan 309300829Sgrehan/* 310300829Sgrehan * Translate keysym to type 2 scancode and insert into keyboard buffer. 311300829Sgrehan */ 312300829Sgrehanstatic void 313300829Sgrehanps2kbd_keysym_queue(struct ps2kbd_softc *sc, 314300829Sgrehan int down, uint32_t keysym) 315300829Sgrehan{ 316300829Sgrehan assert(pthread_mutex_isowned_np(&sc->mtx)); 317341758Saraujo int e0_prefix, found; 318341758Saraujo uint8_t code; 319341758Saraujo const struct extended_translation *trans; 320300829Sgrehan 321341758Saraujo found = 0; 322341758Saraujo if (keysym < 0x80) { 323341758Saraujo code = ascii_translations[keysym]; 324341758Saraujo e0_prefix = 0; 325341758Saraujo found = 1; 326341758Saraujo } else { 327341758Saraujo for (trans = &(extended_translations[0]); trans->keysym != 0; 328341758Saraujo trans++) { 329341758Saraujo if (keysym == trans->keysym) { 330341758Saraujo code = trans->scancode; 331341758Saraujo e0_prefix = trans->flags & SCANCODE_E0_PREFIX; 332341758Saraujo found = 1; 333341758Saraujo break; 334341758Saraujo } 335341758Saraujo } 336341758Saraujo } 337341758Saraujo 338341758Saraujo if (!found) { 339341758Saraujo fprintf(stderr, "Unhandled ps2 keyboard keysym 0x%x\n", keysym); 340341758Saraujo return; 341341758Saraujo } 342341758Saraujo 343341758Saraujo if (e0_prefix) 344300829Sgrehan fifo_put(sc, 0xe0); 345341758Saraujo if (!down) 346341758Saraujo fifo_put(sc, 0xf0); 347341758Saraujo fifo_put(sc, code); 348300829Sgrehan} 349300829Sgrehan 350300829Sgrehanstatic void 351300829Sgrehanps2kbd_event(int down, uint32_t keysym, void *arg) 352300829Sgrehan{ 353300829Sgrehan struct ps2kbd_softc *sc = arg; 354300829Sgrehan int fifo_full; 355300829Sgrehan 356300829Sgrehan pthread_mutex_lock(&sc->mtx); 357300829Sgrehan if (!sc->enabled) { 358300829Sgrehan pthread_mutex_unlock(&sc->mtx); 359300829Sgrehan return; 360300829Sgrehan } 361300829Sgrehan fifo_full = sc->fifo.num == PS2KBD_FIFOSZ; 362300829Sgrehan ps2kbd_keysym_queue(sc, down, keysym); 363300829Sgrehan pthread_mutex_unlock(&sc->mtx); 364300829Sgrehan 365300829Sgrehan if (!fifo_full) 366300829Sgrehan atkbdc_event(sc->atkbdc_sc, 1); 367300829Sgrehan} 368300829Sgrehan 369300829Sgrehanstruct ps2kbd_softc * 370300829Sgrehanps2kbd_init(struct atkbdc_softc *atkbdc_sc) 371300829Sgrehan{ 372300829Sgrehan struct ps2kbd_softc *sc; 373300829Sgrehan 374300829Sgrehan sc = calloc(1, sizeof (struct ps2kbd_softc)); 375300829Sgrehan pthread_mutex_init(&sc->mtx, NULL); 376300829Sgrehan fifo_init(sc); 377300829Sgrehan sc->atkbdc_sc = atkbdc_sc; 378300829Sgrehan 379300829Sgrehan console_kbd_register(ps2kbd_event, sc, 1); 380300829Sgrehan 381300829Sgrehan return (sc); 382300829Sgrehan} 383300829Sgrehan 384