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