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