Author: gonzo
Date: Tue Oct 18 20:17:57 2016
New Revision: 307576
URL: https://svnweb.freebsd.org/changeset/base/307576

Log:
  MFC r306355, r306474, r306746:
  
  r306355:
  Add Elantech trackpad support
  
  Elantech trackpads are found in some laptops like the Asus UX31E. They
  are "synaptics compatible" but use a slightly different protocol.
  
  Elantech hardware support is not enabled by default and just like
  Synaptic or TrackPoint devices it should be enabled by setting
  tunable, in this case hw.psm.elantech_support, to non-zero value
  
  PR:           205690
  Submitted by: Vladimir Kondratyev <w...@cicgroup.ru>
  MFC after:    1 week
  
  r306474:
  Replace explicit TUNABLE_INT to sysctl with CTLFLAG_TUN
  
  - Replace tunables-only hw.psm.synaptics_support, hw.psm.trackpoint_support,
      and hw.psm.elantech_support with respective sysctls declared with
      CTLFLAG_TUN. It simplifies checking them in userland, also makes them
      easier to get discovered by user
  - Get rid of debug.psm.loglevel and hw.psm.tap_enabled TUNABLE_INT
      declaration by adding CTLFLAG_TUN to read/write sysctls that were
      already declared for these tunables.
  
  Suggested by: jhb
  
  r306746:
  Fix extended buttons support on synaptic clickpad
  
  Fix regression introduced by r306355 on synaptic clickpads with
  extended buttons (buttons stopped working)
  
  PR:           205690
  Submitted by: Vladimir Kondratyev <w...@cicgroup.ru>

Modified:
  stable/11/sys/dev/atkbdc/psm.c
  stable/11/sys/sys/mouse.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/dev/atkbdc/psm.c
==============================================================================
--- stable/11/sys/dev/atkbdc/psm.c      Tue Oct 18 19:15:43 2016        
(r307575)
+++ stable/11/sys/dev/atkbdc/psm.c      Tue Oct 18 20:17:57 2016        
(r307576)
@@ -81,6 +81,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/sysctl.h>
 #include <sys/time.h>
 #include <sys/uio.h>
+#include <sys/libkern.h>
 
 #include <sys/limits.h>
 #include <sys/mouse.h>
@@ -161,40 +162,6 @@ typedef struct packetbuf {
 #define        PSM_PACKETQUEUE 128
 #endif
 
-enum {
-       SYNAPTICS_SYSCTL_MIN_PRESSURE,
-       SYNAPTICS_SYSCTL_MAX_PRESSURE,
-       SYNAPTICS_SYSCTL_MAX_WIDTH,
-       SYNAPTICS_SYSCTL_MARGIN_TOP,
-       SYNAPTICS_SYSCTL_MARGIN_RIGHT,
-       SYNAPTICS_SYSCTL_MARGIN_BOTTOM,
-       SYNAPTICS_SYSCTL_MARGIN_LEFT,
-       SYNAPTICS_SYSCTL_NA_TOP,
-       SYNAPTICS_SYSCTL_NA_RIGHT,
-       SYNAPTICS_SYSCTL_NA_BOTTOM,
-       SYNAPTICS_SYSCTL_NA_LEFT,
-       SYNAPTICS_SYSCTL_WINDOW_MIN,
-       SYNAPTICS_SYSCTL_WINDOW_MAX,
-       SYNAPTICS_SYSCTL_MULTIPLICATOR,
-       SYNAPTICS_SYSCTL_WEIGHT_CURRENT,
-       SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS,
-       SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA,
-       SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED,
-       SYNAPTICS_SYSCTL_DIV_MIN,
-       SYNAPTICS_SYSCTL_DIV_MAX,
-       SYNAPTICS_SYSCTL_DIV_MAX_NA,
-       SYNAPTICS_SYSCTL_DIV_LEN,
-       SYNAPTICS_SYSCTL_TAP_MAX_DELTA,
-       SYNAPTICS_SYSCTL_TAP_MIN_QUEUE,
-       SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT,
-       SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA,
-       SYNAPTICS_SYSCTL_VSCROLL_VER_AREA,
-       SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA,
-       SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN,
-       SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX,
-       SYNAPTICS_SYSCTL_TOUCHPAD_OFF
-};
-
 typedef struct synapticsinfo {
        struct sysctl_ctx_list   sysctl_ctx;
        struct sysctl_oid       *sysctl_tree;
@@ -231,6 +198,11 @@ typedef struct synapticsinfo {
        int                      vscroll_div_min;
        int                      vscroll_div_max;
        int                      touchpad_off;
+       int                      softbuttons_y;
+       int                      softbutton2_x;
+       int                      softbutton3_x;
+       int                      max_x;
+       int                      max_y;
 } synapticsinfo_t;
 
 typedef struct synapticspacket {
@@ -246,22 +218,29 @@ typedef struct synapticspacket {
     ((synhw).infoMajor > (major) ||                                    \
      ((synhw).infoMajor == (major) && (synhw).infoMinor >= (minor)))
 
-typedef struct synapticsaction {
+typedef struct smoother {
        synapticspacket_t       queue[SYNAPTICS_PACKETQUEUE];
        int                     queue_len;
        int                     queue_cursor;
-       int                     window_min;
        int                     start_x;
        int                     start_y;
        int                     avg_dx;
        int                     avg_dy;
        int                     squelch_x;
        int                     squelch_y;
+       int                     is_fuzzy;
+       int                     active;
+} smoother_t;
+
+typedef struct gesture {
+       int                     window_min;
        int                     fingers_nb;
        int                     tap_button;
        int                     in_taphold;
        int                     in_vscroll;
-} synapticsaction_t;
+       int                     zmax;           /* maximum pressure value */
+       struct timeval          taptimeout;     /* tap timeout for touchpads */
+} gesture_t;
 
 enum {
        TRACKPOINT_SYSCTL_SENSITIVITY,
@@ -295,6 +274,100 @@ typedef struct trackpointinfo {
        int     skipback;
 } trackpointinfo_t;
 
+typedef struct finger {
+       int                     x;
+       int                     y;
+       int                     p;
+       int                     w;
+       int                     flags;
+} finger_t;
+#define        PSM_FINGERS             2       /* # of processed fingers */
+#define        PSM_FINGER_IS_PEN       (1<<0)
+#define        PSM_FINGER_FUZZY        (1<<1)
+#define        PSM_FINGER_DEFAULT_P    tap_threshold
+#define        PSM_FINGER_DEFAULT_W    1
+#define        PSM_FINGER_IS_SET(f) ((f).x != -1 && (f).y != -1 && (f).p != 0)
+#define        PSM_FINGER_RESET(f) do { \
+       (f) = (finger_t) { .x = -1, .y = -1, .p = 0, .w = 0, .flags = 0 }; \
+} while (0)
+
+typedef struct elantechhw {
+       int                     hwversion;
+       int                     fwversion;
+       int                     sizex;
+       int                     sizey;
+       int                     dpmmx;
+       int                     dpmmy;
+       int                     ntracesx;
+       int                     ntracesy;
+       int                     issemimt;
+       int                     isclickpad;
+       int                     hascrc;
+       int                     hastrackpoint;
+       int                     haspressure;
+} elantechhw_t;
+
+/* minimum versions supported by this driver */
+#define        ELANTECH_HW_IS_V1(fwver) ((fwver) < 0x020030 || (fwver) == 
0x020600)
+
+#define        ELANTECH_MAGIC(magic)                           \
+       ((magic)[0] == 0x3c && (magic)[1] == 0x03 &&    \
+       ((magic)[2] == 0xc8 || (magic)[2] == 0x00))
+
+#define        ELANTECH_FW_ID          0x00
+#define        ELANTECH_FW_VERSION     0x01
+#define        ELANTECH_CAPABILITIES   0x02
+#define        ELANTECH_SAMPLE         0x03
+#define        ELANTECH_RESOLUTION     0x04
+#define        ELANTECH_REG_READ       0x10
+#define        ELANTECH_REG_WRITE      0x11
+#define        ELANTECH_REG_RDWR       0x00
+#define        ELANTECH_CUSTOM_CMD     0xf8
+
+#define        ELANTECH_MAX_FINGERS    PSM_FINGERS
+
+#define        ELANTECH_FINGER_SET_XYP(pb) (finger_t) {                        
\
+    .x = (((pb)->ipacket[1] & 0x0f) << 8) | (pb)->ipacket[2],          \
+    .y = (((pb)->ipacket[4] & 0x0f) << 8) | (pb)->ipacket[5],          \
+    .p = ((pb)->ipacket[1] & 0xf0) | (((pb)->ipacket[4] >> 4) & 0x0f), \
+    .w = PSM_FINGER_DEFAULT_W,                                         \
+    .flags = 0                                                         \
+}
+
+enum {
+       ELANTECH_PKT_NOP,
+       ELANTECH_PKT_TRACKPOINT,
+       ELANTECH_PKT_V2_COMMON,
+       ELANTECH_PKT_V2_2FINGER,
+       ELANTECH_PKT_V3,
+       ELANTECH_PKT_V4_STATUS,
+       ELANTECH_PKT_V4_HEAD,
+       ELANTECH_PKT_V4_MOTION
+};
+
+#define        ELANTECH_PKT_IS_TRACKPOINT(pb) (((pb)->ipacket[3] & 0x0f) == 
0x06)
+#define        ELANTECH_PKT_IS_DEBOUNCE(pb, hwversion) ((hwversion) == 4 ? 0 : 
\
+    (pb)->ipacket[0] == ((hwversion) == 2 ? 0x84 : 0xc4) &&            \
+    (pb)->ipacket[1] == 0xff && (pb)->ipacket[2] == 0xff &&            \
+    (pb)->ipacket[3] == 0x02 && (pb)->ipacket[4] == 0xff &&            \
+    (pb)->ipacket[5] == 0xff)
+#define        ELANTECH_PKT_IS_V2(pb)                                          
\
+    (((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x0f) == 0x02)
+#define        ELANTECH_PKT_IS_V3_HEAD(pb, hascrc) ((hascrc) ?                 
\
+    ((pb)->ipacket[3] & 0x09) == 0x08 :                                \
+    ((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0xcf) == 0x02)
+#define        ELANTECH_PKT_IS_V3_TAIL(pb, hascrc) ((hascrc) ?                 
\
+    ((pb)->ipacket[3] & 0x09) == 0x09 :                                \
+    ((pb)->ipacket[0] & 0x0c) == 0x0c && ((pb)->ipacket[3] & 0xce) == 0x0c)
+#define        ELANTECH_PKT_IS_V4(pb, hascrc) ((hascrc) ?                      
\
+    ((pb)->ipacket[3] & 0x08) == 0x00 :                                        
\
+    ((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x1c) == 0x10)
+
+typedef struct elantechaction {
+       finger_t                fingers[ELANTECH_MAX_FINGERS];
+       int                     mask;
+} elantechaction_t;
+
 /* driver control block */
 struct psm_softc {             /* Driver status information */
        int             unit;
@@ -308,7 +381,10 @@ struct psm_softc {         /* Driver status inf
        mousehw_t       hw;             /* hardware information */
        synapticshw_t   synhw;          /* Synaptics hardware information */
        synapticsinfo_t syninfo;        /* Synaptics configuration */
-       synapticsaction_t synaction;    /* Synaptics action context */
+       smoother_t      smoother[PSM_FINGERS];  /* Motion smoothing */
+       gesture_t       gesture;        /* Gesture context */
+       elantechhw_t    elanhw;         /* Elantech hardware information */
+       elantechaction_t elanaction;    /* Elantech action context */
        int             tphw;           /* TrackPoint hardware information */
        trackpointinfo_t tpinfo;        /* TrackPoint configuration */
        mousemode_t     mode;           /* operation mode */
@@ -324,13 +400,13 @@ struct psm_softc {                /* Driver status inf
        int             xaverage;       /* average X position */
        int             yaverage;       /* average Y position */
        int             squelch; /* level to filter movement at low speed */
-       int             zmax;   /* maximum pressure value for touchpads */
        int             syncerrors; /* # of bytes discarded to synchronize */
        int             pkterrors;  /* # of packets failed during quaranteen. */
        struct timeval  inputtimeout;
        struct timeval  lastsoftintr;   /* time of last soft interrupt */
        struct timeval  lastinputerr;   /* time last sync error happened */
-       struct timeval  taptimeout;     /* tap timeout for touchpads */
+       struct timeval  idletimeout;
+       packetbuf_t     idlepacket;     /* packet to send after idle timeout */
        int             watchdog;       /* watchdog timer flag */
        struct callout  callout;        /* watchdog timer call out */
        struct callout  softcallout; /* buffer timer call out */
@@ -381,16 +457,10 @@ static devclass_t psm_devclass;
 
 /* Tunables */
 static int tap_enabled = -1;
-TUNABLE_INT("hw.psm.tap_enabled", &tap_enabled);
-
+static int verbose = PSM_DEBUG;
 static int synaptics_support = 0;
-TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support);
-
 static int trackpoint_support = 0;
-TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support);
-
-static int verbose = PSM_DEBUG;
-TUNABLE_INT("debug.psm.loglevel", &verbose);
+static int elantech_support = 0;
 
 /* for backward compatibility */
 #define        OLD_MOUSE_GETHWINFO     _IOR('M', 1, old_mousehw_t)
@@ -411,6 +481,44 @@ typedef struct old_mousemode {
        int     accelfactor;
 } old_mousemode_t;
 
+#define SYN_OFFSET(field) offsetof(struct psm_softc, syninfo.field)
+enum {
+       SYNAPTICS_SYSCTL_MIN_PRESSURE =         SYN_OFFSET(min_pressure),
+       SYNAPTICS_SYSCTL_MAX_PRESSURE =         SYN_OFFSET(max_pressure),
+       SYNAPTICS_SYSCTL_MAX_WIDTH =            SYN_OFFSET(max_width),
+       SYNAPTICS_SYSCTL_MARGIN_TOP =           SYN_OFFSET(margin_top),
+       SYNAPTICS_SYSCTL_MARGIN_RIGHT =         SYN_OFFSET(margin_right),
+       SYNAPTICS_SYSCTL_MARGIN_BOTTOM =        SYN_OFFSET(margin_bottom),
+       SYNAPTICS_SYSCTL_MARGIN_LEFT =          SYN_OFFSET(margin_left),
+       SYNAPTICS_SYSCTL_NA_TOP =               SYN_OFFSET(na_top),
+       SYNAPTICS_SYSCTL_NA_RIGHT =             SYN_OFFSET(na_right),
+       SYNAPTICS_SYSCTL_NA_BOTTOM =            SYN_OFFSET(na_bottom),
+       SYNAPTICS_SYSCTL_NA_LEFT =              SYN_OFFSET(na_left),
+       SYNAPTICS_SYSCTL_WINDOW_MIN =           SYN_OFFSET(window_min),
+       SYNAPTICS_SYSCTL_WINDOW_MAX =           SYN_OFFSET(window_max),
+       SYNAPTICS_SYSCTL_MULTIPLICATOR =        SYN_OFFSET(multiplicator),
+       SYNAPTICS_SYSCTL_WEIGHT_CURRENT =       SYN_OFFSET(weight_current),
+       SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS =      SYN_OFFSET(weight_previous),
+       SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA =   SYN_OFFSET(weight_previous_na),
+       SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED =   SYN_OFFSET(weight_len_squared),
+       SYNAPTICS_SYSCTL_DIV_MIN =              SYN_OFFSET(div_min),
+       SYNAPTICS_SYSCTL_DIV_MAX =              SYN_OFFSET(div_max),
+       SYNAPTICS_SYSCTL_DIV_MAX_NA =           SYN_OFFSET(div_max_na),
+       SYNAPTICS_SYSCTL_DIV_LEN =              SYN_OFFSET(div_len),
+       SYNAPTICS_SYSCTL_TAP_MAX_DELTA =        SYN_OFFSET(tap_max_delta),
+       SYNAPTICS_SYSCTL_TAP_MIN_QUEUE =        SYN_OFFSET(tap_min_queue),
+       SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT =      SYN_OFFSET(taphold_timeout),
+       SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA =     SYN_OFFSET(vscroll_hor_area),
+       SYNAPTICS_SYSCTL_VSCROLL_VER_AREA =     SYN_OFFSET(vscroll_ver_area),
+       SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA =    SYN_OFFSET(vscroll_min_delta),
+       SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN =      SYN_OFFSET(vscroll_div_min),
+       SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX =      SYN_OFFSET(vscroll_div_max),
+       SYNAPTICS_SYSCTL_TOUCHPAD_OFF =         SYN_OFFSET(touchpad_off),
+       SYNAPTICS_SYSCTL_SOFTBUTTONS_Y =        SYN_OFFSET(softbuttons_y),
+       SYNAPTICS_SYSCTL_SOFTBUTTON2_X =        SYN_OFFSET(softbutton2_x),
+       SYNAPTICS_SYSCTL_SOFTBUTTON3_X =        SYN_OFFSET(softbutton3_x),
+};
+
 /* packet formatting function */
 typedef int    packetfunc_t(struct psm_softc *, u_char *, int *, int,
     mousestatus_t *);
@@ -446,6 +554,7 @@ static int  doopen(struct psm_softc *, in
 static int     reinitialize(struct psm_softc *, int);
 static char    *model_name(int);
 static void    psmsoftintr(void *);
+static void    psmsoftintridle(void *);
 static void    psmintr(void *);
 static void    psmtimeout(void *);
 static int     timeelapsed(const struct timeval *, int, int,
@@ -458,6 +567,13 @@ static int proc_synaptics(struct psm_sof
                    mousestatus_t *, int *, int *, int *);
 static void    proc_versapad(struct psm_softc *, packetbuf_t *,
                    mousestatus_t *, int *, int *, int *);
+static int     proc_elantech(struct psm_softc *, packetbuf_t *,
+                   mousestatus_t *, int *, int *, int *);
+static int     psmpalmdetect(struct psm_softc *, finger_t *, int);
+static void    psmgestures(struct psm_softc *, finger_t *, int,
+                   mousestatus_t *);
+static void    psmsmoother(struct psm_softc *, finger_t *, int,
+                   mousestatus_t *, int *, int *);
 static int     tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *,
                    u_char *);
 
@@ -480,6 +596,7 @@ static probefunc_t  enable_mmanplus;
 static probefunc_t     enable_synaptics;
 static probefunc_t     enable_trackpoint;
 static probefunc_t     enable_versapad;
+static probefunc_t     enable_elantech;
 
 static void set_trackpoint_parameters(struct psm_softc *sc);
 static void synaptics_passthrough_on(struct psm_softc *sc);
@@ -511,6 +628,8 @@ static struct {
          0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus },
        { MOUSE_MODEL_SYNAPTICS,        /* Synaptics Touchpad */
          0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics },
+       { MOUSE_MODEL_ELANTECH,         /* Elantech Touchpad */
+         0x04, MOUSE_ELANTECH_PACKETSIZE, enable_elantech },
        { MOUSE_MODEL_INTELLI,          /* Microsoft IntelliMouse */
          0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli },
        { MOUSE_MODEL_GLIDEPOINT,       /* ALPS GlidePoint */
@@ -762,6 +881,7 @@ model_name(int model)
                { MOUSE_MODEL_4DPLUS,           "4D+ Mouse" },
                { MOUSE_MODEL_SYNAPTICS,        "Synaptics Touchpad" },
                { MOUSE_MODEL_TRACKPOINT,       "IBM/Lenovo TrackPoint" },
+               { MOUSE_MODEL_ELANTECH,         "Elantech Touchpad" },
                { MOUSE_MODEL_GENERIC,          "Generic PS/2 mouse" },
                { MOUSE_MODEL_UNKNOWN,          "Unknown" },
        };
@@ -1504,6 +1624,7 @@ psmattach(device_t dev)
        case MOUSE_MODEL_SYNAPTICS:
        case MOUSE_MODEL_GLIDEPOINT:
        case MOUSE_MODEL_VERSAPAD:
+       case MOUSE_MODEL_ELANTECH:
                sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
                break;
        default:
@@ -1512,6 +1633,11 @@ psmattach(device_t dev)
                break;
        }
 
+       /* Elantech trackpad`s sync bit differs from touchpad`s one */
+       if (sc->hw.model == MOUSE_MODEL_ELANTECH &&
+           (sc->elanhw.hascrc || sc->elanhw.hastrackpoint))
+               sc->config |= PSM_CONFIG_NOCHECKSYNC;
+
        if (!verbose)
                printf("psm%d: model %s, device ID %d\n",
                    unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff);
@@ -2165,20 +2291,6 @@ psmioctl(struct cdev *dev, u_long cmd, c
                    (*(int *)addr > PSM_LEVEL_MAX))
                        return (EINVAL);
                sc->mode.level = *(int *)addr;
-
-               if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) {
-                       /*
-                        * If we are entering PSM_LEVEL_NATIVE, we want to
-                        * enable sending of "extended W mode" packets to
-                        * userland. Reset the mode of the touchpad so that the
-                        * change in the level is picked up.
-                        */
-                       error = block_mouse_data(sc, &command_byte);
-                       if (error)
-                               return (error);
-                       synaptics_set_mode(sc, synaptics_preferred_mode(sc));
-                       unblock_mouse_data(sc, command_byte);
-               }
                break;
 
        case MOUSE_GETSTATUS:
@@ -2339,7 +2451,7 @@ psmtimeout(void *arg)
 static SYSCTL_NODE(_debug, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
 static SYSCTL_NODE(_hw, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse");
 
-SYSCTL_INT(_debug_psm, OID_AUTO, loglevel, CTLFLAG_RW, &verbose, 0,
+SYSCTL_INT(_debug_psm, OID_AUTO, loglevel, CTLFLAG_RWTUN, &verbose, 0,
     "Verbosity level");
 
 static int psmhz = 20;
@@ -2361,7 +2473,7 @@ static int pkterrthresh = 2;
 SYSCTL_INT(_debug_psm, OID_AUTO, pkterrthresh, CTLFLAG_RW, &pkterrthresh, 0,
     "Number of error packets allowed before reinitializing the mouse");
 
-SYSCTL_INT(_hw_psm, OID_AUTO, tap_enabled, CTLFLAG_RW, &tap_enabled, 0,
+SYSCTL_INT(_hw_psm, OID_AUTO, tap_enabled, CTLFLAG_RWTUN, &tap_enabled, 0,
     "Enable tap and drag gestures");
 static int tap_threshold = PSM_TAP_THRESHOLD;
 SYSCTL_INT(_hw_psm, OID_AUTO, tap_threshold, CTLFLAG_RW, &tap_threshold, 0,
@@ -2370,6 +2482,16 @@ static int tap_timeout = PSM_TAP_TIMEOUT
 SYSCTL_INT(_hw_psm, OID_AUTO, tap_timeout, CTLFLAG_RW, &tap_timeout, 0,
     "Tap timeout for touchpads");
 
+/* Tunables */
+SYSCTL_INT(_hw_psm, OID_AUTO, synaptics_support, CTLFLAG_RDTUN,
+    &synaptics_support, 0, "Enable support for Synaptics touchpads");
+
+SYSCTL_INT(_hw_psm, OID_AUTO, trackpoint_support, CTLFLAG_RDTUN,
+    &trackpoint_support, 0, "Enable support for IBM/Lenovo TrackPoint");
+
+SYSCTL_INT(_hw_psm, OID_AUTO, elantech_support, CTLFLAG_RDTUN,
+    &elantech_support, 0, "Enable support for Elantech touchpads");
+
 static void
 psmintr(void *arg)
 {
@@ -2627,7 +2749,10 @@ proc_synaptics(struct psm_softc *sc, pac
 {
        static int touchpad_buttons;
        static int guest_buttons;
-       int w, x0, y0;
+       static finger_t f[PSM_FINGERS];
+       int w, id, nfingers, ewcode, extended_buttons;
+
+       extended_buttons = 0;
 
        /* TouchPad PS/2 absolute mode message format with capFourButtons:
         *
@@ -2683,6 +2808,7 @@ proc_synaptics(struct psm_softc *sc, pac
                return (-1);
 
        *x = *y = 0;
+       ms->button = ms->obutton;
 
        /*
         * Pressure value.
@@ -2718,34 +2844,80 @@ proc_synaptics(struct psm_softc *sc, pac
                w = 4;
        }
 
-       /*
-        * Handle packets from the guest device. See:
-        * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1
-        */
-       if (w == 3 && sc->synhw.capPassthrough) {
-               *x = ((pb->ipacket[1] & 0x10) ?
-                   pb->ipacket[4] - 256 : pb->ipacket[4]);
-               *y = ((pb->ipacket[1] & 0x20) ?
-                   pb->ipacket[5] - 256 : pb->ipacket[5]);
-               *z = 0;
+       switch (w) {
+       case 3:
+               /*
+                * Handle packets from the guest device. See:
+                * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1
+                */
+               if (sc->synhw.capPassthrough) {
+                       *x = ((pb->ipacket[1] & 0x10) ?
+                           pb->ipacket[4] - 256 : pb->ipacket[4]);
+                       *y = ((pb->ipacket[1] & 0x20) ?
+                           pb->ipacket[5] - 256 : pb->ipacket[5]);
+                       *z = 0;
+
+                       guest_buttons = 0;
+                       if (pb->ipacket[1] & 0x01)
+                               guest_buttons |= MOUSE_BUTTON1DOWN;
+                       if (pb->ipacket[1] & 0x04)
+                               guest_buttons |= MOUSE_BUTTON2DOWN;
+                               if (pb->ipacket[1] & 0x02)
+                               guest_buttons |= MOUSE_BUTTON3DOWN;
 
-               guest_buttons = 0;
-               if (pb->ipacket[1] & 0x01)
-                       guest_buttons |= MOUSE_BUTTON1DOWN;
-               if (pb->ipacket[1] & 0x04)
-                       guest_buttons |= MOUSE_BUTTON2DOWN;
-               if (pb->ipacket[1] & 0x02)
-                       guest_buttons |= MOUSE_BUTTON3DOWN;
+                       ms->button = touchpad_buttons | guest_buttons |
+                           sc->extended_buttons;
+               }
+               goto SYNAPTICS_END;
 
-               ms->button = touchpad_buttons | guest_buttons;
+       case 2:
+               /* Handle Extended W mode packets */
+               ewcode = (pb->ipacket[5] & 0xf0) >> 4;
+#if PSM_FINGERS > 1
+               switch (ewcode) {
+               case 1:
+                       /* Secondary finger */
+                       if (sc->synhw.capAdvancedGestures)
+                               f[1] = (finger_t) {
+                                       .x = (((pb->ipacket[4] & 0x0f) << 8) |
+                                           pb->ipacket[1]) << 1,
+                                       .y = (((pb->ipacket[4] & 0xf0) << 4) |
+                                           pb->ipacket[2]) << 1,
+                                       .p = ((pb->ipacket[3] & 0x30) |
+                                           (pb->ipacket[5] & 0x0f)) << 1,
+                                       .w = PSM_FINGER_DEFAULT_W,
+                                       .flags = PSM_FINGER_FUZZY,
+                               };
+                       else if (sc->synhw.capReportsV)
+                               f[1] = (finger_t) {
+                                       .x = (((pb->ipacket[4] & 0x0f) << 8) |
+                                           (pb->ipacket[1] & 0xfe)) << 1,
+                                       .y = (((pb->ipacket[4] & 0xf0) << 4) |
+                                           (pb->ipacket[2] & 0xfe)) << 1,
+                                       .p = ((pb->ipacket[3] & 0x30) |
+                                           (pb->ipacket[5] & 0x0e)) << 1,
+                                       .w = (((pb->ipacket[5] & 0x01) << 2) |
+                                           ((pb->ipacket[2] & 0x01) << 1) |
+                                           (pb->ipacket[1] & 0x01)) + 8,
+                                       .flags = PSM_FINGER_FUZZY,
+                               };
+               default:
+                       break;
+               }
+#endif
                goto SYNAPTICS_END;
+
+       case 1:
+       case 0:
+               nfingers = w + 2;
+               break;
+
+       default:
+               nfingers = 1;
        }
 
-       if (sc->syninfo.touchpad_off) {
-               *x = *y = *z = 0;
-               ms->button = ms->obutton;
+       if (sc->syninfo.touchpad_off)
                goto SYNAPTICS_END;
-       }
 
        /* Button presses */
        touchpad_buttons = 0;
@@ -2769,21 +2941,21 @@ proc_synaptics(struct psm_softc *sc, pac
                if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x02) {
                        if (sc->syninfo.directional_scrolls) {
                                if (pb->ipacket[4] & 0x01)
-                                       touchpad_buttons |= MOUSE_BUTTON4DOWN;
+                                       extended_buttons |= MOUSE_BUTTON4DOWN;
                                if (pb->ipacket[5] & 0x01)
-                                       touchpad_buttons |= MOUSE_BUTTON5DOWN;
+                                       extended_buttons |= MOUSE_BUTTON5DOWN;
                                if (pb->ipacket[4] & 0x02)
-                                       touchpad_buttons |= MOUSE_BUTTON6DOWN;
+                                       extended_buttons |= MOUSE_BUTTON6DOWN;
                                if (pb->ipacket[5] & 0x02)
-                                       touchpad_buttons |= MOUSE_BUTTON7DOWN;
+                                       extended_buttons |= MOUSE_BUTTON7DOWN;
                        } else {
                                if (pb->ipacket[4] & 0x01)
-                                       touchpad_buttons |= MOUSE_BUTTON1DOWN;
+                                       extended_buttons |= MOUSE_BUTTON1DOWN;
                                if (pb->ipacket[5] & 0x01)
-                                       touchpad_buttons |= MOUSE_BUTTON3DOWN;
+                                       extended_buttons |= MOUSE_BUTTON3DOWN;
                                if (pb->ipacket[4] & 0x02)
-                                       touchpad_buttons |= MOUSE_BUTTON2DOWN;
-                               sc->extended_buttons = touchpad_buttons;
+                                       extended_buttons |= MOUSE_BUTTON2DOWN;
+                               sc->extended_buttons = extended_buttons;
                        }
 
                        /*
@@ -2806,101 +2978,193 @@ proc_synaptics(struct psm_softc *sc, pac
                        pb->ipacket[4] &= ~(mask);
                        pb->ipacket[5] &= ~(mask);
                } else  if (!sc->syninfo.directional_scrolls &&
-                   !sc->synaction.in_vscroll) {
+                   !sc->gesture.in_vscroll) {
                        /*
                         * Keep reporting MOUSE DOWN until we get a new packet
                         * indicating otherwise.
                         */
-                       touchpad_buttons |= sc->extended_buttons;
+                       extended_buttons |= sc->extended_buttons;
                }
        }
-       /* Handle ClickPad. */
+       /* Handle ClickPad */
        if (sc->synhw.capClickPad &&
            ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01))
                touchpad_buttons |= MOUSE_BUTTON1DOWN;
 
-       ms->button = touchpad_buttons | guest_buttons;
+       if (sc->synhw.capReportsV && nfingers > 1)
+               f[0] = (finger_t) {
+                       .x = ((pb->ipacket[3] & 0x10) << 8) |
+                           ((pb->ipacket[1] & 0x0f) << 8) |
+                           (pb->ipacket[4] & 0xfd),
+                       .y = ((pb->ipacket[3] & 0x20) << 7) |
+                           ((pb->ipacket[1] & 0xf0) << 4) |
+                           (pb->ipacket[5] & 0xfd),
+                       .p = *z & 0xfe,
+                       .w = (((pb->ipacket[2] & 0x01) << 2) |
+                           (pb->ipacket[5] & 0x02) |
+                           ((pb->ipacket[4] & 0x02) >> 1)) + 8,
+                       .flags = PSM_FINGER_FUZZY,
+               };
+       else
+               f[0] = (finger_t) {
+                       .x = ((pb->ipacket[3] & 0x10) << 8) |
+                           ((pb->ipacket[1] & 0x0f) << 8) |
+                           pb->ipacket[4],
+                       .y = ((pb->ipacket[3] & 0x20) << 7) |
+                           ((pb->ipacket[1] & 0xf0) << 4) |
+                           pb->ipacket[5],
+                       .p = *z,
+                       .w = w,
+                       .flags = nfingers > 1 ? PSM_FINGER_FUZZY : 0,
+               };
+
+       /* Ignore hovering and unmeasurable touches */
+       if (f[0].p < sc->syninfo.min_pressure || f[0].x < 2)
+               nfingers = 0;
+
+       for (id = 0; id < PSM_FINGERS; id++)
+               if (id >= nfingers)
+                       PSM_FINGER_RESET(f[id]);
+
+       ms->button = touchpad_buttons;
+
+       /* Palm detection doesn't terminate the current action. */
+       if (!psmpalmdetect(sc, &f[0], nfingers)) {
+               psmgestures(sc, &f[0], nfingers, ms);
+               for (id = 0; id < PSM_FINGERS; id++)
+                       psmsmoother(sc, &f[id], id, ms, x, y);
+       } else {
+               VLOG(2, (LOG_DEBUG, "synaptics: palm detected! (%d)\n", 
f[0].w));
+       }
+
+       ms->button |= extended_buttons | guest_buttons;
+
+SYNAPTICS_END:
+       /*
+        * Use the extra buttons as a scrollwheel
+        *
+        * XXX X.Org uses the Z axis for vertical wheel only,
+        * whereas moused(8) understands special values to differ
+        * vertical and horizontal wheels.
+        *
+        * xf86-input-mouse needs therefore a small patch to
+        * understand these special values. Without it, the
+        * horizontal wheel acts as a vertical wheel in X.Org.
+        *
+        * That's why the horizontal wheel is disabled by
+        * default for now.
+        */
+       if (ms->button & MOUSE_BUTTON4DOWN)
+               *z = -1;
+       else if (ms->button & MOUSE_BUTTON5DOWN)
+               *z = 1;
+       else if (ms->button & MOUSE_BUTTON6DOWN)
+               *z = -2;
+       else if (ms->button & MOUSE_BUTTON7DOWN)
+               *z = 2;
+       else
+               *z = 0;
+       ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN |
+           MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN);
+
+       return (0);
+}
+
+static int
+psmpalmdetect(struct psm_softc *sc, finger_t *f, int nfingers)
+{
+       if (!(
+           ((sc->synhw.capMultiFinger ||
+             sc->synhw.capAdvancedGestures) && nfingers > 1) ||
+           (sc->synhw.capPalmDetect && f->w <= sc->syninfo.max_width) ||
+           (!sc->synhw.capPalmDetect && f->p <= sc->syninfo.max_pressure) ||
+           (sc->synhw.capPen && f->flags & PSM_FINGER_IS_PEN))) {
+               /*
+                * We consider the packet irrelevant for the current
+                * action when:
+                *  - the width isn't comprised in:
+                *    [1; max_width]
+                *  - the pressure isn't comprised in:
+                *    [min_pressure; max_pressure]
+                *  - pen aren't supported but PSM_FINGER_IS_PEN is set
+                */
+               return (1);
+       }
+       return (0);
+}
+
+static void
+psmgestures(struct psm_softc *sc, finger_t *fingers, int nfingers,
+    mousestatus_t *ms)
+{
+       smoother_t *smoother;
+       gesture_t *gest;
+       finger_t *f;
+       int y_ok, center_button, center_x, right_button, right_x, i;
+
+       f = &fingers[0];
+       smoother = &sc->smoother[0];
+       gest = &sc->gesture;
+
+       /* Find first active finger. */
+       if (nfingers > 0) {
+               for (i = 0; i < PSM_FINGERS; i++) {
+                       if (PSM_FINGER_IS_SET(fingers[i])) {
+                               f = &fingers[i];
+                               smoother = &sc->smoother[i];
+                               break;
+                       }
+               }
+       }
 
        /*
         * Check pressure to detect a real wanted action on the
         * touchpad.
         */
-       if (*z >= sc->syninfo.min_pressure) {
-               synapticsaction_t *synaction;
-               int cursor, peer, window;
-               int dx, dy, dxp, dyp;
-               int max_width, max_pressure;
+       if (f->p >= sc->syninfo.min_pressure) {
+               int x0, y0;
+               int dxp, dyp;
+               int start_x, start_y;
+               int queue_len;
                int margin_top, margin_right, margin_bottom, margin_left;
-               int na_top, na_right, na_bottom, na_left;
                int window_min, window_max;
-               int multiplicator;
-               int weight_current, weight_previous, weight_len_squared;
-               int div_min, div_max, div_len;
                int vscroll_hor_area, vscroll_ver_area;
                int two_finger_scroll;
-               int len, weight_prev_x, weight_prev_y;
-               int div_max_x, div_max_y, div_x, div_y;
-               int exiting_scroll;
+               int max_x, max_y;
 
                /* Read sysctl. */
                /* XXX Verify values? */
-               max_width = sc->syninfo.max_width;
-               max_pressure = sc->syninfo.max_pressure;
                margin_top = sc->syninfo.margin_top;
                margin_right = sc->syninfo.margin_right;
                margin_bottom = sc->syninfo.margin_bottom;
                margin_left = sc->syninfo.margin_left;
-               na_top = sc->syninfo.na_top;
-               na_right = sc->syninfo.na_right;
-               na_bottom = sc->syninfo.na_bottom;
-               na_left = sc->syninfo.na_left;
                window_min = sc->syninfo.window_min;
                window_max = sc->syninfo.window_max;
-               multiplicator = sc->syninfo.multiplicator;
-               weight_current = sc->syninfo.weight_current;
-               weight_previous = sc->syninfo.weight_previous;
-               weight_len_squared = sc->syninfo.weight_len_squared;
-               div_min = sc->syninfo.div_min;
-               div_max = sc->syninfo.div_max;
-               div_len = sc->syninfo.div_len;
                vscroll_hor_area = sc->syninfo.vscroll_hor_area;
                vscroll_ver_area = sc->syninfo.vscroll_ver_area;
                two_finger_scroll = sc->syninfo.two_finger_scroll;
-
-               exiting_scroll = 0;
-
-               /* Palm detection. */
-               if (!(
-                   ((sc->synhw.capMultiFinger ||
-                     sc->synhw.capAdvancedGestures) && (w == 0 || w == 1)) ||
-                   (sc->synhw.capPalmDetect && w >= 4 && w <= max_width) ||
-                   (!sc->synhw.capPalmDetect && *z <= max_pressure) ||
-                   (sc->synhw.capPen && w == 2))) {
-                       /*
-                        * We consider the packet irrelevant for the current
-                        * action when:
-                        *  - the width isn't comprised in:
-                        *    [4; max_width]
-                        *  - the pressure isn't comprised in:
-                        *    [min_pressure; max_pressure]
-                        *  - pen aren't supported but w is 2
-                        *
-                        *  Note that this doesn't terminate the current action.
-                        */
-                       VLOG(2, (LOG_DEBUG,
-                           "synaptics: palm detected! (%d)\n", w));
-                       goto SYNAPTICS_END;
-               }
+               max_x = sc->syninfo.max_x;
+               max_y = sc->syninfo.max_y;
 
                /* Read current absolute position. */
-               x0 = ((pb->ipacket[3] & 0x10) << 8) |
-                   ((pb->ipacket[1] & 0x0f) << 8) |
-                   pb->ipacket[4];
-               y0 = ((pb->ipacket[3] & 0x20) << 7) |
-                   ((pb->ipacket[1] & 0xf0) << 4) |
-                   pb->ipacket[5];
+               x0 = f->x;
+               y0 = f->y;
+
+               /*
+                * Limit the coordinates to the specified margins because
+                * this area isn't very reliable.
+                */
+               if (x0 <= margin_left)
+                       x0 = margin_left;
+               else if (x0 >= max_x - margin_right)
+                       x0 = max_x - margin_right;
+               if (y0 <= margin_bottom)
+                       y0 = margin_bottom;
+               else if (y0 >= max_y - margin_top)
+                       y0 = max_y - margin_top;
 
-               synaction = &(sc->synaction);
+               VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
+                   x0, y0, f->p, f->w));
 
                /*
                 * If the action is just beginning, init the structure and
@@ -2909,107 +3173,82 @@ proc_synaptics(struct psm_softc *sc, pac
                if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) {
                        VLOG(3, (LOG_DEBUG, "synaptics: ----\n"));
 
-                       /* Store the first point of this action. */
-                       synaction->start_x = x0;
-                       synaction->start_y = y0;
-                       dx = dy = 0;
-
                        /* Initialize queue. */
-                       synaction->queue_cursor = SYNAPTICS_PACKETQUEUE;
-                       synaction->queue_len = 0;
-                       synaction->window_min = window_min;
-
-                       /* Reset average. */
-                       synaction->avg_dx = 0;
-                       synaction->avg_dy = 0;
-
-                       /* Reset squelch. */
-                       synaction->squelch_x = 0;
-                       synaction->squelch_y = 0;
+                       gest->window_min = window_min;
 
                        /* Reset pressure peak. */
-                       sc->zmax = 0;
+                       gest->zmax = 0;
 
                        /* Reset fingers count. */
-                       synaction->fingers_nb = 0;
+                       gest->fingers_nb = 0;
 
                        /* Reset virtual scrolling state. */
-                       synaction->in_vscroll = 0;
+                       gest->in_vscroll = 0;
 
                        /* Compute tap timeout. */
-                       sc->taptimeout.tv_sec  = tap_timeout / 1000000;
-                       sc->taptimeout.tv_usec = tap_timeout % 1000000;
-                       timevaladd(&sc->taptimeout, &sc->lastsoftintr);
+                       gest->taptimeout.tv_sec  = tap_timeout / 1000000;
+                       gest->taptimeout.tv_usec = tap_timeout % 1000000;
+                       timevaladd(&gest->taptimeout, &sc->lastsoftintr);
 
                        sc->flags |= PSM_FLAGS_FINGERDOWN;
+
+                       /* Smoother has not been reset yet */
+                       queue_len = 1;
+                       start_x = x0;
+                       start_y = y0;
                } else {
-                       /* Calculate the current delta. */
-                       cursor = synaction->queue_cursor;
-                       dx = x0 - synaction->queue[cursor].x;
-                       dy = y0 - synaction->queue[cursor].y;
+                       queue_len = smoother->queue_len + 1;
+                       start_x = smoother->start_x;
+                       start_y = smoother->start_y;
                }
 
-               /* If in tap-hold, add the recorded button. */
-               if (synaction->in_taphold)
-                       ms->button |= synaction->tap_button;
-
-               /*
-                * From now on, we can use the SYNAPTICS_END label to skip
-                * the current packet.
-                */
-
-               /*
-                * Limit the coordinates to the specified margins because
-                * this area isn't very reliable.
-                */
-               if (x0 <= margin_left)
-                       x0 = margin_left;
-               else if (x0 >= 6143 - margin_right)
-                       x0 = 6143 - margin_right;
-               if (y0 <= margin_bottom)
-                       y0 = margin_bottom;
-               else if (y0 >= 6143 - margin_top)
-                       y0 = 6143 - margin_top;
+               /* Process ClickPad softbuttons */
+               if (sc->synhw.capClickPad && ms->button & MOUSE_BUTTON1DOWN) {
+                       y_ok = sc->syninfo.softbuttons_y >= 0 ?
+                           start_y < sc->syninfo.softbuttons_y :
+                           start_y > max_y - sc->syninfo.softbuttons_y;
+
+                       center_button = MOUSE_BUTTON2DOWN;
+                       center_x = sc->syninfo.softbutton2_x;
+                       right_button = MOUSE_BUTTON3DOWN;
+                       right_x = sc->syninfo.softbutton3_x;
+
+                       if (center_x > 0 && right_x > 0 && center_x > right_x) {
+                               center_button = MOUSE_BUTTON3DOWN;
+                               center_x = sc->syninfo.softbutton3_x;
+                               right_button = MOUSE_BUTTON2DOWN;
+                               right_x = sc->syninfo.softbutton2_x;
+                       }
 
-               VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n",
-                   x0, y0, *z, w));
+                       if (right_x > 0 && start_x > right_x && y_ok)
+                               ms->button = (ms->button &
+                                   ~MOUSE_BUTTON1DOWN) | right_button;
+                       else if (center_x > 0 && start_x > center_x && y_ok)
+                               ms->button = (ms->button &
+                                   ~MOUSE_BUTTON1DOWN) | center_button;
+               }
 
-               /* Queue this new packet. */
-               cursor = SYNAPTICS_QUEUE_CURSOR(synaction->queue_cursor - 1);
-               synaction->queue[cursor].x = x0;
-               synaction->queue[cursor].y = y0;
-               synaction->queue_cursor = cursor;
-               if (synaction->queue_len < SYNAPTICS_PACKETQUEUE)
-                       synaction->queue_len++;
-               VLOG(5, (LOG_DEBUG,
-                   "synaptics: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n",
-                   cursor, x0, y0, dx, dy));
+               /* If in tap-hold, add the recorded button. */
+               if (gest->in_taphold)
+                       ms->button |= gest->tap_button;
 
                /*
                 * For tap, we keep the maximum number of fingers and the
                 * pressure peak. Also with multiple fingers, we increase
                 * the minimum window.
                 */
-               switch (w) {
-               case 1: /* Three or more fingers. */
-                       synaction->fingers_nb = imax(3, synaction->fingers_nb);
-                       synaction->window_min = window_max;
-                       break;
-               case 0: /* Two fingers. */
-                       synaction->fingers_nb = imax(2, synaction->fingers_nb);
-                       synaction->window_min = window_max;
-                       break;
-               default: /* One finger or undetectable. */
-                       synaction->fingers_nb = imax(1, synaction->fingers_nb);
-               }
-               sc->zmax = imax(*z, sc->zmax);
-
-               /* Do we have enough packets to consider this a movement? */
-               if (synaction->queue_len < synaction->window_min)
-                       goto SYNAPTICS_END;
+               if (nfingers > 1)
+                       gest->window_min = window_max;
+               gest->fingers_nb = imax(nfingers, gest->fingers_nb);
+               gest->zmax = imax(f->p, gest->zmax);
+
+               /* Do we have enough packets to consider this a gesture? */
+               if (queue_len < gest->window_min)
+                       return;
 
                /* Is a scrolling action occurring? */
-               if (!synaction->in_taphold && !synaction->in_vscroll) {
+               if (!gest->in_taphold && !ms->button &&
+                   (!gest->in_vscroll || two_finger_scroll)) {
                        /*
                         * A scrolling action must not conflict with a tap
                         * action. Here are the conditions to consider a
@@ -3020,12 +3259,10 @@ proc_synaptics(struct psm_softc *sc, pac
                         *       first should be above a configurable minimum
                         *     . tap timed out
                         */
-                       dxp = abs(synaction->queue[synaction->queue_cursor].x -
-                           synaction->start_x);
-                       dyp = abs(synaction->queue[synaction->queue_cursor].y -
-                           synaction->start_y);
+                       dxp = abs(x0 - start_x);
+                       dyp = abs(y0 - start_y);
 
-                       if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, >) ||
+                       if (timevalcmp(&sc->lastsoftintr, &gest->taptimeout, >) 
||
                            dxp >= sc->syninfo.vscroll_min_delta ||
                            dyp >= sc->syninfo.vscroll_min_delta) {
                                /*
@@ -3034,176 +3271,65 @@ proc_synaptics(struct psm_softc *sc, pac
                                 * as that keeps the maximum number of fingers.
                                 */
                                if (two_finger_scroll) {

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to