Subject: jornada 720 touchpanel bugs fixed
To: None <port-hpcarm@netbsd.org>
From: Emmanuel Dreyfus <manu@netbsd.org>
List: port-hpcarm
Date: 09/08/2002 20:19:20
Summary of the problem: When moving the stylus on the screen, the cursor
position is updated only when the stylus is released. This makes
impossible to drag anddrop something. Additionnaly if the stylus is
maintained touching the screen for a dozen of seconds, the kernel crash.

I spotted a bit more the problem: while you hit the screen, no user
process is scheduled at all, the kernel spends all its time in interrupt
handlers. Try this:

cat < /dev/wsmouse0 > /dev/null &
dd if=/dev/zero of=/dev/null bs=10k count=100000 progress=1 &

Watch the dots being displayed, while they are moving, it means dd runs.
Touch the screen, dd is stoped. Release the screen, dd runs again. 

This explains why the cursor is moved only when you stop touching the
screen: user processes can only get mouse data once you released the
screen.

When the screen is touched, the j720tp_intr function is called by the
interrupt handler. It schedules j720tpsoft for execution so that the
data input is treated at a lower priority level.

The problem is that before j720tpsoft has an opportunity to exit,
j720tp_intr is called again, and schedule j720tpsoft to run again. Each
time, the wsmouse_input is called and the mouse data is queued in the
wscons event queue, and the reading process is awaken, but the reading
process will never have an opportunity to read the data until the screen
is released.

The following patch resolve the problem by preventing j720tp_intr from
scheduling j720tp_soft until j720tp_soft is finished. If nobody find it
disgusting, I will commit it. 

Ideally, we could skip j720tpsoft scheduling one time over N and have a
sysctl to set N. That way we could control at runtime mouse reactivity
vs interrupt overhead. Opinions about this?

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/08 18:13:24
@@ -114,8 +114,9 @@
        struct tpcalib_softc sc_tpcalib;
 
        void *sc_kbdsi;
        void *sc_tpsi;
+       int sc_tpspin;
        struct callout sc_tptimeout;
        int sc_enabled;
 };
 
@@ -281,8 +282,9 @@
        callout_init(&sc->sc_tptimeout);
 
        /* Setup touchpad interrupt */
        sc->sc_tpsi = softintr_establish(IPL_SOFTCLOCK, j720tpsoft, sc);
+       sc->sc_tpspin = 0;
        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,
@@ -374,16 +376,20 @@
 
        return (1);
 }
 
+#define J720_TPSPIN_MAX 4
 int
 j720tp_intr(void *arg)
 {
        struct j720ssp_softc *sc = arg;
 
        bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_EDR, 1 << 9);
 
-       softintr_schedule(sc->sc_tpsi);
+       if (sc->sc_tpspin == 0) {
+               sc->sc_tpspin = 1;
+               softintr_schedule(sc->sc_tpsi);
+       }       
 
        return (1);
 }
 
@@ -506,8 +512,9 @@
            WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
 
        callout_reset(&sc->sc_tptimeout, hz / 10, j720tp_timeout, sc);
 
+       sc->sc_tpspin = 0;
        return;
 
 out:
        *buf = 0;
@@ -517,15 +524,17 @@
        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);
+       sc->sc_tpspin = 0;
 }
 
 void
 j720tp_timeout(void *arg)
 {
        struct j720ssp_softc *sc = arg;
 
+       sc->sc_tpspin = 0;
 #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)) {


-- 
Emmanuel Dreyfus.  
Avec Windows 3.1 ils etaient au bord du gouffre...
Avec Windows 95 ils ont fait un grand bon en avant.
manu@netbsd.org