Home | History | Annotate | Line # | Download | only in pckbport
pckbd.c revision 1.31
      1 /* $NetBSD: pckbd.c,v 1.31 2013/09/15 09:24:05 martin 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.31 2013/09/15 09:24:05 martin 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("pckbdprobe: reset error %d\n", res);
    292 	if (resp[0] != KBR_RSTDONE)
    293 		printf("pckbdprobe: reset response 0x%x\n",
    294 		    resp[0]);
    295 
    296 	pckbport_flush(sc->id->t_kbctag, sc->id->t_kbcslot);
    297 
    298 	pckbd_enable(sc, 1);
    299 
    300 	return true;
    301 }
    302 
    303 /*
    304  * these are both bad jokes
    305  */
    306 int
    307 pckbdprobe(device_t parent, cfdata_t cf, void *aux)
    308 {
    309 	struct pckbport_attach_args *pa = aux;
    310 	int res;
    311 	u_char cmd[1], resp[1];
    312 
    313 	/*
    314 	 * XXX There are rumours that a keyboard can be connected
    315 	 * to the aux port as well. For me, this didn't work.
    316 	 * For further experiments, allow it if explicitly
    317 	 * wired in the config file.
    318 	 */
    319 	if ((pa->pa_slot != PCKBPORT_KBD_SLOT) &&
    320 	    (cf->cf_loc[PCKBPORTCF_SLOT] == PCKBPORTCF_SLOT_DEFAULT))
    321 		return 0;
    322 
    323 	/* Flush any garbage. */
    324 	pckbport_flush(pa->pa_tag, pa->pa_slot);
    325 
    326 	/* Reset the keyboard. */
    327 	cmd[0] = KBC_RESET;
    328 	res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1);
    329 	if (res) {
    330 		aprint_debug("pckbdprobe: reset error %d\n", res);
    331 		/*
    332 		 * There is probably no keyboard connected.
    333 		 * Let the probe succeed if the keyboard is used
    334 		 * as console input - it can be connected later.
    335 		 */
    336 		return pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0;
    337 	}
    338 	if (resp[0] != KBR_RSTDONE) {
    339 		printf("pckbdprobe: reset response 0x%x\n", resp[0]);
    340 		return 0;
    341 	}
    342 
    343 	/*
    344 	 * Some keyboards seem to leave a second ack byte after the reset.
    345 	 * This is kind of stupid, but we account for them anyway by just
    346 	 * flushing the buffer.
    347 	 */
    348 	pckbport_flush(pa->pa_tag, pa->pa_slot);
    349 
    350 	if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, NULL))
    351 		return 0;
    352 
    353 	return 2;
    354 }
    355 
    356 void
    357 pckbdattach(device_t parent, device_t self, void *aux)
    358 {
    359 	struct pckbd_softc *sc = device_private(self);
    360 	struct pckbport_attach_args *pa = aux;
    361 	struct wskbddev_attach_args a;
    362 	int isconsole;
    363 	u_char cmd[1];
    364 
    365 	aprint_naive("\n");
    366 	aprint_normal("\n");
    367 
    368 	sc->sc_dev = self;
    369 	isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot);
    370 
    371 	if (isconsole) {
    372 		sc->id = &pckbd_consdata;
    373 
    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) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
    380 				      cmd, 1, 0, 0, 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) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
    390 				      cmd, 1, 0, 0, 0);
    391 		sc->sc_enabled = 0;
    392 	}
    393 
    394 	sc->id->t_sc = sc;
    395 
    396 	pckbport_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot,
    397 			       pckbd_input, sc, device_xname(sc->sc_dev));
    398 
    399 	a.console = isconsole;
    400 
    401 	a.keymap = &pckbd_keymapdata;
    402 
    403 	a.accessops = &pckbd_accessops;
    404 	a.accesscookie = sc;
    405 
    406 	if (!pmf_device_register(self, pckbd_suspend, pckbd_resume))
    407 		aprint_error_dev(self, "couldn't establish power handler\n");
    408 
    409 	/*
    410 	 * Attach the wskbd, saving a handle to it.
    411 	 * XXX XXX XXX
    412 	 */
    413 	sc->sc_wskbddev = config_found_ia(self, "wskbddev", &a, wskbddevprint);
    414 }
    415 
    416 int
    417 pckbd_enable(void *v, int on)
    418 {
    419 	struct pckbd_softc *sc = v;
    420 	int res;
    421 	u_char cmd[1];
    422 
    423 	if (on) {
    424 		if (sc->sc_enabled) {
    425 			aprint_debug("pckbd_enable: bad enable\n");
    426 			return EBUSY;
    427 		}
    428 
    429 		pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1);
    430 
    431 		cmd[0] = KBC_ENABLE;
    432 		res = pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
    433 					cmd, 1, 0, NULL, 0);
    434 		if (res) {
    435 			printf("pckbd_enable: command error\n");
    436 			return (res);
    437 		}
    438 
    439 		res = pckbd_set_xtscancode(sc->id->t_kbctag,
    440 					   sc->id->t_kbcslot, sc->id);
    441 		if (res)
    442 			return res;
    443 
    444 		sc->sc_enabled = 1;
    445 	} else {
    446 		if (sc->id->t_isconsole)
    447 			return EBUSY;
    448 
    449 		cmd[0] = KBC_DISABLE;
    450 		res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
    451 					cmd, 1, 0, 1, 0);
    452 		if (res) {
    453 			printf("pckbd_disable: command error\n");
    454 			return res;
    455 		}
    456 
    457 		pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0);
    458 
    459 		sc->sc_enabled = 0;
    460 	}
    461 
    462 	return 0;
    463 }
    464 
    465 const u_int8_t pckbd_xtbl[] = {
    466 /* 0x00 */
    467 	0,
    468 	0x43,		/* F9 */
    469 	0x89,		/* SunStop */
    470 	0x3f,		/* F5 */
    471 	0x3d,		/* F3 */
    472 	0x3b,		/* F1 */
    473 	0x3c,		/* F2 */
    474 	0x58,		/* F12 */
    475 	0,
    476 	0x44,		/* F10 */
    477 	0x42,		/* F8 */
    478 	0x40,		/* F6 */
    479 	0x3e,		/* F4 */
    480 	0x0f,		/* Tab */
    481 	0x29,		/* ` ~ */
    482 	0,
    483 /* 0x10 */
    484 	0,
    485 	0x38,		/* Left Alt */
    486 	0x2a,		/* Left Shift */
    487 	0,
    488 	0x1d,		/* Left Ctrl */
    489 	0x10,		/* q */
    490 	0x02,		/* 1 ! */
    491 	0,
    492 	0,
    493 	0,
    494 	0x2c,		/* z */
    495 	0x1f,		/* s */
    496 	0x1e,		/* a */
    497 	0x11,		/* w */
    498 	0x03,		/* 2 @ */
    499 	0,
    500 /* 0x20 */
    501 	0,
    502 	0x2e,		/* c */
    503 	0x2d,		/* x */
    504 	0x20,		/* d */
    505 	0x12,		/* e */
    506 	0x05,		/* 4 $ */
    507 	0x04,		/* 3 # */
    508 	0,
    509 	0,
    510 	0x39,		/* Space */
    511 	0x2f,		/* v */
    512 	0x21,		/* f */
    513 	0x14,		/* t */
    514 	0x13,		/* r */
    515 	0x06,		/* 5 % */
    516 	0,
    517 /* 0x30 */
    518 	0,
    519 	0x31,		/* n */
    520 	0x30,		/* b */
    521 	0x23,		/* h */
    522 	0x22,		/* g */
    523 	0x15,		/* y */
    524 	0x07,		/* 6 ^ */
    525 	0,
    526 	0,
    527 	0,
    528 	0x32,		/* m */
    529 	0x24,		/* j */
    530 	0x16,		/* u */
    531 	0x08,		/* 7 & */
    532 	0x09,		/* 8 * */
    533 	0,
    534 /* 0x40 */
    535 	0,
    536 	0x33,		/* , < */
    537 	0x25,		/* k */
    538 	0x17,		/* i */
    539 	0x18,		/* o */
    540 	0x0b,		/* 0 ) */
    541 	0x0a,		/* 9 ( */
    542 	0,
    543 	0,
    544 	0x34,		/* . > */
    545 	0x35,		/* / ? */
    546 	0x26,		/* l */
    547 	0x27,		/* ; : */
    548 	0x19,		/* p */
    549 	0x0c,		/* - _ */
    550 	0,
    551 /* 0x50 */
    552 	0,
    553 	0,
    554 	0x28,		/* ' " */
    555 	0,
    556 	0x1a,		/* [ { */
    557 	0x0d,		/* = + */
    558 	0,
    559 	0,
    560 	0x3a,		/* Caps Lock */
    561 	0x36,		/* Right Shift */
    562 	0x1c,		/* Return */
    563 	0x1b,		/* ] } */
    564 	0,
    565 	0x2b,		/* \ | */
    566 	0,
    567 	0,
    568 /* 0x60 */
    569 	0,
    570 	0,
    571 	0,
    572 	0,
    573 	0,
    574 	0,
    575 	0x0e,		/* Back Space */
    576 	0,
    577 	0,
    578 	0x4f,		/* KP 1 */
    579 	0,
    580 	0x4b,		/* KP 4 */
    581 	0x47,		/* KP 7 */
    582 	0,
    583 	0,
    584 	0,
    585 /* 0x70 */
    586 	0x52,		/* KP 0 */
    587 	0x53,		/* KP . */
    588 	0x50,		/* KP 2 */
    589 	0x4c,		/* KP 5 */
    590 	0x4d,		/* KP 6 */
    591 	0x48,		/* KP 8 */
    592 	0x01,		/* Escape */
    593 	0x45,		/* Num Lock */
    594 	0x57,		/* F11 */
    595 	0x4e,		/* KP + */
    596 	0x51,		/* KP 3 */
    597 	0x4a,		/* KP - */
    598 	0x37,		/* KP * */
    599 	0x49,		/* KP 9 */
    600 	0x46,		/* Scroll Lock */
    601 	0,
    602 /* 0x80 */
    603 	0,
    604 	0,
    605 	0,
    606 	0x41,		/* F7 (produced as an actual 8 bit code) */
    607 	0,		/* Alt-Print Screen */
    608 	0,
    609 	0,
    610 	0,
    611 	0,
    612 	0,
    613 	0,
    614 	0,
    615 	0,
    616 	0,
    617 	0,
    618 	0,
    619 /* 0x90 */
    620 	0xdb,		/* Left Meta */
    621 	0x88,		/* SunHelp */
    622 	0x8a,		/* SunAgain */
    623 	0x8c,		/* SunUndo */
    624 	0x8e,		/* SunCopy */
    625 	0x90,		/* SunPaste */
    626 	0x92,		/* SunCut */
    627 	0x8b,		/* SunProps */
    628 	0x8d,		/* SunFront */
    629 	0x8f,		/* SunOpen */
    630 	0x91		/* SunFind */
    631 };
    632 
    633 const u_int8_t pckbd_xtbl_ext[] = {
    634 /* 0x00 */
    635 	0,
    636 	0,
    637 	0,
    638 	0,
    639 	0,
    640 	0,
    641 	0,
    642 	0,
    643 	0,
    644 	0,
    645 	0,
    646 	0,
    647 	0,
    648 	0,
    649 	0,
    650 	0,
    651 /* 0x10 */
    652 	0,
    653 	0x38,		/* Right Alt */
    654 	0,		/* E0 12, to be ignored */
    655 	0,
    656 	0x1d,		/* Right Ctrl */
    657 	0,
    658 	0,
    659 	0,
    660 	0,
    661 	0,
    662 	0,
    663 	0,
    664 	0,
    665 	0,
    666 	0,
    667 	0,
    668 /* 0x20 */
    669 	0,
    670 	0,
    671 	0,
    672 	0,
    673 	0,
    674 	0,
    675 	0,
    676 	0,
    677 	0,
    678 	0,
    679 	0,
    680 	0,
    681 	0,
    682 	0,
    683 	0,
    684 	0xdd,		/* Compose */
    685 /* 0x30 */
    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 	0,
    702 /* 0x40 */
    703 	0,
    704 	0,
    705 	0,
    706 	0,
    707 	0,
    708 	0,
    709 	0,
    710 	0,
    711 	0,
    712 	0,
    713 	0xb5,		/* KP / */
    714 	0,
    715 	0,
    716 	0,
    717 	0,
    718 	0,
    719 /* 0x50 */
    720 	0,
    721 	0,
    722 	0,
    723 	0,
    724 	0,
    725 	0,
    726 	0,
    727 	0,
    728 	0,
    729 	0,
    730 	0x1c,		/* KP Return */
    731 	0,
    732 	0,
    733 	0,
    734 	0,
    735 	0,
    736 /* 0x60 */
    737 	0,
    738 	0,
    739 	0,
    740 	0,
    741 	0,
    742 	0,
    743 	0,
    744 	0,
    745 	0,
    746 	0x4f,		/* End */
    747 	0,
    748 	0x4b,		/* Left */
    749 	0x47,		/* Home */
    750 	0,
    751 	0,
    752 	0,
    753 /* 0x70 */
    754 	0x52,		/* Insert */
    755 	0x53,		/* Delete */
    756 	0x50,		/* Down */
    757 	0,
    758 	0x4d,		/* Right */
    759 	0x48,		/* Up */
    760 	0,
    761 	0,
    762 	0,
    763 	0,
    764 	0x51,		/* Page Down */
    765 	0,
    766 	0x37,		/* Print Screen */
    767 	0x49,		/* Page Up */
    768 	0x46,		/* Ctrl-Break */
    769 	0
    770 };
    771 
    772 /*
    773  * Translate scan codes from set 2 to set 1
    774  */
    775 int
    776 pckbd_scancode_translate(struct pckbd_internal *id, int datain)
    777 {
    778 	if (id->t_translating != 0)
    779 		return datain;
    780 
    781 	if (datain == KBR_BREAK) {
    782 		id->t_releasing = 0x80;	/* next keycode is a release */
    783 		return 0;	/* consume scancode */
    784 	}
    785 
    786 	/*
    787 	 * Handle extended sequences
    788 	 */
    789 	if (datain == KBR_EXTENDED0 || datain == KBR_EXTENDED1)
    790 		return datain;
    791 
    792 	/*
    793 	 * Convert BREAK sequence (14 77 -> 1D 45)
    794 	 */
    795 	if (id->t_extended1 == 2 && datain == 0x14)
    796 		return 0x1d | id->t_releasing;
    797 	else if (id->t_extended1 == 1 && datain == 0x77)
    798 		return 0x45 | id->t_releasing;
    799 
    800 	if (id->t_extended0 != 0) {
    801 		if (datain >= sizeof pckbd_xtbl_ext)
    802 			datain = 0;
    803 		else
    804 			datain = pckbd_xtbl_ext[datain];
    805 	} else {
    806 		if (datain >= sizeof pckbd_xtbl)
    807 			datain = 0;
    808 		else
    809 			datain = pckbd_xtbl[datain];
    810 	}
    811 
    812 	/*
    813 	 * If we are mapping in the range 128-254, then make this
    814 	 * an extended keycode, as table 1 codes are limited to
    815 	 * the range 0-127 (the top bit is used for key up/break).
    816 	 */
    817 	if (datain > 0x7f) {
    818 		datain &= 0x7f;
    819 		id->t_extended0 = 0x80;
    820 	}
    821 
    822 	if (datain == 0) {
    823 		/*
    824 		 * We don't know how to translate this scan code, but
    825 		 * we can't silently eat it either (because there might
    826 		 * have been an extended byte transmitted already).
    827 		 * Hopefully this value will be harmless to the upper
    828 		 * layers.
    829 		 */
    830 		return 0xff;
    831 	}
    832 	return datain | id->t_releasing;
    833 }
    834 
    835 static int
    836 pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout)
    837 {
    838 	int key;
    839 	int releasing;
    840 
    841 	if (datain == KBR_EXTENDED0) {
    842 		id->t_extended0 = 0x80;
    843 		return 0;
    844 	} else if (datain == KBR_EXTENDED1) {
    845 		id->t_extended1 = 2;
    846 		return 0;
    847 	}
    848 
    849 	releasing = datain & 0x80;
    850 	datain &= 0x7f;
    851 
    852 	if (id->t_extended0 == 0x80) {
    853 		switch (datain) {
    854 		case 0x2a:
    855 		case 0x36:
    856 			id->t_extended0 = 0;
    857 			return 0;
    858 		default:
    859 			break;
    860 		}
    861 	}
    862 
    863 	/* map extended keys to (unused) codes 128-254 */
    864 	key = datain | id->t_extended0;
    865 	id->t_extended0 = 0;
    866 
    867 	/*
    868 	 * process PAUSE (also break) key (EXT1 1D 45  EXT1 9D C5):
    869 	 * map to (unused) code 7F
    870 	 */
    871 	if (id->t_extended1 == 2 && (datain == 0x1d || datain == 0x9d)) {
    872 		id->t_extended1 = 1;
    873 		return 0;
    874 	} else if (id->t_extended1 == 1 &&
    875 		   (datain == 0x45 || datain == 0xc5)) {
    876 		id->t_extended1 = 0;
    877 		key = 0x7f;
    878 	} else if (id->t_extended1 > 0) {
    879 		id->t_extended1 = 0;
    880 	}
    881 
    882 	if (id->t_translating != 0) {
    883 		id->t_releasing = releasing;
    884 	} else {
    885 		/* id->t_releasing computed in pckbd_scancode_translate() */
    886 	}
    887 
    888 	if (id->t_releasing) {
    889 		id->t_releasing = 0;
    890 		id->t_lastchar = 0;
    891 		*type = WSCONS_EVENT_KEY_UP;
    892 	} else {
    893 		/* Always ignore typematic keys */
    894 		if (key == id->t_lastchar)
    895 			return 0;
    896 		id->t_lastchar = key;
    897 		*type = WSCONS_EVENT_KEY_DOWN;
    898 	}
    899 
    900 	*dataout = key;
    901 	return 1;
    902 }
    903 
    904 int
    905 pckbd_init(struct pckbd_internal *t, pckbport_tag_t kbctag,
    906     pckbport_slot_t kbcslot, int console)
    907 {
    908 
    909 	memset(t, 0, sizeof(struct pckbd_internal));
    910 
    911 	t->t_isconsole = console;
    912 	t->t_kbctag = kbctag;
    913 	t->t_kbcslot = kbcslot;
    914 
    915 	return pckbd_set_xtscancode(kbctag, kbcslot, t);
    916 }
    917 
    918 static int
    919 pckbd_led_encode(int led)
    920 {
    921 	int res;
    922 
    923 	res = 0;
    924 
    925 	if (led & WSKBD_LED_SCROLL)
    926 		res |= 0x01;
    927 	if (led & WSKBD_LED_NUM)
    928 		res |= 0x02;
    929 	if (led & WSKBD_LED_CAPS)
    930 		res |= 0x04;
    931 	return res;
    932 }
    933 
    934 static int
    935 pckbd_led_decode(int led)
    936 {
    937 	int res;
    938 
    939 	res = 0;
    940 	if (led & 0x01)
    941 		res |= WSKBD_LED_SCROLL;
    942 	if (led & 0x02)
    943 		res |= WSKBD_LED_NUM;
    944 	if (led & 0x04)
    945 		res |= WSKBD_LED_CAPS;
    946 	return res;
    947 }
    948 
    949 void
    950 pckbd_set_leds(void *v, int leds)
    951 {
    952 	struct pckbd_softc *sc = v;
    953 	u_char cmd[2];
    954 
    955 	cmd[0] = KBC_MODEIND;
    956 	cmd[1] = pckbd_led_encode(leds);
    957 	sc->sc_ledstate = cmd[1];
    958 
    959 	(void)pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
    960 				 cmd, 2, 0, 0, 0);
    961 }
    962 
    963 /*
    964  * Got a console receive interrupt -
    965  * the console processor wants to give us a character.
    966  */
    967 void
    968 pckbd_input(void *vsc, int data)
    969 {
    970 	struct pckbd_softc *sc = vsc;
    971 	int key;
    972 	u_int type;
    973 
    974 	data = pckbd_scancode_translate(sc->id, data);
    975 	if (data == 0)
    976 		return;
    977 
    978 #ifdef WSDISPLAY_COMPAT_RAWKBD
    979 	if (sc->rawkbd) {
    980 		u_char d = data;
    981 		wskbd_rawinput(sc->sc_wskbddev, &d, 1);
    982 		return;
    983 	}
    984 #endif
    985 	if (pckbd_decode(sc->id, data, &type, &key))
    986 		wskbd_input(sc->sc_wskbddev, type, key);
    987 }
    988 
    989 int
    990 pckbd_ioctl(void *v, u_long cmd, void *data, int flag,
    991     struct lwp *l)
    992 {
    993 	struct pckbd_softc *sc = v;
    994 
    995 	switch (cmd) {
    996 	case WSKBDIO_GTYPE:
    997 		*(int *)data = WSKBD_TYPE_PC_XT;
    998 		return 0;
    999 	case WSKBDIO_SETLEDS:
   1000 	{
   1001 		int res;
   1002 		u_char cmdb[2];
   1003 
   1004 		cmdb[0] = KBC_MODEIND;
   1005 		cmdb[1] = pckbd_led_encode(*(int *)data);
   1006 		sc->sc_ledstate = cmdb[1];
   1007 		res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
   1008 					cmdb, 2, 0, 1, 0);
   1009 		return res;
   1010 	}
   1011 	case WSKBDIO_GETLEDS:
   1012 		*(int *)data = pckbd_led_decode(sc->sc_ledstate);
   1013 		return 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 #ifdef WSDISPLAY_COMPAT_RAWKBD
   1024 	case WSKBDIO_SETMODE:
   1025 		sc->rawkbd = (*(int *)data == WSKBD_RAW);
   1026 		return 0;
   1027 #endif
   1028 	}
   1029 	return EPASSTHROUGH;
   1030 }
   1031 
   1032 void
   1033 pckbd_bell(u_int pitch, u_int period, u_int volume, int poll)
   1034 {
   1035 
   1036 	if (pckbd_bell_fn != NULL)
   1037 		(*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period,
   1038 		    volume, poll);
   1039 }
   1040 
   1041 void
   1042 pckbd_unhook_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg)
   1043 {
   1044 	if (pckbd_bell_fn != fn && pckbd_bell_fn_arg != arg)
   1045 		return;
   1046 	pckbd_bell_fn = NULL;
   1047 	pckbd_bell_fn_arg = NULL;
   1048 }
   1049 
   1050 void
   1051 pckbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg)
   1052 {
   1053 
   1054 	if (pckbd_bell_fn == NULL) {
   1055 		pckbd_bell_fn = fn;
   1056 		pckbd_bell_fn_arg = arg;
   1057 	}
   1058 }
   1059 
   1060 int
   1061 pckbd_cnattach(pckbport_tag_t kbctag, int kbcslot)
   1062 {
   1063 	int res;
   1064 	u_char cmd[1];
   1065 
   1066 	res = pckbd_init(&pckbd_consdata, kbctag, kbcslot, 1);
   1067 	/* We may allow the console to be attached if no keyboard is present */
   1068 #if defined(PCKBD_CNATTACH_MAY_FAIL)
   1069 	if (res)
   1070 		return res;
   1071 #endif
   1072 
   1073 	/* Just to be sure. */
   1074 	cmd[0] = KBC_ENABLE;
   1075 	res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 1, 0, 0, 0);
   1076 
   1077 #if defined(PCKBD_CNATTACH_MAY_FAIL)
   1078 	if (res)
   1079 		return res;
   1080 #endif
   1081 
   1082 	wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata);
   1083 
   1084 	return res;
   1085 }
   1086 
   1087 /* ARGSUSED */
   1088 void
   1089 pckbd_cngetc(void *v, u_int *type, int *data)
   1090 {
   1091         struct pckbd_internal *t = v;
   1092 	int val;
   1093 
   1094 	for (;;) {
   1095 		val = pckbport_poll_data(t->t_kbctag, t->t_kbcslot);
   1096 		if (val == -1)
   1097 			continue;
   1098 
   1099 		val = pckbd_scancode_translate(t, val);
   1100 		if (val == 0)
   1101 			continue;
   1102 
   1103 		if (pckbd_decode(t, val, type, data))
   1104 			return;
   1105 	}
   1106 }
   1107 
   1108 void
   1109 pckbd_cnpollc(void *v, int on)
   1110 {
   1111 	struct pckbd_internal *t = v;
   1112 
   1113 	pckbport_set_poll(t->t_kbctag, t->t_kbcslot, on);
   1114 }
   1115 
   1116 void
   1117 pckbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
   1118 {
   1119 
   1120 	pckbd_bell(pitch, period, volume, 1);
   1121 }
   1122