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 <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
fifo_init(struct ps2kbd_softc * sc)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
fifo_reset(struct ps2kbd_softc * sc)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
fifo_put(struct ps2kbd_softc * sc,uint8_t val)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
fifo_get(struct ps2kbd_softc * sc,uint8_t * val)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
ps2kbd_read(struct ps2kbd_softc * sc,uint8_t * val)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
ps2kbd_write(struct ps2kbd_softc * sc,uint8_t val)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
ps2kbd_keysym_queue(struct ps2kbd_softc * sc,int down,uint32_t keysym)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
ps2kbd_event(int down,uint32_t keysym,void * arg)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 *
ps2kbd_init(struct atkbdc_softc * atkbdc_sc)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
384