xref: /openbsd/sys/dev/pckbc/pckbd.c (revision d415bd75)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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