summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pckbc/pms.c148
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;