summaryrefslogtreecommitdiff
path: root/libevdev/libevdev.c
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2014-04-01 15:32:46 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2014-04-03 13:30:49 +1000
commitf8fba5b5884bfb62225b9bde991dfdbec92ad751 (patch)
tree06edf1ee8870c5335c81feb00002543c04dbdfe3 /libevdev/libevdev.c
parentca082d5fcbe26edf13632a16a7a4d09f680296f6 (diff)
downloadlibevdev-f8fba5b5884bfb62225b9bde991dfdbec92ad751.tar.gz
Drop hardcoded MAX_SLOTS in favour of pre-allocated memory
We can't allocate in sync_mt_state since it may be called in the signal handler. So pre-allocate based on the device's number of slots, store that in the libevdev struct and use it for the sync process. This fixes a remaining bug with the handling of ABS_MT_TRACKING_ID. If a device had > MAX_SLOTS and a slot above that limit would start or stop during a SYN_DROPPED event, the slot would not be synced, and a subsequent touch in that slot may double-terminate or double-open a touchpoint in the client. For the effects of that see commit 41334b5b40cd5456f5f584b55d8888aaafa1f26e Author: Peter Hutterer <peter.hutterer@who-t.net> Date: Thu Mar 6 11:54:00 2014 +1000 If the tracking ID changes during SYN_DROPPED, terminate the touch first Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
Diffstat (limited to 'libevdev/libevdev.c')
-rw-r--r--libevdev/libevdev.c50
1 files changed, 35 insertions, 15 deletions
diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c
index e2070d4..572fd37 100644
--- a/libevdev/libevdev.c
+++ b/libevdev/libevdev.c
@@ -152,6 +152,9 @@ libevdev_reset(struct libevdev *dev)
free(dev->phys);
free(dev->uniq);
free(dev->mt_slot_vals);
+ free(dev->mt_sync.mt_state);
+ free(dev->mt_sync.tracking_id_changes);
+ free(dev->mt_sync.slot_update);
memset(dev, 0, sizeof(*dev));
dev->fd = -1;
dev->initialized = false;
@@ -389,8 +392,24 @@ libevdev_set_fd(struct libevdev* dev, int fd)
goto out;
}
dev->current_slot = abs_info.value;
- }
+ dev->mt_sync.mt_state_sz = sizeof(*dev->mt_sync.mt_state) +
+ (dev->num_slots) * sizeof(int);
+ dev->mt_sync.mt_state = calloc(1, dev->mt_sync.mt_state_sz);
+
+ dev->mt_sync.tracking_id_changes_sz = NLONGS(dev->num_slots) * sizeof(long);
+ dev->mt_sync.tracking_id_changes = malloc(dev->mt_sync.tracking_id_changes_sz);
+
+ dev->mt_sync.slot_update_sz = NLONGS(dev->num_slots * ABS_MT_CNT) * sizeof(long);
+ dev->mt_sync.slot_update = malloc(dev->mt_sync.slot_update_sz);
+
+ if (!dev->mt_sync.tracking_id_changes ||
+ !dev->mt_sync.slot_update ||
+ !dev->mt_sync.mt_state) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ }
}
}
@@ -556,14 +575,15 @@ sync_mt_state(struct libevdev *dev, int create_events)
int axis, slot;
int ioctl_success = 0;
int last_reported_slot = 0;
- struct mt_state {
- int code;
- int val[MAX_SLOTS];
- } mt_state;
- unsigned long slot_update[NLONGS(MAX_SLOTS * ABS_MT_CNT)] = {0};
- unsigned long tracking_id_changes[NLONGS(MAX_SLOTS)] = {0};
+ struct mt_sync_state *mt_state = dev->mt_sync.mt_state;
+ unsigned long *slot_update = dev->mt_sync.slot_update;
+ unsigned long *tracking_id_changes = dev->mt_sync.tracking_id_changes;
int need_tracking_id_changes = 0;
+ memset(dev->mt_sync.slot_update, 0, dev->mt_sync.slot_update_sz);
+ memset(dev->mt_sync.tracking_id_changes, 0,
+ dev->mt_sync.tracking_id_changes_sz);
+
#define AXISBIT(_slot, _axis) (_slot * ABS_MT_CNT + _axis - ABS_MT_MIN)
for (axis = ABS_MT_MIN; axis <= ABS_MT_MAX; axis++) {
@@ -573,8 +593,8 @@ sync_mt_state(struct libevdev *dev, int create_events)
if (!libevdev_has_event_code(dev, EV_ABS, axis))
continue;
- mt_state.code = axis;
- rc = ioctl(dev->fd, EVIOCGMTSLOTS(sizeof(struct mt_state)), &mt_state);
+ mt_state->code = axis;
+ rc = ioctl(dev->fd, EVIOCGMTSLOTS(dev->mt_sync.mt_state_sz), mt_state);
if (rc < 0) {
/* if the first ioctl fails with -EINVAL, chances are the kernel
doesn't support the ioctl. Simply continue */
@@ -586,19 +606,19 @@ sync_mt_state(struct libevdev *dev, int create_events)
if (ioctl_success == 0)
ioctl_success = 1;
- for (slot = 0; slot < min(dev->num_slots, MAX_SLOTS); slot++) {
+ for (slot = 0; slot < dev->num_slots; slot++) {
- if (*slot_value(dev, slot, axis) == mt_state.val[slot])
+ if (*slot_value(dev, slot, axis) == mt_state->val[slot])
continue;
if (axis == ABS_MT_TRACKING_ID &&
*slot_value(dev, slot, axis) != -1 &&
- mt_state.val[slot] != -1) {
+ mt_state->val[slot] != -1) {
set_bit(tracking_id_changes, slot);
need_tracking_id_changes = 1;
}
- *slot_value(dev, slot, axis) = mt_state.val[slot];
+ *slot_value(dev, slot, axis) = mt_state->val[slot];
set_bit(slot_update, AXISBIT(slot, axis));
/* note that this slot has updates */
@@ -615,7 +635,7 @@ sync_mt_state(struct libevdev *dev, int create_events)
}
if (need_tracking_id_changes) {
- for (slot = 0; slot < min(dev->num_slots, MAX_SLOTS); slot++) {
+ for (slot = 0; slot < dev->num_slots; slot++) {
if (!bit_is_set(tracking_id_changes, slot))
continue;
@@ -631,7 +651,7 @@ sync_mt_state(struct libevdev *dev, int create_events)
init_event(dev, ev, EV_SYN, SYN_REPORT, 0);
}
- for (slot = 0; slot < min(dev->num_slots, MAX_SLOTS); slot++) {
+ for (slot = 0; slot < dev->num_slots; slot++) {
if (!bit_is_set(slot_update, AXISBIT(slot, ABS_MT_SLOT)))
continue;