2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
5 * Copyright (c) 2015 Nahanni Systems Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/types.h>
42 #include <pthread_np.h>
53 /* keyboard device commands */
54 #define PS2KC_RESET_DEV 0xff
55 #define PS2KC_DISABLE 0xf5
56 #define PS2KC_ENABLE 0xf4
57 #define PS2KC_SET_TYPEMATIC 0xf3
58 #define PS2KC_SEND_DEV_ID 0xf2
59 #define PS2KC_SET_SCANCODE_SET 0xf0
60 #define PS2KC_ECHO 0xee
61 #define PS2KC_SET_LEDS 0xed
63 #define PS2KC_BAT_SUCCESS 0xaa
64 #define PS2KC_ACK 0xfa
66 #define PS2KBD_FIFOSZ 16
68 #define PS2KBD_LAYOUT_BASEDIR "/usr/share/bhyve/kbdlayout/"
70 #define MAX_PATHNAME 256
73 uint8_t buf
[PS2KBD_FIFOSZ
];
74 int rindex
; /* index to read from */
75 int windex
; /* index to write to */
76 int num
; /* number of bytes in the fifo */
77 int size
; /* size of the fifo */
81 struct atkbdc_softc
*atkbdc_sc
;
87 uint8_t curcmd
; /* current command for next byte */
90 #define SCANCODE_E0_PREFIX 1
91 struct extended_translation
{
98 * FIXME: Pause/break and Print Screen/SysRq require special handling.
100 static struct extended_translation extended_translations
[128] = {
101 {0xff08, 0x66, 0}, /* Back space */
102 {0xff09, 0x0d, 0}, /* Tab */
103 {0xff0d, 0x5a, 0}, /* Return */
104 {0xff1b, 0x76, 0}, /* Escape */
105 {0xff50, 0x6c, SCANCODE_E0_PREFIX
}, /* Home */
106 {0xff51, 0x6b, SCANCODE_E0_PREFIX
}, /* Left arrow */
107 {0xff52, 0x75, SCANCODE_E0_PREFIX
}, /* Up arrow */
108 {0xff53, 0x74, SCANCODE_E0_PREFIX
}, /* Right arrow */
109 {0xff54, 0x72, SCANCODE_E0_PREFIX
}, /* Down arrow */
110 {0xff55, 0x7d, SCANCODE_E0_PREFIX
}, /* PgUp */
111 {0xff56, 0x7a, SCANCODE_E0_PREFIX
}, /* PgDown */
112 {0xff57, 0x69, SCANCODE_E0_PREFIX
}, /* End */
113 {0xff63, 0x70, SCANCODE_E0_PREFIX
}, /* Ins */
114 {0xff8d, 0x5a, SCANCODE_E0_PREFIX
}, /* Keypad Enter */
115 {0xffe1, 0x12, 0}, /* Left shift */
116 {0xffe2, 0x59, 0}, /* Right shift */
117 {0xffe3, 0x14, 0}, /* Left control */
118 {0xffe4, 0x14, SCANCODE_E0_PREFIX
}, /* Right control */
119 /* {0xffe7, XXX}, Left meta */
120 /* {0xffe8, XXX}, Right meta */
121 {0xffe9, 0x11, 0}, /* Left alt */
122 {0xfe03, 0x11, SCANCODE_E0_PREFIX
}, /* AltGr */
123 {0xffea, 0x11, SCANCODE_E0_PREFIX
}, /* Right alt */
124 {0xffeb, 0x1f, SCANCODE_E0_PREFIX
}, /* Left Windows */
125 {0xffec, 0x27, SCANCODE_E0_PREFIX
}, /* Right Windows */
126 {0xffbe, 0x05, 0}, /* F1 */
127 {0xffbf, 0x06, 0}, /* F2 */
128 {0xffc0, 0x04, 0}, /* F3 */
129 {0xffc1, 0x0c, 0}, /* F4 */
130 {0xffc2, 0x03, 0}, /* F5 */
131 {0xffc3, 0x0b, 0}, /* F6 */
132 {0xffc4, 0x83, 0}, /* F7 */
133 {0xffc5, 0x0a, 0}, /* F8 */
134 {0xffc6, 0x01, 0}, /* F9 */
135 {0xffc7, 0x09, 0}, /* F10 */
136 {0xffc8, 0x78, 0}, /* F11 */
137 {0xffc9, 0x07, 0}, /* F12 */
138 {0xffff, 0x71, SCANCODE_E0_PREFIX
}, /* Del */
139 {0xff14, 0x7e, 0}, /* ScrollLock */
140 /* NumLock and Keypads*/
141 {0xff7f, 0x77, 0}, /* NumLock */
142 {0xffaf, 0x4a, SCANCODE_E0_PREFIX
}, /* Keypad slash */
143 {0xffaa, 0x7c, 0}, /* Keypad asterisk */
144 {0xffad, 0x7b, 0}, /* Keypad minus */
145 {0xffab, 0x79, 0}, /* Keypad plus */
146 {0xffb7, 0x6c, 0}, /* Keypad 7 */
147 {0xff95, 0x6c, 0}, /* Keypad home */
148 {0xffb8, 0x75, 0}, /* Keypad 8 */
149 {0xff97, 0x75, 0}, /* Keypad up arrow */
150 {0xffb9, 0x7d, 0}, /* Keypad 9 */
151 {0xff9a, 0x7d, 0}, /* Keypad PgUp */
152 {0xffb4, 0x6b, 0}, /* Keypad 4 */
153 {0xff96, 0x6b, 0}, /* Keypad left arrow */
154 {0xffb5, 0x73, 0}, /* Keypad 5 */
155 {0xff9d, 0x73, 0}, /* Keypad empty */
156 {0xffb6, 0x74, 0}, /* Keypad 6 */
157 {0xff98, 0x74, 0}, /* Keypad right arrow */
158 {0xffb1, 0x69, 0}, /* Keypad 1 */
159 {0xff9c, 0x69, 0}, /* Keypad end */
160 {0xffb2, 0x72, 0}, /* Keypad 2 */
161 {0xff99, 0x72, 0}, /* Keypad down arrow */
162 {0xffb3, 0x7a, 0}, /* Keypad 3 */
163 {0xff9b, 0x7a, 0}, /* Keypad PgDown */
164 {0xffb0, 0x70, 0}, /* Keypad 0 */
165 {0xff9e, 0x70, 0}, /* Keypad ins */
166 {0xffae, 0x71, 0}, /* Keypad . */
167 {0xff9f, 0x71, 0}, /* Keypad del */
168 {0, 0, 0} /* Terminator */
171 /* ASCII to type 2 scancode lookup table */
172 static uint8_t ascii_translations
[128] = {
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52,
178 0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a,
179 0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d,
180 0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a,
181 0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
182 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
183 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
184 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e,
185 0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
186 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
187 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
188 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00,
191 /* ScanCode set1 to set2 lookup table */
192 static const uint8_t keyset1to2_translations
[128] = {
193 0, 0x76, 0x16, 0x1E, 0x26, 0x25, 0x2e, 0x36,
194 0x3d, 0x3e, 0x46, 0x45, 0x4e, 0x55, 0x66, 0x0d,
195 0x15, 0x1d, 0x24, 0x2d, 0x2c, 0x35, 0x3c, 0x43,
196 0x44, 0x4d, 0x54, 0x5b, 0x5a, 0x14, 0x1c, 0x1b,
197 0x23, 0x2b, 0x34, 0x33, 0x3b, 0x42, 0x4b, 0x4c,
198 0x52, 0x0e, 0x12, 0x5d, 0x1a, 0x22, 0x21, 0x2a,
199 0x32, 0x31, 0x3a, 0x41, 0x49, 0x4a, 0x59, 0x7c,
200 0x11, 0x29, 0x58, 0x05, 0x06, 0x04, 0x0c, 0x03,
201 0x0b, 0x83, 0x0a, 0x01, 0x09, 0x77, 0x7e, 0x6c,
202 0x75, 0x7d, 0x7b, 0x6b, 0x73, 0x74, 0x79, 0x69,
203 0x72, 0x7a, 0x70, 0x71, 0x84, 0x60, 0x61, 0x78,
204 0x07, 0x0f, 0x17, 0x1f, 0x27, 0x2f, 0x37, 0x3f,
205 0x47, 0x4f, 0x56, 0x5e, 0x08, 0x10, 0x18, 0x20,
206 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x57, 0x6f,
207 0x13, 0x19, 0x39, 0x51, 0x53, 0x5c, 0x5f, 0x62,
208 0x63, 0x64, 0x65, 0x67, 0x68, 0x6a, 0x6d, 0x6e,
212 fifo_init(struct ps2kbd_softc
*sc
)
217 fifo
->size
= sizeof(((struct fifo
*)0)->buf
);
221 fifo_reset(struct ps2kbd_softc
*sc
)
226 bzero(fifo
, sizeof(struct fifo
));
227 fifo
->size
= sizeof(((struct fifo
*)0)->buf
);
231 fifo_put(struct ps2kbd_softc
*sc
, uint8_t val
)
236 if (fifo
->num
< fifo
->size
) {
237 fifo
->buf
[fifo
->windex
] = val
;
238 fifo
->windex
= (fifo
->windex
+ 1) % fifo
->size
;
244 fifo_get(struct ps2kbd_softc
*sc
, uint8_t *val
)
250 *val
= fifo
->buf
[fifo
->rindex
];
251 fifo
->rindex
= (fifo
->rindex
+ 1) % fifo
->size
;
260 ps2kbd_read(struct ps2kbd_softc
*sc
, uint8_t *val
)
264 pthread_mutex_lock(&sc
->mtx
);
265 retval
= fifo_get(sc
, val
);
266 pthread_mutex_unlock(&sc
->mtx
);
272 ps2kbd_write(struct ps2kbd_softc
*sc
, uint8_t val
)
274 pthread_mutex_lock(&sc
->mtx
);
276 switch (sc
->curcmd
) {
277 case PS2KC_SET_TYPEMATIC
:
278 fifo_put(sc
, PS2KC_ACK
);
280 case PS2KC_SET_SCANCODE_SET
:
281 fifo_put(sc
, PS2KC_ACK
);
284 fifo_put(sc
, PS2KC_ACK
);
287 EPRINTLN("Unhandled ps2 keyboard current "
288 "command byte 0x%02x", val
);
295 fifo_put(sc
, PS2KC_ACK
);
297 case PS2KC_RESET_DEV
:
299 fifo_put(sc
, PS2KC_ACK
);
300 fifo_put(sc
, PS2KC_BAT_SUCCESS
);
304 fifo_put(sc
, PS2KC_ACK
);
309 fifo_put(sc
, PS2KC_ACK
);
311 case PS2KC_SET_TYPEMATIC
:
313 fifo_put(sc
, PS2KC_ACK
);
315 case PS2KC_SEND_DEV_ID
:
316 fifo_put(sc
, PS2KC_ACK
);
320 case PS2KC_SET_SCANCODE_SET
:
322 fifo_put(sc
, PS2KC_ACK
);
325 fifo_put(sc
, PS2KC_ECHO
);
329 fifo_put(sc
, PS2KC_ACK
);
332 EPRINTLN("Unhandled ps2 keyboard command "
337 pthread_mutex_unlock(&sc
->mtx
);
341 * Translate keysym to type 2 scancode and insert into keyboard buffer.
344 ps2kbd_keysym_queue(struct ps2kbd_softc
*sc
,
345 int down
, uint32_t keysym
, uint32_t keycode
)
347 const struct extended_translation
*trans
;
348 int e0_prefix
, found
;
351 assert(pthread_mutex_isowned_np(&sc
->mtx
));
354 code
= keyset1to2_translations
[(uint8_t)(keycode
& 0x7f)];
355 e0_prefix
= ((keycode
& 0x80) ? SCANCODE_E0_PREFIX
: 0);
360 code
= ascii_translations
[keysym
];
364 for (trans
= &extended_translations
[0];
365 trans
->keysym
!= 0; trans
++) {
366 if (keysym
== trans
->keysym
) {
367 code
= trans
->scancode
;
368 e0_prefix
= trans
->flags
& SCANCODE_E0_PREFIX
;
377 EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym
);
389 ps2kbd_event(int down
, uint32_t keysym
, uint32_t keycode
, void *arg
)
391 struct ps2kbd_softc
*sc
= arg
;
394 pthread_mutex_lock(&sc
->mtx
);
396 pthread_mutex_unlock(&sc
->mtx
);
399 fifo_full
= sc
->fifo
.num
== PS2KBD_FIFOSZ
;
400 ps2kbd_keysym_queue(sc
, down
, keysym
, keycode
);
401 pthread_mutex_unlock(&sc
->mtx
);
404 atkbdc_event(sc
->atkbdc_sc
, 1);
408 ps2kbd_update_extended_translation(uint32_t keycode
, uint32_t scancode
, uint32_t prefix
)
413 if (extended_translations
[i
].keysym
== keycode
)
415 } while (extended_translations
[++i
].keysym
);
417 if (i
== (sizeof(extended_translations
) / sizeof(struct extended_translation
) - 1))
420 if (!extended_translations
[i
].keysym
) {
421 extended_translations
[i
].keysym
= keycode
;
423 extended_translations
[i
+1].keysym
= 0;
424 extended_translations
[i
+1].scancode
= 0;
425 extended_translations
[i
+1].flags
= 0;
428 extended_translations
[i
].scancode
= (uint8_t)(scancode
& 0xff);
429 extended_translations
[i
].flags
= (prefix
? SCANCODE_E0_PREFIX
: 0);
433 ps2kbd_setkbdlayout(void)
437 char path
[MAX_PATHNAME
];
438 char *buf
, *next
, *line
;
442 uint32_t keycode
, scancode
, prefix
;
444 snprintf(path
, MAX_PATHNAME
, PS2KBD_LAYOUT_BASEDIR
"%s", get_config_value("keyboard.layout") );
446 err
= stat(path
, &sb
);
450 buf
= (char *)malloc(sizeof(char) * sb
.st_size
);
454 fd
= open(path
, O_RDONLY
);
458 sz
= read(fd
, buf
, sb
.st_size
);
462 if (sz
< 0 || sz
!= sb
.st_size
)
466 while ((line
= strsep(&next
, "\n")) != NULL
) {
467 if (sscanf(line
, "'%c',%x;", &ascii
, &scancode
) == 2) {
469 ascii_translations
[ascii
] = (uint8_t)(scancode
& 0xff);
470 } else if (sscanf(line
, "%x,%x,%x;", &keycode
, &scancode
, &prefix
) == 3 ) {
471 ps2kbd_update_extended_translation(keycode
, scancode
, prefix
);
472 } else if (sscanf(line
, "%x,%x;", &keycode
, &scancode
) == 2) {
474 ascii_translations
[(uint8_t)(keycode
& 0xff)] = (uint8_t)(scancode
& 0xff);
476 ps2kbd_update_extended_translation(keycode
, scancode
, 0);
484 struct ps2kbd_softc
*
485 ps2kbd_init(struct atkbdc_softc
*atkbdc_sc
)
487 struct ps2kbd_softc
*sc
;
489 if (get_config_value("keyboard.layout") != NULL
)
490 ps2kbd_setkbdlayout();
492 sc
= calloc(1, sizeof (struct ps2kbd_softc
));
493 pthread_mutex_init(&sc
->mtx
, NULL
);
495 sc
->atkbdc_sc
= atkbdc_sc
;
497 console_kbd_register(ps2kbd_event
, sc
, 1);