Module Name: src Committed By: jdc Date: Sat Oct 13 17:51:28 UTC 2012
Modified Files: src/sys/dev/ic: pckbc.c src/sys/dev/pckbport: pckbd.c Log Message: Add two flags to keyboard/mouse attachment: PCKBC_CANT_TRANSLATE for keyboards that cannot translate to XT scancodes PCKBC_NEED_AUXWRITE for mice that don't probe first time These flags can be set by the port-specific attachments. Add the translation table and function to handle set 2 to set 1 keyboard translation in software. Based on OpenBSD sys/dev/ic/pckbc.c revisions 1.10, 1.16, 1.17, and sys/dev/pckbc/pckbd.c revision 1.15, and 8042 scan code information at: http://www.computer-engineering.org/ps2keyboard/ Note, that this changes the signature of pckbc_cnattach(), so ride the kernel version bump for namei. To generate a diff of this commit: cvs rdiff -u -r1.53 -r1.54 src/sys/dev/ic/pckbc.c cvs rdiff -u -r1.29 -r1.30 src/sys/dev/pckbport/pckbd.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ic/pckbc.c diff -u src/sys/dev/ic/pckbc.c:1.53 src/sys/dev/ic/pckbc.c:1.54 --- src/sys/dev/ic/pckbc.c:1.53 Thu Feb 2 19:43:03 2012 +++ src/sys/dev/ic/pckbc.c Sat Oct 13 17:51:28 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: pckbc.c,v 1.53 2012/02/02 19:43:03 tls Exp $ */ +/* $NetBSD: pckbc.c,v 1.54 2012/10/13 17:51:28 jdc Exp $ */ /* * Copyright (c) 2004 Ben Harris. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pckbc.c,v 1.53 2012/02/02 19:43:03 tls Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pckbc.c,v 1.54 2012/10/13 17:51:28 jdc Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -354,6 +354,20 @@ pckbc_attach(struct pckbc_softc *sc) t->t_haveaux = 1; bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */ res = pckbc_poll_data1(t, PCKBC_AUX_SLOT); + + /* + * The following is needed to find the aux port on the Tadpole + * SPARCle. + */ + if (res == -1 && ISSET(t->t_flags, PCKBC_NEED_AUXWRITE)) { + /* Read of aux echo timed out, try again */ + if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE)) + goto nomouse; + if (!pckbc_wait_output(iot, ioh_c)) + goto nomouse; + bus_space_write_1(iot, ioh_d, 0, 0x5a); + res = pckbc_poll_data1(t, PCKBC_AUX_SLOT); + } if (res != -1) { /* * In most cases, the 0x5a gets echoed. @@ -365,6 +379,7 @@ pckbc_attach(struct pckbc_softc *sc) if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT)) cmdbits |= KC8_MENABLE; } else { + #ifdef PCKBCDEBUG printf("pckbc: aux echo test failed\n"); #endif @@ -395,6 +410,9 @@ pckbc_xt_translation(void *self, pckbc_s struct pckbc_internal *t = self; int ison; + if (ISSET(t->t_flags, PCKBC_CANT_TRANSLATE)) + return (-1); + if (slot != PCKBC_KBD_SLOT) { /* translation only for kbd slot */ if (on) @@ -602,7 +620,7 @@ pckbcintr(void *vsc) int pckbc_cnattach(bus_space_tag_t iot, bus_addr_t addr, - bus_size_t cmd_offset, pckbc_slot_t slot) + bus_size_t cmd_offset, pckbc_slot_t slot, int flags) { bus_space_handle_t ioh_d, ioh_c; #ifdef PCKBC_CNATTACH_SELFTEST @@ -622,6 +640,7 @@ pckbc_cnattach(bus_space_tag_t iot, bus_ pckbc_consdata.t_ioh_d = ioh_d; pckbc_consdata.t_ioh_c = ioh_c; pckbc_consdata.t_addr = addr; + pckbc_consdata.t_flags = flags; callout_init(&pckbc_consdata.t_cleanup, 0); /* flush */ Index: src/sys/dev/pckbport/pckbd.c diff -u src/sys/dev/pckbport/pckbd.c:1.29 src/sys/dev/pckbport/pckbd.c:1.30 --- src/sys/dev/pckbport/pckbd.c:1.29 Wed Feb 24 22:38:08 2010 +++ src/sys/dev/pckbport/pckbd.c Sat Oct 13 17:51:28 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: pckbd.c,v 1.29 2010/02/24 22:38:08 dyoung Exp $ */ +/* $NetBSD: pckbd.c,v 1.30 2012/10/13 17:51:28 jdc Exp $ */ /*- * Copyright (c) 1998, 2009 The NetBSD Foundation, Inc. @@ -68,7 +68,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pckbd.c,v 1.29 2010/02/24 22:38:08 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pckbd.c,v 1.30 2012/10/13 17:51:28 jdc Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -100,9 +100,12 @@ struct pckbd_internal { pckbport_tag_t t_kbctag; pckbport_slot_t t_kbcslot; + int t_translating; + int t_lastchar; int t_extended0; int t_extended1; + int t_releasing; struct pckbd_softc *t_sc; /* back pointer */ }; @@ -167,7 +170,9 @@ void *pckbd_bell_fn_arg; void pckbd_bell(u_int, u_int, u_int, int); -int pckbd_set_xtscancode(pckbport_tag_t, pckbport_slot_t); +int pckbd_scancode_translate(struct pckbd_internal *, int); +int pckbd_set_xtscancode(pckbport_tag_t, pckbport_slot_t, + struct pckbd_internal *); int pckbd_init(struct pckbd_internal *, pckbport_tag_t, pckbport_slot_t, int); void pckbd_input(void *, int); @@ -179,9 +184,10 @@ static int pckbd_led_decode(int); struct pckbd_internal pckbd_consdata; int -pckbd_set_xtscancode(pckbport_tag_t kbctag, pckbport_slot_t kbcslot) +pckbd_set_xtscancode(pckbport_tag_t kbctag, pckbport_slot_t kbcslot, + struct pckbd_internal *id) { - int res; + int xt, res = 0; u_char cmd[2]; /* @@ -192,12 +198,14 @@ pckbd_set_xtscancode(pckbport_tag_t kbct * known to not work on some PS/2 machines. We try desperately to deal * with this by checking the (lack of a) translate bit in the 8042 and * attempting to set the keyboard to XT mode. If this all fails, well, - * tough luck. + * tough luck. If the PCKBC_CANT_TRANSLATE pckbc flag was set, we + * enable software translation. * * XXX It would perhaps be a better choice to just use AT scan codes * and not bother with this. */ - if (pckbport_xt_translation(kbctag, kbcslot, 1)) { + xt = pckbport_xt_translation(kbctag, kbcslot, 1); + if (xt == 1) { /* The 8042 is translating for us; use AT codes. */ cmd[0] = KBC_SETTABLE; cmd[1] = 2; @@ -216,6 +224,12 @@ pckbd_set_xtscancode(pckbport_tag_t kbct pckbport_flush(kbctag, kbcslot); res = 0; } + if (id != NULL) + id->t_translating = 1; + } else if (xt == -1) { + /* Software translation required */ + if (id != NULL) + id->t_translating = 0; } else { /* Stupid 8042; set keyboard to XT codes. */ cmd[0] = KBC_SETTABLE; @@ -223,6 +237,8 @@ pckbd_set_xtscancode(pckbport_tag_t kbct res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0); if (res) aprint_debug("pckbd: error setting scanset 1\n"); + if (id != NULL) + id->t_translating = 1; } return res; } @@ -331,7 +347,7 @@ pckbdprobe(device_t parent, cfdata_t cf, */ pckbport_flush(pa->pa_tag, pa->pa_slot); - if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot)) + if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, NULL)) return 0; return 2; @@ -421,7 +437,7 @@ pckbd_enable(void *v, int on) } res = pckbd_set_xtscancode(sc->id->t_kbctag, - sc->id->t_kbcslot); + sc->id->t_kbcslot, sc->id); if (res) return res; @@ -446,21 +462,395 @@ pckbd_enable(void *v, int on) return 0; } +const u_int8_t pckbd_xtbl[] = { +/* 0x00 */ + 0, + 0x43, /* F9 */ + 0x89, /* SunStop */ + 0x3f, /* F5 */ + 0x3d, /* F3 */ + 0x3b, /* F1 */ + 0x3c, /* F2 */ + 0x58, /* F12 */ + 0, + 0x44, /* F10 */ + 0x42, /* F8 */ + 0x40, /* F6 */ + 0x3e, /* F4 */ + 0x0f, /* Tab */ + 0x29, /* ` ~ */ + 0, +/* 0x10 */ + 0, + 0x38, /* Left Alt */ + 0x2a, /* Left Shift */ + 0, + 0x1d, /* Left Ctrl */ + 0x10, /* q */ + 0x02, /* 1 ! */ + 0, + 0, + 0, + 0x2c, /* z */ + 0x1f, /* s */ + 0x1e, /* a */ + 0x11, /* w */ + 0x03, /* 2 @ */ + 0, +/* 0x20 */ + 0, + 0x2e, /* c */ + 0x2d, /* x */ + 0x20, /* d */ + 0x12, /* e */ + 0x05, /* 4 $ */ + 0x04, /* 3 # */ + 0, + 0, + 0x39, /* Space */ + 0x2f, /* v */ + 0x21, /* f */ + 0x14, /* t */ + 0x13, /* r */ + 0x06, /* 5 % */ + 0, +/* 0x30 */ + 0, + 0x31, /* n */ + 0x30, /* b */ + 0x23, /* h */ + 0x22, /* g */ + 0x15, /* y */ + 0x07, /* 6 ^ */ + 0, + 0, + 0, + 0x32, /* m */ + 0x24, /* j */ + 0x16, /* u */ + 0x08, /* 7 & */ + 0x09, /* 8 * */ + 0, +/* 0x40 */ + 0, + 0x33, /* , < */ + 0x25, /* k */ + 0x17, /* i */ + 0x18, /* o */ + 0x0b, /* 0 ) */ + 0x0a, /* 9 ( */ + 0, + 0, + 0x34, /* . > */ + 0x35, /* / ? */ + 0x26, /* l */ + 0x27, /* ; : */ + 0x19, /* p */ + 0x0c, /* - _ */ + 0, +/* 0x50 */ + 0, + 0, + 0x28, /* ' " */ + 0, + 0x1a, /* [ { */ + 0x0d, /* = + */ + 0, + 0, + 0x3a, /* Caps Lock */ + 0x36, /* Right Shift */ + 0x1c, /* Return */ + 0x1b, /* ] } */ + 0, + 0x2b, /* \ | */ + 0, + 0, +/* 0x60 */ + 0, + 0, + 0, + 0, + 0, + 0, + 0x0e, /* Back Space */ + 0, + 0, + 0x4f, /* KP 1 */ + 0, + 0x4b, /* KP 4 */ + 0x47, /* KP 7 */ + 0, + 0, + 0, +/* 0x70 */ + 0x52, /* KP 0 */ + 0x53, /* KP . */ + 0x50, /* KP 2 */ + 0x4c, /* KP 5 */ + 0x4d, /* KP 6 */ + 0x48, /* KP 8 */ + 0x01, /* Escape */ + 0x45, /* Num Lock */ + 0x57, /* F11 */ + 0x4e, /* KP + */ + 0x51, /* KP 3 */ + 0x4a, /* KP - */ + 0x37, /* KP * */ + 0x49, /* KP 9 */ + 0x46, /* Scroll Lock */ + 0, +/* 0x80 */ + 0, + 0, + 0, + 0x41, /* F7 (produced as an actual 8 bit code) */ + 0, /* Alt-Print Screen */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +/* 0x90 */ + 0xdb, /* Left Meta */ + 0x88, /* SunHelp */ + 0x8a, /* SunAgain */ + 0x8c, /* SunUndo */ + 0x8e, /* SunCopy */ + 0x90, /* SunPaste */ + 0x92, /* SunCut */ + 0x8b, /* SunProps */ + 0x8d, /* SunFront */ + 0x8f, /* SunOpen */ + 0x91 /* SunFind */ +}; + +const u_int8_t pckbd_xtbl_ext[] = { +/* 0x00 */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +/* 0x10 */ + 0, + 0x38, /* Right Alt */ + 0, /* E0 12, to be ignored */ + 0, + 0x1d, /* Right Ctrl */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +/* 0x20 */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0xdd, /* Compose */ +/* 0x30 */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +/* 0x40 */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0xb5, /* KP / */ + 0, + 0, + 0, + 0, + 0, +/* 0x50 */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0x1c, /* KP Return */ + 0, + 0, + 0, + 0, + 0, +/* 0x60 */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0x4f, /* End */ + 0, + 0x4b, /* Left */ + 0x47, /* Home */ + 0, + 0, + 0, +/* 0x70 */ + 0x52, /* Insert */ + 0x53, /* Delete */ + 0x50, /* Down */ + 0, + 0x4d, /* Right */ + 0x48, /* Up */ + 0, + 0, + 0, + 0, + 0x51, /* Page Down */ + 0, + 0x37, /* Print Screen */ + 0x49, /* Page Up */ + 0x46, /* Ctrl-Break */ + 0 +}; + +/* + * Translate scan codes from set 2 to set 1 + */ +int +pckbd_scancode_translate(struct pckbd_internal *id, int datain) +{ + if (id->t_translating != 0) + return datain; + + if (datain == KBR_BREAK) { + id->t_releasing = 0x80; /* next keycode is a release */ + return 0; /* consume scancode */ + } + + /* + * Handle extended sequences + */ + if (datain == KBR_EXTENDED0 || datain == KBR_EXTENDED1) + return datain; + + /* + * Convert BREAK sequence (14 77 -> 1D 45) + */ + if (id->t_extended1 == 2 && datain == 0x14) + return 0x1d | id->t_releasing; + else if (id->t_extended1 == 1 && datain == 0x77) + return 0x45 | id->t_releasing; + + if (id->t_extended0 != 0) { + if (datain >= sizeof pckbd_xtbl_ext) + datain = 0; + else + datain = pckbd_xtbl_ext[datain]; + } else { + if (datain >= sizeof pckbd_xtbl) + datain = 0; + else + datain = pckbd_xtbl[datain]; + } + + /* + * If we are mapping in the range 128-254, then make this + * an extended keycode, as table 1 codes are limited to + * the range 0-127 (the top bit is used for key up/break). + */ + if (datain > 0x7f) { + datain &= 0x7f; + id->t_extended0 = 0x80; + } + + if (datain == 0) { + /* + * We don't know how to translate this scan code, but + * we can't silently eat it either (because there might + * have been an extended byte transmitted already). + * Hopefully this value will be harmless to the upper + * layers. + */ + return 0xff; + } + return datain | id->t_releasing; +} + static int pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout) { int key; + int releasing; if (datain == KBR_EXTENDED0) { - id->t_extended0 = 1; + id->t_extended0 = 0x80; return 0; } else if (datain == KBR_EXTENDED1) { id->t_extended1 = 2; return 0; } - if (id->t_extended0 == 1) { - switch (datain & 0x7f) { + releasing = datain & 0x80; + datain &= 0x7f; + + if (id->t_extended0 == 0x80) { + switch (datain) { case 0x2a: case 0x36: id->t_extended0 = 0; @@ -470,8 +860,8 @@ pckbd_decode(struct pckbd_internal *id, } } - /* map extended keys to (unused) codes 128-254 */ - key = (datain & 0x7f) | (id->t_extended0 ? 0x80 : 0); + /* map extended keys to (unused) codes 128-254 */ + key = datain | id->t_extended0; id->t_extended0 = 0; /* @@ -489,7 +879,14 @@ pckbd_decode(struct pckbd_internal *id, id->t_extended1 = 0; } - if (datain & 0x80) { + if (id->t_translating != 0) { + id->t_releasing = releasing; + } else { + /* id->t_releasing computed in pckbd_scancode_translate() */ + } + + if (id->t_releasing) { + id->t_releasing = 0; id->t_lastchar = 0; *type = WSCONS_EVENT_KEY_UP; } else { @@ -515,7 +912,7 @@ pckbd_init(struct pckbd_internal *t, pck t->t_kbctag = kbctag; t->t_kbcslot = kbcslot; - return pckbd_set_xtscancode(kbctag, kbcslot); + return pckbd_set_xtscancode(kbctag, kbcslot, t); } static int @@ -574,6 +971,10 @@ pckbd_input(void *vsc, int data) int key; u_int type; + data = pckbd_scancode_translate(sc->id, data); + if (data == 0) + return; + #ifdef WSDISPLAY_COMPAT_RAWKBD if (sc->rawkbd) { u_char d = data; @@ -692,7 +1093,14 @@ pckbd_cngetc(void *v, u_int *type, int * for (;;) { val = pckbport_poll_data(t->t_kbctag, t->t_kbcslot); - if ((val != -1) && pckbd_decode(t, val, type, data)) + if (val == -1) + continue; + + val = pckbd_scancode_translate(t, val); + if (val == 0) + continue; + + if (pckbd_decode(t, val, type, data)) return; } }