1/*
2 * Copyright � 1999 Henry Davies
3 * Copyright � 2001 Stefan Gmeiner
4 * Copyright � 2002 S. Lehner
5 * Copyright � 2002 Peter Osterlund
6 * Copyright � 2002 Linuxcare Inc. David Kennedy
7 * Copyright � 2003 Hartwig Felger
8 * Copyright � 2003 J�rg B�sner
9 * Copyright � 2003 Fred Hucht
10 * Copyright � 2004 Alexei Gilchrist
11 * Copyright � 2004 Matthias Ihmig
12 * Copyright � 2006 Stefan Bethge
13 * Copyright � 2006 Christian Thaeter
14 * Copyright � 2007 Joseph P. Skudlarek
15 * Copyright � 2008 Fedor P. Goncharov
16 * Copyright � 2008-2012 Red Hat, Inc.
17 * Copyright � 2011 The Chromium OS Authors
18 *
19 * Permission to use, copy, modify, distribute, and sell this software
20 * and its documentation for any purpose is hereby granted without
21 * fee, provided that the above copyright notice appear in all copies
22 * and that both that copyright notice and this permission notice
23 * appear in supporting documentation, and that the name of Red Hat
24 * not be used in advertising or publicity pertaining to distribution
25 * of the software without specific, written prior permission.  Red
26 * Hat makes no representations about the suitability of this software
27 * for any purpose.  It is provided "as is" without express or implied
28 * warranty.
29 *
30 * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
31 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
32 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
33 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
34 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
35 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
36 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
37 *
38 * Authors:
39 *      Joseph P. Skudlarek <Jskud@Jskud.com>
40 *      Christian Thaeter <chth@gmx.net>
41 *      Stefan Bethge <stefan.bethge@web.de>
42 *      Matthias Ihmig <m.ihmig@gmx.net>
43 *      Alexei Gilchrist <alexei@physics.uq.edu.au>
44 *      J�rg B�sner <ich@joerg-boesner.de>
45 *      Hartwig Felger <hgfelger@hgfelger.de>
46 *      Peter Osterlund <petero2@telia.com>
47 *      S. Lehner <sam_x@bluemail.ch>
48 *      Stefan Gmeiner <riddlebox@freesurf.ch>
49 *      Henry Davies <hdavies@ameritech.net> for the
50 *      Linuxcare Inc. David Kennedy <dkennedy@linuxcare.com>
51 *      Fred Hucht <fred@thp.Uni-Duisburg.de>
52 *      Fedor P. Goncharov <fedgo@gorodok.net>
53 *      Simon Thum <simon.thum@gmx.de>
54 *
55 * Trademarks are the property of their respective owners.
56 */
57
58#ifdef HAVE_CONFIG_H
59#include "config.h"
60#endif
61
62#include <xorg-server.h>
63#include <unistd.h>
64#include <misc.h>
65#include <xf86.h>
66#include <math.h>
67#include <stdio.h>
68#include <xf86_OSproc.h>
69#include <xf86Xinput.h>
70#include <exevents.h>
71
72#include <X11/Xatom.h>
73#include <X11/extensions/XI2.h>
74#include <xserver-properties.h>
75#include <ptrveloc.h>
76
77#include "synapticsstr.h"
78#include "synaptics-properties.h"
79
80enum EdgeType {
81    NO_EDGE = 0,
82    BOTTOM_EDGE = 1,
83    TOP_EDGE = 2,
84    LEFT_EDGE = 4,
85    RIGHT_EDGE = 8,
86    LEFT_BOTTOM_EDGE = BOTTOM_EDGE | LEFT_EDGE,
87    RIGHT_BOTTOM_EDGE = BOTTOM_EDGE | RIGHT_EDGE,
88    RIGHT_TOP_EDGE = TOP_EDGE | RIGHT_EDGE,
89    LEFT_TOP_EDGE = TOP_EDGE | LEFT_EDGE
90};
91
92/*
93 * We expect to be receiving a steady 80 packets/sec (which gives 40
94 * reports/sec with more than one finger on the pad, as Advanced Gesture Mode
95 * requires two PS/2 packets per report).  Instead of a random scattering of
96 * magic 13 and 20ms numbers scattered throughout the driver, introduce
97 * POLL_MS as 14ms, which is slightly less than 80Hz.  13ms is closer to
98 * 80Hz, but if the kernel event reporting was even slightly delayed,
99 * we would produce synthetic motion followed immediately by genuine
100 * motion, so use 14.
101 *
102 * We use this to call back at a constant rate to at least produce the
103 * illusion of smooth motion.  It works a lot better than you'd expect.
104*/
105#define POLL_MS 14
106
107#define MAX(a, b) (((a)>(b))?(a):(b))
108#define MIN(a, b) (((a)<(b))?(a):(b))
109#define TIME_DIFF(a, b) ((int)((a)-(b)))
110
111#define SQR(x) ((x) * (x))
112
113#ifndef M_PI
114#define M_PI 3.14159265358979323846
115#endif
116
117#define INPUT_BUFFER_SIZE 200
118
119/*****************************************************************************
120 * Forward declaration
121 ****************************************************************************/
122static int SynapticsPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
123static void SynapticsUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
124static Bool DeviceControl(DeviceIntPtr, int);
125static void ReadInput(InputInfoPtr);
126static int HandleState(InputInfoPtr, struct SynapticsHwState *, CARD32 now,
127                       Bool from_timer);
128static int ControlProc(InputInfoPtr, xDeviceCtl *);
129static int SwitchMode(ClientPtr, DeviceIntPtr, int);
130static int DeviceInit(DeviceIntPtr);
131static int DeviceOn(DeviceIntPtr);
132static int DeviceOff(DeviceIntPtr);
133static int DeviceClose(DeviceIntPtr);
134static Bool QueryHardware(InputInfoPtr);
135static void ReadDevDimensions(InputInfoPtr);
136static void ScaleCoordinates(SynapticsPrivate * priv,
137                             struct SynapticsHwState *hw);
138static void CalculateScalingCoeffs(SynapticsPrivate * priv);
139static void SanitizeDimensions(InputInfoPtr pInfo);
140
141void InitDeviceProperties(InputInfoPtr pInfo);
142int SetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
143                BOOL checkonly);
144
145const static struct {
146    const char *name;
147    struct SynapticsProtocolOperations *proto_ops;
148} protocols[] = {
149#ifdef BUILD_EVENTCOMM
150    { "event", &event_proto_operations },
151#endif
152#ifdef BUILD_PSMCOMM
153    { "psm", &psm_proto_operations },
154#endif
155#ifdef BUILD_PS2COMM
156    { "psaux", &psaux_proto_operations },
157    { "alps", &alps_proto_operations },
158#endif
159    { NULL, NULL }
160};
161
162InputDriverRec SYNAPTICS = {
163    1,
164    "synaptics",
165    NULL,
166    SynapticsPreInit,
167    SynapticsUnInit,
168    NULL,
169};
170
171static XF86ModuleVersionInfo VersionRec = {
172    "synaptics",
173    MODULEVENDORSTRING,
174    MODINFOSTRING1,
175    MODINFOSTRING2,
176    XORG_VERSION_CURRENT,
177    PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
178    ABI_CLASS_XINPUT,
179    ABI_XINPUT_VERSION,
180    MOD_CLASS_XINPUT,
181    {0, 0, 0, 0}
182};
183
184static pointer
185SetupProc(pointer module, pointer options, int *errmaj, int *errmin)
186{
187    xf86AddInputDriver(&SYNAPTICS, module, 0);
188    return module;
189}
190
191_X_EXPORT XF86ModuleData synapticsModuleData = {
192    &VersionRec,
193    &SetupProc,
194    NULL
195};
196
197/*****************************************************************************
198 *	Function Definitions
199 ****************************************************************************/
200/**
201 * Fill in default dimensions for backends that cannot query the hardware.
202 * Eventually, we want the edges to be 1900/5400 for x, 1900/4000 for y.
203 * These values are based so that calculate_edge_widths() will give us the
204 * right values.
205 *
206 * The default values 1900, etc. come from the dawn of time, when men where
207 * men, or possibly apes.
208 */
209static void
210SanitizeDimensions(InputInfoPtr pInfo)
211{
212    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
213
214    if (priv->minx >= priv->maxx) {
215        priv->minx = 1615;
216        priv->maxx = 5685;
217        priv->resx = 0;
218
219        xf86IDrvMsg(pInfo, X_PROBED,
220                    "invalid x-axis range.  defaulting to %d - %d\n",
221                    priv->minx, priv->maxx);
222    }
223
224    if (priv->miny >= priv->maxy) {
225        priv->miny = 1729;
226        priv->maxy = 4171;
227        priv->resy = 0;
228
229        xf86IDrvMsg(pInfo, X_PROBED,
230                    "invalid y-axis range.  defaulting to %d - %d\n",
231                    priv->miny, priv->maxy);
232    }
233
234    if (priv->minp >= priv->maxp) {
235        priv->minp = 0;
236        priv->maxp = 255;
237
238        xf86IDrvMsg(pInfo, X_PROBED,
239                    "invalid pressure range.  defaulting to %d - %d\n",
240                    priv->minp, priv->maxp);
241    }
242
243    if (priv->minw >= priv->maxw) {
244        priv->minw = 0;
245        priv->maxw = 15;
246
247        xf86IDrvMsg(pInfo, X_PROBED,
248                    "invalid finger width range.  defaulting to %d - %d\n",
249                    priv->minw, priv->maxw);
250    }
251}
252
253static Bool
254SetDeviceAndProtocol(InputInfoPtr pInfo)
255{
256    SynapticsPrivate *priv = pInfo->private;
257    char *proto, *device;
258    int i;
259
260    proto = xf86SetStrOption(pInfo->options, "Protocol", NULL);
261    device = xf86SetStrOption(pInfo->options, "Device", NULL);
262
263    /* If proto is auto-dev, unset and let the code do the rest */
264    if (proto && !strcmp(proto, "auto-dev")) {
265        free(proto);
266        proto = NULL;
267    }
268
269    for (i = 0; protocols[i].name; i++) {
270        if ((!device || !proto) &&
271            protocols[i].proto_ops->AutoDevProbe &&
272            protocols[i].proto_ops->AutoDevProbe(pInfo, device))
273            break;
274        else if (proto && !strcmp(proto, protocols[i].name))
275            break;
276    }
277    free(proto);
278    free(device);
279
280    priv->proto_ops = protocols[i].proto_ops;
281
282    return (priv->proto_ops != NULL);
283}
284
285static void
286calculate_edge_widths(SynapticsPrivate * priv, int *l, int *r, int *t, int *b)
287{
288    int width, height;
289    int ewidth, eheight;        /* edge width/height */
290
291    width = abs(priv->maxx - priv->minx);
292    height = abs(priv->maxy - priv->miny);
293
294    if (priv->model == MODEL_SYNAPTICS) {
295        ewidth = width * .07;
296        eheight = height * .07;
297    }
298    else if (priv->model == MODEL_ALPS) {
299        ewidth = width * .15;
300        eheight = height * .15;
301    }
302    else if (priv->model == MODEL_APPLETOUCH ||
303             priv->model == MODEL_UNIBODY_MACBOOK) {
304        ewidth = width * .085;
305        eheight = height * .085;
306    }
307    else {
308        ewidth = width * .04;
309        eheight = height * .054;
310    }
311
312    *l = priv->minx + ewidth;
313    *r = priv->maxx - ewidth;
314    *t = priv->miny + eheight;
315    *b = priv->maxy - eheight;
316}
317
318static void
319calculate_tap_hysteresis(SynapticsPrivate * priv, int range,
320                         int *fingerLow, int *fingerHigh)
321{
322    switch (priv->model) {
323    case MODEL_ELANTECH:
324        /* All Elantech touchpads don't need the Z filtering to get the
325         * number of fingers correctly. See Documentation/elantech.txt
326         * in the kernel.
327         */
328        *fingerLow = priv->minp + 1;
329        *fingerHigh = priv->minp + 1;
330        break;
331    case MODEL_UNIBODY_MACBOOK:
332        *fingerLow = 70;
333        *fingerHigh = 75;
334        break;
335    default:
336        *fingerLow = priv->minp + range * (25.0 / 256);
337        *fingerHigh = priv->minp + range * (30.0 / 256);
338        break;
339    }
340}
341
342/* Area options support both percent values and absolute values. This is
343 * awkward. The xf86Set* calls will print to the log, but they'll
344 * also print an error if we request a percent value but only have an
345 * int. So - check first for percent, then call xf86Set* again to get
346 * the log message.
347 */
348static int
349set_percent_option(pointer options, const char *optname,
350                   const int range, const int offset, const int default_value)
351{
352    int result;
353    double percent = xf86CheckPercentOption(options, optname, -1);
354
355    if (percent >= 0.0) {
356        percent = xf86SetPercentOption(options, optname, -1);
357        result = percent / 100.0 * range + offset;
358    } else
359        result = xf86SetIntOption(options, optname, default_value);
360
361    return result;
362}
363
364Bool
365SynapticsIsSoftButtonAreasValid(int *values)
366{
367    Bool right_disabled = FALSE;
368    Bool middle_disabled = FALSE;
369
370    enum {
371        /* right button left, right, top, bottom */
372        RBL = 0,
373        RBR = 1,
374        RBT = 2,
375        RBB = 3,
376        /* middle button left, right, top, bottom */
377        MBL = 4,
378        MBR = 5,
379        MBT = 6,
380        MBB = 7,
381    };
382
383    /* Check right button area */
384    if ((((values[RBL] != 0) && (values[RBR] != 0)) && (values[RBL] > values[RBR])) ||
385        (((values[RBT] != 0) && (values[RBB] != 0)) && (values[RBT] > values[RBB])))
386        return FALSE;
387
388    /* Check middle button area */
389    if ((((values[MBL] != 0) && (values[MBR] != 0)) && (values[MBL] > values[MBR])) ||
390        (((values[MBT] != 0) && (values[MBB] != 0)) && (values[MBT] > values[MBB])))
391        return FALSE;
392
393    if (values[RBL] == 0 && values[RBR] == 0 && values[RBT] == 0 && values[RBB] == 0)
394        right_disabled = TRUE;
395
396    if (values[MBL] == 0 && values[MBR] == 0 && values[MBT] == 0 && values[MBB] == 0)
397        middle_disabled = TRUE;
398
399    if (!right_disabled &&
400        ((values[RBL] && values[RBL] == values[RBR]) ||
401         (values[RBT] && values[RBT] == values[RBB])))
402        return FALSE;
403
404    if (!middle_disabled &&
405        ((values[MBL] && values[MBL] == values[MBR]) ||
406         (values[MBT] && values[MBT] == values[MBB])))
407        return FALSE;
408
409    /* Check for overlapping button areas */
410    if (!right_disabled && !middle_disabled) {
411        int right_left = values[RBL] ? values[RBL] : INT_MIN;
412        int right_right = values[RBR] ? values[RBR] : INT_MAX;
413        int right_top = values[RBT] ? values[RBT] : INT_MIN;
414        int right_bottom = values[RBB] ? values[RBB] : INT_MAX;
415        int middle_left = values[MBL] ? values[MBL] : INT_MIN;
416        int middle_right = values[MBR] ? values[MBR] : INT_MAX;
417        int middle_top = values[MBT] ? values[MBT] : INT_MIN;
418        int middle_bottom = values[MBB] ? values[MBB] : INT_MAX;
419
420        /* If areas overlap in the Y axis */
421        if ((right_bottom <= middle_bottom && right_bottom >= middle_top) ||
422            (right_top <= middle_bottom && right_top >= middle_top)) {
423            /* Check for overlapping left edges */
424            if ((right_left < middle_left && right_right > middle_left) ||
425                (middle_left < right_left && middle_right > right_left))
426                return FALSE;
427
428            /* Check for overlapping right edges */
429            if ((right_right > middle_right && right_left < middle_right) ||
430                (middle_right > right_right && middle_left < right_right))
431                return FALSE;
432        }
433
434        /* If areas overlap in the X axis */
435        if ((right_left >= middle_left && right_left <= middle_right) ||
436            (right_right >= middle_left && right_right <= middle_right)) {
437            /* Check for overlapping top edges */
438            if ((right_top < middle_top && right_bottom > middle_top) ||
439                (middle_top < right_top && middle_bottom > right_top))
440                return FALSE;
441
442            /* Check for overlapping bottom edges */
443            if ((right_bottom > middle_bottom && right_top < middle_bottom) ||
444                (middle_bottom > right_bottom && middle_top < right_bottom))
445                return FALSE;
446        }
447    }
448
449    return TRUE;
450}
451
452static void
453set_softbutton_areas_option(InputInfoPtr pInfo)
454{
455    SynapticsPrivate *priv = pInfo->private;
456    SynapticsParameters *pars = &priv->synpara;
457    int values[8];
458    int in_percent = 0;         /* bitmask for which ones are in % */
459    char *option_string;
460    char *next_num;
461    char *end_str;
462    int i;
463    int width, height;
464
465    if (!pars->clickpad)
466        return;
467
468    option_string = xf86SetStrOption(pInfo->options, "SoftButtonAreas", NULL);
469    if (!option_string)
470        return;
471
472    next_num = option_string;
473
474    for (i = 0; i < 8 && *next_num != '\0'; i++) {
475        long int value = strtol(next_num, &end_str, 0);
476
477        if (value > INT_MAX || value < -INT_MAX)
478            goto fail;
479
480        values[i] = value;
481
482        if (next_num != end_str) {
483            if (end_str && *end_str == '%') {
484                in_percent |= 1 << i;
485                end_str++;
486            }
487            next_num = end_str;
488        }
489        else
490            goto fail;
491    }
492
493    if (i < 8 || *next_num != '\0')
494        goto fail;
495
496    width = priv->maxx - priv->minx;
497    height = priv->maxy - priv->miny;
498
499    for (i = 0; in_percent && i < 8; i++) {
500        int base, size;
501
502        if ((in_percent & (1 << i)) == 0 || values[i] == 0)
503            continue;
504
505        size = ((i % 4) < 2) ? width : height;
506        base = ((i % 4) < 2) ? priv->minx : priv->miny;
507        values[i] = base + size * values[i] / 100.0;
508    }
509
510    if (!SynapticsIsSoftButtonAreasValid(values))
511        goto fail;
512
513    memcpy(pars->softbutton_areas[0], values, 4 * sizeof(int));
514    memcpy(pars->softbutton_areas[1], values + 4, 4 * sizeof(int));
515
516    free(option_string);
517
518    return;
519
520 fail:
521    xf86IDrvMsg(pInfo, X_ERROR,
522                "invalid SoftButtonAreas value '%s', keeping defaults\n",
523                option_string);
524    free(option_string);
525}
526
527static void
528set_default_parameters(InputInfoPtr pInfo)
529{
530    SynapticsPrivate *priv = pInfo->private;    /* read-only */
531    pointer opts = pInfo->options;      /* read-only */
532    SynapticsParameters *pars = &priv->synpara; /* modified */
533
534    int horizScrollDelta, vertScrollDelta;      /* pixels */
535    int tapMove;                /* pixels */
536    int l, r, t, b;             /* left, right, top, bottom */
537    double accelFactor;         /* 1/pixels */
538    int fingerLow, fingerHigh;  /* pressure */
539    int emulateTwoFingerMinZ;   /* pressure */
540    int emulateTwoFingerMinW;   /* width */
541    int pressureMotionMinZ, pressureMotionMaxZ; /* pressure */
542    int palmMinWidth, palmMinZ; /* pressure */
543    int tapButton1, tapButton2, tapButton3;
544    int clickFinger1, clickFinger2, clickFinger3;
545    Bool vertEdgeScroll, horizEdgeScroll;
546    Bool vertTwoFingerScroll, horizTwoFingerScroll;
547    int horizResolution = 1;
548    int vertResolution = 1;
549    int width, height, diag, range;
550    int horizHyst, vertHyst;
551    int middle_button_timeout;
552
553    /* The synaptics specs specify typical edge widths of 4% on x, and 5.4% on
554     * y (page 7) [Synaptics TouchPad Interfacing Guide, 510-000080 - A
555     * Second Edition, http://www.synaptics.com/support/dev_support.cfm, 8 Sep
556     * 2008]. We use 7% for both instead for synaptics devices, and 15% for
557     * ALPS models.
558     * http://bugs.freedesktop.org/show_bug.cgi?id=21214
559     *
560     * If the range was autodetected, apply these edge widths to all four
561     * sides.
562     */
563
564    width = abs(priv->maxx - priv->minx);
565    height = abs(priv->maxy - priv->miny);
566    diag = sqrt(width * width + height * height);
567
568    calculate_edge_widths(priv, &l, &r, &t, &b);
569
570    /* Again, based on typical x/y range and defaults */
571    horizScrollDelta = diag * .020;
572    vertScrollDelta = diag * .020;
573    tapMove = diag * .044;
574    accelFactor = 200.0 / diag; /* trial-and-error */
575
576    /* hysteresis, assume >= 0 is a detected value (e.g. evdev fuzz) */
577    horizHyst = pars->hyst_x >= 0 ? pars->hyst_x : diag * 0.005;
578    vertHyst = pars->hyst_y >= 0 ? pars->hyst_y : diag * 0.005;
579
580    range = priv->maxp - priv->minp + 1;
581
582    calculate_tap_hysteresis(priv, range, &fingerLow, &fingerHigh);
583
584    /* scaling based on defaults and a pressure of 256 */
585    emulateTwoFingerMinZ = priv->minp + range * (282.0 / 256);
586    pressureMotionMinZ = priv->minp + range * (30.0 / 256);
587    pressureMotionMaxZ = priv->minp + range * (160.0 / 256);
588    palmMinZ = priv->minp + range * (200.0 / 256);
589
590    range = priv->maxw - priv->minw + 1;
591
592    /* scaling based on defaults below and a tool width of 16 */
593    palmMinWidth = priv->minw + range * (10.0 / 16);
594    emulateTwoFingerMinW = priv->minw + range * (7.0 / 16);
595
596    /* Enable tap if we don't have a phys left button */
597    tapButton1 = priv->has_left ? 0 : 1;
598    tapButton2 = priv->has_left ? 0 : 3;
599    tapButton3 = priv->has_left ? 0 : 2;
600
601    /* Enable multifinger-click if only have one physical button,
602       otherwise clickFinger is always button 1. */
603    clickFinger1 = 1;
604    clickFinger2 = (priv->has_right || priv->has_middle) ? 1 : 3;
605    clickFinger3 = (priv->has_right || priv->has_middle) ? 1 : 2;
606
607    /* Enable vert edge scroll if we can't detect doubletap */
608    vertEdgeScroll = priv->has_double ? FALSE : TRUE;
609    horizEdgeScroll = FALSE;
610
611    /* Enable twofinger scroll if we can detect doubletap */
612    vertTwoFingerScroll = priv->has_double ? TRUE : FALSE;
613    horizTwoFingerScroll = FALSE;
614
615    /* Use resolution reported by hardware if available */
616    if ((priv->resx > 0) && (priv->resy > 0)) {
617        horizResolution = priv->resx;
618        vertResolution = priv->resy;
619    }
620
621    /* set the parameters */
622    pars->left_edge = xf86SetIntOption(opts, "LeftEdge", l);
623    pars->right_edge = xf86SetIntOption(opts, "RightEdge", r);
624    pars->top_edge = xf86SetIntOption(opts, "TopEdge", t);
625    pars->bottom_edge = xf86SetIntOption(opts, "BottomEdge", b);
626
627    pars->area_top_edge =
628        set_percent_option(opts, "AreaTopEdge", height, priv->miny, 0);
629    pars->area_bottom_edge =
630        set_percent_option(opts, "AreaBottomEdge", height, priv->miny, 0);
631    pars->area_left_edge =
632        set_percent_option(opts, "AreaLeftEdge", width, priv->minx, 0);
633    pars->area_right_edge =
634        set_percent_option(opts, "AreaRightEdge", width, priv->minx, 0);
635
636    pars->hyst_x =
637        set_percent_option(opts, "HorizHysteresis", width, 0, horizHyst);
638    pars->hyst_y =
639        set_percent_option(opts, "VertHysteresis", height, 0, vertHyst);
640
641    pars->finger_low = xf86SetIntOption(opts, "FingerLow", fingerLow);
642    pars->finger_high = xf86SetIntOption(opts, "FingerHigh", fingerHigh);
643    pars->tap_time = xf86SetIntOption(opts, "MaxTapTime", 180);
644    pars->tap_move = xf86SetIntOption(opts, "MaxTapMove", tapMove);
645    pars->tap_time_2 = xf86SetIntOption(opts, "MaxDoubleTapTime", 180);
646    pars->click_time = xf86SetIntOption(opts, "ClickTime", 100);
647    pars->clickpad = xf86SetBoolOption(opts, "ClickPad", pars->clickpad);       /* Probed */
648    /* middle mouse button emulation on a clickpad? nah, you're joking */
649    middle_button_timeout = pars->clickpad ? 0 : 75;
650    pars->emulate_mid_button_time =
651        xf86SetIntOption(opts, "EmulateMidButtonTime", middle_button_timeout);
652    pars->emulate_twofinger_z =
653        xf86SetIntOption(opts, "EmulateTwoFingerMinZ", emulateTwoFingerMinZ);
654    pars->emulate_twofinger_w =
655        xf86SetIntOption(opts, "EmulateTwoFingerMinW", emulateTwoFingerMinW);
656    pars->scroll_dist_vert =
657        xf86SetIntOption(opts, "VertScrollDelta", vertScrollDelta);
658    pars->scroll_dist_horiz =
659        xf86SetIntOption(opts, "HorizScrollDelta", horizScrollDelta);
660    pars->scroll_edge_vert =
661        xf86SetBoolOption(opts, "VertEdgeScroll", vertEdgeScroll);
662    pars->scroll_edge_horiz =
663        xf86SetBoolOption(opts, "HorizEdgeScroll", horizEdgeScroll);
664    pars->scroll_edge_corner = xf86SetBoolOption(opts, "CornerCoasting", FALSE);
665    pars->scroll_twofinger_vert =
666        xf86SetBoolOption(opts, "VertTwoFingerScroll", vertTwoFingerScroll);
667    pars->scroll_twofinger_horiz =
668        xf86SetBoolOption(opts, "HorizTwoFingerScroll", horizTwoFingerScroll);
669    pars->touchpad_off = xf86SetIntOption(opts, "TouchpadOff", TOUCHPAD_ON);
670    pars->locked_drags = xf86SetBoolOption(opts, "LockedDrags", FALSE);
671    pars->locked_drag_time = xf86SetIntOption(opts, "LockedDragTimeout", 5000);
672    pars->tap_action[RT_TAP] = xf86SetIntOption(opts, "RTCornerButton", 0);
673    pars->tap_action[RB_TAP] = xf86SetIntOption(opts, "RBCornerButton", 0);
674    pars->tap_action[LT_TAP] = xf86SetIntOption(opts, "LTCornerButton", 0);
675    pars->tap_action[LB_TAP] = xf86SetIntOption(opts, "LBCornerButton", 0);
676    pars->tap_action[F1_TAP] = xf86SetIntOption(opts, "TapButton1", tapButton1);
677    pars->tap_action[F2_TAP] = xf86SetIntOption(opts, "TapButton2", tapButton2);
678    pars->tap_action[F3_TAP] = xf86SetIntOption(opts, "TapButton3", tapButton3);
679    pars->click_action[F1_CLICK1] =
680        xf86SetIntOption(opts, "ClickFinger1", clickFinger1);
681    pars->click_action[F2_CLICK1] =
682        xf86SetIntOption(opts, "ClickFinger2", clickFinger2);
683    pars->click_action[F3_CLICK1] =
684        xf86SetIntOption(opts, "ClickFinger3", clickFinger3);
685    pars->circular_scrolling =
686        xf86SetBoolOption(opts, "CircularScrolling", FALSE);
687    pars->circular_trigger = xf86SetIntOption(opts, "CircScrollTrigger", 0);
688    pars->palm_detect = xf86SetBoolOption(opts, "PalmDetect", FALSE);
689    pars->palm_min_width = xf86SetIntOption(opts, "PalmMinWidth", palmMinWidth);
690    pars->palm_min_z = xf86SetIntOption(opts, "PalmMinZ", palmMinZ);
691    pars->single_tap_timeout = xf86SetIntOption(opts, "SingleTapTimeout", 180);
692    pars->press_motion_min_z =
693        xf86SetIntOption(opts, "PressureMotionMinZ", pressureMotionMinZ);
694    pars->press_motion_max_z =
695        xf86SetIntOption(opts, "PressureMotionMaxZ", pressureMotionMaxZ);
696
697    pars->min_speed = xf86SetRealOption(opts, "MinSpeed", 0.4);
698    pars->max_speed = xf86SetRealOption(opts, "MaxSpeed", 0.7);
699    pars->accl = xf86SetRealOption(opts, "AccelFactor", accelFactor);
700    pars->scroll_dist_circ = xf86SetRealOption(opts, "CircScrollDelta", 0.1);
701    pars->coasting_speed = xf86SetRealOption(opts, "CoastingSpeed", 20.0);
702    pars->coasting_friction = xf86SetRealOption(opts, "CoastingFriction", 50);
703    pars->press_motion_min_factor =
704        xf86SetRealOption(opts, "PressureMotionMinFactor", 1.0);
705    pars->press_motion_max_factor =
706        xf86SetRealOption(opts, "PressureMotionMaxFactor", 1.0);
707    pars->grab_event_device = xf86SetBoolOption(opts, "GrabEventDevice", TRUE);
708    pars->tap_and_drag_gesture =
709        xf86SetBoolOption(opts, "TapAndDragGesture", TRUE);
710    pars->resolution_horiz =
711        xf86SetIntOption(opts, "HorizResolution", horizResolution);
712    pars->resolution_vert =
713        xf86SetIntOption(opts, "VertResolution", vertResolution);
714
715    /* Warn about (and fix) incorrectly configured TopEdge/BottomEdge parameters */
716    if (pars->top_edge > pars->bottom_edge) {
717        int tmp = pars->top_edge;
718
719        pars->top_edge = pars->bottom_edge;
720        pars->bottom_edge = tmp;
721        xf86IDrvMsg(pInfo, X_WARNING,
722                    "TopEdge is bigger than BottomEdge. Fixing.\n");
723    }
724
725    set_softbutton_areas_option(pInfo);
726}
727
728static double
729SynapticsAccelerationProfile(DeviceIntPtr dev,
730                             DeviceVelocityPtr vel,
731                             double velocity, double thr, double acc)
732{
733    InputInfoPtr pInfo = dev->public.devicePrivate;
734    SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
735    SynapticsParameters *para = &priv->synpara;
736
737    double accelfct;
738
739    /*
740     * synaptics accel was originally base on device coordinate based
741     * velocity, which we recover this way so para->accl retains its scale.
742     */
743    velocity /= vel->const_acceleration;
744
745    /* speed up linear with finger velocity */
746    accelfct = velocity * para->accl;
747
748    /* clip acceleration factor */
749    if (accelfct > para->max_speed * acc)
750        accelfct = para->max_speed * acc;
751    else if (accelfct < para->min_speed)
752        accelfct = para->min_speed;
753
754    /* modify speed according to pressure */
755    if (priv->moving_state == MS_TOUCHPAD_RELATIVE) {
756        int minZ = para->press_motion_min_z;
757        int maxZ = para->press_motion_max_z;
758        double minFctr = para->press_motion_min_factor;
759        double maxFctr = para->press_motion_max_factor;
760
761        if (priv->hwState->z <= minZ) {
762            accelfct *= minFctr;
763        }
764        else if (priv->hwState->z >= maxZ) {
765            accelfct *= maxFctr;
766        }
767        else {
768            accelfct *=
769                minFctr + (priv->hwState->z - minZ) * (maxFctr -
770                                                       minFctr) / (maxZ - minZ);
771        }
772    }
773
774    return accelfct;
775}
776
777static int
778SynapticsPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
779{
780    SynapticsPrivate *priv;
781
782    /* allocate memory for SynapticsPrivateRec */
783    priv = calloc(1, sizeof(SynapticsPrivate));
784    if (!priv)
785        return BadAlloc;
786
787    pInfo->type_name = XI_TOUCHPAD;
788    pInfo->device_control = DeviceControl;
789    pInfo->read_input = ReadInput;
790    pInfo->control_proc = ControlProc;
791    pInfo->switch_mode = SwitchMode;
792    pInfo->private = priv;
793
794    /* allocate now so we don't allocate in the signal handler */
795    priv->timer = TimerSet(NULL, 0, 0, NULL, NULL);
796    if (!priv->timer) {
797        free(priv);
798        return BadAlloc;
799    }
800
801    /* may change pInfo->options */
802    if (!SetDeviceAndProtocol(pInfo)) {
803        xf86IDrvMsg(pInfo, X_ERROR,
804                    "Synaptics driver unable to detect protocol\n");
805        goto SetupProc_fail;
806    }
807
808    priv->device = xf86FindOptionValue(pInfo->options, "Device");
809
810    /* open the touchpad device */
811    pInfo->fd = xf86OpenSerial(pInfo->options);
812    if (pInfo->fd == -1) {
813        xf86IDrvMsg(pInfo, X_ERROR, "Synaptics driver unable to open device\n");
814        goto SetupProc_fail;
815    }
816    xf86ErrorFVerb(6, "port opened successfully\n");
817
818    /* initialize variables */
819    priv->count_packet_finger = 0;
820    priv->tap_state = TS_START;
821    priv->tap_button = 0;
822    priv->tap_button_state = TBS_BUTTON_UP;
823    priv->touch_on.millis = 0;
824    priv->synpara.hyst_x = -1;
825    priv->synpara.hyst_y = -1;
826
827    /* read hardware dimensions */
828    ReadDevDimensions(pInfo);
829
830    set_default_parameters(pInfo);
831
832    CalculateScalingCoeffs(priv);
833
834    priv->comm.buffer = XisbNew(pInfo->fd, INPUT_BUFFER_SIZE);
835
836    if (!QueryHardware(pInfo)) {
837        xf86IDrvMsg(pInfo, X_ERROR,
838                    "Unable to query/initialize Synaptics hardware.\n");
839        goto SetupProc_fail;
840    }
841
842    xf86ProcessCommonOptions(pInfo, pInfo->options);
843
844    if (pInfo->fd != -1) {
845        if (priv->comm.buffer) {
846            XisbFree(priv->comm.buffer);
847            priv->comm.buffer = NULL;
848        }
849        xf86CloseSerial(pInfo->fd);
850    }
851    pInfo->fd = -1;
852
853    return Success;
854
855 SetupProc_fail:
856    if (pInfo->fd >= 0) {
857        xf86CloseSerial(pInfo->fd);
858        pInfo->fd = -1;
859    }
860
861    if (priv->comm.buffer)
862        XisbFree(priv->comm.buffer);
863    free(priv->proto_data);
864    free(priv->timer);
865    free(priv);
866    pInfo->private = NULL;
867    return BadAlloc;
868}
869
870/*
871 *  Uninitialize the device.
872 */
873static void
874SynapticsUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
875{
876    SynapticsPrivate *priv = ((SynapticsPrivate *) pInfo->private);
877
878    if (priv && priv->timer)
879        free(priv->timer);
880    if (priv && priv->proto_data)
881        free(priv->proto_data);
882    if (priv && priv->scroll_events_mask)
883        valuator_mask_free(&priv->scroll_events_mask);
884    if (priv && priv->open_slots)
885        free(priv->open_slots);
886    free(pInfo->private);
887    pInfo->private = NULL;
888    xf86DeleteInput(pInfo, 0);
889}
890
891/*
892 *  Alter the control parameters for the mouse. Note that all special
893 *  protocol values are handled by dix.
894 */
895static void
896SynapticsCtrl(DeviceIntPtr device, PtrCtrl * ctrl)
897{
898}
899
900static int
901DeviceControl(DeviceIntPtr dev, int mode)
902{
903    Bool RetValue;
904
905    switch (mode) {
906    case DEVICE_INIT:
907        RetValue = DeviceInit(dev);
908        break;
909    case DEVICE_ON:
910        RetValue = DeviceOn(dev);
911        break;
912    case DEVICE_OFF:
913        RetValue = DeviceOff(dev);
914        break;
915    case DEVICE_CLOSE:
916        RetValue = DeviceClose(dev);
917        break;
918    default:
919        RetValue = BadValue;
920    }
921
922    return RetValue;
923}
924
925static int
926DeviceOn(DeviceIntPtr dev)
927{
928    InputInfoPtr pInfo = dev->public.devicePrivate;
929    SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
930
931    DBG(3, "Synaptics DeviceOn called\n");
932
933    pInfo->fd = xf86OpenSerial(pInfo->options);
934    if (pInfo->fd == -1) {
935        xf86IDrvMsg(pInfo, X_WARNING, "cannot open input device\n");
936        return !Success;
937    }
938
939    if (priv->proto_ops->DeviceOnHook &&
940        !priv->proto_ops->DeviceOnHook(pInfo, &priv->synpara))
941        return !Success;
942
943    priv->comm.buffer = XisbNew(pInfo->fd, INPUT_BUFFER_SIZE);
944    if (!priv->comm.buffer) {
945        xf86CloseSerial(pInfo->fd);
946        pInfo->fd = -1;
947        return !Success;
948    }
949
950    xf86FlushInput(pInfo->fd);
951
952    /* reinit the pad */
953    if (!QueryHardware(pInfo)) {
954        XisbFree(priv->comm.buffer);
955        priv->comm.buffer = NULL;
956        xf86CloseSerial(pInfo->fd);
957        pInfo->fd = -1;
958        return !Success;
959    }
960
961    xf86AddEnabledDevice(pInfo);
962    dev->public.on = TRUE;
963
964    return Success;
965}
966
967static void
968SynapticsReset(SynapticsPrivate * priv)
969{
970    SynapticsResetHwState(priv->hwState);
971    SynapticsResetHwState(priv->local_hw_state);
972    SynapticsResetHwState(priv->old_hw_state);
973    SynapticsResetHwState(priv->comm.hwState);
974
975    memset(priv->move_hist, 0, sizeof(priv->move_hist));
976    priv->hyst_center_x = 0;
977    priv->hyst_center_y = 0;
978    memset(&priv->scroll, 0, sizeof(priv->scroll));
979    priv->count_packet_finger = 0;
980    priv->finger_state = FS_UNTOUCHED;
981    priv->last_motion_millis = 0;
982    priv->tap_state = TS_START;
983    priv->tap_button = 0;
984    priv->tap_button_state = TBS_BUTTON_UP;
985    priv->moving_state = MS_FALSE;
986    priv->vert_scroll_edge_on = FALSE;
987    priv->horiz_scroll_edge_on = FALSE;
988    priv->vert_scroll_twofinger_on = FALSE;
989    priv->horiz_scroll_twofinger_on = FALSE;
990    priv->circ_scroll_on = FALSE;
991    priv->circ_scroll_vert = FALSE;
992    priv->mid_emu_state = MBE_OFF;
993    priv->lastButtons = 0;
994    priv->prev_z = 0;
995    priv->prevFingers = 0;
996    priv->num_active_touches = 0;
997    memset(priv->open_slots, 0, priv->num_slots * sizeof(int));
998}
999
1000static int
1001DeviceOff(DeviceIntPtr dev)
1002{
1003    InputInfoPtr pInfo = dev->public.devicePrivate;
1004    SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
1005    Bool rc = Success;
1006
1007    DBG(3, "Synaptics DeviceOff called\n");
1008
1009    if (pInfo->fd != -1) {
1010        TimerCancel(priv->timer);
1011        xf86RemoveEnabledDevice(pInfo);
1012        SynapticsReset(priv);
1013
1014        if (priv->proto_ops->DeviceOffHook &&
1015            !priv->proto_ops->DeviceOffHook(pInfo))
1016            rc = !Success;
1017        if (priv->comm.buffer) {
1018            XisbFree(priv->comm.buffer);
1019            priv->comm.buffer = NULL;
1020        }
1021        xf86CloseSerial(pInfo->fd);
1022        pInfo->fd = -1;
1023    }
1024    dev->public.on = FALSE;
1025    return rc;
1026}
1027
1028static int
1029DeviceClose(DeviceIntPtr dev)
1030{
1031    Bool RetValue;
1032    InputInfoPtr pInfo = dev->public.devicePrivate;
1033    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
1034
1035    RetValue = DeviceOff(dev);
1036    TimerFree(priv->timer);
1037    priv->timer = NULL;
1038    free(priv->touch_axes);
1039    priv->touch_axes = NULL;
1040    SynapticsHwStateFree(&priv->hwState);
1041    SynapticsHwStateFree(&priv->old_hw_state);
1042    SynapticsHwStateFree(&priv->local_hw_state);
1043    SynapticsHwStateFree(&priv->comm.hwState);
1044    return RetValue;
1045}
1046
1047static void
1048InitAxesLabels(Atom *labels, int nlabels, const SynapticsPrivate * priv)
1049{
1050    int i;
1051
1052    memset(labels, 0, nlabels * sizeof(Atom));
1053    switch (nlabels) {
1054    default:
1055    case 4:
1056        labels[3] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_VSCROLL);
1057    case 3:
1058        labels[2] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_HSCROLL);
1059    case 2:
1060        labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
1061    case 1:
1062        labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
1063        break;
1064    }
1065
1066    for (i = 0; i < priv->num_mt_axes; i++) {
1067        SynapticsTouchAxisRec *axis = &priv->touch_axes[i];
1068        int axnum = nlabels - priv->num_mt_axes + i;
1069
1070        labels[axnum] = XIGetKnownProperty(axis->label);
1071    }
1072}
1073
1074static void
1075InitButtonLabels(Atom *labels, int nlabels)
1076{
1077    memset(labels, 0, nlabels * sizeof(Atom));
1078    switch (nlabels) {
1079    default:
1080    case 7:
1081        labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
1082    case 6:
1083        labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
1084    case 5:
1085        labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
1086    case 4:
1087        labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
1088    case 3:
1089        labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
1090    case 2:
1091        labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
1092    case 1:
1093        labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
1094        break;
1095    }
1096}
1097
1098static void
1099DeviceInitTouch(DeviceIntPtr dev, Atom *axes_labels)
1100{
1101    InputInfoPtr pInfo = dev->public.devicePrivate;
1102    SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
1103    int i;
1104
1105    if (priv->has_touch) {
1106        priv->num_slots =
1107            priv->max_touches ? priv->max_touches : SYNAPTICS_MAX_TOUCHES;
1108
1109        priv->open_slots = malloc(priv->num_slots * sizeof(int));
1110        if (!priv->open_slots) {
1111            xf86IDrvMsg(pInfo, X_ERROR,
1112                        "failed to allocate open touch slots array\n");
1113            priv->has_touch = 0;
1114            priv->num_slots = 0;
1115            return;
1116        }
1117
1118        /* x/y + whatever other MT axes we found */
1119        if (!InitTouchClassDeviceStruct(dev, priv->max_touches,
1120                                        XIDependentTouch,
1121                                        2 + priv->num_mt_axes)) {
1122            xf86IDrvMsg(pInfo, X_ERROR,
1123                        "failed to initialize touch class device\n");
1124            priv->has_touch = 0;
1125            priv->num_slots = 0;
1126            free(priv->open_slots);
1127            priv->open_slots = NULL;
1128            return;
1129        }
1130
1131        for (i = 0; i < priv->num_mt_axes; i++) {
1132            SynapticsTouchAxisRec *axis = &priv->touch_axes[i];
1133            int axnum = 4 + i;  /* Skip x, y, and scroll axes */
1134
1135            if (!xf86InitValuatorAxisStruct(dev, axnum, axes_labels[axnum],
1136                                            axis->min, axis->max, axis->res, 0,
1137                                            axis->res, Absolute)) {
1138                xf86IDrvMsg(pInfo, X_WARNING,
1139                            "failed to initialize axis %s, skipping\n",
1140                            axis->label);
1141                continue;
1142            }
1143
1144            xf86InitValuatorDefaults(dev, axnum);
1145        }
1146    }
1147}
1148
1149static int
1150DeviceInit(DeviceIntPtr dev)
1151{
1152    InputInfoPtr pInfo = dev->public.devicePrivate;
1153    SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
1154    Atom float_type, prop;
1155    float tmpf;
1156    unsigned char map[SYN_MAX_BUTTONS + 1];
1157    int i;
1158    int min, max;
1159    int num_axes = 2;
1160    Atom btn_labels[SYN_MAX_BUTTONS] = { 0 };
1161    Atom *axes_labels;
1162    DeviceVelocityPtr pVel;
1163
1164    num_axes += 2;
1165
1166    num_axes += priv->num_mt_axes;
1167
1168    axes_labels = calloc(num_axes, sizeof(Atom));
1169    if (!axes_labels) {
1170        xf86IDrvMsg(pInfo, X_ERROR, "failed to allocate axis labels\n");
1171        return !Success;
1172    }
1173
1174    InitAxesLabels(axes_labels, num_axes, priv);
1175    InitButtonLabels(btn_labels, SYN_MAX_BUTTONS);
1176
1177    DBG(3, "Synaptics DeviceInit called\n");
1178
1179    for (i = 0; i <= SYN_MAX_BUTTONS; i++)
1180        map[i] = i;
1181
1182    dev->public.on = FALSE;
1183
1184    InitPointerDeviceStruct((DevicePtr) dev, map,
1185                            SYN_MAX_BUTTONS,
1186                            btn_labels,
1187                            SynapticsCtrl,
1188                            GetMotionHistorySize(), num_axes, axes_labels);
1189
1190    /*
1191     * setup dix acceleration to match legacy synaptics settings, and
1192     * etablish a device-specific profile to do stuff like pressure-related
1193     * acceleration.
1194     */
1195    if (NULL != (pVel = GetDevicePredictableAccelData(dev))) {
1196        SetDeviceSpecificAccelerationProfile(pVel,
1197                                             SynapticsAccelerationProfile);
1198
1199        /* float property type */
1200        float_type = XIGetKnownProperty(XATOM_FLOAT);
1201
1202        /* translate MinAcc to constant deceleration.
1203         * May be overridden in xf86InitValuatorDefaults */
1204        tmpf = 1.0 / priv->synpara.min_speed;
1205
1206        xf86IDrvMsg(pInfo, X_CONFIG,
1207                    "(accel) MinSpeed is now constant deceleration " "%.1f\n",
1208                    tmpf);
1209        prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION);
1210        XIChangeDeviceProperty(dev, prop, float_type, 32,
1211                               PropModeReplace, 1, &tmpf, FALSE);
1212
1213        /* adjust accordingly */
1214        priv->synpara.max_speed /= priv->synpara.min_speed;
1215        priv->synpara.min_speed = 1.0;
1216
1217        /* synaptics seems to report 80 packet/s, but dix scales for
1218         * 100 packet/s by default. */
1219        pVel->corr_mul = 12.5f; /*1000[ms]/80[/s] = 12.5 */
1220
1221        xf86IDrvMsg(pInfo, X_CONFIG, "(accel) MaxSpeed is now %.2f\n",
1222                    priv->synpara.max_speed);
1223        xf86IDrvMsg(pInfo, X_CONFIG, "(accel) AccelFactor is now %.3f\n",
1224                    priv->synpara.accl);
1225
1226        prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER);
1227        i = AccelProfileDeviceSpecific;
1228        XIChangeDeviceProperty(dev, prop, XA_INTEGER, 32,
1229                               PropModeReplace, 1, &i, FALSE);
1230    }
1231
1232    /* X valuator */
1233    if (priv->minx < priv->maxx) {
1234        min = priv->minx;
1235        max = priv->maxx;
1236    }
1237    else {
1238        min = 0;
1239        max = -1;
1240    }
1241
1242    xf86InitValuatorAxisStruct(dev, 0, axes_labels[0], min, max,
1243			       priv->resx * 1000, 0, priv->resx * 1000,
1244			       Relative);
1245    xf86InitValuatorDefaults(dev, 0);
1246
1247    /* Y valuator */
1248    if (priv->miny < priv->maxy) {
1249        min = priv->miny;
1250        max = priv->maxy;
1251    }
1252    else {
1253        min = 0;
1254        max = -1;
1255    }
1256
1257    xf86InitValuatorAxisStruct(dev, 1, axes_labels[1], min, max,
1258			       priv->resy * 1000, 0, priv->resy * 1000,
1259			       Relative);
1260    xf86InitValuatorDefaults(dev, 1);
1261
1262    xf86InitValuatorAxisStruct(dev, 2, axes_labels[2], 0, -1, 0, 0, 0,
1263                               Relative);
1264    priv->scroll_axis_horiz = 2;
1265    xf86InitValuatorAxisStruct(dev, 3, axes_labels[3], 0, -1, 0, 0, 0,
1266                               Relative);
1267    priv->scroll_axis_vert = 3;
1268    priv->scroll_events_mask = valuator_mask_new(MAX_VALUATORS);
1269    if (!priv->scroll_events_mask) {
1270        free(axes_labels);
1271        return !Success;
1272    }
1273
1274    SetScrollValuator(dev, priv->scroll_axis_horiz, SCROLL_TYPE_HORIZONTAL,
1275                      priv->synpara.scroll_dist_horiz, 0);
1276    SetScrollValuator(dev, priv->scroll_axis_vert, SCROLL_TYPE_VERTICAL,
1277                      priv->synpara.scroll_dist_vert, 0);
1278
1279    DeviceInitTouch(dev, axes_labels);
1280
1281    free(axes_labels);
1282
1283    priv->hwState = SynapticsHwStateAlloc(priv);
1284    if (!priv->hwState)
1285        goto fail;
1286
1287    priv->old_hw_state = SynapticsHwStateAlloc(priv);
1288    if (!priv->old_hw_state)
1289        goto fail;
1290
1291    priv->local_hw_state = SynapticsHwStateAlloc(priv);
1292    if (!priv->local_hw_state)
1293        goto fail;
1294
1295    priv->comm.hwState = SynapticsHwStateAlloc(priv);
1296
1297    InitDeviceProperties(pInfo);
1298    XIRegisterPropertyHandler(pInfo->dev, SetProperty, NULL, NULL);
1299
1300    return Success;
1301
1302 fail:
1303    free(priv->local_hw_state);
1304    free(priv->hwState);
1305    free(priv->open_slots);
1306    return !Success;
1307}
1308
1309/* return angle of point relative to center */
1310static double
1311angle(SynapticsPrivate * priv, int x, int y)
1312{
1313    double xCenter = (priv->synpara.left_edge + priv->synpara.right_edge) / 2.0;
1314    double yCenter = (priv->synpara.top_edge + priv->synpara.bottom_edge) / 2.0;
1315
1316    return atan2(-(y - yCenter), x - xCenter);
1317}
1318
1319/* return angle difference */
1320static double
1321diffa(double a1, double a2)
1322{
1323    double da = fmod(a2 - a1, 2 * M_PI);
1324
1325    if (da < 0)
1326        da += 2 * M_PI;
1327    if (da > M_PI)
1328        da -= 2 * M_PI;
1329    return da;
1330}
1331
1332static enum EdgeType
1333edge_detection(SynapticsPrivate * priv, int x, int y)
1334{
1335    enum EdgeType edge = NO_EDGE;
1336
1337    if (x > priv->synpara.right_edge)
1338        edge |= RIGHT_EDGE;
1339    else if (x < priv->synpara.left_edge)
1340        edge |= LEFT_EDGE;
1341
1342    if (y < priv->synpara.top_edge)
1343        edge |= TOP_EDGE;
1344    else if (y > priv->synpara.bottom_edge)
1345        edge |= BOTTOM_EDGE;
1346
1347    return edge;
1348}
1349
1350/* Checks whether coordinates are in the Synaptics Area
1351 * or not. If no Synaptics Area is defined (i.e. if
1352 * priv->synpara.area_{left|right|top|bottom}_edge are
1353 * all set to zero), the function returns TRUE.
1354 */
1355static Bool
1356is_inside_active_area(SynapticsPrivate * priv, int x, int y)
1357{
1358    Bool inside_area = TRUE;
1359
1360    if ((priv->synpara.area_left_edge != 0) &&
1361        (x < priv->synpara.area_left_edge))
1362        inside_area = FALSE;
1363    else if ((priv->synpara.area_right_edge != 0) &&
1364             (x > priv->synpara.area_right_edge))
1365        inside_area = FALSE;
1366
1367    if ((priv->synpara.area_top_edge != 0) && (y < priv->synpara.area_top_edge))
1368        inside_area = FALSE;
1369    else if ((priv->synpara.area_bottom_edge != 0) &&
1370             (y > priv->synpara.area_bottom_edge))
1371        inside_area = FALSE;
1372
1373    return inside_area;
1374}
1375
1376static Bool
1377is_inside_button_area(SynapticsParameters * para, int which, int x, int y)
1378{
1379    Bool inside_area = TRUE;
1380
1381    enum {
1382        LEFT = 0,
1383        RIGHT = 1,
1384        TOP = 2,
1385        BOTTOM = 3
1386    };
1387
1388    if (para->softbutton_areas[which][LEFT] == 0 &&
1389        para->softbutton_areas[which][RIGHT] == 0 &&
1390        para->softbutton_areas[which][TOP] == 0 &&
1391        para->softbutton_areas[which][BOTTOM] == 0)
1392        return FALSE;
1393
1394    if (para->softbutton_areas[which][LEFT] &&
1395        x < para->softbutton_areas[which][LEFT])
1396        inside_area = FALSE;
1397    else if (para->softbutton_areas[which][RIGHT] &&
1398             x > para->softbutton_areas[which][RIGHT])
1399        inside_area = FALSE;
1400    else if (para->softbutton_areas[which][TOP] &&
1401             y < para->softbutton_areas[which][TOP])
1402        inside_area = FALSE;
1403    else if (para->softbutton_areas[which][BOTTOM] &&
1404             y > para->softbutton_areas[which][BOTTOM])
1405        inside_area = FALSE;
1406
1407    return inside_area;
1408}
1409
1410static Bool
1411is_inside_rightbutton_area(SynapticsParameters * para, int x, int y)
1412{
1413    return is_inside_button_area(para, 0, x, y);
1414}
1415
1416static Bool
1417is_inside_middlebutton_area(SynapticsParameters * para, int x, int y)
1418{
1419    return is_inside_button_area(para, 1, x, y);
1420}
1421
1422static CARD32
1423timerFunc(OsTimerPtr timer, CARD32 now, pointer arg)
1424{
1425    InputInfoPtr pInfo = arg;
1426    SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
1427    struct SynapticsHwState *hw = priv->local_hw_state;
1428    int delay;
1429    int sigstate;
1430
1431    sigstate = xf86BlockSIGIO();
1432
1433    priv->hwState->millis += now - priv->timer_time;
1434    SynapticsCopyHwState(hw, priv->hwState);
1435    SynapticsResetTouchHwState(hw, FALSE);
1436    delay = HandleState(pInfo, hw, hw->millis, TRUE);
1437
1438    priv->timer_time = now;
1439    priv->timer = TimerSet(priv->timer, 0, delay, timerFunc, pInfo);
1440
1441    xf86UnblockSIGIO(sigstate);
1442
1443    return 0;
1444}
1445
1446static int
1447clamp(int val, int min, int max)
1448{
1449    if (val < min)
1450        return min;
1451    else if (val < max)
1452        return val;
1453    else
1454        return max;
1455}
1456
1457static Bool
1458SynapticsGetHwState(InputInfoPtr pInfo, SynapticsPrivate * priv,
1459                    struct SynapticsHwState *hw)
1460{
1461    return priv->proto_ops->ReadHwState(pInfo, &priv->comm, hw);
1462}
1463
1464/*
1465 *  called for each full received packet from the touchpad
1466 */
1467static void
1468ReadInput(InputInfoPtr pInfo)
1469{
1470    SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
1471    struct SynapticsHwState *hw = priv->local_hw_state;
1472    int delay = 0;
1473    Bool newDelay = FALSE;
1474
1475    SynapticsResetTouchHwState(hw, FALSE);
1476
1477    while (SynapticsGetHwState(pInfo, priv, hw)) {
1478        /* Semi-mt device touch slots do not track touches. When there is a
1479         * change in the number of touches, we must disregard the temporary
1480         * motion changes. */
1481        if (priv->has_semi_mt && hw->numFingers != priv->hwState->numFingers) {
1482            hw->cumulative_dx = priv->hwState->cumulative_dx;
1483            hw->cumulative_dy = priv->hwState->cumulative_dy;
1484        }
1485
1486        /* timer may cause actual events to lag behind (#48777) */
1487        if (priv->hwState->millis > hw->millis)
1488            hw->millis = priv->hwState->millis;
1489
1490        SynapticsCopyHwState(priv->hwState, hw);
1491        delay = HandleState(pInfo, hw, hw->millis, FALSE);
1492        newDelay = TRUE;
1493    }
1494
1495    if (newDelay) {
1496        priv->timer_time = GetTimeInMillis();
1497        priv->timer = TimerSet(priv->timer, 0, delay, timerFunc, pInfo);
1498    }
1499}
1500
1501static int
1502HandleMidButtonEmulation(SynapticsPrivate * priv, struct SynapticsHwState *hw,
1503                         CARD32 now, int *delay)
1504{
1505    SynapticsParameters *para = &priv->synpara;
1506    Bool done = FALSE;
1507    int timeleft;
1508    int mid = 0;
1509
1510    if (para->emulate_mid_button_time <= 0)
1511        return mid;
1512
1513    while (!done) {
1514        switch (priv->mid_emu_state) {
1515        case MBE_LEFT_CLICK:
1516        case MBE_RIGHT_CLICK:
1517        case MBE_OFF:
1518            priv->button_delay_millis = now;
1519            if (hw->left) {
1520                priv->mid_emu_state = MBE_LEFT;
1521            }
1522            else if (hw->right) {
1523                priv->mid_emu_state = MBE_RIGHT;
1524            }
1525            else {
1526                done = TRUE;
1527            }
1528            break;
1529        case MBE_LEFT:
1530            timeleft =
1531                TIME_DIFF(priv->button_delay_millis +
1532                          para->emulate_mid_button_time, now);
1533            if (timeleft > 0)
1534                *delay = MIN(*delay, timeleft);
1535
1536            /* timeout, but within the same ReadInput cycle! */
1537            if ((timeleft <= 0) && !hw->left) {
1538                priv->mid_emu_state = MBE_LEFT_CLICK;
1539                done = TRUE;
1540            }
1541            else if ((!hw->left) || (timeleft <= 0)) {
1542                hw->left = TRUE;
1543                priv->mid_emu_state = MBE_TIMEOUT;
1544                done = TRUE;
1545            }
1546            else if (hw->right) {
1547                priv->mid_emu_state = MBE_MID;
1548            }
1549            else {
1550                hw->left = FALSE;
1551                done = TRUE;
1552            }
1553            break;
1554        case MBE_RIGHT:
1555            timeleft =
1556                TIME_DIFF(priv->button_delay_millis +
1557                          para->emulate_mid_button_time, now);
1558            if (timeleft > 0)
1559                *delay = MIN(*delay, timeleft);
1560
1561            /* timeout, but within the same ReadInput cycle! */
1562            if ((timeleft <= 0) && !hw->right) {
1563                priv->mid_emu_state = MBE_RIGHT_CLICK;
1564                done = TRUE;
1565            }
1566            else if (!hw->right || (timeleft <= 0)) {
1567                hw->right = TRUE;
1568                priv->mid_emu_state = MBE_TIMEOUT;
1569                done = TRUE;
1570            }
1571            else if (hw->left) {
1572                priv->mid_emu_state = MBE_MID;
1573            }
1574            else {
1575                hw->right = FALSE;
1576                done = TRUE;
1577            }
1578            break;
1579        case MBE_MID:
1580            if (!hw->left && !hw->right) {
1581                priv->mid_emu_state = MBE_OFF;
1582            }
1583            else {
1584                mid = TRUE;
1585                hw->left = hw->right = FALSE;
1586                done = TRUE;
1587            }
1588            break;
1589        case MBE_TIMEOUT:
1590            if (!hw->left && !hw->right) {
1591                priv->mid_emu_state = MBE_OFF;
1592            }
1593            else {
1594                done = TRUE;
1595            }
1596        }
1597    }
1598    return mid;
1599}
1600
1601static enum FingerState
1602SynapticsDetectFinger(SynapticsPrivate * priv, struct SynapticsHwState *hw)
1603{
1604    SynapticsParameters *para = &priv->synpara;
1605    enum FingerState finger;
1606
1607    /* finger detection thru pressure and threshold */
1608    if (hw->z < para->finger_low)
1609        return FS_UNTOUCHED;
1610
1611    if (priv->finger_state == FS_BLOCKED)
1612        return FS_BLOCKED;
1613
1614    if (hw->z > para->finger_high && priv->finger_state == FS_UNTOUCHED)
1615        finger = FS_TOUCHED;
1616    else
1617        finger = priv->finger_state;
1618
1619    if (!para->palm_detect)
1620        return finger;
1621
1622    /* palm detection */
1623
1624    if ((hw->z > para->palm_min_z) && (hw->fingerWidth > para->palm_min_width))
1625        return FS_BLOCKED;
1626
1627    if (hw->x == 0 || priv->finger_state == FS_UNTOUCHED)
1628        priv->avg_width = 0;
1629    else
1630        priv->avg_width += (hw->fingerWidth - priv->avg_width + 1) / 2;
1631
1632    if (finger != FS_UNTOUCHED && priv->finger_state == FS_UNTOUCHED) {
1633        int safe_width = MAX(hw->fingerWidth, priv->avg_width);
1634
1635        if (hw->numFingers > 1 ||       /* more than one finger -> not a palm */
1636            ((safe_width < 6) && (priv->prev_z < para->finger_high)) || /* thin finger, distinct touch -> not a palm */
1637            ((safe_width < 7) && (priv->prev_z < para->finger_high / 2))) {     /* thin finger, distinct touch -> not a palm */
1638            /* leave finger value as is */
1639        }
1640        else if (hw->z > priv->prev_z + 1)      /* z not stable, may be a palm */
1641            finger = FS_UNTOUCHED;
1642        else if (hw->z < priv->prev_z - 5)      /* z not stable, may be a palm */
1643            finger = FS_UNTOUCHED;
1644        else if (hw->fingerWidth > para->palm_min_width)        /* finger width too large -> probably palm */
1645            finger = FS_UNTOUCHED;
1646    }
1647    priv->prev_z = hw->z;
1648
1649    return finger;
1650}
1651
1652static void
1653SelectTapButton(SynapticsPrivate * priv, enum EdgeType edge)
1654{
1655    enum TapEvent tap;
1656
1657    if (priv->synpara.touchpad_off == TOUCHPAD_TAP_OFF) {
1658        priv->tap_button = 0;
1659        return;
1660    }
1661
1662    switch (priv->tap_max_fingers) {
1663    case 1:
1664        switch (edge) {
1665        case RIGHT_TOP_EDGE:
1666            DBG(7, "right top edge\n");
1667            tap = RT_TAP;
1668            break;
1669        case RIGHT_BOTTOM_EDGE:
1670            DBG(7, "right bottom edge\n");
1671            tap = RB_TAP;
1672            break;
1673        case LEFT_TOP_EDGE:
1674            DBG(7, "left top edge\n");
1675            tap = LT_TAP;
1676            break;
1677        case LEFT_BOTTOM_EDGE:
1678            DBG(7, "left bottom edge\n");
1679            tap = LB_TAP;
1680            break;
1681        default:
1682            DBG(7, "no edge\n");
1683            tap = F1_TAP;
1684            break;
1685        }
1686        break;
1687    case 2:
1688        DBG(7, "two finger tap\n");
1689        tap = F2_TAP;
1690        break;
1691    case 3:
1692        DBG(7, "three finger tap\n");
1693        tap = F3_TAP;
1694        break;
1695    default:
1696        priv->tap_button = 0;
1697        return;
1698    }
1699
1700    priv->tap_button = priv->synpara.tap_action[tap];
1701    priv->tap_button = clamp(priv->tap_button, 0, SYN_MAX_BUTTONS);
1702}
1703
1704static void
1705SetTapState(SynapticsPrivate * priv, enum TapState tap_state, CARD32 millis)
1706{
1707    DBG(3, "SetTapState - %d -> %d (millis:%u)\n", priv->tap_state, tap_state,
1708        millis);
1709    switch (tap_state) {
1710    case TS_START:
1711        priv->tap_button_state = TBS_BUTTON_UP;
1712        priv->tap_max_fingers = 0;
1713        break;
1714    case TS_1:
1715        priv->tap_button_state = TBS_BUTTON_UP;
1716        break;
1717    case TS_2A:
1718	priv->tap_button_state = TBS_BUTTON_UP;
1719        break;
1720    case TS_2B:
1721        priv->tap_button_state = TBS_BUTTON_UP;
1722        break;
1723    case TS_3:
1724        priv->tap_button_state = TBS_BUTTON_DOWN;
1725        break;
1726    case TS_SINGLETAP:
1727	priv->tap_button_state = TBS_BUTTON_DOWN;
1728        priv->touch_on.millis = millis;
1729        break;
1730    default:
1731        break;
1732    }
1733    priv->tap_state = tap_state;
1734}
1735
1736static void
1737SetMovingState(SynapticsPrivate * priv, enum MovingState moving_state,
1738               CARD32 millis)
1739{
1740    DBG(7, "SetMovingState - %d -> %d center at %d/%d (millis:%u)\n",
1741        priv->moving_state, moving_state, priv->hwState->x, priv->hwState->y,
1742        millis);
1743
1744    priv->moving_state = moving_state;
1745}
1746
1747static int
1748GetTimeOut(SynapticsPrivate * priv)
1749{
1750    SynapticsParameters *para = &priv->synpara;
1751
1752    switch (priv->tap_state) {
1753    case TS_1:
1754    case TS_3:
1755    case TS_5:
1756        return para->tap_time;
1757    case TS_SINGLETAP:
1758        return para->click_time;
1759    case TS_2A:
1760        return para->single_tap_timeout;
1761    case TS_2B:
1762        return para->tap_time_2;
1763    case TS_4:
1764        return para->locked_drag_time;
1765    default:
1766        return -1;              /* No timeout */
1767    }
1768}
1769
1770static int
1771HandleTapProcessing(SynapticsPrivate * priv, struct SynapticsHwState *hw,
1772                    CARD32 now, enum FingerState finger,
1773                    Bool inside_active_area)
1774{
1775    SynapticsParameters *para = &priv->synpara;
1776    Bool touch, release, is_timeout, move, press;
1777    int timeleft, timeout;
1778    enum EdgeType edge;
1779    int delay = 1000000000;
1780
1781    if (priv->finger_state == FS_BLOCKED)
1782        return delay;
1783
1784    touch = finger >= FS_TOUCHED && priv->finger_state == FS_UNTOUCHED;
1785    release = finger == FS_UNTOUCHED && priv->finger_state >= FS_TOUCHED;
1786    move = (finger >= FS_TOUCHED &&
1787            (priv->tap_max_fingers <=
1788             ((priv->horiz_scroll_twofinger_on ||
1789               priv->vert_scroll_twofinger_on) ? 2 : 1)) &&
1790            ((abs(hw->x - priv->touch_on.x) >= para->tap_move) ||
1791             (abs(hw->y - priv->touch_on.y) >= para->tap_move)));
1792    press = (hw->left || hw->right || hw->middle);
1793
1794    if (touch) {
1795        priv->touch_on.x = hw->x;
1796        priv->touch_on.y = hw->y;
1797        priv->touch_on.millis = now;
1798    }
1799    else if (release) {
1800        priv->touch_on.millis = now;
1801    }
1802    if (hw->z > para->finger_high)
1803        if (priv->tap_max_fingers < hw->numFingers)
1804            priv->tap_max_fingers = hw->numFingers;
1805    timeout = GetTimeOut(priv);
1806    timeleft = TIME_DIFF(priv->touch_on.millis + timeout, now);
1807    is_timeout = timeleft <= 0;
1808
1809 restart:
1810    switch (priv->tap_state) {
1811    case TS_START:
1812        if (touch)
1813            SetTapState(priv, TS_1, now);
1814        break;
1815    case TS_1:
1816        if (para->clickpad && press) {
1817            SetTapState(priv, TS_CLICKPAD_MOVE, now);
1818            goto restart;
1819        }
1820        if (move) {
1821            SetMovingState(priv, MS_TOUCHPAD_RELATIVE, now);
1822            SetTapState(priv, TS_MOVE, now);
1823            goto restart;
1824        }
1825        else if (is_timeout) {
1826            if (finger == FS_TOUCHED) {
1827                SetMovingState(priv, MS_TOUCHPAD_RELATIVE, now);
1828            }
1829            SetTapState(priv, TS_MOVE, now);
1830            goto restart;
1831        }
1832        else if (release) {
1833            edge = edge_detection(priv, priv->touch_on.x, priv->touch_on.y);
1834            SelectTapButton(priv, edge);
1835            /* Disable taps outside of the active area */
1836            if (!inside_active_area) {
1837                priv->tap_button = 0;
1838            }
1839            SetTapState(priv, TS_2A, now);
1840        }
1841        break;
1842    case TS_MOVE:
1843        if (para->clickpad && press) {
1844            SetTapState(priv, TS_CLICKPAD_MOVE, now);
1845            goto restart;
1846        }
1847        if (release) {
1848            SetMovingState(priv, MS_FALSE, now);
1849            SetTapState(priv, TS_START, now);
1850        }
1851        break;
1852    case TS_2A:
1853        if (touch)
1854            SetTapState(priv, TS_3, now);
1855        else if (is_timeout)
1856            SetTapState(priv, TS_SINGLETAP, now);
1857        break;
1858    case TS_2B:
1859        if (touch) {
1860            SetTapState(priv, TS_3, now);
1861        }
1862        else if (is_timeout) {
1863            SetTapState(priv, TS_START, now);
1864            priv->tap_button_state = TBS_BUTTON_DOWN_UP;
1865        }
1866        break;
1867    case TS_SINGLETAP:
1868        if (touch)
1869            SetTapState(priv, TS_1, now);
1870        else if (is_timeout)
1871            SetTapState(priv, TS_START, now);
1872        break;
1873    case TS_3:
1874        if (move) {
1875            if (para->tap_and_drag_gesture) {
1876                SetMovingState(priv, MS_TOUCHPAD_RELATIVE, now);
1877                SetTapState(priv, TS_DRAG, now);
1878            }
1879            else {
1880                SetTapState(priv, TS_1, now);
1881            }
1882            goto restart;
1883        }
1884        else if (is_timeout) {
1885            if (para->tap_and_drag_gesture) {
1886                if (finger == FS_TOUCHED) {
1887                    SetMovingState(priv, MS_TOUCHPAD_RELATIVE, now);
1888                }
1889                SetTapState(priv, TS_DRAG, now);
1890            }
1891            else {
1892                SetTapState(priv, TS_1, now);
1893            }
1894            goto restart;
1895        }
1896        else if (release) {
1897            SetTapState(priv, TS_2B, now);
1898        }
1899        break;
1900    case TS_DRAG:
1901        if (para->clickpad && press) {
1902            SetTapState(priv, TS_CLICKPAD_MOVE, now);
1903            goto restart;
1904        }
1905        if (move)
1906            SetMovingState(priv, MS_TOUCHPAD_RELATIVE, now);
1907        if (release) {
1908            SetMovingState(priv, MS_FALSE, now);
1909            if (para->locked_drags) {
1910                SetTapState(priv, TS_4, now);
1911            }
1912            else {
1913                SetTapState(priv, TS_START, now);
1914            }
1915        }
1916        break;
1917    case TS_4:
1918        if (is_timeout) {
1919            SetTapState(priv, TS_START, now);
1920            goto restart;
1921        }
1922        if (touch)
1923            SetTapState(priv, TS_5, now);
1924        break;
1925    case TS_5:
1926        if (is_timeout || move) {
1927            SetTapState(priv, TS_DRAG, now);
1928            goto restart;
1929        }
1930        else if (release) {
1931            SetMovingState(priv, MS_FALSE, now);
1932            SetTapState(priv, TS_START, now);
1933        }
1934        break;
1935    case TS_CLICKPAD_MOVE:
1936        /* Disable scrolling once a button is pressed on a clickpad */
1937        priv->vert_scroll_edge_on = FALSE;
1938        priv->horiz_scroll_edge_on = FALSE;
1939        priv->vert_scroll_twofinger_on = FALSE;
1940        priv->horiz_scroll_twofinger_on = FALSE;
1941
1942        /* Assume one touch is only for holding the clickpad button down */
1943        if (hw->numFingers > 1)
1944            hw->numFingers--;
1945        SetMovingState(priv, MS_TOUCHPAD_RELATIVE, now);
1946        if (!press) {
1947            SetMovingState(priv, MS_FALSE, now);
1948            SetTapState(priv, TS_MOVE, now);
1949            priv->count_packet_finger = 0;
1950        }
1951        break;
1952    }
1953
1954    timeout = GetTimeOut(priv);
1955    if (timeout >= 0) {
1956        timeleft = TIME_DIFF(priv->touch_on.millis + timeout, now);
1957        delay = clamp(timeleft, 1, delay);
1958    }
1959    return delay;
1960}
1961
1962#define HIST(a) (priv->move_hist[((priv->hist_index - (a) + SYNAPTICS_MOVE_HISTORY) % SYNAPTICS_MOVE_HISTORY)])
1963#define HIST_DELTA(a, b, e) ((HIST((a)).e) - (HIST((b)).e))
1964
1965static void
1966store_history(SynapticsPrivate * priv, int x, int y, CARD32 millis)
1967{
1968    int idx = (priv->hist_index + 1) % SYNAPTICS_MOVE_HISTORY;
1969
1970    priv->move_hist[idx].x = x;
1971    priv->move_hist[idx].y = y;
1972    priv->move_hist[idx].millis = millis;
1973    priv->hist_index = idx;
1974    if (priv->count_packet_finger < SYNAPTICS_MOVE_HISTORY)
1975        priv->count_packet_finger++;
1976}
1977
1978/*
1979 * Estimate the slope for the data sequence [x3, x2, x1, x0] by using
1980 * linear regression to fit a line to the data and use the slope of the
1981 * line.
1982 */
1983static double
1984estimate_delta(double x0, double x1, double x2, double x3)
1985{
1986    return x0 * 0.3 + x1 * 0.1 - x2 * 0.1 - x3 * 0.3;
1987}
1988
1989/**
1990 * Applies hysteresis. center is shifted such that it is in range with
1991 * in by the margin again. The new center is returned.
1992 * @param in the current value
1993 * @param center the current center
1994 * @param margin the margin to center in which no change is applied
1995 * @return the new center (which might coincide with the previous)
1996 */
1997static int
1998hysteresis(int in, int center, int margin)
1999{
2000    int diff = in - center;
2001
2002    if (abs(diff) <= margin) {
2003        diff = 0;
2004    }
2005    else if (diff > margin) {
2006        diff -= margin;
2007    }
2008    else if (diff < -margin) {
2009        diff += margin;
2010    }
2011    return center + diff;
2012}
2013
2014static void
2015get_delta(SynapticsPrivate *priv, const struct SynapticsHwState *hw,
2016          enum EdgeType edge, double *dx, double *dy)
2017{
2018    double dtime = (hw->millis - HIST(0).millis) / 1000.0;
2019    double integral;
2020    double tmpf;
2021    int x_edge_speed = 0;
2022    int y_edge_speed = 0;
2023
2024    *dx = hw->x - HIST(0).x;
2025    *dy = hw->y - HIST(0).y;
2026
2027    /* report edge speed as synthetic motion. Of course, it would be
2028     * cooler to report floats than to buffer, but anyway. */
2029
2030    /* FIXME: When these values go NaN, bad things happen. Root cause is unknown
2031     * thus far though. */
2032    if (isnan(priv->frac_x))
2033        priv->frac_x = 0;
2034    if (isnan(priv->frac_y))
2035        priv->frac_y = 0;
2036
2037    tmpf = *dx + x_edge_speed * dtime + priv->frac_x;
2038    priv->frac_x = modf(tmpf, &integral);
2039    *dx = integral;
2040    tmpf = *dy + y_edge_speed * dtime + priv->frac_y;
2041    priv->frac_y = modf(tmpf, &integral);
2042    *dy = integral;
2043}
2044
2045/**
2046 * Compute relative motion ('deltas') including edge motion.
2047 */
2048static int
2049ComputeDeltas(SynapticsPrivate * priv, const struct SynapticsHwState *hw,
2050              enum EdgeType edge, int *dxP, int *dyP, Bool inside_area)
2051{
2052    enum MovingState moving_state;
2053    double dx, dy;
2054    int delay = 1000000000;
2055
2056    dx = dy = 0;
2057
2058    moving_state = priv->moving_state;
2059    if (moving_state == MS_FALSE) {
2060        switch (priv->tap_state) {
2061        case TS_MOVE:
2062        case TS_DRAG:
2063            moving_state = MS_TOUCHPAD_RELATIVE;
2064            break;
2065        case TS_1:
2066        case TS_3:
2067        case TS_5:
2068            moving_state = MS_TOUCHPAD_RELATIVE;
2069            break;
2070        default:
2071            break;
2072        }
2073    }
2074
2075    if (!inside_area || !moving_state || priv->finger_state == FS_BLOCKED ||
2076        priv->vert_scroll_edge_on || priv->horiz_scroll_edge_on ||
2077        priv->vert_scroll_twofinger_on || priv->horiz_scroll_twofinger_on ||
2078        priv->circ_scroll_on || priv->prevFingers != hw->numFingers ||
2079        (moving_state == MS_TOUCHPAD_RELATIVE && hw->numFingers != 1)) {
2080        /* reset packet counter. */
2081        priv->count_packet_finger = 0;
2082        goto out;
2083    }
2084
2085    /* To create the illusion of fluid motion, call back at roughly the report
2086     * rate, even in the absence of new hardware events; see comment above
2087     * POLL_MS declaration. */
2088    delay = MIN(delay, POLL_MS);
2089
2090    if (priv->count_packet_finger <= 1)
2091        goto out;               /* skip the lot */
2092
2093    if (moving_state == MS_TOUCHPAD_RELATIVE)
2094        get_delta(priv, hw, edge, &dx, &dy);
2095
2096 out:
2097    priv->prevFingers = hw->numFingers;
2098
2099    *dxP = dx;
2100    *dyP = dy;
2101
2102    return delay;
2103}
2104
2105static double
2106estimate_delta_circ(SynapticsPrivate * priv)
2107{
2108    double a1 = angle(priv, HIST(3).x, HIST(3).y);
2109    double a2 = angle(priv, HIST(2).x, HIST(2).y);
2110    double a3 = angle(priv, HIST(1).x, HIST(1).y);
2111    double a4 = angle(priv, HIST(0).x, HIST(0).y);
2112    double d1 = diffa(a2, a1);
2113    double d2 = d1 + diffa(a3, a2);
2114    double d3 = d2 + diffa(a4, a3);
2115
2116    return estimate_delta(d3, d2, d1, 0);
2117}
2118
2119/* vert and horiz are to know which direction to start coasting
2120 * circ is true if the user had been circular scrolling.
2121 */
2122static void
2123start_coasting(SynapticsPrivate * priv, struct SynapticsHwState *hw,
2124               Bool vert, Bool horiz, Bool circ)
2125{
2126    SynapticsParameters *para = &priv->synpara;
2127
2128    priv->scroll.coast_delta_y = 0.0;
2129    priv->scroll.coast_delta_x = 0.0;
2130
2131    if ((priv->scroll.packets_this_scroll > 3) && (para->coasting_speed > 0.0)) {
2132        double pkt_time = HIST_DELTA(0, 3, millis) / 1000.0;
2133
2134        if (vert && !circ) {
2135            double dy =
2136                estimate_delta(HIST(0).y, HIST(1).y, HIST(2).y, HIST(3).y);
2137            if (pkt_time > 0) {
2138                double scrolls_per_sec = (dy / abs(para->scroll_dist_vert)) / pkt_time;
2139
2140                if (fabs(scrolls_per_sec) >= para->coasting_speed) {
2141                    priv->scroll.coast_speed_y = scrolls_per_sec;
2142                    priv->scroll.coast_delta_y = (hw->y - priv->scroll.last_y);
2143                }
2144            }
2145        }
2146        if (horiz && !circ) {
2147            double dx =
2148                estimate_delta(HIST(0).x, HIST(1).x, HIST(2).x, HIST(3).x);
2149            if (pkt_time > 0) {
2150                double scrolls_per_sec = (dx / abs(para->scroll_dist_vert)) / pkt_time;
2151
2152                if (fabs(scrolls_per_sec) >= para->coasting_speed) {
2153                    priv->scroll.coast_speed_x = scrolls_per_sec;
2154                    priv->scroll.coast_delta_x = (hw->x - priv->scroll.last_x);
2155                }
2156            }
2157        }
2158        if (circ) {
2159            double da = estimate_delta_circ(priv);
2160
2161            if (pkt_time > 0) {
2162                double scrolls_per_sec = (da / para->scroll_dist_circ) / pkt_time;
2163
2164                if (fabs(scrolls_per_sec) >= para->coasting_speed) {
2165                    if (vert) {
2166                        priv->scroll.coast_speed_y = scrolls_per_sec;
2167                        priv->scroll.coast_delta_y =
2168                            diffa(priv->scroll.last_a,
2169                                  angle(priv, hw->x, hw->y));
2170                    }
2171                    else if (horiz) {
2172                        priv->scroll.coast_speed_x = scrolls_per_sec;
2173                        priv->scroll.coast_delta_x =
2174                            diffa(priv->scroll.last_a,
2175                                  angle(priv, hw->x, hw->y));
2176                    }
2177                }
2178            }
2179        }
2180    }
2181    priv->scroll.packets_this_scroll = 0;
2182}
2183
2184static void
2185stop_coasting(SynapticsPrivate * priv)
2186{
2187    priv->scroll.coast_speed_x = 0;
2188    priv->scroll.coast_speed_y = 0;
2189    priv->scroll.packets_this_scroll = 0;
2190}
2191
2192static int
2193HandleScrolling(SynapticsPrivate * priv, struct SynapticsHwState *hw,
2194                enum EdgeType edge, Bool finger)
2195{
2196    SynapticsParameters *para = &priv->synpara;
2197    int delay = 1000000000;
2198
2199    if ((priv->synpara.touchpad_off == TOUCHPAD_TAP_OFF) || (priv->finger_state == FS_BLOCKED)) {
2200        stop_coasting(priv);
2201        priv->circ_scroll_on = FALSE;
2202        priv->vert_scroll_edge_on = FALSE;
2203        priv->horiz_scroll_edge_on = FALSE;
2204        priv->vert_scroll_twofinger_on = FALSE;
2205        priv->horiz_scroll_twofinger_on = FALSE;
2206        return delay;
2207    }
2208
2209    /* scroll detection */
2210    if (finger && priv->finger_state == FS_UNTOUCHED) {
2211        stop_coasting(priv);
2212        priv->scroll.delta_y = 0;
2213        priv->scroll.delta_x = 0;
2214        if (para->circular_scrolling) {
2215            if ((para->circular_trigger == 0 && edge) ||
2216                (para->circular_trigger == 1 && edge & TOP_EDGE) ||
2217                (para->circular_trigger == 2 && edge & TOP_EDGE &&
2218                 edge & RIGHT_EDGE) || (para->circular_trigger == 3 &&
2219                                        edge & RIGHT_EDGE) ||
2220                (para->circular_trigger == 4 && edge & RIGHT_EDGE &&
2221                 edge & BOTTOM_EDGE) || (para->circular_trigger == 5 &&
2222                                         edge & BOTTOM_EDGE) ||
2223                (para->circular_trigger == 6 && edge & BOTTOM_EDGE &&
2224                 edge & LEFT_EDGE) || (para->circular_trigger == 7 &&
2225                                       edge & LEFT_EDGE) ||
2226                (para->circular_trigger == 8 && edge & LEFT_EDGE &&
2227                 edge & TOP_EDGE)) {
2228                priv->circ_scroll_on = TRUE;
2229                priv->circ_scroll_vert = TRUE;
2230                priv->scroll.last_a = angle(priv, hw->x, hw->y);
2231                DBG(7, "circular scroll detected on edge\n");
2232            }
2233        }
2234    }
2235    if (!priv->circ_scroll_on) {
2236        if (finger) {
2237            if (hw->numFingers == 2) {
2238                if (!priv->vert_scroll_twofinger_on &&
2239                    (para->scroll_twofinger_vert) &&
2240                    (para->scroll_dist_vert != 0)) {
2241                    stop_coasting(priv);
2242                    priv->vert_scroll_twofinger_on = TRUE;
2243                    priv->vert_scroll_edge_on = FALSE;
2244                    priv->scroll.last_y = hw->y;
2245                    DBG(7, "vert two-finger scroll detected\n");
2246                }
2247                if (!priv->horiz_scroll_twofinger_on &&
2248                    (para->scroll_twofinger_horiz) &&
2249                    (para->scroll_dist_horiz != 0)) {
2250                    stop_coasting(priv);
2251                    priv->horiz_scroll_twofinger_on = TRUE;
2252                    priv->horiz_scroll_edge_on = FALSE;
2253                    priv->scroll.last_x = hw->x;
2254                    DBG(7, "horiz two-finger scroll detected\n");
2255                }
2256            }
2257        }
2258        if (finger && priv->finger_state == FS_UNTOUCHED) {
2259            if (!priv->vert_scroll_twofinger_on &&
2260                !priv->horiz_scroll_twofinger_on) {
2261                if ((para->scroll_edge_vert) && (para->scroll_dist_vert != 0) &&
2262                    (edge & RIGHT_EDGE)) {
2263                    priv->vert_scroll_edge_on = TRUE;
2264                    priv->scroll.last_y = hw->y;
2265                    DBG(7, "vert edge scroll detected on right edge\n");
2266                }
2267                if ((para->scroll_edge_horiz) && (para->scroll_dist_horiz != 0)
2268                    && (edge & BOTTOM_EDGE)) {
2269                    priv->horiz_scroll_edge_on = TRUE;
2270                    priv->scroll.last_x = hw->x;
2271                    DBG(7, "horiz edge scroll detected on bottom edge\n");
2272                }
2273            }
2274        }
2275    }
2276    {
2277        Bool oldv = priv->vert_scroll_twofinger_on || priv->vert_scroll_edge_on
2278            || (priv->circ_scroll_on && priv->circ_scroll_vert);
2279
2280        Bool oldh = priv->horiz_scroll_twofinger_on ||
2281            priv->horiz_scroll_edge_on || (priv->circ_scroll_on &&
2282                                           !priv->circ_scroll_vert);
2283
2284        Bool oldc = priv->circ_scroll_on;
2285
2286        if (priv->circ_scroll_on && !finger) {
2287            /* circular scroll locks in until finger is raised */
2288            DBG(7, "cicular scroll off\n");
2289            priv->circ_scroll_on = FALSE;
2290        }
2291
2292        if (!finger || hw->numFingers != 2) {
2293            if (priv->vert_scroll_twofinger_on) {
2294                DBG(7, "vert two-finger scroll off\n");
2295                priv->vert_scroll_twofinger_on = FALSE;
2296            }
2297            if (priv->horiz_scroll_twofinger_on) {
2298                DBG(7, "horiz two-finger scroll off\n");
2299                priv->horiz_scroll_twofinger_on = FALSE;
2300            }
2301        }
2302
2303        if (priv->vert_scroll_edge_on && (!(edge & RIGHT_EDGE) || !finger)) {
2304            DBG(7, "vert edge scroll off\n");
2305            priv->vert_scroll_edge_on = FALSE;
2306        }
2307        if (priv->horiz_scroll_edge_on && (!(edge & BOTTOM_EDGE) || !finger)) {
2308            DBG(7, "horiz edge scroll off\n");
2309            priv->horiz_scroll_edge_on = FALSE;
2310        }
2311        /* If we were corner edge scrolling (coasting),
2312         * but no longer in corner or raised a finger, then stop coasting. */
2313        if (para->scroll_edge_corner &&
2314            (priv->scroll.coast_speed_x || priv->scroll.coast_speed_y)) {
2315            Bool is_in_corner = ((edge & RIGHT_EDGE) &&
2316                                 (edge & (TOP_EDGE | BOTTOM_EDGE))) ||
2317                ((edge & BOTTOM_EDGE) && (edge & (LEFT_EDGE | RIGHT_EDGE)));
2318            if (!is_in_corner || !finger) {
2319                DBG(7, "corner edge scroll off\n");
2320                stop_coasting(priv);
2321            }
2322        }
2323        /* if we were scrolling, but couldn't corner edge scroll,
2324         * and are no longer scrolling, then start coasting */
2325        oldv = oldv && !(priv->vert_scroll_twofinger_on ||
2326                         priv->vert_scroll_edge_on || (priv->circ_scroll_on &&
2327                                                       priv->circ_scroll_vert));
2328
2329        oldh = oldh && !(priv->horiz_scroll_twofinger_on ||
2330                         priv->horiz_scroll_edge_on || (priv->circ_scroll_on &&
2331                                                        !priv->
2332                                                        circ_scroll_vert));
2333
2334        oldc = oldc && !priv->circ_scroll_on;
2335
2336        if ((oldv || oldh) && !para->scroll_edge_corner) {
2337            start_coasting(priv, hw, oldv, oldh, oldc);
2338        }
2339    }
2340
2341    /* if hitting a corner (top right or bottom right) while vertical
2342     * scrolling is active, consider starting corner edge scrolling or
2343     * switching over to circular scrolling smoothly */
2344    if (priv->vert_scroll_edge_on && !priv->horiz_scroll_edge_on &&
2345        (edge & RIGHT_EDGE) && (edge & (TOP_EDGE | BOTTOM_EDGE))) {
2346        if (para->scroll_edge_corner) {
2347            if (priv->scroll.coast_speed_y == 0) {
2348                /* FYI: We can generate multiple start_coasting requests if
2349                 * we're in the corner, but we were moving so slowly when we
2350                 * got here that we didn't actually start coasting. */
2351                DBG(7, "corner edge scroll on\n");
2352                start_coasting(priv, hw, TRUE, FALSE, FALSE);
2353            }
2354        }
2355        else if (para->circular_scrolling) {
2356            priv->vert_scroll_edge_on = FALSE;
2357            priv->circ_scroll_on = TRUE;
2358            priv->circ_scroll_vert = TRUE;
2359            priv->scroll.last_a = angle(priv, hw->x, hw->y);
2360            DBG(7, "switching to circular scrolling\n");
2361        }
2362    }
2363    /* Same treatment for horizontal scrolling */
2364    if (priv->horiz_scroll_edge_on && !priv->vert_scroll_edge_on &&
2365        (edge & BOTTOM_EDGE) && (edge & (LEFT_EDGE | RIGHT_EDGE))) {
2366        if (para->scroll_edge_corner) {
2367            if (priv->scroll.coast_speed_x == 0) {
2368                /* FYI: We can generate multiple start_coasting requests if
2369                 * we're in the corner, but we were moving so slowly when we
2370                 * got here that we didn't actually start coasting. */
2371                DBG(7, "corner edge scroll on\n");
2372                start_coasting(priv, hw, FALSE, TRUE, FALSE);
2373            }
2374        }
2375        else if (para->circular_scrolling) {
2376            priv->horiz_scroll_edge_on = FALSE;
2377            priv->circ_scroll_on = TRUE;
2378            priv->circ_scroll_vert = FALSE;
2379            priv->scroll.last_a = angle(priv, hw->x, hw->y);
2380            DBG(7, "switching to circular scrolling\n");
2381        }
2382    }
2383
2384    if (priv->vert_scroll_edge_on || priv->horiz_scroll_edge_on ||
2385        priv->vert_scroll_twofinger_on || priv->horiz_scroll_twofinger_on ||
2386        priv->circ_scroll_on) {
2387        priv->scroll.packets_this_scroll++;
2388    }
2389
2390    if (priv->vert_scroll_edge_on || priv->vert_scroll_twofinger_on) {
2391        /* + = down, - = up */
2392        if (para->scroll_dist_vert != 0 && hw->y != priv->scroll.last_y) {
2393            priv->scroll.delta_y += (hw->y - priv->scroll.last_y);
2394            priv->scroll.last_y = hw->y;
2395        }
2396    }
2397    if (priv->horiz_scroll_edge_on || priv->horiz_scroll_twofinger_on) {
2398        /* + = right, - = left */
2399        if (para->scroll_dist_horiz != 0 && hw->x != priv->scroll.last_x) {
2400            priv->scroll.delta_x += (hw->x - priv->scroll.last_x);
2401            priv->scroll.last_x = hw->x;
2402        }
2403    }
2404    if (priv->circ_scroll_on) {
2405        /* + = counter clockwise, - = clockwise */
2406        double delta = para->scroll_dist_circ;
2407        double diff = diffa(priv->scroll.last_a, angle(priv, hw->x, hw->y));
2408
2409        if (delta >= 0.005 && diff != 0.0) {
2410            if (priv->circ_scroll_vert)
2411                priv->scroll.delta_y -= diff / delta * para->scroll_dist_vert;
2412            else
2413                priv->scroll.delta_x -= diff / delta * para->scroll_dist_horiz;
2414            priv->scroll.last_a = angle(priv, hw->x, hw->y);
2415        }
2416    }
2417
2418    if (priv->scroll.coast_speed_y) {
2419        double dtime = (hw->millis - priv->scroll.last_millis) / 1000.0;
2420        double ddy = para->coasting_friction * dtime;
2421
2422        priv->scroll.delta_y += priv->scroll.coast_speed_y * dtime * abs(para->scroll_dist_vert);
2423        delay = MIN(delay, POLL_MS);
2424        if (abs(priv->scroll.coast_speed_y) < ddy) {
2425            priv->scroll.coast_speed_y = 0;
2426            priv->scroll.packets_this_scroll = 0;
2427        }
2428        else {
2429            priv->scroll.coast_speed_y +=
2430                (priv->scroll.coast_speed_y < 0 ? ddy : -ddy);
2431        }
2432    }
2433
2434    if (priv->scroll.coast_speed_x) {
2435        double dtime = (hw->millis - priv->scroll.last_millis) / 1000.0;
2436        double ddx = para->coasting_friction * dtime;
2437        priv->scroll.delta_x += priv->scroll.coast_speed_x * dtime * abs(para->scroll_dist_horiz);
2438        delay = MIN(delay, POLL_MS);
2439        if (abs(priv->scroll.coast_speed_x) < ddx) {
2440            priv->scroll.coast_speed_x = 0;
2441            priv->scroll.packets_this_scroll = 0;
2442        }
2443        else {
2444            priv->scroll.coast_speed_x +=
2445                (priv->scroll.coast_speed_x < 0 ? ddx : -ddx);
2446        }
2447    }
2448
2449    return delay;
2450}
2451
2452/**
2453 * Check if any 2+ fingers are close enough together to assume this is a
2454 * ClickFinger action.
2455 */
2456static int
2457clickpad_guess_clickfingers(SynapticsPrivate * priv,
2458                            struct SynapticsHwState *hw)
2459{
2460    int nfingers = 0;
2461    uint32_t close_point = 0; /* 1 bit for each point close to another one */
2462    int i, j;
2463
2464    BUG_RETURN_VAL(hw->num_mt_mask > sizeof(close_point) * 8, 0);
2465
2466    for (i = 0; i < hw->num_mt_mask - 1; i++) {
2467        ValuatorMask *f1;
2468
2469        if (hw->slot_state[i] == SLOTSTATE_EMPTY ||
2470            hw->slot_state[i] == SLOTSTATE_CLOSE)
2471            continue;
2472
2473        f1 = hw->mt_mask[i];
2474
2475        for (j = i + 1; j < hw->num_mt_mask; j++) {
2476            ValuatorMask *f2;
2477            double x1, x2, y1, y2;
2478
2479            if (hw->slot_state[j] == SLOTSTATE_EMPTY ||
2480                hw->slot_state[j] == SLOTSTATE_CLOSE)
2481                continue;
2482
2483            f2 = hw->mt_mask[j];
2484
2485            x1 = valuator_mask_get_double(f1, 0);
2486            y1 = valuator_mask_get_double(f1, 1);
2487
2488            x2 = valuator_mask_get_double(f2, 0);
2489            y2 = valuator_mask_get_double(f2, 1);
2490
2491            /* FIXME: fingers closer together than 30% of touchpad width, but
2492             * really, this should be dependent on the touchpad size. Also,
2493             * you'll need to find a touchpad that doesn't lie about it's
2494             * size. Good luck. */
2495            if (abs(x1 - x2) < (priv->maxx - priv->minx) * .3 &&
2496                abs(y1 - y2) < (priv->maxy - priv->miny) * .3) {
2497                close_point |= (1 << j);
2498                close_point |= (1 << i);
2499            }
2500        }
2501    }
2502
2503    while (close_point > 0) {
2504        nfingers += close_point & 0x1;
2505        close_point >>= 1;
2506    }
2507
2508    return nfingers;
2509}
2510
2511static void
2512handle_clickfinger(SynapticsPrivate * priv, struct SynapticsHwState *hw)
2513{
2514    SynapticsParameters *para = &priv->synpara;
2515    int action = 0;
2516    int nfingers = hw->numFingers;
2517
2518    /* if this is a clickpad, clickfinger handling is:
2519     * one finger down: no action, this is a normal click
2520     * two fingers down: F2_CLICK
2521     * three fingers down: F3_CLICK
2522     */
2523
2524    if (para->clickpad)
2525        nfingers = clickpad_guess_clickfingers(priv, hw);
2526
2527    switch (nfingers) {
2528    case 1:
2529        action = para->click_action[F1_CLICK1];
2530        break;
2531    case 2:
2532        action = para->click_action[F2_CLICK1];
2533        break;
2534    case 3:
2535        action = para->click_action[F3_CLICK1];
2536        break;
2537    }
2538    switch (action) {
2539    case 1:
2540        hw->left = 1 | BTN_EMULATED_FLAG;
2541        break;
2542    case 2:
2543        hw->left = 0;
2544        hw->middle = 1 | BTN_EMULATED_FLAG;
2545        break;
2546    case 3:
2547        hw->left = 0;
2548        hw->right = 1 | BTN_EMULATED_FLAG;
2549        break;
2550    }
2551}
2552
2553static void
2554update_hw_button_state(const InputInfoPtr pInfo, struct SynapticsHwState *hw,
2555                       struct SynapticsHwState *old, CARD32 now, int *delay)
2556{
2557    SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
2558    SynapticsParameters *para = &priv->synpara;
2559
2560    /* Treat the first two multi buttons as up/down for now. */
2561    hw->up |= hw->multi[0];
2562    hw->down |= hw->multi[1];
2563
2564    /* 3rd button emulation */
2565    hw->middle |= HandleMidButtonEmulation(priv, hw, now, delay);
2566
2567    /* If this is a clickpad and the user clicks in a soft button area, press
2568     * the soft button instead. */
2569    if (para->clickpad) {
2570        /* hw->left is down, but no other buttons were already down */
2571        if (!old->left && !old->right && !old->middle &&
2572            hw->left && !hw->right && !hw->middle) {
2573                if (is_inside_rightbutton_area(para, hw->x, hw->y)) {
2574                    hw->left = 0;
2575                    hw->right = 1;
2576                }
2577                else if (is_inside_middlebutton_area(para, hw->x, hw->y)) {
2578                    hw->left = 0;
2579                    hw->middle = 1;
2580                }
2581        }
2582        else if (hw->left) {
2583            hw->left = old->left;
2584            hw->right = old->right;
2585            hw->middle = old->middle;
2586        }
2587    }
2588
2589    /* Fingers emulate other buttons. ClickFinger can only be
2590       triggered on transition, when left is pressed
2591     */
2592    if (hw->left && !old->left && !old->middle && !old->right &&
2593        hw->numFingers >= 1) {
2594        handle_clickfinger(priv, hw);
2595    }
2596
2597    /* Two finger emulation */
2598    if (hw->numFingers == 1 && hw->z >= para->emulate_twofinger_z &&
2599        hw->fingerWidth >= para->emulate_twofinger_w) {
2600        hw->numFingers = 2;
2601    }
2602}
2603
2604static void
2605post_button_click(const InputInfoPtr pInfo, const int button)
2606{
2607    xf86PostButtonEvent(pInfo->dev, FALSE, button, TRUE, 0, 0);
2608    xf86PostButtonEvent(pInfo->dev, FALSE, button, FALSE, 0, 0);
2609}
2610
2611static void
2612post_scroll_events(const InputInfoPtr pInfo)
2613{
2614    SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
2615
2616    valuator_mask_zero(priv->scroll_events_mask);
2617
2618    if (priv->scroll.delta_y != 0.0) {
2619        valuator_mask_set_double(priv->scroll_events_mask,
2620                                 priv->scroll_axis_vert, priv->scroll.delta_y);
2621        priv->scroll.delta_y = 0;
2622    }
2623    if (priv->scroll.delta_x != 0.0) {
2624        valuator_mask_set_double(priv->scroll_events_mask,
2625                                 priv->scroll_axis_horiz, priv->scroll.delta_x);
2626        priv->scroll.delta_x = 0;
2627    }
2628    if (valuator_mask_num_valuators(priv->scroll_events_mask))
2629        xf86PostMotionEventM(pInfo->dev, FALSE, priv->scroll_events_mask);
2630}
2631
2632/* Update the open slots and number of active touches */
2633static void
2634UpdateTouchState(InputInfoPtr pInfo, struct SynapticsHwState *hw)
2635{
2636    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
2637    int i;
2638
2639    for (i = 0; i < hw->num_mt_mask; i++) {
2640        if (hw->slot_state[i] == SLOTSTATE_OPEN) {
2641            priv->open_slots[priv->num_active_touches] = i;
2642            priv->num_active_touches++;
2643            BUG_WARN(priv->num_active_touches > priv->num_slots);
2644        }
2645        else if (hw->slot_state[i] == SLOTSTATE_CLOSE) {
2646            Bool found = FALSE;
2647            int j;
2648
2649            for (j = 0; j < priv->num_active_touches - 1; j++) {
2650                if (priv->open_slots[j] == i)
2651                    found = TRUE;
2652
2653                if (found)
2654                    priv->open_slots[j] = priv->open_slots[j + 1];
2655            }
2656
2657            BUG_WARN(priv->num_active_touches == 0);
2658            if (priv->num_active_touches > 0)
2659                priv->num_active_touches--;
2660        }
2661    }
2662
2663    SynapticsResetTouchHwState(hw, FALSE);
2664}
2665
2666static void
2667HandleTouches(InputInfoPtr pInfo, struct SynapticsHwState *hw)
2668{
2669    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
2670    SynapticsParameters *para = &priv->synpara;
2671    int new_active_touches = priv->num_active_touches;
2672    int min_touches = 2;
2673    Bool restart_touches = FALSE;
2674    int i;
2675
2676    if (para->click_action[F3_CLICK1] || para->tap_action[F3_TAP])
2677        min_touches = 4;
2678    else if (para->click_action[F2_CLICK1] || para->tap_action[F2_TAP] ||
2679             para->scroll_twofinger_vert || para->scroll_twofinger_horiz)
2680        min_touches = 3;
2681
2682    /* Count new number of active touches */
2683    for (i = 0; i < hw->num_mt_mask; i++) {
2684        if (hw->slot_state[i] == SLOTSTATE_OPEN)
2685            new_active_touches++;
2686        else if (hw->slot_state[i] == SLOTSTATE_CLOSE)
2687            new_active_touches--;
2688    }
2689
2690    if (priv->has_semi_mt)
2691        goto out;
2692
2693    if (priv->num_active_touches < min_touches &&
2694        new_active_touches < min_touches) {
2695        /* We stayed below number of touches needed to send events */
2696        goto out;
2697    }
2698    else if (priv->num_active_touches >= min_touches &&
2699             new_active_touches < min_touches) {
2700        /* We are transitioning to less than the number of touches needed to
2701         * send events. End all currently open touches. */
2702        for (i = 0; i < priv->num_active_touches; i++) {
2703            int slot = priv->open_slots[i];
2704
2705            xf86PostTouchEvent(pInfo->dev, slot, XI_TouchEnd, 0,
2706                               hw->mt_mask[slot]);
2707        }
2708
2709        /* Don't send any more events */
2710        goto out;
2711    }
2712    else if (priv->num_active_touches < min_touches &&
2713             new_active_touches >= min_touches) {
2714        /* We are transitioning to more than the number of touches needed to
2715         * send events. Begin all already open touches. */
2716        restart_touches = TRUE;
2717        for (i = 0; i < priv->num_active_touches; i++) {
2718            int slot = priv->open_slots[i];
2719
2720            xf86PostTouchEvent(pInfo->dev, slot, XI_TouchBegin, 0,
2721                               hw->mt_mask[slot]);
2722        }
2723    }
2724
2725    /* Send touch begin events for all new touches */
2726    for (i = 0; i < hw->num_mt_mask; i++)
2727        if (hw->slot_state[i] == SLOTSTATE_OPEN)
2728            xf86PostTouchEvent(pInfo->dev, i, XI_TouchBegin, 0, hw->mt_mask[i]);
2729
2730    /* Send touch update/end events for all the rest */
2731    for (i = 0; i < priv->num_active_touches; i++) {
2732        int slot = priv->open_slots[i];
2733
2734        /* Don't send update event if we just reopened the touch above */
2735        if (hw->slot_state[slot] == SLOTSTATE_UPDATE && !restart_touches)
2736            xf86PostTouchEvent(pInfo->dev, slot, XI_TouchUpdate, 0,
2737                               hw->mt_mask[slot]);
2738        else if (hw->slot_state[slot] == SLOTSTATE_CLOSE)
2739            xf86PostTouchEvent(pInfo->dev, slot, XI_TouchEnd, 0,
2740                               hw->mt_mask[slot]);
2741    }
2742
2743 out:
2744    UpdateTouchState(pInfo, hw);
2745}
2746
2747static void
2748filter_jitter(SynapticsPrivate * priv, int *x, int *y)
2749{
2750    SynapticsParameters *para = &priv->synpara;
2751
2752    priv->hyst_center_x = hysteresis(*x, priv->hyst_center_x, para->hyst_x);
2753    priv->hyst_center_y = hysteresis(*y, priv->hyst_center_y, para->hyst_y);
2754    *x = priv->hyst_center_x;
2755    *y = priv->hyst_center_y;
2756}
2757
2758static void
2759reset_hw_state(struct SynapticsHwState *hw)
2760{
2761    hw->x = 0;
2762    hw->y = 0;
2763    hw->z = 0;
2764    hw->numFingers = 0;
2765    hw->fingerWidth = 0;
2766}
2767
2768/*
2769 * React on changes in the hardware state. This function is called every time
2770 * the hardware state changes. The return value is used to specify how many
2771 * milliseconds to wait before calling the function again if no state change
2772 * occurs.
2773 *
2774 * from_timer denotes if HandleState was triggered from a timer (e.g. to
2775 * generate fake motion events, or for the tap-to-click state machine), rather
2776 * than from having received a motion event.
2777 */
2778static int
2779HandleState(InputInfoPtr pInfo, struct SynapticsHwState *hw, CARD32 now,
2780            Bool from_timer)
2781{
2782    SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
2783    SynapticsParameters *para = &priv->synpara;
2784    enum FingerState finger = FS_UNTOUCHED;
2785    int dx = 0, dy = 0, buttons, id;
2786    enum EdgeType edge = NO_EDGE;
2787    int change;
2788    int double_click = FALSE;
2789    int delay = 1000000000;
2790    int timeleft;
2791    Bool inside_active_area;
2792
2793    /* If touchpad is switched off, we skip the whole thing and return delay */
2794    if (para->touchpad_off == TOUCHPAD_OFF) {
2795        UpdateTouchState(pInfo, hw);
2796        return delay;
2797    }
2798
2799    /* We need both and x/y, the driver can't handle just one of the two
2800     * yet. But since it's possible to hit a phys button on non-clickpads
2801     * without ever getting motion data first, we must continue with 0/0 for
2802     * that case. */
2803    if (hw->x == INT_MIN || hw->y == INT_MAX) {
2804        if (para->clickpad)
2805            return delay;
2806        else if (hw->left || hw->right || hw->middle) {
2807            hw->x = (hw->x == INT_MIN) ? 0 : hw->x;
2808            hw->y = (hw->y == INT_MIN) ? 0 : hw->y;
2809        }
2810    }
2811
2812    /* If a physical button is pressed on a clickpad, use cumulative relative
2813     * touch movements for motion */
2814    if (para->clickpad && (hw->left || hw->right || hw->middle)) {
2815        hw->x = hw->cumulative_dx;
2816        hw->y = hw->cumulative_dy;
2817    }
2818
2819    /* apply hysteresis before doing anything serious. This cancels
2820     * out a lot of noise which might surface in strange phenomena
2821     * like flicker in scrolling or noise motion. */
2822    filter_jitter(priv, &hw->x, &hw->y);
2823
2824    inside_active_area = is_inside_active_area(priv, hw->x, hw->y);
2825
2826    /* these two just update hw->left, right, etc. */
2827    update_hw_button_state(pInfo, hw, priv->old_hw_state, now, &delay);
2828
2829    /* now we know that these _coordinates_ aren't in the area.
2830       invalid are: x, y, z, numFingers, fingerWidth
2831       valid are: millis, left/right/middle/up/down/etc.
2832     */
2833    if (!inside_active_area) {
2834        reset_hw_state(hw);
2835
2836        /* FIXME: if finger accidentally moves into the area and doesn't
2837         * really release, the finger should remain down. */
2838    }
2839
2840    /* no edge or finger detection outside of area */
2841    if (inside_active_area) {
2842        edge = edge_detection(priv, hw->x, hw->y);
2843        if (!from_timer)
2844            finger = SynapticsDetectFinger(priv, hw);
2845        else
2846            finger = priv->finger_state;
2847    }
2848
2849    /* tap and drag detection. Needs to be performed even if the finger is in
2850     * the dead area to reset the state. */
2851    timeleft = HandleTapProcessing(priv, hw, now, finger, inside_active_area);
2852    if (timeleft > 0)
2853        delay = MIN(delay, timeleft);
2854
2855    if (inside_active_area) {
2856        /* Don't bother about scrolling in the dead area of the touchpad. */
2857        timeleft = HandleScrolling(priv, hw, edge, (finger >= FS_TOUCHED));
2858        if (timeleft > 0)
2859            delay = MIN(delay, timeleft);
2860
2861        /*
2862         * Compensate for unequal x/y resolution. This needs to be done after
2863         * calculations that require unadjusted coordinates, for example edge
2864         * detection.
2865         */
2866        ScaleCoordinates(priv, hw);
2867    }
2868
2869    dx = dy = 0;
2870
2871    timeleft = ComputeDeltas(priv, hw, edge, &dx, &dy, inside_active_area);
2872    delay = MIN(delay, timeleft);
2873
2874    buttons = ((hw->left ? 0x01 : 0) |
2875               (hw->middle ? 0x02 : 0) |
2876               (hw->right ? 0x04 : 0) |
2877               (hw->up ? 0x08 : 0) |
2878               (hw->down ? 0x10 : 0) |
2879               (hw->multi[2] ? 0x20 : 0) | (hw->multi[3] ? 0x40 : 0));
2880
2881    if (priv->tap_button > 0) {
2882        int tap_mask = 1 << (priv->tap_button - 1);
2883
2884        if (priv->tap_button_state == TBS_BUTTON_DOWN_UP) {
2885            if (tap_mask != (priv->lastButtons & tap_mask)) {
2886                xf86PostButtonEvent(pInfo->dev, FALSE, priv->tap_button, TRUE,
2887                                    0, 0);
2888                priv->lastButtons |= tap_mask;
2889            }
2890            priv->tap_button_state = TBS_BUTTON_UP;
2891        }
2892        if (priv->tap_button_state == TBS_BUTTON_DOWN)
2893            buttons |= tap_mask;
2894    }
2895
2896    /* Post events */
2897    if (finger >= FS_TOUCHED && (dx || dy))
2898        xf86PostMotionEvent(pInfo->dev, 0, 0, 2, dx, dy);
2899
2900    if (priv->mid_emu_state == MBE_LEFT_CLICK) {
2901        post_button_click(pInfo, 1);
2902        priv->mid_emu_state = MBE_OFF;
2903    }
2904    else if (priv->mid_emu_state == MBE_RIGHT_CLICK) {
2905        post_button_click(pInfo, 3);
2906        priv->mid_emu_state = MBE_OFF;
2907    }
2908
2909    change = buttons ^ priv->lastButtons;
2910    while (change) {
2911        id = ffs(change);       /* number of first set bit 1..32 is returned */
2912        change &= ~(1 << (id - 1));
2913        xf86PostButtonEvent(pInfo->dev, FALSE, id, (buttons & (1 << (id - 1))),
2914                            0, 0);
2915    }
2916
2917    /* Process scroll events only if coordinates are
2918     * in the Synaptics Area
2919     */
2920    if (inside_active_area &&
2921        (priv->scroll.delta_x != 0.0 || priv->scroll.delta_y != 0.0)) {
2922        post_scroll_events(pInfo);
2923        priv->scroll.last_millis = hw->millis;
2924    }
2925
2926    if (double_click) {
2927        post_button_click(pInfo, 1);
2928        post_button_click(pInfo, 1);
2929    }
2930
2931    HandleTouches(pInfo, hw);
2932
2933    /* Save old values of some state variables */
2934    priv->finger_state = finger;
2935    priv->lastButtons = buttons;
2936
2937    /* generate a history of the absolute positions */
2938    if (inside_active_area)
2939        store_history(priv, hw->x, hw->y, hw->millis);
2940
2941    /* Save logical state for transition comparisons */
2942    SynapticsCopyHwState(priv->old_hw_state, hw);
2943
2944    return delay;
2945}
2946
2947static int
2948ControlProc(InputInfoPtr pInfo, xDeviceCtl * control)
2949{
2950    DBG(3, "Control Proc called\n");
2951    return Success;
2952}
2953
2954static int
2955SwitchMode(ClientPtr client, DeviceIntPtr dev, int mode)
2956{
2957    DBG(3, "SwitchMode called\n");
2958
2959    return XI_BadMode;
2960}
2961
2962static void
2963ReadDevDimensions(InputInfoPtr pInfo)
2964{
2965    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
2966
2967    if (priv->proto_ops->ReadDevDimensions)
2968        priv->proto_ops->ReadDevDimensions(pInfo);
2969
2970    SanitizeDimensions(pInfo);
2971}
2972
2973static Bool
2974QueryHardware(InputInfoPtr pInfo)
2975{
2976    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
2977
2978    priv->comm.protoBufTail = 0;
2979
2980    if (!priv->proto_ops->QueryHardware(pInfo)) {
2981        xf86IDrvMsg(pInfo, X_PROBED, "no supported touchpad found\n");
2982        if (priv->proto_ops->DeviceOffHook)
2983            priv->proto_ops->DeviceOffHook(pInfo);
2984        return FALSE;
2985    }
2986
2987    return TRUE;
2988}
2989
2990static void
2991ScaleCoordinates(SynapticsPrivate * priv, struct SynapticsHwState *hw)
2992{
2993    int xCenter = (priv->synpara.left_edge + priv->synpara.right_edge) / 2;
2994    int yCenter = (priv->synpara.top_edge + priv->synpara.bottom_edge) / 2;
2995
2996    hw->x = (hw->x - xCenter) * priv->horiz_coeff + xCenter;
2997    hw->y = (hw->y - yCenter) * priv->vert_coeff + yCenter;
2998}
2999
3000void
3001CalculateScalingCoeffs(SynapticsPrivate * priv)
3002{
3003    int vertRes = priv->synpara.resolution_vert;
3004    int horizRes = priv->synpara.resolution_horiz;
3005
3006    if ((horizRes > vertRes) && (horizRes > 0)) {
3007        priv->horiz_coeff = vertRes / (double) horizRes;
3008        priv->vert_coeff = 1;
3009    }
3010    else if ((horizRes < vertRes) && (vertRes > 0)) {
3011        priv->horiz_coeff = 1;
3012        priv->vert_coeff = horizRes / (double) vertRes;
3013    }
3014    else {
3015        priv->horiz_coeff = 1;
3016        priv->vert_coeff = 1;
3017    }
3018}
3019