Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bhyve/amd64/ps2kbd.c
105686 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
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/types.h>
31
#include <sys/stat.h>
32
33
#include <machine/vmm_snapshot.h>
34
35
#include <assert.h>
36
#include <stdbool.h>
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include <strings.h>
41
#include <pthread.h>
42
#include <pthread_np.h>
43
#include <unistd.h>
44
#include <fcntl.h>
45
46
#include "atkbdc.h"
47
#include "bhyverun.h"
48
#include "config.h"
49
#include "console.h"
50
#include "debug.h"
51
#include "ps2kbd.h"
52
53
/* keyboard device commands */
54
#define PS2KC_RESET_DEV 0xff
55
#define PS2KC_SET_DEFAULTS 0xf6
56
#define PS2KC_DISABLE 0xf5
57
#define PS2KC_ENABLE 0xf4
58
#define PS2KC_SET_TYPEMATIC 0xf3
59
#define PS2KC_SEND_DEV_ID 0xf2
60
#define PS2KC_SET_SCANCODE_SET 0xf0
61
#define PS2KC_ECHO 0xee
62
#define PS2KC_SET_LEDS 0xed
63
64
#define PS2KC_BAT_SUCCESS 0xaa
65
#define PS2KC_ACK 0xfa
66
67
#define PS2KBD_FIFOSZ 16
68
69
#define PS2KBD_LAYOUT_BASEDIR "/usr/share/bhyve/kbdlayout/"
70
71
#define MAX_PATHNAME 256
72
73
struct fifo {
74
uint8_t buf[PS2KBD_FIFOSZ];
75
int rindex; /* index to read from */
76
int windex; /* index to write to */
77
int num; /* number of bytes in the fifo */
78
int size; /* size of the fifo */
79
};
80
81
struct ps2kbd_softc {
82
struct atkbdc_softc *atkbdc_sc;
83
pthread_mutex_t mtx;
84
85
bool enabled;
86
struct fifo fifo;
87
88
uint8_t curcmd; /* current command for next byte */
89
};
90
91
#define SCANCODE_E0_PREFIX 1
92
struct extended_translation {
93
uint32_t keysym;
94
uint8_t scancode;
95
int flags;
96
};
97
98
/*
99
* FIXME: Pause/break and Print Screen/SysRq require special handling.
100
*/
101
static struct extended_translation extended_translations[128] = {
102
{0xff08, 0x66, 0}, /* Back space */
103
{0xff09, 0x0d, 0}, /* Tab */
104
{0xff0d, 0x5a, 0}, /* Return */
105
{0xff1b, 0x76, 0}, /* Escape */
106
{0xff50, 0x6c, SCANCODE_E0_PREFIX}, /* Home */
107
{0xff51, 0x6b, SCANCODE_E0_PREFIX}, /* Left arrow */
108
{0xff52, 0x75, SCANCODE_E0_PREFIX}, /* Up arrow */
109
{0xff53, 0x74, SCANCODE_E0_PREFIX}, /* Right arrow */
110
{0xff54, 0x72, SCANCODE_E0_PREFIX}, /* Down arrow */
111
{0xff55, 0x7d, SCANCODE_E0_PREFIX}, /* PgUp */
112
{0xff56, 0x7a, SCANCODE_E0_PREFIX}, /* PgDown */
113
{0xff57, 0x69, SCANCODE_E0_PREFIX}, /* End */
114
{0xff63, 0x70, SCANCODE_E0_PREFIX}, /* Ins */
115
{0xff8d, 0x5a, SCANCODE_E0_PREFIX}, /* Keypad Enter */
116
{0xffe1, 0x12, 0}, /* Left shift */
117
{0xffe2, 0x59, 0}, /* Right shift */
118
{0xffe3, 0x14, 0}, /* Left control */
119
{0xffe4, 0x14, SCANCODE_E0_PREFIX}, /* Right control */
120
/* {0xffe7, XXX}, Left meta */
121
/* {0xffe8, XXX}, Right meta */
122
{0xffe9, 0x11, 0}, /* Left alt */
123
{0xfe03, 0x11, SCANCODE_E0_PREFIX}, /* AltGr */
124
{0xffea, 0x11, SCANCODE_E0_PREFIX}, /* Right alt */
125
{0xffeb, 0x1f, SCANCODE_E0_PREFIX}, /* Left Windows */
126
{0xffec, 0x27, SCANCODE_E0_PREFIX}, /* Right Windows */
127
{0xffbe, 0x05, 0}, /* F1 */
128
{0xffbf, 0x06, 0}, /* F2 */
129
{0xffc0, 0x04, 0}, /* F3 */
130
{0xffc1, 0x0c, 0}, /* F4 */
131
{0xffc2, 0x03, 0}, /* F5 */
132
{0xffc3, 0x0b, 0}, /* F6 */
133
{0xffc4, 0x83, 0}, /* F7 */
134
{0xffc5, 0x0a, 0}, /* F8 */
135
{0xffc6, 0x01, 0}, /* F9 */
136
{0xffc7, 0x09, 0}, /* F10 */
137
{0xffc8, 0x78, 0}, /* F11 */
138
{0xffc9, 0x07, 0}, /* F12 */
139
{0xffff, 0x71, SCANCODE_E0_PREFIX}, /* Del */
140
{0xff14, 0x7e, 0}, /* ScrollLock */
141
/* NumLock and Keypads*/
142
{0xff7f, 0x77, 0}, /* NumLock */
143
{0xffaf, 0x4a, SCANCODE_E0_PREFIX}, /* Keypad slash */
144
{0xffaa, 0x7c, 0}, /* Keypad asterisk */
145
{0xffad, 0x7b, 0}, /* Keypad minus */
146
{0xffab, 0x79, 0}, /* Keypad plus */
147
{0xffb7, 0x6c, 0}, /* Keypad 7 */
148
{0xff95, 0x6c, 0}, /* Keypad home */
149
{0xffb8, 0x75, 0}, /* Keypad 8 */
150
{0xff97, 0x75, 0}, /* Keypad up arrow */
151
{0xffb9, 0x7d, 0}, /* Keypad 9 */
152
{0xff9a, 0x7d, 0}, /* Keypad PgUp */
153
{0xffb4, 0x6b, 0}, /* Keypad 4 */
154
{0xff96, 0x6b, 0}, /* Keypad left arrow */
155
{0xffb5, 0x73, 0}, /* Keypad 5 */
156
{0xff9d, 0x73, 0}, /* Keypad empty */
157
{0xffb6, 0x74, 0}, /* Keypad 6 */
158
{0xff98, 0x74, 0}, /* Keypad right arrow */
159
{0xffb1, 0x69, 0}, /* Keypad 1 */
160
{0xff9c, 0x69, 0}, /* Keypad end */
161
{0xffb2, 0x72, 0}, /* Keypad 2 */
162
{0xff99, 0x72, 0}, /* Keypad down arrow */
163
{0xffb3, 0x7a, 0}, /* Keypad 3 */
164
{0xff9b, 0x7a, 0}, /* Keypad PgDown */
165
{0xffb0, 0x70, 0}, /* Keypad 0 */
166
{0xff9e, 0x70, 0}, /* Keypad ins */
167
{0xffae, 0x71, 0}, /* Keypad . */
168
{0xff9f, 0x71, 0}, /* Keypad del */
169
{0, 0, 0} /* Terminator */
170
};
171
172
/* ASCII to type 2 scancode lookup table */
173
static uint8_t ascii_translations[128] = {
174
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178
0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52,
179
0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a,
180
0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d,
181
0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a,
182
0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
183
0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
184
0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
185
0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e,
186
0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
187
0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
188
0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
189
0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00,
190
};
191
192
/* ScanCode set1 to set2 lookup table */
193
static const uint8_t keyset1to2_translations[128] = {
194
0, 0x76, 0x16, 0x1E, 0x26, 0x25, 0x2e, 0x36,
195
0x3d, 0x3e, 0x46, 0x45, 0x4e, 0x55, 0x66, 0x0d,
196
0x15, 0x1d, 0x24, 0x2d, 0x2c, 0x35, 0x3c, 0x43,
197
0x44, 0x4d, 0x54, 0x5b, 0x5a, 0x14, 0x1c, 0x1b,
198
0x23, 0x2b, 0x34, 0x33, 0x3b, 0x42, 0x4b, 0x4c,
199
0x52, 0x0e, 0x12, 0x5d, 0x1a, 0x22, 0x21, 0x2a,
200
0x32, 0x31, 0x3a, 0x41, 0x49, 0x4a, 0x59, 0x7c,
201
0x11, 0x29, 0x58, 0x05, 0x06, 0x04, 0x0c, 0x03,
202
0x0b, 0x83, 0x0a, 0x01, 0x09, 0x77, 0x7e, 0x6c,
203
0x75, 0x7d, 0x7b, 0x6b, 0x73, 0x74, 0x79, 0x69,
204
0x72, 0x7a, 0x70, 0x71, 0x84, 0x60, 0x61, 0x78,
205
0x07, 0x0f, 0x17, 0x1f, 0x27, 0x2f, 0x37, 0x3f,
206
0x47, 0x4f, 0x56, 0x5e, 0x08, 0x10, 0x18, 0x20,
207
0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x57, 0x6f,
208
0x13, 0x19, 0x39, 0x51, 0x53, 0x5c, 0x5f, 0x62,
209
0x63, 0x64, 0x65, 0x67, 0x68, 0x6a, 0x6d, 0x6e,
210
};
211
212
static void
213
fifo_init(struct ps2kbd_softc *sc)
214
{
215
struct fifo *fifo;
216
217
fifo = &sc->fifo;
218
fifo->size = sizeof(((struct fifo *)0)->buf);
219
}
220
221
static void
222
fifo_reset(struct ps2kbd_softc *sc)
223
{
224
struct fifo *fifo;
225
226
fifo = &sc->fifo;
227
bzero(fifo, sizeof(struct fifo));
228
fifo->size = sizeof(((struct fifo *)0)->buf);
229
}
230
231
static void
232
fifo_put(struct ps2kbd_softc *sc, uint8_t val)
233
{
234
struct fifo *fifo;
235
236
fifo = &sc->fifo;
237
if (fifo->num < fifo->size) {
238
fifo->buf[fifo->windex] = val;
239
fifo->windex = (fifo->windex + 1) % fifo->size;
240
fifo->num++;
241
}
242
}
243
244
static int
245
fifo_get(struct ps2kbd_softc *sc, uint8_t *val)
246
{
247
struct fifo *fifo;
248
249
fifo = &sc->fifo;
250
if (fifo->num > 0) {
251
*val = fifo->buf[fifo->rindex];
252
fifo->rindex = (fifo->rindex + 1) % fifo->size;
253
fifo->num--;
254
return (0);
255
}
256
257
return (-1);
258
}
259
260
int
261
ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
262
{
263
int retval;
264
265
pthread_mutex_lock(&sc->mtx);
266
retval = fifo_get(sc, val);
267
pthread_mutex_unlock(&sc->mtx);
268
269
return (retval);
270
}
271
272
void
273
ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
274
{
275
pthread_mutex_lock(&sc->mtx);
276
if (sc->curcmd) {
277
switch (sc->curcmd) {
278
case PS2KC_SET_TYPEMATIC:
279
fifo_put(sc, PS2KC_ACK);
280
break;
281
case PS2KC_SET_SCANCODE_SET:
282
fifo_put(sc, PS2KC_ACK);
283
break;
284
case PS2KC_SET_LEDS:
285
fifo_put(sc, PS2KC_ACK);
286
break;
287
default:
288
EPRINTLN("Unhandled ps2 keyboard current "
289
"command byte 0x%02x", val);
290
break;
291
}
292
sc->curcmd = 0;
293
} else {
294
switch (val) {
295
case 0x00:
296
fifo_put(sc, PS2KC_ACK);
297
break;
298
case PS2KC_RESET_DEV:
299
fifo_reset(sc);
300
fifo_put(sc, PS2KC_ACK);
301
fifo_put(sc, PS2KC_BAT_SUCCESS);
302
break;
303
case PS2KC_SET_DEFAULTS:
304
fifo_reset(sc);
305
fifo_put(sc, PS2KC_ACK);
306
break;
307
case PS2KC_DISABLE:
308
sc->enabled = false;
309
fifo_put(sc, PS2KC_ACK);
310
break;
311
case PS2KC_ENABLE:
312
sc->enabled = true;
313
fifo_reset(sc);
314
fifo_put(sc, PS2KC_ACK);
315
break;
316
case PS2KC_SET_TYPEMATIC:
317
sc->curcmd = val;
318
fifo_put(sc, PS2KC_ACK);
319
break;
320
case PS2KC_SEND_DEV_ID:
321
fifo_put(sc, PS2KC_ACK);
322
fifo_put(sc, 0xab);
323
fifo_put(sc, 0x83);
324
break;
325
case PS2KC_SET_SCANCODE_SET:
326
sc->curcmd = val;
327
fifo_put(sc, PS2KC_ACK);
328
break;
329
case PS2KC_ECHO:
330
fifo_put(sc, PS2KC_ECHO);
331
break;
332
case PS2KC_SET_LEDS:
333
sc->curcmd = val;
334
fifo_put(sc, PS2KC_ACK);
335
break;
336
default:
337
EPRINTLN("Unhandled ps2 keyboard command "
338
"0x%02x", val);
339
break;
340
}
341
}
342
pthread_mutex_unlock(&sc->mtx);
343
}
344
345
/*
346
* Translate keysym to type 2 scancode and insert into keyboard buffer.
347
*/
348
static void
349
ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
350
int down, uint32_t keysym, uint32_t keycode)
351
{
352
const struct extended_translation *trans;
353
int e0_prefix, found;
354
uint8_t code;
355
356
assert(pthread_mutex_isowned_np(&sc->mtx));
357
358
if (keycode) {
359
code = keyset1to2_translations[(uint8_t)(keycode & 0x7f)];
360
e0_prefix = ((keycode & 0x80) ? SCANCODE_E0_PREFIX : 0);
361
found = 1;
362
} else {
363
found = 0;
364
if (keysym < 0x80) {
365
code = ascii_translations[keysym];
366
e0_prefix = 0;
367
found = 1;
368
} else {
369
for (trans = &extended_translations[0];
370
trans->keysym != 0; trans++) {
371
if (keysym == trans->keysym) {
372
code = trans->scancode;
373
e0_prefix = trans->flags & SCANCODE_E0_PREFIX;
374
found = 1;
375
break;
376
}
377
}
378
}
379
}
380
381
if (!found) {
382
EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym);
383
return;
384
}
385
386
if (e0_prefix)
387
fifo_put(sc, 0xe0);
388
if (!down)
389
fifo_put(sc, 0xf0);
390
fifo_put(sc, code);
391
}
392
393
static void
394
ps2kbd_event(int down, uint32_t keysym, uint32_t keycode, void *arg)
395
{
396
struct ps2kbd_softc *sc = arg;
397
int fifo_full;
398
399
pthread_mutex_lock(&sc->mtx);
400
if (!sc->enabled) {
401
pthread_mutex_unlock(&sc->mtx);
402
return;
403
}
404
fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
405
ps2kbd_keysym_queue(sc, down, keysym, keycode);
406
pthread_mutex_unlock(&sc->mtx);
407
408
if (!fifo_full)
409
atkbdc_event(sc->atkbdc_sc, 1);
410
}
411
412
static void
413
ps2kbd_update_extended_translation(uint32_t keycode, uint32_t scancode, uint32_t prefix)
414
{
415
int i = 0;
416
417
do {
418
if (extended_translations[i].keysym == keycode)
419
break;
420
} while (extended_translations[++i].keysym);
421
422
if (i == (sizeof(extended_translations) / sizeof(struct extended_translation) - 1))
423
return;
424
425
if (!extended_translations[i].keysym) {
426
extended_translations[i].keysym = keycode;
427
428
extended_translations[i+1].keysym = 0;
429
extended_translations[i+1].scancode = 0;
430
extended_translations[i+1].flags = 0;
431
}
432
433
extended_translations[i].scancode = (uint8_t)(scancode & 0xff);
434
extended_translations[i].flags = (prefix ? SCANCODE_E0_PREFIX : 0);
435
}
436
437
static void
438
ps2kbd_setkbdlayout(void)
439
{
440
int err;
441
int fd;
442
char path[MAX_PATHNAME];
443
char *buf, *next, *line;
444
struct stat sb;
445
ssize_t sz;
446
uint8_t ascii;
447
uint32_t keycode, scancode, prefix;
448
449
snprintf(path, MAX_PATHNAME, PS2KBD_LAYOUT_BASEDIR"%s", get_config_value("keyboard.layout") );
450
451
err = stat(path, &sb);
452
if (err)
453
return;
454
455
buf = (char *)malloc(sizeof(char) * sb.st_size);
456
if (buf == NULL)
457
return;
458
459
fd = open(path, O_RDONLY);
460
if (fd == -1)
461
goto out;
462
463
sz = read(fd, buf, sb.st_size);
464
465
close(fd);
466
467
if (sz < 0 || sz != sb.st_size)
468
goto out;
469
470
next = buf;
471
while ((line = strsep(&next, "\n")) != NULL) {
472
if (sscanf(line, "'%c',%x;", &ascii, &scancode) == 2) {
473
if (ascii < 0x80)
474
ascii_translations[ascii] = (uint8_t)(scancode & 0xff);
475
} else if (sscanf(line, "%x,%x,%x;", &keycode, &scancode, &prefix) == 3 ) {
476
ps2kbd_update_extended_translation(keycode, scancode, prefix);
477
} else if (sscanf(line, "%x,%x;", &keycode, &scancode) == 2) {
478
if (keycode < 0x80)
479
ascii_translations[(uint8_t)(keycode & 0xff)] = (uint8_t)(scancode & 0xff);
480
else
481
ps2kbd_update_extended_translation(keycode, scancode, 0);
482
}
483
}
484
485
out:
486
free(buf);
487
}
488
489
struct ps2kbd_softc *
490
ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
491
{
492
struct ps2kbd_softc *sc;
493
494
if (get_config_value("keyboard.layout") != NULL)
495
ps2kbd_setkbdlayout();
496
497
sc = calloc(1, sizeof (struct ps2kbd_softc));
498
pthread_mutex_init(&sc->mtx, NULL);
499
fifo_init(sc);
500
sc->atkbdc_sc = atkbdc_sc;
501
502
console_kbd_register(ps2kbd_event, sc, 1);
503
504
return (sc);
505
}
506
507
#ifdef BHYVE_SNAPSHOT
508
int
509
ps2kbd_snapshot(struct ps2kbd_softc *sc, struct vm_snapshot_meta *meta)
510
{
511
int ret;
512
513
SNAPSHOT_VAR_OR_LEAVE(sc->enabled, meta, ret, done);
514
SNAPSHOT_VAR_OR_LEAVE(sc->curcmd, meta, ret, done);
515
516
done:
517
return (ret);
518
}
519
#endif
520
521
522