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