1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2015 Tycho Nightingale <[email protected]>
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
fifo_init(struct ps2kbd_softc * sc)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
fifo_reset(struct ps2kbd_softc * sc)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
fifo_put(struct ps2kbd_softc * sc,uint8_t val)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
fifo_get(struct ps2kbd_softc * sc,uint8_t * val)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
ps2kbd_read(struct ps2kbd_softc * sc,uint8_t * val)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
ps2kbd_write(struct ps2kbd_softc * sc,uint8_t val)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
ps2kbd_keysym_queue(struct ps2kbd_softc * sc,int down,uint32_t keysym)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
ps2kbd_event(int down,uint32_t keysym,void * arg)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 *
ps2kbd_init(struct atkbdc_softc * atkbdc_sc)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
ps2kbd_snapshot(struct ps2kbd_softc * sc,struct vm_snapshot_meta * meta)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
402