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