summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Willich <sabotageandi@gmail.com>2011-08-06 22:56:54 +0200
committerAndreas Willich <sabotageandi@gmail.com>2011-08-06 22:56:54 +0200
commit05e2888845ef46a6851eeb8817811e7f2a5172f1 (patch)
tree01f71afdf31b80285ceaec7fe6dbb4f05a430ce5 /x11-drivers
downloadsabotageandi-05e2888845ef46a6851eeb8817811e7f2a5172f1.tar.gz
sabotageandi-05e2888845ef46a6851eeb8817811e7f2a5172f1.tar.bz2
sabotageandi-05e2888845ef46a6851eeb8817811e7f2a5172f1.zip
ebuild push
Diffstat (limited to 'x11-drivers')
-rw-r--r--x11-drivers/xf86-input-evdev/Manifest4
-rw-r--r--x11-drivers/xf86-input-evdev/files/xf86-input-evdev-gestures.patch664
-rw-r--r--x11-drivers/xf86-input-evdev/files/xf86-input-evdev-xi2.1.patch1678
-rw-r--r--x11-drivers/xf86-input-evdev/xf86-input-evdev-2.6.0-r1.ebuild33
4 files changed, 2379 insertions, 0 deletions
diff --git a/x11-drivers/xf86-input-evdev/Manifest b/x11-drivers/xf86-input-evdev/Manifest
new file mode 100644
index 0000000..f66b468
--- /dev/null
+++ b/x11-drivers/xf86-input-evdev/Manifest
@@ -0,0 +1,4 @@
+AUX xf86-input-evdev-gestures.patch 23436 RMD160 839e8cd97fe0c47b4b02ce6f6d8ddc0d5f4b84e3 SHA1 6da156d429f3cc3f9fd03e03a7799b1b19835164 SHA256 9e868d28efbe7baaa3ccc405d866668a656b8526c8d7d91ebb6f3fc2437e8541
+AUX xf86-input-evdev-xi2.1.patch 57618 RMD160 cc15cc711667a0efc9d6bdda1d4c77dd06d5c5c8 SHA1 2fb6f062900872ece9c44bf223b0d1da8b36bf4a SHA256 f774127a8aff8076d37c12a9993816fef69586e3dcf7e01e77206291dfecfd74
+DIST xf86-input-evdev-2.6.0.tar.bz2 322773 RMD160 cde3345f882a4774dffe3ec9c716ef077f25febf SHA1 fb6f7a6f5168ae07efe890e4ace9fb8af1d4e1e0 SHA256 b0e7f3991a8183a4743196c3e16d7184d439b80bf43653aa2f45b0756a6753ac
+EBUILD xf86-input-evdev-2.6.0-r1.ebuild 778 RMD160 a8c2e11dbcf32a32e9dba0cf12fd016b34de1a1b SHA1 ec5ba962c207dfb7994d12658ac60c3512354f9a SHA256 2923c72deb30b5ec8e86fd5464d69342387dbb19fa5a5ebbfc4945f2aad0e882
diff --git a/x11-drivers/xf86-input-evdev/files/xf86-input-evdev-gestures.patch b/x11-drivers/xf86-input-evdev/files/xf86-input-evdev-gestures.patch
new file mode 100644
index 0000000..fd55d1a
--- /dev/null
+++ b/x11-drivers/xf86-input-evdev/files/xf86-input-evdev-gestures.patch
@@ -0,0 +1,664 @@
+--- a/configure.ac
++++ b/configure.ac
+@@ -68,6 +68,22 @@ sdkdir=`$PKG_CONFIG --variable=sdkdir xo
+ AC_ARG_WITH([sdkdir], [], [sdkdir="$withval"])
+ AC_SUBST([sdkdir])
+
++AC_ARG_ENABLE(utouch-grail, AS_HELP_STRING([--enable-utouch-grail], [Build with utouch-grail gesture support (default: auto)]), [GRAIL=$enableval], [GRAIL=auto])
++PKG_CHECK_MODULES(GRAIL, utouch-grail, [have_grail=yes], [have_grail=no])
++if test "x$GRAIL" = xauto; then
++ GRAIL="$have_grail"
++fi
++if test "x$GRAIL" = xyes; then
++ if test "x$have_grail" = xno; then
++ AC_MSG_ERROR([Grail build explicitly requested, but required modules not found.])
++ fi
++ AC_DEFINE(USE_GRAIL, 1, Whether to use grail or not)
++ AC_DEFINE(GESTURES, 1, Needed to interpret xorg headers properly)
++else
++ AC_DEFINE(USE_GRAIL, 0, Whether to use grail or not)
++fi
++AM_CONDITIONAL(USE_GRAIL, [test "x$GRAIL" = xyes])
++
+ DRIVER_NAME=evdev
+ AC_SUBST([DRIVER_NAME])
+
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -29,12 +29,17 @@ AM_CFLAGS = $(XORG_CFLAGS) $(CWARNFLAGS)
+ AM_CPPFLAGS =-I$(top_srcdir)/include
+
+ @DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la
+-@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
++@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version @GRAIL_LIBS@
+ @DRIVER_NAME@_drv_la_LIBADD = $(MTDEV_LIBS)
+ @DRIVER_NAME@_drv_ladir = @inputdir@
+
++if USE_GRAIL
++GRAIL_SRC=evdev-grail.c evdev-grail.h
++endif
++
+ @DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c \
+ @DRIVER_NAME@.h \
++ $(GRAIL_SRC) \
+ emuMB.c \
+ emuWheel.c \
+ draglock.c
+--- /dev/null
++++ b/src/evdev-grail.c
+@@ -0,0 +1,375 @@
++/*
++ * Copyright © 2010 Canonical, Ltd.
++ *
++ * 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.
++ *
++ * 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.
++ *
++ * Authors:
++ * Chase Douglas (chase.douglas@canonical.com)
++ */
++
++/* So we can get at the right data in xorg/windowstr.h */
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#include <xorg-server.h>
++#include <X11/Xatom.h>
++#include <xf86.h>
++#include <xf86Xinput.h>
++#include <exevents.h>
++#include <windowstr.h>
++#include <xorg/os.h>
++
++#include <evdev-properties.h>
++#include "evdev.h"
++#include "evdev-grail.h"
++#include "gestureproto.h"
++
++/* Copied from evdev.c, will be in evdev.h when xserver 1.9 is merged */
++#define EVDEV_RELATIVE_EVENTS (1 << 2)
++#define EVDEV_TOUCHPAD (1 << 4)
++
++/*
++ * Provided by the Maverick X server, we don't want to pollute the official
++ * X.org API.
++ */
++extern _X_EXPORT void xf86PostGestureEvent(DeviceIntPtr dev, unsigned short x,
++ unsigned short y, unsigned short client_id,
++ unsigned short gesture_id, unsigned short gesture_type,
++ Window root, Window event, Window child,
++ unsigned short status, unsigned short num_props,
++ float *props);
++
++static WindowPtr CommonAncestor(WindowPtr a, WindowPtr b)
++{
++ WindowPtr c;
++
++ if (a == b)
++ return a;
++
++ for (b = b; b; b = b->parent)
++ for (c = a; c; c = c->parent)
++ if (c == b)
++ return b;
++
++ return NullWindow;
++}
++
++static WindowPtr GetWindowForGestures(struct grail *grail,
++ const struct grail_coord *contacts,
++ int num_contacts)
++{
++ WindowPtr window = NULL;
++ int i;
++
++ for (i = 0; i < num_contacts; i++)
++ {
++ float screen_x = contacts[i].x;
++ float screen_y = contacts[i].y;
++ WindowPtr this_window;
++
++ this_window = xf86CoordinatesToWindow(screen_x, screen_y, 0);
++ if (!this_window)
++ return NullWindow;
++
++ if (!window)
++ window = this_window;
++ else
++ window = CommonAncestor(window, this_window);
++ }
++
++ return window;
++}
++
++static int GetClients(struct grail *grail,
++ struct grail_client_info *clients, int max_clients,
++ const struct grail_coord *contacts, int num_contacts,
++ const grail_mask_t *types, int type_bytes)
++{
++ WindowPtr child_window;
++ WindowPtr window;
++ WindowPtr root_window;
++ InputInfoPtr pInfo = grail->priv;
++ EvdevPtr pEvdev = pInfo->private;
++ int j;
++ int found_match = 0;
++ int num_clients = 0;
++ int type;
++
++ if (max_clients <= 0)
++ return 0;
++
++ if (pEvdev->flags & (EVDEV_RELATIVE_EVENTS | EVDEV_TOUCHPAD))
++ {
++ DeviceIntPtr master = pInfo->dev->u.master;
++ struct grail_coord cursor_coord;
++
++ /* If this mouse isn't hooked up to a cursor, don't do anything */
++ if (!master)
++ return 0;
++
++ cursor_coord.x = master->last.valuators[0];
++ cursor_coord.y = master->last.valuators[1];
++
++ child_window = GetWindowForGestures(grail, &cursor_coord, 1);
++ } else
++ child_window = GetWindowForGestures(grail, contacts, num_contacts);
++
++ if (!child_window)
++ return 0;
++
++ memset(clients, 0, sizeof(struct grail_client_info) * max_clients);
++
++ /* Find the root window. */
++ for (root_window = child_window; root_window->parent;
++ root_window = root_window->parent);
++
++ /*
++ * Check for a root client with SYSFLAG1 set. SYSFLAG1 is effectively an
++ * active grab for system gestures. We assume only one client has SYSFLAG1
++ * set.
++ */
++ window = child_window;
++ while (window)
++ {
++ /* Check if any gestures have been selected on this window. */
++ if (wGestureMasks(window))
++ {
++ GestureClientsPtr client;
++
++ /* For each client */
++ for (client = wGestureMasks(window)->clients; client;
++ client = client->next)
++ {
++ int first = 1;
++
++ /* If the client has set the SYSFLAG1 bit */
++ if (BitIsOn(client->gestureMask[0], GRAIL_TYPE_SYSFLAG1))
++ {
++ /* For each recognized gesture */
++ grail_mask_foreach(type, types, type_bytes)
++ {
++ if (type == GRAIL_TYPE_SYSFLAG1)
++ continue;
++
++ /*
++ * Check if this client selected for this gesture.
++ * Request may be for this device or all devices.
++ */
++ if (BitIsOn(client->gestureMask[pInfo->dev->id], type) ||
++ BitIsOn(client->gestureMask[0], type))
++ {
++ if (first) {
++ /* Set up new client in array */
++ clients[0].id.client = CLIENT_ID(client->resource);
++ clients[0].id.root = root_window->drawable.id;
++ clients[0].id.child = child_window->drawable.id;
++ clients[0].id.event = window->drawable.id;
++ grail_mask_clear(clients[0].mask,
++ DIM_GRAIL_TYPE_BYTES);
++ first = 0;
++ }
++
++ /* Set this gesture bit in the client's gesture mask */
++ SetBit(clients[0].mask, type);
++ num_clients = 1;
++ }
++ }
++
++ /*
++ * Either we found a gesture, or we stop looking for SYSFLAG1
++ * clients.
++ */
++ if (num_clients) {
++ SetBit(clients[0].mask, GRAIL_TYPE_SYSFLAG1);
++ goto next_window;
++ }
++ }
++ }
++ }
++
++next_window:
++ window = window->parent;
++ }
++
++ /*
++ * Traverse the window hierarchy looking for a window with a client
++ * selecting for one of the recognized gestures.
++ *
++ * All clients of the top most window with a match will receive events if
++ * they have selected for gestures that have been recognized, even if they
++ * have selected for different gestures between them.
++ *
++ * Once any gesture is matched on a window, propagation through the window
++ * hierarchy ends.
++ */
++ for (window = child_window; window && !found_match; window = window->parent)
++ {
++ /* No client selected for gestures on this window */
++ if (!wGestureMasks(window))
++ continue;
++
++ /* For each recognized gesture */
++ grail_mask_foreach(type, types, type_bytes)
++ {
++ if (type == GRAIL_TYPE_SYSFLAG1)
++ continue;
++
++ /* Check if any client selected for this gesture on the window */
++ if (BitIsOn(wGestureMasks(window)->mask, type))
++ {
++ GestureClientsPtr client;
++
++ /* For each client that selected for gestures on this window */
++ for (client = wGestureMasks(window)->clients; client;
++ client = client->next)
++ {
++ /*
++ * Check if this client selected for this gesture. Request
++ * may be for this device or all devices.
++ */
++ if (BitIsOn(client->gestureMask[pInfo->dev->id], type) ||
++ BitIsOn(client->gestureMask[0], type))
++ {
++ /*
++ * Find this client in the clients array passed back to
++ * the caller.
++ */
++ for (j = 0; j < num_clients; j++)
++ if (clients[j].id.client ==
++ CLIENT_ID(client->resource))
++ break;
++
++ /* Check if the client exists in the array yet */
++ if (j >= num_clients)
++ {
++ /* We ran out of room in the array, return error */
++ if (num_clients >= max_clients)
++ return -1;
++ /* Set up new client in array */
++ clients[j].id.client = CLIENT_ID(client->resource);
++ clients[j].id.root = root_window->drawable.id;
++ clients[j].id.child = child_window->drawable.id;
++ clients[j].id.event = window->drawable.id;
++ num_clients++;
++ }
++
++ /* Set this gesture bit in the client's gesture mask */
++ SetBit(clients[j].mask, type);
++ }
++ }
++
++ /* A match has been found, stop propagating */
++ found_match = 1;
++ }
++ }
++ }
++
++ return num_clients;
++}
++
++static void GrailEvent(struct grail *grail, const struct input_event *ev)
++{
++ InputInfoPtr pInfo = (InputInfoPtr)grail->priv;
++ EvdevProcessEvent(pInfo, (struct input_event *)ev);
++}
++
++static void GrailGesture(struct grail *grail, const struct grail_event *ev)
++{
++ InputInfoPtr pInfo = grail->priv;
++ EvdevPtr pEvdev = pInfo->private;
++ int x;
++ int y;
++
++ /* Override event focus point if this is a relative device */
++ if (pEvdev->flags & (EVDEV_RELATIVE_EVENTS | EVDEV_TOUCHPAD))
++ {
++ DeviceIntPtr master = pInfo->dev->u.master;
++
++ /* If this mouse isn't hooked up to a cursor, don't do anything */
++ if (!master)
++ return;
++
++ /* Note: Master device valuators are in screen coordinates */
++ x = master->last.valuators[0];
++ y = master->last.valuators[1];
++ } else {
++ x = ev->pos.x;
++ y = ev->pos.y;
++ }
++
++ xf86PostGestureEvent(pInfo->dev, x, y, ev->client_id.client, ev->id,
++ ev->type, ev->client_id.root, ev->client_id.event,
++ ev->client_id.child, ev->status,
++ ev->nprop, (float *)ev->prop);
++}
++
++int
++GrailOpen(InputInfoPtr pInfo)
++{
++ EvdevPtr pEvdev = pInfo->private;
++
++ pEvdev->grail = malloc(sizeof(struct grail));
++ if (!pEvdev->grail) {
++ xf86Msg(X_ERROR, "evdev-grail: failed to allocate grail structure\n");
++ return -1;
++ }
++
++ memset(pEvdev->grail, 0, sizeof(struct grail));
++ pEvdev->grail->get_clients = GetClients;
++ pEvdev->grail->event = GrailEvent;
++ pEvdev->grail->gesture = GrailGesture;
++ pEvdev->grail->priv = pInfo;
++
++ if (grail_open(pEvdev->grail, pInfo->fd)) {
++ xf86Msg(X_INFO,
++ "evdev-grail: failed to open grail, no gesture support\n");
++ free(pEvdev->grail);
++ pEvdev->grail = NULL;
++ return -1;
++ }
++
++ {
++ struct grail_coord min;
++ struct grail_coord max;
++
++ min.x = screenInfo.screens[0]->x;
++ min.y = screenInfo.screens[0]->y;
++ max.x = min.x + screenInfo.screens[0]->width;
++ max.y = min.y + screenInfo.screens[0]->height;
++
++ grail_set_bbox(pEvdev->grail, &min, &max);
++ }
++
++ return 0;
++}
++
++void
++GrailClose(InputInfoPtr pInfo)
++{
++ EvdevPtr pEvdev = pInfo->private;
++
++ if (pEvdev->grail) {
++ grail_close(pEvdev->grail, pInfo->fd);
++ free(pEvdev->grail);
++ pEvdev->grail = NULL;
++ }
++}
+--- /dev/null
++++ b/src/evdev-grail.h
+@@ -0,0 +1,9 @@
++#ifndef EVDEV_GRAIL_H_
++#define EVDEV_GRAIL_H_
++
++#include <grail.h>
++
++extern int GrailOpen(InputInfoPtr pInfo);
++extern void GrailClose(InputInfoPtr pInfo);
++
++#endif /* _EVDEV_GRAIL_H_ */
+--- a/src/evdev.c
++++ b/src/evdev.c
+@@ -60,6 +60,13 @@
+ #define MAXDEVICES MAX_DEVICES
+ #endif
+
++#if USE_GRAIL
++#include "evdev-grail.h"
++#else
++#define GrailOpen(pInfo)
++#define GrailClose(pInfo)
++#endif
++
+ #define ArrayLength(a) (sizeof(a) / (sizeof((a)[0])))
+
+ #define MIN_KEYCODE 8
+@@ -900,7 +907,7 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo
+ * Process the events from the device; nothing is actually posted to the server
+ * until an EV_SYN event is received.
+ */
+-static void
++void
+ EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
+ {
+ switch (ev->type) {
+@@ -934,17 +941,14 @@ EvdevReadInput(InputInfoPtr pInfo)
+
+ while (len == sizeof(ev))
+ {
+-#ifdef MULTITOUCH
++#if USE_GRAIL
+ EvdevPtr pEvdev = pInfo->private;
+
+- if (pEvdev->mtdev)
+- len = mtdev_get(pEvdev->mtdev, pInfo->fd, ev, NUM_EVENTS) *
+- sizeof(struct input_event);
++ if (pEvdev->grail)
++ len = grail_pull(pEvdev->grail, pInfo->fd);
+ else
+- len = read(pInfo->fd, &ev, sizeof(ev));
+-#else
+- len = read(pInfo->fd, &ev, sizeof(ev));
+ #endif
++ len = read(pInfo->fd, &ev, sizeof(ev));
+ if (len <= 0)
+ {
+ if (errno == ENODEV) /* May happen after resume */
+@@ -962,6 +966,11 @@ EvdevReadInput(InputInfoPtr pInfo)
+ break;
+ }
+
++#if USE_GRAIL
++ if (pEvdev->grail)
++ return;
++#endif
++
+ /* The kernel promises that we always only read a complete
+ * event, so len != sizeof ev is an error. */
+ if (len % sizeof(ev[0])) {
+@@ -1620,6 +1629,7 @@ EvdevProc(DeviceIntPtr device, int what)
+ if (pEvdev->mtdev)
+ mtdev_close(pEvdev->mtdev);
+ #endif
++ GrailClose(pInfo);
+ EvdevRemoveDevice(pInfo);
+ pEvdev->min_maj = 0;
+ break;
+@@ -1857,6 +1867,8 @@ EvdevProbe(InputInfoPtr pInfo)
+ xf86Msg(X_PROBED, "%s: Found absolute axes\n", pInfo->name);
+ pEvdev->flags |= EVDEV_ABSOLUTE_EVENTS;
+
++ GrailOpen(pInfo);
++
+ if ((TestBit(ABS_X, pEvdev->abs_bitmask) &&
+ TestBit(ABS_Y, pEvdev->abs_bitmask))) {
+ xf86Msg(X_PROBED, "%s: Found x and y absolute axes\n", pInfo->name);
+--- a/src/evdev.h
++++ b/src/evdev.h
+@@ -207,8 +207,14 @@ typedef struct {
+ /* Event queue used to defer keyboard/button events until EV_SYN time. */
+ int num_queue;
+ EventQueueRec queue[EVDEV_MAXQUEUE];
++
++#if USE_GRAIL
++ struct grail *grail;
++#endif
+ } EvdevRec, *EvdevPtr;
+
++void EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev);
++
+ /* Event posting functions */
+ void EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value);
+ void EvdevQueueButtonEvent(InputInfoPtr pInfo, int button, int value);
+--- /dev/null
++++ b/src/gestureproto.h
+@@ -0,0 +1,132 @@
++/*
++ * Copyright © 2010 Canonical, Ltd.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: Chase Douglas <chase.douglas@canonical.com>
++ *
++ */
++
++#ifndef _GESTUREPROTO_H_
++#define _GESTUREPROTO_H_
++
++#include <stdint.h>
++#include <X11/X.h>
++
++#define Window uint32_t
++#define Time uint32_t
++
++#define X_GestureQueryVersion 1
++#define X_GestureSelectEvents 2
++#define X_GestureGetSelectedEvents 3
++
++#define GESTUREREQUESTS (X_GestureGetSelectedEvents - X_GestureQueryVersion + 1)
++
++#define GestureAllDevices 0
++
++/**
++ * Used to select for events on a given window.
++ * Struct is followed by (mask_len * CARD8), with each bit set representing
++ * the event mask for the given type. A mask bit represents an event type if
++ * (mask == (1 << type)).
++ */
++typedef struct {
++ uint16_t device_id; /**< Device id to select for */
++ uint16_t mask_len; /**< Length of mask in 4 byte units */
++} GestureEventMask;
++
++typedef struct {
++ uint8_t reqType; /**< Gesture extension major code */
++ uint8_t ReqType; /**< Always ::X_GestureQueryVersion */
++ uint16_t length; /**< Length in 4 byte units */
++ uint16_t major_version;
++ uint16_t minor_version;
++} GestureQueryVersionReq;
++
++typedef struct {
++ uint8_t repType; /**< ::X_Reply */
++ uint8_t RepType; /**< Always ::X_GestureQueryVersion */
++ uint16_t sequenceNumber;
++ uint32_t length;
++ uint16_t major_version;
++ uint16_t minor_version;
++ uint32_t pad1;
++ uint32_t pad2;
++ uint32_t pad3;
++ uint32_t pad4;
++ uint32_t pad5;
++} GestureQueryVersionReply;
++
++typedef struct {
++ uint8_t reqType; /**< Gesture extension major code */
++ uint8_t ReqType; /**< Always ::X_GestureSelectEvents */
++ uint16_t length; /**< Length in 4 byte units */
++ Window window;
++ GestureEventMask mask;
++} GestureSelectEventsReq;
++
++typedef struct {
++ uint8_t reqType; /**< Gesture extension major code */
++ uint8_t ReqType; /**< Always ::X_GestureGetSelectedEvents */
++ uint16_t length; /**< Length in 4 byte units */
++ Window window;
++} GestureGetSelectedEventsReq;
++
++typedef struct {
++ uint8_t repType; /**< Gesture extension major opcode */
++ uint8_t RepType; /**< Always ::X_GestureGetSelectedEvents */
++ uint16_t sequenceNumber;
++ uint32_t length;
++ uint16_t num_masks; /**< Number of GestureEventMask structs
++ trailing the reply */
++ uint16_t pad0;
++ uint32_t pad1;
++ uint32_t pad2;
++ uint32_t pad3;
++ uint32_t pad4;
++ uint32_t pad5;
++} GestureGetSelectedEventsReply;
++
++typedef struct
++{
++ uint8_t type; /**< Always GenericEvent */
++ uint8_t extension; /**< Gesture extension offset */
++ uint16_t sequenceNumber; /**< Xevent sequence number */
++ uint32_t length; /**< Length in 4 byte uints */
++ uint16_t evtype; /**< X generic event type */
++ uint16_t gesture_id; /**< Unique ID for gesture */
++ uint16_t gesture_type; /**< Gesture type (zoom, rotate, etc.) */
++ uint16_t device_id; /**< Device that generated this gesture */
++ Time time; /**< Time of gesture event */
++ Window root; /**< Root window event occurred on */
++ Window event; /**< Window selecting this event for a client */
++ Window child; /**< Top-most window of gesture event */
++/* └──────── 32 byte boundary ────────┘ */
++ float focus_x; /**< Always window coords, 16.16 fixed point */
++ float focus_y; /**< Relative to event window */
++ uint16_t status; /**< Gesture event status */
++ uint16_t num_props; /**< Number of properties for gesture event */
++/* └──── Gesture properties below ────┘ */
++} GestureEvent;
++
++#undef Window
++#undef Time
++
++#endif /* _GESTUREPROTO_H_ */
diff --git a/x11-drivers/xf86-input-evdev/files/xf86-input-evdev-xi2.1.patch b/x11-drivers/xf86-input-evdev/files/xf86-input-evdev-xi2.1.patch
new file mode 100644
index 0000000..10598f1
--- /dev/null
+++ b/x11-drivers/xf86-input-evdev/files/xf86-input-evdev-xi2.1.patch
@@ -0,0 +1,1678 @@
+diff --git a/configure.ac b/configure.ac
+index 887021c..b4b0bad 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -47,6 +47,9 @@ XORG_DEFAULT_OPTIONS
+ # Obtain compiler/linker options from server and required extensions
+ PKG_CHECK_MODULES(XORG, xorg-server xproto inputproto)
+
++# Obtain compiler/linker options for mtdev
++PKG_CHECK_MODULES(MTDEV, mtdev)
++
+ # Define a configure option for an alternate input module directory
+ AC_ARG_WITH(xorg-module-dir,
+ AC_HELP_STRING([--with-xorg-module-dir=DIR],
+diff --git a/src/Makefile.am b/src/Makefile.am
+index a5c89ac..b8d0dd9 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -30,6 +30,7 @@ AM_CPPFLAGS =-I$(top_srcdir)/include
+
+ @DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la
+ @DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
++@DRIVER_NAME@_drv_la_LIBADD = $(MTDEV_LIBS)
+ @DRIVER_NAME@_drv_ladir = @inputdir@
+
+ @DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c \
+diff --git a/src/draglock.c b/src/draglock.c
+index af80cf6..0b430f0 100644
+--- a/src/draglock.c
++++ b/src/draglock.c
+@@ -44,9 +44,7 @@
+
+ #include <evdev-properties.h>
+
+-#ifdef HAVE_PROPERTIES
+ static Atom prop_dlock = 0; /* Drag lock buttons. */
+-#endif
+
+ void EvdevDragLockLockButton(InputInfoPtr pInfo, unsigned int button);
+
+@@ -211,7 +209,6 @@ EvdevDragLockFilterEvent(InputInfoPtr pInfo, unsigned int button, int value)
+ return FALSE;
+ }
+
+-#ifdef HAVE_PROPERTIES
+ /**
+ * Set the drag lock property.
+ * If only one value is supplied, then this is used as the meta button.
+@@ -319,5 +316,3 @@ EvdevDragLockInitProperty(DeviceIntPtr dev)
+
+ XIRegisterPropertyHandler(dev, EvdevDragLockSetProperty, NULL, NULL);
+ }
+-
+-#endif
+diff --git a/src/emuMB.c b/src/emuMB.c
+index 764b30e..b7a57b8 100644
+--- a/src/emuMB.c
++++ b/src/emuMB.c
+@@ -43,10 +43,8 @@
+
+ #include <evdev-properties.h>
+
+-#ifdef HAVE_PROPERTIES
+ static Atom prop_mbemu = 0; /* Middle button emulation on/off property */
+ static Atom prop_mbtimeout = 0; /* Middle button timeout property */
+-#endif
+ /*
+ * Lets create a simple finite-state machine for 3 button emulation:
+ *
+@@ -330,7 +328,6 @@ EvdevMBEmuFinalize(InputInfoPtr pInfo)
+
+ }
+
+-#ifdef HAVE_PROPERTIES
+ static int
+ EvdevMBEmuSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
+ BOOL checkonly)
+@@ -391,4 +388,3 @@ EvdevMBEmuInitProperty(DeviceIntPtr dev)
+
+ XIRegisterPropertyHandler(dev, EvdevMBEmuSetProperty, NULL, NULL);
+ }
+-#endif
+diff --git a/src/emuWheel.c b/src/emuWheel.c
+index 9a53211..715f8d1 100644
+--- a/src/emuWheel.c
++++ b/src/emuWheel.c
+@@ -44,13 +44,11 @@
+
+ #define WHEEL_NOT_CONFIGURED 0
+
+-#ifdef HAVE_PROPERTIES
+ static Atom prop_wheel_emu = 0;
+ static Atom prop_wheel_axismap = 0;
+ static Atom prop_wheel_inertia = 0;
+ static Atom prop_wheel_timeout = 0;
+ static Atom prop_wheel_button = 0;
+-#endif
+
+ /* Local Funciton Prototypes */
+ static BOOL EvdevWheelEmuHandleButtonMap(InputInfoPtr pInfo, WheelAxisPtr pAxis, char *axis_name);
+@@ -120,8 +118,9 @@ EvdevWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv)
+
+ /* We don't want to intercept real mouse wheel events */
+ if(pEv->type == EV_ABS) {
+- oldValue = pEvdev->vals[pEvdev->axis_map[pEv->code]];
+- pEvdev->vals[pEvdev->axis_map[pEv->code]] = value;
++ int axis = pEvdev->axis_map[pEv->code];
++ oldValue = valuator_mask_get(pEvdev->vals, axis);
++ valuator_mask_set(pEvdev->vals, axis, value);
+ value -= oldValue; /* make value into a differential measurement */
+ }
+
+@@ -335,7 +334,6 @@ EvdevWheelEmuPreInit(InputInfoPtr pInfo)
+ pInfo->name, pEvdev->emulateWheel.button, inertia, timeout);
+ }
+
+-#ifdef HAVE_PROPERTIES
+ static int
+ EvdevWheelEmuSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
+ BOOL checkonly)
+@@ -485,4 +483,3 @@ EvdevWheelEmuInitProperty(DeviceIntPtr dev)
+
+ XIRegisterPropertyHandler(dev, EvdevWheelEmuSetProperty, NULL, NULL);
+ }
+-#endif
+diff --git a/src/evdev.c b/src/evdev.c
+index 45873c1..ef72f8f 100644
+--- a/src/evdev.c
++++ b/src/evdev.c
+@@ -48,23 +48,12 @@
+ #include <xorgVersion.h>
+ #include <xkbsrv.h>
+
+-#ifdef HAVE_PROPERTIES
+ #include <X11/Xatom.h>
+ #include <evdev-properties.h>
+ #include <xserver-properties.h>
+-/* 1.6 has properties, but no labels */
+-#ifdef AXIS_LABEL_PROP
+-#define HAVE_LABELS
+-#else
+-#undef HAVE_LABELS
+-#endif
+-
+-#endif
+
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
+ /* removed from server, purge when dropping support for server 1.10 */
+ #define XI86_SEND_DRAG_EVENTS 0x08
+-#endif
+
+ #ifndef MAXDEVICES
+ #include <inputstr.h> /* for MAX_DEVICES */
+@@ -87,6 +76,14 @@
+ #define MODEFLAG 8
+ #define COMPOSEFLAG 16
+
++#ifndef ABS_MT_SLOT
++#define ABS_MT_SLOT 0x2f
++#endif
++
++#ifndef ABS_MT_TRACKING_ID
++#define ABS_MT_TRACKING_ID 0x39
++#endif
++
+ static char *evdevDefaults[] = {
+ "XkbRules", "evdev",
+ "XkbModel", "evdev",
+@@ -114,7 +111,6 @@ static BOOL EvdevGrabDevice(InputInfoPtr pInfo, int grab, int ungrab);
+ static void EvdevSetCalibration(InputInfoPtr pInfo, int num_calibration, int calibration[4]);
+ static int EvdevOpenDevice(InputInfoPtr pInfo);
+
+-#ifdef HAVE_PROPERTIES
+ static void EvdevInitAxesLabels(EvdevPtr pEvdev, int natoms, Atom *atoms);
+ static void EvdevInitButtonLabels(EvdevPtr pEvdev, int natoms, Atom *atoms);
+ static void EvdevInitProperty(DeviceIntPtr dev);
+@@ -125,7 +121,6 @@ static Atom prop_calibration = 0;
+ static Atom prop_swap = 0;
+ static Atom prop_axis_label = 0;
+ static Atom prop_btn_label = 0;
+-#endif
+
+ /* All devices the evdev driver has allocated and knows about.
+ * MAXDEVICES is safe as null-terminated array, as two devices (VCP and VCK)
+@@ -302,22 +297,13 @@ EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value)
+
+ /* Filter all repeated events from device.
+ We'll do softrepeat in the server, but only since 1.6 */
+- if (value == 2
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) <= 2
+- && (ev->code == KEY_LEFTCTRL || ev->code == KEY_RIGHTCTRL ||
+- ev->code == KEY_LEFTSHIFT || ev->code == KEY_RIGHTSHIFT ||
+- ev->code == KEY_LEFTALT || ev->code == KEY_RIGHTALT ||
+- ev->code == KEY_LEFTMETA || ev->code == KEY_RIGHTMETA ||
+- ev->code == KEY_CAPSLOCK || ev->code == KEY_NUMLOCK ||
+- ev->code == KEY_SCROLLLOCK) /* XXX windows keys? */
+-#endif
+- )
+- return;
++ if (value == 2)
++ return;
+
+ if ((pQueue = EvdevNextInQueue(pInfo)))
+ {
+ pQueue->type = EV_QUEUE_KEY;
+- pQueue->key = code;
++ pQueue->detail.key = code;
+ pQueue->val = value;
+ }
+ }
+@@ -327,10 +313,14 @@ EvdevQueueButtonEvent(InputInfoPtr pInfo, int button, int value)
+ {
+ EventQueuePtr pQueue;
+
++ /* Direct touch devices use server side pointer emulation */
++ if (pInfo->dev->touch && pInfo->dev->touch->mode == XIDirectTouch)
++ return;
++
+ if ((pQueue = EvdevNextInQueue(pInfo)))
+ {
+ pQueue->type = EV_QUEUE_BTN;
+- pQueue->key = button;
++ pQueue->detail.key = button;
+ pQueue->val = value;
+ }
+ }
+@@ -342,11 +332,27 @@ EvdevQueueProximityEvent(InputInfoPtr pInfo, int value)
+ if ((pQueue = EvdevNextInQueue(pInfo)))
+ {
+ pQueue->type = EV_QUEUE_PROXIMITY;
+- pQueue->key = 0;
++ pQueue->detail.key = 0;
+ pQueue->val = value;
+ }
+ }
+
++#ifdef MULTITOUCH
++void
++EvdevQueueTouchEvent(InputInfoPtr pInfo, unsigned int touch, ValuatorMask *mask,
++ uint16_t evtype)
++{
++ EventQueuePtr pQueue;
++ if ((pQueue = EvdevNextInQueue(pInfo)))
++ {
++ pQueue->type = EV_QUEUE_TOUCH;
++ pQueue->detail.touch = touch;
++ valuator_mask_copy(pQueue->touch_vals, mask);
++ pQueue->val = evtype;
++ }
++}
++#endif
++
+ /**
+ * Post button event right here, right now.
+ * Interface for MB emulation since these need to post immediately.
+@@ -368,41 +374,44 @@ EvdevQueueButtonClicks(InputInfoPtr pInfo, int button, int count)
+ }
+ }
+
+-#define ABS_X_VALUE 0x1
+-#define ABS_Y_VALUE 0x2
+-#define ABS_VALUE 0x4
+ /**
+ * Take the valuators and process them accordingly.
+ */
+ static void
+-EvdevProcessValuators(InputInfoPtr pInfo, int v[MAX_VALUATORS], int *num_v,
+- int *first_v)
++EvdevProcessValuators(InputInfoPtr pInfo)
+ {
+ int tmp;
+ EvdevPtr pEvdev = pInfo->private;
+-
+- *num_v = *first_v = 0;
++ int *delta = pEvdev->delta;
+
+ /* convert to relative motion for touchpads */
+ if (pEvdev->abs_queued && (pEvdev->flags & EVDEV_RELATIVE_MODE)) {
+ if (pEvdev->in_proximity) {
+- if (pEvdev->old_vals[0] != -1)
+- pEvdev->delta[REL_X] = pEvdev->vals[0] - pEvdev->old_vals[0];
+- if (pEvdev->old_vals[1] != -1)
+- pEvdev->delta[REL_Y] = pEvdev->vals[1] - pEvdev->old_vals[1];
+- if (pEvdev->abs_queued & ABS_X_VALUE)
+- pEvdev->old_vals[0] = pEvdev->vals[0];
+- if (pEvdev->abs_queued & ABS_Y_VALUE)
+- pEvdev->old_vals[1] = pEvdev->vals[1];
++ if (valuator_mask_isset(pEvdev->vals, 0))
++ {
++ if (valuator_mask_isset(pEvdev->old_vals, 0))
++ delta[REL_X] = valuator_mask_get(pEvdev->vals, 0) -
++ valuator_mask_get(pEvdev->old_vals, 0);
++ valuator_mask_set(pEvdev->old_vals, 0,
++ valuator_mask_get(pEvdev->vals, 0));
++ }
++ if (valuator_mask_isset(pEvdev->vals, 1))
++ {
++ if (valuator_mask_isset(pEvdev->old_vals, 1))
++ delta[REL_Y] = valuator_mask_get(pEvdev->vals, 1) -
++ valuator_mask_get(pEvdev->old_vals, 1);
++ valuator_mask_set(pEvdev->old_vals, 1,
++ valuator_mask_get(pEvdev->vals, 1));
++ }
+ } else {
+- pEvdev->old_vals[0] = pEvdev->old_vals[1] = -1;
++ valuator_mask_zero(pEvdev->old_vals);
+ }
++ valuator_mask_zero(pEvdev->vals);
+ pEvdev->abs_queued = 0;
+ pEvdev->rel_queued = 1;
+ }
+
+ if (pEvdev->rel_queued) {
+- int first = REL_CNT, last = -1;
+ int i;
+
+ if (pEvdev->swap_axes) {
+@@ -419,19 +428,7 @@ EvdevProcessValuators(InputInfoPtr pInfo, int v[MAX_VALUATORS], int *num_v,
+ {
+ int map = pEvdev->axis_map[i];
+ if (pEvdev->delta[i] && map != -1)
+- {
+- v[map] = pEvdev->delta[i];
+- if (map < first)
+- first = map;
+- if (map > last)
+- last = map;
+- }
+- }
+-
+- if (last >= 0)
+- {
+- *num_v = (last - first + 1);
+- *first_v = first;
++ valuator_mask_set(pEvdev->vals, map, pEvdev->delta[i]);
+ }
+ }
+ /*
+@@ -444,43 +441,46 @@ EvdevProcessValuators(InputInfoPtr pInfo, int v[MAX_VALUATORS], int *num_v,
+ * just works.
+ */
+ else if (pEvdev->abs_queued && pEvdev->in_proximity) {
+- memcpy(v, pEvdev->vals, sizeof(int) * pEvdev->num_vals);
++ int unswapped_x = valuator_mask_get(pEvdev->vals, 0);
++ int unswapped_y = valuator_mask_get(pEvdev->vals, 1);
++ int i;
+
+- if (pEvdev->swap_axes) {
+- int tmp = v[0];
+- v[0] = xf86ScaleAxis(v[1],
+- pEvdev->absinfo[ABS_X].maximum,
+- pEvdev->absinfo[ABS_X].minimum,
+- pEvdev->absinfo[ABS_Y].maximum,
+- pEvdev->absinfo[ABS_Y].minimum);
+- v[1] = xf86ScaleAxis(tmp,
+- pEvdev->absinfo[ABS_Y].maximum,
+- pEvdev->absinfo[ABS_Y].minimum,
+- pEvdev->absinfo[ABS_X].maximum,
+- pEvdev->absinfo[ABS_X].minimum);
+- }
++ for (i = 0; i <= 1; i++) {
++ int val;
++ int calib_min;
++ int calib_max;
+
+- if (pEvdev->flags & EVDEV_CALIBRATED)
+- {
+- v[0] = xf86ScaleAxis(v[0],
+- pEvdev->absinfo[ABS_X].maximum,
+- pEvdev->absinfo[ABS_X].minimum,
+- pEvdev->calibration.max_x, pEvdev->calibration.min_x);
+- v[1] = xf86ScaleAxis(v[1],
+- pEvdev->absinfo[ABS_Y].maximum,
+- pEvdev->absinfo[ABS_Y].minimum,
+- pEvdev->calibration.max_y, pEvdev->calibration.min_y);
+- }
++ if (!valuator_mask_isset(pEvdev->vals, i))
++ continue;
+
+- if (pEvdev->invert_x)
+- v[0] = (pEvdev->absinfo[ABS_X].maximum - v[0] +
+- pEvdev->absinfo[ABS_X].minimum);
+- if (pEvdev->invert_y)
+- v[1] = (pEvdev->absinfo[ABS_Y].maximum - v[1] +
+- pEvdev->absinfo[ABS_Y].minimum);
++ val = valuator_mask_get(pEvdev->vals, i);
++
++ if (i == 0) {
++ calib_min = pEvdev->calibration.min_x;
++ calib_max = pEvdev->calibration.max_x;
++ } else {
++ calib_min = pEvdev->calibration.min_y;
++ calib_max = pEvdev->calibration.max_y;
++ }
++
++ if (pEvdev->swap_axes)
++ val = xf86ScaleAxis((i == 0 ? unswapped_y : unswapped_x),
++ pEvdev->absinfo[i].maximum,
++ pEvdev->absinfo[i].minimum,
++ pEvdev->absinfo[1 - i].maximum,
++ pEvdev->absinfo[1 - i].minimum);
+
+- *num_v = pEvdev->num_vals;
+- *first_v = 0;
++ if (pEvdev->flags & EVDEV_CALIBRATED)
++ val = xf86ScaleAxis(val, pEvdev->absinfo[i].maximum,
++ pEvdev->absinfo[i].minimum, calib_max,
++ calib_min);
++
++ if ((i == 0 && pEvdev->invert_x) || (i == 1 && pEvdev->invert_y))
++ val = (pEvdev->absinfo[i].maximum - val +
++ pEvdev->absinfo[i].minimum);
++
++ valuator_mask_set(pEvdev->vals, i, val);
++ }
+ }
+ }
+
+@@ -518,11 +518,15 @@ EvdevProcessProximityState(InputInfoPtr pInfo)
+ int prox_state = 0;
+ int i;
+
++ /* Does this device have any proximity axes? */
++ if (!pEvdev->prox)
++ return 0;
++
+ /* no proximity change in the queue */
+ if (!pEvdev->prox_queued)
+ {
+ if (pEvdev->abs_queued && !pEvdev->in_proximity)
+- pEvdev->abs_prox = pEvdev->abs_queued;
++ valuator_mask_copy(pEvdev->prox, pEvdev->vals);
+ return 0;
+ }
+
+@@ -540,10 +544,11 @@ EvdevProcessProximityState(InputInfoPtr pInfo)
+ {
+ /* We're about to go into/out of proximity but have no abs events
+ * within the EV_SYN. Use the last coordinates we have. */
+- if (!pEvdev->abs_queued && pEvdev->abs_prox)
++ if (!pEvdev->abs_queued &&
++ valuator_mask_num_valuators(pEvdev->prox) > 0)
+ {
+- pEvdev->abs_queued = pEvdev->abs_prox;
+- pEvdev->abs_prox = 0;
++ valuator_mask_copy(pEvdev->vals, pEvdev->prox);
++ valuator_mask_zero(pEvdev->prox);
+ }
+ }
+
+@@ -590,6 +595,7 @@ EvdevProcessRelativeMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
+ {
+ int value;
+ EvdevPtr pEvdev = pInfo->private;
++ int map;
+
+ /* Get the signed value, earlier kernels had this as unsigned */
+ value = ev->value;
+@@ -622,10 +628,63 @@ EvdevProcessRelativeMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
+
+ pEvdev->rel_queued = 1;
+ pEvdev->delta[ev->code] += value;
++ map = pEvdev->axis_map[ev->code];
++ valuator_mask_set(pEvdev->vals, map, value);
+ break;
+ }
+ }
+
++#ifdef MULTITOUCH
++static void
++EvdevProcessTouch(InputInfoPtr pInfo)
++{
++ EvdevPtr pEvdev = pInfo->private;
++
++ if (pEvdev->cur_slot < 0 || !pEvdev->mt_vals ||
++ (!pEvdev->open_slot && !pEvdev->close_slot &&
++ valuator_mask_num_valuators(pEvdev->mt_vals) == 0))
++ return;
++
++ if (pEvdev->close_slot) {
++ EvdevQueueTouchEvent(pInfo, pEvdev->cur_slot, pEvdev->mt_vals,
++ XI_TouchEnd);
++ pEvdev->close_slot = 0;
++ } else {
++ EvdevQueueTouchEvent(pInfo, pEvdev->cur_slot, pEvdev->mt_vals,
++ pEvdev->open_slot ? XI_TouchBegin :
++ XI_TouchUpdate);
++ pEvdev->open_slot = 0;
++ }
++
++ valuator_mask_zero(pEvdev->mt_vals);
++}
++
++static void
++EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev)
++{
++ EvdevPtr pEvdev = pInfo->private;
++ int map;
++
++ if (ev->code == ABS_MT_SLOT) {
++ EvdevProcessTouch(pInfo);
++ pEvdev->cur_slot = ev->value;
++ } else if (ev->code == ABS_MT_TRACKING_ID) {
++ if (ev->value >= 0) {
++ pEvdev->open_slot = 1;
++ valuator_mask_copy(pEvdev->mt_vals, pEvdev->cur_vals);
++ } else
++ pEvdev->close_slot = 1;
++ } else {
++ map = pEvdev->axis_map[ev->code] - pEvdev->num_vals;
++ valuator_mask_set(pEvdev->mt_vals, map, ev->value);
++ valuator_mask_set(pEvdev->cur_vals, map, ev->value);
++ }
++}
++#else
++#define EvdevProcessTouch(pInfo)
++#define EvdevProcessTouchEvent(pInfo, ev)
++#endif /* MULTITOUCH */
++
+ /**
+ * Take the absolute motion input event and process it accordingly.
+ */
+@@ -634,6 +693,7 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
+ {
+ int value;
+ EvdevPtr pEvdev = pInfo->private;
++ int map;
+
+ /* Get the signed value, earlier kernels had this as unsigned */
+ value = ev->value;
+@@ -648,13 +708,16 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
+ if (EvdevWheelEmuFilterMotion(pInfo, ev))
+ return;
+
+- pEvdev->vals[pEvdev->axis_map[ev->code]] = value;
+- if (ev->code == ABS_X)
+- pEvdev->abs_queued |= ABS_X_VALUE;
+- else if (ev->code == ABS_Y)
+- pEvdev->abs_queued |= ABS_Y_VALUE;
+- else
+- pEvdev->abs_queued |= ABS_VALUE;
++ if (ev->code >= ABS_MT_SLOT) {
++ EvdevProcessTouchEvent(pInfo, ev);
++ pEvdev->abs_queued = 1;
++ }
++ /* Direct touch devices use server side pointer emulation */
++ else if (!pInfo->dev->touch || pInfo->dev->touch->mode != XIDirectTouch) {
++ map = pEvdev->axis_map[ev->code];
++ valuator_mask_set(pEvdev->vals, map, value);
++ pEvdev->abs_queued = 1;
++ }
+ }
+
+ /**
+@@ -712,7 +775,7 @@ EvdevPostRelativeMotionEvents(InputInfoPtr pInfo, int num_v, int first_v,
+ EvdevPtr pEvdev = pInfo->private;
+
+ if (pEvdev->rel_queued) {
+- xf86PostMotionEventP(pInfo->dev, FALSE, first_v, num_v, v + first_v);
++ xf86PostMotionEventM(pInfo->dev, FALSE, pEvdev->vals);
+ }
+ }
+
+@@ -735,7 +798,7 @@ EvdevPostAbsoluteMotionEvents(InputInfoPtr pInfo, int num_v, int first_v,
+ * this scheme still just work.
+ */
+ if (pEvdev->abs_queued && pEvdev->in_proximity) {
+- xf86PostMotionEventP(pInfo->dev, TRUE, first_v, num_v, v + first_v);
++ xf86PostMotionEventM(pInfo->dev, TRUE, pEvdev->vals);
+ }
+ }
+
+@@ -750,6 +813,9 @@ EvdevPostProximityEvents(InputInfoPtr pInfo, int which, int num_v, int first_v,
+ switch (pEvdev->queue[i].type) {
+ case EV_QUEUE_KEY:
+ case EV_QUEUE_BTN:
++#ifdef MULTITOUCH
++ case EV_QUEUE_TOUCH:
++#endif
+ break;
+ case EV_QUEUE_PROXIMITY:
+ if (pEvdev->queue[i].val == which)
+@@ -772,23 +838,28 @@ static void EvdevPostQueuedEvents(InputInfoPtr pInfo, int num_v, int first_v,
+ for (i = 0; i < pEvdev->num_queue; i++) {
+ switch (pEvdev->queue[i].type) {
+ case EV_QUEUE_KEY:
+- xf86PostKeyboardEvent(pInfo->dev, pEvdev->queue[i].key,
++ xf86PostKeyboardEvent(pInfo->dev, pEvdev->queue[i].detail.key,
+ pEvdev->queue[i].val);
+ break;
+ case EV_QUEUE_BTN:
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 11
+ if (pEvdev->abs_queued && pEvdev->in_proximity) {
+- xf86PostButtonEventP(pInfo->dev, 1, pEvdev->queue[i].key,
++ xf86PostButtonEventP(pInfo->dev, 1, pEvdev->queue[i].detail.key,
+ pEvdev->queue[i].val, first_v, num_v,
+ v + first_v);
+
+ } else
+-#endif
+- xf86PostButtonEvent(pInfo->dev, 0, pEvdev->queue[i].key,
++ xf86PostButtonEvent(pInfo->dev, 0, pEvdev->queue[i].detail.key,
+ pEvdev->queue[i].val, 0, 0);
+ break;
+ case EV_QUEUE_PROXIMITY:
+ break;
++#ifdef MULTITOUCH
++ case EV_QUEUE_TOUCH:
++ xf86PostTouchEvent(pInfo->dev, pEvdev->queue[i].detail.touch,
++ pEvdev->queue[i].val, 0,
++ pEvdev->queue[i].touch_vals);
++ break;
++#endif
+ }
+ }
+ }
+@@ -806,7 +877,8 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev)
+
+ EvdevProcessProximityState(pInfo);
+
+- EvdevProcessValuators(pInfo, v, &num_v, &first_v);
++ EvdevProcessValuators(pInfo);
++ EvdevProcessTouch(pInfo);
+
+ EvdevPostProximityEvents(pInfo, TRUE, num_v, first_v, v);
+ EvdevPostRelativeMotionEvents(pInfo, num_v, first_v, v);
+@@ -815,7 +887,8 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev)
+ EvdevPostProximityEvents(pInfo, FALSE, num_v, first_v, v);
+
+ memset(pEvdev->delta, 0, sizeof(pEvdev->delta));
+- memset(pEvdev->queue, 0, sizeof(pEvdev->queue));
++ if (pEvdev->vals)
++ valuator_mask_zero(pEvdev->vals);
+ pEvdev->num_queue = 0;
+ pEvdev->abs_queued = 0;
+ pEvdev->rel_queued = 0;
+@@ -861,7 +934,17 @@ EvdevReadInput(InputInfoPtr pInfo)
+
+ while (len == sizeof(ev))
+ {
+- len = read(pInfo->fd, &ev, sizeof(ev));
++#ifdef MULTITOUCH
++ EvdevPtr pEvdev = pInfo->private;
++
++ if (pEvdev->mtdev)
++ len = mtdev_get(pEvdev->mtdev, pInfo->fd, ev, NUM_EVENTS) *
++ sizeof(struct input_event);
++ else
++ len = read(pInfo->fd, &ev, sizeof(ev));
++#else
++ len = read(pInfo->fd, &ev, sizeof(ev));
++#endif
+ if (len <= 0)
+ {
+ if (errno == ENODEV) /* May happen after resume */
+@@ -900,317 +983,6 @@ EvdevPtrCtrlProc(DeviceIntPtr device, PtrCtrl *ctrl)
+ /* Nothing to do, dix handles all settings */
+ }
+
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 5
+-static KeySym map[] = {
+- /* 0x00 */ NoSymbol, NoSymbol,
+- /* 0x01 */ XK_Escape, NoSymbol,
+- /* 0x02 */ XK_1, XK_exclam,
+- /* 0x03 */ XK_2, XK_at,
+- /* 0x04 */ XK_3, XK_numbersign,
+- /* 0x05 */ XK_4, XK_dollar,
+- /* 0x06 */ XK_5, XK_percent,
+- /* 0x07 */ XK_6, XK_asciicircum,
+- /* 0x08 */ XK_7, XK_ampersand,
+- /* 0x09 */ XK_8, XK_asterisk,
+- /* 0x0a */ XK_9, XK_parenleft,
+- /* 0x0b */ XK_0, XK_parenright,
+- /* 0x0c */ XK_minus, XK_underscore,
+- /* 0x0d */ XK_equal, XK_plus,
+- /* 0x0e */ XK_BackSpace, NoSymbol,
+- /* 0x0f */ XK_Tab, XK_ISO_Left_Tab,
+- /* 0x10 */ XK_Q, NoSymbol,
+- /* 0x11 */ XK_W, NoSymbol,
+- /* 0x12 */ XK_E, NoSymbol,
+- /* 0x13 */ XK_R, NoSymbol,
+- /* 0x14 */ XK_T, NoSymbol,
+- /* 0x15 */ XK_Y, NoSymbol,
+- /* 0x16 */ XK_U, NoSymbol,
+- /* 0x17 */ XK_I, NoSymbol,
+- /* 0x18 */ XK_O, NoSymbol,
+- /* 0x19 */ XK_P, NoSymbol,
+- /* 0x1a */ XK_bracketleft, XK_braceleft,
+- /* 0x1b */ XK_bracketright,XK_braceright,
+- /* 0x1c */ XK_Return, NoSymbol,
+- /* 0x1d */ XK_Control_L, NoSymbol,
+- /* 0x1e */ XK_A, NoSymbol,
+- /* 0x1f */ XK_S, NoSymbol,
+- /* 0x20 */ XK_D, NoSymbol,
+- /* 0x21 */ XK_F, NoSymbol,
+- /* 0x22 */ XK_G, NoSymbol,
+- /* 0x23 */ XK_H, NoSymbol,
+- /* 0x24 */ XK_J, NoSymbol,
+- /* 0x25 */ XK_K, NoSymbol,
+- /* 0x26 */ XK_L, NoSymbol,
+- /* 0x27 */ XK_semicolon, XK_colon,
+- /* 0x28 */ XK_quoteright, XK_quotedbl,
+- /* 0x29 */ XK_quoteleft, XK_asciitilde,
+- /* 0x2a */ XK_Shift_L, NoSymbol,
+- /* 0x2b */ XK_backslash, XK_bar,
+- /* 0x2c */ XK_Z, NoSymbol,
+- /* 0x2d */ XK_X, NoSymbol,
+- /* 0x2e */ XK_C, NoSymbol,
+- /* 0x2f */ XK_V, NoSymbol,
+- /* 0x30 */ XK_B, NoSymbol,
+- /* 0x31 */ XK_N, NoSymbol,
+- /* 0x32 */ XK_M, NoSymbol,
+- /* 0x33 */ XK_comma, XK_less,
+- /* 0x34 */ XK_period, XK_greater,
+- /* 0x35 */ XK_slash, XK_question,
+- /* 0x36 */ XK_Shift_R, NoSymbol,
+- /* 0x37 */ XK_KP_Multiply, NoSymbol,
+- /* 0x38 */ XK_Alt_L, XK_Meta_L,
+- /* 0x39 */ XK_space, NoSymbol,
+- /* 0x3a */ XK_Caps_Lock, NoSymbol,
+- /* 0x3b */ XK_F1, NoSymbol,
+- /* 0x3c */ XK_F2, NoSymbol,
+- /* 0x3d */ XK_F3, NoSymbol,
+- /* 0x3e */ XK_F4, NoSymbol,
+- /* 0x3f */ XK_F5, NoSymbol,
+- /* 0x40 */ XK_F6, NoSymbol,
+- /* 0x41 */ XK_F7, NoSymbol,
+- /* 0x42 */ XK_F8, NoSymbol,
+- /* 0x43 */ XK_F9, NoSymbol,
+- /* 0x44 */ XK_F10, NoSymbol,
+- /* 0x45 */ XK_Num_Lock, NoSymbol,
+- /* 0x46 */ XK_Scroll_Lock, NoSymbol,
+- /* These KP keys should have the KP_7 keysyms in the numlock
+- * modifer... ? */
+- /* 0x47 */ XK_KP_Home, XK_KP_7,
+- /* 0x48 */ XK_KP_Up, XK_KP_8,
+- /* 0x49 */ XK_KP_Prior, XK_KP_9,
+- /* 0x4a */ XK_KP_Subtract, NoSymbol,
+- /* 0x4b */ XK_KP_Left, XK_KP_4,
+- /* 0x4c */ XK_KP_Begin, XK_KP_5,
+- /* 0x4d */ XK_KP_Right, XK_KP_6,
+- /* 0x4e */ XK_KP_Add, NoSymbol,
+- /* 0x4f */ XK_KP_End, XK_KP_1,
+- /* 0x50 */ XK_KP_Down, XK_KP_2,
+- /* 0x51 */ XK_KP_Next, XK_KP_3,
+- /* 0x52 */ XK_KP_Insert, XK_KP_0,
+- /* 0x53 */ XK_KP_Delete, XK_KP_Decimal,
+- /* 0x54 */ NoSymbol, NoSymbol,
+- /* 0x55 */ XK_F13, NoSymbol,
+- /* 0x56 */ XK_less, XK_greater,
+- /* 0x57 */ XK_F11, NoSymbol,
+- /* 0x58 */ XK_F12, NoSymbol,
+- /* 0x59 */ XK_F14, NoSymbol,
+- /* 0x5a */ XK_F15, NoSymbol,
+- /* 0x5b */ XK_F16, NoSymbol,
+- /* 0x5c */ XK_F17, NoSymbol,
+- /* 0x5d */ XK_F18, NoSymbol,
+- /* 0x5e */ XK_F19, NoSymbol,
+- /* 0x5f */ XK_F20, NoSymbol,
+- /* 0x60 */ XK_KP_Enter, NoSymbol,
+- /* 0x61 */ XK_Control_R, NoSymbol,
+- /* 0x62 */ XK_KP_Divide, NoSymbol,
+- /* 0x63 */ XK_Print, XK_Sys_Req,
+- /* 0x64 */ XK_Alt_R, XK_Meta_R,
+- /* 0x65 */ NoSymbol, NoSymbol, /* KEY_LINEFEED */
+- /* 0x66 */ XK_Home, NoSymbol,
+- /* 0x67 */ XK_Up, NoSymbol,
+- /* 0x68 */ XK_Prior, NoSymbol,
+- /* 0x69 */ XK_Left, NoSymbol,
+- /* 0x6a */ XK_Right, NoSymbol,
+- /* 0x6b */ XK_End, NoSymbol,
+- /* 0x6c */ XK_Down, NoSymbol,
+- /* 0x6d */ XK_Next, NoSymbol,
+- /* 0x6e */ XK_Insert, NoSymbol,
+- /* 0x6f */ XK_Delete, NoSymbol,
+- /* 0x70 */ NoSymbol, NoSymbol, /* KEY_MACRO */
+- /* 0x71 */ NoSymbol, NoSymbol,
+- /* 0x72 */ NoSymbol, NoSymbol,
+- /* 0x73 */ NoSymbol, NoSymbol,
+- /* 0x74 */ NoSymbol, NoSymbol,
+- /* 0x75 */ XK_KP_Equal, NoSymbol,
+- /* 0x76 */ NoSymbol, NoSymbol,
+- /* 0x77 */ NoSymbol, NoSymbol,
+- /* 0x78 */ XK_F21, NoSymbol,
+- /* 0x79 */ XK_F22, NoSymbol,
+- /* 0x7a */ XK_F23, NoSymbol,
+- /* 0x7b */ XK_F24, NoSymbol,
+- /* 0x7c */ XK_KP_Separator, NoSymbol,
+- /* 0x7d */ XK_Meta_L, NoSymbol,
+- /* 0x7e */ XK_Meta_R, NoSymbol,
+- /* 0x7f */ XK_Multi_key, NoSymbol,
+- /* 0x80 */ NoSymbol, NoSymbol,
+- /* 0x81 */ NoSymbol, NoSymbol,
+- /* 0x82 */ NoSymbol, NoSymbol,
+- /* 0x83 */ NoSymbol, NoSymbol,
+- /* 0x84 */ NoSymbol, NoSymbol,
+- /* 0x85 */ NoSymbol, NoSymbol,
+- /* 0x86 */ NoSymbol, NoSymbol,
+- /* 0x87 */ NoSymbol, NoSymbol,
+- /* 0x88 */ NoSymbol, NoSymbol,
+- /* 0x89 */ NoSymbol, NoSymbol,
+- /* 0x8a */ NoSymbol, NoSymbol,
+- /* 0x8b */ NoSymbol, NoSymbol,
+- /* 0x8c */ NoSymbol, NoSymbol,
+- /* 0x8d */ NoSymbol, NoSymbol,
+- /* 0x8e */ NoSymbol, NoSymbol,
+- /* 0x8f */ NoSymbol, NoSymbol,
+- /* 0x90 */ NoSymbol, NoSymbol,
+- /* 0x91 */ NoSymbol, NoSymbol,
+- /* 0x92 */ NoSymbol, NoSymbol,
+- /* 0x93 */ NoSymbol, NoSymbol,
+- /* 0x94 */ NoSymbol, NoSymbol,
+- /* 0x95 */ NoSymbol, NoSymbol,
+- /* 0x96 */ NoSymbol, NoSymbol,
+- /* 0x97 */ NoSymbol, NoSymbol,
+- /* 0x98 */ NoSymbol, NoSymbol,
+- /* 0x99 */ NoSymbol, NoSymbol,
+- /* 0x9a */ NoSymbol, NoSymbol,
+- /* 0x9b */ NoSymbol, NoSymbol,
+- /* 0x9c */ NoSymbol, NoSymbol,
+- /* 0x9d */ NoSymbol, NoSymbol,
+- /* 0x9e */ NoSymbol, NoSymbol,
+- /* 0x9f */ NoSymbol, NoSymbol,
+- /* 0xa0 */ NoSymbol, NoSymbol,
+- /* 0xa1 */ NoSymbol, NoSymbol,
+- /* 0xa2 */ NoSymbol, NoSymbol,
+- /* 0xa3 */ NoSymbol, NoSymbol,
+- /* 0xa4 */ NoSymbol, NoSymbol,
+- /* 0xa5 */ NoSymbol, NoSymbol,
+- /* 0xa6 */ NoSymbol, NoSymbol,
+- /* 0xa7 */ NoSymbol, NoSymbol,
+- /* 0xa8 */ NoSymbol, NoSymbol,
+- /* 0xa9 */ NoSymbol, NoSymbol,
+- /* 0xaa */ NoSymbol, NoSymbol,
+- /* 0xab */ NoSymbol, NoSymbol,
+- /* 0xac */ NoSymbol, NoSymbol,
+- /* 0xad */ NoSymbol, NoSymbol,
+- /* 0xae */ NoSymbol, NoSymbol,
+- /* 0xaf */ NoSymbol, NoSymbol,
+- /* 0xb0 */ NoSymbol, NoSymbol,
+- /* 0xb1 */ NoSymbol, NoSymbol,
+- /* 0xb2 */ NoSymbol, NoSymbol,
+- /* 0xb3 */ NoSymbol, NoSymbol,
+- /* 0xb4 */ NoSymbol, NoSymbol,
+- /* 0xb5 */ NoSymbol, NoSymbol,
+- /* 0xb6 */ NoSymbol, NoSymbol,
+- /* 0xb7 */ NoSymbol, NoSymbol,
+- /* 0xb8 */ NoSymbol, NoSymbol,
+- /* 0xb9 */ NoSymbol, NoSymbol,
+- /* 0xba */ NoSymbol, NoSymbol,
+- /* 0xbb */ NoSymbol, NoSymbol,
+- /* 0xbc */ NoSymbol, NoSymbol,
+- /* 0xbd */ NoSymbol, NoSymbol,
+- /* 0xbe */ NoSymbol, NoSymbol,
+- /* 0xbf */ NoSymbol, NoSymbol,
+- /* 0xc0 */ NoSymbol, NoSymbol,
+- /* 0xc1 */ NoSymbol, NoSymbol,
+- /* 0xc2 */ NoSymbol, NoSymbol,
+- /* 0xc3 */ NoSymbol, NoSymbol,
+- /* 0xc4 */ NoSymbol, NoSymbol,
+- /* 0xc5 */ NoSymbol, NoSymbol,
+- /* 0xc6 */ NoSymbol, NoSymbol,
+- /* 0xc7 */ NoSymbol, NoSymbol,
+- /* 0xc8 */ NoSymbol, NoSymbol,
+- /* 0xc9 */ NoSymbol, NoSymbol,
+- /* 0xca */ NoSymbol, NoSymbol,
+- /* 0xcb */ NoSymbol, NoSymbol,
+- /* 0xcc */ NoSymbol, NoSymbol,
+- /* 0xcd */ NoSymbol, NoSymbol,
+- /* 0xce */ NoSymbol, NoSymbol,
+- /* 0xcf */ NoSymbol, NoSymbol,
+- /* 0xd0 */ NoSymbol, NoSymbol,
+- /* 0xd1 */ NoSymbol, NoSymbol,
+- /* 0xd2 */ NoSymbol, NoSymbol,
+- /* 0xd3 */ NoSymbol, NoSymbol,
+- /* 0xd4 */ NoSymbol, NoSymbol,
+- /* 0xd5 */ NoSymbol, NoSymbol,
+- /* 0xd6 */ NoSymbol, NoSymbol,
+- /* 0xd7 */ NoSymbol, NoSymbol,
+- /* 0xd8 */ NoSymbol, NoSymbol,
+- /* 0xd9 */ NoSymbol, NoSymbol,
+- /* 0xda */ NoSymbol, NoSymbol,
+- /* 0xdb */ NoSymbol, NoSymbol,
+- /* 0xdc */ NoSymbol, NoSymbol,
+- /* 0xdd */ NoSymbol, NoSymbol,
+- /* 0xde */ NoSymbol, NoSymbol,
+- /* 0xdf */ NoSymbol, NoSymbol,
+- /* 0xe0 */ NoSymbol, NoSymbol,
+- /* 0xe1 */ NoSymbol, NoSymbol,
+- /* 0xe2 */ NoSymbol, NoSymbol,
+- /* 0xe3 */ NoSymbol, NoSymbol,
+- /* 0xe4 */ NoSymbol, NoSymbol,
+- /* 0xe5 */ NoSymbol, NoSymbol,
+- /* 0xe6 */ NoSymbol, NoSymbol,
+- /* 0xe7 */ NoSymbol, NoSymbol,
+- /* 0xe8 */ NoSymbol, NoSymbol,
+- /* 0xe9 */ NoSymbol, NoSymbol,
+- /* 0xea */ NoSymbol, NoSymbol,
+- /* 0xeb */ NoSymbol, NoSymbol,
+- /* 0xec */ NoSymbol, NoSymbol,
+- /* 0xed */ NoSymbol, NoSymbol,
+- /* 0xee */ NoSymbol, NoSymbol,
+- /* 0xef */ NoSymbol, NoSymbol,
+- /* 0xf0 */ NoSymbol, NoSymbol,
+- /* 0xf1 */ NoSymbol, NoSymbol,
+- /* 0xf2 */ NoSymbol, NoSymbol,
+- /* 0xf3 */ NoSymbol, NoSymbol,
+- /* 0xf4 */ NoSymbol, NoSymbol,
+- /* 0xf5 */ NoSymbol, NoSymbol,
+- /* 0xf6 */ NoSymbol, NoSymbol,
+- /* 0xf7 */ NoSymbol, NoSymbol,
+-};
+-
+-static struct { KeySym keysym; CARD8 mask; } modifiers[] = {
+- { XK_Shift_L, ShiftMask },
+- { XK_Shift_R, ShiftMask },
+- { XK_Control_L, ControlMask },
+- { XK_Control_R, ControlMask },
+- { XK_Caps_Lock, LockMask },
+- { XK_Alt_L, AltMask },
+- { XK_Alt_R, AltMask },
+- { XK_Meta_L, Mod4Mask },
+- { XK_Meta_R, Mod4Mask },
+- { XK_Num_Lock, NumLockMask },
+- { XK_Scroll_Lock, ScrollLockMask },
+- { XK_Mode_switch, AltLangMask }
+-};
+-
+-/* Server 1.6 and earlier */
+-static int
+-EvdevInitKeysyms(DeviceIntPtr device)
+-{
+- InputInfoPtr pInfo;
+- EvdevPtr pEvdev;
+- KeySymsRec keySyms;
+- CARD8 modMap[MAP_LENGTH];
+- KeySym sym;
+- int i, j;
+-
+- pInfo = device->public.devicePrivate;
+- pEvdev = pInfo->private;
+-
+- /* Compute the modifier map */
+- memset(modMap, 0, sizeof modMap);
+-
+- for (i = 0; i < ArrayLength(map) / GLYPHS_PER_KEY; i++) {
+- sym = map[i * GLYPHS_PER_KEY];
+- for (j = 0; j < ArrayLength(modifiers); j++) {
+- if (modifiers[j].keysym == sym)
+- modMap[i + MIN_KEYCODE] = modifiers[j].mask;
+- }
+- }
+-
+- keySyms.map = map;
+- keySyms.mapWidth = GLYPHS_PER_KEY;
+- keySyms.minKeyCode = MIN_KEYCODE;
+- keySyms.maxKeyCode = MIN_KEYCODE + ArrayLength(map) / GLYPHS_PER_KEY - 1;
+-
+- XkbSetRulesDflts(pEvdev->rmlvo.rules, pEvdev->rmlvo.model,
+- pEvdev->rmlvo.layout, pEvdev->rmlvo.variant,
+- pEvdev->rmlvo.options);
+- if (!XkbInitKeyboardDeviceStruct(device, &pEvdev->xkbnames,
+- &keySyms, modMap, NULL,
+- EvdevKbdCtrl))
+- return 0;
+-
+- return 1;
+-}
+-#endif
+-
+ static void
+ EvdevKbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl)
+ {
+@@ -1263,14 +1035,8 @@ EvdevAddKeyClass(DeviceIntPtr device)
+ if (!pEvdev->rmlvo.options)
+ SetXkbOption(pInfo, "XkbOptions", &pEvdev->rmlvo.options);
+
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5
+ if (!InitKeyboardDeviceStruct(device, &pEvdev->rmlvo, NULL, EvdevKbdCtrl))
+ return !Success;
+-#else
+- if (!EvdevInitKeysyms(device))
+- return !Success;
+-
+-#endif
+
+ return Success;
+ }
+@@ -1280,53 +1046,114 @@ EvdevAddAbsClass(DeviceIntPtr device)
+ {
+ InputInfoPtr pInfo;
+ EvdevPtr pEvdev;
+- int num_axes, axis, i = 0;
++ int num_axes, num_mt_axes, axis, i = 0;
+ Atom *atoms;
+
+ pInfo = device->public.devicePrivate;
+ pEvdev = pInfo->private;
+
+ if (!TestBit(EV_ABS, pEvdev->bitmask))
+- return !Success;
++ goto out;
+
+- num_axes = EvdevCountBits(pEvdev->abs_bitmask, NLONGS(ABS_MAX));
+- if (num_axes < 1)
+- return !Success;
++ num_axes = CountBits((uint8_t *)pEvdev->abs_bitmask, ABS_MT_SLOT);
++ num_mt_axes = CountBits((uint8_t *)pEvdev->abs_bitmask, ABS_CNT) - num_axes;
+
+ if (num_axes > MAX_VALUATORS) {
+ xf86Msg(X_WARNING, "%s: found %d axes, limiting to %d.\n", device->name, num_axes, MAX_VALUATORS);
+ num_axes = MAX_VALUATORS;
+ }
+
++#ifdef MULTITOUCH
++ if (TestBit(ABS_MT_SLOT, pEvdev->abs_bitmask))
++ num_mt_axes--;
++ if (TestBit(ABS_MT_TRACKING_ID, pEvdev->abs_bitmask))
++ num_mt_axes--;
++
++ if (num_mt_axes > MAX_VALUATORS) {
++ xf86Msg(X_WARNING, "%s: found %d MT axes, limiting to %d.\n", device->name, num_axes, MAX_VALUATORS);
++ num_mt_axes = MAX_VALUATORS;
++ }
++#endif
++
++ if (num_axes < 1 && num_mt_axes < 1) {
++ xf86Msg(X_WARNING, "%s: no absolute or touch axes found.\n",
++ device->name);
++ goto out;
++ }
++
+ pEvdev->num_vals = num_axes;
+- memset(pEvdev->vals, 0, num_axes * sizeof(int));
+- memset(pEvdev->old_vals, -1, num_axes * sizeof(int));
+- atoms = malloc(pEvdev->num_vals * sizeof(Atom));
++ if (num_axes > 0) {
++ pEvdev->vals = valuator_mask_new(num_axes);
++ pEvdev->old_vals = valuator_mask_new(num_axes);
++ if (!pEvdev->vals || !pEvdev->old_vals) {
++ xf86Msg(X_ERROR, "%s: failed to allocate valuator masks.\n",
++ device->name);
++ goto out;
++ }
++ }
++#ifdef MULTITOUCH
++ pEvdev->num_mt_vals = num_mt_axes;
++ if (num_mt_axes > 0) {
++ pEvdev->mt_vals = valuator_mask_new(num_mt_axes);
++ pEvdev->cur_vals = valuator_mask_new(num_mt_axes);
++ if (!pEvdev->mt_vals || !pEvdev->cur_vals) {
++ xf86Msg(X_ERROR, "%s: failed to allocate MT valuator mask.\n",
++ device->name);
++ goto out;
++ }
+
++ for (i = 0; i < EVDEV_MAXQUEUE; i++) {
++ pEvdev->queue[i].touch_vals =
++ valuator_mask_new(num_mt_axes);
++ if (!pEvdev->queue[i].touch_vals) {
++ xf86Msg(X_ERROR, "%s: failed to allocate MT valuator masks for "
++ "evdev event queue.\n", device->name);
++ goto out;
++ }
++ }
++ }
++#endif
++ atoms = malloc((pEvdev->num_vals + num_mt_axes) * sizeof(Atom));
++
++ i = 0;
+ for (axis = ABS_X; i < MAX_VALUATORS && axis <= ABS_MAX; axis++) {
+ pEvdev->axis_map[axis] = -1;
+- if (!TestBit(axis, pEvdev->abs_bitmask))
++ if (!TestBit(axis, pEvdev->abs_bitmask) || axis == ABS_MT_SLOT ||
++ axis == ABS_MT_TRACKING_ID)
+ continue;
+ pEvdev->axis_map[axis] = i;
+ i++;
+ }
+
+- EvdevInitAxesLabels(pEvdev, pEvdev->num_vals, atoms);
++ EvdevInitAxesLabels(pEvdev, pEvdev->num_vals + num_mt_axes, atoms);
+
+- if (!InitValuatorClassDeviceStruct(device, num_axes,
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+- atoms,
+-#endif
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
+- GetMotionHistory,
+-#endif
++ if (!InitValuatorClassDeviceStruct(device, num_axes, atoms,
+ GetMotionHistorySize(), Absolute)) {
+ xf86Msg(X_ERROR, "%s: failed to initialize valuator class device.\n",
+ device->name);
+- return !Success;
++ goto out;
++ }
++
++#ifdef MULTITOUCH
++ if (num_mt_axes > 0)
++ {
++ int num_touches = 10;
++ int mode = pEvdev->flags & EVDEV_TOUCHPAD ?
++ XIDependentTouch : XIDirectTouch;
++
++ if (pEvdev->mtdev->caps.slot.maximum > 0)
++ num_touches = pEvdev->mtdev->caps.slot.maximum;
++
++ if (!InitTouchClassDeviceStruct(device, num_touches, mode,
++ num_mt_axes)) {
++ xf86Msg(X_ERROR, "%s: failed to initialize touch class device.\n",
++ device->name);
++ goto out;
++ }
+ }
++#endif
+
+- for (axis = ABS_X; axis <= ABS_MAX; axis++) {
++ for (axis = ABS_X; axis < ABS_MT_SLOT; axis++) {
+ int axnum = pEvdev->axis_map[axis];
+ int resolution = 10000;
+
+@@ -1340,20 +1167,32 @@ EvdevAddAbsClass(DeviceIntPtr device)
+ #endif
+
+ xf86InitValuatorAxisStruct(device, axnum,
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+ atoms[axnum],
+-#endif
+ pEvdev->absinfo[axis].minimum,
+ pEvdev->absinfo[axis].maximum,
+- resolution, 0, resolution
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
+- , Absolute
+-#endif
+- );
++ resolution, 0, resolution, Absolute);
+ xf86InitValuatorDefaults(device, axnum);
+- pEvdev->old_vals[axnum] = -1;
+ }
+
++#ifdef MULTITOUCH
++ for (axis = ABS_MT_TOUCH_MAJOR; axis <= ABS_MAX; axis++) {
++ int axnum = pEvdev->axis_map[axis] - pEvdev->num_vals;
++ int resolution = 10000;
++
++ if (axnum < 0)
++ continue;
++
++ if (pEvdev->absinfo[axis].resolution)
++ resolution = pEvdev->absinfo[axis].resolution * 1000;
++
++ xf86InitTouchValuatorAxisStruct(device, axnum,
++ atoms[axnum + pEvdev->num_vals],
++ pEvdev->absinfo[axis].minimum,
++ pEvdev->absinfo[axis].maximum,
++ pEvdev->absinfo[axis].resolution);
++ }
++#endif
++
+ free(atoms);
+
+ for (i = 0; i < ArrayLength(proximity_bits); i++)
+@@ -1364,6 +1203,12 @@ EvdevAddAbsClass(DeviceIntPtr device)
+ if (TestBit(proximity_bits[i], pEvdev->key_bitmask))
+ {
+ InitProximityClassDeviceStruct(device);
++ pEvdev->prox = valuator_mask_new(num_axes);
++ if (!pEvdev->prox) {
++ xf86Msg(X_ERROR, "%s: failed to allocate proximity valuator "
++ "mask.\n", device->name);
++ goto out;
++ }
+ break;
+ }
+ }
+@@ -1371,7 +1216,7 @@ EvdevAddAbsClass(DeviceIntPtr device)
+ if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc)) {
+ xf86Msg(X_ERROR, "%s: failed to initialize pointer feedback class "
+ "device.\n", device->name);
+- return !Success;
++ goto out;
+ }
+
+ if (pEvdev->flags & EVDEV_TOUCHPAD)
+@@ -1393,6 +1238,18 @@ EvdevAddAbsClass(DeviceIntPtr device)
+ }
+
+ return Success;
++
++out:
++#ifdef MULTITOUCH
++ valuator_mask_free(&pEvdev->mt_vals);
++ valuator_mask_free(&pEvdev->cur_vals);
++ for (i = 0; i < EVDEV_MAXQUEUE; i++)
++ valuator_mask_free(&pEvdev->queue[i].touch_vals);
++#endif
++ valuator_mask_free(&pEvdev->vals);
++ valuator_mask_free(&pEvdev->old_vals);
++ valuator_mask_free(&pEvdev->prox);
++ return !Success;
+ }
+
+ static int
+@@ -1407,11 +1264,11 @@ EvdevAddRelClass(DeviceIntPtr device)
+ pEvdev = pInfo->private;
+
+ if (!TestBit(EV_REL, pEvdev->bitmask))
+- return !Success;
++ goto out;
+
+ num_axes = EvdevCountBits(pEvdev->rel_bitmask, NLONGS(REL_MAX));
+ if (num_axes < 1)
+- return !Success;
++ goto out;
+
+ /* Wheels are special, we post them as button events. So let's ignore them
+ * in the axes list too */
+@@ -1423,7 +1280,7 @@ EvdevAddRelClass(DeviceIntPtr device)
+ num_axes--;
+
+ if (num_axes <= 0)
+- return !Success;
++ goto out;
+
+ if (num_axes > MAX_VALUATORS) {
+ xf86Msg(X_WARNING, "%s: found %d axes, limiting to %d.\n", device->name, num_axes, MAX_VALUATORS);
+@@ -1431,7 +1288,11 @@ EvdevAddRelClass(DeviceIntPtr device)
+ }
+
+ pEvdev->num_vals = num_axes;
+- memset(pEvdev->vals, 0, num_axes * sizeof(int));
++ if (num_axes > 0) {
++ pEvdev->vals = valuator_mask_new(num_axes);
++ if (!pEvdev->vals)
++ goto out;
++ }
+ atoms = malloc(pEvdev->num_vals * sizeof(Atom));
+
+ for (axis = REL_X; i < MAX_VALUATORS && axis <= REL_MAX; axis++)
+@@ -1448,23 +1309,17 @@ EvdevAddRelClass(DeviceIntPtr device)
+
+ EvdevInitAxesLabels(pEvdev, pEvdev->num_vals, atoms);
+
+- if (!InitValuatorClassDeviceStruct(device, num_axes,
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+- atoms,
+-#endif
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
+- GetMotionHistory,
+-#endif
++ if (!InitValuatorClassDeviceStruct(device, num_axes, atoms,
+ GetMotionHistorySize(), Relative)) {
+ xf86Msg(X_ERROR, "%s: failed to initialize valuator class device.\n",
+ device->name);
+- return !Success;
++ goto out;
+ }
+
+ if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc)) {
+ xf86Msg(X_ERROR, "%s: failed to initialize pointer feedback class "
+ "device.\n", device->name);
+- return !Success;
++ goto out;
+ }
+
+ for (axis = REL_X; axis <= REL_MAX; axis++)
+@@ -1473,21 +1328,18 @@ EvdevAddRelClass(DeviceIntPtr device)
+
+ if (axnum == -1)
+ continue;
+- xf86InitValuatorAxisStruct(device, axnum,
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+- atoms[axnum],
+-#endif
+- -1, -1, 1, 0, 1
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
+- , Relative
+-#endif
+- );
++ xf86InitValuatorAxisStruct(device, axnum, atoms[axnum], -1, -1, 1, 0, 1,
++ Relative);
+ xf86InitValuatorDefaults(device, axnum);
+ }
+
+ free(atoms);
+
+ return Success;
++
++out:
++ valuator_mask_free(&pEvdev->vals);
++ return !Success;
+ }
+
+ static int
+@@ -1503,10 +1355,7 @@ EvdevAddButtonClass(DeviceIntPtr device)
+ labels = malloc(pEvdev->num_buttons * sizeof(Atom));
+ EvdevInitButtonLabels(pEvdev, pEvdev->num_buttons, labels);
+
+- if (!InitButtonClassDeviceStruct(device, pEvdev->num_buttons,
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+- labels,
+-#endif
++ if (!InitButtonClassDeviceStruct(device, pEvdev->num_buttons, labels,
+ pEvdev->btnmap))
+ return !Success;
+
+@@ -1678,7 +1527,6 @@ EvdevInit(DeviceIntPtr device)
+ else if (pEvdev->flags & EVDEV_ABSOLUTE_EVENTS)
+ EvdevInitAbsClass(device, pEvdev);
+
+-#ifdef HAVE_PROPERTIES
+ /* We drop the return value, the only time we ever want the handlers to
+ * unregister is when the device dies. In which case we don't have to
+ * unregister anyway */
+@@ -1687,7 +1535,6 @@ EvdevInit(DeviceIntPtr device)
+ EvdevMBEmuInitProperty(device);
+ EvdevWheelEmuInitProperty(device);
+ EvdevDragLockInitProperty(device);
+-#endif
+
+ return Success;
+ }
+@@ -1726,6 +1573,9 @@ EvdevProc(DeviceIntPtr device, int what)
+ {
+ InputInfoPtr pInfo;
+ EvdevPtr pEvdev;
++#ifdef MULTITOUCH
++ int i;
++#endif
+
+ pInfo = device->public.devicePrivate;
+ pEvdev = pInfo->private;
+@@ -1759,6 +1609,17 @@ EvdevProc(DeviceIntPtr device, int what)
+ close(pInfo->fd);
+ pInfo->fd = -1;
+ }
++ valuator_mask_free(&pEvdev->vals);
++ valuator_mask_free(&pEvdev->old_vals);
++ valuator_mask_free(&pEvdev->prox);
++#ifdef MULTITOUCH
++ valuator_mask_free(&pEvdev->mt_vals);
++ valuator_mask_free(&pEvdev->cur_vals);
++ for (i = 0; i < EVDEV_MAXQUEUE; i++)
++ valuator_mask_free(&pEvdev->queue[i].touch_vals);
++ if (pEvdev->mtdev)
++ mtdev_close(pEvdev->mtdev);
++#endif
+ EvdevRemoveDevice(pInfo);
+ pEvdev->min_maj = 0;
+ break;
+@@ -2015,7 +1876,6 @@ EvdevProbe(InputInfoPtr pInfo)
+ if (has_lmr || TestBit(BTN_TOOL_FINGER, pEvdev->key_bitmask)) {
+ xf86Msg(X_PROBED, "%s: Found absolute touchpad.\n", pInfo->name);
+ pEvdev->flags |= EVDEV_TOUCHPAD;
+- memset(pEvdev->old_vals, -1, sizeof(int) * pEvdev->num_vals);
+ } else {
+ xf86Msg(X_PROBED, "%s: Found absolute touchscreen\n", pInfo->name);
+ pEvdev->flags |= EVDEV_TOUCHSCREEN;
+@@ -2135,6 +1995,16 @@ EvdevOpenDevice(InputInfoPtr pInfo)
+
+ pEvdev->device = device;
+ xf86Msg(X_CONFIG, "%s: Device: \"%s\"\n", pInfo->name, device);
++
++#ifdef MULTITOUCH
++ pEvdev->mtdev = malloc(sizeof(struct mtdev));
++ if (!pEvdev->mtdev)
++ {
++ xf86Msg(X_ERROR, "%s: Couldn't allocate mtdev structure\n",
++ pInfo->name);
++ return BadAlloc;
++ }
++#endif
+ }
+
+ if (pInfo->fd < 0)
+@@ -2149,6 +2019,17 @@ EvdevOpenDevice(InputInfoPtr pInfo)
+ }
+ }
+
++#ifdef MULTITOUCH
++ if (mtdev_open(pEvdev->mtdev, pInfo->fd) == 0)
++ pEvdev->cur_slot = pEvdev->mtdev->caps.slot.value;
++ else {
++ free(pEvdev->mtdev);
++ pEvdev->mtdev = NULL;
++ xf86Msg(X_ERROR, "%s: Couldn't open mtdev device\n", pInfo->name);
++ return FALSE;
++ }
++#endif
++
+ /* Check major/minor of device node to avoid adding duplicate devices. */
+ pEvdev->min_maj = EvdevGetMajorMinor(pInfo);
+ if (EvdevIsDuplicate(pInfo))
+@@ -2162,52 +2043,8 @@ EvdevOpenDevice(InputInfoPtr pInfo)
+ return Success;
+ }
+
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
+-static int NewEvdevPreInit(InputDriverPtr, InputInfoPtr, int);
+-
+-static InputInfoPtr
+-EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
+-{
+- InputInfoPtr pInfo;
+-
+- if (!(pInfo = xf86AllocateInput(drv, 0)))
+- return NULL;
+-
+- /* Initialise the InputInfoRec. */
+- pInfo->fd = -1;
+- pInfo->name = dev->identifier;
+- pInfo->flags = 0;
+- pInfo->history_size = 0;
+- pInfo->control_proc = NULL;
+- pInfo->close_proc = NULL;
+- pInfo->conversion_proc = NULL;
+- pInfo->reverse_conversion_proc = NULL;
+- pInfo->dev = NULL;
+- pInfo->private_flags = 0;
+- pInfo->always_core_feedback = NULL;
+- pInfo->conf_idev = dev;
+- pInfo->private = NULL;
+-
+- xf86CollectInputOptions(pInfo, (const char**)evdevDefaults, NULL);
+- xf86ProcessCommonOptions(pInfo, pInfo->options);
+-
+- if (NewEvdevPreInit(drv, pInfo, flags) == Success)
+- {
+- pInfo->flags |= XI86_CONFIGURED;
+- return pInfo;
+- }
+-
+-
+- xf86DeleteInput(pInfo, 0);
+- return NULL;
+-}
+-
+-static int
+-NewEvdevPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
+-#else
+ static int
+ EvdevPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
+-#endif
+ {
+ EvdevPtr pEvdev;
+ int rc = BadAlloc;
+@@ -2225,6 +2062,10 @@ EvdevPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
+ if (rc != Success)
+ goto error;
+
++#ifdef MULTITOUCH
++ pEvdev->cur_slot = -1;
++#endif
++
+ /*
+ * We initialize pEvdev->in_proximity to 1 so that device that doesn't use
+ * proximity will still report events.
+@@ -2279,9 +2120,7 @@ _X_EXPORT InputDriverRec EVDEV = {
+ EvdevPreInit,
+ NULL,
+ NULL,
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
+ evdevDefaults
+-#endif
+ };
+
+ static void
+@@ -2356,8 +2195,6 @@ EvdevUtilButtonEventToButtonNumber(EvdevPtr pEvdev, int code)
+ }
+ }
+
+-#ifdef HAVE_PROPERTIES
+-#ifdef HAVE_LABELS
+ /* Aligned with linux/input.h.
+ Note that there are holes in the ABS_ range, these are simply replaced with
+ MISC here */
+@@ -2411,7 +2248,6 @@ static char* abs_labels[] = {
+ AXIS_LABEL_PROP_ABS_MISC, /* undefined */
+ AXIS_LABEL_PROP_ABS_MISC, /* undefined */
+ AXIS_LABEL_PROP_ABS_MISC, /* undefined */
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 10
+ AXIS_LABEL_PROP_ABS_MT_TOUCH_MAJOR, /* 0x30 */
+ AXIS_LABEL_PROP_ABS_MT_TOUCH_MINOR, /* 0x31 */
+ AXIS_LABEL_PROP_ABS_MT_WIDTH_MAJOR, /* 0x32 */
+@@ -2423,7 +2259,6 @@ static char* abs_labels[] = {
+ AXIS_LABEL_PROP_ABS_MT_BLOB_ID, /* 0x38 */
+ AXIS_LABEL_PROP_ABS_MT_TRACKING_ID, /* 0x39 */
+ AXIS_LABEL_PROP_ABS_MT_PRESSURE, /* 0x3a */
+-#endif
+ };
+
+ static char* rel_labels[] = {
+@@ -2520,11 +2355,8 @@ static char* btn_labels[][16] = {
+ }
+ };
+
+-#endif /* HAVE_LABELS */
+-
+ static void EvdevInitAxesLabels(EvdevPtr pEvdev, int natoms, Atom *atoms)
+ {
+-#ifdef HAVE_LABELS
+ Atom atom;
+ int axis;
+ char **labels;
+@@ -2557,12 +2389,10 @@ static void EvdevInitAxesLabels(EvdevPtr pEvdev, int natoms, Atom *atoms)
+
+ atoms[pEvdev->axis_map[axis]] = atom;
+ }
+-#endif
+ }
+
+ static void EvdevInitButtonLabels(EvdevPtr pEvdev, int natoms, Atom *atoms)
+ {
+-#ifdef HAVE_LABELS
+ Atom atom;
+ int button, bmap;
+
+@@ -2600,7 +2430,6 @@ static void EvdevInitButtonLabels(EvdevPtr pEvdev, int natoms, Atom *atoms)
+ atoms[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
+ if (natoms > 6)
+ atoms[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
+-#endif
+ }
+
+ static void
+@@ -2659,11 +2488,10 @@ EvdevInitProperty(DeviceIntPtr dev)
+
+ XISetDevicePropertyDeletable(dev, prop_swap, FALSE);
+
+-#ifdef HAVE_LABELS
+ /* Axis labelling */
+ if ((pEvdev->num_vals > 0) && (prop_axis_label = XIGetKnownProperty(AXIS_LABEL_PROP)))
+ {
+- Atom atoms[pEvdev->num_vals];
++ Atom atoms[pEvdev->num_vals + pEvdev->num_mt_vals];
+ EvdevInitAxesLabels(pEvdev, pEvdev->num_vals, atoms);
+ XIChangeDeviceProperty(dev, prop_axis_label, XA_ATOM, 32,
+ PropModeReplace, pEvdev->num_vals, atoms, FALSE);
+@@ -2678,7 +2506,6 @@ EvdevInitProperty(DeviceIntPtr dev)
+ PropModeReplace, pEvdev->num_buttons, atoms, FALSE);
+ XISetDevicePropertyDeletable(dev, prop_btn_label, FALSE);
+ }
+-#endif /* HAVE_LABELS */
+ }
+
+ }
+@@ -2723,4 +2550,3 @@ EvdevSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
+
+ return Success;
+ }
+-#endif
+diff --git a/src/evdev.h b/src/evdev.h
+index f640fdd..a590eaf 100644
+--- a/src/evdev.h
++++ b/src/evdev.h
+@@ -39,6 +39,16 @@
+ #include <xf86_OSproc.h>
+ #include <xkbstr.h>
+
++#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) * 100 + GET_ABI_MINOR(ABI_XINPUT_VERSION) < 1202
++#error "Need X server input ABI version 12.2 or greater"
++#endif
++
++#define MULTITOUCH /* Will be at least ABI 13.1, but it's not there yet */
++
++#ifdef MULTITOUCH
++#include <mtdev.h>
++#endif
++
+ #ifndef EV_CNT /* linux 2.6.23 kernels and earlier lack _CNT defines */
+ #define EV_CNT (EV_MAX+1)
+ #endif
+@@ -72,26 +82,10 @@
+ #define EVDEV_UNIGNORE_RELATIVE (1 << 10) /* explicitly unignore rel axes */
+ #define EVDEV_RELATIVE_MODE (1 << 11) /* Force relative events for devices with absolute axes */
+
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 3
+-#define HAVE_PROPERTIES 1
+-#endif
+-
+ #ifndef MAX_VALUATORS
+ #define MAX_VALUATORS 36
+ #endif
+
+-
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 5
+-typedef struct {
+- char *rules;
+- char *model;
+- char *layout;
+- char *variant;
+- char *options;
+-} XkbRMLVOSet;
+-#endif
+-
+-
+ #define LONG_BITS (sizeof(long) * 8)
+
+ /* Number of longs needed to hold the given number of bits */
+@@ -110,9 +104,20 @@ typedef struct {
+ EV_QUEUE_KEY, /* xf86PostKeyboardEvent() */
+ EV_QUEUE_BTN, /* xf86PostButtonEvent() */
+ EV_QUEUE_PROXIMITY, /* xf86PostProximityEvent() */
++#ifdef MULTITOUCH
++ EV_QUEUE_TOUCH, /*xf86PostTouchEvent() */
++#endif
+ } type;
+- int key; /* May be either a key code or button number. */
+- int val; /* State of the key/button; pressed or released. */
++ union {
++ int key; /* May be either a key code or button number. */
++#ifdef MULTITOUCH
++ unsigned int touch; /* Touch ID */
++#endif
++ } detail;
++ int val; /* State of the key/button/touch; pressed or released. */
++#ifdef MULTITOUCH
++ ValuatorMask *touch_vals; /* current state of valuators for touch */
++#endif
+ } EventQueueRec, *EventQueuePtr;
+
+ typedef struct {
+@@ -121,8 +126,18 @@ typedef struct {
+
+ int num_vals; /* number of valuators */
+ int axis_map[max(ABS_CNT, REL_CNT)]; /* Map evdev <axis> to index */
+- int vals[MAX_VALUATORS];
+- int old_vals[MAX_VALUATORS]; /* Translate absolute inputs to relative */
++ ValuatorMask *vals; /* new values coming in */
++ ValuatorMask *old_vals; /* old values for calculating relative motion */
++ ValuatorMask *prox; /* last values set while not in proximity */
++#ifdef MULTITOUCH
++ int num_mt_vals;
++ ValuatorMask *mt_vals; /* multitouch values coming in */
++ ValuatorMask *cur_vals; /* current values of MT axes in evdev state */
++ int cur_slot;
++ BOOL close_slot;
++ BOOL open_slot;
++ struct mtdev *mtdev;
++#endif
+
+ int flags;
+ int in_proximity; /* device in proximity */
+@@ -134,12 +149,8 @@ typedef struct {
+
+ int delta[REL_CNT];
+ unsigned int abs_queued, rel_queued, prox_queued;
+- unsigned int abs_prox; /* valuators posted while out of prox? */
+
+ /* XKB stuff has to be per-device rather than per-driver */
+-#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 5
+- XkbComponentNamesRec xkbnames;
+-#endif
+ XkbRMLVOSet rmlvo;
+
+ /* Middle mouse button emulation */
+@@ -202,6 +213,10 @@ typedef struct {
+ void EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value);
+ void EvdevQueueButtonEvent(InputInfoPtr pInfo, int button, int value);
+ void EvdevQueueProximityEvent(InputInfoPtr pInfo, int value);
++#ifdef MULTITOUCH
++void EvdevQueueTouchEvent(InputInfoPtr pInfo, unsigned int touch,
++ ValuatorMask *mask, uint16_t type);
++#endif
+ void EvdevPostButtonEvent(InputInfoPtr pInfo, int button, int value);
+ void EvdevQueueButtonClicks(InputInfoPtr pInfo, int button, int count);
+ void EvdevPostRelativeMotionEvents(InputInfoPtr pInfo, int num_v, int first_v,
+@@ -228,9 +243,7 @@ BOOL EvdevWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv);
+ void EvdevDragLockPreInit(InputInfoPtr pInfo);
+ BOOL EvdevDragLockFilterEvent(InputInfoPtr pInfo, unsigned int button, int value);
+
+-#ifdef HAVE_PROPERTIES
+ void EvdevMBEmuInitProperty(DeviceIntPtr);
+ void EvdevWheelEmuInitProperty(DeviceIntPtr);
+ void EvdevDragLockInitProperty(DeviceIntPtr);
+ #endif
+-#endif
diff --git a/x11-drivers/xf86-input-evdev/xf86-input-evdev-2.6.0-r1.ebuild b/x11-drivers/xf86-input-evdev/xf86-input-evdev-2.6.0-r1.ebuild
new file mode 100644
index 0000000..d6fe225
--- /dev/null
+++ b/x11-drivers/xf86-input-evdev/xf86-input-evdev-2.6.0-r1.ebuild
@@ -0,0 +1,33 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/x11-drivers/xf86-input-evdev/xf86-input-evdev-2.6.0.ebuild,v 1.7 2011/03/05 18:09:14 xarthisius Exp $
+
+EAPI=3
+XORG_EAUTORECONF=yes
+
+inherit xorg-2
+
+DESCRIPTION="Generic Linux input driver"
+KEYWORDS="alpha amd64 arm hppa ia64 ~mips ppc ppc64 sh sparc x86"
+IUSE="utouch"
+
+RDEPEND=">=x11-base/xorg-server-1.6.3"
+DEPEND="${RDEPEND}
+ >=sys-kernel/linux-headers-2.6
+ x11-proto/inputproto
+ x11-proto/xproto"
+
+src_prepare() {
+ if use utouch ; then
+ epatch "${FILESDIR}/xf86-input-evdev-xi2.1.patch"
+ epatch "${FILESDIR}/xf86-input-evdev-gestures.patch"
+ fi
+
+ xorg-2_src_prepare
+}
+
+src_install() {
+ xorg-2_src_install
+}
+
+