Subject: kthreaded ssp access: today's patch
To: None <port-hpcarm@netbsd.org>
From: Emmanuel Dreyfus <manu@netbsd.org>
List: port-hpcarm
Date: 09/11/2002 23:33:40
Please find below my last patch proposal about the touchpanel problems. If
nobody complains, I will commit it shortly.

I think I addressed the re-entrency problem pointed out by Toshihiro. We now
have only one kernel thread, called j720ssp. I use a status flag to communicate
between interrupt handlers and the kernel thread. 

It is possible to use the keyboard while the stylus is moving the X cursor, this
works, I checked it.

Somewhat related:
During my checks, I found some weird behaviors: if you hit d continously, the
machine displays a lot of d, then while d is still pressed, hit k quickly, the
machine display a k and then carry on displaying d

Try the same think with l and x, you don't get the same behavior. Any idea why?

One more weird thing: in windowmaker, while moving a window with the stylus, I
type a a dozen of times. Nothing is displayed, which is normal since the window
does not have the focus. When I stop moving it, even if I released it, the
system believes the a key is hold, and I get a appearing in my shell forever
until I hit another key. Is it a windowmaker bug or a jornada bug? Anyone can
reproduce it? 


Index: j720ssp.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/hpcarm/dev/j720ssp.c,v
retrieving revision 1.8
diff -U4 -r1.8 j720ssp.c
--- j720ssp.c   2002/07/22 20:55:48     1.8
+++ j720ssp.c   2002/09/11 21:04:23
@@ -76,12 +76,13 @@
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
-#include <sys/callout.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/ioctl.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
 
 #include <machine/bus.h>
 #include <machine/config_hook.h>
 #include <machine/bootinfo.h>
@@ -114,17 +115,26 @@
        struct tpcalib_softc sc_tpcalib;
 
        void *sc_kbdsi;
        void *sc_tpsi;
-       struct callout sc_tptimeout;
        int sc_enabled;
+
+       struct proc *sc_ssp_kthread;
+       int sc_ssp_status;
+       struct simplelock sc_ssp_status_lock;
 };
+/* Values for struct softc's sc_ssp_status */
+#define J720_SSP_STATUS_NONE   0
+#define J720_SSP_STATUS_TP     1
+#define J720_SSP_STATUS_KBD    2
 
+void j720ssp_create_kthread(void *);
+void j720ssp_kthread(void *);
 int j720kbd_intr(void *);
 int j720tp_intr(void *);
-void j720kbdsoft(void *);
-void j720tpsoft(void *);
-void j720tp_timeout(void *);
+void j720kbd_poll(void *);
+int j720tp_poll(void *);
+
 int j720lcdparam(void *, int, long, void *);
 static void j720kbd_read(struct j720ssp_softc *, char *);
 static int j720ssp_readwrite(struct j720ssp_softc *, int, int, int *);
 
@@ -220,9 +230,11 @@
                       sc->sc_dev.dv_xname);
                return;
        }
 
-       sc->sc_kbdsi = softintr_establish(IPL_SOFTCLOCK, j720kbdsoft, sc);
+       sc->sc_ssp_status = J720_SSP_STATUS_NONE;
+       simple_lock_init(&sc->sc_ssp_status_lock);
+       kthread_create(j720ssp_create_kthread, sc);
 
        sc->sc_enabled = 0;
 
        a.console = 0;
@@ -277,12 +289,10 @@
                    (caddr_t)&j720_default_calib, 0, 0);
        }
 
        j720tp_disable(sc);
-       callout_init(&sc->sc_tptimeout);
 
        /* Setup touchpad interrupt */
-       sc->sc_tpsi = softintr_establish(IPL_SOFTCLOCK, j720tpsoft, sc);
        sa11x0_intr_establish(0, 9, 1, IPL_BIO, j720tp_intr, sc);
 
        /* LCD control is on the same bus */
        config_hook(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS,
@@ -299,8 +309,55 @@
        config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_CONTRAST_MAX,
                    CONFIG_HOOK_SHARE, j720lcdparam, sc);
 }
 
+void
+j720ssp_create_kthread(arg)
+       void *arg;
+{
+       struct j720ssp_softc *sc = arg;
+
+       if (kthread_create1(j720ssp_kthread, sc, 
+           &sc->sc_ssp_kthread, "j720ssp")) 
+               panic("j720ssp_create_kthread");
+
+       return;
+}
+
+void
+j720ssp_kthread(arg)
+       void *arg;
+{
+       struct j720ssp_softc *sc = arg;
+       int ssp_status;
+
+       while (1) {
+               if (ssp_status & J720_SSP_STATUS_TP)
+                       tsleep(&sc->sc_ssp_kthread, PRIBIO, "j720ssp", hz / 25);
+               else
+                       tsleep(&sc->sc_ssp_kthread, PRIBIO, "j720ssp", 0);
+                       
+               simple_lock(&sc->sc_ssp_status_lock);
+               ssp_status = sc->sc_ssp_status;
+               sc->sc_ssp_status &= ~J720_SSP_STATUS_KBD;
+               simple_unlock(&sc->sc_ssp_status_lock);
+
+               if (ssp_status & J720_SSP_STATUS_KBD)
+                       j720kbd_poll(sc);
+
+               if (ssp_status & J720_SSP_STATUS_TP) {
+                       if (j720tp_poll(sc) == 0) {
+                               simple_lock(&sc->sc_ssp_status_lock);
+                               sc->sc_ssp_status &= ~J720_SSP_STATUS_TP;
+                               simple_unlock(&sc->sc_ssp_status_lock);
+                       }
+               }
+       }
+
+       /* NOTREACHED */
+}
+
+
 int
 j720kbd_submatch(struct device *parant, struct cfdata *cf, void *aux) {
 
        if (strcmp(cf->cf_driver->cd_name, "wskbd") == 0)
@@ -360,19 +417,14 @@
        struct j720ssp_softc *sc = arg;
 
        bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_EDR, 1);
 
-       /*
-        * Schedule a soft interrupt to process at lower priority,
-        * as reading keycodes takes time.
-        *
-        * Interrupts are generated every 25-33ms as long as there
-        * are unprocessed key events.  So it is not a good idea to
-        * use callout to call j720kbdsoft after some delay in hope
-        * of reducing interrupts.
-        */
-       softintr_schedule(sc->sc_kbdsi);
+       simple_lock(&sc->sc_ssp_status_lock);
+       sc->sc_ssp_status |= J720_SSP_STATUS_KBD;
+       simple_unlock(&sc->sc_ssp_status_lock);
 
+       wakeup(&sc->sc_ssp_kthread);
+
        return (1);
 }
 
 int
@@ -380,16 +432,21 @@
 {
        struct j720ssp_softc *sc = arg;
 
        bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_EDR, 1 << 9);
+
+       simple_lock(&sc->sc_ssp_status_lock);
+       sc->sc_ssp_status |= J720_SSP_STATUS_TP;
+       simple_unlock(&sc->sc_ssp_status_lock);
 
-       softintr_schedule(sc->sc_tpsi);
+       j720tp_disable(sc);
+       wakeup(&sc->sc_ssp_kthread);
 
        return (1);
 }
 
 void
-j720kbdsoft(void *arg)
+j720kbd_poll(void *arg)
 {
        struct j720ssp_softc *sc = arg;
        int s, type, value;
        char buf[9], *p;
@@ -464,14 +521,25 @@
        bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x387);
 printf("j720kbd_read: error %x\n", data);
 }
 
-void
-j720tpsoft(void *arg)
+int
+j720tp_poll(void *arg)
 {
        struct j720ssp_softc *sc = arg;
        int buf[8], data, i, x, y;
 
+       /* 
+        * If touch panel is not touched anymore, 
+        * stop polling and re-enable interrupt 
+        */
+       if (bus_space_read_4(sc->sc_iot, 
+           sc->sc_gpioh, SAGPIO_PLR) & (1 << 9)) {
+               wsmouse_input(sc->sc_wsmousedev, 0, 0, 0, 0, 0);
+               j720tp_enable(sc);
+               return 0;
+       }
+
        bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PCR, 0x2000000);
 
        /* send read touchpanel command */
        if (j720ssp_readwrite(sc, 1, 0x500, &data) < 0 ||
@@ -495,20 +563,18 @@
                buf[i + 3] |= buf[7] & 0x300;
                buf[7] >>= 2;
        }
 #if 0
-       printf("j720tpsoft: %d %d %d  %d %d %d\n", buf[0], buf[1], buf[2],
+       printf("j720tp_poll: %d %d %d  %d %d %d\n", buf[0], buf[1], buf[2],
            buf[3], buf[4], buf[5]);
 #endif
 
        /* XXX buf[1], buf[2], ... should also be used */
        tpcalib_trans(&sc->sc_tpcalib, buf[1], buf[4], &x, &y);
        wsmouse_input(sc->sc_wsmousedev, 1, x, y, 0,
            WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
 
-       callout_reset(&sc->sc_tptimeout, hz / 10, j720tp_timeout, sc);
-
-       return;
+       return 1;
 
 out:
        *buf = 0;
        bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000);
@@ -516,27 +582,11 @@
        /* reset SSP */
        bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x307);
        delay(100);
        bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x387);
-       printf("j720tpsoft: error %x\n", data);
-}
-
-void
-j720tp_timeout(void *arg)
-{
-       struct j720ssp_softc *sc = arg;
+       printf("j720tp_poll: error %x\n", data);
 
-#if 0
-       /* XXX I don't this this is necessary (untested) */
-       if (bus_space_read_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PLR) &
-           (1 << 9)) {
-               /* Touchpad is still pressed */
-               callout_reset(&sc->sc_tptimeout, hz / 10, j720tp_timeout, sc);
-               return;
-       }
-#endif
-
-       wsmouse_input(sc->sc_wsmousedev, 0, 0, 0, 0, 0);
+       return 0;
 }
 
 static int
 j720tp_enable(void *arg) {
@@ -670,8 +720,9 @@
 static int
 j720ssp_readwrite(struct j720ssp_softc *sc, int drainfifo, int in, int *out)
 {
        int timo;
+       int dontcare;
 
        timo = 100000;
        while(bus_space_read_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PLR) & 0x400)
                if (--timo == 0) {
@@ -682,15 +733,15 @@
                while(bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_SR) &
                      SR_RNE)
                        bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_DR);
 #if 1
-               delay(5000);
+               tsleep(&dontcare, PRIBIO, "j720ssp_readwrite", 1);
 #endif
        }
 
        bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_DR, in);
 
-       delay(5000);
+       tsleep(&dontcare, PRIBIO, "j720ssp_readwrite", 1);
        timo = 100000;
        while(! (bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_SR) & SR_RNE))
                if (--timo == 0) {
                        printf("timo1\n");


-- 
Emmanuel Dreyfus.
NetBSD, parceque je le vaux bien.
manu@netbsd.org