Index: j720tp.c
===================================================================
RCS file: /cvsroot/src/sys/arch/hpcarm/dev/j720tp.c,v
retrieving revision 1.2
diff -u -r1.2 j720tp.c
--- j720tp.c	27 Jun 2006 14:36:50 -0000	1.2
+++ j720tp.c	24 Sep 2006 18:30:43 -0000
@@ -41,6 +41,11 @@
 #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD: j720tp.c,v 1.2 2006/06/27 14:36:50 peter Exp $");
 
+#ifdef _KERNEL_OPT
+#include "opt_j720tp.h"
+#include "opt_wsdisplay_compat.h"
+#endif
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
@@ -48,6 +53,7 @@
 #include <sys/malloc.h>
 #include <sys/ioctl.h>
 #include <sys/callout.h>
+#include <sys/sysctl.h>
 
 #include <machine/platid.h>
 #include <machine/platid_mask.h>
@@ -59,27 +65,44 @@
 
 #include <dev/wscons/wsconsio.h>
 #include <dev/wscons/wsmousevar.h>
+#include <dev/wscons/wskbdvar.h>
+#include <dev/wscons/wsksymvar.h>
+#include <dev/wscons/wsksymdef.h>
 #include <dev/hpc/hpctpanelvar.h>
 
 #include <hpcarm/dev/j720sspvar.h>
 
-#include "opt_j720tp.h"
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+#include <dev/hpc/pckbd_encode.h>
+#endif
+
+#define arraysize(ary)	(sizeof(ary) / sizeof(ary[0]))
 
 #ifdef J720TP_DEBUG
-#define DPRINTF(arg)	printf arg
+int j720tp_debug = 0;
+#define DPRINTF(arg)		if (j720tp_debug) printf arg
+#define DPRINTFN(n, arg)	if (j720tp_debug >= (n)) printf arg
 #else
-#define DPRINTF(arg)	/* nothing */
+#define DPRINTF(arg)		/* nothing */
+#define DPRINTFN(n, arg)	/* nothing */
 #endif
 
 struct j720tp_softc {
 	struct device		sc_dev;
 
+#define J720TP_WSMOUSE_ENABLED	0x01
+#define J720TP_WSKBD_ENABLED	0x02
 	int			sc_enabled;
+	int			sc_hard_icon;
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+	int			sc_rawkbd;
+#endif
 
 	struct callout		sc_tpcallout;
 	struct j720ssp_softc	*sc_ssp;
 
 	struct device		*sc_wsmousedev;
+	struct device		*sc_wskbddev;
 
 	struct tpcalib_softc	sc_tpcalib;
 };
@@ -92,13 +115,19 @@
 			struct lwp *);
 static void	j720tp_wsmouse_disable(void *);
 
+static int	j720tp_wskbd_enable(void *, int);
+static void	j720tp_wskbd_set_leds(void *, int);
+static int	j720tp_wskbd_ioctl(void *, u_long, caddr_t, int, struct lwp *);
+
 static void	j720tp_enable_intr(struct j720tp_softc *);
 static void	j720tp_disable_intr(struct j720tp_softc *);
 static int	j720tp_intr(void *);
 static int	j720tp_get_rawxy(struct j720tp_softc *, int *, int *);
+static int	j720tp_get_hard_icon(struct j720tp_softc *, int, int);
 static void	j720tp_wsmouse_input(struct j720tp_softc *, int, int);
 static void	j720tp_wsmouse_callout(void *);
-
+static void	j720tp_wskbd_input(struct j720tp_softc *, u_int);
+static void	j720tp_wskbd_callout(void *);
 
 const struct wsmouse_accessops j720tp_wsmouse_accessops = {
 	j720tp_wsmouse_enable,
@@ -115,6 +144,63 @@
 	 {  88, 940, 639, 239 }}
 };
 
+const struct wskbd_accessops j720tp_wskbd_accessops = {
+	j720tp_wskbd_enable,
+	j720tp_wskbd_set_leds,
+	j720tp_wskbd_ioctl
+};
+
+#ifndef J720TP_SETTINGS_ICON_KEYSYM
+#define J720TP_SETTINGS_ICON_KEYSYM	KS_Home
+#endif
+#ifndef J720TP_BACKUP_ICON_KEYSYM
+#define J720TP_BACKUP_ICON_KEYSYM	KS_Prior
+#endif
+#ifndef J720TP_DIALUP_ICON_KEYSYM
+#define J720TP_DIALUP_ICON_KEYSYM	KS_Next
+#endif
+#ifndef J720TP_MEDIA_ICON_KEYSYM
+#define J720TP_MEDIA_ICON_KEYSYM	KS_End
+#endif
+
+/* Max Y value of the n'th hard icon. */
+#define J720TP_HARD_ICON_MAX_Y(n) \
+	(((j720tp_hard_icon_bottom - j720tp_hard_icon_top) / 4) * (n)) + \
+	j720tp_hard_icon_top
+
+/* Default raw X/Y values of the hard icon area. */
+static int j720tp_hard_icon_left = 70;
+static int j720tp_hard_icon_right = 20;
+static int j720tp_hard_icon_top = 70;
+static int j720tp_hard_icon_bottom = 940;
+
+/* Maps the icon number to a raw keycode. */
+static const int j720tp_wskbd_keys[] = {
+	/* Icon 1 */ 199,
+	/* Icon 2 */ 201,
+	/* Icon 3 */ 209,
+	/* Icon 4 */ 207
+};
+
+static const keysym_t j720tp_wskbd_keydesc[] = {
+	KS_KEYCODE(199), J720TP_SETTINGS_ICON_KEYSYM,
+	KS_KEYCODE(201), J720TP_BACKUP_ICON_KEYSYM,
+	KS_KEYCODE(209), J720TP_DIALUP_ICON_KEYSYM,
+	KS_KEYCODE(207), J720TP_MEDIA_ICON_KEYSYM
+};
+
+const struct wscons_keydesc j720tp_wskbd_keydesctab[] = {
+	{ KB_US, 0,
+	  sizeof(j720tp_wskbd_keydesc) / sizeof(keysym_t),
+	  j720tp_wskbd_keydesc
+	},
+	{ 0, 0, 0, 0 }
+};
+
+const struct wskbd_mapdata j720tp_wskbd_keymapdata = {
+	j720tp_wskbd_keydesctab, KB_US
+};
+
 CFATTACH_DECL(j720tp, sizeof(struct j720tp_softc),
     j720tp_match, j720tp_attach, NULL, NULL);
 
@@ -134,13 +220,16 @@
 static void
 j720tp_attach(struct device *parent, struct device *self, void *aux)
 {
-        struct j720tp_softc *sc = (struct j720tp_softc *)self;
+	struct j720tp_softc *sc = (struct j720tp_softc *)self;
 	struct wsmousedev_attach_args wsma;
+	struct wskbddev_attach_args wska;
 
 	printf("\n");
 
 	sc->sc_ssp = (struct j720ssp_softc *)parent;
 	sc->sc_enabled = 0;
+	sc->sc_hard_icon = 0;
+	sc->sc_rawkbd = 0;
 
 	/* Touch-panel as a pointing device. */
 	wsma.accessops = &j720tp_wsmouse_accessops;
@@ -148,6 +237,8 @@
 
 	sc->sc_wsmousedev = config_found_ia(self, "wsmousedev", &wsma,
 	    wsmousedevprint);
+	if (sc->sc_wsmousedev == NULL)
+		return;
 
 	/* Initialize calibration, set default parameters. */
 	tpcalib_init(&sc->sc_tpcalib);
@@ -157,6 +248,15 @@
 	j720tp_wsmouse_disable(sc);
 	callout_init(&sc->sc_tpcallout);
 
+	/* On-screen "hard icons" as a keyboard device. */
+	wska.console = 0;
+	wska.keymap = &j720tp_wskbd_keymapdata;
+	wska.accessops = &j720tp_wskbd_accessops;
+	wska.accesscookie = sc;
+
+	sc->sc_wskbddev = config_found_ia(self, "wskbddev", &wska,
+	    wskbddevprint);
+
 	/* Setup touch-panel interrupt. */
 	sa11x0_intr_establish(0, 9, 1, IPL_TTY, j720tp_intr, sc);
 }
@@ -171,7 +271,7 @@
 
 	j720tp_enable_intr(sc);
 
-	sc->sc_enabled = 1;
+	sc->sc_enabled |= J720TP_WSMOUSE_ENABLED;
 
 	splx(s);
 	return 0;
@@ -197,11 +297,55 @@
 	j720tp_disable_intr(sc);
 	callout_stop(&sc->sc_tpcallout);
 
-	sc->sc_enabled = 0;
+	sc->sc_enabled &= ~J720TP_WSMOUSE_ENABLED;
 
 	splx(s);
 }
 
+static int
+j720tp_wskbd_enable(void *self, int on)
+{
+	struct j720tp_softc *sc = self;
+	int s;
+
+	s = spltty();
+	sc->sc_enabled |= J720TP_WSKBD_ENABLED;
+	splx(s);
+
+	return 0;
+}
+
+static void
+j720tp_wskbd_set_leds(void *self, int leds)
+{
+	/* nothing to do */
+}
+
+static int
+j720tp_wskbd_ioctl(void *self, u_long cmd, caddr_t data, int flag,
+    struct lwp *l)
+{
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+	struct j720tp_softc *sc = self;
+#endif
+
+	switch (cmd) {
+	case WSKBDIO_GTYPE:
+		*(int *)data = WSKBD_TYPE_HPC_BTN;
+		return 0;
+	case WSKBDIO_GETLEDS:
+		*(int *)data = 0;
+		return 0;
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+	case WSKBDIO_SETMODE:
+		sc->sc_rawkbd = (*(int *)data == WSKBD_RAW);
+		return 0;
+#endif
+	}
+
+	return EPASSTHROUGH;
+}
+
 /*
  * Enable touch-panel interrupt.  Must be called at spltty().
  */
@@ -239,17 +383,26 @@
 
 	bus_space_write_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_EDR, 1 << 9);
 
-	if (!sc->sc_enabled) {
+	if (!(sc->sc_enabled & J720TP_WSMOUSE_ENABLED)) {
 		DPRINTF(("j720tp_intr: !sc_enabled\n"));
 		return 0;
 	}
 
 	j720tp_disable_intr(sc);
 
-	if (j720tp_get_rawxy(sc, &rawx, &rawy))
-		j720tp_wsmouse_input(sc, rawx, rawy);
+	if (j720tp_get_rawxy(sc, &rawx, &rawy)) {
+		sc->sc_hard_icon = j720tp_get_hard_icon(sc, rawx, rawy);
 
-	callout_reset(&sc->sc_tpcallout, hz / 32, j720tp_wsmouse_callout, sc);
+		if (sc->sc_hard_icon > 0) {
+			j720tp_wskbd_input(sc, WSCONS_EVENT_KEY_DOWN);
+			callout_reset(&sc->sc_tpcallout, hz / 32,
+			    j720tp_wskbd_callout, sc);
+		} else {
+			j720tp_wsmouse_input(sc, rawx, rawy);
+			callout_reset(&sc->sc_tpcallout, hz / 32,
+			    j720tp_wsmouse_callout, sc);
+		}
+	}
 
 	return 1;
 }
@@ -285,10 +438,8 @@
 		buf[7] >>= 2;
 	}
 
-#if 0
-	DPRINTF(("j720tp_get_rawxy: %d:%d:%d:%d:%d:%d:%d:%d\n", buf[0], buf[1],
-	    buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]));
-#endif
+	DPRINTFN(2, ("j720tp_get_rawxy: %d:%d:%d:%d:%d:%d:%d:%d\n",
+	    buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]));
 
 	*rawx = buf[1];
 	*rawy = buf[4];
@@ -306,6 +457,29 @@
 	return 0;
 }
 
+static int
+j720tp_get_hard_icon(struct j720tp_softc *sc, int rawx, int rawy)
+{
+	int icon = 0;
+
+	if (!(sc->sc_enabled & J720TP_WSKBD_ENABLED))
+		return 0;
+	/* Check if the touch was in the hard icons area. */
+	if (rawx > j720tp_hard_icon_left)
+		return 0;
+
+	if (rawy < J720TP_HARD_ICON_MAX_Y(1))
+		icon = 1;
+	else if (rawy < J720TP_HARD_ICON_MAX_Y(2))
+		icon = 2;
+	else if (rawy < J720TP_HARD_ICON_MAX_Y(3))
+		icon = 3;
+	else if (rawy < J720TP_HARD_ICON_MAX_Y(4))
+		icon = 4;
+
+	return icon;
+}
+
 static void
 j720tp_wsmouse_input(struct j720tp_softc *sc, int rawx, int rawy)
 {
@@ -325,7 +499,7 @@
 
 	s = spltty();
 
-	if (!sc->sc_enabled) {
+	if (!(sc->sc_enabled & J720TP_WSMOUSE_ENABLED)) {
 		DPRINTF(("j720tp_wsmouse_callout: !sc_enabled\n"));
 		splx(s);
 		return;
@@ -337,9 +511,109 @@
 	} else {
 		if (j720tp_get_rawxy(sc, &rawx, &rawy))
 			j720tp_wsmouse_input(sc, rawx, rawy);
+		callout_schedule(&sc->sc_tpcallout, hz / 32);
+	}
+
+	splx(s);
+}
+
+static void
+j720tp_wskbd_input(struct j720tp_softc *sc, u_int evtype)
+{
+	int key = j720tp_wskbd_keys[sc->sc_hard_icon - 1];
+
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+	if (sc->sc_rawkbd) {
+		int n;
+		u_char data[16];
+
+		n = pckbd_encode(evtype, key, data);
+		wskbd_rawinput(sc->sc_wskbddev, data, n);
+	} else 
+#endif
+		wskbd_input(sc->sc_wskbddev, evtype, key);
+}
+
+static void
+j720tp_wskbd_callout(void *arg)
+{
+	struct j720tp_softc *sc = arg;
+	struct j720ssp_softc *ssp = sc->sc_ssp;
+	int s;
+
+	s = spltty();
+
+	if (!sc->sc_enabled) {
+		DPRINTF(("j720tp_wskbd_callout: !sc_enabled\n"));
+		splx(s);
+		return;
+	}
 
+	if (bus_space_read_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_PLR) & (1<<9)) {
+		j720tp_wskbd_input(sc, WSCONS_EVENT_KEY_UP);
+		j720tp_enable_intr(sc);
+	} else {
 		callout_schedule(&sc->sc_tpcallout, hz / 32);
 	}
 
 	splx(s);
 }
+
+SYSCTL_SETUP(sysctl_j720tp, "sysctl j720tp subtree setup")
+{
+	const struct sysctlnode *rnode;
+	int rc;
+
+	if ((rc = sysctl_createv(clog, 0, NULL, &rnode,
+	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL,
+	    NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0)
+		goto err;
+
+	if ((rc = sysctl_createv(clog, 0, &rnode, &rnode,
+	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "j720tp",
+	    SYSCTL_DESCR("Jornada 720 touch panel controls"),
+	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
+		goto err;
+
+#ifdef J720TP_DEBUG
+	if ((rc = sysctl_createv(clog, 0, &rnode, NULL,
+	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
+	    SYSCTL_DESCR("Verbosity of debugging messages"),
+	    NULL, 0, &j720tp_debug, 0, CTL_CREATE, CTL_EOL)) != 0)
+		goto err;
+#endif /* J720TP_DEBUG */
+
+	if ((rc = sysctl_createv(clog, 0, &rnode, &rnode,
+	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "hard_icons",
+	    SYSCTL_DESCR("Touch panel hard icons controls"),
+	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
+		goto err;
+
+	if ((rc = sysctl_createv(clog, 0, &rnode, NULL,
+	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, "left",
+	    SYSCTL_DESCR("Raw left X value of the hard icon area"),
+	    NULL, 0, &j720tp_hard_icon_left, 0, CTL_CREATE, CTL_EOL)) != 0)
+		goto err;
+
+	if ((rc = sysctl_createv(clog, 0, &rnode, NULL,
+	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, "right",
+	    SYSCTL_DESCR("Raw right X value of the hard icon area"),
+	    NULL, 0, &j720tp_hard_icon_right, 0, CTL_CREATE, CTL_EOL)) != 0)
+		goto err;
+
+	if ((rc = sysctl_createv(clog, 0, &rnode, NULL,
+	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, "top",
+	    SYSCTL_DESCR("Raw top Y value of the hard icon area"),
+	    NULL, 0, &j720tp_hard_icon_top, 0, CTL_CREATE, CTL_EOL)) != 0)
+		goto err;
+
+	if ((rc = sysctl_createv(clog, 0, &rnode, NULL,
+	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, "bottom",
+	    SYSCTL_DESCR("Raw bottom Y value of the hard icon area"),
+	    NULL, 0, &j720tp_hard_icon_bottom, 0, CTL_CREATE, CTL_EOL)) != 0)
+		goto err;
+
+	return;
+err:
+	printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
+}
