1300829Sgrehan/*-
2336189Saraujo * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3336189Saraujo *
4300829Sgrehan * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
5300829Sgrehan * Copyright (c) 2015 Nahanni Systems Inc.
6300829Sgrehan * All rights reserved.
7300829Sgrehan *
8300829Sgrehan * Redistribution and use in source and binary forms, with or without
9300829Sgrehan * modification, are permitted provided that the following conditions
10300829Sgrehan * are met:
11300829Sgrehan * 1. Redistributions of source code must retain the above copyright
12300829Sgrehan *    notice, this list of conditions and the following disclaimer.
13300829Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
14300829Sgrehan *    notice, this list of conditions and the following disclaimer in the
15300829Sgrehan *    documentation and/or other materials provided with the distribution.
16300829Sgrehan *
17300829Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
18300829Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19300829Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20300829Sgrehan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21300829Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22300829Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23300829Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24300829Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25300829Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26300829Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27300829Sgrehan * SUCH DAMAGE.
28300829Sgrehan */
29300829Sgrehan
30300829Sgrehan#include <sys/cdefs.h>
31300829Sgrehan__FBSDID("$FreeBSD: stable/11/usr.sbin/bhyve/ps2kbd.c 341758 2018-12-09 06:42:06Z araujo $");
32300829Sgrehan
33300829Sgrehan#include <sys/types.h>
34300829Sgrehan
35300829Sgrehan#include <assert.h>
36300829Sgrehan#include <stdbool.h>
37300829Sgrehan#include <stdio.h>
38300829Sgrehan#include <stdlib.h>
39300829Sgrehan#include <strings.h>
40300829Sgrehan#include <pthread.h>
41300829Sgrehan#include <pthread_np.h>
42300829Sgrehan
43300829Sgrehan#include "atkbdc.h"
44300829Sgrehan#include "console.h"
45300829Sgrehan
46300829Sgrehan/* keyboard device commands */
47300829Sgrehan#define	PS2KC_RESET_DEV		0xff
48300829Sgrehan#define	PS2KC_DISABLE		0xf5
49300829Sgrehan#define	PS2KC_ENABLE		0xf4
50300829Sgrehan#define	PS2KC_SET_TYPEMATIC	0xf3
51300829Sgrehan#define	PS2KC_SEND_DEV_ID	0xf2
52300829Sgrehan#define	PS2KC_SET_SCANCODE_SET	0xf0
53300829Sgrehan#define	PS2KC_ECHO		0xee
54300829Sgrehan#define	PS2KC_SET_LEDS		0xed
55300829Sgrehan
56300829Sgrehan#define	PS2KC_BAT_SUCCESS	0xaa
57300829Sgrehan#define	PS2KC_ACK		0xfa
58300829Sgrehan
59300829Sgrehan#define	PS2KBD_FIFOSZ		16
60300829Sgrehan
61300829Sgrehanstruct fifo {
62300829Sgrehan	uint8_t	buf[PS2KBD_FIFOSZ];
63300829Sgrehan	int	rindex;		/* index to read from */
64300829Sgrehan	int	windex;		/* index to write to */
65300829Sgrehan	int	num;		/* number of bytes in the fifo */
66300829Sgrehan	int	size;		/* size of the fifo */
67300829Sgrehan};
68300829Sgrehan
69300829Sgrehanstruct ps2kbd_softc {
70300829Sgrehan	struct atkbdc_softc	*atkbdc_sc;
71300829Sgrehan	pthread_mutex_t		mtx;
72300829Sgrehan
73300829Sgrehan	bool			enabled;
74300829Sgrehan	struct fifo		fifo;
75300829Sgrehan
76300829Sgrehan	uint8_t			curcmd;	/* current command for next byte */
77300829Sgrehan};
78300829Sgrehan
79341758Saraujo#define SCANCODE_E0_PREFIX 1
80341758Saraujostruct extended_translation {
81341758Saraujo	uint32_t keysym;
82341758Saraujo	uint8_t scancode;
83341758Saraujo	int flags;
84341758Saraujo};
85341758Saraujo
86341758Saraujo/*
87341758Saraujo * FIXME: Pause/break and Print Screen/SysRq require special handling.
88341758Saraujo */
89341758Saraujostatic const struct extended_translation extended_translations[] = {
90341758Saraujo		{0xff08, 0x66},		/* Back space */
91341758Saraujo		{0xff09, 0x0d},		/* Tab */
92341758Saraujo		{0xff0d, 0x5a},		/* Return */
93341758Saraujo		{0xff1b, 0x76},		/* Escape */
94341758Saraujo		{0xff50, 0x6c, SCANCODE_E0_PREFIX}, 	/* Home */
95341758Saraujo		{0xff51, 0x6b, SCANCODE_E0_PREFIX}, 	/* Left arrow */
96341758Saraujo		{0xff52, 0x75, SCANCODE_E0_PREFIX}, 	/* Up arrow */
97341758Saraujo		{0xff53, 0x74, SCANCODE_E0_PREFIX}, 	/* Right arrow */
98341758Saraujo		{0xff54, 0x72, SCANCODE_E0_PREFIX}, 	/* Down arrow */
99341758Saraujo		{0xff55, 0x7d, SCANCODE_E0_PREFIX}, 	/* PgUp */
100341758Saraujo		{0xff56, 0x7a, SCANCODE_E0_PREFIX}, 	/* PgDown */
101341758Saraujo		{0xff57, 0x69, SCANCODE_E0_PREFIX}, 	/* End */
102341758Saraujo		{0xff63, 0x70, SCANCODE_E0_PREFIX}, 	/* Ins */
103341758Saraujo		{0xff8d, 0x5a, SCANCODE_E0_PREFIX}, 	/* Keypad Enter */
104341758Saraujo		{0xffe1, 0x12},		/* Left shift */
105341758Saraujo		{0xffe2, 0x59},		/* Right shift */
106341758Saraujo		{0xffe3, 0x14},		/* Left control */
107341758Saraujo		{0xffe4, 0x14, SCANCODE_E0_PREFIX}, 	/* Right control */
108341758Saraujo		/* {0xffe7, XXX}, Left meta */
109341758Saraujo		/* {0xffe8, XXX}, Right meta */
110341758Saraujo		{0xffe9, 0x11},		/* Left alt */
111341758Saraujo		{0xfe03, 0x11, SCANCODE_E0_PREFIX}, 	/* AltGr */
112341758Saraujo		{0xffea, 0x11, SCANCODE_E0_PREFIX}, 	/* Right alt */
113341758Saraujo		{0xffeb, 0x1f, SCANCODE_E0_PREFIX}, 	/* Left Windows */
114341758Saraujo		{0xffec, 0x27, SCANCODE_E0_PREFIX}, 	/* Right Windows */
115341758Saraujo		{0xffbe, 0x05},		/* F1 */
116341758Saraujo		{0xffbf, 0x06},		/* F2 */
117341758Saraujo		{0xffc0, 0x04},		/* F3 */
118341758Saraujo		{0xffc1, 0x0c},		/* F4 */
119341758Saraujo		{0xffc2, 0x03},		/* F5 */
120341758Saraujo		{0xffc3, 0x0b},		/* F6 */
121341758Saraujo		{0xffc4, 0x83},		/* F7 */
122341758Saraujo		{0xffc5, 0x0a},		/* F8 */
123341758Saraujo		{0xffc6, 0x01},		/* F9 */
124341758Saraujo		{0xffc7, 0x09},		/* F10 */
125341758Saraujo		{0xffc8, 0x78},		/* F11 */
126341758Saraujo		{0xffc9, 0x07},		/* F12 */
127341758Saraujo		{0xffff, 0x71, SCANCODE_E0_PREFIX},	/* Del */
128341758Saraujo		{0xff14, 0x7e},		/* ScrollLock */
129341758Saraujo		/* NumLock and Keypads*/
130341758Saraujo		{0xff7f, 0x77}, 	/* NumLock */
131341758Saraujo		{0xffaf, 0x4a, SCANCODE_E0_PREFIX}, 	/* Keypad slash */
132341758Saraujo		{0xffaa, 0x7c}, 	/* Keypad asterisk */
133341758Saraujo		{0xffad, 0x7b}, 	/* Keypad minus */
134341758Saraujo		{0xffab, 0x79}, 	/* Keypad plus */
135341758Saraujo		{0xffb7, 0x6c}, 	/* Keypad 7 */
136341758Saraujo		{0xff95, 0x6c}, 	/* Keypad home */
137341758Saraujo		{0xffb8, 0x75}, 	/* Keypad 8 */
138341758Saraujo		{0xff97, 0x75}, 	/* Keypad up arrow */
139341758Saraujo		{0xffb9, 0x7d}, 	/* Keypad 9 */
140341758Saraujo		{0xff9a, 0x7d}, 	/* Keypad PgUp */
141341758Saraujo		{0xffb4, 0x6b}, 	/* Keypad 4 */
142341758Saraujo		{0xff96, 0x6b}, 	/* Keypad left arrow */
143341758Saraujo		{0xffb5, 0x73}, 	/* Keypad 5 */
144341758Saraujo		{0xff9d, 0x73}, 	/* Keypad empty */
145341758Saraujo		{0xffb6, 0x74}, 	/* Keypad 6 */
146341758Saraujo		{0xff98, 0x74}, 	/* Keypad right arrow */
147341758Saraujo		{0xffb1, 0x69}, 	/* Keypad 1 */
148341758Saraujo		{0xff9c, 0x69}, 	/* Keypad end */
149341758Saraujo		{0xffb2, 0x72}, 	/* Keypad 2 */
150341758Saraujo		{0xff99, 0x72}, 	/* Keypad down arrow */
151341758Saraujo		{0xffb3, 0x7a}, 	/* Keypad 3 */
152341758Saraujo		{0xff9b, 0x7a}, 	/* Keypad PgDown */
153341758Saraujo		{0xffb0, 0x70}, 	/* Keypad 0 */
154341758Saraujo		{0xff9e, 0x70}, 	/* Keypad ins */
155341758Saraujo		{0xffae, 0x71}, 	/* Keypad . */
156341758Saraujo		{0xff9f, 0x71}, 	/* Keypad del */
157341758Saraujo		{0, 0, 0} 		/* Terminator */
158341758Saraujo};
159341758Saraujo
160341758Saraujo/* ASCII to type 2 scancode lookup table */
161341758Saraujostatic const uint8_t ascii_translations[128] = {
162341758Saraujo		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
163341758Saraujo		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164341758Saraujo		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165341758Saraujo		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
166341758Saraujo		0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52,
167341758Saraujo		0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a,
168341758Saraujo		0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d,
169341758Saraujo		0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a,
170341758Saraujo		0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
171341758Saraujo		0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
172341758Saraujo		0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
173341758Saraujo		0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e,
174341758Saraujo		0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
175341758Saraujo		0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
176341758Saraujo		0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
177341758Saraujo		0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00,
178341758Saraujo};
179341758Saraujo
180300829Sgrehanstatic void
181300829Sgrehanfifo_init(struct ps2kbd_softc *sc)
182300829Sgrehan{
183300829Sgrehan	struct fifo *fifo;
184300829Sgrehan
185300829Sgrehan	fifo = &sc->fifo;
186300829Sgrehan	fifo->size = sizeof(((struct fifo *)0)->buf);
187300829Sgrehan}
188300829Sgrehan
189300829Sgrehanstatic void
190300829Sgrehanfifo_reset(struct ps2kbd_softc *sc)
191300829Sgrehan{
192300829Sgrehan	struct fifo *fifo;
193300829Sgrehan
194300829Sgrehan	fifo = &sc->fifo;
195300829Sgrehan	bzero(fifo, sizeof(struct fifo));
196300829Sgrehan	fifo->size = sizeof(((struct fifo *)0)->buf);
197300829Sgrehan}
198300829Sgrehan
199300829Sgrehanstatic void
200300829Sgrehanfifo_put(struct ps2kbd_softc *sc, uint8_t val)
201300829Sgrehan{
202300829Sgrehan	struct fifo *fifo;
203300829Sgrehan
204300829Sgrehan	fifo = &sc->fifo;
205300829Sgrehan	if (fifo->num < fifo->size) {
206300829Sgrehan		fifo->buf[fifo->windex] = val;
207300829Sgrehan		fifo->windex = (fifo->windex + 1) % fifo->size;
208300829Sgrehan		fifo->num++;
209300829Sgrehan	}
210300829Sgrehan}
211300829Sgrehan
212300829Sgrehanstatic int
213300829Sgrehanfifo_get(struct ps2kbd_softc *sc, uint8_t *val)
214300829Sgrehan{
215300829Sgrehan	struct fifo *fifo;
216300829Sgrehan
217300829Sgrehan	fifo = &sc->fifo;
218300829Sgrehan	if (fifo->num > 0) {
219300829Sgrehan		*val = fifo->buf[fifo->rindex];
220300829Sgrehan		fifo->rindex = (fifo->rindex + 1) % fifo->size;
221300829Sgrehan		fifo->num--;
222300829Sgrehan		return (0);
223300829Sgrehan	}
224300829Sgrehan
225300829Sgrehan	return (-1);
226300829Sgrehan}
227300829Sgrehan
228300829Sgrehanint
229300829Sgrehanps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
230300829Sgrehan{
231300829Sgrehan	int retval;
232300829Sgrehan
233300829Sgrehan	pthread_mutex_lock(&sc->mtx);
234300829Sgrehan	retval = fifo_get(sc, val);
235300829Sgrehan	pthread_mutex_unlock(&sc->mtx);
236300829Sgrehan
237300829Sgrehan	return (retval);
238300829Sgrehan}
239300829Sgrehan
240300829Sgrehanvoid
241300829Sgrehanps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
242300829Sgrehan{
243300829Sgrehan	pthread_mutex_lock(&sc->mtx);
244300829Sgrehan	if (sc->curcmd) {
245300829Sgrehan		switch (sc->curcmd) {
246300829Sgrehan		case PS2KC_SET_TYPEMATIC:
247300829Sgrehan			fifo_put(sc, PS2KC_ACK);
248300829Sgrehan			break;
249300829Sgrehan		case PS2KC_SET_SCANCODE_SET:
250300829Sgrehan			fifo_put(sc, PS2KC_ACK);
251300829Sgrehan			break;
252300829Sgrehan		case PS2KC_SET_LEDS:
253300829Sgrehan			fifo_put(sc, PS2KC_ACK);
254300829Sgrehan			break;
255300829Sgrehan		default:
256300829Sgrehan			fprintf(stderr, "Unhandled ps2 keyboard current "
257300829Sgrehan			    "command byte 0x%02x\n", val);
258300829Sgrehan			break;
259300829Sgrehan		}
260300829Sgrehan		sc->curcmd = 0;
261300829Sgrehan	} else {
262300829Sgrehan		switch (val) {
263300829Sgrehan		case 0x00:
264300829Sgrehan			fifo_put(sc, PS2KC_ACK);
265300829Sgrehan			break;
266300829Sgrehan		case PS2KC_RESET_DEV:
267300829Sgrehan			fifo_reset(sc);
268300829Sgrehan			fifo_put(sc, PS2KC_ACK);
269300829Sgrehan			fifo_put(sc, PS2KC_BAT_SUCCESS);
270300829Sgrehan			break;
271300829Sgrehan		case PS2KC_DISABLE:
272300829Sgrehan			sc->enabled = false;
273300829Sgrehan			fifo_put(sc, PS2KC_ACK);
274300829Sgrehan			break;
275300829Sgrehan		case PS2KC_ENABLE:
276300829Sgrehan			sc->enabled = true;
277300829Sgrehan			fifo_reset(sc);
278300829Sgrehan			fifo_put(sc, PS2KC_ACK);
279300829Sgrehan			break;
280300829Sgrehan		case PS2KC_SET_TYPEMATIC:
281300829Sgrehan			sc->curcmd = val;
282300829Sgrehan			fifo_put(sc, PS2KC_ACK);
283300829Sgrehan			break;
284300829Sgrehan		case PS2KC_SEND_DEV_ID:
285300829Sgrehan			fifo_put(sc, PS2KC_ACK);
286300829Sgrehan			fifo_put(sc, 0xab);
287300829Sgrehan			fifo_put(sc, 0x83);
288300829Sgrehan			break;
289300829Sgrehan		case PS2KC_SET_SCANCODE_SET:
290300829Sgrehan			sc->curcmd = val;
291300829Sgrehan			fifo_put(sc, PS2KC_ACK);
292300829Sgrehan			break;
293300829Sgrehan		case PS2KC_ECHO:
294300829Sgrehan			fifo_put(sc, PS2KC_ECHO);
295300829Sgrehan			break;
296300829Sgrehan		case PS2KC_SET_LEDS:
297300829Sgrehan			sc->curcmd = val;
298300829Sgrehan			fifo_put(sc, PS2KC_ACK);
299300829Sgrehan			break;
300300829Sgrehan		default:
301300829Sgrehan			fprintf(stderr, "Unhandled ps2 keyboard command "
302300829Sgrehan			    "0x%02x\n", val);
303300829Sgrehan			break;
304300829Sgrehan		}
305300829Sgrehan	}
306300829Sgrehan	pthread_mutex_unlock(&sc->mtx);
307300829Sgrehan}
308300829Sgrehan
309300829Sgrehan/*
310300829Sgrehan * Translate keysym to type 2 scancode and insert into keyboard buffer.
311300829Sgrehan */
312300829Sgrehanstatic void
313300829Sgrehanps2kbd_keysym_queue(struct ps2kbd_softc *sc,
314300829Sgrehan    int down, uint32_t keysym)
315300829Sgrehan{
316300829Sgrehan	assert(pthread_mutex_isowned_np(&sc->mtx));
317341758Saraujo	int e0_prefix, found;
318341758Saraujo	uint8_t code;
319341758Saraujo	const struct extended_translation *trans;
320300829Sgrehan
321341758Saraujo	found = 0;
322341758Saraujo	if (keysym < 0x80) {
323341758Saraujo		code = ascii_translations[keysym];
324341758Saraujo		e0_prefix = 0;
325341758Saraujo		found = 1;
326341758Saraujo	} else {
327341758Saraujo		for (trans = &(extended_translations[0]); trans->keysym != 0;
328341758Saraujo		    trans++) {
329341758Saraujo			if (keysym == trans->keysym) {
330341758Saraujo				code = trans->scancode;
331341758Saraujo				e0_prefix = trans->flags & SCANCODE_E0_PREFIX;
332341758Saraujo				found = 1;
333341758Saraujo				break;
334341758Saraujo			}
335341758Saraujo		}
336341758Saraujo	}
337341758Saraujo
338341758Saraujo	if (!found) {
339341758Saraujo		fprintf(stderr, "Unhandled ps2 keyboard keysym 0x%x\n", keysym);
340341758Saraujo		return;
341341758Saraujo	}
342341758Saraujo
343341758Saraujo	if (e0_prefix)
344300829Sgrehan		fifo_put(sc, 0xe0);
345341758Saraujo	if (!down)
346341758Saraujo		fifo_put(sc, 0xf0);
347341758Saraujo	fifo_put(sc, code);
348300829Sgrehan}
349300829Sgrehan
350300829Sgrehanstatic void
351300829Sgrehanps2kbd_event(int down, uint32_t keysym, void *arg)
352300829Sgrehan{
353300829Sgrehan	struct ps2kbd_softc *sc = arg;
354300829Sgrehan	int fifo_full;
355300829Sgrehan
356300829Sgrehan	pthread_mutex_lock(&sc->mtx);
357300829Sgrehan	if (!sc->enabled) {
358300829Sgrehan		pthread_mutex_unlock(&sc->mtx);
359300829Sgrehan		return;
360300829Sgrehan	}
361300829Sgrehan	fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
362300829Sgrehan	ps2kbd_keysym_queue(sc, down, keysym);
363300829Sgrehan	pthread_mutex_unlock(&sc->mtx);
364300829Sgrehan
365300829Sgrehan	if (!fifo_full)
366300829Sgrehan		atkbdc_event(sc->atkbdc_sc, 1);
367300829Sgrehan}
368300829Sgrehan
369300829Sgrehanstruct ps2kbd_softc *
370300829Sgrehanps2kbd_init(struct atkbdc_softc *atkbdc_sc)
371300829Sgrehan{
372300829Sgrehan	struct ps2kbd_softc *sc;
373300829Sgrehan
374300829Sgrehan	sc = calloc(1, sizeof (struct ps2kbd_softc));
375300829Sgrehan	pthread_mutex_init(&sc->mtx, NULL);
376300829Sgrehan	fifo_init(sc);
377300829Sgrehan	sc->atkbdc_sc = atkbdc_sc;
378300829Sgrehan
379300829Sgrehan	console_kbd_register(ps2kbd_event, sc, 1);
380300829Sgrehan
381300829Sgrehan	return (sc);
382300829Sgrehan}
383300829Sgrehan
384