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