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