]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/ps2kbd.c
Merge bmake-20180512
[FreeBSD/FreeBSD.git] / usr.sbin / bhyve / ps2kbd.c
1 /*-
2  * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
3  * Copyright (c) 2015 Nahanni Systems Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/types.h>
32
33 #include <assert.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <strings.h>
38 #include <pthread.h>
39 #include <pthread_np.h>
40
41 #include "atkbdc.h"
42 #include "console.h"
43
44 /* keyboard device commands */
45 #define PS2KC_RESET_DEV         0xff
46 #define PS2KC_DISABLE           0xf5
47 #define PS2KC_ENABLE            0xf4
48 #define PS2KC_SET_TYPEMATIC     0xf3
49 #define PS2KC_SEND_DEV_ID       0xf2
50 #define PS2KC_SET_SCANCODE_SET  0xf0
51 #define PS2KC_ECHO              0xee
52 #define PS2KC_SET_LEDS          0xed
53
54 #define PS2KC_BAT_SUCCESS       0xaa
55 #define PS2KC_ACK               0xfa
56
57 #define PS2KBD_FIFOSZ           16
58
59 struct fifo {
60         uint8_t buf[PS2KBD_FIFOSZ];
61         int     rindex;         /* index to read from */
62         int     windex;         /* index to write to */
63         int     num;            /* number of bytes in the fifo */
64         int     size;           /* size of the fifo */
65 };
66
67 struct ps2kbd_softc {
68         struct atkbdc_softc     *atkbdc_sc;
69         pthread_mutex_t         mtx;
70
71         bool                    enabled;
72         struct fifo             fifo;
73
74         uint8_t                 curcmd; /* current command for next byte */
75 };
76
77 static void
78 fifo_init(struct ps2kbd_softc *sc)
79 {
80         struct fifo *fifo;
81
82         fifo = &sc->fifo;
83         fifo->size = sizeof(((struct fifo *)0)->buf);
84 }
85
86 static void
87 fifo_reset(struct ps2kbd_softc *sc)
88 {
89         struct fifo *fifo;
90
91         fifo = &sc->fifo;
92         bzero(fifo, sizeof(struct fifo));
93         fifo->size = sizeof(((struct fifo *)0)->buf);
94 }
95
96 static void
97 fifo_put(struct ps2kbd_softc *sc, uint8_t val)
98 {
99         struct fifo *fifo;
100
101         fifo = &sc->fifo;
102         if (fifo->num < fifo->size) {
103                 fifo->buf[fifo->windex] = val;
104                 fifo->windex = (fifo->windex + 1) % fifo->size;
105                 fifo->num++;
106         }
107 }
108
109 static int
110 fifo_get(struct ps2kbd_softc *sc, uint8_t *val)
111 {
112         struct fifo *fifo;
113
114         fifo = &sc->fifo;
115         if (fifo->num > 0) {
116                 *val = fifo->buf[fifo->rindex];
117                 fifo->rindex = (fifo->rindex + 1) % fifo->size;
118                 fifo->num--;
119                 return (0);
120         }
121
122         return (-1);
123 }
124
125 int
126 ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
127 {
128         int retval;
129
130         pthread_mutex_lock(&sc->mtx);
131         retval = fifo_get(sc, val);
132         pthread_mutex_unlock(&sc->mtx);
133
134         return (retval);
135 }
136
137 void
138 ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
139 {
140         pthread_mutex_lock(&sc->mtx);
141         if (sc->curcmd) {
142                 switch (sc->curcmd) {
143                 case PS2KC_SET_TYPEMATIC:
144                         fifo_put(sc, PS2KC_ACK);
145                         break;
146                 case PS2KC_SET_SCANCODE_SET:
147                         fifo_put(sc, PS2KC_ACK);
148                         break;
149                 case PS2KC_SET_LEDS:
150                         fifo_put(sc, PS2KC_ACK);
151                         break;
152                 default:
153                         fprintf(stderr, "Unhandled ps2 keyboard current "
154                             "command byte 0x%02x\n", val);
155                         break;
156                 }
157                 sc->curcmd = 0;
158         } else {
159                 switch (val) {
160                 case 0x00:
161                         fifo_put(sc, PS2KC_ACK);
162                         break;
163                 case PS2KC_RESET_DEV:
164                         fifo_reset(sc);
165                         fifo_put(sc, PS2KC_ACK);
166                         fifo_put(sc, PS2KC_BAT_SUCCESS);
167                         break;
168                 case PS2KC_DISABLE:
169                         sc->enabled = false;
170                         fifo_put(sc, PS2KC_ACK);
171                         break;
172                 case PS2KC_ENABLE:
173                         sc->enabled = true;
174                         fifo_reset(sc);
175                         fifo_put(sc, PS2KC_ACK);
176                         break;
177                 case PS2KC_SET_TYPEMATIC:
178                         sc->curcmd = val;
179                         fifo_put(sc, PS2KC_ACK);
180                         break;
181                 case PS2KC_SEND_DEV_ID:
182                         fifo_put(sc, PS2KC_ACK);
183                         fifo_put(sc, 0xab);
184                         fifo_put(sc, 0x83);
185                         break;
186                 case PS2KC_SET_SCANCODE_SET:
187                         sc->curcmd = val;
188                         fifo_put(sc, PS2KC_ACK);
189                         break;
190                 case PS2KC_ECHO:
191                         fifo_put(sc, PS2KC_ECHO);
192                         break;
193                 case PS2KC_SET_LEDS:
194                         sc->curcmd = val;
195                         fifo_put(sc, PS2KC_ACK);
196                         break;
197                 default:
198                         fprintf(stderr, "Unhandled ps2 keyboard command "
199                             "0x%02x\n", val);
200                         break;
201                 }
202         }
203         pthread_mutex_unlock(&sc->mtx);
204 }
205
206 /*
207  * Translate keysym to type 2 scancode and insert into keyboard buffer.
208  */
209 static void
210 ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
211     int down, uint32_t keysym)
212 {
213         /* ASCII to type 2 scancode lookup table */
214         const uint8_t translation[128] = {
215                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
216                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219                 0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52,
220                 0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a,
221                 0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d,
222                 0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a,
223                 0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
224                 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
225                 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
226                 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e,
227                 0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
228                 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
229                 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
230                 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00,
231         };
232
233         assert(pthread_mutex_isowned_np(&sc->mtx));
234
235         switch (keysym) {
236         case 0x0 ... 0x7f:
237                 if (!down)
238                         fifo_put(sc, 0xf0);
239                 fifo_put(sc, translation[keysym]);
240                 break;
241         case 0xff08:    /* Back space */
242                 if (!down)
243                         fifo_put(sc, 0xf0);
244                 fifo_put(sc, 0x66);
245                 break;
246         case 0xff09:    /* Tab */
247                 if (!down)
248                         fifo_put(sc, 0xf0);
249                 fifo_put(sc, 0x0d);
250                 break;
251         case 0xff0d:    /* Return  */
252                 if (!down)
253                         fifo_put(sc, 0xf0);
254                 fifo_put(sc, 0x5a);
255                 break;
256         case 0xff1b:    /* Escape */
257                 if (!down)
258                         fifo_put(sc, 0xf0);
259                 fifo_put(sc, 0x76);
260                 break;
261         case 0xff50:    /* Home */
262                 fifo_put(sc, 0xe0);
263                 if (!down)
264                         fifo_put(sc, 0xf0);
265                 fifo_put(sc, 0x6c);
266                 break;
267         case 0xff51:    /* Left arrow */
268                 fifo_put(sc, 0xe0);
269                 if (!down)
270                         fifo_put(sc, 0xf0);
271                 fifo_put(sc, 0x6b);
272                 break;
273         case 0xff52:    /* Up arrow */
274                 fifo_put(sc, 0xe0);
275                 if (!down)
276                         fifo_put(sc, 0xf0);
277                 fifo_put(sc, 0x75);
278                 break;
279         case 0xff53:    /* Right arrow */
280                 fifo_put(sc, 0xe0);
281                 if (!down)
282                         fifo_put(sc, 0xf0);
283                 fifo_put(sc, 0x74);
284                 break;
285         case 0xff54:    /* Down arrow */
286                 fifo_put(sc, 0xe0);
287                 if (!down)
288                         fifo_put(sc, 0xf0);
289                 fifo_put(sc, 0x72);
290                 break;
291         case 0xff55:    /* PgUp */
292                 fifo_put(sc, 0xe0);
293                 if (!down)
294                         fifo_put(sc, 0xf0);     
295                 fifo_put(sc, 0x7d);
296                 break;
297         case 0xff56:    /* PgDwn */
298                 fifo_put(sc, 0xe0);
299                 if (!down)
300                         fifo_put(sc, 0xf0);     
301                 fifo_put(sc, 0x7a);
302                 break;
303         case 0xff57:    /* End */
304                 fifo_put(sc, 0xe0);
305                 if (!down)
306                         fifo_put(sc, 0xf0);     
307                 fifo_put(sc, 0x69);
308                 break;
309         case 0xff63:    /* Ins */
310                 fifo_put(sc, 0xe0);
311                 if (!down)
312                         fifo_put(sc, 0xf0);     
313                 fifo_put(sc, 0x70);
314                 break;
315         case 0xff8d:    /* Keypad Enter */
316                 fifo_put(sc, 0xe0);
317                 if (!down)
318                         fifo_put(sc, 0xf0);
319                 fifo_put(sc, 0x5a);
320                 break;
321         case 0xffe1:    /* Left shift */
322                 if (!down)
323                         fifo_put(sc, 0xf0);
324                 fifo_put(sc, 0x12);
325                 break;
326         case 0xffe2:    /* Right shift */
327                 if (!down)
328                         fifo_put(sc, 0xf0);
329                 fifo_put(sc, 0x59);
330                 break;
331         case 0xffe3:    /* Left control */
332                 if (!down)
333                         fifo_put(sc, 0xf0);
334                 fifo_put(sc, 0x14);
335                 break;
336         case 0xffe4:    /* Right control */
337                 fifo_put(sc, 0xe0);
338                 if (!down)
339                         fifo_put(sc, 0xf0);
340                 fifo_put(sc, 0x14);
341                 break;
342         case 0xffe7:    /* Left meta */
343                 /* XXX */
344                 break;
345         case 0xffe8:    /* Right meta */
346                 /* XXX */
347                 break;
348         case 0xffe9:    /* Left alt */
349                 if (!down)
350                         fifo_put(sc, 0xf0);
351                 fifo_put(sc, 0x11);
352                 break;
353         case 0xfe03:    /* AltGr */
354         case 0xffea:    /* Right alt */
355                 fifo_put(sc, 0xe0);
356                 if (!down)
357                         fifo_put(sc, 0xf0);
358                 fifo_put(sc, 0x11);
359                 break;
360         case 0xffeb:    /* Left Windows */
361                 fifo_put(sc, 0xe0);
362                 if (!down)
363                         fifo_put(sc, 0xf0);
364                 fifo_put(sc, 0x1f);
365                 break;
366         case 0xffec:    /* Right Windows */
367                 fifo_put(sc, 0xe0);
368                 if (!down)
369                         fifo_put(sc, 0xf0);
370                 fifo_put(sc, 0x27);
371                 break;
372         case 0xffbe:    /* F1 */
373                 if (!down)
374                         fifo_put(sc, 0xf0);
375                 fifo_put(sc, 0x05);
376                 break;
377         case 0xffbf:    /* F2 */
378                 if (!down)
379                         fifo_put(sc, 0xf0);
380                 fifo_put(sc, 0x06);
381                 break;
382         case 0xffc0:    /* F3 */
383                 if (!down)
384                         fifo_put(sc, 0xf0);
385                 fifo_put(sc, 0x04);
386                 break;
387         case 0xffc1:    /* F4 */
388                 if (!down)
389                         fifo_put(sc, 0xf0);
390                 fifo_put(sc, 0x0C);
391                 break;
392         case 0xffc2:    /* F5 */
393                 if (!down)
394                         fifo_put(sc, 0xf0);
395                 fifo_put(sc, 0x03);
396                 break;
397         case 0xffc3:    /* F6 */
398                 if (!down)
399                         fifo_put(sc, 0xf0);
400                 fifo_put(sc, 0x0B);
401                 break;
402         case 0xffc4:    /* F7 */
403                 if (!down)
404                         fifo_put(sc, 0xf0);
405                 fifo_put(sc, 0x83);
406                 break;
407         case 0xffc5:    /* F8 */
408                 if (!down)
409                         fifo_put(sc, 0xf0);
410                 fifo_put(sc, 0x0A);
411                 break;
412         case 0xffc6:    /* F9 */
413                 if (!down)
414                         fifo_put(sc, 0xf0);
415                 fifo_put(sc, 0x01);
416                 break;
417         case 0xffc7:    /* F10 */
418                 if (!down)
419                         fifo_put(sc, 0xf0);
420                 fifo_put(sc, 0x09);
421                 break;
422         case 0xffc8:    /* F11 */
423                 if (!down)
424                         fifo_put(sc, 0xf0);
425                 fifo_put(sc, 0x78);
426                 break;
427         case 0xffc9:    /* F12 */
428                 if (!down)
429                         fifo_put(sc, 0xf0);
430                 fifo_put(sc, 0x07);
431                 break;
432         case 0xffff:    /* Del */
433                 fifo_put(sc, 0xe0);
434                 if (!down)
435                         fifo_put(sc, 0xf0);
436                 fifo_put(sc, 0x71);
437                 break;
438         default:
439                 fprintf(stderr, "Unhandled ps2 keyboard keysym 0x%x\n",
440                      keysym);
441                 break;
442         }
443 }
444
445 static void
446 ps2kbd_event(int down, uint32_t keysym, void *arg)
447 {
448         struct ps2kbd_softc *sc = arg;
449         int fifo_full;
450
451         pthread_mutex_lock(&sc->mtx);
452         if (!sc->enabled) {
453                 pthread_mutex_unlock(&sc->mtx);
454                 return;
455         }
456         fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
457         ps2kbd_keysym_queue(sc, down, keysym);
458         pthread_mutex_unlock(&sc->mtx);
459
460         if (!fifo_full)
461                 atkbdc_event(sc->atkbdc_sc, 1);
462 }
463
464 struct ps2kbd_softc *
465 ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
466 {
467         struct ps2kbd_softc *sc;
468
469         sc = calloc(1, sizeof (struct ps2kbd_softc));
470         pthread_mutex_init(&sc->mtx, NULL);
471         fifo_init(sc);
472         sc->atkbdc_sc = atkbdc_sc;
473
474         console_kbd_register(ps2kbd_event, sc, 1);
475
476         return (sc);
477 }
478