Home | History | Annotate | Line # | Download | only in pckbport
      1 /* $NetBSD: pckbd.c,v 1.39 2024/02/09 22:08:36 andvar 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.39 2024/02/09 22:08:36 andvar 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 int pckbdprobe(device_t, cfdata_t, void *);
    128 void pckbdattach(device_t, device_t, void *);
    129 
    130 CFATTACH_DECL_NEW(pckbd, sizeof(struct pckbd_softc),
    131     pckbdprobe, pckbdattach, NULL, NULL);
    132 
    133 int	pckbd_enable(void *, int);
    134 void	pckbd_set_leds(void *, int);
    135 int	pckbd_ioctl(void *, u_long, void *, int, struct lwp *);
    136 
    137 const struct wskbd_accessops pckbd_accessops = {
    138 	.enable = pckbd_enable,
    139 	.set_leds = pckbd_set_leds,
    140 	.ioctl = pckbd_ioctl,
    141 };
    142 
    143 void	pckbd_cngetc(void *, u_int *, int *);
    144 void	pckbd_cnpollc(void *, int);
    145 void	pckbd_cnbell(void *, u_int, u_int, u_int);
    146 
    147 const struct wskbd_consops pckbd_consops = {
    148 	.getc = pckbd_cngetc,
    149 	.pollc = pckbd_cnpollc,
    150 	.bell = pckbd_cnbell,
    151 };
    152 
    153 const struct wskbd_mapdata pckbd_keymapdata = {
    154 	.keydesc = pckbd_keydesctab,
    155 #ifdef PCKBD_LAYOUT
    156 	.layout = PCKBD_LAYOUT,
    157 #else
    158 	.layout = KB_US,
    159 #endif
    160 };
    161 
    162 /*
    163  * Hackish support for a bell on the PC Keyboard; when a suitable beeper
    164  * is found, it attaches itself into the pckbd driver here.
    165  */
    166 void	(*pckbd_bell_fn)(void *, u_int, u_int, u_int, int);
    167 void	*pckbd_bell_fn_arg;
    168 
    169 void	pckbd_bell(u_int, u_int, u_int, int);
    170 
    171 int	pckbd_scancode_translate(struct pckbd_internal *, int);
    172 int	pckbd_set_xtscancode(pckbport_tag_t, pckbport_slot_t,
    173 	    struct pckbd_internal *);
    174 int	pckbd_init(struct pckbd_internal *, pckbport_tag_t, pckbport_slot_t,
    175 			int);
    176 void	pckbd_input(void *, int);
    177 
    178 struct pckbd_internal pckbd_consdata;
    179 
    180 int
    181 pckbd_set_xtscancode(pckbport_tag_t kbctag, pckbport_slot_t kbcslot,
    182     struct pckbd_internal *id)
    183 {
    184 	int xt, res = 0;
    185 	u_char cmd[2];
    186 
    187 	/*
    188 	 * Some keyboard/8042 combinations do not seem to work if the keyboard
    189 	 * is set to table 1; in fact, it would appear that some keyboards just
    190 	 * ignore the command altogether.  So by default, we use the AT scan
    191 	 * codes and have the 8042 translate them.  Unfortunately, this is
    192 	 * known to not work on some PS/2 machines.  We try desperately to deal
    193 	 * with this by checking the (lack of a) translate bit in the 8042 and
    194 	 * attempting to set the keyboard to XT mode.  If this all fails, well,
    195 	 * tough luck.  If the PCKBC_CANT_TRANSLATE pckbc flag was set, we
    196 	 * enable software translation.
    197 	 *
    198 	 * XXX It would perhaps be a better choice to just use AT scan codes
    199 	 * and not bother with this.
    200 	 */
    201 	xt = pckbport_xt_translation(kbctag, kbcslot, 1);
    202 	if (xt == 1) {
    203 		/* The 8042 is translating for us; use AT codes. */
    204 		cmd[0] = KBC_SETTABLE;
    205 		cmd[1] = 2;
    206 		res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0);
    207 		if (res) {
    208 			u_char cmdb[1];
    209 			aprint_debug("%s: error setting scanset 2\n", __func__);
    210 			/*
    211 			 * XXX at least one keyboard is reported to lock up
    212 			 * if a "set table" is attempted, thus the "reset".
    213 			 * XXX ignore errors, scanset 2 should be
    214 			 * default anyway.
    215 			 */
    216 			cmdb[0] = KBC_RESET;
    217 			(void)pckbport_poll_cmd(kbctag, kbcslot, cmdb, 1, 1,
    218 			    0, 1);
    219 			pckbport_flush(kbctag, kbcslot);
    220 			res = 0;
    221 		}
    222 		if (id != NULL)
    223 			id->t_translating = 1;
    224 	} else if (xt == -1) {
    225 		/* Software translation required */
    226 		if (id != NULL)
    227 			id->t_translating = 0;
    228 	} else {
    229 		/* Stupid 8042; set keyboard to XT codes. */
    230 		cmd[0] = KBC_SETTABLE;
    231 		cmd[1] = 1;
    232 		res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0);
    233 		if (res)
    234 			aprint_debug("%s: error setting scanset 1\n", __func__);
    235 		if (id != NULL)
    236 			id->t_translating = 1;
    237 	}
    238 	return res;
    239 }
    240 
    241 static int
    242 pckbd_is_console(pckbport_tag_t tag, pckbport_slot_t slot)
    243 {
    244 
    245 	return pckbd_consdata.t_isconsole &&
    246 	    tag == pckbd_consdata.t_kbctag && slot == pckbd_consdata.t_kbcslot;
    247 }
    248 
    249 static bool
    250 pckbd_suspend(device_t dv, const pmf_qual_t *qual)
    251 {
    252 	struct pckbd_softc *sc = device_private(dv);
    253 	u_char cmd[1];
    254 	int res;
    255 
    256 	/* XXX duped from pckbd_enable, but we want to disable
    257 	 *     it even if it's the console kbd
    258 	 */
    259 	cmd[0] = KBC_DISABLE;
    260 	res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
    261 	    cmd, 1, 0, 1, 0);
    262 	if (res)
    263 		return false;
    264 
    265 	pckbport_slot_enable(sc->id->t_kbctag,
    266 	    sc->id->t_kbcslot, 0);
    267 
    268 	sc->sc_enabled = 0;
    269 	return true;
    270 }
    271 
    272 static bool
    273 pckbd_resume(device_t dv, const pmf_qual_t *qual)
    274 {
    275 	struct pckbd_softc *sc = device_private(dv);
    276 	u_char cmd[1], resp[1];
    277 	int res;
    278 
    279 	/* XXX jmcneill reset the keyboard */
    280 	pckbport_flush(sc->id->t_kbctag, sc->id->t_kbcslot);
    281 
    282 	cmd[0] = KBC_RESET;
    283 	res = pckbport_poll_cmd(sc->id->t_kbctag,
    284 	    sc->id->t_kbcslot, cmd, 1, 1, resp, 1);
    285 	if (res)
    286 		aprint_debug("%s: reset error %d\n", __func__, res);
    287 	if (resp[0] != KBR_RSTDONE)
    288 		printf("%s: reset response 0x%x\n", __func__, resp[0]);
    289 
    290 	pckbport_flush(sc->id->t_kbctag, sc->id->t_kbcslot);
    291 
    292 	pckbd_enable(sc, 1);
    293 
    294 	return true;
    295 }
    296 
    297 /*
    298  * these are three bad jokes
    299  */
    300 static bool
    301 check_keyboard_by_id(struct pckbport_attach_args *pa)
    302 {
    303 	u_char cmd[1], resp[2];
    304 	int res;
    305 
    306 	cmd[0] = KBC_GETID;
    307 	res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 0);
    308 	if (res) {
    309 		aprint_debug("%s: getid failed with %d\n", __func__, res);
    310 		return false;
    311 	}
    312 
    313 	switch (resp[0]) {
    314 	case 0xab: case 0xac:	/* Regular and NCD Sun keyboards */
    315 	case 0x2b: case 0x5d:	/* Trust keyboard, raw and translated */
    316 	case 0x60: case 0x47:	/* NMB SGI keyboard, raw and translated */
    317 		return true;
    318 	default:
    319 		aprint_debug("%s: getid returned %#x\n", __func__, resp[0]);
    320 		return false;
    321 	}
    322 
    323 }
    324 
    325 int
    326 pckbdprobe(device_t parent, cfdata_t cf, void *aux)
    327 {
    328 	struct pckbport_attach_args *pa = aux;
    329 	int res;
    330 	u_char cmd[1], resp[1];
    331 
    332 	/*
    333 	 * XXX There are rumours that a keyboard can be connected
    334 	 * to the aux port as well. For me, this didn't work.
    335 	 * For further experiments, allow it if explicitly
    336 	 * wired in the config file.
    337 	 */
    338 	if ((pa->pa_slot != PCKBPORT_KBD_SLOT) &&
    339 	    (cf->cf_loc[PCKBPORTCF_SLOT] == PCKBPORTCF_SLOT_DEFAULT))
    340 		return 0;
    341 
    342 	/* Flush any garbage. */
    343 	pckbport_flush(pa->pa_tag, pa->pa_slot);
    344 
    345 	/* Reset the keyboard. */
    346 	cmd[0] = KBC_RESET;
    347 	res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1);
    348 	if (res) {
    349 		aprint_debug("%s: reset error %d\n", __func__, res);
    350 
    351 		/*
    352 		 * On Chromebooks reset fails but otherwise the controller
    353 		 * works fine.
    354 		 * Check keyboard IDs similar to Linux and Haiku.
    355 		 * FreeBSD's approach here is to skip probing if
    356 		 * coreboot is detected which is suboptimal as coreboot
    357 		 * also supports some mac models which have no PC controller
    358 		 */
    359 		if (check_keyboard_by_id(pa)) {
    360 			if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, NULL))
    361 				return 0;
    362 			return 2;
    363 		}
    364 
    365 		/*
    366 		 * There is probably no keyboard connected.
    367 		 * Let the probe succeed if the keyboard is used
    368 		 * as console input - it can be connected later.
    369 		 */
    370 		return pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0;
    371 	}
    372 	if (resp[0] != KBR_RSTDONE) {
    373 		printf("%s: reset response %#x\n", __func__, resp[0]);
    374 
    375 		if (check_keyboard_by_id(pa)) {
    376 			if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, NULL))
    377 				return 0;
    378 			return 2;
    379 		}
    380 
    381 		return 0;
    382 	}
    383 
    384 	/*
    385 	 * Some keyboards seem to leave a second ack byte after the reset.
    386 	 * This is kind of stupid, but we account for them anyway by just
    387 	 * flushing the buffer.
    388 	 */
    389 	pckbport_flush(pa->pa_tag, pa->pa_slot);
    390 
    391 	if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, NULL))
    392 		return 0;
    393 
    394 	return 2;
    395 }
    396 
    397 void
    398 pckbdattach(device_t parent, device_t self, void *aux)
    399 {
    400 	struct pckbd_softc *sc = device_private(self);
    401 	struct pckbport_attach_args *pa = aux;
    402 	struct wskbddev_attach_args a;
    403 	int isconsole;
    404 	u_char cmd[1];
    405 
    406 	aprint_naive("\n");
    407 	aprint_normal("\n");
    408 
    409 	sc->sc_dev = self;
    410 	isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot);
    411 
    412 	if (isconsole) {
    413 		sc->id = &pckbd_consdata;
    414 
    415 		/*
    416 		 * Some keyboards are not enabled after a reset,
    417 		 * so make sure it is enabled now.
    418 		 */
    419 		cmd[0] = KBC_ENABLE;
    420 		(void) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
    421 		    cmd, 1, 0, 0, 0);
    422 		sc->sc_enabled = 1;
    423 	} else {
    424 		sc->id = malloc(sizeof(*sc->id), M_DEVBUF, M_WAITOK);
    425 		(void) pckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0);
    426 
    427 		/* no interrupts until enabled */
    428 		cmd[0] = KBC_DISABLE;
    429 		(void) pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
    430 		    cmd, 1, 0, 0, 0);
    431 		sc->sc_enabled = 0;
    432 	}
    433 
    434 	sc->id->t_sc = sc;
    435 
    436 	pckbport_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot,
    437 			       pckbd_input, sc, device_xname(sc->sc_dev));
    438 
    439 	a.console = isconsole;
    440 
    441 	a.keymap = &pckbd_keymapdata;
    442 
    443 	a.accessops = &pckbd_accessops;
    444 	a.accesscookie = sc;
    445 
    446 	if (!pmf_device_register(self, pckbd_suspend, pckbd_resume))
    447 		aprint_error_dev(self, "couldn't establish power handler\n");
    448 
    449 	/*
    450 	 * Attach the wskbd, saving a handle to it.
    451 	 * XXX XXX XXX
    452 	 */
    453 	sc->sc_wskbddev = config_found(self, &a, wskbddevprint, CFARGS_NONE);
    454 }
    455 
    456 int
    457 pckbd_enable(void *v, int on)
    458 {
    459 	struct pckbd_softc *sc = v;
    460 	int res;
    461 	u_char cmd[1];
    462 
    463 	if (on) {
    464 		if (sc->sc_enabled) {
    465 			aprint_debug("%s: bad enable\n", __func__);
    466 			return EBUSY;
    467 		}
    468 
    469 		pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1);
    470 
    471 		cmd[0] = KBC_ENABLE;
    472 		res = pckbport_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
    473 		    cmd, 1, 0, NULL, 0);
    474 		if (res) {
    475 			printf("%s: command error\n", __func__);
    476 			return res;
    477 		}
    478 
    479 		res = pckbd_set_xtscancode(sc->id->t_kbctag,
    480 		    sc->id->t_kbcslot, sc->id);
    481 		if (res)
    482 			return res;
    483 
    484 		sc->sc_enabled = 1;
    485 	} else {
    486 		if (sc->id->t_isconsole)
    487 			return EBUSY;
    488 
    489 		cmd[0] = KBC_DISABLE;
    490 		res = pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
    491 		    cmd, 1, 0, 1, 0);
    492 		if (res) {
    493 			printf("%s: command error\n", __func__);
    494 			return res;
    495 		}
    496 
    497 		pckbport_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0);
    498 
    499 		sc->sc_enabled = 0;
    500 	}
    501 
    502 	return 0;
    503 }
    504 
    505 const u_int8_t pckbd_xtbl[] = {
    506 /* 0x00 */
    507 	0,
    508 	0x43,		/* F9 */
    509 	0x89,		/* SunStop */
    510 	0x3f,		/* F5 */
    511 	0x3d,		/* F3 */
    512 	0x3b,		/* F1 */
    513 	0x3c,		/* F2 */
    514 	0x58,		/* F12 */
    515 	0,
    516 	0x44,		/* F10 */
    517 	0x42,		/* F8 */
    518 	0x40,		/* F6 */
    519 	0x3e,		/* F4 */
    520 	0x0f,		/* Tab */
    521 	0x29,		/* ` ~ */
    522 	0,
    523 /* 0x10 */
    524 	0,
    525 	0x38,		/* Left Alt */
    526 	0x2a,		/* Left Shift */
    527 	0,
    528 	0x1d,		/* Left Ctrl */
    529 	0x10,		/* q */
    530 	0x02,		/* 1 ! */
    531 	0,
    532 	0,
    533 	0,
    534 	0x2c,		/* z */
    535 	0x1f,		/* s */
    536 	0x1e,		/* a */
    537 	0x11,		/* w */
    538 	0x03,		/* 2 @ */
    539 	0,
    540 /* 0x20 */
    541 	0,
    542 	0x2e,		/* c */
    543 	0x2d,		/* x */
    544 	0x20,		/* d */
    545 	0x12,		/* e */
    546 	0x05,		/* 4 $ */
    547 	0x04,		/* 3 # */
    548 	0,
    549 	0,
    550 	0x39,		/* Space */
    551 	0x2f,		/* v */
    552 	0x21,		/* f */
    553 	0x14,		/* t */
    554 	0x13,		/* r */
    555 	0x06,		/* 5 % */
    556 	0,
    557 /* 0x30 */
    558 	0,
    559 	0x31,		/* n */
    560 	0x30,		/* b */
    561 	0x23,		/* h */
    562 	0x22,		/* g */
    563 	0x15,		/* y */
    564 	0x07,		/* 6 ^ */
    565 	0,
    566 	0,
    567 	0,
    568 	0x32,		/* m */
    569 	0x24,		/* j */
    570 	0x16,		/* u */
    571 	0x08,		/* 7 & */
    572 	0x09,		/* 8 * */
    573 	0,
    574 /* 0x40 */
    575 	0,
    576 	0x33,		/* , < */
    577 	0x25,		/* k */
    578 	0x17,		/* i */
    579 	0x18,		/* o */
    580 	0x0b,		/* 0 ) */
    581 	0x0a,		/* 9 ( */
    582 	0,
    583 	0,
    584 	0x34,		/* . > */
    585 	0x35,		/* / ? */
    586 	0x26,		/* l */
    587 	0x27,		/* ; : */
    588 	0x19,		/* p */
    589 	0x0c,		/* - _ */
    590 	0,
    591 /* 0x50 */
    592 	0,
    593 	0,
    594 	0x28,		/* ' " */
    595 	0,
    596 	0x1a,		/* [ { */
    597 	0x0d,		/* = + */
    598 	0,
    599 	0,
    600 	0x3a,		/* Caps Lock */
    601 	0x36,		/* Right Shift */
    602 	0x1c,		/* Return */
    603 	0x1b,		/* ] } */
    604 	0,
    605 	0x2b,		/* \ | */
    606 	0,
    607 	0,
    608 /* 0x60 */
    609 	0,
    610 	0,
    611 	0,
    612 	0,
    613 	0,
    614 	0,
    615 	0x0e,		/* Back Space */
    616 	0,
    617 	0,
    618 	0x4f,		/* KP 1 */
    619 	0,
    620 	0x4b,		/* KP 4 */
    621 	0x47,		/* KP 7 */
    622 	0,
    623 	0,
    624 	0,
    625 /* 0x70 */
    626 	0x52,		/* KP 0 */
    627 	0x53,		/* KP . */
    628 	0x50,		/* KP 2 */
    629 	0x4c,		/* KP 5 */
    630 	0x4d,		/* KP 6 */
    631 	0x48,		/* KP 8 */
    632 	0x01,		/* Escape */
    633 	0x45,		/* Num Lock */
    634 	0x57,		/* F11 */
    635 	0x4e,		/* KP + */
    636 	0x51,		/* KP 3 */
    637 	0x4a,		/* KP - */
    638 	0x37,		/* KP * */
    639 	0x49,		/* KP 9 */
    640 	0x46,		/* Scroll Lock */
    641 	0,
    642 /* 0x80 */
    643 	0,
    644 	0,
    645 	0,
    646 	0x41,		/* F7 (produced as an actual 8 bit code) */
    647 	0,		/* Alt-Print Screen */
    648 	0,
    649 	0,
    650 	0,
    651 	0,
    652 	0,
    653 	0,
    654 	0,
    655 	0,
    656 	0,
    657 	0,
    658 	0,
    659 /* 0x90 */
    660 	0xdb,		/* Left Meta */
    661 	0x88,		/* SunHelp */
    662 	0x8a,		/* SunAgain */
    663 	0x8c,		/* SunUndo */
    664 	0x8e,		/* SunCopy */
    665 	0x90,		/* SunPaste */
    666 	0x92,		/* SunCut */
    667 	0x8b,		/* SunProps */
    668 	0x8d,		/* SunFront */
    669 	0x8f,		/* SunOpen */
    670 	0x91		/* SunFind */
    671 };
    672 
    673 const u_int8_t pckbd_xtbl_ext[] = {
    674 /* 0x00 */
    675 	0,
    676 	0,
    677 	0,
    678 	0,
    679 	0,
    680 	0,
    681 	0,
    682 	0,
    683 	0,
    684 	0,
    685 	0,
    686 	0,
    687 	0,
    688 	0,
    689 	0,
    690 	0,
    691 /* 0x10 */
    692 	0,
    693 	0x38,		/* Right Alt */
    694 	0,		/* E0 12, to be ignored */
    695 	0,
    696 	0x1d,		/* Right Ctrl */
    697 	0,
    698 	0,
    699 	0,
    700 	0,
    701 	0,
    702 	0,
    703 	0,
    704 	0,
    705 	0,
    706 	0,
    707 	0,
    708 /* 0x20 */
    709 	0,
    710 	0,
    711 	0,
    712 	0,
    713 	0,
    714 	0,
    715 	0,
    716 	0,
    717 	0,
    718 	0,
    719 	0,
    720 	0,
    721 	0,
    722 	0,
    723 	0,
    724 	0xdd,		/* Compose */
    725 /* 0x30 */
    726 	0,
    727 	0,
    728 	0,
    729 	0,
    730 	0,
    731 	0,
    732 	0,
    733 	0,
    734 	0,
    735 	0,
    736 	0,
    737 	0,
    738 	0,
    739 	0,
    740 	0,
    741 	0,
    742 /* 0x40 */
    743 	0,
    744 	0,
    745 	0,
    746 	0,
    747 	0,
    748 	0,
    749 	0,
    750 	0,
    751 	0,
    752 	0,
    753 	0xb5,		/* KP / */
    754 	0,
    755 	0,
    756 	0,
    757 	0,
    758 	0,
    759 /* 0x50 */
    760 	0,
    761 	0,
    762 	0,
    763 	0,
    764 	0,
    765 	0,
    766 	0,
    767 	0,
    768 	0,
    769 	0,
    770 	0x1c,		/* KP Return */
    771 	0,
    772 	0,
    773 	0,
    774 	0,
    775 	0,
    776 /* 0x60 */
    777 	0,
    778 	0,
    779 	0,
    780 	0,
    781 	0,
    782 	0,
    783 	0,
    784 	0,
    785 	0,
    786 	0x4f,		/* End */
    787 	0,
    788 	0x4b,		/* Left */
    789 	0x47,		/* Home */
    790 	0,
    791 	0,
    792 	0,
    793 /* 0x70 */
    794 	0x52,		/* Insert */
    795 	0x53,		/* Delete */
    796 	0x50,		/* Down */
    797 	0,
    798 	0x4d,		/* Right */
    799 	0x48,		/* Up */
    800 	0,
    801 	0,
    802 	0,
    803 	0,
    804 	0x51,		/* Page Down */
    805 	0,
    806 	0x37,		/* Print Screen */
    807 	0x49,		/* Page Up */
    808 	0x46,		/* Ctrl-Break */
    809 	0
    810 };
    811 
    812 /*
    813  * Translate scan codes from set 2 to set 1
    814  */
    815 int
    816 pckbd_scancode_translate(struct pckbd_internal *id, int datain)
    817 {
    818 	if (id->t_translating != 0)
    819 		return datain;
    820 
    821 	if (datain == KBR_BREAK) {
    822 		id->t_releasing = 0x80;	/* next keycode is a release */
    823 		return 0;	/* consume scancode */
    824 	}
    825 
    826 	/*
    827 	 * Handle extended sequences
    828 	 */
    829 	if (datain == KBR_EXTENDED0 || datain == KBR_EXTENDED1)
    830 		return datain;
    831 
    832 	/*
    833 	 * Convert BREAK sequence (14 77 -> 1D 45)
    834 	 */
    835 	if (id->t_extended1 == 2 && datain == 0x14)
    836 		return 0x1d | id->t_releasing;
    837 	else if (id->t_extended1 == 1 && datain == 0x77)
    838 		return 0x45 | id->t_releasing;
    839 
    840 	if (id->t_extended0 != 0) {
    841 		if (datain >= sizeof pckbd_xtbl_ext)
    842 			datain = 0;
    843 		else
    844 			datain = pckbd_xtbl_ext[datain];
    845 	} else {
    846 		if (datain >= sizeof pckbd_xtbl)
    847 			datain = 0;
    848 		else
    849 			datain = pckbd_xtbl[datain];
    850 	}
    851 
    852 	/*
    853 	 * If we are mapping in the range 128-254, then make this
    854 	 * an extended keycode, as table 1 codes are limited to
    855 	 * the range 0-127 (the top bit is used for key up/break).
    856 	 */
    857 	if (datain > 0x7f) {
    858 		datain &= 0x7f;
    859 		id->t_extended0 = 0x80;
    860 	}
    861 
    862 	if (datain == 0) {
    863 		/*
    864 		 * We don't know how to translate this scan code, but
    865 		 * we can't silently eat it either (because there might
    866 		 * have been an extended byte transmitted already).
    867 		 * Hopefully this value will be harmless to the upper
    868 		 * layers.
    869 		 */
    870 		return 0xff;
    871 	}
    872 	return datain | id->t_releasing;
    873 }
    874 
    875 static bool
    876 pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout)
    877 {
    878 	int key;
    879 	int releasing;
    880 
    881 	if (datain == KBR_EXTENDED0) {
    882 		id->t_extended0 = 0x80;
    883 		return false;
    884 	} else if (datain == KBR_EXTENDED1) {
    885 		id->t_extended1 = 2;
    886 		return false;
    887 	}
    888 
    889 	releasing = datain & 0x80;
    890 	datain &= 0x7f;
    891 
    892 	if (id->t_extended0 == 0x80) {
    893 		switch (datain) {
    894 		case 0x2a:
    895 		case 0x36:
    896 			id->t_extended0 = 0;
    897 			return false;
    898 		default:
    899 			break;
    900 		}
    901 	}
    902 
    903 	/* map extended keys to (unused) codes 128-254 */
    904 	key = datain | id->t_extended0;
    905 	id->t_extended0 = 0;
    906 
    907 	/*
    908 	 * process PAUSE (also break) key (EXT1 1D 45  EXT1 9D C5):
    909 	 * map to (unused) code 7F
    910 	 */
    911 	if (id->t_extended1 == 2 && (datain == 0x1d || datain == 0x9d)) {
    912 		id->t_extended1 = 1;
    913 		return false;
    914 	} else if (id->t_extended1 == 1 &&
    915 		   (datain == 0x45 || datain == 0xc5)) {
    916 		id->t_extended1 = 0;
    917 		key = 0x7f;
    918 	} else if (id->t_extended1 > 0) {
    919 		id->t_extended1 = 0;
    920 	}
    921 
    922 	if (id->t_translating != 0) {
    923 		id->t_releasing = releasing;
    924 	} else {
    925 		/* id->t_releasing computed in pckbd_scancode_translate() */
    926 	}
    927 
    928 	if (id->t_releasing) {
    929 		id->t_releasing = 0;
    930 		id->t_lastchar = 0;
    931 		*type = WSCONS_EVENT_KEY_UP;
    932 	} else {
    933 		/* Always ignore typematic keys */
    934 		if (key == id->t_lastchar)
    935 			return false;
    936 		id->t_lastchar = key;
    937 		*type = WSCONS_EVENT_KEY_DOWN;
    938 	}
    939 
    940 	*dataout = key;
    941 	return true;
    942 }
    943 
    944 int
    945 pckbd_init(struct pckbd_internal *t, pckbport_tag_t kbctag,
    946     pckbport_slot_t kbcslot, int console)
    947 {
    948 
    949 	memset(t, 0, sizeof(struct pckbd_internal));
    950 
    951 	t->t_isconsole = console;
    952 	t->t_kbctag = kbctag;
    953 	t->t_kbcslot = kbcslot;
    954 
    955 	return pckbd_set_xtscancode(kbctag, kbcslot, t);
    956 }
    957 
    958 static int
    959 pckbd_led_encode(int led)
    960 {
    961 	int res;
    962 
    963 	res = 0;
    964 
    965 	if (led & WSKBD_LED_SCROLL)
    966 		res |= 0x01;
    967 	if (led & WSKBD_LED_NUM)
    968 		res |= 0x02;
    969 	if (led & WSKBD_LED_CAPS)
    970 		res |= 0x04;
    971 	return res;
    972 }
    973 
    974 static int
    975 pckbd_led_decode(int led)
    976 {
    977 	int res;
    978 
    979 	res = 0;
    980 	if (led & 0x01)
    981 		res |= WSKBD_LED_SCROLL;
    982 	if (led & 0x02)
    983 		res |= WSKBD_LED_NUM;
    984 	if (led & 0x04)
    985 		res |= WSKBD_LED_CAPS;
    986 	return res;
    987 }
    988 
    989 void
    990 pckbd_set_leds(void *v, int leds)
    991 {
    992 	struct pckbd_softc *sc = v;
    993 	u_char cmd[2];
    994 
    995 	cmd[0] = KBC_MODEIND;
    996 	cmd[1] = pckbd_led_encode(leds);
    997 	sc->sc_ledstate = cmd[1];
    998 
    999 	(void)pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
   1000 	    cmd, 2, 0, 0, 0);
   1001 }
   1002 
   1003 /*
   1004  * Got a console receive interrupt -
   1005  * the console processor wants to give us a character.
   1006  */
   1007 void
   1008 pckbd_input(void *vsc, int data)
   1009 {
   1010 	struct pckbd_softc *sc = vsc;
   1011 	int key;
   1012 	u_int type;
   1013 
   1014 	data = pckbd_scancode_translate(sc->id, data);
   1015 	if (data == 0)
   1016 		return;
   1017 
   1018 #ifdef WSDISPLAY_COMPAT_RAWKBD
   1019 	if (sc->rawkbd) {
   1020 		u_char d = data;
   1021 		wskbd_rawinput(sc->sc_wskbddev, &d, 1);
   1022 		return;
   1023 	}
   1024 #endif
   1025 	if (pckbd_decode(sc->id, data, &type, &key))
   1026 		wskbd_input(sc->sc_wskbddev, type, key);
   1027 }
   1028 
   1029 int
   1030 pckbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
   1031 {
   1032 	struct pckbd_softc *sc = v;
   1033 	u_char cmdb[2];
   1034 
   1035 	switch (cmd) {
   1036 	case WSKBDIO_GTYPE:
   1037 		*(int *)data = WSKBD_TYPE_PC_XT;
   1038 		return 0;
   1039 	case WSKBDIO_SETLEDS:
   1040 		cmdb[0] = KBC_MODEIND;
   1041 		cmdb[1] = pckbd_led_encode(*(int *)data);
   1042 		sc->sc_ledstate = cmdb[1];
   1043 		return pckbport_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
   1044 		    cmdb, 2, 0, 1, 0);
   1045 	case WSKBDIO_GETLEDS:
   1046 		*(int *)data = pckbd_led_decode(sc->sc_ledstate);
   1047 		return 0;
   1048 #if 0
   1049 	case WSKBDIO_COMPLEXBELL:
   1050 #define d ((struct wskbd_bell_data *)data)
   1051 		/*
   1052 		 * Keyboard can't beep directly; we have an
   1053 		 * externally-provided global hook to do this.
   1054 		 */
   1055 		pckbd_bell(d->pitch, d->period, d->volume, 0);
   1056 #undef d
   1057 		return 0;
   1058 #endif
   1059 #ifdef WSDISPLAY_COMPAT_RAWKBD
   1060 	case WSKBDIO_SETMODE:
   1061 		sc->rawkbd = (*(int *)data == WSKBD_RAW);
   1062 		return 0;
   1063 #endif
   1064 	}
   1065 	return EPASSTHROUGH;
   1066 }
   1067 
   1068 void
   1069 pckbd_bell(u_int pitch, u_int period, u_int volume, int poll)
   1070 {
   1071 
   1072 	if (pckbd_bell_fn != NULL)
   1073 		(*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period,
   1074 		    volume, poll);
   1075 }
   1076 
   1077 void
   1078 pckbd_unhook_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg)
   1079 {
   1080 	if (pckbd_bell_fn != fn && pckbd_bell_fn_arg != arg)
   1081 		return;
   1082 	pckbd_bell_fn = NULL;
   1083 	pckbd_bell_fn_arg = NULL;
   1084 }
   1085 
   1086 void
   1087 pckbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg)
   1088 {
   1089 
   1090 	if (pckbd_bell_fn == NULL) {
   1091 		pckbd_bell_fn = fn;
   1092 		pckbd_bell_fn_arg = arg;
   1093 	}
   1094 }
   1095 
   1096 int
   1097 pckbd_cnattach(pckbport_tag_t kbctag, int kbcslot)
   1098 {
   1099 	int res;
   1100 	u_char cmd[1];
   1101 
   1102 	res = pckbd_init(&pckbd_consdata, kbctag, kbcslot, 1);
   1103 	/* We may allow the console to be attached if no keyboard is present */
   1104 #if defined(PCKBD_CNATTACH_MAY_FAIL)
   1105 	if (res)
   1106 		return res;
   1107 #endif
   1108 
   1109 	/* Just to be sure. */
   1110 	cmd[0] = KBC_ENABLE;
   1111 	res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 1, 0, 0, 0);
   1112 
   1113 #if defined(PCKBD_CNATTACH_MAY_FAIL)
   1114 	if (res)
   1115 		return res;
   1116 #endif
   1117 
   1118 	wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata);
   1119 
   1120 	return res;
   1121 }
   1122 
   1123 /* ARGSUSED */
   1124 void
   1125 pckbd_cngetc(void *v, u_int *type, int *data)
   1126 {
   1127         struct pckbd_internal *t = v;
   1128 	int val;
   1129 
   1130 	for (;;) {
   1131 		val = pckbport_poll_data(t->t_kbctag, t->t_kbcslot);
   1132 		if (val == -1) {
   1133 			*type = 0;
   1134 			*data = 0;
   1135 			return;
   1136 		}
   1137 
   1138 		val = pckbd_scancode_translate(t, val);
   1139 		if (val == 0)
   1140 			continue;
   1141 
   1142 		if (pckbd_decode(t, val, type, data))
   1143 			return;
   1144 	}
   1145 }
   1146 
   1147 void
   1148 pckbd_cnpollc(void *v, int on)
   1149 {
   1150 	struct pckbd_internal *t = v;
   1151 
   1152 	pckbport_set_poll(t->t_kbctag, t->t_kbcslot, on);
   1153 }
   1154 
   1155 void
   1156 pckbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
   1157 {
   1158 
   1159 	pckbd_bell(pitch, period, volume, 1);
   1160 }
   1161