eventcomm.c 31.8 KB
Newer Older
1
/*
2
 * Copyright © 2004-2007 Peter Osterlund
3
 * Copyright © 2008-2012 Red Hat, Inc.
4
 *
5 6 7 8 9 10 11 12 13 14
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without
 * fee, provided that the above copyright notice appear in all copies
 * and that both that copyright notice and this permission notice
 * appear in supporting documentation, and that the name of Red Hat
 * not be used in advertising or publicity pertaining to distribution
 * of the software without specific, written prior permission.  Red
 * Hat makes no representations about the suitability of this software
 * for any purpose.  It is provided "as is" without express or implied
 * warranty.
15
 *
16 17 18 19 20 21 22
 * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23
 *
24 25
 * Authors:
 *      Peter Osterlund (petero2@telia.com)
26 27
 */

28 29 30 31
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

32
#include <xorg-server.h>
33
#include <xserver-properties.h>
34
#include "eventcomm.h"
35 36 37 38
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
39 40
#include <dirent.h>
#include <string.h>
41
#include <stdio.h>
42
#include "synproto.h"
43
#include "synapticsstr.h"
44
#include <xf86.h>
45 46
#include <mtdev-plumbing.h>
#include <libevdev/libevdev.h>
47

48 49 50 51 52 53
#ifndef INPUT_PROP_BUTTONPAD
#define INPUT_PROP_BUTTONPAD 0x02
#endif
#ifndef INPUT_PROP_SEMI_MT
#define INPUT_PROP_SEMI_MT 0x03
#endif
54 55 56

#define SYSCALL(call) while (((call) == -1) && (errno == EINTR))

57 58
#define LONG_BITS (sizeof(long) * 8)
#define NBITS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
59 60 61
#define OFF(x)   ((x) % LONG_BITS)
#define LONG(x)  ((x) / LONG_BITS)
#define TEST_BIT(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
62

63 64 65
/**
 * Protocol-specific data.
 */
Peter Hutterer's avatar
Peter Hutterer committed
66
struct eventcomm_proto_data {
67 68 69 70 71 72
    /**
     * Do we need to grab the event device?
     * Note that in the current flow, this variable is always false and
     * exists for readability of the code.
     */
    BOOL need_grab;
Peter Hutterer's avatar
Peter Hutterer committed
73 74
    int st_to_mt_offset[2];
    double st_to_mt_scale[2];
75
    struct mtdev *mtdev;
76
    int axis_map[MT_ABS_SIZE];
77 78
    int cur_slot;
    ValuatorMask **last_mt_vals;
79
    int num_touches;
80 81 82

    struct libevdev *evdev;
    enum libevdev_read_flag read_flag;
83
};
84

85
struct eventcomm_proto_data *
86
EventProtoDataAlloc(int fd)
87
{
88
    struct eventcomm_proto_data *proto_data;
89
    int rc;
90 91 92 93 94

    proto_data = calloc(1, sizeof(struct eventcomm_proto_data));
    if (!proto_data)
        return NULL;

Peter Hutterer's avatar
Peter Hutterer committed
95 96
    proto_data->st_to_mt_scale[0] = 1;
    proto_data->st_to_mt_scale[1] = 1;
97

98 99 100 101 102 103 104
    rc = libevdev_new_from_fd(fd, &proto_data->evdev);
    if (rc < 0) {
        free(proto_data);
        proto_data = NULL;
    } else
        proto_data->read_flag = LIBEVDEV_READ_FLAG_NORMAL;

105
    return proto_data;
106 107
}

108
static int
Peter Hutterer's avatar
Peter Hutterer committed
109
last_mt_vals_slot(const SynapticsPrivate * priv)
110
{
Peter Hutterer's avatar
Peter Hutterer committed
111 112
    struct eventcomm_proto_data *proto_data =
        (struct eventcomm_proto_data *) priv->proto_data;
113
    int value = proto_data->cur_slot;
114

115
    return value < priv->num_slots ? value : -1;
116 117 118 119 120
}

static void
UninitializeTouch(InputInfoPtr pInfo)
{
Peter Hutterer's avatar
Peter Hutterer committed
121 122 123
    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
    struct eventcomm_proto_data *proto_data =
        (struct eventcomm_proto_data *) priv->proto_data;
124

125
    if (!priv->has_touch)
126 127
        return;

Peter Hutterer's avatar
Peter Hutterer committed
128
    if (proto_data->last_mt_vals) {
129 130
        int i;

131
        for (i = 0; i < priv->num_slots; i++)
132 133 134 135 136
            valuator_mask_free(&proto_data->last_mt_vals[i]);
        free(proto_data->last_mt_vals);
        proto_data->last_mt_vals = NULL;
    }

137
    mtdev_close_delete(proto_data->mtdev);
138
    proto_data->mtdev = NULL;
139
    proto_data->num_touches = 0;
140 141 142 143 144
}

static void
InitializeTouch(InputInfoPtr pInfo)
{
Peter Hutterer's avatar
Peter Hutterer committed
145 146 147
    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
    struct eventcomm_proto_data *proto_data =
        (struct eventcomm_proto_data *) priv->proto_data;
148 149
    int i;

150 151 152
    if (!priv->has_touch)
        return;

153
    proto_data->mtdev = mtdev_new_open(pInfo->fd);
Peter Hutterer's avatar
Peter Hutterer committed
154
    if (!proto_data->mtdev) {
155 156 157 158 159 160
        xf86IDrvMsg(pInfo, X_WARNING,
                    "failed to create mtdev instance, ignoring touch events\n");
        return;
    }

    proto_data->cur_slot = proto_data->mtdev->caps.slot.value;
161
    proto_data->num_touches = 0;
162

Peter Hutterer's avatar
Peter Hutterer committed
163 164
    proto_data->last_mt_vals = calloc(priv->num_slots, sizeof(ValuatorMask *));
    if (!proto_data->last_mt_vals) {
165 166 167 168 169 170
        xf86IDrvMsg(pInfo, X_WARNING,
                    "failed to allocate MT last values mask array\n");
        UninitializeTouch(pInfo);
        return;
    }

Peter Hutterer's avatar
Peter Hutterer committed
171
    for (i = 0; i < priv->num_slots; i++) {
172 173 174
        int j;

        proto_data->last_mt_vals[i] = valuator_mask_new(4 + priv->num_mt_axes);
Peter Hutterer's avatar
Peter Hutterer committed
175
        if (!proto_data->last_mt_vals[i]) {
176 177 178 179 180 181 182 183 184 185
            xf86IDrvMsg(pInfo, X_WARNING,
                        "failed to allocate MT last values mask\n");
            UninitializeTouch(pInfo);
            return;
        }

        /* Axes 0-4 are for X, Y, and scrolling. num_mt_axes does not include X
         * and Y. */
        valuator_mask_set(proto_data->last_mt_vals[i], 0, 0);
        valuator_mask_set(proto_data->last_mt_vals[i], 1, 0);
186 187
        for (j = 0; j < priv->num_mt_axes; j++)
            valuator_mask_set(proto_data->last_mt_vals[i], 4 + j, 0);
188 189 190
    }
}

191
static Bool
Peter Hutterer's avatar
Peter Hutterer committed
192
EventDeviceOnHook(InputInfoPtr pInfo, SynapticsParameters * para)
193
{
Peter Hutterer's avatar
Peter Hutterer committed
194 195 196
    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
    struct eventcomm_proto_data *proto_data =
        (struct eventcomm_proto_data *) priv->proto_data;
197

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
    if (libevdev_get_fd(proto_data->evdev) != -1) {
        struct input_event ev;

        libevdev_change_fd(proto_data->evdev, pInfo->fd);

        /* re-sync libevdev's state, but we don't care about the actual
           events here */
        libevdev_next_event(proto_data->evdev, LIBEVDEV_READ_FLAG_FORCE_SYNC, &ev);
        while (libevdev_next_event(proto_data->evdev,
                    LIBEVDEV_READ_FLAG_SYNC, &ev) == LIBEVDEV_READ_STATUS_SYNC)
            ;

    } else
        libevdev_set_fd(proto_data->evdev, pInfo->fd);


214 215 216 217 218 219 220 221 222 223 224 225 226 227
    if (para->grab_event_device) {
        /* Try to grab the event device so that data don't leak to /dev/input/mice */
        int ret;

        ret = libevdev_grab(proto_data->evdev, LIBEVDEV_GRAB);
        if (ret < 0) {
            xf86IDrvMsg(pInfo, X_WARNING, "can't grab event device, errno=%d\n",
                        -ret);
            return FALSE;
        }
    }

    proto_data->need_grab = FALSE;

228
    InitializeTouch(pInfo);
229

230
    return TRUE;
231 232
}

233 234 235
static Bool
EventDeviceOffHook(InputInfoPtr pInfo)
{
236 237 238
    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
    struct eventcomm_proto_data *proto_data = priv->proto_data;

239
    UninitializeTouch(pInfo);
240
    libevdev_grab(proto_data->evdev, LIBEVDEV_UNGRAB);
241 242 243 244

    return Success;
}

245 246 247 248 249 250 251 252
/**
 * Test if the device on the file descriptior is recognized as touchpad
 * device. Required bits for touchpad recognition are:
 * - ABS_X + ABS_Y for absolute axes
 * - ABS_PRESSURE or BTN_TOUCH
 * - BTN_TOOL_FINGER
 * - BTN_TOOL_PEN is _not_ set
 *
253
 * @param evdev Libevdev handle
254 255 256 257 258
 * @param test_grab If true, test whether an EVIOCGRAB is possible on the
 * device. A failure to grab the event device returns in a failure.
 *
 * @return TRUE if the device is a touchpad or FALSE otherwise.
 */
259
static Bool
260
event_query_is_touchpad(struct libevdev *evdev, BOOL test_grab)
261
{
262
    int ret = FALSE, rc;
263

Peter Hutterer's avatar
Peter Hutterer committed
264
    if (test_grab) {
265
        rc = libevdev_grab(evdev, LIBEVDEV_GRAB);
266
        if (rc < 0)
267 268 269
            return FALSE;
    }

270
    /* Check for ABS_X, ABS_Y, ABS_PRESSURE and BTN_TOOL_FINGER */
271 272 273
    if (!libevdev_has_event_type(evdev, EV_SYN) ||
        !libevdev_has_event_type(evdev, EV_ABS) ||
        !libevdev_has_event_type(evdev, EV_KEY))
Peter Hutterer's avatar
Peter Hutterer committed
274
        goto unwind;
275

276 277
    if (!libevdev_has_event_code(evdev, EV_ABS, ABS_X) ||
        !libevdev_has_event_code(evdev, EV_ABS, ABS_Y))
Peter Hutterer's avatar
Peter Hutterer committed
278
        goto unwind;
279 280

    /* we expect touchpad either report raw pressure or touches */
281 282
    if (!libevdev_has_event_code(evdev, EV_KEY, BTN_TOUCH) &&
        !libevdev_has_event_code(evdev, EV_ABS, ABS_PRESSURE))
Peter Hutterer's avatar
Peter Hutterer committed
283
        goto unwind;
284

285
    /* all Synaptics-like touchpad report BTN_TOOL_FINGER */
286 287
    if (!libevdev_has_event_code(evdev, EV_KEY, BTN_TOOL_FINGER) ||
        libevdev_has_event_code(evdev, EV_ABS, BTN_TOOL_PEN)) /* Don't match wacom tablets */
Peter Hutterer's avatar
Peter Hutterer committed
288
        goto unwind;
289

290 291
    ret = TRUE;

Peter Hutterer's avatar
Peter Hutterer committed
292
 unwind:
293
    if (test_grab)
294
        libevdev_grab(evdev, LIBEVDEV_UNGRAB);
295

296
    return (ret == TRUE);
297 298
}

Peter Hutterer's avatar
Peter Hutterer committed
299 300 301
#define PRODUCT_ANY 0x0000

struct model_lookup_t {
Peter Hutterer's avatar
Peter Hutterer committed
302
    short vendor;
303 304
    short product_start;
    short product_end;
Peter Hutterer's avatar
Peter Hutterer committed
305
    enum TouchpadModel model;
Peter Hutterer's avatar
Peter Hutterer committed
306
};
Peter Hutterer's avatar
Peter Hutterer committed
307

308

Peter Hutterer's avatar
Peter Hutterer committed
309
static struct model_lookup_t model_lookup_table[] = {
310 311 312 313 314 315
    {0x0002, 0x0007, 0x0007, MODEL_SYNAPTICS},
    {0x0002, 0x0008, 0x0008, MODEL_ALPS},
    {0x05ac, PRODUCT_ANY, 0x222, MODEL_APPLETOUCH},
    {0x05ac, 0x223, PRODUCT_ANY, MODEL_UNIBODY_MACBOOK},
    {0x0002, 0x000e, 0x000e, MODEL_ELANTECH},
    {0x0, 0x0, 0x0, 0x0}
316 317
};

318 319 320 321 322 323 324 325 326 327 328
/**
 * Check for the vendor/product id on the file descriptor and compare
 * with the built-in model LUT. This information is used in synaptics.c to
 * initialize model-specific dimensions.
 *
 * @param fd The file descriptor to a event device.
 * @param[out] model_out The type of touchpad model detected.
 *
 * @return TRUE on success or FALSE otherwise.
 */
static Bool
329
event_query_model(struct libevdev *evdev, enum TouchpadModel *model_out,
Peter Hutterer's avatar
Peter Hutterer committed
330
                  unsigned short *vendor_id, unsigned short *product_id)
331
{
332
    int vendor, product;
Peter Hutterer's avatar
Peter Hutterer committed
333
    struct model_lookup_t *model_lookup;
334

335 336
    vendor = libevdev_get_id_vendor(evdev);
    product = libevdev_get_id_product(evdev);
337

Peter Hutterer's avatar
Peter Hutterer committed
338 339
    for (model_lookup = model_lookup_table; model_lookup->vendor;
         model_lookup++) {
340
        if (model_lookup->vendor == vendor &&
341
            (model_lookup->product_start == PRODUCT_ANY ||
342
             model_lookup->product_start <= product) &&
343
            (model_lookup->product_end == PRODUCT_ANY ||
344
             model_lookup->product_end >= product))
345
            *model_out = model_lookup->model;
346
    }
347

348 349
    *vendor_id = vendor;
    *product_id = product;
350

351
    return TRUE;
352 353
}

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
/**
 * Get absinfo information from the given file descriptor for the given
 * ABS_FOO code and store the information in min, max, fuzz and res.
 *
 * @param fd File descriptor to an event device
 * @param code Event code (e.g. ABS_X)
 * @param[out] min Minimum axis range
 * @param[out] max Maximum axis range
 * @param[out] fuzz Fuzz of this axis. If NULL, fuzz is ignored.
 * @param[out] res Axis resolution. If NULL or the current kernel does not
 * support the resolution field, res is ignored
 *
 * @return Zero on success, or errno otherwise.
 */
static int
369
event_get_abs(struct libevdev *evdev, int code,
370
              int *min, int *max, int *fuzz, int *res)
371
{
372
    const struct input_absinfo *abs;
373

374 375 376
    abs = libevdev_get_abs_info(evdev, code);
    *min = abs->minimum;
    *max = abs->maximum;
377 378

    /* We dont trust a zero fuzz as it probably is just a lazy value */
379 380
    if (fuzz && abs->fuzz > 0)
        *fuzz = abs->fuzz;
381 382
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)
    if (res)
383
        *res = abs->resolution;
384 385 386 387 388
#endif

    return 0;
}

389
/* Query device for axis ranges */
390
static void
391
event_query_axis_ranges(InputInfoPtr pInfo)
392
{
Peter Hutterer's avatar
Peter Hutterer committed
393
    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
394
    struct eventcomm_proto_data *proto_data = priv->proto_data;
Peter Hutterer's avatar
Peter Hutterer committed
395
    char buf[256] = { 0 };
396

397 398
    /* The kernel's fuzziness concept seems a bit weird, but it can more or
     * less be applied as hysteresis directly, i.e. no factor here. */
399
    event_get_abs(proto_data->evdev, ABS_X, &priv->minx, &priv->maxx,
Peter Hutterer's avatar
Peter Hutterer committed
400
                  &priv->synpara.hyst_x, &priv->resx);
401

402
    event_get_abs(proto_data->evdev, ABS_Y, &priv->miny, &priv->maxy,
Peter Hutterer's avatar
Peter Hutterer committed
403
                  &priv->synpara.hyst_y, &priv->resy);
404

405 406
    priv->has_pressure = libevdev_has_event_code(proto_data->evdev, EV_ABS, ABS_PRESSURE);
    priv->has_width = libevdev_has_event_code(proto_data->evdev, EV_ABS, ABS_TOOL_WIDTH);
407 408

    if (priv->has_pressure)
409
        event_get_abs(proto_data->evdev, ABS_PRESSURE, &priv->minp, &priv->maxp,
Peter Hutterer's avatar
Peter Hutterer committed
410
                      NULL, NULL);
411

412
    if (priv->has_width)
413
        event_get_abs(proto_data->evdev, ABS_TOOL_WIDTH,
Peter Hutterer's avatar
Peter Hutterer committed
414
                      &priv->minw, &priv->maxw, NULL, NULL);
415

Peter Hutterer's avatar
Peter Hutterer committed
416
    if (priv->has_touch) {
417 418 419 420 421
        int st_minx = priv->minx;
        int st_maxx = priv->maxx;
        int st_miny = priv->miny;
        int st_maxy = priv->maxy;

422
        event_get_abs(proto_data->evdev, ABS_MT_POSITION_X, &priv->minx,
423
                      &priv->maxx, &priv->synpara.hyst_x, &priv->resx);
424
        event_get_abs(proto_data->evdev, ABS_MT_POSITION_Y, &priv->miny,
425 426
                      &priv->maxy, &priv->synpara.hyst_y, &priv->resy);

Peter Hutterer's avatar
Peter Hutterer committed
427 428
        proto_data->st_to_mt_offset[0] = priv->minx - st_minx;
        proto_data->st_to_mt_scale[0] =
429
            (priv->maxx - priv->minx) / (st_maxx - st_minx);
Peter Hutterer's avatar
Peter Hutterer committed
430 431
        proto_data->st_to_mt_offset[1] = priv->miny - st_miny;
        proto_data->st_to_mt_scale[1] =
432 433 434
            (priv->maxy - priv->miny) / (st_maxy - st_miny);
    }

435 436 437 438 439 440 441 442 443 444 445
    priv->has_left = libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_LEFT);
    priv->has_right = libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_RIGHT);
    priv->has_middle = libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_MIDDLE);
    priv->has_double = libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_TOOL_DOUBLETAP);
    priv->has_triple = libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_TOOL_TRIPLETAP);

    if (libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_0) ||
        libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_1) ||
        libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_2) ||
        libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_3))
        priv->has_scrollbuttons = 1;
446 447

    /* Now print the device information */
448 449 450 451
    xf86IDrvMsg(pInfo, X_PROBED, "x-axis range %d - %d (res %d)\n",
                priv->minx, priv->maxx, priv->resx);
    xf86IDrvMsg(pInfo, X_PROBED, "y-axis range %d - %d (res %d)\n",
                priv->miny, priv->maxy, priv->resy);
452
    if (priv->has_pressure)
Peter Hutterer's avatar
Peter Hutterer committed
453 454
        xf86IDrvMsg(pInfo, X_PROBED, "pressure range %d - %d\n",
                    priv->minp, priv->maxp);
455
    else
Peter Hutterer's avatar
Peter Hutterer committed
456 457
        xf86IDrvMsg(pInfo, X_INFO,
                    "device does not report pressure, will use touch data.\n");
458
    if (priv->has_width)
Peter Hutterer's avatar
Peter Hutterer committed
459 460
        xf86IDrvMsg(pInfo, X_PROBED, "finger width range %d - %d\n",
                    priv->minw, priv->maxw);
461
    else
Peter Hutterer's avatar
Peter Hutterer committed
462
        xf86IDrvMsg(pInfo, X_INFO, "device does not report finger width.\n");
463 464

    if (priv->has_left)
Peter Hutterer's avatar
Peter Hutterer committed
465
        strcat(buf, " left");
466
    if (priv->has_right)
Peter Hutterer's avatar
Peter Hutterer committed
467
        strcat(buf, " right");
468
    if (priv->has_middle)
Peter Hutterer's avatar
Peter Hutterer committed
469
        strcat(buf, " middle");
470
    if (priv->has_double)
Peter Hutterer's avatar
Peter Hutterer committed
471
        strcat(buf, " double");
472
    if (priv->has_triple)
Peter Hutterer's avatar
Peter Hutterer committed
473
        strcat(buf, " triple");
474
    if (priv->has_scrollbuttons)
Peter Hutterer's avatar
Peter Hutterer committed
475
        strcat(buf, " scroll-buttons");
476

477
    xf86IDrvMsg(pInfo, X_PROBED, "buttons:%s\n", buf);
478 479
}

480
static Bool
481
EventQueryHardware(InputInfoPtr pInfo)
482
{
Peter Hutterer's avatar
Peter Hutterer committed
483
    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
484
    struct eventcomm_proto_data *proto_data = priv->proto_data;
485

486 487
    if (!event_query_is_touchpad(proto_data->evdev,
                                 (proto_data) ? proto_data->need_grab : TRUE))
Peter Hutterer's avatar
Peter Hutterer committed
488
        return FALSE;
489

490
    xf86IDrvMsg(pInfo, X_PROBED, "touchpad found\n");
491 492

    return TRUE;
493
}
494

495
static Bool
496
SynapticsReadEvent(InputInfoPtr pInfo, struct input_event *ev)
497
{
Peter Hutterer's avatar
Peter Hutterer committed
498
    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
499
    struct eventcomm_proto_data *proto_data = priv->proto_data;
500 501 502
    int rc;
    int have_events = TRUE;
    static struct timeval last_event_time;
503

504 505 506 507
    /* empty mtdev queue first */
    if (proto_data->mtdev && !mtdev_empty(proto_data->mtdev)) {
        mtdev_get_event(proto_data->mtdev, ev);
        return TRUE;
Peter Hutterer's avatar
Peter Hutterer committed
508
    }
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528

    do {
        rc = libevdev_next_event(proto_data->evdev, proto_data->read_flag, ev);
        if (rc < 0) {
            if (rc != -EAGAIN) {
                LogMessageVerbSigSafe(X_ERROR, 0, "%s: Read error %d\n", pInfo->name,
                        errno);
            } else if (proto_data->read_flag == LIBEVDEV_READ_FLAG_SYNC)
                proto_data->read_flag = LIBEVDEV_READ_FLAG_NORMAL;
            have_events = FALSE;
        } else {
            have_events = TRUE;

            /* SYN_DROPPED received in normal mode. Create a normal EV_SYN
               so we process what's in the queue atm, then ensure we sync
               next time */
            if (rc == LIBEVDEV_READ_STATUS_SYNC &&
                proto_data->read_flag == LIBEVDEV_READ_FLAG_NORMAL) {
                proto_data->read_flag = LIBEVDEV_READ_FLAG_SYNC;
                ev->type = EV_SYN;
529
                ev->code = SYN_REPORT;
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
                ev->value = 0;
                ev->time = last_event_time;
            } else if (ev->type == EV_SYN)
                last_event_time = ev->time;

            /* feed mtdev. nomnomnomnom */
            if (proto_data->mtdev)
                mtdev_put_event(proto_data->mtdev, ev);
        }
    } while (have_events && proto_data->mtdev && mtdev_empty(proto_data->mtdev));

    /* loop exits if:
       - we don't have mtdev, ev is valid, rc is TRUE, let's return it
       - we have mtdev and it has events for us, get those
       - we don't have a new event and mtdev doesn't have events either.
     */
    if (have_events && proto_data->mtdev) {
        have_events = !mtdev_empty(proto_data->mtdev);
        if (have_events)
            mtdev_get_event(proto_data->mtdev, ev);
550
    }
551 552

    return have_events;
553 554
}

555
static Bool
Peter Hutterer's avatar
Peter Hutterer committed
556
EventTouchSlotPreviouslyOpen(SynapticsPrivate * priv, int slot)
557 558 559 560 561 562 563 564 565 566
{
    int i;

    for (i = 0; i < priv->num_active_touches; i++)
        if (priv->open_slots[i] == slot)
            return TRUE;

    return FALSE;
}

567
static void
568
EventProcessTouchEvent(InputInfoPtr pInfo, struct SynapticsHwState *hw,
569 570
                       struct input_event *ev)
{
Peter Hutterer's avatar
Peter Hutterer committed
571
    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
572 573
    struct eventcomm_proto_data *proto_data = priv->proto_data;

574 575 576
    if (!priv->has_touch)
        return;

Peter Hutterer's avatar
Peter Hutterer committed
577
    if (ev->code == ABS_MT_SLOT) {
578
        proto_data->cur_slot = ev->value;
Peter Hutterer's avatar
Peter Hutterer committed
579 580
    }
    else {
581
        int slot_index = last_mt_vals_slot(priv);
582

583 584 585
        if (slot_index < 0)
            return;

Chase Douglas's avatar
Chase Douglas committed
586
        if (hw->slot_state[slot_index] == SLOTSTATE_OPEN_EMPTY)
587
            hw->slot_state[slot_index] = SLOTSTATE_UPDATE;
Peter Hutterer's avatar
Peter Hutterer committed
588 589
        if (ev->code == ABS_MT_TRACKING_ID) {
            if (ev->value >= 0) {
590
                hw->slot_state[slot_index] = SLOTSTATE_OPEN;
591
                proto_data->num_touches++;
592 593
                valuator_mask_copy(hw->mt_mask[slot_index],
                                   proto_data->last_mt_vals[slot_index]);
Peter Hutterer's avatar
Peter Hutterer committed
594
            }
Chase Douglas's avatar
Chase Douglas committed
595
            else if (hw->slot_state[slot_index] != SLOTSTATE_EMPTY) {
596
                hw->slot_state[slot_index] = SLOTSTATE_CLOSE;
597 598
                proto_data->num_touches--;
            }
Peter Hutterer's avatar
Peter Hutterer committed
599 600
        }
        else {
601
            ValuatorMask *mask = proto_data->last_mt_vals[slot_index];
602
            int map = proto_data->axis_map[ev->code - ABS_MT_TOUCH_MAJOR];
603
            int last_val = valuator_mask_get(mask, map);
Peter Hutterer's avatar
Peter Hutterer committed
604

605
            valuator_mask_set(hw->mt_mask[slot_index], map, ev->value);
606 607 608 609 610
            if (EventTouchSlotPreviouslyOpen(priv, slot_index)) {
                if (ev->code == ABS_MT_POSITION_X)
                    hw->cumulative_dx += ev->value - last_val;
                else if (ev->code == ABS_MT_POSITION_Y)
                    hw->cumulative_dy += ev->value - last_val;
611
            }
612 613

            valuator_mask_set(mask, map, ev->value);
614 615 616 617
        }
    }
}

618 619 620 621 622 623 624 625
/**
 * Count the number of fingers based on the CommData information.
 * The CommData struct contains the event information based on previous
 * struct input_events, now we're just counting based on that.
 *
 * @param comm Assembled information from previous events.
 * @return The number of fingers currently set.
 */
Peter Hutterer's avatar
Peter Hutterer committed
626 627
static int
count_fingers(InputInfoPtr pInfo, const struct CommData *comm)
628
{
Peter Hutterer's avatar
Peter Hutterer committed
629
    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
630
    struct eventcomm_proto_data *proto_data = priv->proto_data;
631 632 633
    int fingers = 0;

    if (comm->oneFinger)
Peter Hutterer's avatar
Peter Hutterer committed
634
        fingers = 1;
635
    else if (comm->twoFingers)
Peter Hutterer's avatar
Peter Hutterer committed
636
        fingers = 2;
637
    else if (comm->threeFingers)
Peter Hutterer's avatar
Peter Hutterer committed
638
        fingers = 3;
639

640 641 642
    if (priv->has_touch && proto_data->num_touches > fingers)
        fingers = proto_data->num_touches;

643 644 645
    return fingers;
}

646 647 648
static inline double
apply_st_scaling(struct eventcomm_proto_data *proto_data, int value, int axis)
{
Peter Hutterer's avatar
Peter Hutterer committed
649 650
    return value * proto_data->st_to_mt_scale[axis] +
        proto_data->st_to_mt_offset[axis];
651 652
}

653
Bool
654
EventReadHwState(InputInfoPtr pInfo,
Peter Hutterer's avatar
Peter Hutterer committed
655
                 struct CommData *comm, struct SynapticsHwState *hwRet)
656 657 658
{
    struct input_event ev;
    Bool v;
659
    struct SynapticsHwState *hw = comm->hwState;
Peter Hutterer's avatar
Peter Hutterer committed
660
    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
661
    SynapticsParameters *para = &priv->synpara;
662
    struct eventcomm_proto_data *proto_data = priv->proto_data;
663
    Bool sync_cumulative = FALSE;
664

665
    SynapticsResetTouchHwState(hw, FALSE);
666

667 668 669
    /* Reset cumulative values if buttons were not previously pressed,
     * or no finger was previously present. */
    if ((!hw->left && !hw->right && !hw->middle) || hw->z < para->finger_low) {
670 671
        hw->cumulative_dx = hw->x;
        hw->cumulative_dy = hw->y;
672
        sync_cumulative = TRUE;
673 674
    }

675
    while (SynapticsReadEvent(pInfo, &ev)) {
Peter Hutterer's avatar
Peter Hutterer committed
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
        switch (ev.type) {
        case EV_SYN:
            switch (ev.code) {
            case SYN_REPORT:
                hw->numFingers = count_fingers(pInfo, comm);
                hw->millis = 1000 * ev.time.tv_sec + ev.time.tv_usec / 1000;
                SynapticsCopyHwState(hwRet, hw);
                return TRUE;
            }
            break;
        case EV_KEY:
            v = (ev.value ? TRUE : FALSE);
            switch (ev.code) {
            case BTN_LEFT:
                hw->left = v;
                break;
            case BTN_RIGHT:
                hw->right = v;
                break;
            case BTN_MIDDLE:
                hw->middle = v;
                break;
            case BTN_FORWARD:
                hw->up = v;
                break;
            case BTN_BACK:
                hw->down = v;
                break;
            case BTN_0:
                hw->multi[0] = v;
                break;
            case BTN_1:
                hw->multi[1] = v;
                break;
            case BTN_2:
                hw->multi[2] = v;
                break;
            case BTN_3:
                hw->multi[3] = v;
                break;
            case BTN_4:
                hw->multi[4] = v;
                break;
            case BTN_5:
                hw->multi[5] = v;
                break;
            case BTN_6:
                hw->multi[6] = v;
                break;
            case BTN_7:
                hw->multi[7] = v;
                break;
            case BTN_TOOL_FINGER:
                comm->oneFinger = v;
                break;
            case BTN_TOOL_DOUBLETAP:
                comm->twoFingers = v;
                break;
            case BTN_TOOL_TRIPLETAP:
                comm->threeFingers = v;
                break;
            case BTN_TOUCH:
                if (!priv->has_pressure)
                    hw->z = v ? para->finger_high + 1 : 0;
                break;
            }
            break;
        case EV_ABS:
            if (ev.code < ABS_MT_SLOT) {
                switch (ev.code) {
                case ABS_X:
                    hw->x = apply_st_scaling(proto_data, ev.value, 0);
748 749
                    if (sync_cumulative)
                        hw->cumulative_dx = hw->x;
Peter Hutterer's avatar
Peter Hutterer committed
750 751 752
                    break;
                case ABS_Y:
                    hw->y = apply_st_scaling(proto_data, ev.value, 1);
753 754
                    if (sync_cumulative)
                        hw->cumulative_dy = hw->y;
Peter Hutterer's avatar
Peter Hutterer committed
755 756 757 758 759 760 761 762 763 764 765 766 767
                    break;
                case ABS_PRESSURE:
                    hw->z = ev.value;
                    break;
                case ABS_TOOL_WIDTH:
                    hw->fingerWidth = ev.value;
                    break;
                }
            }
            else
                EventProcessTouchEvent(pInfo, hw, &ev);
            break;
        }
768 769 770
    }
    return FALSE;
}
771

772
/* filter for the AutoDevProbe scandir on /dev/input */
Peter Hutterer's avatar
Peter Hutterer committed
773 774 775 776
static int
EventDevOnly(const struct dirent *dir)
{
    return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0;
777 778
}

779 780 781
static void
event_query_touch(InputInfoPtr pInfo)
{
Peter Hutterer's avatar
Peter Hutterer committed
782
    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
Chase Douglas's avatar
Chase Douglas committed
783
    SynapticsParameters *para = &priv->synpara;
784 785 786 787
    struct eventcomm_proto_data *proto_data = priv->proto_data;
    struct mtdev *mtdev;
    int i;

788
    priv->max_touches = 0;
789 790
    priv->num_mt_axes = 0;

791
#ifdef EVIOCGPROP
792
    if (libevdev_has_property(proto_data->evdev, INPUT_PROP_SEMI_MT)) {
793 794
        xf86IDrvMsg(pInfo, X_INFO,
                    "ignoring touch events for semi-multitouch device\n");
795
        priv->has_semi_mt = TRUE;
796 797
    }

798
    if (libevdev_has_property(proto_data->evdev, INPUT_PROP_BUTTONPAD)) {
Chase Douglas's avatar
Chase Douglas committed
799 800 801
        xf86IDrvMsg(pInfo, X_INFO, "found clickpad property\n");
        para->clickpad = TRUE;
    }
802
#endif
Chase Douglas's avatar
Chase Douglas committed
803

804
    mtdev = mtdev_new_open(pInfo->fd);
Peter Hutterer's avatar
Peter Hutterer committed
805
    if (!mtdev) {
806 807 808 809 810
        xf86IDrvMsg(pInfo, X_WARNING,
                    "failed to open mtdev when querying touch capabilities\n");
        return;
    }

Peter Hutterer's avatar
Peter Hutterer committed
811 812 813
    for (i = 0; i < MT_ABS_SIZE; i++) {
        if (mtdev->caps.has_abs[i]) {
            switch (i) {
814
                /* X and Y axis info is handed by synaptics already */
Peter Hutterer's avatar
Peter Hutterer committed
815 816
            case ABS_MT_POSITION_X - ABS_MT_TOUCH_MAJOR:
            case ABS_MT_POSITION_Y - ABS_MT_TOUCH_MAJOR:
817
                /* Skip tracking ID info */
Peter Hutterer's avatar
Peter Hutterer committed
818 819 820 821 822
            case ABS_MT_TRACKING_ID - ABS_MT_TOUCH_MAJOR:
                break;
            default:
                priv->num_mt_axes++;
                break;
823 824 825 826 827
            }
            priv->has_touch = TRUE;
        }
    }

Peter Hutterer's avatar
Peter Hutterer committed
828
    if (priv->has_touch) {
829
        int axnum;
Peter Hutterer's avatar
Peter Hutterer committed
830 831

        static const char *labels[] = {
832 833 834 835 836 837 838 839 840 841 842 843 844 845
            AXIS_LABEL_PROP_ABS_MT_TOUCH_MAJOR,
            AXIS_LABEL_PROP_ABS_MT_TOUCH_MINOR,
            AXIS_LABEL_PROP_ABS_MT_WIDTH_MAJOR,
            AXIS_LABEL_PROP_ABS_MT_WIDTH_MINOR,
            AXIS_LABEL_PROP_ABS_MT_ORIENTATION,
            AXIS_LABEL_PROP_ABS_MT_POSITION_X,
            AXIS_LABEL_PROP_ABS_MT_POSITION_Y,
            AXIS_LABEL_PROP_ABS_MT_TOOL_TYPE,
            AXIS_LABEL_PROP_ABS_MT_BLOB_ID,
            AXIS_LABEL_PROP_ABS_MT_TRACKING_ID,
            AXIS_LABEL_PROP_ABS_MT_PRESSURE,
        };

        if (mtdev->caps.slot.maximum > 0)
846
            priv->max_touches = mtdev->caps.slot.maximum -
Peter Hutterer's avatar
Peter Hutterer committed
847
                mtdev->caps.slot.minimum + 1;
848 849 850

        priv->touch_axes = malloc(priv->num_mt_axes *
                                  sizeof(SynapticsTouchAxisRec));
Peter Hutterer's avatar
Peter Hutterer committed
851
        if (!priv->touch_axes) {
852 853 854 855 856
            priv->has_touch = FALSE;
            goto out;
        }

        axnum = 0;
Peter Hutterer's avatar
Peter Hutterer committed
857 858 859
        for (i = 0; i < MT_ABS_SIZE; i++) {
            if (mtdev->caps.has_abs[i]) {
                switch (i) {
860 861
                    /* X and Y axis info is handed by synaptics already, we just
                     * need to map the evdev codes to the valuator numbers */