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