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.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/types.h>
36 #include <machine/vmm_snapshot.h>
45 #include <pthread_np.h>
56 /* keyboard device commands */
57 #define PS2KC_RESET_DEV 0xff
58 #define PS2KC_DISABLE 0xf5
59 #define PS2KC_ENABLE 0xf4
60 #define PS2KC_SET_TYPEMATIC 0xf3
61 #define PS2KC_SEND_DEV_ID 0xf2
62 #define PS2KC_SET_SCANCODE_SET 0xf0
63 #define PS2KC_ECHO 0xee
64 #define PS2KC_SET_LEDS 0xed
66 #define PS2KC_BAT_SUCCESS 0xaa
67 #define PS2KC_ACK 0xfa
69 #define PS2KBD_FIFOSZ 16
71 #define PS2KBD_LAYOUT_BASEDIR "/usr/share/bhyve/kbdlayout/"
73 #define MAX_PATHNAME 256
76 uint8_t buf[PS2KBD_FIFOSZ];
77 int rindex; /* index to read from */
78 int windex; /* index to write to */
79 int num; /* number of bytes in the fifo */
80 int size; /* size of the fifo */
84 struct atkbdc_softc *atkbdc_sc;
90 uint8_t curcmd; /* current command for next byte */
93 #define SCANCODE_E0_PREFIX 1
94 struct extended_translation {
101 * FIXME: Pause/break and Print Screen/SysRq require special handling.
103 static struct extended_translation extended_translations[128] = {
104 {0xff08, 0x66, 0}, /* Back space */
105 {0xff09, 0x0d, 0}, /* Tab */
106 {0xff0d, 0x5a, 0}, /* Return */
107 {0xff1b, 0x76, 0}, /* Escape */
108 {0xff50, 0x6c, SCANCODE_E0_PREFIX}, /* Home */
109 {0xff51, 0x6b, SCANCODE_E0_PREFIX}, /* Left arrow */
110 {0xff52, 0x75, SCANCODE_E0_PREFIX}, /* Up arrow */
111 {0xff53, 0x74, SCANCODE_E0_PREFIX}, /* Right arrow */
112 {0xff54, 0x72, SCANCODE_E0_PREFIX}, /* Down arrow */
113 {0xff55, 0x7d, SCANCODE_E0_PREFIX}, /* PgUp */
114 {0xff56, 0x7a, SCANCODE_E0_PREFIX}, /* PgDown */
115 {0xff57, 0x69, SCANCODE_E0_PREFIX}, /* End */
116 {0xff63, 0x70, SCANCODE_E0_PREFIX}, /* Ins */
117 {0xff8d, 0x5a, SCANCODE_E0_PREFIX}, /* Keypad Enter */
118 {0xffe1, 0x12, 0}, /* Left shift */
119 {0xffe2, 0x59, 0}, /* Right shift */
120 {0xffe3, 0x14, 0}, /* Left control */
121 {0xffe4, 0x14, SCANCODE_E0_PREFIX}, /* Right control */
122 /* {0xffe7, XXX}, Left meta */
123 /* {0xffe8, XXX}, Right meta */
124 {0xffe9, 0x11, 0}, /* Left alt */
125 {0xfe03, 0x11, SCANCODE_E0_PREFIX}, /* AltGr */
126 {0xffea, 0x11, SCANCODE_E0_PREFIX}, /* Right alt */
127 {0xffeb, 0x1f, SCANCODE_E0_PREFIX}, /* Left Windows */
128 {0xffec, 0x27, SCANCODE_E0_PREFIX}, /* Right Windows */
129 {0xffbe, 0x05, 0}, /* F1 */
130 {0xffbf, 0x06, 0}, /* F2 */
131 {0xffc0, 0x04, 0}, /* F3 */
132 {0xffc1, 0x0c, 0}, /* F4 */
133 {0xffc2, 0x03, 0}, /* F5 */
134 {0xffc3, 0x0b, 0}, /* F6 */
135 {0xffc4, 0x83, 0}, /* F7 */
136 {0xffc5, 0x0a, 0}, /* F8 */
137 {0xffc6, 0x01, 0}, /* F9 */
138 {0xffc7, 0x09, 0}, /* F10 */
139 {0xffc8, 0x78, 0}, /* F11 */
140 {0xffc9, 0x07, 0}, /* F12 */
141 {0xffff, 0x71, SCANCODE_E0_PREFIX}, /* Del */
142 {0xff14, 0x7e, 0}, /* ScrollLock */
143 /* NumLock and Keypads*/
144 {0xff7f, 0x77, 0}, /* NumLock */
145 {0xffaf, 0x4a, SCANCODE_E0_PREFIX}, /* Keypad slash */
146 {0xffaa, 0x7c, 0}, /* Keypad asterisk */
147 {0xffad, 0x7b, 0}, /* Keypad minus */
148 {0xffab, 0x79, 0}, /* Keypad plus */
149 {0xffb7, 0x6c, 0}, /* Keypad 7 */
150 {0xff95, 0x6c, 0}, /* Keypad home */
151 {0xffb8, 0x75, 0}, /* Keypad 8 */
152 {0xff97, 0x75, 0}, /* Keypad up arrow */
153 {0xffb9, 0x7d, 0}, /* Keypad 9 */
154 {0xff9a, 0x7d, 0}, /* Keypad PgUp */
155 {0xffb4, 0x6b, 0}, /* Keypad 4 */
156 {0xff96, 0x6b, 0}, /* Keypad left arrow */
157 {0xffb5, 0x73, 0}, /* Keypad 5 */
158 {0xff9d, 0x73, 0}, /* Keypad empty */
159 {0xffb6, 0x74, 0}, /* Keypad 6 */
160 {0xff98, 0x74, 0}, /* Keypad right arrow */
161 {0xffb1, 0x69, 0}, /* Keypad 1 */
162 {0xff9c, 0x69, 0}, /* Keypad end */
163 {0xffb2, 0x72, 0}, /* Keypad 2 */
164 {0xff99, 0x72, 0}, /* Keypad down arrow */
165 {0xffb3, 0x7a, 0}, /* Keypad 3 */
166 {0xff9b, 0x7a, 0}, /* Keypad PgDown */
167 {0xffb0, 0x70, 0}, /* Keypad 0 */
168 {0xff9e, 0x70, 0}, /* Keypad ins */
169 {0xffae, 0x71, 0}, /* Keypad . */
170 {0xff9f, 0x71, 0}, /* Keypad del */
171 {0, 0, 0} /* Terminator */
174 /* ASCII to type 2 scancode lookup table */
175 static uint8_t ascii_translations[128] = {
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180 0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52,
181 0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a,
182 0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d,
183 0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a,
184 0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
185 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
186 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
187 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e,
188 0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
189 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
190 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
191 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00,
194 /* ScanCode set1 to set2 lookup table */
195 static const uint8_t keyset1to2_translations[128] = {
196 0, 0x76, 0x16, 0x1E, 0x26, 0x25, 0x2e, 0x36,
197 0x3d, 0x3e, 0x46, 0x45, 0x4e, 0x55, 0x66, 0x0d,
198 0x15, 0x1d, 0x24, 0x2d, 0x2c, 0x35, 0x3c, 0x43,
199 0x44, 0x4d, 0x54, 0x5b, 0x5a, 0x14, 0x1c, 0x1b,
200 0x23, 0x2b, 0x34, 0x33, 0x3b, 0x42, 0x4b, 0x4c,
201 0x52, 0x0e, 0x12, 0x5d, 0x1a, 0x22, 0x21, 0x2a,
202 0x32, 0x31, 0x3a, 0x41, 0x49, 0x4a, 0x59, 0x7c,
203 0x11, 0x29, 0x58, 0x05, 0x06, 0x04, 0x0c, 0x03,
204 0x0b, 0x83, 0x0a, 0x01, 0x09, 0x77, 0x7e, 0x6c,
205 0x75, 0x7d, 0x7b, 0x6b, 0x73, 0x74, 0x79, 0x69,
206 0x72, 0x7a, 0x70, 0x71, 0x84, 0x60, 0x61, 0x78,
207 0x07, 0x0f, 0x17, 0x1f, 0x27, 0x2f, 0x37, 0x3f,
208 0x47, 0x4f, 0x56, 0x5e, 0x08, 0x10, 0x18, 0x20,
209 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x57, 0x6f,
210 0x13, 0x19, 0x39, 0x51, 0x53, 0x5c, 0x5f, 0x62,
211 0x63, 0x64, 0x65, 0x67, 0x68, 0x6a, 0x6d, 0x6e,
215 fifo_init(struct ps2kbd_softc *sc)
220 fifo->size = sizeof(((struct fifo *)0)->buf);
224 fifo_reset(struct ps2kbd_softc *sc)
229 bzero(fifo, sizeof(struct fifo));
230 fifo->size = sizeof(((struct fifo *)0)->buf);
234 fifo_put(struct ps2kbd_softc *sc, uint8_t val)
239 if (fifo->num < fifo->size) {
240 fifo->buf[fifo->windex] = val;
241 fifo->windex = (fifo->windex + 1) % fifo->size;
247 fifo_get(struct ps2kbd_softc *sc, uint8_t *val)
253 *val = fifo->buf[fifo->rindex];
254 fifo->rindex = (fifo->rindex + 1) % fifo->size;
263 ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
267 pthread_mutex_lock(&sc->mtx);
268 retval = fifo_get(sc, val);
269 pthread_mutex_unlock(&sc->mtx);
275 ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
277 pthread_mutex_lock(&sc->mtx);
279 switch (sc->curcmd) {
280 case PS2KC_SET_TYPEMATIC:
281 fifo_put(sc, PS2KC_ACK);
283 case PS2KC_SET_SCANCODE_SET:
284 fifo_put(sc, PS2KC_ACK);
287 fifo_put(sc, PS2KC_ACK);
290 EPRINTLN("Unhandled ps2 keyboard current "
291 "command byte 0x%02x", val);
298 fifo_put(sc, PS2KC_ACK);
300 case PS2KC_RESET_DEV:
302 fifo_put(sc, PS2KC_ACK);
303 fifo_put(sc, PS2KC_BAT_SUCCESS);
307 fifo_put(sc, PS2KC_ACK);
312 fifo_put(sc, PS2KC_ACK);
314 case PS2KC_SET_TYPEMATIC:
316 fifo_put(sc, PS2KC_ACK);
318 case PS2KC_SEND_DEV_ID:
319 fifo_put(sc, PS2KC_ACK);
323 case PS2KC_SET_SCANCODE_SET:
325 fifo_put(sc, PS2KC_ACK);
328 fifo_put(sc, PS2KC_ECHO);
332 fifo_put(sc, PS2KC_ACK);
335 EPRINTLN("Unhandled ps2 keyboard command "
340 pthread_mutex_unlock(&sc->mtx);
344 * Translate keysym to type 2 scancode and insert into keyboard buffer.
347 ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
348 int down, uint32_t keysym, uint32_t keycode)
350 const struct extended_translation *trans;
351 int e0_prefix, found;
354 assert(pthread_mutex_isowned_np(&sc->mtx));
357 code = keyset1to2_translations[(uint8_t)(keycode & 0x7f)];
358 e0_prefix = ((keycode & 0x80) ? SCANCODE_E0_PREFIX : 0);
363 code = ascii_translations[keysym];
367 for (trans = &extended_translations[0];
368 trans->keysym != 0; trans++) {
369 if (keysym == trans->keysym) {
370 code = trans->scancode;
371 e0_prefix = trans->flags & SCANCODE_E0_PREFIX;
380 EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym);
392 ps2kbd_event(int down, uint32_t keysym, uint32_t keycode, void *arg)
394 struct ps2kbd_softc *sc = arg;
397 pthread_mutex_lock(&sc->mtx);
399 pthread_mutex_unlock(&sc->mtx);
402 fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
403 ps2kbd_keysym_queue(sc, down, keysym, keycode);
404 pthread_mutex_unlock(&sc->mtx);
407 atkbdc_event(sc->atkbdc_sc, 1);
411 ps2kbd_update_extended_translation(uint32_t keycode, uint32_t scancode, uint32_t prefix)
416 if (extended_translations[i].keysym == keycode)
418 } while (extended_translations[++i].keysym);
420 if (i == (sizeof(extended_translations) / sizeof(struct extended_translation) - 1))
423 if (!extended_translations[i].keysym) {
424 extended_translations[i].keysym = keycode;
426 extended_translations[i+1].keysym = 0;
427 extended_translations[i+1].scancode = 0;
428 extended_translations[i+1].flags = 0;
431 extended_translations[i].scancode = (uint8_t)(scancode & 0xff);
432 extended_translations[i].flags = (prefix ? SCANCODE_E0_PREFIX : 0);
436 ps2kbd_setkbdlayout(void)
440 char path[MAX_PATHNAME];
441 char *buf, *next, *line;
445 uint32_t keycode, scancode, prefix;
447 snprintf(path, MAX_PATHNAME, PS2KBD_LAYOUT_BASEDIR"%s", get_config_value("keyboard.layout") );
449 err = stat(path, &sb);
453 buf = (char *)malloc(sizeof(char) * sb.st_size);
457 fd = open(path, O_RDONLY);
461 sz = read(fd, buf, sb.st_size);
465 if (sz < 0 || sz != sb.st_size)
469 while ((line = strsep(&next, "\n")) != NULL) {
470 if (sscanf(line, "'%c',%x;", &ascii, &scancode) == 2) {
472 ascii_translations[ascii] = (uint8_t)(scancode & 0xff);
473 } else if (sscanf(line, "%x,%x,%x;", &keycode, &scancode, &prefix) == 3 ) {
474 ps2kbd_update_extended_translation(keycode, scancode, prefix);
475 } else if (sscanf(line, "%x,%x;", &keycode, &scancode) == 2) {
477 ascii_translations[(uint8_t)(keycode & 0xff)] = (uint8_t)(scancode & 0xff);
479 ps2kbd_update_extended_translation(keycode, scancode, 0);
487 struct ps2kbd_softc *
488 ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
490 struct ps2kbd_softc *sc;
492 if (get_config_value("keyboard.layout") != NULL)
493 ps2kbd_setkbdlayout();
495 sc = calloc(1, sizeof (struct ps2kbd_softc));
496 pthread_mutex_init(&sc->mtx, NULL);
498 sc->atkbdc_sc = atkbdc_sc;
500 console_kbd_register(ps2kbd_event, sc, 1);
505 #ifdef BHYVE_SNAPSHOT
507 ps2kbd_snapshot(struct ps2kbd_softc *sc, struct vm_snapshot_meta *meta)
511 SNAPSHOT_VAR_OR_LEAVE(sc->enabled, meta, ret, done);
512 SNAPSHOT_VAR_OR_LEAVE(sc->curcmd, meta, ret, done);