xref: /illumos-gate/usr/src/cmd/bhyve/ps2kbd.c (revision 32640292)
1bf21cd93STycho Nightingale /*-
2*32640292SAndy Fiddaman  * SPDX-License-Identifier: BSD-2-Clause
34c87aefeSPatrick 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 
32bf21cd93STycho Nightingale #include <sys/types.h>
33d7b72f7bSAndy Fiddaman #include <sys/stat.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>
42d7b72f7bSAndy Fiddaman #include <unistd.h>
43d7b72f7bSAndy Fiddaman #include <fcntl.h>
44bf21cd93STycho Nightingale 
45bf21cd93STycho Nightingale #include "atkbdc.h"
4659d65d31SAndy Fiddaman #include "bhyverun.h"
47d7b72f7bSAndy Fiddaman #include "config.h"
48bf21cd93STycho Nightingale #include "console.h"
4959d65d31SAndy Fiddaman #include "debug.h"
5059d65d31SAndy Fiddaman #include "ps2kbd.h"
51bf21cd93STycho Nightingale 
52bf21cd93STycho Nightingale /* keyboard device commands */
53bf21cd93STycho Nightingale #define	PS2KC_RESET_DEV		0xff
54bf21cd93STycho Nightingale #define	PS2KC_DISABLE		0xf5
55bf21cd93STycho Nightingale #define	PS2KC_ENABLE		0xf4
56bf21cd93STycho Nightingale #define	PS2KC_SET_TYPEMATIC	0xf3
57bf21cd93STycho Nightingale #define	PS2KC_SEND_DEV_ID	0xf2
58bf21cd93STycho Nightingale #define	PS2KC_SET_SCANCODE_SET	0xf0
59bf21cd93STycho Nightingale #define	PS2KC_ECHO		0xee
60bf21cd93STycho Nightingale #define	PS2KC_SET_LEDS		0xed
61bf21cd93STycho Nightingale 
62bf21cd93STycho Nightingale #define	PS2KC_BAT_SUCCESS	0xaa
63bf21cd93STycho Nightingale #define	PS2KC_ACK		0xfa
64bf21cd93STycho Nightingale 
65bf21cd93STycho Nightingale #define	PS2KBD_FIFOSZ		16
66bf21cd93STycho Nightingale 
67d7b72f7bSAndy Fiddaman #define	PS2KBD_LAYOUT_BASEDIR	"/usr/share/bhyve/kbdlayout/"
68d7b72f7bSAndy Fiddaman 
69d7b72f7bSAndy Fiddaman #define	MAX_PATHNAME		256
70d7b72f7bSAndy Fiddaman 
71bf21cd93STycho Nightingale struct fifo {
72bf21cd93STycho Nightingale 	uint8_t	buf[PS2KBD_FIFOSZ];
73bf21cd93STycho Nightingale 	int	rindex;		/* index to read from */
74bf21cd93STycho Nightingale 	int	windex;		/* index to write to */
75bf21cd93STycho Nightingale 	int	num;		/* number of bytes in the fifo */
76bf21cd93STycho Nightingale 	int	size;		/* size of the fifo */
77bf21cd93STycho Nightingale };
78bf21cd93STycho Nightingale 
79bf21cd93STycho Nightingale struct ps2kbd_softc {
80bf21cd93STycho Nightingale 	struct atkbdc_softc	*atkbdc_sc;
81bf21cd93STycho Nightingale 	pthread_mutex_t		mtx;
82bf21cd93STycho Nightingale 
83bf21cd93STycho Nightingale 	bool			enabled;
84bf21cd93STycho Nightingale 	struct fifo		fifo;
85bf21cd93STycho Nightingale 
86bf21cd93STycho Nightingale 	uint8_t			curcmd;	/* current command for next byte */
87bf21cd93STycho Nightingale };
88bf21cd93STycho Nightingale 
894c87aefeSPatrick Mooney #define SCANCODE_E0_PREFIX 1
904c87aefeSPatrick Mooney struct extended_translation {
914c87aefeSPatrick Mooney 	uint32_t keysym;
924c87aefeSPatrick Mooney 	uint8_t scancode;
934c87aefeSPatrick Mooney 	int flags;
944c87aefeSPatrick Mooney };
954c87aefeSPatrick Mooney 
964c87aefeSPatrick Mooney /*
974c87aefeSPatrick Mooney  * FIXME: Pause/break and Print Screen/SysRq require special handling.
984c87aefeSPatrick Mooney  */
99d7b72f7bSAndy Fiddaman static struct extended_translation extended_translations[128] = {
10059d65d31SAndy Fiddaman 		{0xff08, 0x66, 0},		/* Back space */
10159d65d31SAndy Fiddaman 		{0xff09, 0x0d, 0},		/* Tab */
10259d65d31SAndy Fiddaman 		{0xff0d, 0x5a, 0},		/* Return */
10359d65d31SAndy Fiddaman 		{0xff1b, 0x76, 0},		/* Escape */
1044c87aefeSPatrick Mooney 		{0xff50, 0x6c, SCANCODE_E0_PREFIX}, 	/* Home */
1054c87aefeSPatrick Mooney 		{0xff51, 0x6b, SCANCODE_E0_PREFIX}, 	/* Left arrow */
1064c87aefeSPatrick Mooney 		{0xff52, 0x75, SCANCODE_E0_PREFIX}, 	/* Up arrow */
1074c87aefeSPatrick Mooney 		{0xff53, 0x74, SCANCODE_E0_PREFIX}, 	/* Right arrow */
1084c87aefeSPatrick Mooney 		{0xff54, 0x72, SCANCODE_E0_PREFIX}, 	/* Down arrow */
1094c87aefeSPatrick Mooney 		{0xff55, 0x7d, SCANCODE_E0_PREFIX}, 	/* PgUp */
1104c87aefeSPatrick Mooney 		{0xff56, 0x7a, SCANCODE_E0_PREFIX}, 	/* PgDown */
1114c87aefeSPatrick Mooney 		{0xff57, 0x69, SCANCODE_E0_PREFIX}, 	/* End */
1124c87aefeSPatrick Mooney 		{0xff63, 0x70, SCANCODE_E0_PREFIX}, 	/* Ins */
1134c87aefeSPatrick Mooney 		{0xff8d, 0x5a, SCANCODE_E0_PREFIX}, 	/* Keypad Enter */
11459d65d31SAndy Fiddaman 		{0xffe1, 0x12, 0},		/* Left shift */
11559d65d31SAndy Fiddaman 		{0xffe2, 0x59, 0},		/* Right shift */
11659d65d31SAndy Fiddaman 		{0xffe3, 0x14, 0},		/* Left control */
1174c87aefeSPatrick Mooney 		{0xffe4, 0x14, SCANCODE_E0_PREFIX}, 	/* Right control */
1184c87aefeSPatrick Mooney 		/* {0xffe7, XXX}, Left meta */
1194c87aefeSPatrick Mooney 		/* {0xffe8, XXX}, Right meta */
12059d65d31SAndy Fiddaman 		{0xffe9, 0x11, 0},		/* Left alt */
1214c87aefeSPatrick Mooney 		{0xfe03, 0x11, SCANCODE_E0_PREFIX}, 	/* AltGr */
1224c87aefeSPatrick Mooney 		{0xffea, 0x11, SCANCODE_E0_PREFIX}, 	/* Right alt */
1234c87aefeSPatrick Mooney 		{0xffeb, 0x1f, SCANCODE_E0_PREFIX}, 	/* Left Windows */
1244c87aefeSPatrick Mooney 		{0xffec, 0x27, SCANCODE_E0_PREFIX}, 	/* Right Windows */
12559d65d31SAndy Fiddaman 		{0xffbe, 0x05, 0},		/* F1 */
12659d65d31SAndy Fiddaman 		{0xffbf, 0x06, 0},		/* F2 */
12759d65d31SAndy Fiddaman 		{0xffc0, 0x04, 0},		/* F3 */
12859d65d31SAndy Fiddaman 		{0xffc1, 0x0c, 0},		/* F4 */
12959d65d31SAndy Fiddaman 		{0xffc2, 0x03, 0},		/* F5 */
13059d65d31SAndy Fiddaman 		{0xffc3, 0x0b, 0},		/* F6 */
13159d65d31SAndy Fiddaman 		{0xffc4, 0x83, 0},		/* F7 */
13259d65d31SAndy Fiddaman 		{0xffc5, 0x0a, 0},		/* F8 */
13359d65d31SAndy Fiddaman 		{0xffc6, 0x01, 0},		/* F9 */
13459d65d31SAndy Fiddaman 		{0xffc7, 0x09, 0},		/* F10 */
13559d65d31SAndy Fiddaman 		{0xffc8, 0x78, 0},		/* F11 */
13659d65d31SAndy Fiddaman 		{0xffc9, 0x07, 0},		/* F12 */
1374c87aefeSPatrick Mooney 		{0xffff, 0x71, SCANCODE_E0_PREFIX},	/* Del */
13859d65d31SAndy Fiddaman 		{0xff14, 0x7e, 0},		/* ScrollLock */
1394c87aefeSPatrick Mooney 		/* NumLock and Keypads*/
14059d65d31SAndy Fiddaman 		{0xff7f, 0x77, 0}, 	/* NumLock */
1414c87aefeSPatrick Mooney 		{0xffaf, 0x4a, SCANCODE_E0_PREFIX}, 	/* Keypad slash */
14259d65d31SAndy Fiddaman 		{0xffaa, 0x7c, 0}, 	/* Keypad asterisk */
14359d65d31SAndy Fiddaman 		{0xffad, 0x7b, 0}, 	/* Keypad minus */
14459d65d31SAndy Fiddaman 		{0xffab, 0x79, 0}, 	/* Keypad plus */
14559d65d31SAndy Fiddaman 		{0xffb7, 0x6c, 0}, 	/* Keypad 7 */
14659d65d31SAndy Fiddaman 		{0xff95, 0x6c, 0}, 	/* Keypad home */
14759d65d31SAndy Fiddaman 		{0xffb8, 0x75, 0}, 	/* Keypad 8 */
14859d65d31SAndy Fiddaman 		{0xff97, 0x75, 0}, 	/* Keypad up arrow */
14959d65d31SAndy Fiddaman 		{0xffb9, 0x7d, 0}, 	/* Keypad 9 */
15059d65d31SAndy Fiddaman 		{0xff9a, 0x7d, 0}, 	/* Keypad PgUp */
15159d65d31SAndy Fiddaman 		{0xffb4, 0x6b, 0}, 	/* Keypad 4 */
15259d65d31SAndy Fiddaman 		{0xff96, 0x6b, 0}, 	/* Keypad left arrow */
15359d65d31SAndy Fiddaman 		{0xffb5, 0x73, 0}, 	/* Keypad 5 */
15459d65d31SAndy Fiddaman 		{0xff9d, 0x73, 0}, 	/* Keypad empty */
15559d65d31SAndy Fiddaman 		{0xffb6, 0x74, 0}, 	/* Keypad 6 */
15659d65d31SAndy Fiddaman 		{0xff98, 0x74, 0}, 	/* Keypad right arrow */
15759d65d31SAndy Fiddaman 		{0xffb1, 0x69, 0}, 	/* Keypad 1 */
15859d65d31SAndy Fiddaman 		{0xff9c, 0x69, 0}, 	/* Keypad end */
15959d65d31SAndy Fiddaman 		{0xffb2, 0x72, 0}, 	/* Keypad 2 */
16059d65d31SAndy Fiddaman 		{0xff99, 0x72, 0}, 	/* Keypad down arrow */
16159d65d31SAndy Fiddaman 		{0xffb3, 0x7a, 0}, 	/* Keypad 3 */
16259d65d31SAndy Fiddaman 		{0xff9b, 0x7a, 0}, 	/* Keypad PgDown */
16359d65d31SAndy Fiddaman 		{0xffb0, 0x70, 0}, 	/* Keypad 0 */
16459d65d31SAndy Fiddaman 		{0xff9e, 0x70, 0}, 	/* Keypad ins */
16559d65d31SAndy Fiddaman 		{0xffae, 0x71, 0}, 	/* Keypad . */
16659d65d31SAndy Fiddaman 		{0xff9f, 0x71, 0}, 	/* Keypad del */
1674c87aefeSPatrick Mooney 		{0, 0, 0} 		/* Terminator */
1684c87aefeSPatrick Mooney };
1694c87aefeSPatrick Mooney 
1704c87aefeSPatrick Mooney /* ASCII to type 2 scancode lookup table */
171d7b72f7bSAndy Fiddaman static uint8_t ascii_translations[128] = {
1724c87aefeSPatrick Mooney 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1734c87aefeSPatrick Mooney 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1744c87aefeSPatrick Mooney 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1754c87aefeSPatrick Mooney 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1764c87aefeSPatrick Mooney 		0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52,
1774c87aefeSPatrick Mooney 		0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a,
1784c87aefeSPatrick Mooney 		0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d,
1794c87aefeSPatrick Mooney 		0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a,
1804c87aefeSPatrick Mooney 		0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
1814c87aefeSPatrick Mooney 		0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
1824c87aefeSPatrick Mooney 		0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
1834c87aefeSPatrick Mooney 		0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e,
1844c87aefeSPatrick Mooney 		0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
1854c87aefeSPatrick Mooney 		0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
1864c87aefeSPatrick Mooney 		0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
1874c87aefeSPatrick Mooney 		0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00,
1884c87aefeSPatrick Mooney };
1894c87aefeSPatrick Mooney 
190b0de25cbSAndy Fiddaman /* ScanCode set1 to set2 lookup table */
19159d65d31SAndy Fiddaman static const uint8_t keyset1to2_translations[128] = {
192b0de25cbSAndy Fiddaman 		   0, 0x76, 0x16, 0x1E, 0x26, 0x25, 0x2e, 0x36,
193b0de25cbSAndy Fiddaman 		0x3d, 0x3e, 0x46, 0x45, 0x4e, 0x55, 0x66, 0x0d,
194b0de25cbSAndy Fiddaman 		0x15, 0x1d, 0x24, 0x2d, 0x2c, 0x35, 0x3c, 0x43,
195b0de25cbSAndy Fiddaman 		0x44, 0x4d, 0x54, 0x5b, 0x5a, 0x14, 0x1c, 0x1b,
196b0de25cbSAndy Fiddaman 		0x23, 0x2b, 0x34, 0x33, 0x3b, 0x42, 0x4b, 0x4c,
197b0de25cbSAndy Fiddaman 		0x52, 0x0e, 0x12, 0x5d, 0x1a, 0x22, 0x21, 0x2a,
198b0de25cbSAndy Fiddaman 		0x32, 0x31, 0x3a, 0x41, 0x49, 0x4a, 0x59, 0x7c,
199b0de25cbSAndy Fiddaman 		0x11, 0x29, 0x58, 0x05, 0x06, 0x04, 0x0c, 0x03,
200b0de25cbSAndy Fiddaman 		0x0b, 0x83, 0x0a, 0x01, 0x09, 0x77, 0x7e, 0x6c,
201b0de25cbSAndy Fiddaman 		0x75, 0x7d, 0x7b, 0x6b, 0x73, 0x74, 0x79, 0x69,
202b0de25cbSAndy Fiddaman 		0x72, 0x7a, 0x70, 0x71, 0x84, 0x60, 0x61, 0x78,
203b0de25cbSAndy Fiddaman 		0x07, 0x0f, 0x17, 0x1f, 0x27, 0x2f, 0x37, 0x3f,
204b0de25cbSAndy Fiddaman 		0x47, 0x4f, 0x56, 0x5e, 0x08, 0x10, 0x18, 0x20,
205b0de25cbSAndy Fiddaman 		0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x57, 0x6f,
206b0de25cbSAndy Fiddaman 		0x13, 0x19, 0x39, 0x51, 0x53, 0x5c, 0x5f, 0x62,
207b0de25cbSAndy Fiddaman 		0x63, 0x64, 0x65, 0x67, 0x68, 0x6a, 0x6d, 0x6e,
208b0de25cbSAndy Fiddaman };
209b0de25cbSAndy Fiddaman 
210bf21cd93STycho Nightingale static void
fifo_init(struct ps2kbd_softc * sc)211bf21cd93STycho Nightingale fifo_init(struct ps2kbd_softc *sc)
212bf21cd93STycho Nightingale {
213bf21cd93STycho Nightingale 	struct fifo *fifo;
214bf21cd93STycho Nightingale 
215bf21cd93STycho Nightingale 	fifo = &sc->fifo;
216bf21cd93STycho Nightingale 	fifo->size = sizeof(((struct fifo *)0)->buf);
217bf21cd93STycho Nightingale }
218bf21cd93STycho Nightingale 
219bf21cd93STycho Nightingale static void
fifo_reset(struct ps2kbd_softc * sc)220bf21cd93STycho Nightingale fifo_reset(struct ps2kbd_softc *sc)
221bf21cd93STycho Nightingale {
222bf21cd93STycho Nightingale 	struct fifo *fifo;
223bf21cd93STycho Nightingale 
224bf21cd93STycho Nightingale 	fifo = &sc->fifo;
225bf21cd93STycho Nightingale 	bzero(fifo, sizeof(struct fifo));
226bf21cd93STycho Nightingale 	fifo->size = sizeof(((struct fifo *)0)->buf);
227bf21cd93STycho Nightingale }
228bf21cd93STycho Nightingale 
229bf21cd93STycho Nightingale static void
fifo_put(struct ps2kbd_softc * sc,uint8_t val)230bf21cd93STycho Nightingale fifo_put(struct ps2kbd_softc *sc, uint8_t val)
231bf21cd93STycho Nightingale {
232bf21cd93STycho Nightingale 	struct fifo *fifo;
233bf21cd93STycho Nightingale 
234bf21cd93STycho Nightingale 	fifo = &sc->fifo;
235bf21cd93STycho Nightingale 	if (fifo->num < fifo->size) {
236bf21cd93STycho Nightingale 		fifo->buf[fifo->windex] = val;
237bf21cd93STycho Nightingale 		fifo->windex = (fifo->windex + 1) % fifo->size;
238bf21cd93STycho Nightingale 		fifo->num++;
239bf21cd93STycho Nightingale 	}
240bf21cd93STycho Nightingale }
241bf21cd93STycho Nightingale 
242bf21cd93STycho Nightingale static int
fifo_get(struct ps2kbd_softc * sc,uint8_t * val)243bf21cd93STycho Nightingale fifo_get(struct ps2kbd_softc *sc, uint8_t *val)
244bf21cd93STycho Nightingale {
245bf21cd93STycho Nightingale 	struct fifo *fifo;
246bf21cd93STycho Nightingale 
247bf21cd93STycho Nightingale 	fifo = &sc->fifo;
248bf21cd93STycho Nightingale 	if (fifo->num > 0) {
249bf21cd93STycho Nightingale 		*val = fifo->buf[fifo->rindex];
250bf21cd93STycho Nightingale 		fifo->rindex = (fifo->rindex + 1) % fifo->size;
251bf21cd93STycho Nightingale 		fifo->num--;
252bf21cd93STycho Nightingale 		return (0);
253bf21cd93STycho Nightingale 	}
254bf21cd93STycho Nightingale 
255bf21cd93STycho Nightingale 	return (-1);
256bf21cd93STycho Nightingale }
257bf21cd93STycho Nightingale 
258bf21cd93STycho Nightingale int
ps2kbd_read(struct ps2kbd_softc * sc,uint8_t * val)259bf21cd93STycho Nightingale ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
260bf21cd93STycho Nightingale {
261bf21cd93STycho Nightingale 	int retval;
262bf21cd93STycho Nightingale 
263bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
264bf21cd93STycho Nightingale 	retval = fifo_get(sc, val);
265bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
266bf21cd93STycho Nightingale 
267bf21cd93STycho Nightingale 	return (retval);
268bf21cd93STycho Nightingale }
269bf21cd93STycho Nightingale 
270bf21cd93STycho Nightingale void
ps2kbd_write(struct ps2kbd_softc * sc,uint8_t val)271bf21cd93STycho Nightingale ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
272bf21cd93STycho Nightingale {
273bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
274bf21cd93STycho Nightingale 	if (sc->curcmd) {
275bf21cd93STycho Nightingale 		switch (sc->curcmd) {
276bf21cd93STycho Nightingale 		case PS2KC_SET_TYPEMATIC:
277bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
278bf21cd93STycho Nightingale 			break;
279bf21cd93STycho Nightingale 		case PS2KC_SET_SCANCODE_SET:
280bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
281bf21cd93STycho Nightingale 			break;
282bf21cd93STycho Nightingale 		case PS2KC_SET_LEDS:
283bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
284bf21cd93STycho Nightingale 			break;
285bf21cd93STycho Nightingale 		default:
286154972afSPatrick Mooney 			EPRINTLN("Unhandled ps2 keyboard current "
287154972afSPatrick Mooney 			    "command byte 0x%02x", val);
288bf21cd93STycho Nightingale 			break;
289bf21cd93STycho Nightingale 		}
290bf21cd93STycho Nightingale 		sc->curcmd = 0;
291bf21cd93STycho Nightingale 	} else {
292bf21cd93STycho Nightingale 		switch (val) {
2934c87aefeSPatrick Mooney 		case 0x00:
2944c87aefeSPatrick Mooney 			fifo_put(sc, PS2KC_ACK);
2954c87aefeSPatrick Mooney 			break;
296bf21cd93STycho Nightingale 		case PS2KC_RESET_DEV:
297bf21cd93STycho Nightingale 			fifo_reset(sc);
298bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
299bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_BAT_SUCCESS);
300bf21cd93STycho Nightingale 			break;
301bf21cd93STycho Nightingale 		case PS2KC_DISABLE:
302bf21cd93STycho Nightingale 			sc->enabled = false;
303bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
304bf21cd93STycho Nightingale 			break;
305bf21cd93STycho Nightingale 		case PS2KC_ENABLE:
306bf21cd93STycho Nightingale 			sc->enabled = true;
307bf21cd93STycho Nightingale 			fifo_reset(sc);
308bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
309bf21cd93STycho Nightingale 			break;
310bf21cd93STycho Nightingale 		case PS2KC_SET_TYPEMATIC:
311bf21cd93STycho Nightingale 			sc->curcmd = val;
312bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
313bf21cd93STycho Nightingale 			break;
314bf21cd93STycho Nightingale 		case PS2KC_SEND_DEV_ID:
315bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
316bf21cd93STycho Nightingale 			fifo_put(sc, 0xab);
317bf21cd93STycho Nightingale 			fifo_put(sc, 0x83);
318bf21cd93STycho Nightingale 			break;
319bf21cd93STycho Nightingale 		case PS2KC_SET_SCANCODE_SET:
320bf21cd93STycho Nightingale 			sc->curcmd = val;
321bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
322bf21cd93STycho Nightingale 			break;
323bf21cd93STycho Nightingale 		case PS2KC_ECHO:
324bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ECHO);
325bf21cd93STycho Nightingale 			break;
326bf21cd93STycho Nightingale 		case PS2KC_SET_LEDS:
327bf21cd93STycho Nightingale 			sc->curcmd = val;
328bf21cd93STycho Nightingale 			fifo_put(sc, PS2KC_ACK);
329bf21cd93STycho Nightingale 			break;
330bf21cd93STycho Nightingale 		default:
331154972afSPatrick Mooney 			EPRINTLN("Unhandled ps2 keyboard command "
332154972afSPatrick Mooney 			    "0x%02x", val);
333bf21cd93STycho Nightingale 			break;
334bf21cd93STycho Nightingale 		}
335bf21cd93STycho Nightingale 	}
336bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
337bf21cd93STycho Nightingale }
338bf21cd93STycho Nightingale 
339bf21cd93STycho Nightingale /*
340bf21cd93STycho Nightingale  * Translate keysym to type 2 scancode and insert into keyboard buffer.
341bf21cd93STycho Nightingale  */
342bf21cd93STycho Nightingale static void
ps2kbd_keysym_queue(struct ps2kbd_softc * sc,int down,uint32_t keysym,uint32_t keycode)343bf21cd93STycho Nightingale ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
344b0de25cbSAndy Fiddaman     int down, uint32_t keysym, uint32_t keycode)
345bf21cd93STycho Nightingale {
34659d65d31SAndy Fiddaman 	const struct extended_translation *trans;
3474c87aefeSPatrick Mooney 	int e0_prefix, found;
3484c87aefeSPatrick Mooney 	uint8_t code;
34959d65d31SAndy Fiddaman 
35059d65d31SAndy Fiddaman 	assert(pthread_mutex_isowned_np(&sc->mtx));
3514c87aefeSPatrick Mooney 
352b0de25cbSAndy Fiddaman 	if (keycode) {
353b0de25cbSAndy Fiddaman 		code =  keyset1to2_translations[(uint8_t)(keycode & 0x7f)];
354b0de25cbSAndy Fiddaman 		e0_prefix = ((keycode & 0x80) ?  SCANCODE_E0_PREFIX : 0);
3554c87aefeSPatrick Mooney 		found = 1;
3564c87aefeSPatrick Mooney 	} else {
357b0de25cbSAndy Fiddaman 		found = 0;
358b0de25cbSAndy Fiddaman 		if (keysym < 0x80) {
359b0de25cbSAndy Fiddaman 			code = ascii_translations[keysym];
360b0de25cbSAndy Fiddaman 			e0_prefix = 0;
361b0de25cbSAndy Fiddaman 			found = 1;
362b0de25cbSAndy Fiddaman 		} else {
36359d65d31SAndy Fiddaman 			for (trans = &extended_translations[0];
36459d65d31SAndy Fiddaman 			    trans->keysym != 0; trans++) {
365b0de25cbSAndy Fiddaman 				if (keysym == trans->keysym) {
366b0de25cbSAndy Fiddaman 					code = trans->scancode;
367b0de25cbSAndy Fiddaman 					e0_prefix = trans->flags & SCANCODE_E0_PREFIX;
368b0de25cbSAndy Fiddaman 					found = 1;
369b0de25cbSAndy Fiddaman 					break;
370b0de25cbSAndy Fiddaman 				}
3714c87aefeSPatrick Mooney 			}
3724c87aefeSPatrick Mooney 		}
3734c87aefeSPatrick Mooney 	}
374bf21cd93STycho Nightingale 
3754c87aefeSPatrick Mooney 	if (!found) {
376154972afSPatrick Mooney 		EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym);
3774c87aefeSPatrick Mooney 		return;
378bf21cd93STycho Nightingale 	}
3794c87aefeSPatrick Mooney 
3804c87aefeSPatrick Mooney 	if (e0_prefix)
3814c87aefeSPatrick Mooney 		fifo_put(sc, 0xe0);
3824c87aefeSPatrick Mooney 	if (!down)
3834c87aefeSPatrick Mooney 		fifo_put(sc, 0xf0);
3844c87aefeSPatrick Mooney 	fifo_put(sc, code);
385bf21cd93STycho Nightingale }
386bf21cd93STycho Nightingale 
387bf21cd93STycho Nightingale static void
ps2kbd_event(int down,uint32_t keysym,uint32_t keycode,void * arg)388b0de25cbSAndy Fiddaman ps2kbd_event(int down, uint32_t keysym, uint32_t keycode, void *arg)
389bf21cd93STycho Nightingale {
390bf21cd93STycho Nightingale 	struct ps2kbd_softc *sc = arg;
3914c87aefeSPatrick Mooney 	int fifo_full;
392bf21cd93STycho Nightingale 
393bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
394bf21cd93STycho Nightingale 	if (!sc->enabled) {
395bf21cd93STycho Nightingale 		pthread_mutex_unlock(&sc->mtx);
396bf21cd93STycho Nightingale 		return;
397bf21cd93STycho Nightingale 	}
3984c87aefeSPatrick Mooney 	fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
399b0de25cbSAndy Fiddaman 	ps2kbd_keysym_queue(sc, down, keysym, keycode);
400bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
401bf21cd93STycho Nightingale 
4024c87aefeSPatrick Mooney 	if (!fifo_full)
4034c87aefeSPatrick Mooney 		atkbdc_event(sc->atkbdc_sc, 1);
404bf21cd93STycho Nightingale }
405bf21cd93STycho Nightingale 
406d7b72f7bSAndy Fiddaman static void
ps2kbd_update_extended_translation(uint32_t keycode,uint32_t scancode,uint32_t prefix)407d7b72f7bSAndy Fiddaman ps2kbd_update_extended_translation(uint32_t keycode, uint32_t scancode, uint32_t prefix)
408d7b72f7bSAndy Fiddaman {
409d7b72f7bSAndy Fiddaman 	int i = 0;
410d7b72f7bSAndy Fiddaman 
41159d65d31SAndy Fiddaman 	do {
412d7b72f7bSAndy Fiddaman 		if (extended_translations[i].keysym == keycode)
413d7b72f7bSAndy Fiddaman 			break;
41459d65d31SAndy Fiddaman 	} while (extended_translations[++i].keysym);
415d7b72f7bSAndy Fiddaman 
416d7b72f7bSAndy Fiddaman 	if (i == (sizeof(extended_translations) / sizeof(struct extended_translation) - 1))
417d7b72f7bSAndy Fiddaman 		return;
418d7b72f7bSAndy Fiddaman 
419d7b72f7bSAndy Fiddaman 	if (!extended_translations[i].keysym)	{
420d7b72f7bSAndy Fiddaman 		extended_translations[i].keysym = keycode;
421d7b72f7bSAndy Fiddaman 
422d7b72f7bSAndy Fiddaman 		extended_translations[i+1].keysym = 0;
423d7b72f7bSAndy Fiddaman 		extended_translations[i+1].scancode = 0;
424d7b72f7bSAndy Fiddaman 		extended_translations[i+1].flags = 0;
425d7b72f7bSAndy Fiddaman 	}
426d7b72f7bSAndy Fiddaman 
427d7b72f7bSAndy Fiddaman 	extended_translations[i].scancode = (uint8_t)(scancode & 0xff);
428d7b72f7bSAndy Fiddaman 	extended_translations[i].flags = (prefix ? SCANCODE_E0_PREFIX : 0);
429d7b72f7bSAndy Fiddaman }
430d7b72f7bSAndy Fiddaman 
431d7b72f7bSAndy Fiddaman static void
ps2kbd_setkbdlayout(void)432d7b72f7bSAndy Fiddaman ps2kbd_setkbdlayout(void)
433d7b72f7bSAndy Fiddaman {
434d7b72f7bSAndy Fiddaman 	int err;
435d7b72f7bSAndy Fiddaman 	int fd;
436d7b72f7bSAndy Fiddaman 	char path[MAX_PATHNAME];
437d7b72f7bSAndy Fiddaman 	char *buf, *next, *line;
438d7b72f7bSAndy Fiddaman 	struct stat sb;
43959d65d31SAndy Fiddaman 	ssize_t sz;
440d7b72f7bSAndy Fiddaman 	uint8_t ascii;
441d7b72f7bSAndy Fiddaman 	uint32_t keycode, scancode, prefix;
442d7b72f7bSAndy Fiddaman 
443d7b72f7bSAndy Fiddaman 	snprintf(path, MAX_PATHNAME, PS2KBD_LAYOUT_BASEDIR"%s", get_config_value("keyboard.layout") );
444d7b72f7bSAndy Fiddaman 
445d7b72f7bSAndy Fiddaman 	err = stat(path, &sb);
446d7b72f7bSAndy Fiddaman 	if (err)
447d7b72f7bSAndy Fiddaman 		return;
448d7b72f7bSAndy Fiddaman 
449d7b72f7bSAndy Fiddaman 	buf = (char *)malloc(sizeof(char) * sb.st_size);
450d7b72f7bSAndy Fiddaman 	if (buf == NULL)
451d7b72f7bSAndy Fiddaman 		return;
452d7b72f7bSAndy Fiddaman 
453d7b72f7bSAndy Fiddaman 	fd = open(path, O_RDONLY);
454d7b72f7bSAndy Fiddaman 	if (fd == -1)
455d7b72f7bSAndy Fiddaman 		goto out;
456d7b72f7bSAndy Fiddaman 
45759d65d31SAndy Fiddaman 	sz = read(fd, buf, sb.st_size);
458d7b72f7bSAndy Fiddaman 
459d7b72f7bSAndy Fiddaman 	close(fd);
460d7b72f7bSAndy Fiddaman 
46159d65d31SAndy Fiddaman 	if (sz < 0 || sz != sb.st_size)
462d7b72f7bSAndy Fiddaman 		goto out;
463d7b72f7bSAndy Fiddaman 
464d7b72f7bSAndy Fiddaman 	next = buf;
465d7b72f7bSAndy Fiddaman 	while ((line = strsep(&next, "\n")) != NULL)	{
466d7b72f7bSAndy Fiddaman 		if (sscanf(line, "'%c',%x;", &ascii, &scancode) == 2)	{
467d7b72f7bSAndy Fiddaman 			if (ascii < 0x80)
468d7b72f7bSAndy Fiddaman 				ascii_translations[ascii] = (uint8_t)(scancode & 0xff);
469d7b72f7bSAndy Fiddaman 		} else if (sscanf(line, "%x,%x,%x;", &keycode, &scancode, &prefix) == 3 )	{
470d7b72f7bSAndy Fiddaman 			ps2kbd_update_extended_translation(keycode, scancode, prefix);
471d7b72f7bSAndy Fiddaman 		} else if (sscanf(line, "%x,%x;", &keycode, &scancode) == 2)	{
472d7b72f7bSAndy Fiddaman 			if (keycode < 0x80)
473d7b72f7bSAndy Fiddaman 				ascii_translations[(uint8_t)(keycode & 0xff)] = (uint8_t)(scancode & 0xff);
474d7b72f7bSAndy Fiddaman 			else
475d7b72f7bSAndy Fiddaman 				ps2kbd_update_extended_translation(keycode, scancode, 0);
476d7b72f7bSAndy Fiddaman 		}
477d7b72f7bSAndy Fiddaman 	}
478d7b72f7bSAndy Fiddaman 
479d7b72f7bSAndy Fiddaman out:
480d7b72f7bSAndy Fiddaman 	free(buf);
481d7b72f7bSAndy Fiddaman }
482d7b72f7bSAndy Fiddaman 
483bf21cd93STycho Nightingale struct ps2kbd_softc *
ps2kbd_init(struct atkbdc_softc * atkbdc_sc)484bf21cd93STycho Nightingale ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
485bf21cd93STycho Nightingale {
486bf21cd93STycho Nightingale 	struct ps2kbd_softc *sc;
487bf21cd93STycho Nightingale 
488d7b72f7bSAndy Fiddaman 	if (get_config_value("keyboard.layout") != NULL)
489d7b72f7bSAndy Fiddaman 		ps2kbd_setkbdlayout();
490d7b72f7bSAndy Fiddaman 
491bf21cd93STycho Nightingale 	sc = calloc(1, sizeof (struct ps2kbd_softc));
492bf21cd93STycho Nightingale 	pthread_mutex_init(&sc->mtx, NULL);
493bf21cd93STycho Nightingale 	fifo_init(sc);
494bf21cd93STycho Nightingale 	sc->atkbdc_sc = atkbdc_sc;
495bf21cd93STycho Nightingale 
4964c87aefeSPatrick Mooney 	console_kbd_register(ps2kbd_event, sc, 1);
497bf21cd93STycho Nightingale 
498bf21cd93STycho Nightingale 	return (sc);
499bf21cd93STycho Nightingale }
5004c87aefeSPatrick Mooney 
501