]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/ps2kbd.c
Provide basic descriptions for VMX exit reason (from "Intel 64 and IA-32
[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 "console.h"
45
46 /* keyboard device commands */
47 #define PS2KC_RESET_DEV         0xff
48 #define PS2KC_DISABLE           0xf5
49 #define PS2KC_ENABLE            0xf4
50 #define PS2KC_SET_TYPEMATIC     0xf3
51 #define PS2KC_SEND_DEV_ID       0xf2
52 #define PS2KC_SET_SCANCODE_SET  0xf0
53 #define PS2KC_ECHO              0xee
54 #define PS2KC_SET_LEDS          0xed
55
56 #define PS2KC_BAT_SUCCESS       0xaa
57 #define PS2KC_ACK               0xfa
58
59 #define PS2KBD_FIFOSZ           16
60
61 struct fifo {
62         uint8_t buf[PS2KBD_FIFOSZ];
63         int     rindex;         /* index to read from */
64         int     windex;         /* index to write to */
65         int     num;            /* number of bytes in the fifo */
66         int     size;           /* size of the fifo */
67 };
68
69 struct ps2kbd_softc {
70         struct atkbdc_softc     *atkbdc_sc;
71         pthread_mutex_t         mtx;
72
73         bool                    enabled;
74         struct fifo             fifo;
75
76         uint8_t                 curcmd; /* current command for next byte */
77 };
78
79 static void
80 fifo_init(struct ps2kbd_softc *sc)
81 {
82         struct fifo *fifo;
83
84         fifo = &sc->fifo;
85         fifo->size = sizeof(((struct fifo *)0)->buf);
86 }
87
88 static void
89 fifo_reset(struct ps2kbd_softc *sc)
90 {
91         struct fifo *fifo;
92
93         fifo = &sc->fifo;
94         bzero(fifo, sizeof(struct fifo));
95         fifo->size = sizeof(((struct fifo *)0)->buf);
96 }
97
98 static void
99 fifo_put(struct ps2kbd_softc *sc, uint8_t val)
100 {
101         struct fifo *fifo;
102
103         fifo = &sc->fifo;
104         if (fifo->num < fifo->size) {
105                 fifo->buf[fifo->windex] = val;
106                 fifo->windex = (fifo->windex + 1) % fifo->size;
107                 fifo->num++;
108         }
109 }
110
111 static int
112 fifo_get(struct ps2kbd_softc *sc, uint8_t *val)
113 {
114         struct fifo *fifo;
115
116         fifo = &sc->fifo;
117         if (fifo->num > 0) {
118                 *val = fifo->buf[fifo->rindex];
119                 fifo->rindex = (fifo->rindex + 1) % fifo->size;
120                 fifo->num--;
121                 return (0);
122         }
123
124         return (-1);
125 }
126
127 int
128 ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
129 {
130         int retval;
131
132         pthread_mutex_lock(&sc->mtx);
133         retval = fifo_get(sc, val);
134         pthread_mutex_unlock(&sc->mtx);
135
136         return (retval);
137 }
138
139 void
140 ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
141 {
142         pthread_mutex_lock(&sc->mtx);
143         if (sc->curcmd) {
144                 switch (sc->curcmd) {
145                 case PS2KC_SET_TYPEMATIC:
146                         fifo_put(sc, PS2KC_ACK);
147                         break;
148                 case PS2KC_SET_SCANCODE_SET:
149                         fifo_put(sc, PS2KC_ACK);
150                         break;
151                 case PS2KC_SET_LEDS:
152                         fifo_put(sc, PS2KC_ACK);
153                         break;
154                 default:
155                         fprintf(stderr, "Unhandled ps2 keyboard current "
156                             "command byte 0x%02x\n", val);
157                         break;
158                 }
159                 sc->curcmd = 0;
160         } else {
161                 switch (val) {
162                 case 0x00:
163                         fifo_put(sc, PS2KC_ACK);
164                         break;
165                 case PS2KC_RESET_DEV:
166                         fifo_reset(sc);
167                         fifo_put(sc, PS2KC_ACK);
168                         fifo_put(sc, PS2KC_BAT_SUCCESS);
169                         break;
170                 case PS2KC_DISABLE:
171                         sc->enabled = false;
172                         fifo_put(sc, PS2KC_ACK);
173                         break;
174                 case PS2KC_ENABLE:
175                         sc->enabled = true;
176                         fifo_reset(sc);
177                         fifo_put(sc, PS2KC_ACK);
178                         break;
179                 case PS2KC_SET_TYPEMATIC:
180                         sc->curcmd = val;
181                         fifo_put(sc, PS2KC_ACK);
182                         break;
183                 case PS2KC_SEND_DEV_ID:
184                         fifo_put(sc, PS2KC_ACK);
185                         fifo_put(sc, 0xab);
186                         fifo_put(sc, 0x83);
187                         break;
188                 case PS2KC_SET_SCANCODE_SET:
189                         sc->curcmd = val;
190                         fifo_put(sc, PS2KC_ACK);
191                         break;
192                 case PS2KC_ECHO:
193                         fifo_put(sc, PS2KC_ECHO);
194                         break;
195                 case PS2KC_SET_LEDS:
196                         sc->curcmd = val;
197                         fifo_put(sc, PS2KC_ACK);
198                         break;
199                 default:
200                         fprintf(stderr, "Unhandled ps2 keyboard command "
201                             "0x%02x\n", val);
202                         break;
203                 }
204         }
205         pthread_mutex_unlock(&sc->mtx);
206 }
207
208 /*
209  * Translate keysym to type 2 scancode and insert into keyboard buffer.
210  */
211 static void
212 ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
213     int down, uint32_t keysym)
214 {
215         /* ASCII to type 2 scancode lookup table */
216         const uint8_t translation[128] = {
217                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221                 0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52,
222                 0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a,
223                 0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d,
224                 0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a,
225                 0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
226                 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
227                 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
228                 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e,
229                 0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
230                 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
231                 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
232                 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00,
233         };
234
235         assert(pthread_mutex_isowned_np(&sc->mtx));
236
237         switch (keysym) {
238         case 0x0 ... 0x7f:
239                 if (!down)
240                         fifo_put(sc, 0xf0);
241                 fifo_put(sc, translation[keysym]);
242                 break;
243         case 0xff08:    /* Back space */
244                 if (!down)
245                         fifo_put(sc, 0xf0);
246                 fifo_put(sc, 0x66);
247                 break;
248         case 0xff09:    /* Tab */
249                 if (!down)
250                         fifo_put(sc, 0xf0);
251                 fifo_put(sc, 0x0d);
252                 break;
253         case 0xff0d:    /* Return  */
254                 if (!down)
255                         fifo_put(sc, 0xf0);
256                 fifo_put(sc, 0x5a);
257                 break;
258         case 0xff1b:    /* Escape */
259                 if (!down)
260                         fifo_put(sc, 0xf0);
261                 fifo_put(sc, 0x76);
262                 break;
263         case 0xff50:    /* Home */
264                 fifo_put(sc, 0xe0);
265                 if (!down)
266                         fifo_put(sc, 0xf0);
267                 fifo_put(sc, 0x6c);
268                 break;
269         case 0xff51:    /* Left arrow */
270                 fifo_put(sc, 0xe0);
271                 if (!down)
272                         fifo_put(sc, 0xf0);
273                 fifo_put(sc, 0x6b);
274                 break;
275         case 0xff52:    /* Up arrow */
276                 fifo_put(sc, 0xe0);
277                 if (!down)
278                         fifo_put(sc, 0xf0);
279                 fifo_put(sc, 0x75);
280                 break;
281         case 0xff53:    /* Right arrow */
282                 fifo_put(sc, 0xe0);
283                 if (!down)
284                         fifo_put(sc, 0xf0);
285                 fifo_put(sc, 0x74);
286                 break;
287         case 0xff54:    /* Down arrow */
288                 fifo_put(sc, 0xe0);
289                 if (!down)
290                         fifo_put(sc, 0xf0);
291                 fifo_put(sc, 0x72);
292                 break;
293         case 0xff55:    /* PgUp */
294                 fifo_put(sc, 0xe0);
295                 if (!down)
296                         fifo_put(sc, 0xf0);     
297                 fifo_put(sc, 0x7d);
298                 break;
299         case 0xff56:    /* PgDwn */
300                 fifo_put(sc, 0xe0);
301                 if (!down)
302                         fifo_put(sc, 0xf0);     
303                 fifo_put(sc, 0x7a);
304                 break;
305         case 0xff57:    /* End */
306                 fifo_put(sc, 0xe0);
307                 if (!down)
308                         fifo_put(sc, 0xf0);     
309                 fifo_put(sc, 0x69);
310                 break;
311         case 0xff63:    /* Ins */
312                 fifo_put(sc, 0xe0);
313                 if (!down)
314                         fifo_put(sc, 0xf0);     
315                 fifo_put(sc, 0x70);
316                 break;
317         case 0xff8d:    /* Keypad Enter */
318                 fifo_put(sc, 0xe0);
319                 if (!down)
320                         fifo_put(sc, 0xf0);
321                 fifo_put(sc, 0x5a);
322                 break;
323         case 0xffe1:    /* Left shift */
324                 if (!down)
325                         fifo_put(sc, 0xf0);
326                 fifo_put(sc, 0x12);
327                 break;
328         case 0xffe2:    /* Right shift */
329                 if (!down)
330                         fifo_put(sc, 0xf0);
331                 fifo_put(sc, 0x59);
332                 break;
333         case 0xffe3:    /* Left control */
334                 if (!down)
335                         fifo_put(sc, 0xf0);
336                 fifo_put(sc, 0x14);
337                 break;
338         case 0xffe4:    /* Right control */
339                 fifo_put(sc, 0xe0);
340                 if (!down)
341                         fifo_put(sc, 0xf0);
342                 fifo_put(sc, 0x14);
343                 break;
344         case 0xffe7:    /* Left meta */
345                 /* XXX */
346                 break;
347         case 0xffe8:    /* Right meta */
348                 /* XXX */
349                 break;
350         case 0xffe9:    /* Left alt */
351                 if (!down)
352                         fifo_put(sc, 0xf0);
353                 fifo_put(sc, 0x11);
354                 break;
355         case 0xfe03:    /* AltGr */
356         case 0xffea:    /* Right alt */
357                 fifo_put(sc, 0xe0);
358                 if (!down)
359                         fifo_put(sc, 0xf0);
360                 fifo_put(sc, 0x11);
361                 break;
362         case 0xffeb:    /* Left Windows */
363                 fifo_put(sc, 0xe0);
364                 if (!down)
365                         fifo_put(sc, 0xf0);
366                 fifo_put(sc, 0x1f);
367                 break;
368         case 0xffec:    /* Right Windows */
369                 fifo_put(sc, 0xe0);
370                 if (!down)
371                         fifo_put(sc, 0xf0);
372                 fifo_put(sc, 0x27);
373                 break;
374         case 0xffbe:    /* F1 */
375                 if (!down)
376                         fifo_put(sc, 0xf0);
377                 fifo_put(sc, 0x05);
378                 break;
379         case 0xffbf:    /* F2 */
380                 if (!down)
381                         fifo_put(sc, 0xf0);
382                 fifo_put(sc, 0x06);
383                 break;
384         case 0xffc0:    /* F3 */
385                 if (!down)
386                         fifo_put(sc, 0xf0);
387                 fifo_put(sc, 0x04);
388                 break;
389         case 0xffc1:    /* F4 */
390                 if (!down)
391                         fifo_put(sc, 0xf0);
392                 fifo_put(sc, 0x0C);
393                 break;
394         case 0xffc2:    /* F5 */
395                 if (!down)
396                         fifo_put(sc, 0xf0);
397                 fifo_put(sc, 0x03);
398                 break;
399         case 0xffc3:    /* F6 */
400                 if (!down)
401                         fifo_put(sc, 0xf0);
402                 fifo_put(sc, 0x0B);
403                 break;
404         case 0xffc4:    /* F7 */
405                 if (!down)
406                         fifo_put(sc, 0xf0);
407                 fifo_put(sc, 0x83);
408                 break;
409         case 0xffc5:    /* F8 */
410                 if (!down)
411                         fifo_put(sc, 0xf0);
412                 fifo_put(sc, 0x0A);
413                 break;
414         case 0xffc6:    /* F9 */
415                 if (!down)
416                         fifo_put(sc, 0xf0);
417                 fifo_put(sc, 0x01);
418                 break;
419         case 0xffc7:    /* F10 */
420                 if (!down)
421                         fifo_put(sc, 0xf0);
422                 fifo_put(sc, 0x09);
423                 break;
424         case 0xffc8:    /* F11 */
425                 if (!down)
426                         fifo_put(sc, 0xf0);
427                 fifo_put(sc, 0x78);
428                 break;
429         case 0xffc9:    /* F12 */
430                 if (!down)
431                         fifo_put(sc, 0xf0);
432                 fifo_put(sc, 0x07);
433                 break;
434         case 0xffff:    /* Del */
435                 fifo_put(sc, 0xe0);
436                 if (!down)
437                         fifo_put(sc, 0xf0);
438                 fifo_put(sc, 0x71);
439                 break;
440         default:
441                 fprintf(stderr, "Unhandled ps2 keyboard keysym 0x%x\n",
442                      keysym);
443                 break;
444         }
445 }
446
447 static void
448 ps2kbd_event(int down, uint32_t keysym, void *arg)
449 {
450         struct ps2kbd_softc *sc = arg;
451         int fifo_full;
452
453         pthread_mutex_lock(&sc->mtx);
454         if (!sc->enabled) {
455                 pthread_mutex_unlock(&sc->mtx);
456                 return;
457         }
458         fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
459         ps2kbd_keysym_queue(sc, down, keysym);
460         pthread_mutex_unlock(&sc->mtx);
461
462         if (!fifo_full)
463                 atkbdc_event(sc->atkbdc_sc, 1);
464 }
465
466 struct ps2kbd_softc *
467 ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
468 {
469         struct ps2kbd_softc *sc;
470
471         sc = calloc(1, sizeof (struct ps2kbd_softc));
472         pthread_mutex_init(&sc->mtx, NULL);
473         fifo_init(sc);
474         sc->atkbdc_sc = atkbdc_sc;
475
476         console_kbd_register(ps2kbd_event, sc, 1);
477
478         return (sc);
479 }
480