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