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