1 /* $OpenBSD: pckbd.c,v 1.51 2023/08/13 21:54:02 miod Exp $ */
2 /* $NetBSD: pckbd.c,v 1.24 2000/06/05 22:20:57 sommerfeld Exp $ */
3
4 /*-
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Charles M. Hannum.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*-
34 * Copyright (c) 1990 The Regents of the University of California.
35 * All rights reserved.
36 *
37 * This code is derived from software contributed to Berkeley by
38 * William Jolitz and Don Ahn.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 * @(#)pccons.c 5.11 (Berkeley) 5/21/91
65 */
66
67 /*
68 * code to work keyboard for PC-style console
69 */
70
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/device.h>
74 #include <sys/malloc.h>
75 #include <sys/ioctl.h>
76
77 #include <machine/bus.h>
78
79 #include <dev/ic/pckbcvar.h>
80 #include <dev/pckbc/pckbdreg.h>
81 #include <dev/pckbc/pmsreg.h>
82
83 #include <dev/wscons/wsconsio.h>
84 #include <dev/wscons/wskbdraw.h>
85 #include <dev/wscons/wskbdvar.h>
86 #include <dev/wscons/wsksymdef.h>
87 #include <dev/wscons/wsksymvar.h>
88
89 #include <dev/pckbc/wskbdmap_mfii.h>
90
91 struct pckbd_internal {
92 int t_isconsole;
93 pckbc_tag_t t_kbctag;
94 pckbc_slot_t t_kbcslot;
95
96 int t_translating; /* nonzero if hardware performs translation */
97 int t_table; /* scan code set in use */
98
99 int t_lastchar;
100 int t_extended;
101 int t_extended1;
102 int t_releasing;
103
104 struct pckbd_softc *t_sc; /* back pointer */
105 };
106
107 struct pckbd_softc {
108 struct device sc_dev;
109
110 struct pckbd_internal *id;
111 int sc_enabled;
112
113 int sc_ledstate;
114
115 struct device *sc_wskbddev;
116 #ifdef WSDISPLAY_COMPAT_RAWKBD
117 int rawkbd;
118 u_int sc_rawcnt;
119 char sc_rawbuf[3];
120 #endif
121 };
122
123 static int pckbd_is_console(pckbc_tag_t, pckbc_slot_t);
124
125 int pckbdprobe(struct device *, void *, void *);
126 void pckbdattach(struct device *, struct device *, void *);
127 int pckbdactivate(struct device *, int);
128
129 const struct cfattach pckbd_ca = {
130 sizeof(struct pckbd_softc),
131 pckbdprobe,
132 pckbdattach,
133 NULL,
134 pckbdactivate
135 };
136
137 int pckbd_enable(void *, int);
138 void pckbd_set_leds(void *, int);
139 int pckbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
140
141 const struct wskbd_accessops pckbd_accessops = {
142 pckbd_enable,
143 pckbd_set_leds,
144 pckbd_ioctl,
145 };
146
147 void pckbd_cngetc(void *, u_int *, int *);
148 void pckbd_cnpollc(void *, int);
149 void pckbd_cnbell(void *, u_int, u_int, u_int);
150
151 const struct wskbd_consops pckbd_consops = {
152 pckbd_cngetc,
153 pckbd_cnpollc,
154 pckbd_cnbell,
155 };
156
157 const struct wskbd_mapdata pckbd_keymapdata = {
158 pckbd_keydesctab,
159 #ifdef PCKBD_LAYOUT
160 PCKBD_LAYOUT,
161 #else
162 KB_US | KB_DEFAULT,
163 #endif
164 };
165
166 /*
167 * Hackish support for a bell on the PC Keyboard; when a suitable beeper
168 * is found, it attaches itself into the pckbd driver here.
169 */
170 void (*pckbd_bell_fn)(void *, u_int, u_int, u_int, int);
171 void *pckbd_bell_fn_arg;
172
173 void pckbd_bell(u_int, u_int, u_int, int);
174
175 int pckbd_scancode_translate(struct pckbd_internal *, int);
176 int pckbd_set_xtscancode(pckbc_tag_t, pckbc_slot_t,
177 struct pckbd_internal *);
178 void pckbd_init(struct pckbd_internal *, pckbc_tag_t, pckbc_slot_t, int);
179 void pckbd_input(void *, int);
180
181 static int pckbd_decode(struct pckbd_internal *, int,
182 u_int *, int *);
183 static int pckbd_led_encode(int);
184
185 struct pckbd_internal pckbd_consdata;
186
187 int
pckbdactivate(struct device * self,int act)188 pckbdactivate(struct device *self, int act)
189 {
190 struct pckbd_softc *sc = (struct pckbd_softc *)self;
191 int rv = 0;
192 u_char cmd[1];
193
194 switch(act) {
195 case DVACT_RESUME:
196 if (sc->sc_enabled) {
197 /*
198 * Some keyboards are not enabled after a reset,
199 * so make sure it is enabled now.
200 */
201 cmd[0] = KBC_ENABLE;
202 (void) pckbc_poll_cmd(sc->id->t_kbctag,
203 sc->id->t_kbcslot, cmd, 1, 0, NULL, 0);
204 /* XXX - also invoke pckbd_set_xtscancode() too? */
205 }
206 break;
207 }
208
209 rv = config_activate_children(self, act);
210
211 return (rv);
212 }
213
214 int
pckbd_set_xtscancode(pckbc_tag_t kbctag,pckbc_slot_t kbcslot,struct pckbd_internal * id)215 pckbd_set_xtscancode(pckbc_tag_t kbctag, pckbc_slot_t kbcslot,
216 struct pckbd_internal *id)
217 {
218 int table = 0;
219
220 if (pckbc_xt_translation(kbctag, &table)) {
221 #ifdef DEBUG
222 printf("pckbd: enabling of translation failed\n");
223 #endif
224 #ifdef __sparc64__ /* only pckbc@ebus on sparc64 uses this */
225 /*
226 * If hardware lacks translation capability, stick to the
227 * table it is using.
228 */
229 if (table != 0) {
230 id->t_translating = 0;
231 id->t_table = table;
232 return 0;
233 }
234 #endif
235 /*
236 * Since the keyboard controller can not translate scan
237 * codes to the XT set (#1), we would like to request
238 * this exact set. However it is likely that the
239 * controller does not support it either.
240 *
241 * So try scan code set #2 as well, which this driver
242 * knows how to translate.
243 */
244 table = 2;
245 if (id != NULL)
246 id->t_translating = 0;
247 } else {
248 table = 3;
249 if (id != NULL) {
250 id->t_translating = 1;
251 if (id->t_table == 0) {
252 /*
253 * Don't bother explicitly setting into set 2,
254 * it's the default.
255 */
256 id->t_table = 2;
257 return (0);
258 }
259 }
260 }
261
262 /* keep falling back until we hit a table that looks usable. */
263 for (; table >= 1; table--) {
264 u_char cmd[2];
265 #ifdef DEBUG
266 printf("pckbd: trying table %d\n", table);
267 #endif
268 cmd[0] = KBC_SETTABLE;
269 cmd[1] = table;
270 if (pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 0, NULL, 0)) {
271 #ifdef DEBUG
272 printf("pckbd: table set of %d failed\n", table);
273 #endif
274 if (table > 1) {
275 cmd[0] = KBC_RESET;
276 (void)pckbc_poll_cmd(kbctag, kbcslot, cmd,
277 1, 1, NULL, 1);
278 pckbc_flush(kbctag, kbcslot);
279
280 continue;
281 }
282 }
283
284 /*
285 * the 8042 took the table set request, however, not all that
286 * report they can work with table 3 actually work, so ask what
287 * table it reports it's in.
288 */
289 if (table == 3) {
290 u_char resp[1];
291
292 cmd[0] = KBC_SETTABLE;
293 cmd[1] = 0;
294 if (pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 1, resp, 0)) {
295 /*
296 * query failed, step down to table 2 to be
297 * safe.
298 */
299 #ifdef DEBUG
300 printf("pckbd: table 3 verification failed\n");
301 #endif
302 continue;
303 } else if (resp[0] == 3) {
304 #ifdef DEBUG
305 printf("pckbd: settling on table 3\n");
306 #endif
307 break;
308 }
309 #ifdef DEBUG
310 else
311 printf("pckbd: table \"%x\" != 3, trying 2\n",
312 resp[0]);
313 #endif
314 } else {
315 #ifdef DEBUG
316 printf("pckbd: settling on table %d\n", table);
317 #endif
318 break;
319 }
320 }
321
322 if (table == 0)
323 return (1);
324
325 if (id != NULL)
326 id->t_table = table;
327
328 return (0);
329 }
330
331 static int
pckbd_is_console(pckbc_tag_t tag,pckbc_slot_t slot)332 pckbd_is_console(pckbc_tag_t tag, pckbc_slot_t slot)
333 {
334 return (pckbd_consdata.t_isconsole &&
335 (tag == pckbd_consdata.t_kbctag) &&
336 (slot == pckbd_consdata.t_kbcslot));
337 }
338
339 /*
340 * these are both bad jokes
341 */
342 int
pckbdprobe(struct device * parent,void * match,void * aux)343 pckbdprobe(struct device *parent, void *match, void *aux)
344 {
345 struct cfdata *cf = match;
346 struct pckbc_attach_args *pa = aux;
347 u_char cmd[1], resp[2];
348 int res;
349
350 /*
351 * XXX There are rumours that a keyboard can be connected
352 * to the aux port as well. For me, this didn't work.
353 * For further experiments, allow it if explicitly
354 * wired in the config file.
355 */
356 if ((pa->pa_slot != PCKBC_KBD_SLOT) &&
357 (cf->cf_loc[PCKBCCF_SLOT] == PCKBCCF_SLOT_DEFAULT))
358 return (0);
359
360 /* Flush any garbage. */
361 pckbc_flush(pa->pa_tag, pa->pa_slot);
362
363 /* Reset the keyboard. */
364 cmd[0] = KBC_RESET;
365 res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1);
366 if (res != 0) {
367 #ifdef DEBUG
368 printf("pckbdprobe: reset error %d\n", res);
369 #endif
370 } else if (resp[0] != KBR_RSTDONE) {
371 #ifdef DEBUG
372 printf("pckbdprobe: reset response 0x%x\n", resp[0]);
373 #endif
374 res = EINVAL;
375 }
376 #if defined(__i386__) || defined(__amd64__)
377 if (res) {
378 /*
379 * The 8042 emulation on Chromebooks fails the reset
380 * command but otherwise appears to work correctly.
381 * Try a "get ID" command to give it a second chance.
382 */
383 cmd[0] = KBC_GETID;
384 res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot,
385 cmd, 1, 2, resp, 0);
386 if (res != 0) {
387 #ifdef DEBUG
388 printf("pckbdprobe: getid error %d\n", res);
389 #endif
390 } else if (resp[0] != 0xab || resp[1] != 0x83) {
391 #ifdef DEBUG
392 printf("pckbdprobe: unexpected id 0x%x/0x%x\n",
393 resp[0], resp[1]);
394 #endif
395 res = EINVAL;
396 }
397 }
398 #endif
399 if (res) {
400 /*
401 * There is probably no keyboard connected.
402 * Let the probe succeed if the keyboard is used
403 * as console input - it can be connected later.
404 */
405 #if defined(__i386__) || defined(__amd64__)
406 /*
407 * However, on legacy-free PCs, there might really
408 * be no PS/2 connector at all; in that case, do not
409 * even try to attach; ukbd will take over as console.
410 */
411 if (res == ENXIO) {
412 /* check cf_flags from parent */
413 struct cfdata *cf = parent->dv_cfdata;
414 if (!ISSET(cf->cf_flags, PCKBCF_FORCE_KEYBOARD_PRESENT))
415 return 0;
416 }
417 #endif
418 return (pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0);
419 }
420
421 /*
422 * Some keyboards seem to leave a second ack byte after the reset.
423 * This is kind of stupid, but we account for them anyway by just
424 * flushing the buffer.
425 */
426 pckbc_flush(pa->pa_tag, pa->pa_slot);
427
428 return (2);
429 }
430
431 void
pckbdattach(struct device * parent,struct device * self,void * aux)432 pckbdattach(struct device *parent, struct device *self, void *aux)
433 {
434 struct pckbd_softc *sc = (void *)self;
435 struct pckbc_attach_args *pa = aux;
436 int isconsole;
437 struct wskbddev_attach_args a;
438 u_char cmd[1];
439
440 isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot);
441
442 if (isconsole) {
443 sc->id = &pckbd_consdata;
444 if (sc->id->t_table == 0)
445 pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, sc->id);
446
447 /*
448 * Some keyboards are not enabled after a reset,
449 * so make sure it is enabled now.
450 */
451 cmd[0] = KBC_ENABLE;
452 (void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
453 cmd, 1, 0, NULL, 0);
454 sc->sc_enabled = 1;
455 } else {
456 sc->id = malloc(sizeof(struct pckbd_internal),
457 M_DEVBUF, M_WAITOK);
458 pckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0);
459 pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, sc->id);
460
461 /* no interrupts until enabled */
462 cmd[0] = KBC_DISABLE;
463 (void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
464 cmd, 1, 0, NULL, 0);
465 sc->sc_enabled = 0;
466 }
467
468 sc->id->t_sc = sc;
469
470 pckbc_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot,
471 pckbd_input, sc, sc->sc_dev.dv_xname);
472
473 a.console = isconsole;
474
475 a.keymap = &pckbd_keymapdata;
476
477 a.accessops = &pckbd_accessops;
478 a.accesscookie = sc;
479
480 printf("\n");
481
482 /*
483 * Attach the wskbd, saving a handle to it.
484 */
485 sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
486 }
487
488 int
pckbd_enable(void * v,int on)489 pckbd_enable(void *v, int on)
490 {
491 struct pckbd_softc *sc = v;
492 u_char cmd[1];
493 int res;
494
495 if (on) {
496 if (sc->sc_enabled)
497 return (EBUSY);
498
499 pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1);
500
501 cmd[0] = KBC_ENABLE;
502 res = pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
503 cmd, 1, 0, NULL, 0);
504 if (res) {
505 printf("pckbd_enable: command error\n");
506 return (res);
507 }
508
509 res = pckbd_set_xtscancode(sc->id->t_kbctag,
510 sc->id->t_kbcslot, sc->id);
511 if (res)
512 return (res);
513
514 sc->sc_enabled = 1;
515 } else {
516 if (sc->id->t_isconsole)
517 return (EBUSY);
518
519 cmd[0] = KBC_DISABLE;
520 res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
521 cmd, 1, 0, 1, 0);
522 if (res) {
523 printf("pckbd_disable: command error\n");
524 return (res);
525 }
526
527 pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0);
528
529 sc->sc_enabled = 0;
530 }
531
532 return (0);
533 }
534
535 /*
536 * Scan code set #2 translation tables
537 */
538
539 const u_int8_t pckbd_xtbl2[] = {
540 /* 0x00 */
541 0,
542 RAWKEY_f9,
543 0,
544 RAWKEY_f5,
545 RAWKEY_f3,
546 RAWKEY_f1,
547 RAWKEY_f2,
548 RAWKEY_f12,
549 RAWKEY_f6, /* F6 according to documentation */
550 RAWKEY_f10,
551 RAWKEY_f8,
552 RAWKEY_f6, /* F6 according to experimentation */
553 RAWKEY_f4,
554 RAWKEY_Tab,
555 RAWKEY_grave,
556 0,
557 /* 0x10 */
558 0,
559 RAWKEY_Alt_L,
560 RAWKEY_Shift_L,
561 0,
562 RAWKEY_Control_L,
563 RAWKEY_q,
564 RAWKEY_1,
565 0,
566 0,
567 0,
568 RAWKEY_z,
569 RAWKEY_s,
570 RAWKEY_a,
571 RAWKEY_w,
572 RAWKEY_2,
573 RAWKEY_Meta_L,
574 /* 0x20 */
575 0,
576 RAWKEY_c,
577 RAWKEY_x,
578 RAWKEY_d,
579 RAWKEY_e,
580 RAWKEY_4,
581 RAWKEY_3,
582 0,
583 RAWKEY_Meta_R,
584 RAWKEY_space,
585 RAWKEY_v,
586 RAWKEY_f,
587 RAWKEY_t,
588 RAWKEY_r,
589 RAWKEY_5,
590 0,
591 /* 0x30 */
592 0,
593 RAWKEY_n,
594 RAWKEY_b,
595 RAWKEY_h,
596 RAWKEY_g,
597 RAWKEY_y,
598 RAWKEY_6,
599 0,
600 0,
601 0,
602 RAWKEY_m,
603 RAWKEY_j,
604 RAWKEY_u,
605 RAWKEY_7,
606 RAWKEY_8,
607 0,
608 /* 0x40 */
609 0,
610 RAWKEY_comma,
611 RAWKEY_k,
612 RAWKEY_i,
613 RAWKEY_o,
614 RAWKEY_0,
615 RAWKEY_9,
616 0,
617 0,
618 RAWKEY_period,
619 RAWKEY_slash,
620 RAWKEY_l,
621 RAWKEY_semicolon,
622 RAWKEY_p,
623 RAWKEY_minus,
624 0,
625 /* 0x50 */
626 0,
627 0,
628 RAWKEY_apostrophe,
629 0,
630 RAWKEY_bracketleft,
631 RAWKEY_equal,
632 0,
633 0,
634 RAWKEY_Caps_Lock,
635 RAWKEY_Shift_R,
636 RAWKEY_Return,
637 RAWKEY_bracketright,
638 0,
639 RAWKEY_backslash,
640 0,
641 0,
642 /* 0x60 */
643 0,
644 0,
645 0,
646 0,
647 0,
648 0,
649 RAWKEY_BackSpace,
650 0,
651 0,
652 RAWKEY_KP_End,
653 0,
654 RAWKEY_KP_Left,
655 RAWKEY_KP_Home,
656 0,
657 0,
658 0,
659 /* 0x70 */
660 RAWKEY_KP_Insert,
661 RAWKEY_KP_Delete,
662 RAWKEY_KP_Down,
663 RAWKEY_KP_Begin,
664 RAWKEY_KP_Right,
665 RAWKEY_KP_Up,
666 RAWKEY_Escape,
667 RAWKEY_Num_Lock,
668 RAWKEY_f11,
669 RAWKEY_KP_Add,
670 RAWKEY_KP_Next,
671 RAWKEY_KP_Subtract,
672 RAWKEY_KP_Multiply,
673 RAWKEY_KP_Prior,
674 RAWKEY_Hold_Screen,
675 0,
676 /* 0x80 */
677 0,
678 0,
679 0,
680 RAWKEY_f7,
681 0 /* Alt-Print Screen */
682 };
683
684 const u_int8_t pckbd_xtbl2_ext[] = {
685 /* 0x00 */
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 /* 0x10 */
702 0,
703 RAWKEY_Alt_R,
704 0, /* E0 12, to be ignored */
705 0,
706 RAWKEY_Control_R,
707 0,
708 0,
709 0,
710 0,
711 0,
712 0,
713 0,
714 0,
715 0,
716 0,
717 0,
718 /* 0x20 */
719 0,
720 0,
721 0,
722 0,
723 0,
724 0,
725 0,
726 0,
727 0,
728 0,
729 0,
730 0,
731 0,
732 0,
733 0,
734 0,
735 /* 0x30 */
736 0,
737 0,
738 0,
739 0,
740 0,
741 0,
742 0,
743 0,
744 0,
745 0,
746 0,
747 0,
748 0,
749 0,
750 0,
751 0,
752 /* 0x40 */
753 0,
754 0,
755 0,
756 0,
757 0,
758 0,
759 0,
760 0,
761 0,
762 0,
763 RAWKEY_KP_Divide,
764 0,
765 0,
766 0,
767 0,
768 0,
769 /* 0x50 */
770 0,
771 0,
772 0,
773 0,
774 0,
775 0,
776 0,
777 0,
778 0,
779 0,
780 RAWKEY_KP_Enter,
781 0,
782 0,
783 0,
784 0,
785 0,
786 /* 0x60 */
787 0,
788 0,
789 0,
790 0,
791 0,
792 0,
793 0,
794 0,
795 0,
796 RAWKEY_End,
797 0,
798 RAWKEY_Left,
799 RAWKEY_Home,
800 0,
801 0,
802 0,
803 /* 0x70 */
804 RAWKEY_Insert,
805 RAWKEY_Delete,
806 RAWKEY_Down,
807 0,
808 RAWKEY_Right,
809 RAWKEY_Up,
810 0,
811 0,
812 0,
813 0,
814 RAWKEY_Next,
815 0,
816 RAWKEY_Print_Screen,
817 RAWKEY_Prior,
818 0xc6, /* Ctrl-Break */
819 0
820 };
821
822 #ifdef __sparc64__ /* only pckbc@ebus on sparc64 uses this */
823
824 /*
825 * Scan code set #3 translation table
826 */
827
828 const u_int8_t pckbd_xtbl3[] = {
829 /* 0x00 */
830 0,
831 RAWKEY_L5, /* Front */
832 RAWKEY_L1, /* Stop */
833 RAWKEY_L3, /* Props */
834 0,
835 RAWKEY_L7, /* Open */
836 RAWKEY_L9, /* Find */
837 RAWKEY_f1,
838 RAWKEY_Escape,
839 RAWKEY_L10, /* Cut */
840 0,
841 0,
842 0,
843 RAWKEY_Tab,
844 RAWKEY_grave,
845 RAWKEY_f2,
846 /* 0x10 */
847 RAWKEY_Help,
848 RAWKEY_Control_L,
849 RAWKEY_Shift_L,
850 0,
851 RAWKEY_Caps_Lock,
852 RAWKEY_q,
853 RAWKEY_1,
854 RAWKEY_f3,
855 0,
856 RAWKEY_Alt_L,
857 RAWKEY_z,
858 RAWKEY_s,
859 RAWKEY_a,
860 RAWKEY_w,
861 RAWKEY_2,
862 RAWKEY_f4,
863 /* 0x20 */
864 0,
865 RAWKEY_c,
866 RAWKEY_x,
867 RAWKEY_d,
868 RAWKEY_e,
869 RAWKEY_4,
870 RAWKEY_3,
871 RAWKEY_f5,
872 RAWKEY_L4, /* Undo */
873 RAWKEY_space,
874 RAWKEY_v,
875 RAWKEY_f,
876 RAWKEY_t,
877 RAWKEY_r,
878 RAWKEY_5,
879 RAWKEY_f6,
880 /* 0x30 */
881 RAWKEY_L2, /* Again */
882 RAWKEY_n,
883 RAWKEY_b,
884 RAWKEY_h,
885 RAWKEY_g,
886 RAWKEY_y,
887 RAWKEY_6,
888 RAWKEY_f7,
889 0,
890 RAWKEY_Alt_R,
891 RAWKEY_m,
892 RAWKEY_j,
893 RAWKEY_u,
894 RAWKEY_7,
895 RAWKEY_8,
896 RAWKEY_f8,
897 /* 0x40 */
898 0,
899 RAWKEY_comma,
900 RAWKEY_k,
901 RAWKEY_i,
902 RAWKEY_o,
903 RAWKEY_0,
904 RAWKEY_9,
905 RAWKEY_f9,
906 RAWKEY_L6, /* Copy */
907 RAWKEY_period,
908 RAWKEY_slash,
909 RAWKEY_l,
910 RAWKEY_semicolon,
911 RAWKEY_p,
912 RAWKEY_minus,
913 RAWKEY_f10,
914 /* 0x50 */
915 0,
916 0,
917 RAWKEY_apostrophe,
918 0,
919 RAWKEY_bracketleft,
920 RAWKEY_equal,
921 RAWKEY_f11,
922 RAWKEY_Print_Screen,
923 RAWKEY_Control_R,
924 RAWKEY_Shift_R,
925 RAWKEY_Return,
926 RAWKEY_bracketright,
927 RAWKEY_backslash,
928 0,
929 RAWKEY_f12,
930 RAWKEY_Hold_Screen,
931 /* 0x60 */
932 RAWKEY_Down,
933 RAWKEY_Left,
934 RAWKEY_Pause,
935 RAWKEY_Up,
936 RAWKEY_Delete,
937 RAWKEY_End,
938 RAWKEY_BackSpace,
939 RAWKEY_Insert,
940 RAWKEY_L8, /* Paste */
941 RAWKEY_KP_End,
942 RAWKEY_Right,
943 RAWKEY_KP_Left,
944 RAWKEY_KP_Home,
945 RAWKEY_Next,
946 RAWKEY_Home,
947 RAWKEY_Prior,
948 /* 0x70 */
949 RAWKEY_KP_Insert,
950 RAWKEY_KP_Delete,
951 RAWKEY_KP_Down,
952 RAWKEY_KP_Begin,
953 RAWKEY_KP_Right,
954 RAWKEY_KP_Up,
955 RAWKEY_Num_Lock,
956 RAWKEY_KP_Divide,
957 0,
958 RAWKEY_KP_Enter,
959 RAWKEY_KP_Next,
960 0,
961 RAWKEY_KP_Add,
962 RAWKEY_KP_Prior,
963 RAWKEY_KP_Multiply,
964 0,
965 /* 0x80 */
966 0,
967 0,
968 0,
969 0,
970 RAWKEY_KP_Subtract,
971 0,
972 0,
973 0,
974 0,
975 0,
976 0,
977 RAWKEY_Meta_L,
978 RAWKEY_Meta_R
979 };
980
981 #endif
982
983 /*
984 * Translate scan codes from set 2 or 3 to set 1
985 */
986 int
pckbd_scancode_translate(struct pckbd_internal * id,int datain)987 pckbd_scancode_translate(struct pckbd_internal *id, int datain)
988 {
989 if (id->t_translating != 0 || id->t_table == 1)
990 return datain;
991
992 if (datain == KBR_BREAK) {
993 id->t_releasing = 0x80; /* next keycode is a release */
994 return 0; /* consume scancode */
995 }
996
997 switch (id->t_table) {
998 case 2:
999 /*
1000 * Convert BREAK sequence (14 77 -> 1D 45)
1001 */
1002 if (id->t_extended1 == 2 && datain == 0x14)
1003 return 0x1d | id->t_releasing;
1004 else if (id->t_extended1 == 1 && datain == 0x77)
1005 return 0x45 | id->t_releasing;
1006
1007 if (id->t_extended != 0) {
1008 if (datain >= sizeof pckbd_xtbl2_ext)
1009 datain = 0;
1010 else
1011 datain = pckbd_xtbl2_ext[datain];
1012 /* xtbl2_ext already has the upper bit set */
1013 id->t_extended = 0;
1014 } else {
1015 if (datain >= sizeof pckbd_xtbl2)
1016 datain = 0;
1017 else
1018 datain = pckbd_xtbl2[datain] & ~0x80;
1019 }
1020 break;
1021 #ifdef __sparc64__ /* only pckbc@ebus on sparc64 uses this */
1022 case 3:
1023 if (datain >= sizeof pckbd_xtbl3)
1024 datain = 0;
1025 else
1026 datain = pckbd_xtbl3[datain] & ~0x80;
1027 break;
1028 #endif
1029 }
1030
1031 if (datain == 0) {
1032 /*
1033 * We don't know how to translate this scan code, but
1034 * we can't silently eat it either (because there might
1035 * have been an extended byte transmitted already).
1036 * Hopefully this value will be harmless to the upper
1037 * layers.
1038 */
1039 return 0xff;
1040 }
1041
1042 return datain | id->t_releasing;
1043 }
1044
1045 static int
pckbd_decode(struct pckbd_internal * id,int datain,u_int * type,int * dataout)1046 pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout)
1047 {
1048 int key;
1049 int releasing;
1050
1051 if (datain == KBR_EXTENDED0) {
1052 id->t_extended = 0x80;
1053 return 0;
1054 } else if (datain == KBR_EXTENDED1) {
1055 id->t_extended1 = 2;
1056 return 0;
1057 }
1058
1059 releasing = datain & 0x80;
1060 datain &= 0x7f;
1061
1062 /*
1063 * process BREAK key sequence (EXT1 1D 45 / EXT1 9D C5):
1064 * map to (unused) code 7F
1065 */
1066 if (id->t_extended1 == 2 && datain == 0x1d) {
1067 id->t_extended1 = 1;
1068 return 0;
1069 } else if (id->t_extended1 == 1 && datain == 0x45) {
1070 id->t_extended1 = 0;
1071 datain = 0x7f;
1072 } else
1073 id->t_extended1 = 0;
1074
1075 if (id->t_translating != 0 || id->t_table == 1) {
1076 id->t_releasing = releasing;
1077 } else {
1078 /* id->t_releasing computed in pckbd_scancode_translate() */
1079 }
1080
1081 /* map extended keys to (unused) codes 128-254 */
1082 key = datain | id->t_extended;
1083 id->t_extended = 0;
1084
1085 if (id->t_releasing) {
1086 id->t_releasing = 0;
1087 id->t_lastchar = 0;
1088 *type = WSCONS_EVENT_KEY_UP;
1089 } else {
1090 /* Always ignore typematic keys */
1091 if (key == id->t_lastchar)
1092 return 0;
1093 id->t_lastchar = key;
1094 *type = WSCONS_EVENT_KEY_DOWN;
1095 }
1096
1097 *dataout = key;
1098 return 1;
1099 }
1100
1101 void
pckbd_init(struct pckbd_internal * t,pckbc_tag_t kbctag,pckbc_slot_t kbcslot,int console)1102 pckbd_init(struct pckbd_internal *t, pckbc_tag_t kbctag, pckbc_slot_t kbcslot,
1103 int console)
1104 {
1105 bzero(t, sizeof(struct pckbd_internal));
1106
1107 t->t_isconsole = console;
1108 t->t_kbctag = kbctag;
1109 t->t_kbcslot = kbcslot;
1110 }
1111
1112 static int
pckbd_led_encode(int led)1113 pckbd_led_encode(int led)
1114 {
1115 int res;
1116
1117 res = 0;
1118
1119 if (led & WSKBD_LED_SCROLL)
1120 res |= 0x01;
1121 if (led & WSKBD_LED_NUM)
1122 res |= 0x02;
1123 if (led & WSKBD_LED_CAPS)
1124 res |= 0x04;
1125 return(res);
1126 }
1127
1128 void
pckbd_set_leds(void * v,int leds)1129 pckbd_set_leds(void *v, int leds)
1130 {
1131 struct pckbd_softc *sc = v;
1132 u_char cmd[2];
1133
1134 cmd[0] = KBC_MODEIND;
1135 cmd[1] = pckbd_led_encode(leds);
1136 sc->sc_ledstate = leds;
1137
1138 (void) pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
1139 cmd, 2, 0, 0, 0);
1140 }
1141
1142 /*
1143 * Got a console receive interrupt -
1144 * the console processor wants to give us a character.
1145 */
1146 void
pckbd_input(void * vsc,int data)1147 pckbd_input(void *vsc, int data)
1148 {
1149 struct pckbd_softc *sc = vsc;
1150 int rc, type, key;
1151
1152 data = pckbd_scancode_translate(sc->id, data);
1153 if (data == 0)
1154 return;
1155
1156 rc = pckbd_decode(sc->id, data, &type, &key);
1157
1158 #ifdef WSDISPLAY_COMPAT_RAWKBD
1159 if (sc->rawkbd) {
1160 sc->sc_rawbuf[sc->sc_rawcnt++] = (char)data;
1161
1162 if (rc != 0 || sc->sc_rawcnt == sizeof(sc->sc_rawbuf)) {
1163 wskbd_rawinput(sc->sc_wskbddev, sc->sc_rawbuf,
1164 sc->sc_rawcnt);
1165 sc->sc_rawcnt = 0;
1166 }
1167
1168 /*
1169 * Pass audio keys to wskbd_input anyway.
1170 */
1171 if (rc == 0 || (key != 160 && key != 174 && key != 176))
1172 return;
1173 }
1174 #endif
1175 if (rc != 0)
1176 wskbd_input(sc->sc_wskbddev, type, key);
1177 }
1178
1179 int
pckbd_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)1180 pckbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
1181 {
1182 struct pckbd_softc *sc = v;
1183
1184 switch (cmd) {
1185 case WSKBDIO_GTYPE:
1186 *(int *)data = WSKBD_TYPE_PC_XT;
1187 return 0;
1188 case WSKBDIO_SETLEDS: {
1189 char cmd[2];
1190 int res;
1191 cmd[0] = KBC_MODEIND;
1192 cmd[1] = pckbd_led_encode(*(int *)data);
1193 sc->sc_ledstate = *(int *)data & (WSKBD_LED_SCROLL |
1194 WSKBD_LED_NUM | WSKBD_LED_CAPS);
1195 res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
1196 cmd, 2, 0, 1, 0);
1197 return (res);
1198 }
1199 case WSKBDIO_GETLEDS:
1200 *(int *)data = sc->sc_ledstate;
1201 return (0);
1202 case WSKBDIO_COMPLEXBELL:
1203 #define d ((struct wskbd_bell_data *)data)
1204 /*
1205 * Keyboard can't beep directly; we have an
1206 * externally-provided global hook to do this.
1207 */
1208 pckbd_bell(d->pitch, d->period, d->volume, 0);
1209 #undef d
1210 return (0);
1211 #ifdef WSDISPLAY_COMPAT_RAWKBD
1212 case WSKBDIO_SETMODE:
1213 sc->rawkbd = (*(int *)data == WSKBD_RAW);
1214 return (0);
1215 #endif
1216 }
1217 return -1;
1218 }
1219
1220 void
pckbd_bell(u_int pitch,u_int period,u_int volume,int poll)1221 pckbd_bell(u_int pitch, u_int period, u_int volume, int poll)
1222 {
1223
1224 if (pckbd_bell_fn != NULL)
1225 (*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period,
1226 volume, poll);
1227 }
1228
1229 void
pckbd_hookup_bell(void (* fn)(void *,u_int,u_int,u_int,int),void * arg)1230 pckbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg)
1231 {
1232
1233 if (pckbd_bell_fn == NULL) {
1234 pckbd_bell_fn = fn;
1235 pckbd_bell_fn_arg = arg;
1236 }
1237 }
1238
1239 int
pckbd_cnattach(pckbc_tag_t kbctag)1240 pckbd_cnattach(pckbc_tag_t kbctag)
1241 {
1242 pckbd_init(&pckbd_consdata, kbctag, PCKBC_KBD_SLOT, 1);
1243 wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata);
1244 return (0);
1245 }
1246
1247 void
pckbd_cngetc(void * v,u_int * type,int * data)1248 pckbd_cngetc(void *v, u_int *type, int *data)
1249 {
1250 struct pckbd_internal *t = v;
1251 int val;
1252
1253 for (;;) {
1254 val = pckbc_poll_data(t->t_kbctag, t->t_kbcslot);
1255 if (val == -1)
1256 continue;
1257
1258 val = pckbd_scancode_translate(t, val);
1259 if (val == 0)
1260 continue;
1261
1262 if (pckbd_decode(t, val, type, data))
1263 return;
1264 }
1265 }
1266
1267 void
pckbd_cnpollc(void * v,int on)1268 pckbd_cnpollc(void *v, int on)
1269 {
1270 struct pckbd_internal *t = v;
1271
1272 pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on);
1273
1274 /*
1275 * If we enter ukc or ddb before having attached the console
1276 * keyboard we need to probe its scan code set.
1277 */
1278 if (t->t_table == 0) {
1279 char cmd[1];
1280
1281 pckbc_flush(t->t_kbctag, t->t_kbcslot);
1282 pckbd_set_xtscancode(t->t_kbctag, t->t_kbcslot, t);
1283
1284 /* Just to be sure. */
1285 cmd[0] = KBC_ENABLE;
1286 pckbc_poll_cmd(t->t_kbctag, PCKBC_KBD_SLOT, cmd, 1, 0, NULL, 0);
1287 }
1288 }
1289
1290 void
pckbd_cnbell(void * v,u_int pitch,u_int period,u_int volume)1291 pckbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
1292 {
1293
1294 pckbd_bell(pitch, period, volume, 1);
1295 }
1296
1297 struct cfdriver pckbd_cd = {
1298 NULL, "pckbd", DV_DULL
1299 };
1300