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