xref: /freebsd/usr.sbin/bhyve/amd64/ps2kbd.c (revision a2f733abcff64628b7771a47089628b7327a88bd)
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/cdefs.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 
34 #include <machine/vmm_snapshot.h>
35 
36 #include <assert.h>
37 #include <stdbool.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <strings.h>
42 #include <pthread.h>
43 #include <pthread_np.h>
44 #include <unistd.h>
45 #include <fcntl.h>
46 
47 #include "atkbdc.h"
48 #include "bhyverun.h"
49 #include "config.h"
50 #include "console.h"
51 #include "debug.h"
52 #include "ps2kbd.h"
53 
54 /* keyboard device commands */
55 #define	PS2KC_RESET_DEV		0xff
56 #define	PS2KC_SET_DEFAULTS	0xf6
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
64 
65 #define	PS2KC_BAT_SUCCESS	0xaa
66 #define	PS2KC_ACK		0xfa
67 
68 #define	PS2KBD_FIFOSZ		16
69 
70 #define	PS2KBD_LAYOUT_BASEDIR	"/usr/share/bhyve/kbdlayout/"
71 
72 #define	MAX_PATHNAME		256
73 
74 struct fifo {
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 */
80 };
81 
82 struct ps2kbd_softc {
83 	struct atkbdc_softc	*atkbdc_sc;
84 	pthread_mutex_t		mtx;
85 
86 	bool			enabled;
87 	struct fifo		fifo;
88 
89 	uint8_t			curcmd;	/* current command for next byte */
90 };
91 
92 #define SCANCODE_E0_PREFIX 1
93 struct extended_translation {
94 	uint32_t keysym;
95 	uint8_t scancode;
96 	int flags;
97 };
98 
99 /*
100  * FIXME: Pause/break and Print Screen/SysRq require special handling.
101  */
102 static struct extended_translation extended_translations[128] = {
103 		{0xff08, 0x66, 0},		/* Back space */
104 		{0xff09, 0x0d, 0},		/* Tab */
105 		{0xff0d, 0x5a, 0},		/* Return */
106 		{0xff1b, 0x76, 0},		/* 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, 0},		/* Left shift */
118 		{0xffe2, 0x59, 0},		/* Right shift */
119 		{0xffe3, 0x14, 0},		/* Left control */
120 		{0xffe4, 0x14, SCANCODE_E0_PREFIX}, 	/* Right control */
121 		/* {0xffe7, XXX}, Left meta */
122 		/* {0xffe8, XXX}, Right meta */
123 		{0xffe9, 0x11, 0},		/* 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, 0},		/* F1 */
129 		{0xffbf, 0x06, 0},		/* F2 */
130 		{0xffc0, 0x04, 0},		/* F3 */
131 		{0xffc1, 0x0c, 0},		/* F4 */
132 		{0xffc2, 0x03, 0},		/* F5 */
133 		{0xffc3, 0x0b, 0},		/* F6 */
134 		{0xffc4, 0x83, 0},		/* F7 */
135 		{0xffc5, 0x0a, 0},		/* F8 */
136 		{0xffc6, 0x01, 0},		/* F9 */
137 		{0xffc7, 0x09, 0},		/* F10 */
138 		{0xffc8, 0x78, 0},		/* F11 */
139 		{0xffc9, 0x07, 0},		/* F12 */
140 		{0xffff, 0x71, SCANCODE_E0_PREFIX},	/* Del */
141 		{0xff14, 0x7e, 0},		/* ScrollLock */
142 		/* NumLock and Keypads*/
143 		{0xff7f, 0x77, 0}, 	/* NumLock */
144 		{0xffaf, 0x4a, SCANCODE_E0_PREFIX}, 	/* Keypad slash */
145 		{0xffaa, 0x7c, 0}, 	/* Keypad asterisk */
146 		{0xffad, 0x7b, 0}, 	/* Keypad minus */
147 		{0xffab, 0x79, 0}, 	/* Keypad plus */
148 		{0xffb7, 0x6c, 0}, 	/* Keypad 7 */
149 		{0xff95, 0x6c, 0}, 	/* Keypad home */
150 		{0xffb8, 0x75, 0}, 	/* Keypad 8 */
151 		{0xff97, 0x75, 0}, 	/* Keypad up arrow */
152 		{0xffb9, 0x7d, 0}, 	/* Keypad 9 */
153 		{0xff9a, 0x7d, 0}, 	/* Keypad PgUp */
154 		{0xffb4, 0x6b, 0}, 	/* Keypad 4 */
155 		{0xff96, 0x6b, 0}, 	/* Keypad left arrow */
156 		{0xffb5, 0x73, 0}, 	/* Keypad 5 */
157 		{0xff9d, 0x73, 0}, 	/* Keypad empty */
158 		{0xffb6, 0x74, 0}, 	/* Keypad 6 */
159 		{0xff98, 0x74, 0}, 	/* Keypad right arrow */
160 		{0xffb1, 0x69, 0}, 	/* Keypad 1 */
161 		{0xff9c, 0x69, 0}, 	/* Keypad end */
162 		{0xffb2, 0x72, 0}, 	/* Keypad 2 */
163 		{0xff99, 0x72, 0}, 	/* Keypad down arrow */
164 		{0xffb3, 0x7a, 0}, 	/* Keypad 3 */
165 		{0xff9b, 0x7a, 0}, 	/* Keypad PgDown */
166 		{0xffb0, 0x70, 0}, 	/* Keypad 0 */
167 		{0xff9e, 0x70, 0}, 	/* Keypad ins */
168 		{0xffae, 0x71, 0}, 	/* Keypad . */
169 		{0xff9f, 0x71, 0}, 	/* Keypad del */
170 		{0, 0, 0} 		/* Terminator */
171 };
172 
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,
191 };
192 
193 /* ScanCode set1 to set2 lookup table */
194 static 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,
211 };
212 
213 static void
214 fifo_init(struct ps2kbd_softc *sc)
215 {
216 	struct fifo *fifo;
217 
218 	fifo = &sc->fifo;
219 	fifo->size = sizeof(((struct fifo *)0)->buf);
220 }
221 
222 static void
223 fifo_reset(struct ps2kbd_softc *sc)
224 {
225 	struct fifo *fifo;
226 
227 	fifo = &sc->fifo;
228 	bzero(fifo, sizeof(struct fifo));
229 	fifo->size = sizeof(((struct fifo *)0)->buf);
230 }
231 
232 static void
233 fifo_put(struct ps2kbd_softc *sc, uint8_t val)
234 {
235 	struct fifo *fifo;
236 
237 	fifo = &sc->fifo;
238 	if (fifo->num < fifo->size) {
239 		fifo->buf[fifo->windex] = val;
240 		fifo->windex = (fifo->windex + 1) % fifo->size;
241 		fifo->num++;
242 	}
243 }
244 
245 static int
246 fifo_get(struct ps2kbd_softc *sc, uint8_t *val)
247 {
248 	struct fifo *fifo;
249 
250 	fifo = &sc->fifo;
251 	if (fifo->num > 0) {
252 		*val = fifo->buf[fifo->rindex];
253 		fifo->rindex = (fifo->rindex + 1) % fifo->size;
254 		fifo->num--;
255 		return (0);
256 	}
257 
258 	return (-1);
259 }
260 
261 int
262 ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
263 {
264 	int retval;
265 
266 	pthread_mutex_lock(&sc->mtx);
267 	retval = fifo_get(sc, val);
268 	pthread_mutex_unlock(&sc->mtx);
269 
270 	return (retval);
271 }
272 
273 void
274 ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
275 {
276 	pthread_mutex_lock(&sc->mtx);
277 	if (sc->curcmd) {
278 		switch (sc->curcmd) {
279 		case PS2KC_SET_TYPEMATIC:
280 			fifo_put(sc, PS2KC_ACK);
281 			break;
282 		case PS2KC_SET_SCANCODE_SET:
283 			fifo_put(sc, PS2KC_ACK);
284 			break;
285 		case PS2KC_SET_LEDS:
286 			fifo_put(sc, PS2KC_ACK);
287 			break;
288 		default:
289 			EPRINTLN("Unhandled ps2 keyboard current "
290 			    "command byte 0x%02x", val);
291 			break;
292 		}
293 		sc->curcmd = 0;
294 	} else {
295 		switch (val) {
296 		case 0x00:
297 			fifo_put(sc, PS2KC_ACK);
298 			break;
299 		case PS2KC_RESET_DEV:
300 			fifo_reset(sc);
301 			fifo_put(sc, PS2KC_ACK);
302 			fifo_put(sc, PS2KC_BAT_SUCCESS);
303 			break;
304 		case PS2KC_SET_DEFAULTS:
305 			fifo_reset(sc);
306 			fifo_put(sc, PS2KC_ACK);
307 			break;
308 		case PS2KC_DISABLE:
309 			sc->enabled = false;
310 			fifo_put(sc, PS2KC_ACK);
311 			break;
312 		case PS2KC_ENABLE:
313 			sc->enabled = true;
314 			fifo_reset(sc);
315 			fifo_put(sc, PS2KC_ACK);
316 			break;
317 		case PS2KC_SET_TYPEMATIC:
318 			sc->curcmd = val;
319 			fifo_put(sc, PS2KC_ACK);
320 			break;
321 		case PS2KC_SEND_DEV_ID:
322 			fifo_put(sc, PS2KC_ACK);
323 			fifo_put(sc, 0xab);
324 			fifo_put(sc, 0x83);
325 			break;
326 		case PS2KC_SET_SCANCODE_SET:
327 			sc->curcmd = val;
328 			fifo_put(sc, PS2KC_ACK);
329 			break;
330 		case PS2KC_ECHO:
331 			fifo_put(sc, PS2KC_ECHO);
332 			break;
333 		case PS2KC_SET_LEDS:
334 			sc->curcmd = val;
335 			fifo_put(sc, PS2KC_ACK);
336 			break;
337 		default:
338 			EPRINTLN("Unhandled ps2 keyboard command "
339 			    "0x%02x", val);
340 			break;
341 		}
342 	}
343 	pthread_mutex_unlock(&sc->mtx);
344 }
345 
346 /*
347  * Translate keysym to type 2 scancode and insert into keyboard buffer.
348  */
349 static void
350 ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
351     int down, uint32_t keysym, uint32_t keycode)
352 {
353 	const struct extended_translation *trans;
354 	int e0_prefix, found;
355 	uint8_t code;
356 
357 	assert(pthread_mutex_isowned_np(&sc->mtx));
358 
359 	if (keycode) {
360 		code =  keyset1to2_translations[(uint8_t)(keycode & 0x7f)];
361 		e0_prefix = ((keycode & 0x80) ?  SCANCODE_E0_PREFIX : 0);
362 		found = 1;
363 	} else {
364 		found = 0;
365 		if (keysym < 0x80) {
366 			code = ascii_translations[keysym];
367 			e0_prefix = 0;
368 			found = 1;
369 		} else {
370 			for (trans = &extended_translations[0];
371 			    trans->keysym != 0; trans++) {
372 				if (keysym == trans->keysym) {
373 					code = trans->scancode;
374 					e0_prefix = trans->flags & SCANCODE_E0_PREFIX;
375 					found = 1;
376 					break;
377 				}
378 			}
379 		}
380 	}
381 
382 	if (!found) {
383 		EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym);
384 		return;
385 	}
386 
387 	if (e0_prefix)
388 		fifo_put(sc, 0xe0);
389 	if (!down)
390 		fifo_put(sc, 0xf0);
391 	fifo_put(sc, code);
392 }
393 
394 static void
395 ps2kbd_event(int down, uint32_t keysym, uint32_t keycode, void *arg)
396 {
397 	struct ps2kbd_softc *sc = arg;
398 	int fifo_full;
399 
400 	pthread_mutex_lock(&sc->mtx);
401 	if (!sc->enabled) {
402 		pthread_mutex_unlock(&sc->mtx);
403 		return;
404 	}
405 	fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
406 	ps2kbd_keysym_queue(sc, down, keysym, keycode);
407 	pthread_mutex_unlock(&sc->mtx);
408 
409 	if (!fifo_full)
410 		atkbdc_event(sc->atkbdc_sc, 1);
411 }
412 
413 static void
414 ps2kbd_update_extended_translation(uint32_t keycode, uint32_t scancode, uint32_t prefix)
415 {
416 	int i = 0;
417 
418 	do {
419 		if (extended_translations[i].keysym == keycode)
420 			break;
421 	} while (extended_translations[++i].keysym);
422 
423 	if (i == (sizeof(extended_translations) / sizeof(struct extended_translation) - 1))
424 		return;
425 
426 	if (!extended_translations[i].keysym)	{
427 		extended_translations[i].keysym = keycode;
428 
429 		extended_translations[i+1].keysym = 0;
430 		extended_translations[i+1].scancode = 0;
431 		extended_translations[i+1].flags = 0;
432 	}
433 
434 	extended_translations[i].scancode = (uint8_t)(scancode & 0xff);
435 	extended_translations[i].flags = (prefix ? SCANCODE_E0_PREFIX : 0);
436 }
437 
438 static void
439 ps2kbd_setkbdlayout(void)
440 {
441 	int err;
442 	int fd;
443 	char path[MAX_PATHNAME];
444 	char *buf, *next, *line;
445 	struct stat sb;
446 	ssize_t sz;
447 	uint8_t ascii;
448 	uint32_t keycode, scancode, prefix;
449 
450 	snprintf(path, MAX_PATHNAME, PS2KBD_LAYOUT_BASEDIR"%s", get_config_value("keyboard.layout") );
451 
452 	err = stat(path, &sb);
453 	if (err)
454 		return;
455 
456 	buf = (char *)malloc(sizeof(char) * sb.st_size);
457 	if (buf == NULL)
458 		return;
459 
460 	fd = open(path, O_RDONLY);
461 	if (fd == -1)
462 		goto out;
463 
464 	sz = read(fd, buf, sb.st_size);
465 
466 	close(fd);
467 
468 	if (sz < 0 || sz != sb.st_size)
469 		goto out;
470 
471 	next = buf;
472 	while ((line = strsep(&next, "\n")) != NULL)	{
473 		if (sscanf(line, "'%c',%x;", &ascii, &scancode) == 2)	{
474 			if (ascii < 0x80)
475 				ascii_translations[ascii] = (uint8_t)(scancode & 0xff);
476 		} else if (sscanf(line, "%x,%x,%x;", &keycode, &scancode, &prefix) == 3 )	{
477 			ps2kbd_update_extended_translation(keycode, scancode, prefix);
478 		} else if (sscanf(line, "%x,%x;", &keycode, &scancode) == 2)	{
479 			if (keycode < 0x80)
480 				ascii_translations[(uint8_t)(keycode & 0xff)] = (uint8_t)(scancode & 0xff);
481 			else
482 				ps2kbd_update_extended_translation(keycode, scancode, 0);
483 		}
484 	}
485 
486 out:
487 	free(buf);
488 }
489 
490 struct ps2kbd_softc *
491 ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
492 {
493 	struct ps2kbd_softc *sc;
494 
495 	if (get_config_value("keyboard.layout") != NULL)
496 		ps2kbd_setkbdlayout();
497 
498 	sc = calloc(1, sizeof (struct ps2kbd_softc));
499 	pthread_mutex_init(&sc->mtx, NULL);
500 	fifo_init(sc);
501 	sc->atkbdc_sc = atkbdc_sc;
502 
503 	console_kbd_register(ps2kbd_event, sc, 1);
504 
505 	return (sc);
506 }
507 
508 #ifdef BHYVE_SNAPSHOT
509 int
510 ps2kbd_snapshot(struct ps2kbd_softc *sc, struct vm_snapshot_meta *meta)
511 {
512 	int ret;
513 
514 	SNAPSHOT_VAR_OR_LEAVE(sc->enabled, meta, ret, done);
515 	SNAPSHOT_VAR_OR_LEAVE(sc->curcmd, meta, ret, done);
516 
517 done:
518 	return (ret);
519 }
520 #endif
521 
522