blob: 9ae781d6062002c03bca2dc437cdfe9339d9e599 [file] [log] [blame]
Author: Chris Wolfe <cwolfe@chromium.org>
Date: Thu Nov 24 15:07:16 2011 -0500
xf86-evdev: Avoid crashing on misbehaving evdev drivers.
Some multi-touch drivers produce ABS_MT_TRACKING_ID events
without the expected ABS_MT_SLOT. Added a check to ignore
TRACKING_ID events when the slot map is uninitialized.
Author: Sadrul Habib Chowdhury <sadrul@chromium.org>
Date: Mon Apr 18 15:17:07 2011 -0400
xf86-evdev: Add support for MT tracking for proto B.
diff --git a/src/evdev.c b/src/evdev.c
index 45873c1..d7735bf 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -87,6 +87,11 @@
#define MODEFLAG 8
#define COMPOSEFLAG 16
+/* Defining ABS_MT_SLOT for compatibility with older kernel headers. */
+#ifndef ABS_MT_SLOT
+#define ABS_MT_SLOT 0x2f
+#endif
+
static char *evdevDefaults[] = {
"XkbRules", "evdev",
"XkbModel", "evdev",
@@ -648,6 +653,33 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
if (EvdevWheelEmuFilterMotion(pInfo, ev))
return;
+ if (ev->code == ABS_MT_SLOT)
+ {
+ int i;
+ if (value >= pEvdev->mt_slots || value < 0)
+ {
+ xf86Msg(X_INFO, "Invalid slot id: %d\n", value);
+ return;
+ }
+
+ pEvdev->cur_slot = value;
+ /* Restore all the MT valuators for the current slot. */
+ for (i = 0; i < MT_NUM_AXES; i++)
+ {
+ int mt_axis = pEvdev->mt_axis_map[i];
+ if (mt_axis != -1)
+ {
+ pEvdev->vals[pEvdev->axis_map[MT_AXIS_FIRST + i]] =
+ pEvdev->mt_slot_map[pEvdev->cur_slot][mt_axis];
+ }
+ }
+ }
+ else if (IS_MT_AXIS(ev->code) && pEvdev->mt_slot_map)
+ {
+ pEvdev->mt_slot_map[pEvdev->cur_slot]
+ [pEvdev->mt_axis_map[MT_AXIS(ev->code)]] = value;
+ }
+
pEvdev->vals[pEvdev->axis_map[ev->code]] = value;
if (ev->code == ABS_X)
pEvdev->abs_queued |= ABS_X_VALUE;
@@ -820,7 +852,6 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev)
pEvdev->abs_queued = 0;
pEvdev->rel_queued = 0;
pEvdev->prox_queued = 0;
-
}
/**
@@ -1280,7 +1311,7 @@ EvdevAddAbsClass(DeviceIntPtr device)
{
InputInfoPtr pInfo;
EvdevPtr pEvdev;
- int num_axes, axis, i = 0;
+ int num_axes, mt_num_axes, axis, i = 0;
Atom *atoms;
pInfo = device->public.devicePrivate;
@@ -1301,15 +1332,20 @@ EvdevAddAbsClass(DeviceIntPtr device)
pEvdev->num_vals = num_axes;
memset(pEvdev->vals, 0, num_axes * sizeof(int));
memset(pEvdev->old_vals, -1, num_axes * sizeof(int));
+ memset(pEvdev->mt_axis_map, -1, MT_NUM_AXES * sizeof(int));
atoms = malloc(pEvdev->num_vals * sizeof(Atom));
+ mt_num_axes = 0;
for (axis = ABS_X; i < MAX_VALUATORS && axis <= ABS_MAX; axis++) {
pEvdev->axis_map[axis] = -1;
if (!TestBit(axis, pEvdev->abs_bitmask))
continue;
pEvdev->axis_map[axis] = i;
+ if (IS_MT_AXIS(axis))
+ pEvdev->mt_axis_map[MT_AXIS(axis)] = mt_num_axes++;
i++;
}
+ pEvdev->mt_num_axes = mt_num_axes;
EvdevInitAxesLabels(pEvdev, pEvdev->num_vals, atoms);
@@ -1326,6 +1362,40 @@ EvdevAddAbsClass(DeviceIntPtr device)
return !Success;
}
+ if (TestBit(ABS_MT_SLOT, pEvdev->abs_bitmask))
+ {
+ /* The maximum value is a valid index, so the size is + 1 */
+ int num_touches = pEvdev->absinfo[ABS_MT_SLOT].maximum + 1;
+ pEvdev->mt_slot_map = malloc(num_touches * sizeof(int *));
+ if (!pEvdev->mt_slot_map)
+ {
+ xf86Msg(X_ERROR, "Insufficient memory for MT.\n");
+ return !Success;
+ }
+ for (i = 0; i < num_touches; i++)
+ {
+ pEvdev->mt_slot_map[i] = malloc(mt_num_axes * sizeof(int));
+ if (!pEvdev->mt_slot_map[i])
+ {
+ xf86Msg(X_ERROR, "Insufficient memory for MT.\n");
+ while (i--)
+ free(pEvdev->mt_slot_map[i]);
+ free(pEvdev->mt_slot_map);
+ return !Success;
+ }
+ memset(pEvdev->mt_slot_map[i], 0, mt_num_axes * sizeof(int));
+ if (TestBit(ABS_MT_TRACKING_ID, pEvdev->abs_bitmask))
+ pEvdev->mt_slot_map[i]
+ [pEvdev->mt_axis_map[MT_AXIS(ABS_MT_TRACKING_ID)]] = -1;
+ }
+ pEvdev->mt_slots = num_touches;
+ }
+ else
+ {
+ pEvdev->mt_slots = 0;
+ pEvdev->mt_slot_map = NULL;
+ }
+
for (axis = ABS_X; axis <= ABS_MAX; axis++) {
int axnum = pEvdev->axis_map[axis];
int resolution = 10000;
@@ -1761,6 +1831,15 @@ EvdevProc(DeviceIntPtr device, int what)
}
EvdevRemoveDevice(pInfo);
pEvdev->min_maj = 0;
+ if (pEvdev->mt_slot_map)
+ {
+ int i;
+ for (i = 0; i < pEvdev->mt_slots; i++)
+ free(pEvdev->mt_slot_map[i]);
+ free(pEvdev->mt_slot_map);
+ pEvdev->mt_slots = 0;
+ pEvdev->mt_slot_map = NULL;
+ }
break;
}
@@ -2410,8 +2489,8 @@ static char* abs_labels[] = {
AXIS_LABEL_PROP_ABS_MISC, /* undefined */
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_SLOT, /* 0x2f */
AXIS_LABEL_PROP_ABS_MT_TOUCH_MAJOR, /* 0x30 */
AXIS_LABEL_PROP_ABS_MT_TOUCH_MINOR, /* 0x31 */
AXIS_LABEL_PROP_ABS_MT_WIDTH_MAJOR, /* 0x32 */
diff --git a/src/evdev.h b/src/evdev.h
index f640fdd..4102672 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -80,6 +80,11 @@
#define MAX_VALUATORS 36
#endif
+#define MT_AXIS_FIRST ABS_MT_TOUCH_MAJOR
+#define MT_NUM_AXES (ABS_MT_PRESSURE - MT_AXIS_FIRST + 1)
+#define MT_AXIS(x) (x) - MT_AXIS_FIRST
+#define IS_MT_AXIS(x) (x) >= MT_AXIS_FIRST && (x) <= ABS_MT_PRESSURE
+
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 5
typedef struct {
@@ -121,6 +126,13 @@ typedef struct {
int num_vals; /* number of valuators */
int axis_map[max(ABS_CNT, REL_CNT)]; /* Map evdev <axis> to index */
+
+ int mt_num_axes;
+ int mt_slots; /* number of MT slots */
+ int mt_axis_map[MT_NUM_AXES]; /* Map i-th available MT axis to index */
+ int **mt_slot_map; /* Keep track of the valuators for each slot */
+ int cur_slot;
+
int vals[MAX_VALUATORS];
int old_vals[MAX_VALUATORS]; /* Translate absolute inputs to relative */