diff options
author | Chase Douglas <chase.douglas@ubuntu.com> | 2010-10-18 17:34:13 +0200 |
---|---|---|
committer | Chase Douglas <chase.douglas@ubuntu.com> | 2010-10-19 16:56:45 -0400 |
commit | 624060a41c6431b086342263b5c5cc8039cd990c (patch) | |
tree | 1f765e0ae277e10b7935c6183bd6e206ab98d637 | |
parent | c04b7ae0074ea7b4ae6955c01b370914a3d48492 (diff) |
Switch to slotted evdev multitouch events.
Signed-off-by: Chase Douglas <chase.douglas@canonical.com>
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/evdev.c | 253 | ||||
-rw-r--r-- | src/evdev.h | 16 |
4 files changed, 135 insertions, 139 deletions
diff --git a/configure.ac b/configure.ac index 07cd64e..34dbbd0 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..89137bc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -29,7 +29,7 @@ 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 $(MTDEV_LIBS) @DRIVER_NAME@_drv_ladir = @inputdir@ @DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c \ diff --git a/src/evdev.c b/src/evdev.c index 7a72de8..dd90091 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -98,30 +98,6 @@ static char *evdevDefaults[] = { NULL }; -static int abs_mt_axis_map[] = { - ABS_MT_POSITION_X, - ABS_MT_POSITION_Y, - ABS_MT_TOUCH_MAJOR, - ABS_MT_TOUCH_MINOR, - ABS_MT_WIDTH_MAJOR, - ABS_MT_WIDTH_MINOR, - ABS_MT_ORIENTATION, - ABS_MT_TRACKING_ID, - ABS_MT_TOOL_TYPE, -}; -static inline int mt_axis_to_evdev(int axis) -{ - int i; - - for (i = 0; i < ArrayLength(abs_mt_axis_map); i++) - if (abs_mt_axis_map[i] == axis) - return i; - - return -1; -} -#define mt_cached_axis(_evdev, _axis) \ - (_evdev->mt_tp_axes[mt_axis_to_evdev(_axis)]) - static int EvdevOn(DeviceIntPtr); static int EvdevCacheCompare(InputInfoPtr pInfo, BOOL compare); static void EvdevKbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl); @@ -561,6 +537,54 @@ EvdevProcessRelativeMotionEvent(InputInfoPtr pInfo, struct input_event *ev) } } +static void +EvdevProcessSlot(InputInfoPtr pInfo) +{ + EvdevPtr pEvdev = pInfo->private; + int slot = pEvdev->mt_cur_slot; + + if (slot >= 0 && pEvdev->mt_ids[slot] >= 0) + { + if (BitIsOn(pEvdev->mt_axismask, MT_AXIS(ABS_MT_TRACKING_ID)) && + pEvdev->mt_slot[MT_AXIS(ABS_MT_TRACKING_ID)] < 0) { + xf86FiniTouchPoint(pInfo->dev, pEvdev->mt_ids[slot]); + pEvdev->mt_ids[slot] = -1; + + memset(pEvdev->mt_axismask, 0, sizeof(pEvdev->mt_axismask)); + } + else { + int mask = 0; + + if (BitIsOn(pEvdev->mt_axismask, MT_AXIS(ABS_MT_POSITION_X))) + mask |= XITouchXMask; + if (BitIsOn(pEvdev->mt_axismask, MT_AXIS(ABS_MT_POSITION_Y))) + mask |= XITouchYMask; + if (BitIsOn(pEvdev->mt_axismask, MT_AXIS(ABS_MT_TOUCH_MAJOR)) || + BitIsOn(pEvdev->mt_axismask, MT_AXIS(ABS_MT_TOUCH_MINOR))) + mask |= XITouchTouchSizeMask; + if (BitIsOn(pEvdev->mt_axismask, MT_AXIS(ABS_MT_WIDTH_MAJOR)) || + BitIsOn(pEvdev->mt_axismask, MT_AXIS(ABS_MT_WIDTH_MINOR))) + mask |= XITouchToolSizeMask; + if (BitIsOn(pEvdev->mt_axismask, MT_AXIS(ABS_MT_ORIENTATION))) + mask |= XITouchOrientationMask; + + xf86PostTouchMotion(pInfo->dev, + pEvdev->mt_ids[slot], + pEvdev->mt_slot[MT_AXIS(ABS_MT_TOOL_TYPE)], + mask, + pEvdev->mt_slot[MT_AXIS(ABS_MT_POSITION_X)], + pEvdev->mt_slot[MT_AXIS(ABS_MT_POSITION_Y)], + pEvdev->mt_slot[MT_AXIS(ABS_MT_TOUCH_MAJOR)], + pEvdev->mt_slot[MT_AXIS(ABS_MT_TOUCH_MINOR)], + pEvdev->mt_slot[MT_AXIS(ABS_MT_WIDTH_MAJOR)], + pEvdev->mt_slot[MT_AXIS(ABS_MT_WIDTH_MINOR)], + pEvdev->mt_slot[MT_AXIS(ABS_MT_ORIENTATION)]); + + memset(pEvdev->mt_axismask, 0, sizeof(pEvdev->mt_axismask)); + } + } +} + /** * Take the absolute motion input event and process it accordingly. */ @@ -575,15 +599,31 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev) /* Process multitouch events first, since they don't interfere * with abs/rel. */ - if (ev->code >= ABS_MT_TOUCH_MAJOR && ev->code <= ABS_MT_TRACKING_ID) + if (ev->code == ABS_MT_SLOT) { - int axis = mt_axis_to_evdev(ev->code); - - if (axis == -1 || !(pEvdev->flags & EVDEV_MULTITOUCH)) - return; + /* Process current touch first */ + EvdevProcessSlot(pInfo); - pEvdev->mt_tp_axes[axis] = value; - SetBitLong(ev->code, pEvdev->mt_tp_axismask); + /* Process new slot */ + if (ev->value >= pEvdev->mt_num_slots) + { + pEvdev->mt_cur_slot = -1; + xf86Msg(X_WARNING, "%s: No more slots for touch %d, dropping\n", + pInfo->name, value); + } else + pEvdev->mt_cur_slot = ev->value; + return; + } + if (ev->code >= ABS_MT_TOUCH_MAJOR && ev->code <= ABS_MT_PRESSURE) + { + if ((pEvdev->flags & EVDEV_MULTITOUCH) && pEvdev->mt_cur_slot >= 0) + { + unsigned int slot = pEvdev->mt_cur_slot; + pEvdev->mt_slot[MT_AXIS(ev->code)] = value; + if (ev->code == ABS_MT_TRACKING_ID && ev->value >= 0) + pEvdev->mt_ids[slot] = value; + SetBit(pEvdev->mt_axismask, MT_AXIS(ev->code)); + } return; } @@ -715,40 +755,6 @@ static void EvdevPostQueuedEvents(InputInfoPtr pInfo, int num_v, int first_v, } /** - * If a touchpoint hasn't appeared between EV_SYN::SYN_REPORT pairs, it means - * that it's gone; ABS_MT_TRACKING_ID is always guaranteed to appear - * if a touchpoint is live, even if it hasn't moved. - */ -static void -EvdevGCTouchPoints(InputInfoPtr pInfo) -{ - EvdevPtr pEvdev = pInfo->private; - int i, j; - - if (!(pEvdev->flags & EVDEV_MULTITOUCH)) - return; - - for (i = 0; i < pEvdev->mt_max_tps; i++) - { - if (!pEvdev->mt_all_tps[i]) - continue; - - for (j = 0; j < pEvdev->mt_max_tps; j++) - if (pEvdev->mt_active_tps[j] == pEvdev->mt_all_tps[i]) - break; - if (j == pEvdev->mt_max_tps) - { - xf86FiniTouchPoint(pInfo->dev, pEvdev->mt_all_tps[i]); - pEvdev->mt_all_tps[i] = 0; - } - } - - memcpy(pEvdev->mt_all_tps, pEvdev->mt_active_tps, - pEvdev->mt_max_tps * sizeof(int)); - memset(pEvdev->mt_active_tps, 0, pEvdev->mt_max_tps * sizeof(int)); -} - -/** * Take the synchronization input event and process it accordingly; the motion * notify events are sent first, then any button/key press/release events. */ @@ -757,66 +763,21 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev) { int num_v = 0, first_v = 0; int v[MAX_VALUATORS] = {}; - int i; EvdevPtr pEvdev = pInfo->private; - /* This means we've finished receiving all the events for a given - * touchpoint; collate them, update the valuators, and bail. */ - if (ev->code == SYN_MT_REPORT) { - int id = mt_cached_axis(pEvdev, ABS_MT_TRACKING_ID); - int mask = 0; + EvdevProcessSlot(pInfo); - if (id == -1 || !(pEvdev->flags & EVDEV_MULTITOUCH)) - return; + EvdevProcessValuators(pInfo, v, &num_v, &first_v); - for (i = 0; i < pEvdev->mt_max_tps; i++) { - if (pEvdev->mt_active_tps[i] == 0) { - pEvdev->mt_active_tps[i] = id; - break; - } - } + EvdevPostRelativeMotionEvents(pInfo, num_v, first_v, v); + EvdevPostAbsoluteMotionEvents(pInfo, num_v, first_v, v); + EvdevPostQueuedEvents(pInfo, num_v, first_v, v); - if (TestBit(ABS_MT_POSITION_X, pEvdev->mt_tp_axismask)) - mask |= XITouchXMask; - if (TestBit(ABS_MT_POSITION_Y, pEvdev->mt_tp_axismask)) - mask |= XITouchYMask; - if (TestBit(ABS_MT_TOUCH_MAJOR, pEvdev->mt_tp_axismask) || - TestBit(ABS_MT_TOUCH_MINOR, pEvdev->mt_tp_axismask)) - mask |= XITouchTouchSizeMask; - if (TestBit(ABS_MT_WIDTH_MAJOR, pEvdev->mt_tp_axismask) || - TestBit(ABS_MT_WIDTH_MINOR, pEvdev->mt_tp_axismask)) - mask |= XITouchToolSizeMask; - if (TestBit(ABS_MT_ORIENTATION, pEvdev->mt_tp_axismask)) - mask |= XITouchOrientationMask; - - xf86PostTouchMotion(pInfo->dev, id, - mt_cached_axis(pEvdev, ABS_MT_TOOL_TYPE), - mask, - mt_cached_axis(pEvdev, ABS_MT_POSITION_X), - mt_cached_axis(pEvdev, ABS_MT_POSITION_Y), - mt_cached_axis(pEvdev, ABS_MT_TOUCH_MAJOR), - mt_cached_axis(pEvdev, ABS_MT_TOUCH_MINOR), - mt_cached_axis(pEvdev, ABS_MT_WIDTH_MAJOR), - mt_cached_axis(pEvdev, ABS_MT_WIDTH_MINOR), - mt_cached_axis(pEvdev, ABS_MT_ORIENTATION)); - - memset(pEvdev->mt_tp_axes, 0, pEvdev->mt_max_tps * sizeof(int)); - memset(pEvdev->mt_tp_axismask, 0, sizeof(pEvdev->mt_tp_axismask)); - } else if (ev->code == SYN_REPORT) { - EvdevGCTouchPoints(pInfo); - - EvdevProcessValuators(pInfo, v, &num_v, &first_v); - - EvdevPostRelativeMotionEvents(pInfo, num_v, first_v, v); - EvdevPostAbsoluteMotionEvents(pInfo, num_v, first_v, v); - EvdevPostQueuedEvents(pInfo, num_v, first_v, v); - - memset(pEvdev->delta, 0, sizeof(pEvdev->delta)); - memset(pEvdev->queue, 0, sizeof(pEvdev->queue)); - pEvdev->num_queue = 0; - pEvdev->abs = 0; - pEvdev->rel = 0; - } + memset(pEvdev->delta, 0, sizeof(pEvdev->delta)); + memset(pEvdev->queue, 0, sizeof(pEvdev->queue)); + pEvdev->num_queue = 0; + pEvdev->abs = 0; + pEvdev->rel = 0; } /** @@ -853,11 +814,16 @@ static void EvdevReadInput(InputInfoPtr pInfo) { struct input_event ev[NUM_EVENTS]; + EvdevPtr pEvdev = pInfo->private; int i, len = sizeof(ev); while (len == sizeof(ev)) { - len = read(pInfo->fd, &ev, sizeof(ev)); + 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)); if (len <= 0) { @@ -1304,7 +1270,7 @@ EvdevAddAbsClass(DeviceIntPtr device) if (!TestBit(axis, pEvdev->abs_bitmask)) continue; if ((pEvdev->flags & EVDEV_MULTITOUCH) && - axis >= ABS_MT_TOUCH_MAJOR && axis <= ABS_MT_TRACKING_ID) + axis >= ABS_MT_SLOT && axis <= ABS_MT_PRESSURE) continue; pEvdev->axis_map[axis] = i; i++; @@ -1581,7 +1547,7 @@ EvdevInitMTClass(DeviceIntPtr device, EvdevPtr pEvdev) max_touch_width = -1; } - ret = InitTouchClassDeviceStruct(device, pEvdev->mt_max_tps, Absolute, + ret = InitTouchClassDeviceStruct(device, pEvdev->mt_num_slots, Absolute, Relative, min_x, max_x, min_y, max_y, min_touch_width, max_touch_width); if (ret == TRUE) { @@ -1591,8 +1557,7 @@ EvdevInitMTClass(DeviceIntPtr device, EvdevPtr pEvdev) device->name); } - memset(pEvdev->mt_tp_axes, 0, pEvdev->mt_max_tps * sizeof(int)); - memset(pEvdev->mt_tp_axismask, 0, sizeof(pEvdev->mt_tp_axismask)); + memset(pEvdev->mt_axismask, 0, sizeof(pEvdev->mt_axismask)); } static void @@ -1760,6 +1725,8 @@ EvdevProc(DeviceIntPtr device, int what) close(pInfo->fd); pInfo->fd = -1; } + if (pEvdev->mtdev) + mtdev_close(pEvdev->mtdev); EvdevRemoveDevice(pInfo); pEvdev->min_maj = 0; break; @@ -2149,18 +2116,38 @@ EvdevProbe(InputInfoPtr pInfo) (pInfo->flags & XI86_CONFIGURED)) { pEvdev->flags |= EVDEV_MULTITOUCH; - pEvdev->mt_max_tps = xf86SetIntOption(pInfo->options, - "MaxMTTouchPoints", 10); + pEvdev->mt_num_slots = xf86SetIntOption(pInfo->options, + "MaxMTTouchPoints", 10); xf86Msg(X_INFO, "%s: Adding multitouch support (%d touchpoints)\n", - pInfo->name, pEvdev->mt_max_tps); - pEvdev->mt_active_tps = calloc(pEvdev->mt_max_tps, sizeof(int)); - pEvdev->mt_all_tps = calloc(pEvdev->mt_max_tps, sizeof(int)); - if (!pEvdev->mt_active_tps || !pEvdev->mt_all_tps) + pInfo->name, pEvdev->mt_num_slots); + + pEvdev->mtdev = malloc(sizeof(struct mtdev)); + if (!pEvdev->mtdev) + { + xf86Msg(X_ERROR, "%s: Couldn't allocate mtdev structure\n", + pInfo->name); + return BadAlloc; + } + + if (mtdev_open(pEvdev->mtdev, pInfo->fd)) + { + pEvdev->mtdev = NULL; + xf86Msg(X_ERROR, "%s: Couldn't open mtdev device\n", pInfo->name); + return BadAlloc; + } + + pEvdev->mt_ids = calloc(pEvdev->mt_num_slots, sizeof(unsigned int)); + if (!pEvdev->mt_ids) { - xf86Msg(X_ERROR, "%s: Couldn't allocate MT axis values\n", + free(pEvdev->mtdev); + pEvdev->mtdev = NULL; + xf86Msg(X_ERROR, "%s: Couldn't allocate MT tracking IDs\n", pInfo->name); return BadAlloc; } + + for (i = 0; i < pEvdev->mt_num_slots; i++) + pEvdev->mt_ids[i] = -1; } if ((pInfo->flags & XI86_CONFIGURED) == 0) { @@ -2332,6 +2319,8 @@ EvdevPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags) EvdevDragLockPreInit(pInfo); } + pEvdev->mt_cur_slot = -1; + return Success; error: diff --git a/src/evdev.h b/src/evdev.h index 2f874a2..41f4941 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -39,6 +39,8 @@ #include <xf86_OSproc.h> #include <xkbstr.h> +#include <mtdev.h> + #ifndef EV_CNT /* linux 2.6.23 kernels and earlier lack _CNT defines */ #define EV_CNT (EV_MAX+1) #endif @@ -55,7 +57,8 @@ #define LED_CNT (LED_MAX+1) #endif -#define MT_NUM_AXES (ABS_MT_TRACKING_ID - ABS_MT_TOUCH_MAJOR) +#define MT_NUM_AXES (ABS_MT_PRESSURE - ABS_MT_TOUCH_MAJOR) +#define MT_AXIS(x) (x) - ABS_MT_TOUCH_MAJOR #define EVDEV_MAXBUTTONS 32 #define EVDEV_MAXQUEUE 32 @@ -126,11 +129,11 @@ typedef struct { int vals[MAX_VALUATORS]; int old_vals[MAX_VALUATORS]; /* Translate absolute inputs to relative */ - int *mt_active_tps; /* Active touchpoints in this event stream only */ - int *mt_all_tps; /* All currently active touchpoints */ - int mt_max_tps; /* Maximum number of active touchpoints */ - int mt_tp_axes[MT_NUM_AXES]; /* Valuators for the current touchpoint */ - unsigned long mt_tp_axismask[NLONGS(ABS_CNT)]; + int mt_slot[MT_NUM_AXES]; /* Multitouch touch slots */ + unsigned int mt_num_slots; /* Number of touch slots */ + int mt_cur_slot; /* Current slot for MT values */ + int *mt_ids; /* Tracking IDs of touch slots */ + uint8_t mt_axismask[(MT_NUM_AXES + 7) / 8]; /* Bitmask of new values */ int flags; int proximity; @@ -202,6 +205,7 @@ typedef struct { /* Event queue used to defer keyboard/button events until EV_SYN time. */ int num_queue; EventQueueRec queue[EVDEV_MAXQUEUE]; + struct mtdev *mtdev; } EvdevRec, *EvdevPtr; /* Event posting functions */ |