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