1/*
2 * Copyright © 2004-2007 Peter Osterlund
3 * Copyright © 2008-2012 Red Hat, Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without
7 * fee, provided that the above copyright notice appear in all copies
8 * and that both that copyright notice and this permission notice
9 * appear in supporting documentation, and that the name of Red Hat
10 * not be used in advertising or publicity pertaining to distribution
11 * of the software without specific, written prior permission.  Red
12 * Hat makes no representations about the suitability of this software
13 * for any purpose.  It is provided "as is" without express or implied
14 * warranty.
15 *
16 * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
18 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
20 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
21 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 *
24 * Authors:
25 *      Peter Osterlund (petero2@telia.com)
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include <xorg-server.h>
33#include <xserver-properties.h>
34#include "eventcomm.h"
35#include <errno.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <fcntl.h>
39#include <dirent.h>
40#include <string.h>
41#include <stdio.h>
42#include "synproto.h"
43#include "synapticsstr.h"
44#include <xf86.h>
45#include <mtdev.h>
46
47#ifndef INPUT_PROP_BUTTONPAD
48#define INPUT_PROP_BUTTONPAD 0x02
49#endif
50#ifndef INPUT_PROP_SEMI_MT
51#define INPUT_PROP_SEMI_MT 0x03
52#endif
53
54#define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
55
56#define LONG_BITS (sizeof(long) * 8)
57#define NBITS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
58#define OFF(x)   ((x) % LONG_BITS)
59#define LONG(x)  ((x) / LONG_BITS)
60#define TEST_BIT(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
61
62/**
63 * Protocol-specific data.
64 */
65struct eventcomm_proto_data {
66    /**
67     * Do we need to grab the event device?
68     * Note that in the current flow, this variable is always false and
69     * exists for readability of the code.
70     */
71    BOOL need_grab;
72    int st_to_mt_offset[2];
73    double st_to_mt_scale[2];
74    struct mtdev *mtdev;
75    int axis_map[MT_ABS_SIZE];
76    int cur_slot;
77    ValuatorMask **last_mt_vals;
78    int num_touches;
79};
80
81struct eventcomm_proto_data *
82EventProtoDataAlloc(void)
83{
84    struct eventcomm_proto_data *proto_data;
85
86    proto_data = calloc(1, sizeof(struct eventcomm_proto_data));
87    if (!proto_data)
88        return NULL;
89
90    proto_data->st_to_mt_scale[0] = 1;
91    proto_data->st_to_mt_scale[1] = 1;
92
93    return proto_data;
94}
95
96static int
97last_mt_vals_slot(const SynapticsPrivate * priv)
98{
99    struct eventcomm_proto_data *proto_data =
100        (struct eventcomm_proto_data *) priv->proto_data;
101    int value = proto_data->cur_slot - proto_data->mtdev->caps.slot.minimum;
102
103    return value < priv->num_slots ? value : -1;
104}
105
106static void
107UninitializeTouch(InputInfoPtr pInfo)
108{
109    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
110    struct eventcomm_proto_data *proto_data =
111        (struct eventcomm_proto_data *) priv->proto_data;
112
113    if (!priv->has_touch)
114        return;
115
116    if (proto_data->last_mt_vals) {
117        int i;
118
119        for (i = 0; i < priv->num_slots; i++)
120            valuator_mask_free(&proto_data->last_mt_vals[i]);
121        free(proto_data->last_mt_vals);
122        proto_data->last_mt_vals = NULL;
123    }
124
125    mtdev_close_delete(proto_data->mtdev);
126    proto_data->mtdev = NULL;
127    proto_data->num_touches = 0;
128}
129
130static void
131InitializeTouch(InputInfoPtr pInfo)
132{
133    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
134    struct eventcomm_proto_data *proto_data =
135        (struct eventcomm_proto_data *) priv->proto_data;
136    int i;
137
138    if (!priv->has_touch)
139        return;
140
141    proto_data->mtdev = mtdev_new_open(pInfo->fd);
142    if (!proto_data->mtdev) {
143        xf86IDrvMsg(pInfo, X_WARNING,
144                    "failed to create mtdev instance, ignoring touch events\n");
145        return;
146    }
147
148    proto_data->cur_slot = proto_data->mtdev->caps.slot.value;
149    proto_data->num_touches = 0;
150
151    proto_data->last_mt_vals = calloc(priv->num_slots, sizeof(ValuatorMask *));
152    if (!proto_data->last_mt_vals) {
153        xf86IDrvMsg(pInfo, X_WARNING,
154                    "failed to allocate MT last values mask array\n");
155        UninitializeTouch(pInfo);
156        return;
157    }
158
159    for (i = 0; i < priv->num_slots; i++) {
160        int j;
161
162        proto_data->last_mt_vals[i] = valuator_mask_new(4 + priv->num_mt_axes);
163        if (!proto_data->last_mt_vals[i]) {
164            xf86IDrvMsg(pInfo, X_WARNING,
165                        "failed to allocate MT last values mask\n");
166            UninitializeTouch(pInfo);
167            return;
168        }
169
170        /* Axes 0-4 are for X, Y, and scrolling. num_mt_axes does not include X
171         * and Y. */
172        valuator_mask_set(proto_data->last_mt_vals[i], 0, 0);
173        valuator_mask_set(proto_data->last_mt_vals[i], 1, 0);
174        for (j = 0; j < priv->num_mt_axes; j++)
175            valuator_mask_set(proto_data->last_mt_vals[i], 4 + j, 0);
176    }
177}
178
179static Bool
180EventDeviceOnHook(InputInfoPtr pInfo, SynapticsParameters * para)
181{
182    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
183    struct eventcomm_proto_data *proto_data =
184        (struct eventcomm_proto_data *) priv->proto_data;
185
186    if (para->grab_event_device) {
187        /* Try to grab the event device so that data don't leak to /dev/input/mice */
188        int ret;
189
190        SYSCALL(ret = ioctl(pInfo->fd, EVIOCGRAB, (pointer) 1));
191        if (ret < 0) {
192            xf86IDrvMsg(pInfo, X_WARNING, "can't grab event device, errno=%d\n",
193                        errno);
194            return FALSE;
195        }
196    }
197
198    proto_data->need_grab = FALSE;
199
200    InitializeTouch(pInfo);
201
202    return TRUE;
203}
204
205static Bool
206EventDeviceOffHook(InputInfoPtr pInfo)
207{
208    UninitializeTouch(pInfo);
209
210    return Success;
211}
212
213/**
214 * Test if the device on the file descriptior is recognized as touchpad
215 * device. Required bits for touchpad recognition are:
216 * - ABS_X + ABS_Y for absolute axes
217 * - ABS_PRESSURE or BTN_TOUCH
218 * - BTN_TOOL_FINGER
219 * - BTN_TOOL_PEN is _not_ set
220 *
221 * @param fd The file descriptor to an event device.
222 * @param test_grab If true, test whether an EVIOCGRAB is possible on the
223 * device. A failure to grab the event device returns in a failure.
224 *
225 * @return TRUE if the device is a touchpad or FALSE otherwise.
226 */
227static Bool
228event_query_is_touchpad(int fd, BOOL test_grab)
229{
230    int ret = FALSE, rc;
231    unsigned long evbits[NBITS(EV_MAX)] = { 0 };
232    unsigned long absbits[NBITS(ABS_MAX)] = { 0 };
233    unsigned long keybits[NBITS(KEY_MAX)] = { 0 };
234
235    if (test_grab) {
236        SYSCALL(rc = ioctl(fd, EVIOCGRAB, (pointer) 1));
237        if (rc < 0)
238            return FALSE;
239    }
240
241    /* Check for ABS_X, ABS_Y, ABS_PRESSURE and BTN_TOOL_FINGER */
242
243    SYSCALL(rc = ioctl(fd, EVIOCGBIT(0, sizeof(evbits)), evbits));
244    if (rc < 0)
245        goto unwind;
246    if (!TEST_BIT(EV_SYN, evbits) ||
247        !TEST_BIT(EV_ABS, evbits) || !TEST_BIT(EV_KEY, evbits))
248        goto unwind;
249
250    SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits));
251    if (rc < 0)
252        goto unwind;
253    if (!TEST_BIT(ABS_X, absbits) || !TEST_BIT(ABS_Y, absbits))
254        goto unwind;
255
256    SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits));
257    if (rc < 0)
258        goto unwind;
259
260    /* we expect touchpad either report raw pressure or touches */
261    if (!TEST_BIT(ABS_PRESSURE, absbits) && !TEST_BIT(BTN_TOUCH, keybits))
262        goto unwind;
263    /* all Synaptics-like touchpad report BTN_TOOL_FINGER */
264    if (!TEST_BIT(BTN_TOOL_FINGER, keybits))
265        goto unwind;
266    if (TEST_BIT(BTN_TOOL_PEN, keybits))
267        goto unwind;            /* Don't match wacom tablets */
268
269    ret = TRUE;
270
271 unwind:
272    if (test_grab)
273        SYSCALL(ioctl(fd, EVIOCGRAB, (pointer) 0));
274
275    return (ret == TRUE);
276}
277
278#define PRODUCT_ANY 0x0000
279
280struct model_lookup_t {
281    short vendor;
282    short product_start;
283    short product_end;
284    enum TouchpadModel model;
285};
286
287
288static struct model_lookup_t model_lookup_table[] = {
289    {0x0002, 0x0007, 0x0007, MODEL_SYNAPTICS},
290    {0x0002, 0x0008, 0x0008, MODEL_ALPS},
291    {0x05ac, PRODUCT_ANY, 0x222, MODEL_APPLETOUCH},
292    {0x05ac, 0x223, PRODUCT_ANY, MODEL_UNIBODY_MACBOOK},
293    {0x0002, 0x000e, 0x000e, MODEL_ELANTECH},
294    {0x0, 0x0, 0x0, 0x0}
295};
296
297/**
298 * Check for the vendor/product id on the file descriptor and compare
299 * with the built-in model LUT. This information is used in synaptics.c to
300 * initialize model-specific dimensions.
301 *
302 * @param fd The file descriptor to a event device.
303 * @param[out] model_out The type of touchpad model detected.
304 *
305 * @return TRUE on success or FALSE otherwise.
306 */
307static Bool
308event_query_model(int fd, enum TouchpadModel *model_out,
309                  unsigned short *vendor_id, unsigned short *product_id)
310{
311    struct input_id id;
312    int rc;
313    struct model_lookup_t *model_lookup;
314
315    SYSCALL(rc = ioctl(fd, EVIOCGID, &id));
316    if (rc < 0)
317        return FALSE;
318
319    for (model_lookup = model_lookup_table; model_lookup->vendor;
320         model_lookup++) {
321        if (model_lookup->vendor == id.vendor &&
322            (model_lookup->product_start == PRODUCT_ANY ||
323             model_lookup->product_start <= id.product) &&
324            (model_lookup->product_end == PRODUCT_ANY ||
325             model_lookup->product_end >= id.product))
326            *model_out = model_lookup->model;
327    }
328
329    *vendor_id = id.vendor;
330    *product_id = id.product;
331
332    return TRUE;
333}
334
335/**
336 * Get absinfo information from the given file descriptor for the given
337 * ABS_FOO code and store the information in min, max, fuzz and res.
338 *
339 * @param fd File descriptor to an event device
340 * @param code Event code (e.g. ABS_X)
341 * @param[out] min Minimum axis range
342 * @param[out] max Maximum axis range
343 * @param[out] fuzz Fuzz of this axis. If NULL, fuzz is ignored.
344 * @param[out] res Axis resolution. If NULL or the current kernel does not
345 * support the resolution field, res is ignored
346 *
347 * @return Zero on success, or errno otherwise.
348 */
349static int
350event_get_abs(InputInfoPtr pInfo, int fd, int code,
351              int *min, int *max, int *fuzz, int *res)
352{
353    int rc;
354    struct input_absinfo abs = { 0 };
355
356    SYSCALL(rc = ioctl(fd, EVIOCGABS(code), &abs));
357    if (rc < 0) {
358        xf86IDrvMsg(pInfo, X_ERROR, "%s EVIOCGABS error on %d (%s)\n",
359                    __func__, code, strerror(errno));
360        return errno;
361    }
362
363    *min = abs.minimum;
364    *max = abs.maximum;
365    /* We dont trust a zero fuzz as it probably is just a lazy value */
366    if (fuzz && abs.fuzz > 0)
367        *fuzz = abs.fuzz;
368#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)
369    if (res)
370        *res = abs.resolution;
371#endif
372
373    return 0;
374}
375
376/* Query device for axis ranges */
377static void
378event_query_axis_ranges(InputInfoPtr pInfo)
379{
380    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
381    struct eventcomm_proto_data *proto_data = priv->proto_data;
382    unsigned long absbits[NBITS(ABS_MAX)] = { 0 };
383    unsigned long keybits[NBITS(KEY_MAX)] = { 0 };
384    char buf[256] = { 0 };
385    int rc;
386
387    /* The kernel's fuzziness concept seems a bit weird, but it can more or
388     * less be applied as hysteresis directly, i.e. no factor here. */
389    event_get_abs(pInfo, pInfo->fd, ABS_X, &priv->minx, &priv->maxx,
390                  &priv->synpara.hyst_x, &priv->resx);
391
392    event_get_abs(pInfo, pInfo->fd, ABS_Y, &priv->miny, &priv->maxy,
393                  &priv->synpara.hyst_y, &priv->resy);
394
395    priv->has_pressure = FALSE;
396    priv->has_width = FALSE;
397    SYSCALL(rc = ioctl(pInfo->fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits));
398    if (rc >= 0) {
399        priv->has_pressure = (TEST_BIT(ABS_PRESSURE, absbits) != 0);
400        priv->has_width = (TEST_BIT(ABS_TOOL_WIDTH, absbits) != 0);
401    }
402    else
403        xf86IDrvMsg(pInfo, X_ERROR, "failed to query ABS bits (%s)\n",
404                    strerror(errno));
405
406    if (priv->has_pressure)
407        event_get_abs(pInfo, pInfo->fd, ABS_PRESSURE, &priv->minp, &priv->maxp,
408                      NULL, NULL);
409
410    if (priv->has_width)
411        event_get_abs(pInfo, pInfo->fd, ABS_TOOL_WIDTH,
412                      &priv->minw, &priv->maxw, NULL, NULL);
413
414    if (priv->has_touch) {
415        int st_minx = priv->minx;
416        int st_maxx = priv->maxx;
417        int st_miny = priv->miny;
418        int st_maxy = priv->maxy;
419
420        event_get_abs(pInfo, pInfo->fd, ABS_MT_POSITION_X, &priv->minx,
421                      &priv->maxx, &priv->synpara.hyst_x, &priv->resx);
422        event_get_abs(pInfo, pInfo->fd, ABS_MT_POSITION_Y, &priv->miny,
423                      &priv->maxy, &priv->synpara.hyst_y, &priv->resy);
424
425        proto_data->st_to_mt_offset[0] = priv->minx - st_minx;
426        proto_data->st_to_mt_scale[0] =
427            (priv->maxx - priv->minx) / (st_maxx - st_minx);
428        proto_data->st_to_mt_offset[1] = priv->miny - st_miny;
429        proto_data->st_to_mt_scale[1] =
430            (priv->maxy - priv->miny) / (st_maxy - st_miny);
431    }
432
433    SYSCALL(rc = ioctl(pInfo->fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits));
434    if (rc >= 0) {
435        priv->has_left = (TEST_BIT(BTN_LEFT, keybits) != 0);
436        priv->has_right = (TEST_BIT(BTN_RIGHT, keybits) != 0);
437        priv->has_middle = (TEST_BIT(BTN_MIDDLE, keybits) != 0);
438        priv->has_double = (TEST_BIT(BTN_TOOL_DOUBLETAP, keybits) != 0);
439        priv->has_triple = (TEST_BIT(BTN_TOOL_TRIPLETAP, keybits) != 0);
440
441        if ((TEST_BIT(BTN_0, keybits) != 0) ||
442            (TEST_BIT(BTN_1, keybits) != 0) ||
443            (TEST_BIT(BTN_2, keybits) != 0) || (TEST_BIT(BTN_3, keybits) != 0))
444            priv->has_scrollbuttons = 1;
445    }
446
447    /* Now print the device information */
448    xf86IDrvMsg(pInfo, X_PROBED, "x-axis range %d - %d (res %d)\n",
449                priv->minx, priv->maxx, priv->resx);
450    xf86IDrvMsg(pInfo, X_PROBED, "y-axis range %d - %d (res %d)\n",
451                priv->miny, priv->maxy, priv->resy);
452    if (priv->has_pressure)
453        xf86IDrvMsg(pInfo, X_PROBED, "pressure range %d - %d\n",
454                    priv->minp, priv->maxp);
455    else
456        xf86IDrvMsg(pInfo, X_INFO,
457                    "device does not report pressure, will use touch data.\n");
458    if (priv->has_width)
459        xf86IDrvMsg(pInfo, X_PROBED, "finger width range %d - %d\n",
460                    priv->minw, priv->maxw);
461    else
462        xf86IDrvMsg(pInfo, X_INFO, "device does not report finger width.\n");
463
464    if (priv->has_left)
465        strcat(buf, " left");
466    if (priv->has_right)
467        strcat(buf, " right");
468    if (priv->has_middle)
469        strcat(buf, " middle");
470    if (priv->has_double)
471        strcat(buf, " double");
472    if (priv->has_triple)
473        strcat(buf, " triple");
474    if (priv->has_scrollbuttons)
475        strcat(buf, " scroll-buttons");
476
477    xf86IDrvMsg(pInfo, X_PROBED, "buttons:%s\n", buf);
478}
479
480static Bool
481EventQueryHardware(InputInfoPtr pInfo)
482{
483    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
484    struct eventcomm_proto_data *proto_data = priv->proto_data;
485
486    if (!event_query_is_touchpad
487        (pInfo->fd, (proto_data) ? proto_data->need_grab : TRUE))
488        return FALSE;
489
490    xf86IDrvMsg(pInfo, X_PROBED, "touchpad found\n");
491
492    return TRUE;
493}
494
495static Bool
496SynapticsReadEvent(InputInfoPtr pInfo, struct input_event *ev)
497{
498    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
499    struct eventcomm_proto_data *proto_data = priv->proto_data;
500    int rc = TRUE;
501    ssize_t len;
502
503    if (proto_data->mtdev)
504        len = mtdev_get(proto_data->mtdev, pInfo->fd, ev, 1) *
505            sizeof(struct input_event);
506    else
507        len = read(pInfo->fd, ev, sizeof(*ev));
508    if (len <= 0) {
509        /* We use X_NONE here because it doesn't alloc */
510        if (errno != EAGAIN)
511            LogMessageVerbSigSafe(X_ERROR, 0, "%s: Read error %d\n", pInfo->name,
512                                  errno);
513        rc = FALSE;
514    }
515    else if (len % sizeof(*ev)) {
516        LogMessageVerbSigSafe(X_ERROR, 0, "%s: Read error, invalid number of bytes.",
517                              pInfo->name);
518        rc = FALSE;
519    }
520    return rc;
521}
522
523static Bool
524EventTouchSlotPreviouslyOpen(SynapticsPrivate * priv, int slot)
525{
526    int i;
527
528    for (i = 0; i < priv->num_active_touches; i++)
529        if (priv->open_slots[i] == slot)
530            return TRUE;
531
532    return FALSE;
533}
534
535static void
536EventProcessTouchEvent(InputInfoPtr pInfo, struct SynapticsHwState *hw,
537                       struct input_event *ev)
538{
539    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
540    struct eventcomm_proto_data *proto_data = priv->proto_data;
541
542    if (!priv->has_touch)
543        return;
544
545    if (ev->code == ABS_MT_SLOT) {
546        proto_data->cur_slot = ev->value;
547    }
548    else {
549        int slot_index = last_mt_vals_slot(priv);
550
551        if (slot_index < 0)
552            return;
553
554        if (hw->slot_state[slot_index] == SLOTSTATE_OPEN_EMPTY)
555            hw->slot_state[slot_index] = SLOTSTATE_UPDATE;
556        if (ev->code == ABS_MT_TRACKING_ID) {
557            if (ev->value >= 0) {
558                hw->slot_state[slot_index] = SLOTSTATE_OPEN;
559                proto_data->num_touches++;
560                valuator_mask_copy(hw->mt_mask[slot_index],
561                                   proto_data->last_mt_vals[slot_index]);
562            }
563            else if (hw->slot_state[slot_index] != SLOTSTATE_EMPTY) {
564                hw->slot_state[slot_index] = SLOTSTATE_CLOSE;
565                proto_data->num_touches--;
566            }
567        }
568        else {
569            ValuatorMask *mask = proto_data->last_mt_vals[slot_index];
570            int map = proto_data->axis_map[ev->code - ABS_MT_TOUCH_MAJOR];
571            int last_val = valuator_mask_get(mask, map);
572
573            valuator_mask_set(hw->mt_mask[slot_index], map, ev->value);
574            if (EventTouchSlotPreviouslyOpen(priv, slot_index)) {
575                if (ev->code == ABS_MT_POSITION_X)
576                    hw->cumulative_dx += ev->value - last_val;
577                else if (ev->code == ABS_MT_POSITION_Y)
578                    hw->cumulative_dy += ev->value - last_val;
579            }
580
581            valuator_mask_set(mask, map, ev->value);
582        }
583    }
584}
585
586/**
587 * Count the number of fingers based on the CommData information.
588 * The CommData struct contains the event information based on previous
589 * struct input_events, now we're just counting based on that.
590 *
591 * @param comm Assembled information from previous events.
592 * @return The number of fingers currently set.
593 */
594static int
595count_fingers(InputInfoPtr pInfo, const struct CommData *comm)
596{
597    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
598    struct eventcomm_proto_data *proto_data = priv->proto_data;
599    int fingers = 0;
600
601    if (comm->oneFinger)
602        fingers = 1;
603    else if (comm->twoFingers)
604        fingers = 2;
605    else if (comm->threeFingers)
606        fingers = 3;
607
608    if (priv->has_touch && proto_data->num_touches > fingers)
609        fingers = proto_data->num_touches;
610
611    return fingers;
612}
613
614static inline double
615apply_st_scaling(struct eventcomm_proto_data *proto_data, int value, int axis)
616{
617    return value * proto_data->st_to_mt_scale[axis] +
618        proto_data->st_to_mt_offset[axis];
619}
620
621Bool
622EventReadHwState(InputInfoPtr pInfo,
623                 struct CommData *comm, struct SynapticsHwState *hwRet)
624{
625    struct input_event ev;
626    Bool v;
627    struct SynapticsHwState *hw = comm->hwState;
628    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
629    SynapticsParameters *para = &priv->synpara;
630    struct eventcomm_proto_data *proto_data = priv->proto_data;
631
632    SynapticsResetTouchHwState(hw, FALSE);
633
634    /* Reset cumulative values if buttons were not previously pressed */
635    if (!hw->left && !hw->right && !hw->middle) {
636        hw->cumulative_dx = hw->x;
637        hw->cumulative_dy = hw->y;
638    }
639
640    while (SynapticsReadEvent(pInfo, &ev)) {
641        switch (ev.type) {
642        case EV_SYN:
643            switch (ev.code) {
644            case SYN_REPORT:
645                hw->numFingers = count_fingers(pInfo, comm);
646                hw->millis = 1000 * ev.time.tv_sec + ev.time.tv_usec / 1000;
647                SynapticsCopyHwState(hwRet, hw);
648                return TRUE;
649            }
650            break;
651        case EV_KEY:
652            v = (ev.value ? TRUE : FALSE);
653            switch (ev.code) {
654            case BTN_LEFT:
655                hw->left = v;
656                break;
657            case BTN_RIGHT:
658                hw->right = v;
659                break;
660            case BTN_MIDDLE:
661                hw->middle = v;
662                break;
663            case BTN_FORWARD:
664                hw->up = v;
665                break;
666            case BTN_BACK:
667                hw->down = v;
668                break;
669            case BTN_0:
670                hw->multi[0] = v;
671                break;
672            case BTN_1:
673                hw->multi[1] = v;
674                break;
675            case BTN_2:
676                hw->multi[2] = v;
677                break;
678            case BTN_3:
679                hw->multi[3] = v;
680                break;
681            case BTN_4:
682                hw->multi[4] = v;
683                break;
684            case BTN_5:
685                hw->multi[5] = v;
686                break;
687            case BTN_6:
688                hw->multi[6] = v;
689                break;
690            case BTN_7:
691                hw->multi[7] = v;
692                break;
693            case BTN_TOOL_FINGER:
694                comm->oneFinger = v;
695                break;
696            case BTN_TOOL_DOUBLETAP:
697                comm->twoFingers = v;
698                break;
699            case BTN_TOOL_TRIPLETAP:
700                comm->threeFingers = v;
701                break;
702            case BTN_TOUCH:
703                if (!priv->has_pressure)
704                    hw->z = v ? para->finger_high + 1 : 0;
705                break;
706            }
707            break;
708        case EV_ABS:
709            if (ev.code < ABS_MT_SLOT) {
710                switch (ev.code) {
711                case ABS_X:
712                    hw->x = apply_st_scaling(proto_data, ev.value, 0);
713                    break;
714                case ABS_Y:
715                    hw->y = apply_st_scaling(proto_data, ev.value, 1);
716                    break;
717                case ABS_PRESSURE:
718                    hw->z = ev.value;
719                    break;
720                case ABS_TOOL_WIDTH:
721                    hw->fingerWidth = ev.value;
722                    break;
723                }
724            }
725            else
726                EventProcessTouchEvent(pInfo, hw, &ev);
727            break;
728        }
729    }
730    return FALSE;
731}
732
733/* filter for the AutoDevProbe scandir on /dev/input */
734static int
735EventDevOnly(const struct dirent *dir)
736{
737    return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0;
738}
739
740static void
741event_query_touch(InputInfoPtr pInfo)
742{
743    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
744    SynapticsParameters *para = &priv->synpara;
745    struct eventcomm_proto_data *proto_data = priv->proto_data;
746    struct mtdev *mtdev;
747    int i;
748    int rc;
749    uint8_t prop;
750
751    priv->max_touches = 0;
752    priv->num_mt_axes = 0;
753
754#ifdef EVIOCGPROP
755    SYSCALL(rc = ioctl(pInfo->fd, EVIOCGPROP(sizeof(prop)), &prop));
756    if (rc >= 0 && BitIsOn(&prop, INPUT_PROP_SEMI_MT)) {
757        xf86IDrvMsg(pInfo, X_INFO,
758                    "ignoring touch events for semi-multitouch device\n");
759        priv->has_semi_mt = TRUE;
760    }
761
762    if (rc >= 0 && BitIsOn(&prop, INPUT_PROP_BUTTONPAD)) {
763        xf86IDrvMsg(pInfo, X_INFO, "found clickpad property\n");
764        para->clickpad = TRUE;
765    }
766#endif
767
768    mtdev = mtdev_new_open(pInfo->fd);
769    if (!mtdev) {
770        xf86IDrvMsg(pInfo, X_WARNING,
771                    "failed to open mtdev when querying touch capabilities\n");
772        return;
773    }
774
775    for (i = 0; i < MT_ABS_SIZE; i++) {
776        if (mtdev->caps.has_abs[i]) {
777            switch (i) {
778                /* X and Y axis info is handed by synaptics already */
779            case ABS_MT_POSITION_X - ABS_MT_TOUCH_MAJOR:
780            case ABS_MT_POSITION_Y - ABS_MT_TOUCH_MAJOR:
781                /* Skip tracking ID info */
782            case ABS_MT_TRACKING_ID - ABS_MT_TOUCH_MAJOR:
783                break;
784            default:
785                priv->num_mt_axes++;
786                break;
787            }
788            priv->has_touch = TRUE;
789        }
790    }
791
792    if (priv->has_touch) {
793        int axnum;
794
795        static const char *labels[] = {
796            AXIS_LABEL_PROP_ABS_MT_TOUCH_MAJOR,
797            AXIS_LABEL_PROP_ABS_MT_TOUCH_MINOR,
798            AXIS_LABEL_PROP_ABS_MT_WIDTH_MAJOR,
799            AXIS_LABEL_PROP_ABS_MT_WIDTH_MINOR,
800            AXIS_LABEL_PROP_ABS_MT_ORIENTATION,
801            AXIS_LABEL_PROP_ABS_MT_POSITION_X,
802            AXIS_LABEL_PROP_ABS_MT_POSITION_Y,
803            AXIS_LABEL_PROP_ABS_MT_TOOL_TYPE,
804            AXIS_LABEL_PROP_ABS_MT_BLOB_ID,
805            AXIS_LABEL_PROP_ABS_MT_TRACKING_ID,
806            AXIS_LABEL_PROP_ABS_MT_PRESSURE,
807        };
808
809        if (mtdev->caps.slot.maximum > 0)
810            priv->max_touches = mtdev->caps.slot.maximum -
811                mtdev->caps.slot.minimum + 1;
812
813        priv->touch_axes = malloc(priv->num_mt_axes *
814                                  sizeof(SynapticsTouchAxisRec));
815        if (!priv->touch_axes) {
816            priv->has_touch = FALSE;
817            goto out;
818        }
819
820        axnum = 0;
821        for (i = 0; i < MT_ABS_SIZE; i++) {
822            if (mtdev->caps.has_abs[i]) {
823                switch (i) {
824                    /* X and Y axis info is handed by synaptics already, we just
825                     * need to map the evdev codes to the valuator numbers */
826                case ABS_MT_POSITION_X - ABS_MT_TOUCH_MAJOR:
827                    proto_data->axis_map[i] = 0;
828                    break;
829
830                case ABS_MT_POSITION_Y - ABS_MT_TOUCH_MAJOR:
831                    proto_data->axis_map[i] = 1;
832                    break;
833
834                    /* Skip tracking ID info */
835                case ABS_MT_TRACKING_ID - ABS_MT_TOUCH_MAJOR:
836                    break;
837
838                default:
839                    priv->touch_axes[axnum].label = labels[i];
840                    priv->touch_axes[axnum].min = mtdev->caps.abs[i].minimum;
841                    priv->touch_axes[axnum].max = mtdev->caps.abs[i].maximum;
842                    /* Kernel provides units/mm, X wants units/m */
843                    priv->touch_axes[axnum].res =
844                        mtdev->caps.abs[i].resolution * 1000;
845                    /* Valuators 0-3 are used for X, Y, and scrolling */
846                    proto_data->axis_map[i] = 4 + axnum;
847                    axnum++;
848                    break;
849                }
850            }
851        }
852    }
853
854 out:
855    mtdev_close_delete(mtdev);
856}
857
858/**
859 * Probe the open device for dimensions.
860 */
861static void
862EventReadDevDimensions(InputInfoPtr pInfo)
863{
864    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
865    struct eventcomm_proto_data *proto_data = priv->proto_data;
866    int i;
867
868    proto_data = EventProtoDataAlloc();
869    priv->proto_data = proto_data;
870
871    for (i = 0; i < MT_ABS_SIZE; i++)
872        proto_data->axis_map[i] = -1;
873    proto_data->cur_slot = -1;
874
875    if (event_query_is_touchpad(pInfo->fd, proto_data->need_grab)) {
876        event_query_touch(pInfo);
877        event_query_axis_ranges(pInfo);
878    }
879    event_query_model(pInfo->fd, &priv->model, &priv->id_vendor,
880                      &priv->id_product);
881
882    xf86IDrvMsg(pInfo, X_PROBED, "Vendor %#hx Product %#hx\n",
883                priv->id_vendor, priv->id_product);
884}
885
886static Bool
887EventAutoDevProbe(InputInfoPtr pInfo, const char *device)
888{
889    /* We are trying to find the right eventX device or fall back to
890       the psaux protocol and the given device from XF86Config */
891    int i;
892    Bool touchpad_found = FALSE;
893    struct dirent **namelist;
894
895    if (device) {
896        int fd = -1;
897
898        SYSCALL(fd = open(device, O_RDONLY));
899        if (fd >= 0) {
900            touchpad_found = event_query_is_touchpad(fd, TRUE);
901
902            SYSCALL(close(fd));
903            /* if a device is set and not a touchpad (or already grabbed),
904             * we must return FALSE.  Otherwise, we'll add a device that
905             * wasn't requested for and repeat
906             * f5687a6741a19ef3081e7fd83ac55f6df8bcd5c2. */
907            return touchpad_found;
908        }
909    }
910
911    i = scandir(DEV_INPUT_EVENT, &namelist, EventDevOnly, alphasort);
912    if (i < 0) {
913        xf86IDrvMsg(pInfo, X_ERROR, "Couldn't open %s\n", DEV_INPUT_EVENT);
914        return FALSE;
915    }
916    else if (i == 0) {
917        xf86IDrvMsg(pInfo, X_ERROR,
918                    "The /dev/input/event* device nodes seem to be missing\n");
919        free(namelist);
920        return FALSE;
921    }
922
923    while (i--) {
924        char fname[64];
925        int fd = -1;
926
927        if (!touchpad_found) {
928            sprintf(fname, "%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name);
929            SYSCALL(fd = open(fname, O_RDONLY));
930            if (fd < 0)
931                continue;
932
933            if (event_query_is_touchpad(fd, TRUE)) {
934                touchpad_found = TRUE;
935                xf86IDrvMsg(pInfo, X_PROBED, "auto-dev sets device to %s\n",
936                            fname);
937                pInfo->options =
938                    xf86ReplaceStrOption(pInfo->options, "Device", fname);
939            }
940            SYSCALL(close(fd));
941        }
942        free(namelist[i]);
943    }
944
945    free(namelist);
946
947    if (!touchpad_found) {
948        xf86IDrvMsg(pInfo, X_ERROR, "no synaptics event device found\n");
949        return FALSE;
950    }
951
952    return TRUE;
953}
954
955struct SynapticsProtocolOperations event_proto_operations = {
956    EventDeviceOnHook,
957    EventDeviceOffHook,
958    EventQueryHardware,
959    EventReadHwState,
960    EventAutoDevProbe,
961    EventReadDevDimensions
962};
963