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