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