synaptics.c 52.4 KB
Newer Older
Peter Osterlund's avatar
Peter Osterlund committed
1
/*
2 3 4
 *   Copyright 2006 Stefan Bethge <stefan.bethge@web.de>
 *     patch for two-fingered scrolling
 *
5 6 7
 *   Copyright 2004 Matthias Ihmig <m.ihmig@gmx.net>
 *     patch for pressure dependent EdgeMotion speed
 *
8 9 10
 *   Copyright 2004 Alexei Gilchrist <alexei@physics.uq.edu.au>
 *     patch for circular scrolling
 *
11
 *   Copyright 2003 Jrg Bsner <ich@joerg-boesner.de>
12 13 14
 *     patch for switching the touchpad off (for example, when a
 *     USB mouse is connected)
 *
15
 *   Copyright 2003 Hartwig Felger <hgfelger@hgfelger.de>
Peter Osterlund's avatar
Peter Osterlund committed
16
 *     patch to make the horizontal wheel replacement buttons work.
17
 *
18
 *   Copyright 2002 Peter Osterlund <petero2@telia.com>
Peter Osterlund's avatar
Peter Osterlund committed
19
 *     patches for fast scrolling, palm detection, edge motion,
Peter Osterlund's avatar
Peter Osterlund committed
20
 *     horizontal scrolling
21
 *
22
 *   Copyright 2002 S. Lehner <sam_x@bluemail.ch>
Peter Osterlund's avatar
Peter Osterlund committed
23
 *     for newer Firmware (5.8) protocol changes for 3rd to 6th button
24
 *
25
 *   Copyright (C) 2001 Stefan Gmeiner <riddlebox@freesurf.ch>
Peter Osterlund's avatar
Peter Osterlund committed
26
 *     start merging tpconfig and gpm code to an xfree input module
27
 *     adding some changes and extensions (ex. 3rd and 4th button)
Peter Osterlund's avatar
Peter Osterlund committed
28 29
 *
 *   Copyright (c) 1999 Henry Davies <hdavies@ameritech.net> for the
Peter Osterlund's avatar
Peter Osterlund committed
30
 *     absolute to relative translation code (from the gpm source)
31
 *     and some other ideas
32
 *
33 34 35 36 37
 *   Synaptics Passthrough Support
 *   Copyright (c) 2002 Linuxcare Inc. David Kennedy <dkennedy@linuxcare.com>
 *   adapted to version 0.12.1
 *   Copyright (c) 2003 Fred Hucht <fred@thp.Uni-Duisburg.de>
 *
38 39 40 41 42 43 44 45 46 47 48 49 50 51
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License
 *   as published by the Free Software Foundation; either version 2
 *   of the License, or (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
52 53 54
 *
 * Trademarks are the property of their respective owners.
 *
55 56 57 58 59 60 61
 */


/*****************************************************************************
 *	Standard Headers
 ****************************************************************************/

62
#include <unistd.h>
63
#include <sys/ioctl.h>
64 65 66 67 68 69 70
#include <misc.h>
#include <xf86.h>
#define NEED_XF86_TYPES
#include <xf86_ansic.h>
#include <xf86_OSproc.h>
#include <xf86Xinput.h>
#include "mipointer.h"
71
#ifdef XFREE_4_0_3
Peter Osterlund's avatar
Peter Osterlund committed
72
#include <xf86Optrec.h>  		/* needed for Options */
73
#endif
74

75 76 77 78

/*****************************************************************************
 *	Local Headers
 ****************************************************************************/
Peter Osterlund's avatar
Peter Osterlund committed
79
#define SYNAPTICS_PRIVATE
80 81 82 83 84 85 86
#include "synaptics.h"

/*****************************************************************************
 *	Variables without includable headers
 ****************************************************************************/

/*****************************************************************************
87
 *	Local Variables and Types
88 89 90
 ****************************************************************************/

typedef enum {
91 92 93 94 95 96 97 98
    BOTTOM_EDGE = 1,
    TOP_EDGE = 2,
    LEFT_EDGE = 4,
    RIGHT_EDGE = 8,
    LEFT_BOTTOM_EDGE = BOTTOM_EDGE | LEFT_EDGE,
    RIGHT_BOTTOM_EDGE = BOTTOM_EDGE | RIGHT_EDGE,
    RIGHT_TOP_EDGE = TOP_EDGE | RIGHT_EDGE,
    LEFT_TOP_EDGE = TOP_EDGE | LEFT_EDGE
99 100
} edge_type;

101
#define MAX(a, b) (((a)>(b))?(a):(b))
102
#define MIN(a, b) (((a)<(b))?(a):(b))
103
#define TIME_DIFF(a, b) ((int)((a)-(b)))
104
#define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
105

106 107
#define SQR(x) ((x) * (x))

108 109 110 111
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

112 113 114 115
#ifndef M_SQRT1_2
#define M_SQRT1_2  0.70710678118654752440  /* 1/sqrt(2) */
#endif

116 117 118 119
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 1
#define DBG(a,b)
#endif

120 121 122
/*****************************************************************************
 * Forward declaration
 ****************************************************************************/
123 124 125 126 127 128 129 130 131 132 133
static InputInfoPtr SynapticsPreInit(InputDriverPtr drv, IDevPtr dev, int flags);
static Bool DeviceControl(DeviceIntPtr, int);
static void ReadInput(LocalDevicePtr);
static int HandleState(LocalDevicePtr, struct SynapticsHwState*);
static int ControlProc(LocalDevicePtr, xDeviceCtl*);
static void CloseProc(LocalDevicePtr);
static int SwitchMode(ClientPtr, DeviceIntPtr, int);
static Bool ConvertProc(LocalDevicePtr, int, int, int, int, int, int, int, int, int*, int*);
static Bool DeviceInit(DeviceIntPtr);
static Bool DeviceOn(DeviceIntPtr);
static Bool DeviceOff(DeviceIntPtr);
134
static Bool DeviceClose(DeviceIntPtr);
Peter Osterlund's avatar
Peter Osterlund committed
135
static Bool QueryHardware(LocalDevicePtr);
136 137 138


InputDriverRec SYNAPTICS = {
139 140 141 142 143 144 145
    1,
    "synaptics",
    NULL,
    SynapticsPreInit,
    /*SynapticsUnInit*/ NULL,
    NULL,
    0
146 147 148 149
};

#ifdef XFree86LOADER

150 151 152 153 154 155 156 157 158 159 160 161
static XF86ModuleVersionInfo VersionRec = {
    "synaptics",
    MODULEVENDORSTRING,
    MODINFOSTRING1,
    MODINFOSTRING2,
    XF86_VERSION_CURRENT,
    1, 0, 0,
    ABI_CLASS_XINPUT,
    ABI_XINPUT_VERSION,
    MOD_CLASS_XINPUT,
    {0, 0, 0, 0}				/* signature, to be patched into the file by
						 * a tool */
162 163 164 165
};


static pointer
166
SetupProc(pointer module, pointer options, int *errmaj, int *errmin)
167
{
168 169
    xf86AddInputDriver(&SYNAPTICS, module, 0);
    return module;
170 171 172 173 174 175 176 177 178 179 180
}

XF86ModuleData synapticsModuleData = {&VersionRec, &SetupProc, NULL };

#endif /* XFree86LOADER */


/*****************************************************************************
 *	Function Definitions
 ****************************************************************************/

181 182 183
static void
SetDeviceAndProtocol(LocalDevicePtr local)
{
184
    char *str_par;
185
    SynapticsPrivate *priv = local->private;
186
    enum SynapticsProtocol proto = SYN_PROTO_PSAUX;
187 188

    str_par = xf86FindOptionValue(local->options, "Protocol");
189
    if (str_par && !strcmp(str_par, "psaux")) {
190
	/* Already set up */
191 192 193 194
    } else if (str_par && !strcmp(str_par, "event")) {
	proto = SYN_PROTO_EVENT;
    } else if (str_par && !strcmp(str_par, "psm")) {
	proto = SYN_PROTO_PSM;
195 196
    } else if (str_par && !strcmp(str_par, "alps")) {
	proto = SYN_PROTO_ALPS;
197
    } else { /* default to auto-dev */
198
	if (event_proto_operations.AutoDevProbe(local))
199
	    proto = SYN_PROTO_EVENT;
200
    }
201
    switch (proto) {
202 203 204 205 206 207
    case SYN_PROTO_PSAUX:
	priv->proto_ops = &psaux_proto_operations;
	break;
    case SYN_PROTO_EVENT:
	priv->proto_ops = &event_proto_operations;
	break;
208 209
    case SYN_PROTO_PSM:
	priv->proto_ops = &psm_proto_operations;
210
	break;
211 212 213
    case SYN_PROTO_ALPS:
	priv->proto_ops = &alps_proto_operations;
	break;
214
    }
215 216
}

217 218 219 220 221 222
/*
 * Allocate and initialize memory for the SynapticsSHM data to hold driver
 * parameter settings.
 * The function will allocate shared memory if priv->shm_config is TRUE.
 * The allocated data is initialized from priv->synpara_default.
 */
Peter Osterlund's avatar
Peter Osterlund committed
223 224
static Bool
alloc_param_data(LocalDevicePtr local)
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
{
    int shmid;
    SynapticsPrivate *priv = local->private;

    if (priv->synpara)
	return TRUE;			    /* Already allocated */

    if (priv->shm_config) {
	if ((shmid = xf86shmget(SHM_SYNAPTICS, 0, 0)) != -1)
	    xf86shmctl(shmid, XF86IPC_RMID, NULL);
	if ((shmid = xf86shmget(SHM_SYNAPTICS, sizeof(SynapticsSHM),
				0777 | XF86IPC_CREAT)) == -1) {
	    xf86Msg(X_ERROR, "%s error shmget\n", local->name);
	    return FALSE;
	}
	if ((priv->synpara = (SynapticsSHM*)xf86shmat(shmid, NULL, 0)) == NULL) {
	    xf86Msg(X_ERROR, "%s error shmat\n", local->name);
	    return FALSE;
	}
    } else {
	priv->synpara = xcalloc(1, sizeof(SynapticsSHM));
	if (!priv->synpara)
	    return FALSE;
    }

    *(priv->synpara) = priv->synpara_default;
    return TRUE;
}

/*
 * Free SynapticsSHM data previously allocated by alloc_param_data().
 */
Peter Osterlund's avatar
Peter Osterlund committed
257 258
static void
free_param_data(SynapticsPrivate *priv)
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
{
    int shmid;

    if (!priv->synpara)
	return;

    if (priv->shm_config) {
	if ((shmid = xf86shmget(SHM_SYNAPTICS, 0, 0)) != -1)
	    xf86shmctl(shmid, XF86IPC_RMID, NULL);
    } else {
	xfree(priv->synpara);
    }

    priv->synpara = NULL;
}

275 276 277 278 279 280 281 282 283 284 285
static double
synSetFloatOption(pointer options, const char *optname, double default_value)
{
    char *str_par;
    double value;
    str_par = xf86FindOptionValue(options, optname);
    if ((!str_par) || (xf86sscanf(str_par, "%lf", &value) != 1))
	return default_value;
    return value;
}

286
/*
287
 *  called by the module loader for initialization
288
 */
289 290 291
static InputInfoPtr
SynapticsPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
{
292
    LocalDevicePtr local;
293
    SynapticsPrivate *priv;
294
#ifdef XFREE_4_0_3
295
    XF86OptionPtr optList;
296
#else
297
    pointer optList;
298
#endif
299
    SynapticsSHM *pars;
300
    char *repeater;
301
    pointer opts;
302

Peter Osterlund's avatar
Peter Osterlund committed
303
    /* allocate memory for SynapticsPrivateRec */
Peter Osterlund's avatar
Peter Osterlund committed
304
    priv = xcalloc(1, sizeof(SynapticsPrivate));
305 306 307 308 309
    if (!priv)
	return NULL;

    /* Allocate a new InputInfoRec and add it to the head xf86InputDevs. */
    local = xf86AllocateInput(drv, 0);
310 311 312 313
    if (!local) {
	xfree(priv);
	return NULL;
    }
314

315 316
    /* initialize the InputInfoRec */
    local->name                    = dev->identifier;
Peter Osterlund's avatar
Peter Osterlund committed
317
    local->type_name               = XI_MOUSE; /* XI_TOUCHPAD and KDE killed the X Server at startup ? */
318 319 320 321 322 323 324 325 326 327 328 329
    local->device_control          = DeviceControl;
    local->read_input              = ReadInput;
    local->control_proc            = ControlProc;
    local->close_proc              = CloseProc;
    local->switch_mode             = SwitchMode;
    local->conversion_proc         = ConvertProc;
    local->reverse_conversion_proc = NULL;
    local->dev                     = NULL;
    local->private                 = priv;
    local->private_flags           = 0;
    local->flags                   = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
    local->conf_idev               = dev;
330
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
331 332
    local->motion_history_proc     = xf86GetMotionEvents;
    local->history_size            = 0;
333
#endif
334 335
    local->always_core_feedback    = 0;

336
    xf86Msg(X_INFO, "Synaptics touchpad driver version %s (%d)\n", VERSION, VERSION_ID);
337

338 339
    xf86CollectInputOptions(local, NULL, NULL);

340 341 342
    opts = local->options;

    xf86OptionListReport(opts);
343 344 345 346

    SetDeviceAndProtocol(local);

    /* open the touchpad device */
347
    local->fd = xf86OpenSerial(opts);
348
    if (local->fd == -1) {
Peter Osterlund's avatar
Peter Osterlund committed
349
	ErrorF("Synaptics driver unable to open device\n");
350 351
	goto SetupProc_fail;
    }
Peter Osterlund's avatar
Peter Osterlund committed
352
    xf86ErrorFVerb(6, "port opened successfully\n");
353 354 355 356 357 358

    /* initialize variables */
    priv->timer = NULL;
    priv->repeatButtons = 0;
    priv->nextRepeat = 0;
    priv->count_packet_finger = 0;
359 360 361
    priv->tap_state = TS_START;
    priv->tap_button = 0;
    priv->tap_button_state = TBS_BUTTON_UP;
362
    priv->touch_on.millis = 0;
363

364
    /* install shared memory or normal memory for parameters */
365
    priv->shm_config = xf86SetBoolOption(opts, "SHMConfig", FALSE);
366

367
    /* read the parameters */
368
    pars = &priv->synpara_default;
369
    pars->version = VERSION_ID;
370 371 372 373 374 375 376 377 378 379 380 381
    pars->left_edge = xf86SetIntOption(opts, "LeftEdge", 1900);
    pars->right_edge = xf86SetIntOption(opts, "RightEdge", 5400);
    pars->top_edge = xf86SetIntOption(opts, "TopEdge", 1900);
    pars->bottom_edge = xf86SetIntOption(opts, "BottomEdge", 4000);
    pars->finger_low = xf86SetIntOption(opts, "FingerLow", 25);
    pars->finger_high = xf86SetIntOption(opts, "FingerHigh", 30);
    pars->tap_time = xf86SetIntOption(opts, "MaxTapTime", 180);
    pars->tap_move = xf86SetIntOption(opts, "MaxTapMove", 220);
    pars->tap_time_2 = xf86SetIntOption(opts, "MaxDoubleTapTime", 180);
    pars->click_time = xf86SetIntOption(opts, "ClickTime", 100);
    pars->fast_taps = xf86SetIntOption(opts, "FastTaps", FALSE);
    pars->emulate_mid_button_time = xf86SetIntOption(opts,
382
							      "EmulateMidButtonTime", 75);
383
    pars->emulate_twofinger_z = xf86SetIntOption(opts, "EmulateTwoFingerMinZ", 257);
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
    pars->scroll_dist_vert = xf86SetIntOption(opts, "VertScrollDelta", 100);
    pars->scroll_dist_horiz = xf86SetIntOption(opts, "HorizScrollDelta", 100);
    pars->scroll_edge_vert = xf86SetBoolOption(opts, "VertEdgeScroll", TRUE);
    pars->scroll_edge_horiz = xf86SetBoolOption(opts, "HorizEdgeScroll", TRUE);
    pars->scroll_twofinger_vert = xf86SetBoolOption(opts, "VertTwoFingerScroll", FALSE);
    pars->scroll_twofinger_horiz = xf86SetBoolOption(opts, "HorizTwoFingerScroll", FALSE);
    pars->edge_motion_min_z = xf86SetIntOption(opts, "EdgeMotionMinZ", 30);
    pars->edge_motion_max_z = xf86SetIntOption(opts, "EdgeMotionMaxZ", 160);
    pars->edge_motion_min_speed = xf86SetIntOption(opts, "EdgeMotionMinSpeed", 1);
    pars->edge_motion_max_speed = xf86SetIntOption(opts, "EdgeMotionMaxSpeed", 400);
    pars->edge_motion_use_always = xf86SetBoolOption(opts, "EdgeMotionUseAlways", FALSE);
    repeater = xf86SetStrOption(opts, "Repeater", NULL);
    pars->updown_button_scrolling = xf86SetBoolOption(opts, "UpDownScrolling", TRUE);
    pars->leftright_button_scrolling = xf86SetBoolOption(opts, "LeftRightScrolling", TRUE);
    pars->updown_button_repeat = xf86SetBoolOption(opts, "UpDownScrollRepeat", TRUE);
    pars->leftright_button_repeat = xf86SetBoolOption(opts, "LeftRightScrollRepeat", TRUE);
    pars->scroll_button_repeat = xf86SetIntOption(opts,"ScrollButtonRepeat", 100);
    pars->touchpad_off = xf86SetIntOption(opts, "TouchpadOff", 0);
    pars->guestmouse_off = xf86SetBoolOption(opts, "GuestMouseOff", FALSE);
    pars->locked_drags = xf86SetBoolOption(opts, "LockedDrags", FALSE);
    pars->tap_action[RT_TAP] = xf86SetIntOption(opts, "RTCornerButton", 2);
    pars->tap_action[RB_TAP] = xf86SetIntOption(opts, "RBCornerButton", 3);
    pars->tap_action[LT_TAP] = xf86SetIntOption(opts, "LTCornerButton", 0);
    pars->tap_action[LB_TAP] = xf86SetIntOption(opts, "LBCornerButton", 0);
    pars->tap_action[F1_TAP] = xf86SetIntOption(opts, "TapButton1",     1);
    pars->tap_action[F2_TAP] = xf86SetIntOption(opts, "TapButton2",     2);
    pars->tap_action[F3_TAP] = xf86SetIntOption(opts, "TapButton3",     3);
    pars->circular_scrolling = xf86SetBoolOption(opts, "CircularScrolling", FALSE);
    pars->circular_trigger   = xf86SetIntOption(opts, "CircScrollTrigger", 0);
    pars->circular_pad       = xf86SetBoolOption(opts, "CircularPad", FALSE);
    pars->palm_detect        = xf86SetBoolOption(opts, "PalmDetect", TRUE);
    pars->palm_min_width     = xf86SetIntOption(opts, "PalmMinWidth", 10);
    pars->palm_min_z         = xf86SetIntOption(opts, "PalmMinZ", 200);
417
    pars->single_tap_timeout = xf86SetIntOption(opts, "SingleTapTimeout", 180);
418 419 420
    pars->press_motion_min_z = xf86SetIntOption(opts, "PressureMotionMinZ", pars->edge_motion_min_z);
    pars->press_motion_max_z = xf86SetIntOption(opts, "PressureMotionMaxZ", pars->edge_motion_max_z);

421 422 423 424 425 426 427
    pars->min_speed = synSetFloatOption(opts, "MinSpeed", 0.09);
    pars->max_speed = synSetFloatOption(opts, "MaxSpeed", 0.18);
    pars->accl = synSetFloatOption(opts, "AccelFactor", 0.0015);
    pars->scroll_dist_circ = synSetFloatOption(opts, "CircScrollDelta", 0.1);
    pars->coasting_speed = synSetFloatOption(opts, "CoastingSpeed", 0.0);
    pars->press_motion_min_factor = synSetFloatOption(opts, "PressureMotionMinFactor", 1.0);
    pars->press_motion_max_factor = synSetFloatOption(opts, "PressureMotionMaxFactor", 1.0);
428

Peter Osterlund's avatar
Peter Osterlund committed
429
    /* Warn about (and fix) incorrectly configured TopEdge/BottomEdge parameters */
430 431 432 433
    if (pars->top_edge > pars->bottom_edge) {
	int tmp = pars->top_edge;
	pars->top_edge = pars->bottom_edge;
	pars->bottom_edge = tmp;
434 435 436 437
	xf86Msg(X_WARNING, "%s: TopEdge is bigger than BottomEdge. Fixing.\n",
		local->name);
    }

438
    priv->largest_valid_x = MIN(pars->right_edge, XMAX_NOMINAL);
439

440 441 442
    if (!alloc_param_data(local))
	goto SetupProc_fail;

443 444
    priv->comm.buffer = XisbNew(local->fd, 200);
    DBG(9, XisbTrace(priv->comm.buffer, 1));
445

446
    priv->fifofd = -1;
447
    if (repeater) {
448
	/* create repeater fifo */
449
	if ((xf86mknod(repeater, 666, XF86_S_IFIFO) != 0) &&
450 451 452 453
	    (xf86errno != xf86_EEXIST)) {
	    xf86Msg(X_ERROR, "%s can't create repeater fifo\n", local->name);
	} else {
	    /* open the repeater fifo */
454
	    optList = xf86NewOption("Device", repeater);
455 456 457
	    if ((priv->fifofd = xf86OpenSerial(optList)) == -1) {
		xf86Msg(X_ERROR, "%s repeater device open failed\n", local->name);
	    }
458
	}
459
	xf86free(repeater);
460
    }
461

462
    if (!QueryHardware(local)) {
463 464 465
	xf86Msg(X_ERROR, "%s Unable to query/initialize Synaptics hardware.\n", local->name);
	goto SetupProc_fail;
    }
466

467
    xf86ProcessCommonOptions(local, opts);
468
    local->flags |= XI86_CONFIGURED;
469

470
    if (local->fd != -1) {
471 472 473
	if (priv->comm.buffer) {
	    XisbFree(priv->comm.buffer);
	    priv->comm.buffer = NULL;
474
	}
475 476
	xf86CloseSerial(local->fd);
    }
477
    local->fd = -1;
478
    return local;
479

480 481
 SetupProc_fail:
    if (local->fd >= 0) {
Peter Osterlund's avatar
Peter Osterlund committed
482
	xf86CloseSerial(local->fd);
483 484 485
	local->fd = -1;
    }

486 487
    if (priv->comm.buffer)
	XisbFree(priv->comm.buffer);
488
    free_param_data(priv);
489
    /* Freeing priv makes the X server crash. Don't know why.
Peter Osterlund's avatar
Peter Osterlund committed
490
       xfree(priv);
491
    */
492
    return local;
493 494 495
}

/*
496 497
 *  Alter the control parameters for the mouse. Note that all special
 *  protocol values are handled by dix.
498 499 500 501
 */
static void
SynapticsCtrl(DeviceIntPtr device, PtrCtrl *ctrl)
{
502 503 504 505 506 507 508 509 510
    DBG(3, ErrorF("SynapticsCtrl called.\n"));
    /*
      pInfo = device->public.devicePrivate;
      pMse = pInfo->private;

      pMse->num       = ctrl->num;
      pMse->den       = ctrl->den;
      pMse->threshold = ctrl->threshold;
    */
511 512 513
}

static Bool
Peter Osterlund's avatar
Peter Osterlund committed
514
DeviceControl(DeviceIntPtr dev, int mode)
515
{
Peter Osterlund's avatar
Peter Osterlund committed
516
    Bool RetValue;
517

518 519
    switch (mode) {
    case DEVICE_INIT:
520
	RetValue = DeviceInit(dev);
521 522
	break;
    case DEVICE_ON:
523
	RetValue = DeviceOn(dev);
524 525
	break;
    case DEVICE_OFF:
526
	RetValue = DeviceOff(dev);
527 528
	break;
    case DEVICE_CLOSE:
529
	RetValue = DeviceClose(dev);
530 531 532 533
	break;
    default:
	RetValue = BadValue;
    }
534

535
    return RetValue;
536 537 538
}

static Bool
Peter Osterlund's avatar
Peter Osterlund committed
539
DeviceOn(DeviceIntPtr dev)
540
{
541
    LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
542
    SynapticsPrivate *priv = (SynapticsPrivate *) (local->private);
543

544
    DBG(3, ErrorF("Synaptics DeviceOn called\n"));
545

546
    SetDeviceAndProtocol(local);
547 548 549
    local->fd = xf86OpenSerial(local->options);
    if (local->fd == -1) {
	xf86Msg(X_WARNING, "%s: cannot open input device\n", local->name);
550
	return !Success;
551
    }
552

553
    priv->proto_ops->DeviceOnHook(local);
554

555 556
    priv->comm.buffer = XisbNew(local->fd, 64);
    if (!priv->comm.buffer) {
557 558
	xf86CloseSerial(local->fd);
	local->fd = -1;
559
	return !Success;
560
    }
561

562
    xf86FlushInput(local->fd);
Peter Osterlund's avatar
Peter Osterlund committed
563

564 565
    /* reinit the pad */
    QueryHardware(local);
Peter Osterlund's avatar
Peter Osterlund committed
566
    xf86AddEnabledDevice(local);
567
    dev->public.on = TRUE;
Peter Osterlund's avatar
Peter Osterlund committed
568

569
    return Success;
570 571 572 573 574
}

static Bool
DeviceOff(DeviceIntPtr dev)
{
575
    LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
576
    SynapticsPrivate *priv = (SynapticsPrivate *) (local->private);
577 578 579 580

    DBG(3, ErrorF("Synaptics DeviceOff called\n"));

    if (local->fd != -1) {
581 582
	TimerFree(priv->timer);
	priv->timer = NULL;
Peter Osterlund's avatar
Peter Osterlund committed
583
	xf86RemoveEnabledDevice(local);
584
	priv->proto_ops->DeviceOffHook(local);
585 586 587
	if (priv->comm.buffer) {
	    XisbFree(priv->comm.buffer);
	    priv->comm.buffer = NULL;
588
	}
589 590 591
	xf86CloseSerial(local->fd);
    }
    dev->public.on = FALSE;
592
    return Success;
593 594
}

595 596 597 598 599 600 601 602 603 604 605 606
static Bool
DeviceClose(DeviceIntPtr dev)
{
    Bool RetValue;
    LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
    SynapticsPrivate *priv = (SynapticsPrivate *) local->private;

    RetValue = DeviceOff(dev);
    free_param_data(priv);
    return RetValue;
}

607 608 609
static Bool
DeviceInit(DeviceIntPtr dev)
{
610
    LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
611 612
    unsigned char map[SYN_MAX_BUTTONS + 1];
    int i;
613

614
    DBG(3, ErrorF("Synaptics DeviceInit called\n"));
615

616 617 618
    for (i = 0; i <= SYN_MAX_BUTTONS; i++)
	map[i] = i;

619
    dev->public.on = FALSE;
620

621
    InitPointerDeviceStruct((DevicePtr)dev, map,
622
			    SYN_MAX_BUTTONS,
623 624 625 626 627 628 629 630 631 632
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
			    miPointerGetMotionEvents,
			    SynapticsCtrl,
			    miPointerGetMotionBufferSize()
#else
			    GetMotionHistory,
			    SynapticsCtrl,
			    GetMotionHistorySize(), 2
#endif
			    );
633 634 635 636 637 638
    /* X valuator */
    xf86InitValuatorAxisStruct(dev, 0, 0, -1, 1, 0, 1);
    xf86InitValuatorDefaults(dev, 0);
    /* Y valuator */
    xf86InitValuatorAxisStruct(dev, 1, 0, -1, 1, 0, 1);
    xf86InitValuatorDefaults(dev, 1);
639
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0
640
    xf86MotionHistoryAllocate(local);
641
#endif
642

643 644 645
    if (!alloc_param_data(local))
	return !Success;

646
    return Success;
647 648
}

Peter Osterlund's avatar
Peter Osterlund committed
649
static int
650 651
move_distance(int dx, int dy)
{
652
    return xf86sqrt(SQR(dx) + SQR(dy));
653 654
}

655 656 657 658 659
/*
 * Convert from absolute X/Y coordinates to a coordinate system where
 * -1 corresponds to the left/upper edge and +1 corresponds to the
 * right/lower edge.
 */
Peter Osterlund's avatar
Peter Osterlund committed
660 661 662
static void
relative_coords(SynapticsPrivate *priv, int x, int y,
		double *relX, double *relY)
663 664 665 666 667 668 669 670 671 672 673
{
    int minX = priv->synpara->left_edge;
    int maxX = priv->synpara->right_edge;
    int minY = priv->synpara->top_edge;
    int maxY = priv->synpara->bottom_edge;
    double xCenter = (minX + maxX) / 2.0;
    double yCenter = (minY + maxY) / 2.0;

    if ((maxX - xCenter > 0) && (maxY - yCenter > 0)) {
	*relX = (x - xCenter) / (maxX - xCenter);
	*relY = (y - yCenter) / (maxY - yCenter);
Peter Osterlund's avatar
Peter Osterlund committed
674
    } else {
675 676 677 678 679
	*relX = 0;
	*relY = 0;
    }
}

680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
/* return angle of point relative to center */
static double
angle(SynapticsPrivate *priv, int x, int y)
{
    double xCenter = (priv->synpara->left_edge + priv->synpara->right_edge) / 2.0;
    double yCenter = (priv->synpara->top_edge + priv->synpara->bottom_edge) / 2.0;

    return xf86atan2(-(y - yCenter), x - xCenter);
}

/* return angle difference */
static double
diffa(double a1, double a2)
{
    double da = xf86fmod(a2 - a1, 2 * M_PI);
    if (da < 0)
	da += 2 * M_PI;
    if (da > M_PI)
	da -= 2 * M_PI;
    return da;
}

702 703 704 705 706 707 708
static edge_type
circular_edge_detection(SynapticsPrivate *priv, int x, int y)
{
    edge_type edge = 0;
    double relX, relY, relR;

    relative_coords(priv, x, y, &relX, &relY);
709
    relR = SQR(relX) + SQR(relY);
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726

    if (relR > 1) {
	/* we are outside the ellipse enclosed by the edge parameters */
	if (relX > M_SQRT1_2)
	    edge |= RIGHT_EDGE;
	else if (relX < -M_SQRT1_2)
	    edge |= LEFT_EDGE;

	if (relY < -M_SQRT1_2)
	    edge |= TOP_EDGE;
	else if (relY > M_SQRT1_2)
	    edge |= BOTTOM_EDGE;
    }

    return edge;
}

Peter Osterlund's avatar
Peter Osterlund committed
727
static edge_type
728
edge_detection(SynapticsPrivate *priv, int x, int y)
729
{
730
    edge_type edge = 0;
731

732 733 734
    if (priv->synpara->circular_pad)
	return circular_edge_detection(priv, x, y);

735
    if (x > priv->synpara->right_edge)
736
	edge |= RIGHT_EDGE;
737
    else if (x < priv->synpara->left_edge)
738
	edge |= LEFT_EDGE;
739

740
    if (y < priv->synpara->top_edge)
741
	edge |= TOP_EDGE;
742
    else if (y > priv->synpara->bottom_edge)
743
	edge |= BOTTOM_EDGE;
744

745
    return edge;
746 747 748
}

static CARD32
749
timerFunc(OsTimerPtr timer, CARD32 now, pointer arg)
750 751
{
    LocalDevicePtr local = (LocalDevicePtr) (arg);
752
    SynapticsPrivate *priv = (SynapticsPrivate *) (local->private);
753 754 755 756
    struct SynapticsHwState hw;
    int delay;
    int sigstate;
    CARD32 wakeUpTime;
757

Peter Osterlund's avatar
Peter Osterlund committed
758
    sigstate = xf86BlockSIGIO();
Peter Osterlund's avatar
Peter Osterlund committed
759

760
    hw = priv->hwState;
761
    hw.guest_dx = hw.guest_dy = 0;
762 763
    hw.millis = now;
    delay = HandleState(local, &hw);
764

765 766 767 768 769 770 771 772
    /*
     * Workaround for wraparound bug in the TimerSet function. This bug is already
     * fixed in CVS, but this driver needs to work with XFree86 versions 4.2.x and
     * 4.3.x too.
     */
    wakeUpTime = now + delay;
    if (wakeUpTime <= now)
	wakeUpTime = 0xffffffffL;
773

774
    priv->timer = TimerSet(priv->timer, TimerAbsolute, wakeUpTime, timerFunc, local);
775

Peter Osterlund's avatar
Peter Osterlund committed
776
    xf86UnblockSIGIO(sigstate);
777

778 779 780
    return 0;
}

Peter Osterlund's avatar
Peter Osterlund committed
781 782
static int
clamp(int val, int min, int max)
783
{
784 785 786 787 788 789
    if (val < min)
	return min;
    else if (val < max)
	return val;
    else
	return max;
790 791
}

792 793 794 795
static Bool
SynapticsGetHwState(LocalDevicePtr local, SynapticsPrivate *priv,
		    struct SynapticsHwState *hw)
{
796 797 798 799 800 801 802 803 804 805 806 807
    if (priv->fifofd >= 0) {
	/* when there is no synaptics touchpad pipe the data to the repeater fifo */
	int count = 0;
	int c;
	while ((c = XisbRead(priv->comm.buffer)) >= 0) {
	    unsigned char u = (unsigned char)c;
	    xf86write(priv->fifofd, &u, 1);
	    if (++count >= 3)
		break;
	}
	return FALSE;
    }
808 809
    return priv->proto_ops->ReadHwState(local, &priv->synhw, priv->proto_ops,
					&priv->comm, hw);
810
}
811 812 813 814

/*
 *  called for each full received packet from the touchpad
 */
815 816
static void
ReadInput(LocalDevicePtr local)
817
{
818
    SynapticsPrivate *priv = (SynapticsPrivate *) (local->private);
819
    struct SynapticsHwState hw;
820 821
    int delay = 0;
    Bool newDelay = FALSE;
822

823 824 825 826
    while (SynapticsGetHwState(local, priv, &hw)) {
	hw.millis = GetTimeInMillis();
	priv->hwState = hw;
	delay = HandleState(local, &hw);
827 828
	newDelay = TRUE;
    }
829

830 831
    if (newDelay)
	priv->timer = TimerSet(priv->timer, 0, delay, timerFunc, local);
832 833 834
}

static int
835
HandleMidButtonEmulation(SynapticsPrivate *priv, struct SynapticsHwState *hw, int *delay)
836
{
837
    SynapticsSHM *para = priv->synpara;
838
    Bool done = FALSE;
839
    int timeleft;
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
    int mid = 0;

    while (!done) {
	switch (priv->mid_emu_state) {
	case MBE_OFF:
	    priv->button_delay_millis = hw->millis;
	    if (hw->left) {
		priv->mid_emu_state = MBE_LEFT;
	    } else if (hw->right) {
		priv->mid_emu_state = MBE_RIGHT;
	    } else {
		done = TRUE;
	    }
	    break;
	case MBE_LEFT:
	    timeleft = TIME_DIFF(priv->button_delay_millis + para->emulate_mid_button_time,
				 hw->millis);
	    if (timeleft > 0)
		*delay = MIN(*delay, timeleft);
	    if (!hw->left || (timeleft <= 0)) {
		hw->left = TRUE;
		priv->mid_emu_state = MBE_TIMEOUT;
		done = TRUE;
	    } else if (hw->right) {
		priv->mid_emu_state = MBE_MID;
	    } else {
		hw->left = FALSE;
		done = TRUE;
	    }
	    break;
	case MBE_RIGHT:
	    timeleft = TIME_DIFF(priv->button_delay_millis + para->emulate_mid_button_time,
				 hw->millis);
	    if (timeleft > 0)
		*delay = MIN(*delay, timeleft);
	    if (!hw->right || (timeleft <= 0)) {
		hw->right = TRUE;
		priv->mid_emu_state = MBE_TIMEOUT;
		done = TRUE;
	    } else if (hw->left) {
		priv->mid_emu_state = MBE_MID;
	    } else {
		hw->right = FALSE;
		done = TRUE;
	    }
	    break;
	case MBE_MID:
	    if (!hw->left && !hw->right) {
		priv->mid_emu_state = MBE_OFF;
	    } else {
		mid = TRUE;
		hw->left = hw->right = FALSE;
		done = TRUE;
	    }
	    break;
	case MBE_TIMEOUT:
	    if (!hw->left && !hw->right) {
		priv->mid_emu_state = MBE_OFF;
	    } else {
		done = TRUE;
	    }
901
	}
902 903
    }
    return mid;
904 905
}

906
static int
907
SynapticsDetectFinger(SynapticsPrivate *priv, struct SynapticsHwState *hw)
908
{
909
    SynapticsSHM *para = priv->synpara;
910 911 912 913 914 915
    int finger;

    /* finger detection thru pressure and threshold */
    finger = (((hw->z > para->finger_high) && !priv->finger_flag) ||
	      ((hw->z > para->finger_low)  &&  priv->finger_flag));

916
    if (!para->palm_detect)
Peter Osterlund's avatar
Peter Osterlund committed
917
	return finger;
918

919
    /* palm detection */
920
    if (finger) {
921
	if ((hw->z > para->palm_min_z) && (hw->fingerWidth > para->palm_min_width))
922 923 924 925
	    priv->palm = TRUE;
    } else {
	priv->palm = FALSE;
    }
926
    if (hw->x == 0)
927
	priv->avg_width = 0;
928
    else
929
	priv->avg_width += (hw->fingerWidth - priv->avg_width + 1) / 2;
930
    if (finger && !priv->finger_flag) {
931
	int safe_width = MAX(hw->fingerWidth, priv->avg_width);
932
	if (hw->numFingers > 1)
933 934 935 936 937 938
	    finger = TRUE;			/* more than one finger -> not a palm */
	else if ((safe_width < 6) && (priv->prev_z < para->finger_high))
	    finger = TRUE;			/* thin finger, distinct touch -> not a palm */
	else if ((safe_width < 7) && (priv->prev_z < para->finger_high / 2))
	    finger = TRUE;			/* thin finger, distinct touch -> not a palm */
	else if (hw->z > priv->prev_z + 1)	/* z not stable, may be a palm */
939
	    finger = FALSE;
940
	else if (hw->z < priv->prev_z - 5)	/* z not stable, may be a palm */
941
	    finger = FALSE;
942
	else if (hw->z > para->palm_min_z)	/* z too large -> probably palm */