diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2015-02-09 04:05:26 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2015-02-09 04:05:26 +0000 |
commit | 9a4f13258d5118763e4ab73bee1aa4122924c6c2 (patch) | |
tree | 07fac138c36faff2c768877d5fdae99a8e7f889e /sys | |
parent | f52861956cfbdb20e7999c3de0addb7924362d9b (diff) |
Complete rewrite of the Elantech clickpads v4 packet parser in order to
support "click-and-drag".
This implements a simple filter to keep track of a moving finger on the
clickpad. For the moment wsmouse(4) and wscons(4) are still unaware of
multitouch events and pms(4) has to do the translation, but this is a
small steps in this direction.
All the good work has been done by Ulf Brosziewski.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pckbc/pms.c | 148 |
1 files changed, 89 insertions, 59 deletions
diff --git a/sys/dev/pckbc/pms.c b/sys/dev/pckbc/pms.c index ed0b5acc6d2..fdffa119241 100644 --- a/sys/dev/pckbc/pms.c +++ b/sys/dev/pckbc/pms.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pms.c,v 1.56 2015/01/15 01:19:28 jsg Exp $ */ +/* $OpenBSD: pms.c,v 1.57 2015/02/09 04:05:25 mpi Exp $ */ /* $NetBSD: psm.c,v 1.11 2000/06/05 22:20:57 sommerfeld Exp $ */ /*- @@ -142,8 +142,15 @@ struct elantech_softc { struct { unsigned int x; unsigned int y; + unsigned int z; } mt[ELANTECH_MAX_FINGERS]; - int fingers[ELANTECH_MAX_FINGERS]; + int mt_slots; + int mt_count; + int mt_filter; + int mt_lastid; + int mt_lastcount; + int mt_buttons; + int width; u_char parity[256]; @@ -314,6 +321,7 @@ int elantech_set_absolute_mode_v2(struct pms_softc *); int elantech_set_absolute_mode_v3(struct pms_softc *); int elantech_set_absolute_mode_v4(struct pms_softc *); +void elantech_send_mt_input(struct pms_softc *, int); struct cfattach pms_ca = { sizeof(struct pms_softc), pmsprobe, pmsattach, NULL, @@ -2258,75 +2266,66 @@ void pms_proc_elantech_v4(struct pms_softc *sc) { struct elantech_softc *elantech = sc->elantech; - int z, delta_x1 = 0, delta_x2 = 0, delta_y1 = 0, delta_y2 = 0; - int i, weight, finger, fingers = 0, id, sid; + int n, id, slots, weight, dx, dy; switch (sc->packet[3] & 0x1f) { case ELANTECH_V4_PKT_STATUS: - fingers = sc->packet[1] & 0x1f; - for (i = 0; i < ELANTECH_MAX_FINGERS; i++) { - finger = ((fingers & (1 << i)) != 0); - if (elantech->fingers[i] && !finger) - /* notify that we lifted */ - elantech_send_input(sc, elantech->mt[i].x, - elantech->mt[i].y, 0, 0); - - elantech->fingers[i] = finger; - } + if (elantech->mt_slots == 0) + elantech->mt_lastid = -1; + slots = sc->packet[1] & 0x1f; + if (slots == 0 && elantech->mt_lastid > -1) + /* Notify that we lifted. */ + elantech_send_input(sc, + elantech->mt[elantech->mt_lastid].x, + elantech->mt[elantech->mt_lastid].y, 0, 0); + + elantech->mt_filter = elantech->mt_slots = slots; + + for (elantech->mt_count = 0; slots != 0; slots >>= 1) + elantech->mt_count += (1 & slots); break; case ELANTECH_V4_PKT_HEAD: id = ((sc->packet[3] & 0xe0) >> 5) - 1; - if (id < 0) - return; - - for (i = 0; i < ELANTECH_MAX_FINGERS; i++) - if (elantech->fingers[i]) - fingers++; - - elantech->mt[id].x = ((sc->packet[1] & 0x0f) << 8) | - sc->packet[2]; - elantech->mt[id].y = (((sc->packet[4] & 0x0f) << 8) | - sc->packet[5]); - z = (sc->packet[1] & 0xf0) | ((sc->packet[4] & 0xf0) >> 4); - - elantech_send_input(sc, elantech->mt[id].x, elantech->mt[id].y, - z, fingers); - + if (id > -1 && id < ELANTECH_MAX_FINGERS) { + elantech->mt[id].x = + ((sc->packet[1] & 0x0f) << 8) | sc->packet[2]; + elantech->mt[id].y = + ((sc->packet[4] & 0x0f) << 8) | sc->packet[5]; + elantech->mt[id].z = + (sc->packet[1] & 0xf0) + | ((sc->packet[4] & 0xf0) >> 4); + + if (elantech->mt_filter & (1 << id)) { + elantech_send_mt_input(sc, id); + elantech->mt_filter = (1 << id); + } + } break; case ELANTECH_V4_PKT_MOTION: - id = ((sc->packet[0] & 0xe0) >> 5) - 1; - if (id < 0) - return; - - sid = ((sc->packet[3] & 0xe0) >> 5) - 1; weight = (sc->packet[0] & 0x10) ? ELANTECH_V4_WEIGHT_VALUE : 1; - - delta_x1 = (signed char)sc->packet[1]; - delta_y1 = (signed char)sc->packet[2]; - delta_x2 = (signed char)sc->packet[4]; - delta_y2 = (signed char)sc->packet[5]; - - elantech->mt[id].x += delta_x1 * weight; - elantech->mt[id].y -= delta_y1 * weight; - - for (i = 0; i < ELANTECH_MAX_FINGERS; i++) - if (elantech->fingers[i]) - fingers++; - - elantech_send_input(sc, elantech->mt[id].x, elantech->mt[id].y, - 1, fingers); - - if (sid >= 0) { - elantech->mt[sid].x += delta_x2 * weight; - elantech->mt[sid].y -= delta_y2 * weight; - /* XXX: can only send one finger of input */ - /* - elantech_send_input(sc, elantech->mt[sid].x, - elantech->mt[sid].y, 1, fingers); - */ + for (n = 0; n < 6; n += 3) { + id = ((sc->packet[n] & 0xe0) >> 5) - 1; + if (id < 0 || id >= ELANTECH_MAX_FINGERS) + continue; + dx = weight * (signed char)sc->packet[n + 1]; + dy = weight * (signed char)sc->packet[n + 2]; + elantech->mt[id].x += dx; + elantech->mt[id].y += dy; + elantech->mt[id].z = 1; + if (elantech->mt_filter & (1 << id)) { + if ((dx | dy) + || elantech->mt_count != + elantech->mt_lastcount + || (sc->packet[0] & 3) != + elantech->mt_buttons) + elantech_send_mt_input(sc, id); + + elantech->mt_filter = (dx | dy) ? + (1 << id) : elantech->mt_slots; + } } break; @@ -2339,6 +2338,37 @@ pms_proc_elantech_v4(struct pms_softc *sc) } void +elantech_send_mt_input(struct pms_softc *sc, int id) +{ + struct elantech_softc *elantech = sc->elantech; + + if (id != elantech->mt_lastid) { + /* Correct for compatibility mode, but not useful yet: */ + elantech->old_x = elantech->mt[id].x; + elantech->old_y = elantech->mt[id].y; + /* + * To avoid a jump of the cursor, simulate a change of the + * number of touches (without producing tapping gestures + * accidentally). It should suffice to do that only if + * mt_count hasn't changed, but we cannot rely on the + * synaptics driver, which alters its finger counts when + * handling click-and-drag actions (see HandleTapProcessing + * and ComputeDeltas in synaptics.c). + */ + if (elantech->mt_lastid > -1) + elantech_send_input(sc, + elantech->mt[id].x, elantech->mt[id].y, + elantech->mt[id].z, ELANTECH_MAX_FINGERS); + elantech->mt_lastid = id; + } + elantech->mt_lastcount = elantech->mt_count; + elantech->mt_buttons = sc->packet[0] & 3; + elantech_send_input(sc, + elantech->mt[id].x, elantech->mt[id].y, + elantech->mt[id].z, elantech->mt_count); +} + +void elantech_send_input(struct pms_softc *sc, int x, int y, int z, int w) { struct elantech_softc *elantech = sc->elantech; |