xref: /netbsd-src/sys/dev/pckbport/pckbd.c (revision c38e7cc395b1472a774ff828e46123de44c628e9)
1 /* $NetBSD: pckbd.c,v 1.33 2017/06/11 03:55:56 nat Exp $ */
2 
3 /*-
4  * Copyright (c) 1998, 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Charles M. Hannum.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*-
33  * Copyright (c) 1990 The Regents of the University of California.
34  * All rights reserved.
35  *
36  * This code is derived from software contributed to Berkeley by
37  * William Jolitz and Don Ahn.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. Neither the name of the University nor the names of its contributors
48  *    may be used to endorse or promote products derived from this software
49  *    without specific prior written permission.
50  *
51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61  * SUCH DAMAGE.
62  *
63  *	@(#)pccons.c	5.11 (Berkeley) 5/21/91
64  */
65 
66 /*
67  * code to work keyboard for PC-style console
68  */
69 
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: pckbd.c,v 1.33 2017/06/11 03:55:56 nat Exp $");
72 
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/device.h>
76 #include <sys/malloc.h>
77 #include <sys/ioctl.h>
78 
79 #include <sys/bus.h>
80 
81 #include <dev/pckbport/pckbportvar.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/pckbport/pckbdreg.h>
89 #include <dev/pckbport/pckbdvar.h>
90 #include <dev/pckbport/wskbdmap_mfii.h>
91 
92 #include "locators.h"
93 
94 #include "opt_pckbd_layout.h"
95 #include "opt_pckbd_cnattach_may_fail.h"
96 #include "opt_wsdisplay_compat.h"
97 
98 struct pckbd_internal {
99 	int t_isconsole;
100 	pckbport_tag_t t_kbctag;
101 	pckbport_slot_t t_kbcslot;
102 
103 	int t_translating;
104 
105 	int t_lastchar;
106 	int t_extended0;
107 	int t_extended1;
108 	int t_releasing;
109 
110 	struct pckbd_softc *t_sc; /* back pointer */
111 };
112 
113 struct pckbd_softc {
114         device_t sc_dev;
115 
116 	struct pckbd_internal *id;
117 	int sc_enabled;
118 
119 	int sc_ledstate;
120 
121 	device_t sc_wskbddev;
122 #ifdef WSDISPLAY_COMPAT_RAWKBD
123 	int rawkbd;
124 #endif
125 };
126 
127 static int pckbd_is_console(pckbport_tag_t, pckbport_slot_t);
128 
129 int pckbdprobe(device_t, cfdata_t, void *);
130 void pckbdattach(device_t, device_t, void *);
131 
132 CFATTACH_DECL_NEW(pckbd, sizeof(struct pckbd_softc),
133     pckbdprobe, pckbdattach, NULL, NULL);
134 
135 int	pckbd_enable(void *, int);
136 void	pckbd_set_leds(void *, int);
137 int	pckbd_ioctl(void *, u_long, void *, int, struct lwp *);
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,
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(pckbport_tag_t, pckbport_slot_t,
175 	    struct pckbd_internal *);
176 int	pckbd_init(struct pckbd_internal *, pckbport_tag_t, pckbport_slot_t,
177 			int);
178 void	pckbd_input(void *, int);
179 
180 static int	pckbd_decode(struct pckbd_internal *, int, u_int *, int *);
181 static int	pckbd_led_encode(int);
182 static int	pckbd_led_decode(int);
183 
184 struct pckbd_internal pckbd_consdata;
185 
186 int
187 pckbd_set_xtscancode(pckbport_tag_t kbctag, pckbport_slot_t kbcslot,
188     struct pckbd_internal *id)
189 {
190 	int xt, res = 0;
191 	u_char cmd[2];
192 
193 	/*
194 	 * Some keyboard/8042 combinations do not seem to work if the keyboard
195 	 * is set to table 1; in fact, it would appear that some keyboards just
196 	 * ignore the command altogether.  So by default, we use the AT scan
197 	 * codes and have the 8042 translate them.  Unfortunately, this is
198 	 * known to not work on some PS/2 machines.  We try desperately to deal
199 	 * with this by checking the (lack of a) translate bit in the 8042 and
200 	 * attempting to set the keyboard to XT mode.  If this all fails, well,
201 	 * tough luck.  If the PCKBC_CANT_TRANSLATE pckbc flag was set, we
202 	 * enable software translation.
203 	 *
204 	 * XXX It would perhaps be a better choice to just use AT scan codes
205 	 * and not bother with this.
206 	 */
207 	xt = pckbport_xt_translation(kbctag, kbcslot, 1);
208 	if (xt == 1) {
209 		/* The 8042 is translating for us; use AT codes. */
210 		cmd[0] = KBC_SETTABLE;
211 		cmd[1] = 2;
212 		res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0);
213 		if (res) {
214 			u_char cmdb[1];
215 			aprint_debug("pckbd: error setting scanset 2\n");
216 			/*
217 			 * XXX at least one keyboard is reported to lock up
218 			 * if a "set table" is attempted, thus the "reset".
219 			 * XXX ignore errors, scanset 2 should be
220 			 * default anyway.
221 			 */
222 			cmdb[0] = KBC_RESET;
223 			(void)pckbport_poll_cmd(kbctag, kbcslot, cmdb, 1, 1, 0, 1);
224 			pckbport_flush(kbctag, kbcslot);
225 			res = 0;
226 		}
227 		if (id != NULL)
228 			id->t_translating = 1;
229 	} else if (xt == -1) {
230 		/* Software translation required */
231 		if (id != NULL)
232 			id->t_translating = 0;
233 	} else {
234 		/* Stupid 8042; set keyboard to XT codes. */
235 		cmd[0] = KBC_SETTABLE;
236 		cmd[1] = 1;
237 		res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0);
238 		if (res)
239 			aprint_debug("pckbd: error setting scanset 1\n");
240 		if (id != NULL)
241 			id->t_translating = 1;
242 	}
243 	return res;
244 }
245 
246 static int
247 pckbd_is_console(pckbport_tag_t tag, pckbport_slot_t slot)
248 {
249 
250 	return pckbd_consdata.t_isconsole &&
251 	    tag == pckbd_consdata.t_kbctag && slot == pckbd_consdata.t_kbcslot;
252 }
253 
254 static bool
255 pckbd_suspend(device_t dv, const pmf_qual_t *qual)
256 {
257 	struct pckbd_softc *sc = device_private(dv);
258 	u_char cmd[1];
259 	int res;
260 
261 	/* XXX duped from pckbd_enable, but we want to disable
262 	 *     it even if it's the console kbd
263 	 */
264 	cmd[0] = KBC_DISABLE;
265 	res = pckbport_enqueue_cmd(sc->id->t_kbctag,
266 	    sc->id->t_kbcslot, cmd, 1, 0, 1, 0);
267 	if (res)
268 		return false;
269 
270 	pckbport_slot_enable(sc->id->t_kbctag,
271 	    sc->id->t_kbcslot, 0);
272 
273 	sc->sc_enabled = 0;
274 	return true;
275 }
276 
277 static bool
278 pckbd_resume(device_t dv, const pmf_qual_t *qual)
279 {
280 	struct pckbd_softc *sc = device_private(dv);
281 	u_char cmd[1], resp[1];
282 	int res;
283 
284 	/* XXX jmcneill reset the keyboard */
285 	pckbport_flush(sc->id->t_kbctag, sc->id->t_kbcslot);
286 
287 	cmd[0] = KBC_RESET;
288 	res = pckbport_poll_cmd(sc->id->t_kbctag,
289 	    sc->id->t_kbcslot, cmd, 1, 1, resp, 1);
290 	if (res)
291 		aprint_debug("%s: reset error %d\n", __func__, res);
292 	if (resp[0] != KBR_RSTDONE)
293 		printf("%s: reset response 0x%x\n", __func__, resp[0]);
294 
295 	pckbport_flush(sc->id->t_kbctag, sc->id->t_kbcslot);
296 
297 	pckbd_enable(sc, 1);
298 
299 	return true;
300 }
301 
302 /*
303  * these are both bad jokes
304  */
305 int
306 pckbdprobe(device_t parent, cfdata_t cf, void *aux)
307 {
308 	struct pckbport_attach_args *pa = aux;
309 	int res;
310 	u_char cmd[1], resp[1];
311 
312 	/*
313 	 * XXX There are rumours that a keyboard can be connected
314 	 * to the aux port as well. For me, this didn't work.
315 	 * For further experiments, allow it if explicitly
316 	 * wired in the config file.
317 	 */
318 	if ((pa->pa_slot != PCKBPORT_KBD_SLOT) &&
319 	    (cf->cf_loc[PCKBPORTCF_SLOT] == PCKBPORTCF_SLOT_DEFAULT))
320 		return 0;
321 
322 	/* Flush any garbage. */
323 	pckbport_flush(pa->pa_tag, pa->pa_slot);
324 
325 	/* Reset the keyboard. */
326 	cmd[0] = KBC_RESET;
327 	res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1);
328 	if (res) {
329 		aprint_debug("pckbdprobe: reset error %d\n", res);
330 		/*
331 		 * There is probably no keyboard connected.
332 		 * Let the probe succeed if the keyboard is used
333 		 * as console input - it can be connected later.
334 		 */
335 		return pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0;
336 	}
337 	if (resp[0] != KBR_RSTDONE) {
338 		printf("pckbdprobe: reset response 0x%x\n", resp[0]);
339 		return 0;
340 	}
341 
342 	/*
343 	 * Some keyboards seem to leave a second ack byte after the reset.
344 	 * This is kind of stupid, but we account for them anyway by just
345 	 * flushing the buffer.
346 	 */
347 	pckbport_flush(pa->pa_tag, pa->pa_slot);
348 
349 	if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, NULL))
350 		return 0;
351 
352 	return 2;
353 }
354 
355 void
356 pckbdattach(device_t parent, device_t self, void *aux)
357 {
358 	struct pckbd_softc *sc = device_private(self);
359 	struct pckbport_attach_args *pa = aux;
360 	struct wskbddev_attach_args a;
361 	int isconsole;
362 	u_char cmd[1];
363 
364 	aprint_naive("\n");
365 	aprint_normal("\n");
366 
367 	sc->sc_dev = self;
368 	isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot);
369 
370 	if (isconsole) {
371 		sc->id = &pckbd_consdata;
372 
373 		/*
374 		 * Some keyboards are not enabled after a reset,
375 		 * so make sure it is enabled now.
376 		 */
377 		cmd[0] = KBC_ENABLE;
378 		(void) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
379 				      cmd, 1, 0, 0, 0);
380 		sc->sc_enabled = 1;
381 	} else {
382 		sc->id = malloc(sizeof(struct pckbd_internal),
383 				M_DEVBUF, M_WAITOK);
384 		(void) pckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0);
385 
386 		/* no interrupts until enabled */
387 		cmd[0] = KBC_DISABLE;
388 		(void) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
389 				      cmd, 1, 0, 0, 0);
390 		sc->sc_enabled = 0;
391 	}
392 
393 	sc->id->t_sc = sc;
394 
395 	pckbport_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot,
396 			       pckbd_input, sc, device_xname(sc->sc_dev));
397 
398 	a.console = isconsole;
399 
400 	a.keymap = &pckbd_keymapdata;
401 
402 	a.accessops = &pckbd_accessops;
403 	a.accesscookie = sc;
404 
405 	if (!pmf_device_register(self, pckbd_suspend, pckbd_resume))
406 		aprint_error_dev(self, "couldn't establish power handler\n");
407 
408 	/*
409 	 * Attach the wskbd, saving a handle to it.
410 	 * XXX XXX XXX
411 	 */
412 	sc->sc_wskbddev = config_found_ia(self, "wskbddev", &a, wskbddevprint);
413 }
414 
415 int
416 pckbd_enable(void *v, int on)
417 {
418 	struct pckbd_softc *sc = v;
419 	int res;
420 	u_char cmd[1];
421 
422 	if (on) {
423 		if (sc->sc_enabled) {
424 			aprint_debug("pckbd_enable: bad enable\n");
425 			return EBUSY;
426 		}
427 
428 		pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1);
429 
430 		cmd[0] = KBC_ENABLE;
431 		res = pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
432 					cmd, 1, 0, NULL, 0);
433 		if (res) {
434 			printf("pckbd_enable: command error\n");
435 			return (res);
436 		}
437 
438 		res = pckbd_set_xtscancode(sc->id->t_kbctag,
439 					   sc->id->t_kbcslot, sc->id);
440 		if (res)
441 			return res;
442 
443 		sc->sc_enabled = 1;
444 	} else {
445 		if (sc->id->t_isconsole)
446 			return EBUSY;
447 
448 		cmd[0] = KBC_DISABLE;
449 		res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
450 					cmd, 1, 0, 1, 0);
451 		if (res) {
452 			printf("pckbd_disable: command error\n");
453 			return res;
454 		}
455 
456 		pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0);
457 
458 		sc->sc_enabled = 0;
459 	}
460 
461 	return 0;
462 }
463 
464 const u_int8_t pckbd_xtbl[] = {
465 /* 0x00 */
466 	0,
467 	0x43,		/* F9 */
468 	0x89,		/* SunStop */
469 	0x3f,		/* F5 */
470 	0x3d,		/* F3 */
471 	0x3b,		/* F1 */
472 	0x3c,		/* F2 */
473 	0x58,		/* F12 */
474 	0,
475 	0x44,		/* F10 */
476 	0x42,		/* F8 */
477 	0x40,		/* F6 */
478 	0x3e,		/* F4 */
479 	0x0f,		/* Tab */
480 	0x29,		/* ` ~ */
481 	0,
482 /* 0x10 */
483 	0,
484 	0x38,		/* Left Alt */
485 	0x2a,		/* Left Shift */
486 	0,
487 	0x1d,		/* Left Ctrl */
488 	0x10,		/* q */
489 	0x02,		/* 1 ! */
490 	0,
491 	0,
492 	0,
493 	0x2c,		/* z */
494 	0x1f,		/* s */
495 	0x1e,		/* a */
496 	0x11,		/* w */
497 	0x03,		/* 2 @ */
498 	0,
499 /* 0x20 */
500 	0,
501 	0x2e,		/* c */
502 	0x2d,		/* x */
503 	0x20,		/* d */
504 	0x12,		/* e */
505 	0x05,		/* 4 $ */
506 	0x04,		/* 3 # */
507 	0,
508 	0,
509 	0x39,		/* Space */
510 	0x2f,		/* v */
511 	0x21,		/* f */
512 	0x14,		/* t */
513 	0x13,		/* r */
514 	0x06,		/* 5 % */
515 	0,
516 /* 0x30 */
517 	0,
518 	0x31,		/* n */
519 	0x30,		/* b */
520 	0x23,		/* h */
521 	0x22,		/* g */
522 	0x15,		/* y */
523 	0x07,		/* 6 ^ */
524 	0,
525 	0,
526 	0,
527 	0x32,		/* m */
528 	0x24,		/* j */
529 	0x16,		/* u */
530 	0x08,		/* 7 & */
531 	0x09,		/* 8 * */
532 	0,
533 /* 0x40 */
534 	0,
535 	0x33,		/* , < */
536 	0x25,		/* k */
537 	0x17,		/* i */
538 	0x18,		/* o */
539 	0x0b,		/* 0 ) */
540 	0x0a,		/* 9 ( */
541 	0,
542 	0,
543 	0x34,		/* . > */
544 	0x35,		/* / ? */
545 	0x26,		/* l */
546 	0x27,		/* ; : */
547 	0x19,		/* p */
548 	0x0c,		/* - _ */
549 	0,
550 /* 0x50 */
551 	0,
552 	0,
553 	0x28,		/* ' " */
554 	0,
555 	0x1a,		/* [ { */
556 	0x0d,		/* = + */
557 	0,
558 	0,
559 	0x3a,		/* Caps Lock */
560 	0x36,		/* Right Shift */
561 	0x1c,		/* Return */
562 	0x1b,		/* ] } */
563 	0,
564 	0x2b,		/* \ | */
565 	0,
566 	0,
567 /* 0x60 */
568 	0,
569 	0,
570 	0,
571 	0,
572 	0,
573 	0,
574 	0x0e,		/* Back Space */
575 	0,
576 	0,
577 	0x4f,		/* KP 1 */
578 	0,
579 	0x4b,		/* KP 4 */
580 	0x47,		/* KP 7 */
581 	0,
582 	0,
583 	0,
584 /* 0x70 */
585 	0x52,		/* KP 0 */
586 	0x53,		/* KP . */
587 	0x50,		/* KP 2 */
588 	0x4c,		/* KP 5 */
589 	0x4d,		/* KP 6 */
590 	0x48,		/* KP 8 */
591 	0x01,		/* Escape */
592 	0x45,		/* Num Lock */
593 	0x57,		/* F11 */
594 	0x4e,		/* KP + */
595 	0x51,		/* KP 3 */
596 	0x4a,		/* KP - */
597 	0x37,		/* KP * */
598 	0x49,		/* KP 9 */
599 	0x46,		/* Scroll Lock */
600 	0,
601 /* 0x80 */
602 	0,
603 	0,
604 	0,
605 	0x41,		/* F7 (produced as an actual 8 bit code) */
606 	0,		/* Alt-Print Screen */
607 	0,
608 	0,
609 	0,
610 	0,
611 	0,
612 	0,
613 	0,
614 	0,
615 	0,
616 	0,
617 	0,
618 /* 0x90 */
619 	0xdb,		/* Left Meta */
620 	0x88,		/* SunHelp */
621 	0x8a,		/* SunAgain */
622 	0x8c,		/* SunUndo */
623 	0x8e,		/* SunCopy */
624 	0x90,		/* SunPaste */
625 	0x92,		/* SunCut */
626 	0x8b,		/* SunProps */
627 	0x8d,		/* SunFront */
628 	0x8f,		/* SunOpen */
629 	0x91		/* SunFind */
630 };
631 
632 const u_int8_t pckbd_xtbl_ext[] = {
633 /* 0x00 */
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 	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 	0xdd,		/* Compose */
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 	0xb5,		/* 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)
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 	 * Handle extended sequences
787 	 */
788 	if (datain == KBR_EXTENDED0 || datain == KBR_EXTENDED1)
789 		return datain;
790 
791 	/*
792 	 * Convert BREAK sequence (14 77 -> 1D 45)
793 	 */
794 	if (id->t_extended1 == 2 && datain == 0x14)
795 		return 0x1d | id->t_releasing;
796 	else if (id->t_extended1 == 1 && datain == 0x77)
797 		return 0x45 | id->t_releasing;
798 
799 	if (id->t_extended0 != 0) {
800 		if (datain >= sizeof pckbd_xtbl_ext)
801 			datain = 0;
802 		else
803 			datain = pckbd_xtbl_ext[datain];
804 	} else {
805 		if (datain >= sizeof pckbd_xtbl)
806 			datain = 0;
807 		else
808 			datain = pckbd_xtbl[datain];
809 	}
810 
811 	/*
812 	 * If we are mapping in the range 128-254, then make this
813 	 * an extended keycode, as table 1 codes are limited to
814 	 * the range 0-127 (the top bit is used for key up/break).
815 	 */
816 	if (datain > 0x7f) {
817 		datain &= 0x7f;
818 		id->t_extended0 = 0x80;
819 	}
820 
821 	if (datain == 0) {
822 		/*
823 		 * We don't know how to translate this scan code, but
824 		 * we can't silently eat it either (because there might
825 		 * have been an extended byte transmitted already).
826 		 * Hopefully this value will be harmless to the upper
827 		 * layers.
828 		 */
829 		return 0xff;
830 	}
831 	return datain | id->t_releasing;
832 }
833 
834 static int
835 pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout)
836 {
837 	int key;
838 	int releasing;
839 
840 	if (datain == KBR_EXTENDED0) {
841 		id->t_extended0 = 0x80;
842 		return 0;
843 	} else if (datain == KBR_EXTENDED1) {
844 		id->t_extended1 = 2;
845 		return 0;
846 	}
847 
848 	releasing = datain & 0x80;
849 	datain &= 0x7f;
850 
851 	if (id->t_extended0 == 0x80) {
852 		switch (datain) {
853 		case 0x2a:
854 		case 0x36:
855 			id->t_extended0 = 0;
856 			return 0;
857 		default:
858 			break;
859 		}
860 	}
861 
862 	/* map extended keys to (unused) codes 128-254 */
863 	key = datain | id->t_extended0;
864 	id->t_extended0 = 0;
865 
866 	/*
867 	 * process PAUSE (also break) key (EXT1 1D 45  EXT1 9D C5):
868 	 * map to (unused) code 7F
869 	 */
870 	if (id->t_extended1 == 2 && (datain == 0x1d || datain == 0x9d)) {
871 		id->t_extended1 = 1;
872 		return 0;
873 	} else if (id->t_extended1 == 1 &&
874 		   (datain == 0x45 || datain == 0xc5)) {
875 		id->t_extended1 = 0;
876 		key = 0x7f;
877 	} else if (id->t_extended1 > 0) {
878 		id->t_extended1 = 0;
879 	}
880 
881 	if (id->t_translating != 0) {
882 		id->t_releasing = releasing;
883 	} else {
884 		/* id->t_releasing computed in pckbd_scancode_translate() */
885 	}
886 
887 	if (id->t_releasing) {
888 		id->t_releasing = 0;
889 		id->t_lastchar = 0;
890 		*type = WSCONS_EVENT_KEY_UP;
891 	} else {
892 		/* Always ignore typematic keys */
893 		if (key == id->t_lastchar)
894 			return 0;
895 		id->t_lastchar = key;
896 		*type = WSCONS_EVENT_KEY_DOWN;
897 	}
898 
899 	*dataout = key;
900 	return 1;
901 }
902 
903 int
904 pckbd_init(struct pckbd_internal *t, pckbport_tag_t kbctag,
905     pckbport_slot_t kbcslot, int console)
906 {
907 
908 	memset(t, 0, sizeof(struct pckbd_internal));
909 
910 	t->t_isconsole = console;
911 	t->t_kbctag = kbctag;
912 	t->t_kbcslot = kbcslot;
913 
914 	return pckbd_set_xtscancode(kbctag, kbcslot, t);
915 }
916 
917 static int
918 pckbd_led_encode(int led)
919 {
920 	int res;
921 
922 	res = 0;
923 
924 	if (led & WSKBD_LED_SCROLL)
925 		res |= 0x01;
926 	if (led & WSKBD_LED_NUM)
927 		res |= 0x02;
928 	if (led & WSKBD_LED_CAPS)
929 		res |= 0x04;
930 	return res;
931 }
932 
933 static int
934 pckbd_led_decode(int led)
935 {
936 	int res;
937 
938 	res = 0;
939 	if (led & 0x01)
940 		res |= WSKBD_LED_SCROLL;
941 	if (led & 0x02)
942 		res |= WSKBD_LED_NUM;
943 	if (led & 0x04)
944 		res |= WSKBD_LED_CAPS;
945 	return res;
946 }
947 
948 void
949 pckbd_set_leds(void *v, int leds)
950 {
951 	struct pckbd_softc *sc = v;
952 	u_char cmd[2];
953 
954 	cmd[0] = KBC_MODEIND;
955 	cmd[1] = pckbd_led_encode(leds);
956 	sc->sc_ledstate = cmd[1];
957 
958 	(void)pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
959 				 cmd, 2, 0, 0, 0);
960 }
961 
962 /*
963  * Got a console receive interrupt -
964  * the console processor wants to give us a character.
965  */
966 void
967 pckbd_input(void *vsc, int data)
968 {
969 	struct pckbd_softc *sc = vsc;
970 	int key;
971 	u_int type;
972 
973 	data = pckbd_scancode_translate(sc->id, data);
974 	if (data == 0)
975 		return;
976 
977 #ifdef WSDISPLAY_COMPAT_RAWKBD
978 	if (sc->rawkbd) {
979 		u_char d = data;
980 		wskbd_rawinput(sc->sc_wskbddev, &d, 1);
981 		return;
982 	}
983 #endif
984 	if (pckbd_decode(sc->id, data, &type, &key))
985 		wskbd_input(sc->sc_wskbddev, type, key);
986 }
987 
988 int
989 pckbd_ioctl(void *v, u_long cmd, void *data, int flag,
990     struct lwp *l)
991 {
992 	struct pckbd_softc *sc = v;
993 
994 	switch (cmd) {
995 	case WSKBDIO_GTYPE:
996 		*(int *)data = WSKBD_TYPE_PC_XT;
997 		return 0;
998 	case WSKBDIO_SETLEDS:
999 	{
1000 		int res;
1001 		u_char cmdb[2];
1002 
1003 		cmdb[0] = KBC_MODEIND;
1004 		cmdb[1] = pckbd_led_encode(*(int *)data);
1005 		sc->sc_ledstate = cmdb[1];
1006 		res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
1007 					cmdb, 2, 0, 1, 0);
1008 		return res;
1009 	}
1010 	case WSKBDIO_GETLEDS:
1011 		*(int *)data = pckbd_led_decode(sc->sc_ledstate);
1012 		return 0;
1013 #if 0
1014 	case WSKBDIO_COMPLEXBELL:
1015 #define d ((struct wskbd_bell_data *)data)
1016 		/*
1017 		 * Keyboard can't beep directly; we have an
1018 		 * externally-provided global hook to do this.
1019 		 */
1020 		pckbd_bell(d->pitch, d->period, d->volume, 0);
1021 #undef d
1022 		return 0;
1023 #endif
1024 #ifdef WSDISPLAY_COMPAT_RAWKBD
1025 	case WSKBDIO_SETMODE:
1026 		sc->rawkbd = (*(int *)data == WSKBD_RAW);
1027 		return 0;
1028 #endif
1029 	}
1030 	return EPASSTHROUGH;
1031 }
1032 
1033 void
1034 pckbd_bell(u_int pitch, u_int period, u_int volume, int poll)
1035 {
1036 
1037 	if (pckbd_bell_fn != NULL)
1038 		(*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period,
1039 		    volume, poll);
1040 }
1041 
1042 void
1043 pckbd_unhook_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg)
1044 {
1045 	if (pckbd_bell_fn != fn && pckbd_bell_fn_arg != arg)
1046 		return;
1047 	pckbd_bell_fn = NULL;
1048 	pckbd_bell_fn_arg = NULL;
1049 }
1050 
1051 void
1052 pckbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg)
1053 {
1054 
1055 	if (pckbd_bell_fn == NULL) {
1056 		pckbd_bell_fn = fn;
1057 		pckbd_bell_fn_arg = arg;
1058 	}
1059 }
1060 
1061 int
1062 pckbd_cnattach(pckbport_tag_t kbctag, int kbcslot)
1063 {
1064 	int res;
1065 	u_char cmd[1];
1066 
1067 	res = pckbd_init(&pckbd_consdata, kbctag, kbcslot, 1);
1068 	/* We may allow the console to be attached if no keyboard is present */
1069 #if defined(PCKBD_CNATTACH_MAY_FAIL)
1070 	if (res)
1071 		return res;
1072 #endif
1073 
1074 	/* Just to be sure. */
1075 	cmd[0] = KBC_ENABLE;
1076 	res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 1, 0, 0, 0);
1077 
1078 #if defined(PCKBD_CNATTACH_MAY_FAIL)
1079 	if (res)
1080 		return res;
1081 #endif
1082 
1083 	wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata);
1084 
1085 	return res;
1086 }
1087 
1088 /* ARGSUSED */
1089 void
1090 pckbd_cngetc(void *v, u_int *type, int *data)
1091 {
1092         struct pckbd_internal *t = v;
1093 	int val;
1094 
1095 	for (;;) {
1096 		val = pckbport_poll_data(t->t_kbctag, t->t_kbcslot);
1097 		if (val == -1)
1098 			continue;
1099 
1100 		val = pckbd_scancode_translate(t, val);
1101 		if (val == 0)
1102 			continue;
1103 
1104 		if (pckbd_decode(t, val, type, data))
1105 			return;
1106 	}
1107 }
1108 
1109 void
1110 pckbd_cnpollc(void *v, int on)
1111 {
1112 	struct pckbd_internal *t = v;
1113 
1114 	pckbport_set_poll(t->t_kbctag, t->t_kbcslot, on);
1115 }
1116 
1117 void
1118 pckbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
1119 {
1120 
1121 	pckbd_bell(pitch, period, volume, 1);
1122 }
1123