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