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