]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/ps2kbd.c
ident(1): Normalizing date format
[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 static void
185 fifo_init(struct ps2kbd_softc *sc)
186 {
187         struct fifo *fifo;
188
189         fifo = &sc->fifo;
190         fifo->size = sizeof(((struct fifo *)0)->buf);
191 }
192
193 static void
194 fifo_reset(struct ps2kbd_softc *sc)
195 {
196         struct fifo *fifo;
197
198         fifo = &sc->fifo;
199         bzero(fifo, sizeof(struct fifo));
200         fifo->size = sizeof(((struct fifo *)0)->buf);
201 }
202
203 static void
204 fifo_put(struct ps2kbd_softc *sc, uint8_t val)
205 {
206         struct fifo *fifo;
207
208         fifo = &sc->fifo;
209         if (fifo->num < fifo->size) {
210                 fifo->buf[fifo->windex] = val;
211                 fifo->windex = (fifo->windex + 1) % fifo->size;
212                 fifo->num++;
213         }
214 }
215
216 static int
217 fifo_get(struct ps2kbd_softc *sc, uint8_t *val)
218 {
219         struct fifo *fifo;
220
221         fifo = &sc->fifo;
222         if (fifo->num > 0) {
223                 *val = fifo->buf[fifo->rindex];
224                 fifo->rindex = (fifo->rindex + 1) % fifo->size;
225                 fifo->num--;
226                 return (0);
227         }
228
229         return (-1);
230 }
231
232 int
233 ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
234 {
235         int retval;
236
237         pthread_mutex_lock(&sc->mtx);
238         retval = fifo_get(sc, val);
239         pthread_mutex_unlock(&sc->mtx);
240
241         return (retval);
242 }
243
244 void
245 ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
246 {
247         pthread_mutex_lock(&sc->mtx);
248         if (sc->curcmd) {
249                 switch (sc->curcmd) {
250                 case PS2KC_SET_TYPEMATIC:
251                         fifo_put(sc, PS2KC_ACK);
252                         break;
253                 case PS2KC_SET_SCANCODE_SET:
254                         fifo_put(sc, PS2KC_ACK);
255                         break;
256                 case PS2KC_SET_LEDS:
257                         fifo_put(sc, PS2KC_ACK);
258                         break;
259                 default:
260                         EPRINTLN("Unhandled ps2 keyboard current "
261                             "command byte 0x%02x", val);
262                         break;
263                 }
264                 sc->curcmd = 0;
265         } else {
266                 switch (val) {
267                 case 0x00:
268                         fifo_put(sc, PS2KC_ACK);
269                         break;
270                 case PS2KC_RESET_DEV:
271                         fifo_reset(sc);
272                         fifo_put(sc, PS2KC_ACK);
273                         fifo_put(sc, PS2KC_BAT_SUCCESS);
274                         break;
275                 case PS2KC_DISABLE:
276                         sc->enabled = false;
277                         fifo_put(sc, PS2KC_ACK);
278                         break;
279                 case PS2KC_ENABLE:
280                         sc->enabled = true;
281                         fifo_reset(sc);
282                         fifo_put(sc, PS2KC_ACK);
283                         break;
284                 case PS2KC_SET_TYPEMATIC:
285                         sc->curcmd = val;
286                         fifo_put(sc, PS2KC_ACK);
287                         break;
288                 case PS2KC_SEND_DEV_ID:
289                         fifo_put(sc, PS2KC_ACK);
290                         fifo_put(sc, 0xab);
291                         fifo_put(sc, 0x83);
292                         break;
293                 case PS2KC_SET_SCANCODE_SET:
294                         sc->curcmd = val;
295                         fifo_put(sc, PS2KC_ACK);
296                         break;
297                 case PS2KC_ECHO:
298                         fifo_put(sc, PS2KC_ECHO);
299                         break;
300                 case PS2KC_SET_LEDS:
301                         sc->curcmd = val;
302                         fifo_put(sc, PS2KC_ACK);
303                         break;
304                 default:
305                         EPRINTLN("Unhandled ps2 keyboard command "
306                             "0x%02x", val);
307                         break;
308                 }
309         }
310         pthread_mutex_unlock(&sc->mtx);
311 }
312
313 /*
314  * Translate keysym to type 2 scancode and insert into keyboard buffer.
315  */
316 static void
317 ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
318     int down, uint32_t keysym)
319 {
320         assert(pthread_mutex_isowned_np(&sc->mtx));
321         int e0_prefix, found;
322         uint8_t code;
323         const struct extended_translation *trans;
324
325         found = 0;
326         if (keysym < 0x80) {
327                 code = ascii_translations[keysym];
328                 e0_prefix = 0;
329                 found = 1;
330         } else {
331                 for (trans = &(extended_translations[0]); trans->keysym != 0;
332                     trans++) {
333                         if (keysym == trans->keysym) {
334                                 code = trans->scancode;
335                                 e0_prefix = trans->flags & SCANCODE_E0_PREFIX;
336                                 found = 1;
337                                 break;
338                         }
339                 }
340         }
341
342         if (!found) {
343                 EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym);
344                 return;
345         }
346
347         if (e0_prefix)
348                 fifo_put(sc, 0xe0);
349         if (!down)
350                 fifo_put(sc, 0xf0);
351         fifo_put(sc, code);
352 }
353
354 static void
355 ps2kbd_event(int down, uint32_t keysym, void *arg)
356 {
357         struct ps2kbd_softc *sc = arg;
358         int fifo_full;
359
360         pthread_mutex_lock(&sc->mtx);
361         if (!sc->enabled) {
362                 pthread_mutex_unlock(&sc->mtx);
363                 return;
364         }
365         fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
366         ps2kbd_keysym_queue(sc, down, keysym);
367         pthread_mutex_unlock(&sc->mtx);
368
369         if (!fifo_full)
370                 atkbdc_event(sc->atkbdc_sc, 1);
371 }
372
373 struct ps2kbd_softc *
374 ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
375 {
376         struct ps2kbd_softc *sc;
377
378         sc = calloc(1, sizeof (struct ps2kbd_softc));
379         pthread_mutex_init(&sc->mtx, NULL);
380         fifo_init(sc);
381         sc->atkbdc_sc = atkbdc_sc;
382
383         console_kbd_register(ps2kbd_event, sc, 1);
384
385         return (sc);
386 }
387
388 #ifdef BHYVE_SNAPSHOT
389 int
390 ps2kbd_snapshot(struct ps2kbd_softc *sc, struct vm_snapshot_meta *meta)
391 {
392         int ret;
393
394         SNAPSHOT_VAR_OR_LEAVE(sc->enabled, meta, ret, done);
395         SNAPSHOT_VAR_OR_LEAVE(sc->curcmd, meta, ret, done);
396
397 done:
398         return (ret);
399 }
400 #endif
401