fix touchpanel broken behavior:

- when moving the stylus, the cursor was updated only when the screen was
released
- when moving the stylus for too long, the kernel crashed

This was caused by improper delays in SSP read and write, and by interrupt
hammering while the screen is touched). Both led to the machine handling
interrupts all the time and been unable to schedule the X server, therefore
the lack of cursor refresh.

The problem is fixed by
- masking touchpanel interrupts as soon as we are already handling them
- creating a kernel thread (j720ssp) that takes care of keyboard and
touchpanel I/O, instead of doing it in a softintr.
- reducing delays in j720ssp_readwrite operations from 5ms to 0.1ms.

NB: If the delay in j720ssp_readwrite operation is lowered to 0.1, then
switching on the screen using the power key pushes brightness to maximum.
In order to avoid this, we introduce a wait argument to j720ssp_readwrite,
which specify how many microseconds we have to wait. j720ssp_readwrite is
called with wait = 100 everywhere except in j720lcdparam where it is called
with wait = 500. That way it works.
This commit is contained in:
manu 2002-09-13 22:44:58 +00:00
parent c7acd88451
commit 100872541e
1 changed files with 111 additions and 56 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: j720ssp.c,v 1.8 2002/07/22 20:55:48 manu Exp $ */
/* $NetBSD: j720ssp.c,v 1.9 2002/09/13 22:44:58 manu Exp $ */
/*-
* Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
@ -77,10 +77,11 @@
#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>
@ -115,18 +116,27 @@ struct j720ssp_softc {
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 *);
static int j720ssp_readwrite(struct j720ssp_softc *, int, int, int *, int);
int j720sspprobe(struct device *, struct cfdata *, void *);
void j720sspattach(struct device *, struct device *, void *);
@ -221,7 +231,9 @@ j720sspattach(struct device *parent, struct device *self, void *aux)
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;
@ -278,10 +290,8 @@ j720sspattach(struct device *parent, struct device *self, void *aux)
}
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 */
@ -300,6 +310,53 @@ j720sspattach(struct device *parent, struct device *self, void *aux)
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) {
@ -361,16 +418,11 @@ j720kbd_intr(void *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);
}
@ -382,13 +434,18 @@ j720tp_intr(void *arg)
bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_EDR, 1 << 9);
softintr_schedule(sc->sc_tpsi);
simple_lock(&sc->sc_ssp_status_lock);
sc->sc_ssp_status |= J720_SSP_STATUS_TP;
simple_unlock(&sc->sc_ssp_status_lock);
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;
@ -427,18 +484,18 @@ j720kbd_read(struct j720ssp_softc *sc, char *buf)
bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PCR, 0x2000000);
/* send scan keycode command */
if (j720ssp_readwrite(sc, 1, 0x900, &data) < 0 ||
if (j720ssp_readwrite(sc, 1, 0x900, &data, 100) < 0 ||
data != 0x88)
goto out;
/* read numbers of scancode available */
if (j720ssp_readwrite(sc, 0, 0x8800, &data) < 0)
if (j720ssp_readwrite(sc, 0, 0x8800, &data, 100) < 0)
goto out;
BIT_INVERT(data);
count = data;
for(; count; count--) {
if (j720ssp_readwrite(sc, 0, 0x8800, &data) < 0)
if (j720ssp_readwrite(sc, 0, 0x8800, &data, 100) < 0)
goto out;
BIT_INVERT(data);
*buf++ = data;
@ -465,21 +522,32 @@ out:
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 ||
if (j720ssp_readwrite(sc, 1, 0x500, &data, 100) < 0 ||
data != 0x88)
goto out;
for(i = 0; i < 8; i++) {
if (j720ssp_readwrite(sc, 0, 0x8800, &data) < 0)
if (j720ssp_readwrite(sc, 0, 0x8800, &data, 100) < 0)
goto out;
BIT_INVERT(data);
buf[i] = data;
@ -496,7 +564,7 @@ j720tpsoft(void *arg)
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
@ -505,9 +573,7 @@ j720tpsoft(void *arg)
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;
@ -517,25 +583,9 @@ out:
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);
}
printf("j720tp_poll: error %x\n", data);
void
j720tp_timeout(void *arg)
{
struct j720ssp_softc *sc = arg;
#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
@ -642,7 +692,7 @@ j720lcdparam(void *ctx, int type, long id, void *msg)
bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PCR, 0x2000000);
for (i = 0; i < len; i++) {
if (j720ssp_readwrite(sc, 1, data[i], &data[i]) < 0)
if (j720ssp_readwrite(sc, 1, data[i], &data[i], 500) < 0)
goto out;
}
bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000);
@ -668,7 +718,12 @@ out:
}
static int
j720ssp_readwrite(struct j720ssp_softc *sc, int drainfifo, int in, int *out)
j720ssp_readwrite(sc, drainfifo, in, out, wait)
struct j720ssp_softc *sc;
int drainfifo;
int in;
int *out;
int wait;
{
int timo;
@ -683,13 +738,13 @@ j720ssp_readwrite(struct j720ssp_softc *sc, int drainfifo, int in, int *out)
SR_RNE)
bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_DR);
#if 1
delay(5000);
delay(wait);
#endif
}
bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_DR, in);
delay(5000);
delay(wait);
timo = 100000;
while(! (bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_SR) & SR_RNE))
if (--timo == 0) {