xref: /freebsd-13.1/usr.sbin/bhyve/ps2kbd.c (revision 483d953a)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2015 Tycho Nightingale <[email protected]>
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 __FBSDID("$FreeBSD$");
32 
33 #include <sys/types.h>
34 
35 #include <machine/vmm_snapshot.h>
36 
37 #include <assert.h>
38 #include <stdbool.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <strings.h>
43 #include <pthread.h>
44 #include <pthread_np.h>
45 
46 #include "atkbdc.h"
47 #include "debug.h"
48 #include "console.h"
49 
50 /* keyboard device commands */
51 #define	PS2KC_RESET_DEV		0xff
52 #define	PS2KC_DISABLE		0xf5
53 #define	PS2KC_ENABLE		0xf4
54 #define	PS2KC_SET_TYPEMATIC	0xf3
55 #define	PS2KC_SEND_DEV_ID	0xf2
56 #define	PS2KC_SET_SCANCODE_SET	0xf0
57 #define	PS2KC_ECHO		0xee
58 #define	PS2KC_SET_LEDS		0xed
59 
60 #define	PS2KC_BAT_SUCCESS	0xaa
61 #define	PS2KC_ACK		0xfa
62 
63 #define	PS2KBD_FIFOSZ		16
64 
65 struct fifo {
66 	uint8_t	buf[PS2KBD_FIFOSZ];
67 	int	rindex;		/* index to read from */
68 	int	windex;		/* index to write to */
69 	int	num;		/* number of bytes in the fifo */
70 	int	size;		/* size of the fifo */
71 };
72 
73 struct ps2kbd_softc {
74 	struct atkbdc_softc	*atkbdc_sc;
75 	pthread_mutex_t		mtx;
76 
77 	bool			enabled;
78 	struct fifo		fifo;
79 
80 	uint8_t			curcmd;	/* current command for next byte */
81 };
82 
83 #define SCANCODE_E0_PREFIX 1
84 struct extended_translation {
85 	uint32_t keysym;
86 	uint8_t scancode;
87 	int flags;
88 };
89 
90 /*
91  * FIXME: Pause/break and Print Screen/SysRq require special handling.
92  */
93 static const struct extended_translation extended_translations[] = {
94 		{0xff08, 0x66},		/* Back space */
95 		{0xff09, 0x0d},		/* Tab */
96 		{0xff0d, 0x5a},		/* Return */
97 		{0xff1b, 0x76},		/* Escape */
98 		{0xff50, 0x6c, SCANCODE_E0_PREFIX}, 	/* Home */
99 		{0xff51, 0x6b, SCANCODE_E0_PREFIX}, 	/* Left arrow */
100 		{0xff52, 0x75, SCANCODE_E0_PREFIX}, 	/* Up arrow */
101 		{0xff53, 0x74, SCANCODE_E0_PREFIX}, 	/* Right arrow */
102 		{0xff54, 0x72, SCANCODE_E0_PREFIX}, 	/* Down arrow */
103 		{0xff55, 0x7d, SCANCODE_E0_PREFIX}, 	/* PgUp */
104 		{0xff56, 0x7a, SCANCODE_E0_PREFIX}, 	/* PgDown */
105 		{0xff57, 0x69, SCANCODE_E0_PREFIX}, 	/* End */
106 		{0xff63, 0x70, SCANCODE_E0_PREFIX}, 	/* Ins */
107 		{0xff8d, 0x5a, SCANCODE_E0_PREFIX}, 	/* Keypad Enter */
108 		{0xffe1, 0x12},		/* Left shift */
109 		{0xffe2, 0x59},		/* Right shift */
110 		{0xffe3, 0x14},		/* Left control */
111 		{0xffe4, 0x14, SCANCODE_E0_PREFIX}, 	/* Right control */
112 		/* {0xffe7, XXX}, Left meta */
113 		/* {0xffe8, XXX}, Right meta */
114 		{0xffe9, 0x11},		/* Left alt */
115 		{0xfe03, 0x11, SCANCODE_E0_PREFIX}, 	/* AltGr */
116 		{0xffea, 0x11, SCANCODE_E0_PREFIX}, 	/* Right alt */
117 		{0xffeb, 0x1f, SCANCODE_E0_PREFIX}, 	/* Left Windows */
118 		{0xffec, 0x27, SCANCODE_E0_PREFIX}, 	/* Right Windows */
119 		{0xffbe, 0x05},		/* F1 */
120 		{0xffbf, 0x06},		/* F2 */
121 		{0xffc0, 0x04},		/* F3 */
122 		{0xffc1, 0x0c},		/* F4 */
123 		{0xffc2, 0x03},		/* F5 */
124 		{0xffc3, 0x0b},		/* F6 */
125 		{0xffc4, 0x83},		/* F7 */
126 		{0xffc5, 0x0a},		/* F8 */
127 		{0xffc6, 0x01},		/* F9 */
128 		{0xffc7, 0x09},		/* F10 */
129 		{0xffc8, 0x78},		/* F11 */
130 		{0xffc9, 0x07},		/* F12 */
131 		{0xffff, 0x71, SCANCODE_E0_PREFIX},	/* Del */
132 		{0xff14, 0x7e},		/* ScrollLock */
133 		/* NumLock and Keypads*/
134 		{0xff7f, 0x77}, 	/* NumLock */
135 		{0xffaf, 0x4a, SCANCODE_E0_PREFIX}, 	/* Keypad slash */
136 		{0xffaa, 0x7c}, 	/* Keypad asterisk */
137 		{0xffad, 0x7b}, 	/* Keypad minus */
138 		{0xffab, 0x79}, 	/* Keypad plus */
139 		{0xffb7, 0x6c}, 	/* Keypad 7 */
140 		{0xff95, 0x6c}, 	/* Keypad home */
141 		{0xffb8, 0x75}, 	/* Keypad 8 */
142 		{0xff97, 0x75}, 	/* Keypad up arrow */
143 		{0xffb9, 0x7d}, 	/* Keypad 9 */
144 		{0xff9a, 0x7d}, 	/* Keypad PgUp */
145 		{0xffb4, 0x6b}, 	/* Keypad 4 */
146 		{0xff96, 0x6b}, 	/* Keypad left arrow */
147 		{0xffb5, 0x73}, 	/* Keypad 5 */
148 		{0xff9d, 0x73}, 	/* Keypad empty */
149 		{0xffb6, 0x74}, 	/* Keypad 6 */
150 		{0xff98, 0x74}, 	/* Keypad right arrow */
151 		{0xffb1, 0x69}, 	/* Keypad 1 */
152 		{0xff9c, 0x69}, 	/* Keypad end */
153 		{0xffb2, 0x72}, 	/* Keypad 2 */
154 		{0xff99, 0x72}, 	/* Keypad down arrow */
155 		{0xffb3, 0x7a}, 	/* Keypad 3 */
156 		{0xff9b, 0x7a}, 	/* Keypad PgDown */
157 		{0xffb0, 0x70}, 	/* Keypad 0 */
158 		{0xff9e, 0x70}, 	/* Keypad ins */
159 		{0xffae, 0x71}, 	/* Keypad . */
160 		{0xff9f, 0x71}, 	/* Keypad del */
161 		{0, 0, 0} 		/* Terminator */
162 };
163 
164 /* ASCII to type 2 scancode lookup table */
165 static const uint8_t ascii_translations[128] = {
166 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
167 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
168 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 		0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52,
171 		0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a,
172 		0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d,
173 		0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a,
174 		0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
175 		0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
176 		0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
177 		0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e,
178 		0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
179 		0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
180 		0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
181 		0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00,
182 };
183 
184 static void
fifo_init(struct ps2kbd_softc * sc)185 fifo_init(struct ps2kbd_softc *sc)
186 {
187 	struct fifo *fifo;
188 
189 	fifo = &sc->fifo;
190 	fifo->size = sizeof(((struct fifo *)0)->buf);
191 }
192 
193 static void
fifo_reset(struct ps2kbd_softc * sc)194 fifo_reset(struct ps2kbd_softc *sc)
195 {
196 	struct fifo *fifo;
197 
198 	fifo = &sc->fifo;
199 	bzero(fifo, sizeof(struct fifo));
200 	fifo->size = sizeof(((struct fifo *)0)->buf);
201 }
202 
203 static void
fifo_put(struct ps2kbd_softc * sc,uint8_t val)204 fifo_put(struct ps2kbd_softc *sc, uint8_t val)
205 {
206 	struct fifo *fifo;
207 
208 	fifo = &sc->fifo;
209 	if (fifo->num < fifo->size) {
210 		fifo->buf[fifo->windex] = val;
211 		fifo->windex = (fifo->windex + 1) % fifo->size;
212 		fifo->num++;
213 	}
214 }
215 
216 static int
fifo_get(struct ps2kbd_softc * sc,uint8_t * val)217 fifo_get(struct ps2kbd_softc *sc, uint8_t *val)
218 {
219 	struct fifo *fifo;
220 
221 	fifo = &sc->fifo;
222 	if (fifo->num > 0) {
223 		*val = fifo->buf[fifo->rindex];
224 		fifo->rindex = (fifo->rindex + 1) % fifo->size;
225 		fifo->num--;
226 		return (0);
227 	}
228 
229 	return (-1);
230 }
231 
232 int
ps2kbd_read(struct ps2kbd_softc * sc,uint8_t * val)233 ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
234 {
235 	int retval;
236 
237 	pthread_mutex_lock(&sc->mtx);
238 	retval = fifo_get(sc, val);
239 	pthread_mutex_unlock(&sc->mtx);
240 
241 	return (retval);
242 }
243 
244 void
ps2kbd_write(struct ps2kbd_softc * sc,uint8_t val)245 ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
246 {
247 	pthread_mutex_lock(&sc->mtx);
248 	if (sc->curcmd) {
249 		switch (sc->curcmd) {
250 		case PS2KC_SET_TYPEMATIC:
251 			fifo_put(sc, PS2KC_ACK);
252 			break;
253 		case PS2KC_SET_SCANCODE_SET:
254 			fifo_put(sc, PS2KC_ACK);
255 			break;
256 		case PS2KC_SET_LEDS:
257 			fifo_put(sc, PS2KC_ACK);
258 			break;
259 		default:
260 			EPRINTLN("Unhandled ps2 keyboard current "
261 			    "command byte 0x%02x", val);
262 			break;
263 		}
264 		sc->curcmd = 0;
265 	} else {
266 		switch (val) {
267 		case 0x00:
268 			fifo_put(sc, PS2KC_ACK);
269 			break;
270 		case PS2KC_RESET_DEV:
271 			fifo_reset(sc);
272 			fifo_put(sc, PS2KC_ACK);
273 			fifo_put(sc, PS2KC_BAT_SUCCESS);
274 			break;
275 		case PS2KC_DISABLE:
276 			sc->enabled = false;
277 			fifo_put(sc, PS2KC_ACK);
278 			break;
279 		case PS2KC_ENABLE:
280 			sc->enabled = true;
281 			fifo_reset(sc);
282 			fifo_put(sc, PS2KC_ACK);
283 			break;
284 		case PS2KC_SET_TYPEMATIC:
285 			sc->curcmd = val;
286 			fifo_put(sc, PS2KC_ACK);
287 			break;
288 		case PS2KC_SEND_DEV_ID:
289 			fifo_put(sc, PS2KC_ACK);
290 			fifo_put(sc, 0xab);
291 			fifo_put(sc, 0x83);
292 			break;
293 		case PS2KC_SET_SCANCODE_SET:
294 			sc->curcmd = val;
295 			fifo_put(sc, PS2KC_ACK);
296 			break;
297 		case PS2KC_ECHO:
298 			fifo_put(sc, PS2KC_ECHO);
299 			break;
300 		case PS2KC_SET_LEDS:
301 			sc->curcmd = val;
302 			fifo_put(sc, PS2KC_ACK);
303 			break;
304 		default:
305 			EPRINTLN("Unhandled ps2 keyboard command "
306 			    "0x%02x", val);
307 			break;
308 		}
309 	}
310 	pthread_mutex_unlock(&sc->mtx);
311 }
312 
313 /*
314  * Translate keysym to type 2 scancode and insert into keyboard buffer.
315  */
316 static void
ps2kbd_keysym_queue(struct ps2kbd_softc * sc,int down,uint32_t keysym)317 ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
318     int down, uint32_t keysym)
319 {
320 	assert(pthread_mutex_isowned_np(&sc->mtx));
321 	int e0_prefix, found;
322 	uint8_t code;
323 	const struct extended_translation *trans;
324 
325 	found = 0;
326 	if (keysym < 0x80) {
327 		code = ascii_translations[keysym];
328 		e0_prefix = 0;
329 		found = 1;
330 	} else {
331 		for (trans = &(extended_translations[0]); trans->keysym != 0;
332 		    trans++) {
333 			if (keysym == trans->keysym) {
334 				code = trans->scancode;
335 				e0_prefix = trans->flags & SCANCODE_E0_PREFIX;
336 				found = 1;
337 				break;
338 			}
339 		}
340 	}
341 
342 	if (!found) {
343 		EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym);
344 		return;
345 	}
346 
347 	if (e0_prefix)
348 		fifo_put(sc, 0xe0);
349 	if (!down)
350 		fifo_put(sc, 0xf0);
351 	fifo_put(sc, code);
352 }
353 
354 static void
ps2kbd_event(int down,uint32_t keysym,void * arg)355 ps2kbd_event(int down, uint32_t keysym, void *arg)
356 {
357 	struct ps2kbd_softc *sc = arg;
358 	int fifo_full;
359 
360 	pthread_mutex_lock(&sc->mtx);
361 	if (!sc->enabled) {
362 		pthread_mutex_unlock(&sc->mtx);
363 		return;
364 	}
365 	fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
366 	ps2kbd_keysym_queue(sc, down, keysym);
367 	pthread_mutex_unlock(&sc->mtx);
368 
369 	if (!fifo_full)
370 		atkbdc_event(sc->atkbdc_sc, 1);
371 }
372 
373 struct ps2kbd_softc *
ps2kbd_init(struct atkbdc_softc * atkbdc_sc)374 ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
375 {
376 	struct ps2kbd_softc *sc;
377 
378 	sc = calloc(1, sizeof (struct ps2kbd_softc));
379 	pthread_mutex_init(&sc->mtx, NULL);
380 	fifo_init(sc);
381 	sc->atkbdc_sc = atkbdc_sc;
382 
383 	console_kbd_register(ps2kbd_event, sc, 1);
384 
385 	return (sc);
386 }
387 
388 #ifdef BHYVE_SNAPSHOT
389 int
ps2kbd_snapshot(struct ps2kbd_softc * sc,struct vm_snapshot_meta * meta)390 ps2kbd_snapshot(struct ps2kbd_softc *sc, struct vm_snapshot_meta *meta)
391 {
392 	int ret;
393 
394 	SNAPSHOT_VAR_OR_LEAVE(sc->enabled, meta, ret, done);
395 	SNAPSHOT_VAR_OR_LEAVE(sc->curcmd, meta, ret, done);
396 
397 done:
398 	return (ret);
399 }
400 #endif
401 
402