xref: /illumos-gate/usr/src/cmd/bhyve/ps2kbd.c (revision 4c87aefe)
1bf21cd93STycho Nightingale /*-
2*4c87aefeSPatrick Mooney  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*4c87aefeSPatrick Mooney  *
4bf21cd93STycho Nightingale  * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
5bf21cd93STycho Nightingale  * Copyright (c) 2015 Nahanni Systems Inc.
6bf21cd93STycho Nightingale  * All rights reserved.
7bf21cd93STycho Nightingale  *
8bf21cd93STycho Nightingale  * Redistribution and use in source and binary forms, with or without
9bf21cd93STycho Nightingale  * modification, are permitted provided that the following conditions
10bf21cd93STycho Nightingale  * are met:
11bf21cd93STycho Nightingale  * 1. Redistributions of source code must retain the above copyright
12bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer.
13bf21cd93STycho Nightingale  * 2. Redistributions in binary form must reproduce the above copyright
14bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer in the
15bf21cd93STycho Nightingale  *    documentation and/or other materials provided with the distribution.
16bf21cd93STycho Nightingale  *
17bf21cd93STycho Nightingale  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
18bf21cd93STycho Nightingale  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19bf21cd93STycho Nightingale  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20bf21cd93STycho Nightingale  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21bf21cd93STycho Nightingale  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22bf21cd93STycho Nightingale  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23bf21cd93STycho Nightingale  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24bf21cd93STycho Nightingale  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25bf21cd93STycho Nightingale  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26bf21cd93STycho Nightingale  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27bf21cd93STycho Nightingale  * SUCH DAMAGE.
28bf21cd93STycho Nightingale  */
29bf21cd93STycho Nightingale 
30bf21cd93STycho Nightingale #include <sys/cdefs.h>
31bf21cd93STycho Nightingale __FBSDID("$FreeBSD$");
32bf21cd93STycho Nightingale 
33bf21cd93STycho Nightingale #include <sys/types.h>
34bf21cd93STycho Nightingale 
35bf21cd93STycho Nightingale #include <assert.h>
36bf21cd93STycho Nightingale #include <stdbool.h>
37bf21cd93STycho Nightingale #include <stdio.h>
38bf21cd93STycho Nightingale #include <stdlib.h>
39bf21cd93STycho Nightingale #include <strings.h>
40bf21cd93STycho Nightingale #include <pthread.h>
41bf21cd93STycho Nightingale #include <pthread_np.h>
42bf21cd93STycho Nightingale 
43bf21cd93STycho Nightingale #include "atkbdc.h"
44bf21cd93STycho Nightingale #include "console.h"
45bf21cd93STycho Nightingale 
46bf21cd93STycho Nightingale /* keyboard device commands */
47bf21cd93STycho Nightingale #define	PS2KC_RESET_DEV		0xff
48bf21cd93STycho Nightingale #define	PS2KC_DISABLE		0xf5
49bf21cd93STycho Nightingale #define	PS2KC_ENABLE		0xf4
50bf21cd93STycho Nightingale #define	PS2KC_SET_TYPEMATIC	0xf3
51bf21cd93STycho Nightingale #define	PS2KC_SEND_DEV_ID	0xf2
52bf21cd93STycho Nightingale #define	PS2KC_SET_SCANCODE_SET	0xf0
53bf21cd93STycho Nightingale #define	PS2KC_ECHO		0xee
54bf21cd93STycho Nightingale #define	PS2KC_SET_LEDS		0xed
55bf21cd93STycho Nightingale 
56bf21cd93STycho Nightingale #define	PS2KC_BAT_SUCCESS	0xaa
57bf21cd93STycho Nightingale #define	PS2KC_ACK		0xfa
58bf21cd93STycho Nightingale 
59bf21cd93STycho Nightingale #define	PS2KBD_FIFOSZ		16
60bf21cd93STycho Nightingale 
61bf21cd93STycho Nightingale struct fifo {
62bf21cd93STycho Nightingale 	uint8_t	buf[PS2KBD_FIFOSZ];
63bf21cd93STycho Nightingale 	int	rindex;		/* index to read from */
64bf21cd93STycho Nightingale 	int	windex;		/* index to write to */
65bf21cd93STycho Nightingale 	int	num;		/* number of bytes in the fifo */
66bf21cd93STycho Nightingale 	int	size;		/* size of the fifo */
67bf21cd93STycho Nightingale };
68bf21cd93STycho Nightingale 
69bf21cd93STycho Nightingale struct ps2kbd_softc {
70bf21cd93STycho Nightingale 	struct atkbdc_softc	*atkbdc_sc;
71bf21cd93STycho Nightingale 	pthread_mutex_t		mtx;
72bf21cd93STycho Nightingale 
73bf21cd93STycho Nightingale 	bool			enabled;
74bf21cd93STycho Nightingale 	struct fifo		fifo;
75bf21cd93STycho Nightingale 
76bf21cd93STycho Nightingale 	uint8_t			curcmd;	/* current command for next byte */
77bf21cd93STycho Nightingale };
78bf21cd93STycho Nightingale 
79*4c87aefeSPatrick Mooney #define SCANCODE_E0_PREFIX 1
80*4c87aefeSPatrick Mooney struct extended_translation {
81*4c87aefeSPatrick Mooney 	uint32_t keysym;
82*4c87aefeSPatrick Mooney 	uint8_t scancode;
83*4c87aefeSPatrick Mooney 	int flags;
84*4c87aefeSPatrick Mooney };
85*4c87aefeSPatrick Mooney 
86*4c87aefeSPatrick Mooney /*
87*4c87aefeSPatrick Mooney  * FIXME: Pause/break and Print Screen/SysRq require special handling.
88*4c87aefeSPatrick Mooney  */
89*4c87aefeSPatrick Mooney static const struct extended_translation extended_translations[] = {
90*4c87aefeSPatrick Mooney 		{0xff08, 0x66},		/* Back space */
91*4c87aefeSPatrick Mooney 		{0xff09, 0x0d},		/* Tab */
92*4c87aefeSPatrick Mooney 		{0xff0d, 0x5a},		/* Return */
93*4c87aefeSPatrick Mooney 		{0xff1b, 0x76},		/* Escape */
94*4c87aefeSPatrick Mooney 		{0xff50, 0x6c, SCANCODE_E0_PREFIX}, 	/* Home */
95*4c87aefeSPatrick Mooney 		{0xff51, 0x6b, SCANCODE_E0_PREFIX}, 	/* Left arrow */
96*4c87aefeSPatrick Mooney 		{0xff52, 0x75, SCANCODE_E0_PREFIX}, 	/* Up arrow */
97*4c87aefeSPatrick Mooney 		{0xff53, 0x74, SCANCODE_E0_PREFIX}, 	/* Right arrow */
98*4c87aefeSPatrick Mooney 		{0xff54, 0x72, SCANCODE_E0_PREFIX}, 	/* Down arrow */
99*4c87aefeSPatrick Mooney 		{0xff55, 0x7d, SCANCODE_E0_PREFIX}, 	/* PgUp */
100*4c87aefeSPatrick Mooney 		{0xff56, 0x7a, SCANCODE_E0_PREFIX}, 	/* PgDown */
101*4c87aefeSPatrick Mooney 		{0xff57, 0x69, SCANCODE_E0_PREFIX}, 	/* End */
102*4c87aefeSPatrick Mooney 		{0xff63, 0x70, SCANCODE_E0_PREFIX}, 	/* Ins */
103*4c87aefeSPatrick Mooney 		{0xff8d, 0x5a, SCANCODE_E0_PREFIX}, 	/* Keypad Enter */
104*4c87aefeSPatrick Mooney 		{0xffe1, 0x12},		/* Left shift */
105*4c87aefeSPatrick Mooney 		{0xffe2, 0x59},		/* Right shift */
106*4c87aefeSPatrick Mooney 		{0xffe3, 0x14},		/* Left control */
107*4c87aefeSPatrick Mooney 		{0xffe4, 0x14, SCANCODE_E0_PREFIX}, 	/* Right control */
108*4c87aefeSPatrick Mooney 		/* {0xffe7, XXX}, Left meta */
109*4c87aefeSPatrick Mooney 		/* {0xffe8, XXX}, Right meta */
110*4c87aefeSPatrick Mooney 		{0xffe9, 0x11},		/* Left alt */
111*4c87aefeSPatrick Mooney 		{0xfe03, 0x11, SCANCODE_E0_PREFIX}, 	/* AltGr */
112*4c87aefeSPatrick Mooney 		{0xffea, 0x11, SCANCODE_E0_PREFIX}, 	/* Right alt */
113*4c87aefeSPatrick Mooney 		{0xffeb, 0x1f, SCANCODE_E0_PREFIX}, 	/* Left Windows */
114*4c87aefeSPatrick Mooney 		{0xffec, 0x27, SCANCODE_E0_PREFIX}, 	/* Right Windows */
115*4c87aefeSPatrick Mooney 		{0xffbe, 0x05},		/* F1 */
116*4c87aefeSPatrick Mooney 		{0xffbf, 0x06},		/* F2 */
117*4c87aefeSPatrick Mooney 		{0xffc0, 0x04},		/* F3 */
118*4c87aefeSPatrick Mooney 		{0xffc1, 0x0c},		/* F4 */
119*4c87aefeSPatrick Mooney 		{0xffc2, 0x03},		/* F5 */
120*4c87aefeSPatrick Mooney 		{0xffc3, 0x0b},		/* F6 */
121*4c87aefeSPatrick Mooney 		{0xffc4, 0x83},		/* F7 */
122*4c87aefeSPatrick Mooney 		{0xffc5, 0x0a},		/* F8 */
123*4c87aefeSPatrick Mooney 		{0xffc6, 0x01},		/* F9 */
124*4c87aefeSPatrick Mooney 		{0xffc7, 0x09},		/* F10 */
125*4c87aefeSPatrick Mooney 		{0xffc8, 0x78},		/* F11 */
126*4c87aefeSPatrick Mooney 		{0xffc9, 0x07},		/* F12 */
127*4c87aefeSPatrick Mooney 		{0xffff, 0x71, SCANCODE_E0_PREFIX},	/* Del */
128*4c87aefeSPatrick Mooney 		{0xff14, 0x7e},		/* ScrollLock */
129*4c87aefeSPatrick Mooney 		/* NumLock and Keypads*/
130*4c87aefeSPatrick Mooney 		{0xff7f, 0x77}, 	/* NumLock */
131*4c87aefeSPatrick Mooney 		{0xffaf, 0x4a, SCANCODE_E0_PREFIX}, 	/* Keypad slash */
132*4c87aefeSPatrick Mooney 		{0xffaa, 0x7c}, 	/* Keypad asterisk */
133*4c87aefeSPatrick Mooney 		{0xffad, 0x7b}, 	/* Keypad minus */
134*4c87aefeSPatrick Mooney 		{0xffab, 0x79}, 	/* Keypad plus */
135*4c87aefeSPatrick Mooney 		{0xffb7, 0x6c}, 	/* Keypad 7 */
136*4c87aefeSPatrick Mooney 		{0xff95, 0x6c}, 	/* Keypad home */
137*4c87aefeSPatrick Mooney 		{0xffb8, 0x75}, 	/* Keypad 8 */
138*4c87aefeSPatrick Mooney 		{0xff97, 0x75}, 	/* Keypad up arrow */
139*4c87aefeSPatrick Mooney 		{0xffb9, 0x7d}, 	/* Keypad 9 */
140*4c87aefeSPatrick Mooney 		{0xff9a, 0x7d}, 	/* Keypad PgUp */
141*4c87aefeSPatrick Mooney 		{0xffb4, 0x6b}, 	/* Keypad 4 */
142*4c87aefeSPatrick Mooney 		{0xff96, 0x6b}, 	/* Keypad left arrow */
143*4c87aefeSPatrick Mooney 		{0xffb5, 0x73}, 	/* Keypad 5 */
144*4c87aefeSPatrick Mooney 		{0xff9d, 0x73}, 	/* Keypad empty */
145*4c87aefeSPatrick Mooney 		{0xffb6, 0x74}, 	/* Keypad 6 */
146*4c87aefeSPatrick Mooney 		{0xff98, 0x74}, 	/* Keypad right arrow */
147*4c87aefeSPatrick Mooney 		{0xffb1, 0x69}, 	/* Keypad 1 */
148*4c87aefeSPatrick Mooney 		{0xff9c, 0x69}, 	/* Keypad end */
149*4c87aefeSPatrick Mooney 		{0xffb2, 0x72}, 	/* Keypad 2 */
150*4c87aefeSPatrick Mooney 		{0xff99, 0x72}, 	/* Keypad down arrow */
151*4c87aefeSPatrick Mooney 		{0xffb3, 0x7a}, 	/* Keypad 3 */
152*4c87aefeSPatrick Mooney 		{0xff9b, 0x7a}, 	/* Keypad PgDown */
153*4c87aefeSPatrick Mooney 		{0xffb0, 0x70}, 	/* Keypad 0 */
154*4c87aefeSPatrick Mooney 		{0xff9e, 0x70}, 	/* Keypad ins */
155*4c87aefeSPatrick Mooney 		{0xffae, 0x71}, 	/* Keypad . */
156*4c87aefeSPatrick Mooney 		{0xff9f, 0x71}, 	/* Keypad del */
157*4c87aefeSPatrick Mooney 		{0, 0, 0} 		/* Terminator */
158*4c87aefeSPatrick Mooney };
159*4c87aefeSPatrick Mooney 
160*4c87aefeSPatrick Mooney /* ASCII to type 2 scancode lookup table */
161*4c87aefeSPatrick Mooney static const uint8_t ascii_translations[128] = {
162*4c87aefeSPatrick Mooney 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
163*4c87aefeSPatrick Mooney 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164*4c87aefeSPatrick Mooney 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165*4c87aefeSPatrick Mooney 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
166*4c87aefeSPatrick Mooney 		0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52,
167*4c87aefeSPatrick Mooney 		0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a,
168*4c87aefeSPatrick Mooney 		0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d,
169*4c87aefeSPatrick Mooney 		0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a,
170*4c87aefeSPatrick Mooney 		0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
171*4c87aefeSPatrick Mooney 		0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
172*4c87aefeSPatrick Mooney 		0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
173*4c87aefeSPatrick Mooney 		0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e,
174*4c87aefeSPatrick Mooney 		0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
175*4c87aefeSPatrick Mooney 		0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
176*4c87aefeSPatrick Mooney 		0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
177*4c87aefeSPatrick Mooney 		0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00,
178*4c87aefeSPatrick Mooney };
179*4c87aefeSPatrick Mooney 
180bf21cd93STycho Nightingale static void
181bf21cd93STycho Nightingale fifo_init(struct ps2kbd_softc *sc)
182bf21cd93STycho Nightingale {
183bf21cd93STycho Nightingale 	struct fifo *fifo;
184bf21cd93STycho Nightingale 
185bf21cd93STycho Nightingale 	fifo = &sc->fifo;
186bf21cd93STycho Nightingale 	fifo->size = sizeof(((struct fifo *)0)->buf);
187bf21cd93STycho Nightingale }
188bf21cd93STycho Nightingale 
189bf21cd93STycho Nightingale static void
190bf21cd93STycho Nightingale fifo_reset(struct ps2kbd_softc *sc)
191bf21cd93STycho Nightingale {
192bf21cd93STycho Nightingale 	struct fifo *fifo;
193bf21cd93STycho Nightingale 
194bf21cd93STycho Nightingale 	fifo = &sc->fifo;
195bf21cd93STycho Nightingale 	bzero(fifo, sizeof(struct fifo));
196bf21cd93STycho Nightingale 	fifo->size = sizeof(((struct fifo *)0)->buf);
197bf21cd93STycho Nightingale }
198bf21cd93STycho Nightingale 
199bf21cd93STycho Nightingale static void
200bf21cd93STycho Nightingale fifo_put(struct ps2kbd_softc *sc, uint8_t val)
201bf21cd93STycho Nightingale {
202bf21cd93STycho Nightingale 	struct fifo *fifo;
203bf21cd93STycho Nightingale 
204bf21cd93STycho Nightingale 	fifo = &sc->fifo;
205bf21cd93STycho Nightingale 	if (fifo->num < fifo->size) {
206bf21cd93STycho Nightingale 		fifo->buf[fifo->windex] = val;
207bf21cd93STycho Nightingale 		fifo->windex = (fifo->windex + 1) % fifo->size;
208bf21cd93STycho Nightingale 		fifo->num++;
209bf21cd93STycho Nightingale 	}
210bf21cd93STycho Nightingale }
211bf21cd93STycho Nightingale 
212bf21cd93STycho Nightingale static int
213bf21cd93STycho Nightingale fifo_get(struct ps2kbd_softc *sc, uint8_t *val)
214bf21cd93STycho Nightingale {
215bf21cd93STycho Nightingale 	struct fifo *fifo;
216bf21cd93STycho Nightingale 
217bf21cd93STycho Nightingale 	fifo = &sc->fifo;
218bf21cd93STycho Nightingale 	if (fifo->num > 0) {
219bf21cd93STycho Nightingale 		*val = fifo->buf[fifo->rindex];
220bf21cd93STycho Nightingale 		fifo->rindex = (fifo->rindex + 1) % fifo->size;
221bf21cd93STycho Nightingale 		fifo->num--;
222bf21cd93STycho Nightingale 		return (0);
223bf21cd93STycho Nightingale 	}
224bf21cd93STycho Nightingale 
225bf21cd93STycho Nightingale 	return (-1);
226bf21cd93STycho Nightingale }
227bf21cd93STycho Nightingale 
228bf21cd93STycho Nightingale int
229bf21cd93STycho Nightingale ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
230bf21cd93STycho Nightingale {
231bf21cd93STycho Nightingale 	int retval;
232bf21cd93STycho Nightingale 
233bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
234bf21cd93STycho Nightingale 	retval = fifo_get(sc, val);
235bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
236bf21cd93STycho Nightingale 
237bf21cd93STycho Nightingale 	return (retval);
238bf21cd93STycho Nightingale }
239bf21cd93STycho Nightingale 
240bf21cd93STycho Nightingale void
241bf21cd93STycho Nightingale ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
242bf21cd93STycho Nightingale {
243bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
244bf21cd93STycho Nightingale 	if (sc->curcmd) {
245bf21cd93STycho Nightingale 		switch (sc->curcmd) {
246bf21cd93STycho Nightingale 		case PS2KC_SET_TYPEMATIC:
247bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
248bf21cd93STycho Nightingale 			break;
249bf21cd93STycho Nightingale 		case PS2KC_SET_SCANCODE_SET:
250bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
251bf21cd93STycho Nightingale 			break;
252bf21cd93STycho Nightingale 		case PS2KC_SET_LEDS:
253bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
254bf21cd93STycho Nightingale 			break;
255bf21cd93STycho Nightingale 		default:
256bf21cd93STycho Nightingale 			fprintf(stderr, "Unhandled ps2 keyboard current "
257bf21cd93STycho Nightingale 			    "command byte 0x%02x\n", val);
258bf21cd93STycho Nightingale 			break;
259bf21cd93STycho Nightingale 		}
260bf21cd93STycho Nightingale 		sc->curcmd = 0;
261bf21cd93STycho Nightingale 	} else {
262bf21cd93STycho Nightingale 		switch (val) {
263*4c87aefeSPatrick Mooney 		case 0x00:
264*4c87aefeSPatrick Mooney 			fifo_put(sc, PS2KC_ACK);
265*4c87aefeSPatrick Mooney 			break;
266bf21cd93STycho Nightingale 		case PS2KC_RESET_DEV:
267bf21cd93STycho Nightingale 			fifo_reset(sc);
268bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
269bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_BAT_SUCCESS);
270bf21cd93STycho Nightingale 			break;
271bf21cd93STycho Nightingale 		case PS2KC_DISABLE:
272bf21cd93STycho Nightingale 			sc->enabled = false;
273bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
274bf21cd93STycho Nightingale 			break;
275bf21cd93STycho Nightingale 		case PS2KC_ENABLE:
276bf21cd93STycho Nightingale 			sc->enabled = true;
277bf21cd93STycho Nightingale 			fifo_reset(sc);
278bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
279bf21cd93STycho Nightingale 			break;
280bf21cd93STycho Nightingale 		case PS2KC_SET_TYPEMATIC:
281bf21cd93STycho Nightingale 			sc->curcmd = val;
282bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
283bf21cd93STycho Nightingale 			break;
284bf21cd93STycho Nightingale 		case PS2KC_SEND_DEV_ID:
285bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
286bf21cd93STycho Nightingale 			fifo_put(sc, 0xab);
287bf21cd93STycho Nightingale 			fifo_put(sc, 0x83);
288bf21cd93STycho Nightingale 			break;
289bf21cd93STycho Nightingale 		case PS2KC_SET_SCANCODE_SET:
290bf21cd93STycho Nightingale 			sc->curcmd = val;
291bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
292bf21cd93STycho Nightingale 			break;
293bf21cd93STycho Nightingale 		case PS2KC_ECHO:
294bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ECHO);
295bf21cd93STycho Nightingale 			break;
296bf21cd93STycho Nightingale 		case PS2KC_SET_LEDS:
297bf21cd93STycho Nightingale 			sc->curcmd = val;
298bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
299bf21cd93STycho Nightingale 			break;
300bf21cd93STycho Nightingale 		default:
301bf21cd93STycho Nightingale 			fprintf(stderr, "Unhandled ps2 keyboard command "
302bf21cd93STycho Nightingale 			    "0x%02x\n", val);
303bf21cd93STycho Nightingale 			break;
304bf21cd93STycho Nightingale 		}
305bf21cd93STycho Nightingale 	}
306bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
307bf21cd93STycho Nightingale }
308bf21cd93STycho Nightingale 
309bf21cd93STycho Nightingale /*
310bf21cd93STycho Nightingale  * Translate keysym to type 2 scancode and insert into keyboard buffer.
311bf21cd93STycho Nightingale  */
312bf21cd93STycho Nightingale static void
313bf21cd93STycho Nightingale ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
314bf21cd93STycho Nightingale     int down, uint32_t keysym)
315bf21cd93STycho Nightingale {
316bf21cd93STycho Nightingale 	assert(pthread_mutex_isowned_np(&sc->mtx));
317*4c87aefeSPatrick Mooney 	int e0_prefix, found;
318*4c87aefeSPatrick Mooney 	uint8_t code;
319*4c87aefeSPatrick Mooney 	const struct extended_translation *trans;
320*4c87aefeSPatrick Mooney 
321*4c87aefeSPatrick Mooney 	found = 0;
322*4c87aefeSPatrick Mooney 	if (keysym < 0x80) {
323*4c87aefeSPatrick Mooney 		code = ascii_translations[keysym];
324*4c87aefeSPatrick Mooney 		e0_prefix = 0;
325*4c87aefeSPatrick Mooney 		found = 1;
326*4c87aefeSPatrick Mooney 	} else {
327*4c87aefeSPatrick Mooney 		for (trans = &(extended_translations[0]); trans->keysym != 0;
328*4c87aefeSPatrick Mooney 		    trans++) {
329*4c87aefeSPatrick Mooney 			if (keysym == trans->keysym) {
330*4c87aefeSPatrick Mooney 				code = trans->scancode;
331*4c87aefeSPatrick Mooney 				e0_prefix = trans->flags & SCANCODE_E0_PREFIX;
332*4c87aefeSPatrick Mooney 				found = 1;
333*4c87aefeSPatrick Mooney 				break;
334*4c87aefeSPatrick Mooney 			}
335*4c87aefeSPatrick Mooney 		}
336*4c87aefeSPatrick Mooney 	}
337bf21cd93STycho Nightingale 
338*4c87aefeSPatrick Mooney 	if (!found) {
339*4c87aefeSPatrick Mooney 		fprintf(stderr, "Unhandled ps2 keyboard keysym 0x%x\n", keysym);
340*4c87aefeSPatrick Mooney 		return;
341bf21cd93STycho Nightingale 	}
342*4c87aefeSPatrick Mooney 
343*4c87aefeSPatrick Mooney 	if (e0_prefix)
344*4c87aefeSPatrick Mooney 		fifo_put(sc, 0xe0);
345*4c87aefeSPatrick Mooney 	if (!down)
346*4c87aefeSPatrick Mooney 		fifo_put(sc, 0xf0);
347*4c87aefeSPatrick Mooney 	fifo_put(sc, code);
348bf21cd93STycho Nightingale }
349bf21cd93STycho Nightingale 
350bf21cd93STycho Nightingale static void
351bf21cd93STycho Nightingale ps2kbd_event(int down, uint32_t keysym, void *arg)
352bf21cd93STycho Nightingale {
353bf21cd93STycho Nightingale 	struct ps2kbd_softc *sc = arg;
354*4c87aefeSPatrick Mooney 	int fifo_full;
355bf21cd93STycho Nightingale 
356bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
357bf21cd93STycho Nightingale 	if (!sc->enabled) {
358bf21cd93STycho Nightingale 		pthread_mutex_unlock(&sc->mtx);
359bf21cd93STycho Nightingale 		return;
360bf21cd93STycho Nightingale 	}
361*4c87aefeSPatrick Mooney 	fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
362bf21cd93STycho Nightingale 	ps2kbd_keysym_queue(sc, down, keysym);
363bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
364bf21cd93STycho Nightingale 
365*4c87aefeSPatrick Mooney 	if (!fifo_full)
366*4c87aefeSPatrick Mooney 		atkbdc_event(sc->atkbdc_sc, 1);
367bf21cd93STycho Nightingale }
368bf21cd93STycho Nightingale 
369bf21cd93STycho Nightingale struct ps2kbd_softc *
370bf21cd93STycho Nightingale ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
371bf21cd93STycho Nightingale {
372bf21cd93STycho Nightingale 	struct ps2kbd_softc *sc;
373bf21cd93STycho Nightingale 
374bf21cd93STycho Nightingale 	sc = calloc(1, sizeof (struct ps2kbd_softc));
375bf21cd93STycho Nightingale 	pthread_mutex_init(&sc->mtx, NULL);
376bf21cd93STycho Nightingale 	fifo_init(sc);
377bf21cd93STycho Nightingale 	sc->atkbdc_sc = atkbdc_sc;
378bf21cd93STycho Nightingale 
379*4c87aefeSPatrick Mooney 	console_kbd_register(ps2kbd_event, sc, 1);
380bf21cd93STycho Nightingale 
381bf21cd93STycho Nightingale 	return (sc);
382bf21cd93STycho Nightingale }
383*4c87aefeSPatrick Mooney 
384