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 static void 182 fifo_init(struct ps2kbd_softc *sc) 183 { 184 struct fifo *fifo; 185 186 fifo = &sc->fifo; 187 fifo->size = sizeof(((struct fifo *)0)->buf); 188 } 189 190 static void 191 fifo_reset(struct ps2kbd_softc *sc) 192 { 193 struct fifo *fifo; 194 195 fifo = &sc->fifo; 196 bzero(fifo, sizeof(struct fifo)); 197 fifo->size = sizeof(((struct fifo *)0)->buf); 198 } 199 200 static void 201 fifo_put(struct ps2kbd_softc *sc, uint8_t val) 202 { 203 struct fifo *fifo; 204 205 fifo = &sc->fifo; 206 if (fifo->num < fifo->size) { 207 fifo->buf[fifo->windex] = val; 208 fifo->windex = (fifo->windex + 1) % fifo->size; 209 fifo->num++; 210 } 211 } 212 213 static int 214 fifo_get(struct ps2kbd_softc *sc, uint8_t *val) 215 { 216 struct fifo *fifo; 217 218 fifo = &sc->fifo; 219 if (fifo->num > 0) { 220 *val = fifo->buf[fifo->rindex]; 221 fifo->rindex = (fifo->rindex + 1) % fifo->size; 222 fifo->num--; 223 return (0); 224 } 225 226 return (-1); 227 } 228 229 int 230 ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val) 231 { 232 int retval; 233 234 pthread_mutex_lock(&sc->mtx); 235 retval = fifo_get(sc, val); 236 pthread_mutex_unlock(&sc->mtx); 237 238 return (retval); 239 } 240 241 void 242 ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val) 243 { 244 pthread_mutex_lock(&sc->mtx); 245 if (sc->curcmd) { 246 switch (sc->curcmd) { 247 case PS2KC_SET_TYPEMATIC: 248 fifo_put(sc, PS2KC_ACK); 249 break; 250 case PS2KC_SET_SCANCODE_SET: 251 fifo_put(sc, PS2KC_ACK); 252 break; 253 case PS2KC_SET_LEDS: 254 fifo_put(sc, PS2KC_ACK); 255 break; 256 default: 257 EPRINTLN("Unhandled ps2 keyboard current " 258 "command byte 0x%02x", val); 259 break; 260 } 261 sc->curcmd = 0; 262 } else { 263 switch (val) { 264 case 0x00: 265 fifo_put(sc, PS2KC_ACK); 266 break; 267 case PS2KC_RESET_DEV: 268 fifo_reset(sc); 269 fifo_put(sc, PS2KC_ACK); 270 fifo_put(sc, PS2KC_BAT_SUCCESS); 271 break; 272 case PS2KC_DISABLE: 273 sc->enabled = false; 274 fifo_put(sc, PS2KC_ACK); 275 break; 276 case PS2KC_ENABLE: 277 sc->enabled = true; 278 fifo_reset(sc); 279 fifo_put(sc, PS2KC_ACK); 280 break; 281 case PS2KC_SET_TYPEMATIC: 282 sc->curcmd = val; 283 fifo_put(sc, PS2KC_ACK); 284 break; 285 case PS2KC_SEND_DEV_ID: 286 fifo_put(sc, PS2KC_ACK); 287 fifo_put(sc, 0xab); 288 fifo_put(sc, 0x83); 289 break; 290 case PS2KC_SET_SCANCODE_SET: 291 sc->curcmd = val; 292 fifo_put(sc, PS2KC_ACK); 293 break; 294 case PS2KC_ECHO: 295 fifo_put(sc, PS2KC_ECHO); 296 break; 297 case PS2KC_SET_LEDS: 298 sc->curcmd = val; 299 fifo_put(sc, PS2KC_ACK); 300 break; 301 default: 302 EPRINTLN("Unhandled ps2 keyboard command " 303 "0x%02x", val); 304 break; 305 } 306 } 307 pthread_mutex_unlock(&sc->mtx); 308 } 309 310 /* 311 * Translate keysym to type 2 scancode and insert into keyboard buffer. 312 */ 313 static void 314 ps2kbd_keysym_queue(struct ps2kbd_softc *sc, 315 int down, uint32_t keysym) 316 { 317 assert(pthread_mutex_isowned_np(&sc->mtx)); 318 int e0_prefix, found; 319 uint8_t code; 320 const struct extended_translation *trans; 321 322 found = 0; 323 if (keysym < 0x80) { 324 code = ascii_translations[keysym]; 325 e0_prefix = 0; 326 found = 1; 327 } else { 328 for (trans = &(extended_translations[0]); trans->keysym != 0; 329 trans++) { 330 if (keysym == trans->keysym) { 331 code = trans->scancode; 332 e0_prefix = trans->flags & SCANCODE_E0_PREFIX; 333 found = 1; 334 break; 335 } 336 } 337 } 338 339 if (!found) { 340 EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym); 341 return; 342 } 343 344 if (e0_prefix) 345 fifo_put(sc, 0xe0); 346 if (!down) 347 fifo_put(sc, 0xf0); 348 fifo_put(sc, code); 349 } 350 351 static void 352 ps2kbd_event(int down, uint32_t keysym, void *arg) 353 { 354 struct ps2kbd_softc *sc = arg; 355 int fifo_full; 356 357 pthread_mutex_lock(&sc->mtx); 358 if (!sc->enabled) { 359 pthread_mutex_unlock(&sc->mtx); 360 return; 361 } 362 fifo_full = sc->fifo.num == PS2KBD_FIFOSZ; 363 ps2kbd_keysym_queue(sc, down, keysym); 364 pthread_mutex_unlock(&sc->mtx); 365 366 if (!fifo_full) 367 atkbdc_event(sc->atkbdc_sc, 1); 368 } 369 370 struct ps2kbd_softc * 371 ps2kbd_init(struct atkbdc_softc *atkbdc_sc) 372 { 373 struct ps2kbd_softc *sc; 374 375 sc = calloc(1, sizeof (struct ps2kbd_softc)); 376 pthread_mutex_init(&sc->mtx, NULL); 377 fifo_init(sc); 378 sc->atkbdc_sc = atkbdc_sc; 379 380 console_kbd_register(ps2kbd_event, sc, 1); 381 382 return (sc); 383 } 384 385