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