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.
This commit is contained in:
jdc 2012-10-13 17:51:28 +00:00
parent 2bcf8ce0cf
commit b0cdfa37f7
2 changed files with 447 additions and 20 deletions

View File

@ -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_slot_t slot, int on)
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_addr_t addr,
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 */

View File

@ -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 kbctag, pckbport_slot_t kbcslot)
* 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 kbctag, pckbport_slot_t kbcslot)
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 kbctag, pckbport_slot_t kbcslot)
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, void *aux)
*/
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, int datain, u_int *type, int *dataout)
}
}
/* 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, int datain, u_int *type, int *dataout)
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, pckbport_tag_t kbctag,
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 *data)
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;
}
}