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