Author: wulf
Date: Wed Jan 31 21:14:59 2018
New Revision: 328636
URL: https://svnweb.freebsd.org/changeset/base/328636

Log:
  psm(4): Add support for HP EliteBook 1040 ForcePads.
  
  ForcePads do not have any physical buttons, instead they detect click
  based on finger pressure. Forcepads erroneously report button click
  if there are 2 or more fingers on the touchpad breaking multifinger
  gestures. To workaround this start reporting a click only after
  4 consecutive single touch packets has been received. Skip these packets
  in case more contacts appear.
  
  PR:           223369
  Reported by:  Neel Chauhan <[email protected]>
  Tested by:    Neel Chauhan <[email protected]>
  Reviewed by:  gonzo
  Approved by:  gonzo

Modified:
  head/sys/dev/atkbdc/psm.c
  head/sys/sys/mouse.h

Modified: head/sys/dev/atkbdc/psm.c
==============================================================================
--- head/sys/dev/atkbdc/psm.c   Wed Jan 31 18:13:33 2018        (r328635)
+++ head/sys/dev/atkbdc/psm.c   Wed Jan 31 21:14:59 2018        (r328636)
@@ -132,6 +132,13 @@ __FBSDID("$FreeBSD$");
 
 #define        PSMCPNP_DRIVER_NAME     "psmcpnp"
 
+struct psmcpnp_softc {
+       enum {
+               PSMCPNP_GENERIC,
+               PSMCPNP_FORCEPAD,
+       } type;         /* Based on PnP ID */
+};
+
 /* input queue */
 #define        PSM_BUFSIZE             960
 #define        PSM_SMALLBUFSIZE        240
@@ -416,6 +423,7 @@ struct psm_softc {          /* Driver status information */
        int             squelch; /* level to filter movement at low speed */
        int             syncerrors; /* # of bytes discarded to synchronize */
        int             pkterrors;  /* # of packets failed during quaranteen. */
+       int             fpcount;        /* forcePad valid packet counter */
        struct timeval  inputtimeout;
        struct timeval  lastsoftintr;   /* time of last soft interrupt */
        struct timeval  lastinputerr;   /* time last sync error happened */
@@ -3183,7 +3191,7 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, 
        static int touchpad_buttons;
        static int guest_buttons;
        static finger_t f[PSM_FINGERS];
-       int w, id, nfingers, ewcode, extended_buttons;
+       int w, id, nfingers, ewcode, extended_buttons, clickpad_pressed;
 
        extended_buttons = 0;
 
@@ -3445,10 +3453,6 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, 
                        extended_buttons |= sc->extended_buttons;
                }
        }
-       /* Handle ClickPad */
-       if (sc->synhw.capClickPad &&
-           ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01))
-               touchpad_buttons |= MOUSE_BUTTON1DOWN;
 
        if (sc->synhw.capReportsV && nfingers > 1)
                f[0] = (finger_t) {
@@ -3481,6 +3485,36 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, 
        if (f[0].p < sc->syninfo.min_pressure || f[0].x < 2)
                nfingers = 0;
 
+       /* Handle ClickPad */
+       if (sc->synhw.capClickPad) {
+               clickpad_pressed = (pb->ipacket[0] ^ pb->ipacket[3]) & 0x01;
+               if (sc->synhw.forcePad) {
+                       /*
+                        * Forcepads erroneously report button click if there
+                        * are 2 or more fingers on the touchpad breaking
+                        * multifinger gestures. To workaround this start
+                        * reporting a click only after 4 consecutive single
+                        * touch packets has been received.
+                        * Skip these packets in case more contacts appear.
+                        */
+                       switch (nfingers) {
+                       case 0:
+                               sc->fpcount = 0;
+                               break;
+                       case 1:
+                               if (clickpad_pressed && sc->fpcount < INT_MAX)
+                                       ++sc->fpcount;
+                               /* FALLTHROUGH */
+                       default:
+                               if (!clickpad_pressed)
+                                       sc->fpcount = 0;
+                               if (sc->fpcount >= sc->syninfo.window_min)
+                                       touchpad_buttons |= MOUSE_BUTTON1DOWN;
+                       }
+               } else if (clickpad_pressed)
+                       touchpad_buttons |= MOUSE_BUTTON1DOWN;
+       }
+
        for (id = 0; id < PSM_FINGERS; id++)
                if (id >= nfingers)
                        PSM_FINGER_RESET(f[id]);
@@ -5998,6 +6032,8 @@ synaptics_set_mode(struct psm_softc *sc, int mode_byte
 static int
 enable_synaptics(struct psm_softc *sc, enum probearg arg)
 {
+       device_t psmcpnp;
+       struct psmcpnp_softc *psmcpnp_sc;
        KBDC kbdc = sc->kbdc;
        synapticshw_t synhw;
        int status[3];
@@ -6075,6 +6111,10 @@ enable_synaptics(struct psm_softc *sc, enum probearg a
                return (FALSE);
        }
 
+       psmcpnp = devclass_get_device(devclass_find(PSMCPNP_DRIVER_NAME),
+           sc->unit);
+       psmcpnp_sc = (psmcpnp != NULL) ? device_get_softc(psmcpnp) : NULL;
+
        /* Set the different capabilities when they exist. */
        buttons = 0;
        synhw.capExtended = (status[0] & 0x80) != 0;
@@ -6229,6 +6269,20 @@ enable_synaptics(struct psm_softc *sc, enum probearg a
                                synhw.minimumYCoord = 1408;
                        }
 
+                       /*
+                        * ClickPad properties are not exported through PS/2
+                        * protocol. Detection is based on controller's PnP ID.
+                        */
+                       if (synhw.capClickPad && psmcpnp_sc != NULL) {
+                               switch (psmcpnp_sc->type) {
+                               case PSMCPNP_FORCEPAD:
+                                       synhw.forcePad = 1;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+
                        if (verbose >= 2) {
                                printf("  Continued capabilities:\n");
                                printf("   capClickPad: %d\n",
@@ -6265,6 +6319,10 @@ enable_synaptics(struct psm_softc *sc, enum probearg a
                                        printf("   minimumYCoord: %d\n",
                                               synhw.minimumYCoord);
                                }
+                               if (synhw.capClickPad) {
+                                       printf("   forcePad: %d\n",
+                                              synhw.forcePad);
+                               }
                        }
                        buttons += synhw.capClickPad;
                }
@@ -7090,7 +7148,7 @@ static device_method_t psmcpnp_methods[] = {
 static driver_t psmcpnp_driver = {
        PSMCPNP_DRIVER_NAME,
        psmcpnp_methods,
-       1,                      /* no softc */
+       sizeof(struct psmcpnp_softc),
 };
 
 static struct isa_pnp_id psmcpnp_ids[] = {
@@ -7110,6 +7168,13 @@ static struct isa_pnp_id psmcpnp_ids[] = {
        { 0 }
 };
 
+/* _HID list for quirk detection. Any device below has _CID from psmcpnp_ids */
+static struct isa_pnp_id forcepad_ids[] = {
+       { 0x0d302e4f, "HP PS/2 forcepad port" },        /* SYN300D, EB 1040 */
+       { 0x14302e4f, "HP PS/2 forcepad port" },        /* SYN3014, EB 1040 */
+       { 0 }
+};
+
 static int
 create_a_copy(device_t atkbdc, device_t me)
 {
@@ -7136,11 +7201,16 @@ create_a_copy(device_t atkbdc, device_t me)
 static int
 psmcpnp_probe(device_t dev)
 {
+       struct psmcpnp_softc *sc = device_get_softc(dev);
        struct resource *res;
        u_long irq;
        int rid;
 
-       if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids))
+       if (ISA_PNP_PROBE(device_get_parent(dev), dev, forcepad_ids) == 0)
+               sc->type = PSMCPNP_FORCEPAD;
+       else if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids) == 0)
+               sc->type = PSMCPNP_GENERIC;
+       else
                return (ENXIO);
 
        /*

Modified: head/sys/sys/mouse.h
==============================================================================
--- head/sys/sys/mouse.h        Wed Jan 31 18:13:33 2018        (r328635)
+++ head/sys/sys/mouse.h        Wed Jan 31 21:14:59 2018        (r328636)
@@ -137,6 +137,7 @@ typedef struct synapticshw {
        int maximumYCoord;
        int infoXupmm;
        int infoYupmm;
+       int forcePad;
 } synapticshw_t;
 
 /* iftype */
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to