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