xref: /illumos-gate/usr/src/cmd/bhyve/amd64/ps2kbd.c (revision 5c4a5fe16715fb423db76577a6883b5bbecdbe45)
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 
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 
34 #include <assert.h>
35 #include <stdbool.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <strings.h>
39 #include <pthread.h>
40 #include <pthread_np.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43 
44 #include "atkbdc.h"
45 #include "bhyverun.h"
46 #include "config.h"
47 #include "console.h"
48 #include "debug.h"
49 #include "ps2kbd.h"
50 
51 /* keyboard device commands */
52 #define	PS2KC_RESET_DEV		0xff
53 #define	PS2KC_SET_DEFAULTS	0xf6
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_SET_DEFAULTS:
302 			fifo_reset(sc);
303 			fifo_put(sc, PS2KC_ACK);
304 			break;
305 		case PS2KC_DISABLE:
306 			sc->enabled = false;
307 			fifo_put(sc, PS2KC_ACK);
308 			break;
309 		case PS2KC_ENABLE:
310 			sc->enabled = true;
311 			fifo_reset(sc);
312 			fifo_put(sc, PS2KC_ACK);
313 			break;
314 		case PS2KC_SET_TYPEMATIC:
315 			sc->curcmd = val;
316 			fifo_put(sc, PS2KC_ACK);
317 			break;
318 		case PS2KC_SEND_DEV_ID:
319 			fifo_put(sc, PS2KC_ACK);
320 			fifo_put(sc, 0xab);
321 			fifo_put(sc, 0x83);
322 			break;
323 		case PS2KC_SET_SCANCODE_SET:
324 			sc->curcmd = val;
325 			fifo_put(sc, PS2KC_ACK);
326 			break;
327 		case PS2KC_ECHO:
328 			fifo_put(sc, PS2KC_ECHO);
329 			break;
330 		case PS2KC_SET_LEDS:
331 			sc->curcmd = val;
332 			fifo_put(sc, PS2KC_ACK);
333 			break;
334 		default:
335 			EPRINTLN("Unhandled ps2 keyboard command "
336 			    "0x%02x", val);
337 			break;
338 		}
339 	}
340 	pthread_mutex_unlock(&sc->mtx);
341 }
342 
343 /*
344  * Translate keysym to type 2 scancode and insert into keyboard buffer.
345  */
346 static void
ps2kbd_keysym_queue(struct ps2kbd_softc * sc,int down,uint32_t keysym,uint32_t keycode)347 ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
348     int down, uint32_t keysym, uint32_t keycode)
349 {
350 	const struct extended_translation *trans;
351 	int e0_prefix, found;
352 	uint8_t code;
353 
354 	assert(pthread_mutex_isowned_np(&sc->mtx));
355 
356 	if (keycode) {
357 		code =  keyset1to2_translations[(uint8_t)(keycode & 0x7f)];
358 		e0_prefix = ((keycode & 0x80) ?  SCANCODE_E0_PREFIX : 0);
359 		found = 1;
360 	} else {
361 		found = 0;
362 		if (keysym < 0x80) {
363 			code = ascii_translations[keysym];
364 			e0_prefix = 0;
365 			found = 1;
366 		} else {
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;
372 					found = 1;
373 					break;
374 				}
375 			}
376 		}
377 	}
378 
379 	if (!found) {
380 		EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym);
381 		return;
382 	}
383 
384 	if (e0_prefix)
385 		fifo_put(sc, 0xe0);
386 	if (!down)
387 		fifo_put(sc, 0xf0);
388 	fifo_put(sc, code);
389 }
390 
391 static void
ps2kbd_event(int down,uint32_t keysym,uint32_t keycode,void * arg)392 ps2kbd_event(int down, uint32_t keysym, uint32_t keycode, void *arg)
393 {
394 	struct ps2kbd_softc *sc = arg;
395 	int fifo_full;
396 
397 	pthread_mutex_lock(&sc->mtx);
398 	if (!sc->enabled) {
399 		pthread_mutex_unlock(&sc->mtx);
400 		return;
401 	}
402 	fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
403 	ps2kbd_keysym_queue(sc, down, keysym, keycode);
404 	pthread_mutex_unlock(&sc->mtx);
405 
406 	if (!fifo_full)
407 		atkbdc_event(sc->atkbdc_sc, 1);
408 }
409 
410 static void
ps2kbd_update_extended_translation(uint32_t keycode,uint32_t scancode,uint32_t prefix)411 ps2kbd_update_extended_translation(uint32_t keycode, uint32_t scancode, uint32_t prefix)
412 {
413 	int i = 0;
414 
415 	do {
416 		if (extended_translations[i].keysym == keycode)
417 			break;
418 	} while (extended_translations[++i].keysym);
419 
420 	if (i == (sizeof(extended_translations) / sizeof(struct extended_translation) - 1))
421 		return;
422 
423 	if (!extended_translations[i].keysym)	{
424 		extended_translations[i].keysym = keycode;
425 
426 		extended_translations[i+1].keysym = 0;
427 		extended_translations[i+1].scancode = 0;
428 		extended_translations[i+1].flags = 0;
429 	}
430 
431 	extended_translations[i].scancode = (uint8_t)(scancode & 0xff);
432 	extended_translations[i].flags = (prefix ? SCANCODE_E0_PREFIX : 0);
433 }
434 
435 static void
ps2kbd_setkbdlayout(void)436 ps2kbd_setkbdlayout(void)
437 {
438 	int err;
439 	int fd;
440 	char path[MAX_PATHNAME];
441 	char *buf, *next, *line;
442 	struct stat sb;
443 	ssize_t sz;
444 	uint8_t ascii;
445 	uint32_t keycode, scancode, prefix;
446 
447 	snprintf(path, MAX_PATHNAME, PS2KBD_LAYOUT_BASEDIR"%s", get_config_value("keyboard.layout") );
448 
449 	err = stat(path, &sb);
450 	if (err)
451 		return;
452 
453 	buf = (char *)malloc(sizeof(char) * sb.st_size);
454 	if (buf == NULL)
455 		return;
456 
457 	fd = open(path, O_RDONLY);
458 	if (fd == -1)
459 		goto out;
460 
461 	sz = read(fd, buf, sb.st_size);
462 
463 	close(fd);
464 
465 	if (sz < 0 || sz != sb.st_size)
466 		goto out;
467 
468 	next = buf;
469 	while ((line = strsep(&next, "\n")) != NULL)	{
470 		if (sscanf(line, "'%c',%x;", &ascii, &scancode) == 2)	{
471 			if (ascii < 0x80)
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)	{
476 			if (keycode < 0x80)
477 				ascii_translations[(uint8_t)(keycode & 0xff)] = (uint8_t)(scancode & 0xff);
478 			else
479 				ps2kbd_update_extended_translation(keycode, scancode, 0);
480 		}
481 	}
482 
483 out:
484 	free(buf);
485 }
486 
487 struct ps2kbd_softc *
ps2kbd_init(struct atkbdc_softc * atkbdc_sc)488 ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
489 {
490 	struct ps2kbd_softc *sc;
491 
492 	if (get_config_value("keyboard.layout") != NULL)
493 		ps2kbd_setkbdlayout();
494 
495 	sc = calloc(1, sizeof (struct ps2kbd_softc));
496 	pthread_mutex_init(&sc->mtx, NULL);
497 	fifo_init(sc);
498 	sc->atkbdc_sc = atkbdc_sc;
499 
500 	console_kbd_register(ps2kbd_event, sc, 1);
501 
502 	return (sc);
503 }
504 
505