| 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 */ |
| |