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>
35 #include <machine/vmm_snapshot.h>
44 #include <pthread_np.h>
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
60 #define PS2KC_BAT_SUCCESS 0xaa
61 #define PS2KC_ACK 0xfa
63 #define PS2KBD_FIFOSZ 16
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 */
74 struct atkbdc_softc *atkbdc_sc;
80 uint8_t curcmd; /* current command for next byte */
83 #define SCANCODE_E0_PREFIX 1
84 struct extended_translation {
91 * FIXME: Pause/break and Print Screen/SysRq require special handling.
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 */
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,
184 /* ScanCode set1 to set2 lookup table */
185 const uint8_t keyset1to2_translations[128] = {
186 0, 0x76, 0x16, 0x1E, 0x26, 0x25, 0x2e, 0x36,
187 0x3d, 0x3e, 0x46, 0x45, 0x4e, 0x55, 0x66, 0x0d,
188 0x15, 0x1d, 0x24, 0x2d, 0x2c, 0x35, 0x3c, 0x43,
189 0x44, 0x4d, 0x54, 0x5b, 0x5a, 0x14, 0x1c, 0x1b,
190 0x23, 0x2b, 0x34, 0x33, 0x3b, 0x42, 0x4b, 0x4c,
191 0x52, 0x0e, 0x12, 0x5d, 0x1a, 0x22, 0x21, 0x2a,
192 0x32, 0x31, 0x3a, 0x41, 0x49, 0x4a, 0x59, 0x7c,
193 0x11, 0x29, 0x58, 0x05, 0x06, 0x04, 0x0c, 0x03,
194 0x0b, 0x83, 0x0a, 0x01, 0x09, 0x77, 0x7e, 0x6c,
195 0x75, 0x7d, 0x7b, 0x6b, 0x73, 0x74, 0x79, 0x69,
196 0x72, 0x7a, 0x70, 0x71, 0x84, 0x60, 0x61, 0x78,
197 0x07, 0x0f, 0x17, 0x1f, 0x27, 0x2f, 0x37, 0x3f,
198 0x47, 0x4f, 0x56, 0x5e, 0x08, 0x10, 0x18, 0x20,
199 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x57, 0x6f,
200 0x13, 0x19, 0x39, 0x51, 0x53, 0x5c, 0x5f, 0x62,
201 0x63, 0x64, 0x65, 0x67, 0x68, 0x6a, 0x6d, 0x6e,
205 fifo_init(struct ps2kbd_softc *sc)
210 fifo->size = sizeof(((struct fifo *)0)->buf);
214 fifo_reset(struct ps2kbd_softc *sc)
219 bzero(fifo, sizeof(struct fifo));
220 fifo->size = sizeof(((struct fifo *)0)->buf);
224 fifo_put(struct ps2kbd_softc *sc, uint8_t val)
229 if (fifo->num < fifo->size) {
230 fifo->buf[fifo->windex] = val;
231 fifo->windex = (fifo->windex + 1) % fifo->size;
237 fifo_get(struct ps2kbd_softc *sc, uint8_t *val)
243 *val = fifo->buf[fifo->rindex];
244 fifo->rindex = (fifo->rindex + 1) % fifo->size;
253 ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
257 pthread_mutex_lock(&sc->mtx);
258 retval = fifo_get(sc, val);
259 pthread_mutex_unlock(&sc->mtx);
265 ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
267 pthread_mutex_lock(&sc->mtx);
269 switch (sc->curcmd) {
270 case PS2KC_SET_TYPEMATIC:
271 fifo_put(sc, PS2KC_ACK);
273 case PS2KC_SET_SCANCODE_SET:
274 fifo_put(sc, PS2KC_ACK);
277 fifo_put(sc, PS2KC_ACK);
280 EPRINTLN("Unhandled ps2 keyboard current "
281 "command byte 0x%02x", val);
288 fifo_put(sc, PS2KC_ACK);
290 case PS2KC_RESET_DEV:
292 fifo_put(sc, PS2KC_ACK);
293 fifo_put(sc, PS2KC_BAT_SUCCESS);
297 fifo_put(sc, PS2KC_ACK);
302 fifo_put(sc, PS2KC_ACK);
304 case PS2KC_SET_TYPEMATIC:
306 fifo_put(sc, PS2KC_ACK);
308 case PS2KC_SEND_DEV_ID:
309 fifo_put(sc, PS2KC_ACK);
313 case PS2KC_SET_SCANCODE_SET:
315 fifo_put(sc, PS2KC_ACK);
318 fifo_put(sc, PS2KC_ECHO);
322 fifo_put(sc, PS2KC_ACK);
325 EPRINTLN("Unhandled ps2 keyboard command "
330 pthread_mutex_unlock(&sc->mtx);
334 * Translate keysym to type 2 scancode and insert into keyboard buffer.
337 ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
338 int down, uint32_t keysym, uint32_t keycode)
340 assert(pthread_mutex_isowned_np(&sc->mtx));
341 int e0_prefix, found;
343 const struct extended_translation *trans;
346 code = keyset1to2_translations[(uint8_t)(keycode & 0x7f)];
347 e0_prefix = ((keycode & 0x80) ? SCANCODE_E0_PREFIX : 0);
352 code = ascii_translations[keysym];
356 for (trans = &(extended_translations[0]); trans->keysym != 0;
358 if (keysym == trans->keysym) {
359 code = trans->scancode;
360 e0_prefix = trans->flags & SCANCODE_E0_PREFIX;
369 EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym);
381 ps2kbd_event(int down, uint32_t keysym, uint32_t keycode, void *arg)
383 struct ps2kbd_softc *sc = arg;
386 pthread_mutex_lock(&sc->mtx);
388 pthread_mutex_unlock(&sc->mtx);
391 fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
392 ps2kbd_keysym_queue(sc, down, keysym, keycode);
393 pthread_mutex_unlock(&sc->mtx);
396 atkbdc_event(sc->atkbdc_sc, 1);
399 struct ps2kbd_softc *
400 ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
402 struct ps2kbd_softc *sc;
404 sc = calloc(1, sizeof (struct ps2kbd_softc));
405 pthread_mutex_init(&sc->mtx, NULL);
407 sc->atkbdc_sc = atkbdc_sc;
409 console_kbd_register(ps2kbd_event, sc, 1);
414 #ifdef BHYVE_SNAPSHOT
416 ps2kbd_snapshot(struct ps2kbd_softc *sc, struct vm_snapshot_meta *meta)
420 SNAPSHOT_VAR_OR_LEAVE(sc->enabled, meta, ret, done);
421 SNAPSHOT_VAR_OR_LEAVE(sc->curcmd, meta, ret, done);