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>
55 /* keyboard device commands */
56 #define PS2KC_RESET_DEV 0xff
57 #define PS2KC_DISABLE 0xf5
58 #define PS2KC_ENABLE 0xf4
59 #define PS2KC_SET_TYPEMATIC 0xf3
60 #define PS2KC_SEND_DEV_ID 0xf2
61 #define PS2KC_SET_SCANCODE_SET 0xf0
62 #define PS2KC_ECHO 0xee
63 #define PS2KC_SET_LEDS 0xed
65 #define PS2KC_BAT_SUCCESS 0xaa
66 #define PS2KC_ACK 0xfa
68 #define PS2KBD_FIFOSZ 16
70 #define PS2KBD_LAYOUT_BASEDIR "/usr/share/bhyve/kbdlayout/"
72 #define MAX_PATHNAME 256
75 uint8_t buf[PS2KBD_FIFOSZ];
76 int rindex; /* index to read from */
77 int windex; /* index to write to */
78 int num; /* number of bytes in the fifo */
79 int size; /* size of the fifo */
83 struct atkbdc_softc *atkbdc_sc;
89 uint8_t curcmd; /* current command for next byte */
92 #define SCANCODE_E0_PREFIX 1
93 struct extended_translation {
100 * FIXME: Pause/break and Print Screen/SysRq require special handling.
102 static struct extended_translation extended_translations[128] = {
103 {0xff08, 0x66}, /* Back space */
104 {0xff09, 0x0d}, /* Tab */
105 {0xff0d, 0x5a}, /* Return */
106 {0xff1b, 0x76}, /* Escape */
107 {0xff50, 0x6c, SCANCODE_E0_PREFIX}, /* Home */
108 {0xff51, 0x6b, SCANCODE_E0_PREFIX}, /* Left arrow */
109 {0xff52, 0x75, SCANCODE_E0_PREFIX}, /* Up arrow */
110 {0xff53, 0x74, SCANCODE_E0_PREFIX}, /* Right arrow */
111 {0xff54, 0x72, SCANCODE_E0_PREFIX}, /* Down arrow */
112 {0xff55, 0x7d, SCANCODE_E0_PREFIX}, /* PgUp */
113 {0xff56, 0x7a, SCANCODE_E0_PREFIX}, /* PgDown */
114 {0xff57, 0x69, SCANCODE_E0_PREFIX}, /* End */
115 {0xff63, 0x70, SCANCODE_E0_PREFIX}, /* Ins */
116 {0xff8d, 0x5a, SCANCODE_E0_PREFIX}, /* Keypad Enter */
117 {0xffe1, 0x12}, /* Left shift */
118 {0xffe2, 0x59}, /* Right shift */
119 {0xffe3, 0x14}, /* Left control */
120 {0xffe4, 0x14, SCANCODE_E0_PREFIX}, /* Right control */
121 /* {0xffe7, XXX}, Left meta */
122 /* {0xffe8, XXX}, Right meta */
123 {0xffe9, 0x11}, /* Left alt */
124 {0xfe03, 0x11, SCANCODE_E0_PREFIX}, /* AltGr */
125 {0xffea, 0x11, SCANCODE_E0_PREFIX}, /* Right alt */
126 {0xffeb, 0x1f, SCANCODE_E0_PREFIX}, /* Left Windows */
127 {0xffec, 0x27, SCANCODE_E0_PREFIX}, /* Right Windows */
128 {0xffbe, 0x05}, /* F1 */
129 {0xffbf, 0x06}, /* F2 */
130 {0xffc0, 0x04}, /* F3 */
131 {0xffc1, 0x0c}, /* F4 */
132 {0xffc2, 0x03}, /* F5 */
133 {0xffc3, 0x0b}, /* F6 */
134 {0xffc4, 0x83}, /* F7 */
135 {0xffc5, 0x0a}, /* F8 */
136 {0xffc6, 0x01}, /* F9 */
137 {0xffc7, 0x09}, /* F10 */
138 {0xffc8, 0x78}, /* F11 */
139 {0xffc9, 0x07}, /* F12 */
140 {0xffff, 0x71, SCANCODE_E0_PREFIX}, /* Del */
141 {0xff14, 0x7e}, /* ScrollLock */
142 /* NumLock and Keypads*/
143 {0xff7f, 0x77}, /* NumLock */
144 {0xffaf, 0x4a, SCANCODE_E0_PREFIX}, /* Keypad slash */
145 {0xffaa, 0x7c}, /* Keypad asterisk */
146 {0xffad, 0x7b}, /* Keypad minus */
147 {0xffab, 0x79}, /* Keypad plus */
148 {0xffb7, 0x6c}, /* Keypad 7 */
149 {0xff95, 0x6c}, /* Keypad home */
150 {0xffb8, 0x75}, /* Keypad 8 */
151 {0xff97, 0x75}, /* Keypad up arrow */
152 {0xffb9, 0x7d}, /* Keypad 9 */
153 {0xff9a, 0x7d}, /* Keypad PgUp */
154 {0xffb4, 0x6b}, /* Keypad 4 */
155 {0xff96, 0x6b}, /* Keypad left arrow */
156 {0xffb5, 0x73}, /* Keypad 5 */
157 {0xff9d, 0x73}, /* Keypad empty */
158 {0xffb6, 0x74}, /* Keypad 6 */
159 {0xff98, 0x74}, /* Keypad right arrow */
160 {0xffb1, 0x69}, /* Keypad 1 */
161 {0xff9c, 0x69}, /* Keypad end */
162 {0xffb2, 0x72}, /* Keypad 2 */
163 {0xff99, 0x72}, /* Keypad down arrow */
164 {0xffb3, 0x7a}, /* Keypad 3 */
165 {0xff9b, 0x7a}, /* Keypad PgDown */
166 {0xffb0, 0x70}, /* Keypad 0 */
167 {0xff9e, 0x70}, /* Keypad ins */
168 {0xffae, 0x71}, /* Keypad . */
169 {0xff9f, 0x71}, /* Keypad del */
170 {0, 0, 0} /* Terminator */
173 /* ASCII to type 2 scancode lookup table */
174 static uint8_t ascii_translations[128] = {
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179 0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52,
180 0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a,
181 0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d,
182 0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a,
183 0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
184 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
185 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
186 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e,
187 0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
188 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
189 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
190 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00,
193 /* ScanCode set1 to set2 lookup table */
194 const uint8_t keyset1to2_translations[128] = {
195 0, 0x76, 0x16, 0x1E, 0x26, 0x25, 0x2e, 0x36,
196 0x3d, 0x3e, 0x46, 0x45, 0x4e, 0x55, 0x66, 0x0d,
197 0x15, 0x1d, 0x24, 0x2d, 0x2c, 0x35, 0x3c, 0x43,
198 0x44, 0x4d, 0x54, 0x5b, 0x5a, 0x14, 0x1c, 0x1b,
199 0x23, 0x2b, 0x34, 0x33, 0x3b, 0x42, 0x4b, 0x4c,
200 0x52, 0x0e, 0x12, 0x5d, 0x1a, 0x22, 0x21, 0x2a,
201 0x32, 0x31, 0x3a, 0x41, 0x49, 0x4a, 0x59, 0x7c,
202 0x11, 0x29, 0x58, 0x05, 0x06, 0x04, 0x0c, 0x03,
203 0x0b, 0x83, 0x0a, 0x01, 0x09, 0x77, 0x7e, 0x6c,
204 0x75, 0x7d, 0x7b, 0x6b, 0x73, 0x74, 0x79, 0x69,
205 0x72, 0x7a, 0x70, 0x71, 0x84, 0x60, 0x61, 0x78,
206 0x07, 0x0f, 0x17, 0x1f, 0x27, 0x2f, 0x37, 0x3f,
207 0x47, 0x4f, 0x56, 0x5e, 0x08, 0x10, 0x18, 0x20,
208 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x57, 0x6f,
209 0x13, 0x19, 0x39, 0x51, 0x53, 0x5c, 0x5f, 0x62,
210 0x63, 0x64, 0x65, 0x67, 0x68, 0x6a, 0x6d, 0x6e,
214 fifo_init(struct ps2kbd_softc *sc)
219 fifo->size = sizeof(((struct fifo *)0)->buf);
223 fifo_reset(struct ps2kbd_softc *sc)
228 bzero(fifo, sizeof(struct fifo));
229 fifo->size = sizeof(((struct fifo *)0)->buf);
233 fifo_put(struct ps2kbd_softc *sc, uint8_t val)
238 if (fifo->num < fifo->size) {
239 fifo->buf[fifo->windex] = val;
240 fifo->windex = (fifo->windex + 1) % fifo->size;
246 fifo_get(struct ps2kbd_softc *sc, uint8_t *val)
252 *val = fifo->buf[fifo->rindex];
253 fifo->rindex = (fifo->rindex + 1) % fifo->size;
262 ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
266 pthread_mutex_lock(&sc->mtx);
267 retval = fifo_get(sc, val);
268 pthread_mutex_unlock(&sc->mtx);
274 ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
276 pthread_mutex_lock(&sc->mtx);
278 switch (sc->curcmd) {
279 case PS2KC_SET_TYPEMATIC:
280 fifo_put(sc, PS2KC_ACK);
282 case PS2KC_SET_SCANCODE_SET:
283 fifo_put(sc, PS2KC_ACK);
286 fifo_put(sc, PS2KC_ACK);
289 EPRINTLN("Unhandled ps2 keyboard current "
290 "command byte 0x%02x", val);
297 fifo_put(sc, PS2KC_ACK);
299 case PS2KC_RESET_DEV:
301 fifo_put(sc, PS2KC_ACK);
302 fifo_put(sc, PS2KC_BAT_SUCCESS);
306 fifo_put(sc, PS2KC_ACK);
311 fifo_put(sc, PS2KC_ACK);
313 case PS2KC_SET_TYPEMATIC:
315 fifo_put(sc, PS2KC_ACK);
317 case PS2KC_SEND_DEV_ID:
318 fifo_put(sc, PS2KC_ACK);
322 case PS2KC_SET_SCANCODE_SET:
324 fifo_put(sc, PS2KC_ACK);
327 fifo_put(sc, PS2KC_ECHO);
331 fifo_put(sc, PS2KC_ACK);
334 EPRINTLN("Unhandled ps2 keyboard command "
339 pthread_mutex_unlock(&sc->mtx);
343 * Translate keysym to type 2 scancode and insert into keyboard buffer.
346 ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
347 int down, uint32_t keysym, uint32_t keycode)
349 assert(pthread_mutex_isowned_np(&sc->mtx));
350 int e0_prefix, found;
352 struct extended_translation *trans;
355 code = keyset1to2_translations[(uint8_t)(keycode & 0x7f)];
356 e0_prefix = ((keycode & 0x80) ? SCANCODE_E0_PREFIX : 0);
361 code = ascii_translations[keysym];
365 for (trans = &(extended_translations[0]); trans->keysym != 0;
367 if (keysym == trans->keysym) {
368 code = trans->scancode;
369 e0_prefix = trans->flags & SCANCODE_E0_PREFIX;
378 EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym);
390 ps2kbd_event(int down, uint32_t keysym, uint32_t keycode, void *arg)
392 struct ps2kbd_softc *sc = arg;
395 pthread_mutex_lock(&sc->mtx);
397 pthread_mutex_unlock(&sc->mtx);
400 fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
401 ps2kbd_keysym_queue(sc, down, keysym, keycode);
402 pthread_mutex_unlock(&sc->mtx);
405 atkbdc_event(sc->atkbdc_sc, 1);
409 ps2kbd_update_extended_translation(uint32_t keycode, uint32_t scancode, uint32_t prefix)
414 if (extended_translations[i].keysym == keycode)
416 } while(extended_translations[++i].keysym);
418 if (i == (sizeof(extended_translations) / sizeof(struct extended_translation) - 1))
421 if (!extended_translations[i].keysym) {
422 extended_translations[i].keysym = keycode;
424 extended_translations[i+1].keysym = 0;
425 extended_translations[i+1].scancode = 0;
426 extended_translations[i+1].flags = 0;
429 extended_translations[i].scancode = (uint8_t)(scancode & 0xff);
430 extended_translations[i].flags = (prefix ? SCANCODE_E0_PREFIX : 0);
434 ps2kbd_setkbdlayout(void)
438 char path[MAX_PATHNAME];
439 char *buf, *next, *line;
443 uint32_t keycode, scancode, prefix;
445 snprintf(path, MAX_PATHNAME, PS2KBD_LAYOUT_BASEDIR"%s", get_config_value("keyboard.layout") );
447 err = stat(path, &sb);
451 buf = (char *)malloc(sizeof(char) * sb.st_size);
455 fd = open(path, O_RDONLY);
459 sz = read(fd, buf, sb.st_size );
463 if (sz != sb.st_size )
467 while ((line = strsep(&next, "\n")) != NULL) {
468 if (sscanf(line, "'%c',%x;", &ascii, &scancode) == 2) {
470 ascii_translations[ascii] = (uint8_t)(scancode & 0xff);
471 } else if (sscanf(line, "%x,%x,%x;", &keycode, &scancode, &prefix) == 3 ) {
472 ps2kbd_update_extended_translation(keycode, scancode, prefix);
473 } else if (sscanf(line, "%x,%x;", &keycode, &scancode) == 2) {
475 ascii_translations[(uint8_t)(keycode & 0xff)] = (uint8_t)(scancode & 0xff);
477 ps2kbd_update_extended_translation(keycode, scancode, 0);
485 struct ps2kbd_softc *
486 ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
488 struct ps2kbd_softc *sc;
490 if (get_config_value("keyboard.layout") != NULL)
491 ps2kbd_setkbdlayout();
493 sc = calloc(1, sizeof (struct ps2kbd_softc));
494 pthread_mutex_init(&sc->mtx, NULL);
496 sc->atkbdc_sc = atkbdc_sc;
498 console_kbd_register(ps2kbd_event, sc, 1);
503 #ifdef BHYVE_SNAPSHOT
505 ps2kbd_snapshot(struct ps2kbd_softc *sc, struct vm_snapshot_meta *meta)
509 SNAPSHOT_VAR_OR_LEAVE(sc->enabled, meta, ret, done);
510 SNAPSHOT_VAR_OR_LEAVE(sc->curcmd, meta, ret, done);