1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
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
31 #include <sys/types.h>
32 #include <sys/stat.h>
33
34 #include <assert.h>
35 #include <stdbool.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <strings.h>
39 #include <pthread.h>
40 #include <pthread_np.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43
44 #include "atkbdc.h"
45 #include "bhyverun.h"
46 #include "config.h"
47 #include "console.h"
48 #include "debug.h"
49 #include "ps2kbd.h"
50
51 /* keyboard device commands */
52 #define PS2KC_RESET_DEV 0xff
53 #define PS2KC_SET_DEFAULTS 0xf6
54 #define PS2KC_DISABLE 0xf5
55 #define PS2KC_ENABLE 0xf4
56 #define PS2KC_SET_TYPEMATIC 0xf3
57 #define PS2KC_SEND_DEV_ID 0xf2
58 #define PS2KC_SET_SCANCODE_SET 0xf0
59 #define PS2KC_ECHO 0xee
60 #define PS2KC_SET_LEDS 0xed
61
62 #define PS2KC_BAT_SUCCESS 0xaa
63 #define PS2KC_ACK 0xfa
64
65 #define PS2KBD_FIFOSZ 16
66
67 #define PS2KBD_LAYOUT_BASEDIR "/usr/share/bhyve/kbdlayout/"
68
69 #define MAX_PATHNAME 256
70
71 struct fifo {
72 uint8_t buf[PS2KBD_FIFOSZ];
73 int rindex; /* index to read from */
74 int windex; /* index to write to */
75 int num; /* number of bytes in the fifo */
76 int size; /* size of the fifo */
77 };
78
79 struct ps2kbd_softc {
80 struct atkbdc_softc *atkbdc_sc;
81 pthread_mutex_t mtx;
82
83 bool enabled;
84 struct fifo fifo;
85
86 uint8_t curcmd; /* current command for next byte */
87 };
88
89 #define SCANCODE_E0_PREFIX 1
90 struct extended_translation {
91 uint32_t keysym;
92 uint8_t scancode;
93 int flags;
94 };
95
96 /*
97 * FIXME: Pause/break and Print Screen/SysRq require special handling.
98 */
99 static struct extended_translation extended_translations[128] = {
100 {0xff08, 0x66, 0}, /* Back space */
101 {0xff09, 0x0d, 0}, /* Tab */
102 {0xff0d, 0x5a, 0}, /* Return */
103 {0xff1b, 0x76, 0}, /* Escape */
104 {0xff50, 0x6c, SCANCODE_E0_PREFIX}, /* Home */
105 {0xff51, 0x6b, SCANCODE_E0_PREFIX}, /* Left arrow */
106 {0xff52, 0x75, SCANCODE_E0_PREFIX}, /* Up arrow */
107 {0xff53, 0x74, SCANCODE_E0_PREFIX}, /* Right arrow */
108 {0xff54, 0x72, SCANCODE_E0_PREFIX}, /* Down arrow */
109 {0xff55, 0x7d, SCANCODE_E0_PREFIX}, /* PgUp */
110 {0xff56, 0x7a, SCANCODE_E0_PREFIX}, /* PgDown */
111 {0xff57, 0x69, SCANCODE_E0_PREFIX}, /* End */
112 {0xff63, 0x70, SCANCODE_E0_PREFIX}, /* Ins */
113 {0xff8d, 0x5a, SCANCODE_E0_PREFIX}, /* Keypad Enter */
114 {0xffe1, 0x12, 0}, /* Left shift */
115 {0xffe2, 0x59, 0}, /* Right shift */
116 {0xffe3, 0x14, 0}, /* Left control */
117 {0xffe4, 0x14, SCANCODE_E0_PREFIX}, /* Right control */
118 /* {0xffe7, XXX}, Left meta */
119 /* {0xffe8, XXX}, Right meta */
120 {0xffe9, 0x11, 0}, /* Left alt */
121 {0xfe03, 0x11, SCANCODE_E0_PREFIX}, /* AltGr */
122 {0xffea, 0x11, SCANCODE_E0_PREFIX}, /* Right alt */
123 {0xffeb, 0x1f, SCANCODE_E0_PREFIX}, /* Left Windows */
124 {0xffec, 0x27, SCANCODE_E0_PREFIX}, /* Right Windows */
125 {0xffbe, 0x05, 0}, /* F1 */
126 {0xffbf, 0x06, 0}, /* F2 */
127 {0xffc0, 0x04, 0}, /* F3 */
128 {0xffc1, 0x0c, 0}, /* F4 */
129 {0xffc2, 0x03, 0}, /* F5 */
130 {0xffc3, 0x0b, 0}, /* F6 */
131 {0xffc4, 0x83, 0}, /* F7 */
132 {0xffc5, 0x0a, 0}, /* F8 */
133 {0xffc6, 0x01, 0}, /* F9 */
134 {0xffc7, 0x09, 0}, /* F10 */
135 {0xffc8, 0x78, 0}, /* F11 */
136 {0xffc9, 0x07, 0}, /* F12 */
137 {0xffff, 0x71, SCANCODE_E0_PREFIX}, /* Del */
138 {0xff14, 0x7e, 0}, /* ScrollLock */
139 /* NumLock and Keypads*/
140 {0xff7f, 0x77, 0}, /* NumLock */
141 {0xffaf, 0x4a, SCANCODE_E0_PREFIX}, /* Keypad slash */
142 {0xffaa, 0x7c, 0}, /* Keypad asterisk */
143 {0xffad, 0x7b, 0}, /* Keypad minus */
144 {0xffab, 0x79, 0}, /* Keypad plus */
145 {0xffb7, 0x6c, 0}, /* Keypad 7 */
146 {0xff95, 0x6c, 0}, /* Keypad home */
147 {0xffb8, 0x75, 0}, /* Keypad 8 */
148 {0xff97, 0x75, 0}, /* Keypad up arrow */
149 {0xffb9, 0x7d, 0}, /* Keypad 9 */
150 {0xff9a, 0x7d, 0}, /* Keypad PgUp */
151 {0xffb4, 0x6b, 0}, /* Keypad 4 */
152 {0xff96, 0x6b, 0}, /* Keypad left arrow */
153 {0xffb5, 0x73, 0}, /* Keypad 5 */
154 {0xff9d, 0x73, 0}, /* Keypad empty */
155 {0xffb6, 0x74, 0}, /* Keypad 6 */
156 {0xff98, 0x74, 0}, /* Keypad right arrow */
157 {0xffb1, 0x69, 0}, /* Keypad 1 */
158 {0xff9c, 0x69, 0}, /* Keypad end */
159 {0xffb2, 0x72, 0}, /* Keypad 2 */
160 {0xff99, 0x72, 0}, /* Keypad down arrow */
161 {0xffb3, 0x7a, 0}, /* Keypad 3 */
162 {0xff9b, 0x7a, 0}, /* Keypad PgDown */
163 {0xffb0, 0x70, 0}, /* Keypad 0 */
164 {0xff9e, 0x70, 0}, /* Keypad ins */
165 {0xffae, 0x71, 0}, /* Keypad . */
166 {0xff9f, 0x71, 0}, /* Keypad del */
167 {0, 0, 0} /* Terminator */
168 };
169
170 /* ASCII to type 2 scancode lookup table */
171 static uint8_t ascii_translations[128] = {
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176 0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52,
177 0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a,
178 0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d,
179 0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a,
180 0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
181 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
182 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
183 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e,
184 0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
185 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
186 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
187 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00,
188 };
189
190 /* ScanCode set1 to set2 lookup table */
191 static const uint8_t keyset1to2_translations[128] = {
192 0, 0x76, 0x16, 0x1E, 0x26, 0x25, 0x2e, 0x36,
193 0x3d, 0x3e, 0x46, 0x45, 0x4e, 0x55, 0x66, 0x0d,
194 0x15, 0x1d, 0x24, 0x2d, 0x2c, 0x35, 0x3c, 0x43,
195 0x44, 0x4d, 0x54, 0x5b, 0x5a, 0x14, 0x1c, 0x1b,
196 0x23, 0x2b, 0x34, 0x33, 0x3b, 0x42, 0x4b, 0x4c,
197 0x52, 0x0e, 0x12, 0x5d, 0x1a, 0x22, 0x21, 0x2a,
198 0x32, 0x31, 0x3a, 0x41, 0x49, 0x4a, 0x59, 0x7c,
199 0x11, 0x29, 0x58, 0x05, 0x06, 0x04, 0x0c, 0x03,
200 0x0b, 0x83, 0x0a, 0x01, 0x09, 0x77, 0x7e, 0x6c,
201 0x75, 0x7d, 0x7b, 0x6b, 0x73, 0x74, 0x79, 0x69,
202 0x72, 0x7a, 0x70, 0x71, 0x84, 0x60, 0x61, 0x78,
203 0x07, 0x0f, 0x17, 0x1f, 0x27, 0x2f, 0x37, 0x3f,
204 0x47, 0x4f, 0x56, 0x5e, 0x08, 0x10, 0x18, 0x20,
205 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x57, 0x6f,
206 0x13, 0x19, 0x39, 0x51, 0x53, 0x5c, 0x5f, 0x62,
207 0x63, 0x64, 0x65, 0x67, 0x68, 0x6a, 0x6d, 0x6e,
208 };
209
210 static void
fifo_init(struct ps2kbd_softc * sc)211 fifo_init(struct ps2kbd_softc *sc)
212 {
213 struct fifo *fifo;
214
215 fifo = &sc->fifo;
216 fifo->size = sizeof(((struct fifo *)0)->buf);
217 }
218
219 static void
fifo_reset(struct ps2kbd_softc * sc)220 fifo_reset(struct ps2kbd_softc *sc)
221 {
222 struct fifo *fifo;
223
224 fifo = &sc->fifo;
225 bzero(fifo, sizeof(struct fifo));
226 fifo->size = sizeof(((struct fifo *)0)->buf);
227 }
228
229 static void
fifo_put(struct ps2kbd_softc * sc,uint8_t val)230 fifo_put(struct ps2kbd_softc *sc, uint8_t val)
231 {
232 struct fifo *fifo;
233
234 fifo = &sc->fifo;
235 if (fifo->num < fifo->size) {
236 fifo->buf[fifo->windex] = val;
237 fifo->windex = (fifo->windex + 1) % fifo->size;
238 fifo->num++;
239 }
240 }
241
242 static int
fifo_get(struct ps2kbd_softc * sc,uint8_t * val)243 fifo_get(struct ps2kbd_softc *sc, uint8_t *val)
244 {
245 struct fifo *fifo;
246
247 fifo = &sc->fifo;
248 if (fifo->num > 0) {
249 *val = fifo->buf[fifo->rindex];
250 fifo->rindex = (fifo->rindex + 1) % fifo->size;
251 fifo->num--;
252 return (0);
253 }
254
255 return (-1);
256 }
257
258 int
ps2kbd_read(struct ps2kbd_softc * sc,uint8_t * val)259 ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
260 {
261 int retval;
262
263 pthread_mutex_lock(&sc->mtx);
264 retval = fifo_get(sc, val);
265 pthread_mutex_unlock(&sc->mtx);
266
267 return (retval);
268 }
269
270 void
ps2kbd_write(struct ps2kbd_softc * sc,uint8_t val)271 ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
272 {
273 pthread_mutex_lock(&sc->mtx);
274 if (sc->curcmd) {
275 switch (sc->curcmd) {
276 case PS2KC_SET_TYPEMATIC:
277 fifo_put(sc, PS2KC_ACK);
278 break;
279 case PS2KC_SET_SCANCODE_SET:
280 fifo_put(sc, PS2KC_ACK);
281 break;
282 case PS2KC_SET_LEDS:
283 fifo_put(sc, PS2KC_ACK);
284 break;
285 default:
286 EPRINTLN("Unhandled ps2 keyboard current "
287 "command byte 0x%02x", val);
288 break;
289 }
290 sc->curcmd = 0;
291 } else {
292 switch (val) {
293 case 0x00:
294 fifo_put(sc, PS2KC_ACK);
295 break;
296 case PS2KC_RESET_DEV:
297 fifo_reset(sc);
298 fifo_put(sc, PS2KC_ACK);
299 fifo_put(sc, PS2KC_BAT_SUCCESS);
300 break;
301 case PS2KC_SET_DEFAULTS:
302 fifo_reset(sc);
303 fifo_put(sc, PS2KC_ACK);
304 break;
305 case PS2KC_DISABLE:
306 sc->enabled = false;
307 fifo_put(sc, PS2KC_ACK);
308 break;
309 case PS2KC_ENABLE:
310 sc->enabled = true;
311 fifo_reset(sc);
312 fifo_put(sc, PS2KC_ACK);
313 break;
314 case PS2KC_SET_TYPEMATIC:
315 sc->curcmd = val;
316 fifo_put(sc, PS2KC_ACK);
317 break;
318 case PS2KC_SEND_DEV_ID:
319 fifo_put(sc, PS2KC_ACK);
320 fifo_put(sc, 0xab);
321 fifo_put(sc, 0x83);
322 break;
323 case PS2KC_SET_SCANCODE_SET:
324 sc->curcmd = val;
325 fifo_put(sc, PS2KC_ACK);
326 break;
327 case PS2KC_ECHO:
328 fifo_put(sc, PS2KC_ECHO);
329 break;
330 case PS2KC_SET_LEDS:
331 sc->curcmd = val;
332 fifo_put(sc, PS2KC_ACK);
333 break;
334 default:
335 EPRINTLN("Unhandled ps2 keyboard command "
336 "0x%02x", val);
337 break;
338 }
339 }
340 pthread_mutex_unlock(&sc->mtx);
341 }
342
343 /*
344 * Translate keysym to type 2 scancode and insert into keyboard buffer.
345 */
346 static void
ps2kbd_keysym_queue(struct ps2kbd_softc * sc,int down,uint32_t keysym,uint32_t keycode)347 ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
348 int down, uint32_t keysym, uint32_t keycode)
349 {
350 const struct extended_translation *trans;
351 int e0_prefix, found;
352 uint8_t code;
353
354 assert(pthread_mutex_isowned_np(&sc->mtx));
355
356 if (keycode) {
357 code = keyset1to2_translations[(uint8_t)(keycode & 0x7f)];
358 e0_prefix = ((keycode & 0x80) ? SCANCODE_E0_PREFIX : 0);
359 found = 1;
360 } else {
361 found = 0;
362 if (keysym < 0x80) {
363 code = ascii_translations[keysym];
364 e0_prefix = 0;
365 found = 1;
366 } else {
367 for (trans = &extended_translations[0];
368 trans->keysym != 0; trans++) {
369 if (keysym == trans->keysym) {
370 code = trans->scancode;
371 e0_prefix = trans->flags & SCANCODE_E0_PREFIX;
372 found = 1;
373 break;
374 }
375 }
376 }
377 }
378
379 if (!found) {
380 EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym);
381 return;
382 }
383
384 if (e0_prefix)
385 fifo_put(sc, 0xe0);
386 if (!down)
387 fifo_put(sc, 0xf0);
388 fifo_put(sc, code);
389 }
390
391 static void
ps2kbd_event(int down,uint32_t keysym,uint32_t keycode,void * arg)392 ps2kbd_event(int down, uint32_t keysym, uint32_t keycode, void *arg)
393 {
394 struct ps2kbd_softc *sc = arg;
395 int fifo_full;
396
397 pthread_mutex_lock(&sc->mtx);
398 if (!sc->enabled) {
399 pthread_mutex_unlock(&sc->mtx);
400 return;
401 }
402 fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
403 ps2kbd_keysym_queue(sc, down, keysym, keycode);
404 pthread_mutex_unlock(&sc->mtx);
405
406 if (!fifo_full)
407 atkbdc_event(sc->atkbdc_sc, 1);
408 }
409
410 static void
ps2kbd_update_extended_translation(uint32_t keycode,uint32_t scancode,uint32_t prefix)411 ps2kbd_update_extended_translation(uint32_t keycode, uint32_t scancode, uint32_t prefix)
412 {
413 int i = 0;
414
415 do {
416 if (extended_translations[i].keysym == keycode)
417 break;
418 } while (extended_translations[++i].keysym);
419
420 if (i == (sizeof(extended_translations) / sizeof(struct extended_translation) - 1))
421 return;
422
423 if (!extended_translations[i].keysym) {
424 extended_translations[i].keysym = keycode;
425
426 extended_translations[i+1].keysym = 0;
427 extended_translations[i+1].scancode = 0;
428 extended_translations[i+1].flags = 0;
429 }
430
431 extended_translations[i].scancode = (uint8_t)(scancode & 0xff);
432 extended_translations[i].flags = (prefix ? SCANCODE_E0_PREFIX : 0);
433 }
434
435 static void
ps2kbd_setkbdlayout(void)436 ps2kbd_setkbdlayout(void)
437 {
438 int err;
439 int fd;
440 char path[MAX_PATHNAME];
441 char *buf, *next, *line;
442 struct stat sb;
443 ssize_t sz;
444 uint8_t ascii;
445 uint32_t keycode, scancode, prefix;
446
447 snprintf(path, MAX_PATHNAME, PS2KBD_LAYOUT_BASEDIR"%s", get_config_value("keyboard.layout") );
448
449 err = stat(path, &sb);
450 if (err)
451 return;
452
453 buf = (char *)malloc(sizeof(char) * sb.st_size);
454 if (buf == NULL)
455 return;
456
457 fd = open(path, O_RDONLY);
458 if (fd == -1)
459 goto out;
460
461 sz = read(fd, buf, sb.st_size);
462
463 close(fd);
464
465 if (sz < 0 || sz != sb.st_size)
466 goto out;
467
468 next = buf;
469 while ((line = strsep(&next, "\n")) != NULL) {
470 if (sscanf(line, "'%c',%x;", &ascii, &scancode) == 2) {
471 if (ascii < 0x80)
472 ascii_translations[ascii] = (uint8_t)(scancode & 0xff);
473 } else if (sscanf(line, "%x,%x,%x;", &keycode, &scancode, &prefix) == 3 ) {
474 ps2kbd_update_extended_translation(keycode, scancode, prefix);
475 } else if (sscanf(line, "%x,%x;", &keycode, &scancode) == 2) {
476 if (keycode < 0x80)
477 ascii_translations[(uint8_t)(keycode & 0xff)] = (uint8_t)(scancode & 0xff);
478 else
479 ps2kbd_update_extended_translation(keycode, scancode, 0);
480 }
481 }
482
483 out:
484 free(buf);
485 }
486
487 struct ps2kbd_softc *
ps2kbd_init(struct atkbdc_softc * atkbdc_sc)488 ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
489 {
490 struct ps2kbd_softc *sc;
491
492 if (get_config_value("keyboard.layout") != NULL)
493 ps2kbd_setkbdlayout();
494
495 sc = calloc(1, sizeof (struct ps2kbd_softc));
496 pthread_mutex_init(&sc->mtx, NULL);
497 fifo_init(sc);
498 sc->atkbdc_sc = atkbdc_sc;
499
500 console_kbd_register(ps2kbd_event, sc, 1);
501
502 return (sc);
503 }
504
505