1 /* $NetBSD: pckbd.c,v 1.39 2024/02/09 22:08:36 andvar Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 2009 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*-
33 * Copyright (c) 1990 The Regents of the University of California.
34 * All rights reserved.
35 *
36 * This code is derived from software contributed to Berkeley by
37 * William Jolitz and Don Ahn.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 * @(#)pccons.c 5.11 (Berkeley) 5/21/91
64 */
65
66 /*
67 * code to work keyboard for PC-style console
68 */
69
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: pckbd.c,v 1.39 2024/02/09 22:08:36 andvar Exp $");
72
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/device.h>
76 #include <sys/malloc.h>
77 #include <sys/ioctl.h>
78
79 #include <sys/bus.h>
80
81 #include <dev/pckbport/pckbportvar.h>
82
83 #include <dev/wscons/wsconsio.h>
84 #include <dev/wscons/wskbdvar.h>
85 #include <dev/wscons/wsksymdef.h>
86 #include <dev/wscons/wsksymvar.h>
87
88 #include <dev/pckbport/pckbdreg.h>
89 #include <dev/pckbport/pckbdvar.h>
90 #include <dev/pckbport/wskbdmap_mfii.h>
91
92 #include "locators.h"
93
94 #include "opt_pckbd_layout.h"
95 #include "opt_pckbd_cnattach_may_fail.h"
96 #include "opt_wsdisplay_compat.h"
97
98 struct pckbd_internal {
99 int t_isconsole;
100 pckbport_tag_t t_kbctag;
101 pckbport_slot_t t_kbcslot;
102
103 int t_translating;
104
105 int t_lastchar;
106 int t_extended0;
107 int t_extended1;
108 int t_releasing;
109
110 struct pckbd_softc *t_sc; /* back pointer */
111 };
112
113 struct pckbd_softc {
114 device_t sc_dev;
115
116 struct pckbd_internal *id;
117 int sc_enabled;
118
119 int sc_ledstate;
120
121 device_t sc_wskbddev;
122 #ifdef WSDISPLAY_COMPAT_RAWKBD
123 int rawkbd;
124 #endif
125 };
126
127 int pckbdprobe(device_t, cfdata_t, void *);
128 void pckbdattach(device_t, device_t, void *);
129
130 CFATTACH_DECL_NEW(pckbd, sizeof(struct pckbd_softc),
131 pckbdprobe, pckbdattach, NULL, NULL);
132
133 int pckbd_enable(void *, int);
134 void pckbd_set_leds(void *, int);
135 int pckbd_ioctl(void *, u_long, void *, int, struct lwp *);
136
137 const struct wskbd_accessops pckbd_accessops = {
138 .enable = pckbd_enable,
139 .set_leds = pckbd_set_leds,
140 .ioctl = pckbd_ioctl,
141 };
142
143 void pckbd_cngetc(void *, u_int *, int *);
144 void pckbd_cnpollc(void *, int);
145 void pckbd_cnbell(void *, u_int, u_int, u_int);
146
147 const struct wskbd_consops pckbd_consops = {
148 .getc = pckbd_cngetc,
149 .pollc = pckbd_cnpollc,
150 .bell = pckbd_cnbell,
151 };
152
153 const struct wskbd_mapdata pckbd_keymapdata = {
154 .keydesc = pckbd_keydesctab,
155 #ifdef PCKBD_LAYOUT
156 .layout = PCKBD_LAYOUT,
157 #else
158 .layout = KB_US,
159 #endif
160 };
161
162 /*
163 * Hackish support for a bell on the PC Keyboard; when a suitable beeper
164 * is found, it attaches itself into the pckbd driver here.
165 */
166 void (*pckbd_bell_fn)(void *, u_int, u_int, u_int, int);
167 void *pckbd_bell_fn_arg;
168
169 void pckbd_bell(u_int, u_int, u_int, int);
170
171 int pckbd_scancode_translate(struct pckbd_internal *, int);
172 int pckbd_set_xtscancode(pckbport_tag_t, pckbport_slot_t,
173 struct pckbd_internal *);
174 int pckbd_init(struct pckbd_internal *, pckbport_tag_t, pckbport_slot_t,
175 int);
176 void pckbd_input(void *, int);
177
178 struct pckbd_internal pckbd_consdata;
179
180 int
pckbd_set_xtscancode(pckbport_tag_t kbctag,pckbport_slot_t kbcslot,struct pckbd_internal * id)181 pckbd_set_xtscancode(pckbport_tag_t kbctag, pckbport_slot_t kbcslot,
182 struct pckbd_internal *id)
183 {
184 int xt, res = 0;
185 u_char cmd[2];
186
187 /*
188 * Some keyboard/8042 combinations do not seem to work if the keyboard
189 * is set to table 1; in fact, it would appear that some keyboards just
190 * ignore the command altogether. So by default, we use the AT scan
191 * codes and have the 8042 translate them. Unfortunately, this is
192 * known to not work on some PS/2 machines. We try desperately to deal
193 * with this by checking the (lack of a) translate bit in the 8042 and
194 * attempting to set the keyboard to XT mode. If this all fails, well,
195 * tough luck. If the PCKBC_CANT_TRANSLATE pckbc flag was set, we
196 * enable software translation.
197 *
198 * XXX It would perhaps be a better choice to just use AT scan codes
199 * and not bother with this.
200 */
201 xt = pckbport_xt_translation(kbctag, kbcslot, 1);
202 if (xt == 1) {
203 /* The 8042 is translating for us; use AT codes. */
204 cmd[0] = KBC_SETTABLE;
205 cmd[1] = 2;
206 res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0);
207 if (res) {
208 u_char cmdb[1];
209 aprint_debug("%s: error setting scanset 2\n", __func__);
210 /*
211 * XXX at least one keyboard is reported to lock up
212 * if a "set table" is attempted, thus the "reset".
213 * XXX ignore errors, scanset 2 should be
214 * default anyway.
215 */
216 cmdb[0] = KBC_RESET;
217 (void)pckbport_poll_cmd(kbctag, kbcslot, cmdb, 1, 1,
218 0, 1);
219 pckbport_flush(kbctag, kbcslot);
220 res = 0;
221 }
222 if (id != NULL)
223 id->t_translating = 1;
224 } else if (xt == -1) {
225 /* Software translation required */
226 if (id != NULL)
227 id->t_translating = 0;
228 } else {
229 /* Stupid 8042; set keyboard to XT codes. */
230 cmd[0] = KBC_SETTABLE;
231 cmd[1] = 1;
232 res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0);
233 if (res)
234 aprint_debug("%s: error setting scanset 1\n", __func__);
235 if (id != NULL)
236 id->t_translating = 1;
237 }
238 return res;
239 }
240
241 static int
pckbd_is_console(pckbport_tag_t tag,pckbport_slot_t slot)242 pckbd_is_console(pckbport_tag_t tag, pckbport_slot_t slot)
243 {
244
245 return pckbd_consdata.t_isconsole &&
246 tag == pckbd_consdata.t_kbctag && slot == pckbd_consdata.t_kbcslot;
247 }
248
249 static bool
pckbd_suspend(device_t dv,const pmf_qual_t * qual)250 pckbd_suspend(device_t dv, const pmf_qual_t *qual)
251 {
252 struct pckbd_softc *sc = device_private(dv);
253 u_char cmd[1];
254 int res;
255
256 /* XXX duped from pckbd_enable, but we want to disable
257 * it even if it's the console kbd
258 */
259 cmd[0] = KBC_DISABLE;
260 res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
261 cmd, 1, 0, 1, 0);
262 if (res)
263 return false;
264
265 pckbport_slot_enable(sc->id->t_kbctag,
266 sc->id->t_kbcslot, 0);
267
268 sc->sc_enabled = 0;
269 return true;
270 }
271
272 static bool
pckbd_resume(device_t dv,const pmf_qual_t * qual)273 pckbd_resume(device_t dv, const pmf_qual_t *qual)
274 {
275 struct pckbd_softc *sc = device_private(dv);
276 u_char cmd[1], resp[1];
277 int res;
278
279 /* XXX jmcneill reset the keyboard */
280 pckbport_flush(sc->id->t_kbctag, sc->id->t_kbcslot);
281
282 cmd[0] = KBC_RESET;
283 res = pckbport_poll_cmd(sc->id->t_kbctag,
284 sc->id->t_kbcslot, cmd, 1, 1, resp, 1);
285 if (res)
286 aprint_debug("%s: reset error %d\n", __func__, res);
287 if (resp[0] != KBR_RSTDONE)
288 printf("%s: reset response 0x%x\n", __func__, resp[0]);
289
290 pckbport_flush(sc->id->t_kbctag, sc->id->t_kbcslot);
291
292 pckbd_enable(sc, 1);
293
294 return true;
295 }
296
297 /*
298 * these are three bad jokes
299 */
300 static bool
check_keyboard_by_id(struct pckbport_attach_args * pa)301 check_keyboard_by_id(struct pckbport_attach_args *pa)
302 {
303 u_char cmd[1], resp[2];
304 int res;
305
306 cmd[0] = KBC_GETID;
307 res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 0);
308 if (res) {
309 aprint_debug("%s: getid failed with %d\n", __func__, res);
310 return false;
311 }
312
313 switch (resp[0]) {
314 case 0xab: case 0xac: /* Regular and NCD Sun keyboards */
315 case 0x2b: case 0x5d: /* Trust keyboard, raw and translated */
316 case 0x60: case 0x47: /* NMB SGI keyboard, raw and translated */
317 return true;
318 default:
319 aprint_debug("%s: getid returned %#x\n", __func__, resp[0]);
320 return false;
321 }
322
323 }
324
325 int
pckbdprobe(device_t parent,cfdata_t cf,void * aux)326 pckbdprobe(device_t parent, cfdata_t cf, void *aux)
327 {
328 struct pckbport_attach_args *pa = aux;
329 int res;
330 u_char cmd[1], resp[1];
331
332 /*
333 * XXX There are rumours that a keyboard can be connected
334 * to the aux port as well. For me, this didn't work.
335 * For further experiments, allow it if explicitly
336 * wired in the config file.
337 */
338 if ((pa->pa_slot != PCKBPORT_KBD_SLOT) &&
339 (cf->cf_loc[PCKBPORTCF_SLOT] == PCKBPORTCF_SLOT_DEFAULT))
340 return 0;
341
342 /* Flush any garbage. */
343 pckbport_flush(pa->pa_tag, pa->pa_slot);
344
345 /* Reset the keyboard. */
346 cmd[0] = KBC_RESET;
347 res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1);
348 if (res) {
349 aprint_debug("%s: reset error %d\n", __func__, res);
350
351 /*
352 * On Chromebooks reset fails but otherwise the controller
353 * works fine.
354 * Check keyboard IDs similar to Linux and Haiku.
355 * FreeBSD's approach here is to skip probing if
356 * coreboot is detected which is suboptimal as coreboot
357 * also supports some mac models which have no PC controller
358 */
359 if (check_keyboard_by_id(pa)) {
360 if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, NULL))
361 return 0;
362 return 2;
363 }
364
365 /*
366 * There is probably no keyboard connected.
367 * Let the probe succeed if the keyboard is used
368 * as console input - it can be connected later.
369 */
370 return pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0;
371 }
372 if (resp[0] != KBR_RSTDONE) {
373 printf("%s: reset response %#x\n", __func__, resp[0]);
374
375 if (check_keyboard_by_id(pa)) {
376 if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, NULL))
377 return 0;
378 return 2;
379 }
380
381 return 0;
382 }
383
384 /*
385 * Some keyboards seem to leave a second ack byte after the reset.
386 * This is kind of stupid, but we account for them anyway by just
387 * flushing the buffer.
388 */
389 pckbport_flush(pa->pa_tag, pa->pa_slot);
390
391 if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, NULL))
392 return 0;
393
394 return 2;
395 }
396
397 void
pckbdattach(device_t parent,device_t self,void * aux)398 pckbdattach(device_t parent, device_t self, void *aux)
399 {
400 struct pckbd_softc *sc = device_private(self);
401 struct pckbport_attach_args *pa = aux;
402 struct wskbddev_attach_args a;
403 int isconsole;
404 u_char cmd[1];
405
406 aprint_naive("\n");
407 aprint_normal("\n");
408
409 sc->sc_dev = self;
410 isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot);
411
412 if (isconsole) {
413 sc->id = &pckbd_consdata;
414
415 /*
416 * Some keyboards are not enabled after a reset,
417 * so make sure it is enabled now.
418 */
419 cmd[0] = KBC_ENABLE;
420 (void) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
421 cmd, 1, 0, 0, 0);
422 sc->sc_enabled = 1;
423 } else {
424 sc->id = malloc(sizeof(*sc->id), M_DEVBUF, M_WAITOK);
425 (void) pckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0);
426
427 /* no interrupts until enabled */
428 cmd[0] = KBC_DISABLE;
429 (void) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
430 cmd, 1, 0, 0, 0);
431 sc->sc_enabled = 0;
432 }
433
434 sc->id->t_sc = sc;
435
436 pckbport_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot,
437 pckbd_input, sc, device_xname(sc->sc_dev));
438
439 a.console = isconsole;
440
441 a.keymap = &pckbd_keymapdata;
442
443 a.accessops = &pckbd_accessops;
444 a.accesscookie = sc;
445
446 if (!pmf_device_register(self, pckbd_suspend, pckbd_resume))
447 aprint_error_dev(self, "couldn't establish power handler\n");
448
449 /*
450 * Attach the wskbd, saving a handle to it.
451 * XXX XXX XXX
452 */
453 sc->sc_wskbddev = config_found(self, &a, wskbddevprint, CFARGS_NONE);
454 }
455
456 int
pckbd_enable(void * v,int on)457 pckbd_enable(void *v, int on)
458 {
459 struct pckbd_softc *sc = v;
460 int res;
461 u_char cmd[1];
462
463 if (on) {
464 if (sc->sc_enabled) {
465 aprint_debug("%s: bad enable\n", __func__);
466 return EBUSY;
467 }
468
469 pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1);
470
471 cmd[0] = KBC_ENABLE;
472 res = pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
473 cmd, 1, 0, NULL, 0);
474 if (res) {
475 printf("%s: command error\n", __func__);
476 return res;
477 }
478
479 res = pckbd_set_xtscancode(sc->id->t_kbctag,
480 sc->id->t_kbcslot, sc->id);
481 if (res)
482 return res;
483
484 sc->sc_enabled = 1;
485 } else {
486 if (sc->id->t_isconsole)
487 return EBUSY;
488
489 cmd[0] = KBC_DISABLE;
490 res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
491 cmd, 1, 0, 1, 0);
492 if (res) {
493 printf("%s: command error\n", __func__);
494 return res;
495 }
496
497 pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0);
498
499 sc->sc_enabled = 0;
500 }
501
502 return 0;
503 }
504
505 const u_int8_t pckbd_xtbl[] = {
506 /* 0x00 */
507 0,
508 0x43, /* F9 */
509 0x89, /* SunStop */
510 0x3f, /* F5 */
511 0x3d, /* F3 */
512 0x3b, /* F1 */
513 0x3c, /* F2 */
514 0x58, /* F12 */
515 0,
516 0x44, /* F10 */
517 0x42, /* F8 */
518 0x40, /* F6 */
519 0x3e, /* F4 */
520 0x0f, /* Tab */
521 0x29, /* ` ~ */
522 0,
523 /* 0x10 */
524 0,
525 0x38, /* Left Alt */
526 0x2a, /* Left Shift */
527 0,
528 0x1d, /* Left Ctrl */
529 0x10, /* q */
530 0x02, /* 1 ! */
531 0,
532 0,
533 0,
534 0x2c, /* z */
535 0x1f, /* s */
536 0x1e, /* a */
537 0x11, /* w */
538 0x03, /* 2 @ */
539 0,
540 /* 0x20 */
541 0,
542 0x2e, /* c */
543 0x2d, /* x */
544 0x20, /* d */
545 0x12, /* e */
546 0x05, /* 4 $ */
547 0x04, /* 3 # */
548 0,
549 0,
550 0x39, /* Space */
551 0x2f, /* v */
552 0x21, /* f */
553 0x14, /* t */
554 0x13, /* r */
555 0x06, /* 5 % */
556 0,
557 /* 0x30 */
558 0,
559 0x31, /* n */
560 0x30, /* b */
561 0x23, /* h */
562 0x22, /* g */
563 0x15, /* y */
564 0x07, /* 6 ^ */
565 0,
566 0,
567 0,
568 0x32, /* m */
569 0x24, /* j */
570 0x16, /* u */
571 0x08, /* 7 & */
572 0x09, /* 8 * */
573 0,
574 /* 0x40 */
575 0,
576 0x33, /* , < */
577 0x25, /* k */
578 0x17, /* i */
579 0x18, /* o */
580 0x0b, /* 0 ) */
581 0x0a, /* 9 ( */
582 0,
583 0,
584 0x34, /* . > */
585 0x35, /* / ? */
586 0x26, /* l */
587 0x27, /* ; : */
588 0x19, /* p */
589 0x0c, /* - _ */
590 0,
591 /* 0x50 */
592 0,
593 0,
594 0x28, /* ' " */
595 0,
596 0x1a, /* [ { */
597 0x0d, /* = + */
598 0,
599 0,
600 0x3a, /* Caps Lock */
601 0x36, /* Right Shift */
602 0x1c, /* Return */
603 0x1b, /* ] } */
604 0,
605 0x2b, /* \ | */
606 0,
607 0,
608 /* 0x60 */
609 0,
610 0,
611 0,
612 0,
613 0,
614 0,
615 0x0e, /* Back Space */
616 0,
617 0,
618 0x4f, /* KP 1 */
619 0,
620 0x4b, /* KP 4 */
621 0x47, /* KP 7 */
622 0,
623 0,
624 0,
625 /* 0x70 */
626 0x52, /* KP 0 */
627 0x53, /* KP . */
628 0x50, /* KP 2 */
629 0x4c, /* KP 5 */
630 0x4d, /* KP 6 */
631 0x48, /* KP 8 */
632 0x01, /* Escape */
633 0x45, /* Num Lock */
634 0x57, /* F11 */
635 0x4e, /* KP + */
636 0x51, /* KP 3 */
637 0x4a, /* KP - */
638 0x37, /* KP * */
639 0x49, /* KP 9 */
640 0x46, /* Scroll Lock */
641 0,
642 /* 0x80 */
643 0,
644 0,
645 0,
646 0x41, /* F7 (produced as an actual 8 bit code) */
647 0, /* Alt-Print Screen */
648 0,
649 0,
650 0,
651 0,
652 0,
653 0,
654 0,
655 0,
656 0,
657 0,
658 0,
659 /* 0x90 */
660 0xdb, /* Left Meta */
661 0x88, /* SunHelp */
662 0x8a, /* SunAgain */
663 0x8c, /* SunUndo */
664 0x8e, /* SunCopy */
665 0x90, /* SunPaste */
666 0x92, /* SunCut */
667 0x8b, /* SunProps */
668 0x8d, /* SunFront */
669 0x8f, /* SunOpen */
670 0x91 /* SunFind */
671 };
672
673 const u_int8_t pckbd_xtbl_ext[] = {
674 /* 0x00 */
675 0,
676 0,
677 0,
678 0,
679 0,
680 0,
681 0,
682 0,
683 0,
684 0,
685 0,
686 0,
687 0,
688 0,
689 0,
690 0,
691 /* 0x10 */
692 0,
693 0x38, /* Right Alt */
694 0, /* E0 12, to be ignored */
695 0,
696 0x1d, /* Right Ctrl */
697 0,
698 0,
699 0,
700 0,
701 0,
702 0,
703 0,
704 0,
705 0,
706 0,
707 0,
708 /* 0x20 */
709 0,
710 0,
711 0,
712 0,
713 0,
714 0,
715 0,
716 0,
717 0,
718 0,
719 0,
720 0,
721 0,
722 0,
723 0,
724 0xdd, /* Compose */
725 /* 0x30 */
726 0,
727 0,
728 0,
729 0,
730 0,
731 0,
732 0,
733 0,
734 0,
735 0,
736 0,
737 0,
738 0,
739 0,
740 0,
741 0,
742 /* 0x40 */
743 0,
744 0,
745 0,
746 0,
747 0,
748 0,
749 0,
750 0,
751 0,
752 0,
753 0xb5, /* KP / */
754 0,
755 0,
756 0,
757 0,
758 0,
759 /* 0x50 */
760 0,
761 0,
762 0,
763 0,
764 0,
765 0,
766 0,
767 0,
768 0,
769 0,
770 0x1c, /* KP Return */
771 0,
772 0,
773 0,
774 0,
775 0,
776 /* 0x60 */
777 0,
778 0,
779 0,
780 0,
781 0,
782 0,
783 0,
784 0,
785 0,
786 0x4f, /* End */
787 0,
788 0x4b, /* Left */
789 0x47, /* Home */
790 0,
791 0,
792 0,
793 /* 0x70 */
794 0x52, /* Insert */
795 0x53, /* Delete */
796 0x50, /* Down */
797 0,
798 0x4d, /* Right */
799 0x48, /* Up */
800 0,
801 0,
802 0,
803 0,
804 0x51, /* Page Down */
805 0,
806 0x37, /* Print Screen */
807 0x49, /* Page Up */
808 0x46, /* Ctrl-Break */
809 0
810 };
811
812 /*
813 * Translate scan codes from set 2 to set 1
814 */
815 int
pckbd_scancode_translate(struct pckbd_internal * id,int datain)816 pckbd_scancode_translate(struct pckbd_internal *id, int datain)
817 {
818 if (id->t_translating != 0)
819 return datain;
820
821 if (datain == KBR_BREAK) {
822 id->t_releasing = 0x80; /* next keycode is a release */
823 return 0; /* consume scancode */
824 }
825
826 /*
827 * Handle extended sequences
828 */
829 if (datain == KBR_EXTENDED0 || datain == KBR_EXTENDED1)
830 return datain;
831
832 /*
833 * Convert BREAK sequence (14 77 -> 1D 45)
834 */
835 if (id->t_extended1 == 2 && datain == 0x14)
836 return 0x1d | id->t_releasing;
837 else if (id->t_extended1 == 1 && datain == 0x77)
838 return 0x45 | id->t_releasing;
839
840 if (id->t_extended0 != 0) {
841 if (datain >= sizeof pckbd_xtbl_ext)
842 datain = 0;
843 else
844 datain = pckbd_xtbl_ext[datain];
845 } else {
846 if (datain >= sizeof pckbd_xtbl)
847 datain = 0;
848 else
849 datain = pckbd_xtbl[datain];
850 }
851
852 /*
853 * If we are mapping in the range 128-254, then make this
854 * an extended keycode, as table 1 codes are limited to
855 * the range 0-127 (the top bit is used for key up/break).
856 */
857 if (datain > 0x7f) {
858 datain &= 0x7f;
859 id->t_extended0 = 0x80;
860 }
861
862 if (datain == 0) {
863 /*
864 * We don't know how to translate this scan code, but
865 * we can't silently eat it either (because there might
866 * have been an extended byte transmitted already).
867 * Hopefully this value will be harmless to the upper
868 * layers.
869 */
870 return 0xff;
871 }
872 return datain | id->t_releasing;
873 }
874
875 static bool
pckbd_decode(struct pckbd_internal * id,int datain,u_int * type,int * dataout)876 pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout)
877 {
878 int key;
879 int releasing;
880
881 if (datain == KBR_EXTENDED0) {
882 id->t_extended0 = 0x80;
883 return false;
884 } else if (datain == KBR_EXTENDED1) {
885 id->t_extended1 = 2;
886 return false;
887 }
888
889 releasing = datain & 0x80;
890 datain &= 0x7f;
891
892 if (id->t_extended0 == 0x80) {
893 switch (datain) {
894 case 0x2a:
895 case 0x36:
896 id->t_extended0 = 0;
897 return false;
898 default:
899 break;
900 }
901 }
902
903 /* map extended keys to (unused) codes 128-254 */
904 key = datain | id->t_extended0;
905 id->t_extended0 = 0;
906
907 /*
908 * process PAUSE (also break) key (EXT1 1D 45 EXT1 9D C5):
909 * map to (unused) code 7F
910 */
911 if (id->t_extended1 == 2 && (datain == 0x1d || datain == 0x9d)) {
912 id->t_extended1 = 1;
913 return false;
914 } else if (id->t_extended1 == 1 &&
915 (datain == 0x45 || datain == 0xc5)) {
916 id->t_extended1 = 0;
917 key = 0x7f;
918 } else if (id->t_extended1 > 0) {
919 id->t_extended1 = 0;
920 }
921
922 if (id->t_translating != 0) {
923 id->t_releasing = releasing;
924 } else {
925 /* id->t_releasing computed in pckbd_scancode_translate() */
926 }
927
928 if (id->t_releasing) {
929 id->t_releasing = 0;
930 id->t_lastchar = 0;
931 *type = WSCONS_EVENT_KEY_UP;
932 } else {
933 /* Always ignore typematic keys */
934 if (key == id->t_lastchar)
935 return false;
936 id->t_lastchar = key;
937 *type = WSCONS_EVENT_KEY_DOWN;
938 }
939
940 *dataout = key;
941 return true;
942 }
943
944 int
pckbd_init(struct pckbd_internal * t,pckbport_tag_t kbctag,pckbport_slot_t kbcslot,int console)945 pckbd_init(struct pckbd_internal *t, pckbport_tag_t kbctag,
946 pckbport_slot_t kbcslot, int console)
947 {
948
949 memset(t, 0, sizeof(struct pckbd_internal));
950
951 t->t_isconsole = console;
952 t->t_kbctag = kbctag;
953 t->t_kbcslot = kbcslot;
954
955 return pckbd_set_xtscancode(kbctag, kbcslot, t);
956 }
957
958 static int
pckbd_led_encode(int led)959 pckbd_led_encode(int led)
960 {
961 int res;
962
963 res = 0;
964
965 if (led & WSKBD_LED_SCROLL)
966 res |= 0x01;
967 if (led & WSKBD_LED_NUM)
968 res |= 0x02;
969 if (led & WSKBD_LED_CAPS)
970 res |= 0x04;
971 return res;
972 }
973
974 static int
pckbd_led_decode(int led)975 pckbd_led_decode(int led)
976 {
977 int res;
978
979 res = 0;
980 if (led & 0x01)
981 res |= WSKBD_LED_SCROLL;
982 if (led & 0x02)
983 res |= WSKBD_LED_NUM;
984 if (led & 0x04)
985 res |= WSKBD_LED_CAPS;
986 return res;
987 }
988
989 void
pckbd_set_leds(void * v,int leds)990 pckbd_set_leds(void *v, int leds)
991 {
992 struct pckbd_softc *sc = v;
993 u_char cmd[2];
994
995 cmd[0] = KBC_MODEIND;
996 cmd[1] = pckbd_led_encode(leds);
997 sc->sc_ledstate = cmd[1];
998
999 (void)pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
1000 cmd, 2, 0, 0, 0);
1001 }
1002
1003 /*
1004 * Got a console receive interrupt -
1005 * the console processor wants to give us a character.
1006 */
1007 void
pckbd_input(void * vsc,int data)1008 pckbd_input(void *vsc, int data)
1009 {
1010 struct pckbd_softc *sc = vsc;
1011 int key;
1012 u_int type;
1013
1014 data = pckbd_scancode_translate(sc->id, data);
1015 if (data == 0)
1016 return;
1017
1018 #ifdef WSDISPLAY_COMPAT_RAWKBD
1019 if (sc->rawkbd) {
1020 u_char d = data;
1021 wskbd_rawinput(sc->sc_wskbddev, &d, 1);
1022 return;
1023 }
1024 #endif
1025 if (pckbd_decode(sc->id, data, &type, &key))
1026 wskbd_input(sc->sc_wskbddev, type, key);
1027 }
1028
1029 int
pckbd_ioctl(void * v,u_long cmd,void * data,int flag,struct lwp * l)1030 pckbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
1031 {
1032 struct pckbd_softc *sc = v;
1033 u_char cmdb[2];
1034
1035 switch (cmd) {
1036 case WSKBDIO_GTYPE:
1037 *(int *)data = WSKBD_TYPE_PC_XT;
1038 return 0;
1039 case WSKBDIO_SETLEDS:
1040 cmdb[0] = KBC_MODEIND;
1041 cmdb[1] = pckbd_led_encode(*(int *)data);
1042 sc->sc_ledstate = cmdb[1];
1043 return pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
1044 cmdb, 2, 0, 1, 0);
1045 case WSKBDIO_GETLEDS:
1046 *(int *)data = pckbd_led_decode(sc->sc_ledstate);
1047 return 0;
1048 #if 0
1049 case WSKBDIO_COMPLEXBELL:
1050 #define d ((struct wskbd_bell_data *)data)
1051 /*
1052 * Keyboard can't beep directly; we have an
1053 * externally-provided global hook to do this.
1054 */
1055 pckbd_bell(d->pitch, d->period, d->volume, 0);
1056 #undef d
1057 return 0;
1058 #endif
1059 #ifdef WSDISPLAY_COMPAT_RAWKBD
1060 case WSKBDIO_SETMODE:
1061 sc->rawkbd = (*(int *)data == WSKBD_RAW);
1062 return 0;
1063 #endif
1064 }
1065 return EPASSTHROUGH;
1066 }
1067
1068 void
pckbd_bell(u_int pitch,u_int period,u_int volume,int poll)1069 pckbd_bell(u_int pitch, u_int period, u_int volume, int poll)
1070 {
1071
1072 if (pckbd_bell_fn != NULL)
1073 (*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period,
1074 volume, poll);
1075 }
1076
1077 void
pckbd_unhook_bell(void (* fn)(void *,u_int,u_int,u_int,int),void * arg)1078 pckbd_unhook_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg)
1079 {
1080 if (pckbd_bell_fn != fn && pckbd_bell_fn_arg != arg)
1081 return;
1082 pckbd_bell_fn = NULL;
1083 pckbd_bell_fn_arg = NULL;
1084 }
1085
1086 void
pckbd_hookup_bell(void (* fn)(void *,u_int,u_int,u_int,int),void * arg)1087 pckbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg)
1088 {
1089
1090 if (pckbd_bell_fn == NULL) {
1091 pckbd_bell_fn = fn;
1092 pckbd_bell_fn_arg = arg;
1093 }
1094 }
1095
1096 int
pckbd_cnattach(pckbport_tag_t kbctag,int kbcslot)1097 pckbd_cnattach(pckbport_tag_t kbctag, int kbcslot)
1098 {
1099 int res;
1100 u_char cmd[1];
1101
1102 res = pckbd_init(&pckbd_consdata, kbctag, kbcslot, 1);
1103 /* We may allow the console to be attached if no keyboard is present */
1104 #if defined(PCKBD_CNATTACH_MAY_FAIL)
1105 if (res)
1106 return res;
1107 #endif
1108
1109 /* Just to be sure. */
1110 cmd[0] = KBC_ENABLE;
1111 res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 1, 0, 0, 0);
1112
1113 #if defined(PCKBD_CNATTACH_MAY_FAIL)
1114 if (res)
1115 return res;
1116 #endif
1117
1118 wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata);
1119
1120 return res;
1121 }
1122
1123 /* ARGSUSED */
1124 void
pckbd_cngetc(void * v,u_int * type,int * data)1125 pckbd_cngetc(void *v, u_int *type, int *data)
1126 {
1127 struct pckbd_internal *t = v;
1128 int val;
1129
1130 for (;;) {
1131 val = pckbport_poll_data(t->t_kbctag, t->t_kbcslot);
1132 if (val == -1) {
1133 *type = 0;
1134 *data = 0;
1135 return;
1136 }
1137
1138 val = pckbd_scancode_translate(t, val);
1139 if (val == 0)
1140 continue;
1141
1142 if (pckbd_decode(t, val, type, data))
1143 return;
1144 }
1145 }
1146
1147 void
pckbd_cnpollc(void * v,int on)1148 pckbd_cnpollc(void *v, int on)
1149 {
1150 struct pckbd_internal *t = v;
1151
1152 pckbport_set_poll(t->t_kbctag, t->t_kbcslot, on);
1153 }
1154
1155 void
pckbd_cnbell(void * v,u_int pitch,u_int period,u_int volume)1156 pckbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
1157 {
1158
1159 pckbd_bell(pitch, period, volume, 1);
1160 }
1161