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