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