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