Diff below add support for the missing ALPS Dualpoint touchpads to the
pms(4) driver. Most of the work has been done by shadchin@ and should
fix issues you may have seen since pms(4) supports others ALPS devices
(2011/10).

It adds support for a slightly different version of the ALPS protocol,
which send 'interleaved' PS2 packets in between absolute ALPS packets.
Dell laptops (E6xxx and E5500 at least) have this kind of touchpad.

You may have notice the problem if you see "pms0: not in sync yet" as
soon as you move your clitpad.

Please report any breakage to shadchin@ and myself.

Martin


Index: pms.c
===================================================================
RCS file: /cvs/src/sys/dev/pckbc/pms.c,v
retrieving revision 1.27
diff -u -p -r1.27 pms.c
--- pms.c       28 Jan 2012 21:00:48 -0000      1.27
+++ pms.c       30 Jan 2012 10:41:36 -0000
@@ -87,6 +87,11 @@ struct synaptics_softc {
 
 struct alps_softc {
        int model;
+#define ALPS_GLIDEPOINT                (1 << 1)
+#define ALPS_DUALPOINT         (1 << 2)
+#define ALPS_PASSTHROUGH       (1 << 3)
+#define ALPS_INTERLEAVED       (1 << 4)
+
        int mask;
        int version;
 
@@ -94,6 +99,8 @@ struct alps_softc {
        int max_x, max_y;
        int old_fin;
 
+       u_int sec_buttons;      /* trackpoint */
+
        /* Compat mode */
        int wsmode;
        int old_x, old_y;
@@ -145,18 +152,15 @@ static const struct alps_model {
        int mask;
        int model;
 } alps_models[] = {
-#if 0
-       /* FIXME some clipads are not working yet */
-       { 0x5212, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
-       { 0x6222, 0xcf, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
-#endif
        { 0x2021, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
        { 0x2221, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
        { 0x2222, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
        { 0x3222, 0xf8, ALPS_DUALPOINT | ALPS_PASSTHROUGH },
+       { 0x5212, 0xff, ALPS_DUALPOINT | ALPS_PASSTHROUGH | ALPS_INTERLEAVED },
        { 0x5321, 0xf8, ALPS_GLIDEPOINT },
        { 0x5322, 0xf8, ALPS_GLIDEPOINT },
        { 0x603b, 0xf8, ALPS_GLIDEPOINT },
+       { 0x6222, 0xcf, ALPS_DUALPOINT | ALPS_PASSTHROUGH | ALPS_INTERLEAVED },
        { 0x6321, 0xf8, ALPS_GLIDEPOINT },
        { 0x6322, 0xf8, ALPS_GLIDEPOINT },
        { 0x6323, 0xf8, ALPS_GLIDEPOINT },
@@ -228,6 +232,7 @@ int synaptics_query(struct pms_softc *, 
 int    synaptics_get_hwinfo(struct pms_softc *);
 void   synaptics_sec_proc(struct pms_softc *);
 
+int    alps_sec_proc(struct pms_softc *);
 int    alps_get_hwinfo(struct pms_softc *);
 
 struct cfattach pms_ca = {
@@ -726,6 +731,7 @@ pmsinput(void *vsc, int data)
                return;
        }
 
+       sc->packet[sc->inputstate] = data;
        if (sc->protocol->sync(sc, data)) {
 #ifdef DIAGNOSTIC
                printf("%s: not in sync yet, discard input\n", DEVNAME(sc));
@@ -734,13 +740,13 @@ pmsinput(void *vsc, int data)
                return;
        }
 
-       sc->packet[sc->inputstate++] = data;
+       sc->inputstate++;
 
        if (sc->inputstate != sc->protocol->packetsize)
                return;
 
-       sc->protocol->proc(sc);
        sc->inputstate = 0;
+       sc->protocol->proc(sc);
 }
 
 int
@@ -1050,6 +1056,40 @@ pms_disable_synaptics(struct pms_softc *
 }
 
 int
+alps_sec_proc(struct pms_softc *sc)
+{
+       struct alps_softc *alps = sc->alps;
+       int dx, dy, pos = 0;
+
+       if ((sc->packet[0] & PMS_ALPS_PS2_MASK) == PMS_ALPS_PS2_VALID) {
+               /*
+                * We need to keep buttons states because interleaved
+                * packets only signalize x/y movements.
+                */
+               alps->sec_buttons = butmap[sc->packet[0] & PMS_PS2_BUTTONSMASK];
+       } else if ((sc->packet[3] & PMS_ALPS_INTERLEAVED_MASK) ==
+           PMS_ALPS_INTERLEAVED_VALID) {
+               sc->inputstate = 3;
+               pos = 3;
+       } else {
+               return (0);
+       }
+
+       if ((sc->sc_dev_enable & PMS_DEV_SECONDARY) == 0)
+               return (1);
+
+       dx = (sc->packet[pos] & PMS_PS2_XNEG) ?
+           (int)sc->packet[pos + 1] - 256 : sc->packet[pos + 1];
+       dy = (sc->packet[pos] & PMS_PS2_YNEG) ?
+           (int)sc->packet[pos + 2] - 256 : sc->packet[pos + 2];
+
+       wsmouse_input(sc->sc_sec_wsmousedev, alps->sec_buttons,
+           dx, dy, 0, 0, WSMOUSE_INPUT_DELTA);
+
+       return (1);
+}
+
+int
 alps_get_hwinfo(struct pms_softc *sc)
 {
        struct alps_softc *alps = sc->alps;
@@ -1161,6 +1201,8 @@ pms_enable_alps(struct pms_softc *sc)
                goto err;
        }
 
+       alps->sec_buttons = 0;
+
        return (1);
 
 err:
@@ -1205,6 +1247,13 @@ pms_sync_alps(struct pms_softc *sc, int 
 {
        struct alps_softc *alps = sc->alps;
 
+       if ((alps->model & ALPS_DUALPOINT) &&
+           (sc->packet[0] & PMS_ALPS_PS2_MASK) == PMS_ALPS_PS2_VALID) {
+               if (sc->inputstate == 2)
+                       sc->inputstate += 3;
+               return (0);
+       }
+
        switch (sc->inputstate) {
        case 0:
                if ((data & alps->mask) != alps->mask)
@@ -1213,9 +1262,13 @@ pms_sync_alps(struct pms_softc *sc, int 
        case 1:
        case 2:
        case 3:
+               if ((data & PMS_ALPS_MASK) != PMS_ALPS_VALID)
+                       return (-1);
+               break;
        case 4:
        case 5:
-               if ((data & 0x80) != 0)
+               if ((alps->model & ALPS_INTERLEAVED) == 0 &&
+                   (data & PMS_ALPS_MASK) != PMS_ALPS_VALID)
                        return (-1);
                break;
        }
@@ -1230,6 +1283,9 @@ pms_proc_alps(struct pms_softc *sc)
        int x, y, z, dx, dy;
        u_int buttons;
        int fin, ges;
+
+       if ((alps->model & ALPS_DUALPOINT) && alps_sec_proc(sc))
+               return;
 
        x = sc->packet[1] | ((sc->packet[2] & 0x78) << 4);
        y = sc->packet[4] | ((sc->packet[3] & 0x70) << 3);
Index: pmsreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pckbc/pmsreg.h,v
retrieving revision 1.6
diff -u -p -r1.6 pmsreg.h
--- pmsreg.h    3 Dec 2011 19:43:00 -0000       1.6
+++ pmsreg.h    30 Jan 2012 10:42:39 -0000
@@ -42,6 +42,21 @@
 #define PMS_ALPS_MAGIC3_1      10
 #define PMS_ALPS_MAGIC3_2      100
 
+/*
+ * Checking for almost-standard PS/2 packet
+ * Note: ALPS devices never signal overflow condition
+ */
+#define PMS_ALPS_PS2_MASK                      0xc8
+#define PMS_ALPS_PS2_VALID                     0x08
+
+/* Checking for interleaved packet */
+#define PMS_ALPS_INTERLEAVED_MASK              0xcf
+#define PMS_ALPS_INTERLEAVED_VALID             0x0f
+
+/* Checking for non first byte */
+#define PMS_ALPS_MASK                          0x80
+#define PMS_ALPS_VALID                         0x00
+
 /* Synaptics queries */
 #define SYNAPTICS_QUE_IDENTIFY                 0x00
 #define SYNAPTICS_QUE_MODES                    0x01
@@ -92,10 +107,6 @@
 #define SYNAPTICS_MODEL_PEN                    (1 << 6)
 #define SYNAPTICS_MODEL_SIMPLC                 (1 << 5)
 #define SYNAPTICS_MODEL_GEOMETRY(m)            ((m) & 0x0f)
-
-#define ALPS_GLIDEPOINT                                (1 << 1)
-#define ALPS_DUALPOINT                         (1 << 2)
-#define ALPS_PASSTHROUGH                       (1 << 3)
 
 /* Resolutions */
 #define SYNAPTICS_RESOLUTION_X(r)              (((r) >> 16) & 0xff)

Reply via email to