15325 bhyve upstream sync 2023 January
[illumos-gate.git] / usr / src / cmd / bhyve / ps2kbd.c
blobd7ff5688d534be1f1daf682a9d44e24761798473
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
5 * Copyright (c) 2015 Nahanni Systems Inc.
6 * All rights reserved.
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.
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.
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/types.h>
34 #include <sys/stat.h>
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>
46 #include "atkbdc.h"
47 #include "bhyverun.h"
48 #include "config.h"
49 #include "console.h"
50 #include "debug.h"
51 #include "ps2kbd.h"
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
63 #define PS2KC_BAT_SUCCESS 0xaa
64 #define PS2KC_ACK 0xfa
66 #define PS2KBD_FIFOSZ 16
68 #define PS2KBD_LAYOUT_BASEDIR "/usr/share/bhyve/kbdlayout/"
70 #define MAX_PATHNAME 256
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 */
80 struct ps2kbd_softc {
81 struct atkbdc_softc *atkbdc_sc;
82 pthread_mutex_t mtx;
84 bool enabled;
85 struct fifo fifo;
87 uint8_t curcmd; /* current command for next byte */
90 #define SCANCODE_E0_PREFIX 1
91 struct extended_translation {
92 uint32_t keysym;
93 uint8_t scancode;
94 int flags;
98 * FIXME: Pause/break and Print Screen/SysRq require special handling.
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 */
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,
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,
211 static void
212 fifo_init(struct ps2kbd_softc *sc)
214 struct fifo *fifo;
216 fifo = &sc->fifo;
217 fifo->size = sizeof(((struct fifo *)0)->buf);
220 static void
221 fifo_reset(struct ps2kbd_softc *sc)
223 struct fifo *fifo;
225 fifo = &sc->fifo;
226 bzero(fifo, sizeof(struct fifo));
227 fifo->size = sizeof(((struct fifo *)0)->buf);
230 static void
231 fifo_put(struct ps2kbd_softc *sc, uint8_t val)
233 struct fifo *fifo;
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++;
243 static int
244 fifo_get(struct ps2kbd_softc *sc, uint8_t *val)
246 struct fifo *fifo;
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);
256 return (-1);
260 ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
262 int retval;
264 pthread_mutex_lock(&sc->mtx);
265 retval = fifo_get(sc, val);
266 pthread_mutex_unlock(&sc->mtx);
268 return (retval);
271 void
272 ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
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;
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;
337 pthread_mutex_unlock(&sc->mtx);
341 * Translate keysym to type 2 scancode and insert into keyboard buffer.
343 static void
344 ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
345 int down, uint32_t keysym, uint32_t keycode)
347 const struct extended_translation *trans;
348 int e0_prefix, found;
349 uint8_t code;
351 assert(pthread_mutex_isowned_np(&sc->mtx));
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;
376 if (!found) {
377 EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym);
378 return;
381 if (e0_prefix)
382 fifo_put(sc, 0xe0);
383 if (!down)
384 fifo_put(sc, 0xf0);
385 fifo_put(sc, code);
388 static void
389 ps2kbd_event(int down, uint32_t keysym, uint32_t keycode, void *arg)
391 struct ps2kbd_softc *sc = arg;
392 int fifo_full;
394 pthread_mutex_lock(&sc->mtx);
395 if (!sc->enabled) {
396 pthread_mutex_unlock(&sc->mtx);
397 return;
399 fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
400 ps2kbd_keysym_queue(sc, down, keysym, keycode);
401 pthread_mutex_unlock(&sc->mtx);
403 if (!fifo_full)
404 atkbdc_event(sc->atkbdc_sc, 1);
407 static void
408 ps2kbd_update_extended_translation(uint32_t keycode, uint32_t scancode, uint32_t prefix)
410 int i = 0;
412 do {
413 if (extended_translations[i].keysym == keycode)
414 break;
415 } while (extended_translations[++i].keysym);
417 if (i == (sizeof(extended_translations) / sizeof(struct extended_translation) - 1))
418 return;
420 if (!extended_translations[i].keysym) {
421 extended_translations[i].keysym = keycode;
423 extended_translations[i+1].keysym = 0;
424 extended_translations[i+1].scancode = 0;
425 extended_translations[i+1].flags = 0;
428 extended_translations[i].scancode = (uint8_t)(scancode & 0xff);
429 extended_translations[i].flags = (prefix ? SCANCODE_E0_PREFIX : 0);
432 static void
433 ps2kbd_setkbdlayout(void)
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;
444 snprintf(path, MAX_PATHNAME, PS2KBD_LAYOUT_BASEDIR"%s", get_config_value("keyboard.layout") );
446 err = stat(path, &sb);
447 if (err)
448 return;
450 buf = (char *)malloc(sizeof(char) * sb.st_size);
451 if (buf == NULL)
452 return;
454 fd = open(path, O_RDONLY);
455 if (fd == -1)
456 goto out;
458 sz = read(fd, buf, sb.st_size);
460 close(fd);
462 if (sz < 0 || sz != sb.st_size)
463 goto out;
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);
480 out:
481 free(buf);
484 struct ps2kbd_softc *
485 ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
487 struct ps2kbd_softc *sc;
489 if (get_config_value("keyboard.layout") != NULL)
490 ps2kbd_setkbdlayout();
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;
497 console_kbd_register(ps2kbd_event, sc, 1);
499 return (sc);