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;
 	}
 }

Reply via email to