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