diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2013-05-29 15:07:44 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2013-10-14 16:34:10 +1000 |
commit | 41840a656f5c790b49fe798b9d99136c23e09a5f (patch) | |
tree | 732577d37eef3e3a08f006db8b68cc2eec4ddc56 /src | |
parent | 0fb59b3487d57523a03f078a2061e2ea0cacbc7c (diff) |
Switch to libevdev for the eventcomm backend
This has a potential bug that would need to be fixed in mtdev first:
if we get a SYN_DROPPED and we miss out on events, the current code emulates a
normal EV_SYN, feeds that to mtdev and hopes that that fills the mtdev output
queue.
If mtdev doesn't generate events on that EV_SYN, we're stuck in limbo and may
get weird results. The loop will continue and sync the device, but there's the
off chance we get odd events.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/eventcomm.c | 282 | ||||
-rw-r--r-- | src/eventcomm.h | 2 |
3 files changed, 165 insertions, 123 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 5443094..69ef453 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -48,7 +48,9 @@ if BUILD_EVENTCOMM synaptics_drv_la_SOURCES += \ eventcomm.c eventcomm.h synaptics_drv_la_LIBADD = \ - $(MTDEV_LIBS) + $(MTDEV_LIBS) \ + $(LIBEVDEV_LIBS) +AM_CPPFLAGS += $(LIBEVDEV_CFLAGS) endif if BUILD_PSMCOMM diff --git a/src/eventcomm.c b/src/eventcomm.c index 258a538..7b9a403 100644 --- a/src/eventcomm.c +++ b/src/eventcomm.c @@ -42,7 +42,8 @@ #include "synproto.h" #include "synapticsstr.h" #include <xf86.h> -#include <mtdev.h> +#include <mtdev-plumbing.h> +#include <libevdev/libevdev.h> #ifndef INPUT_PROP_BUTTONPAD #define INPUT_PROP_BUTTONPAD 0x02 @@ -76,12 +77,16 @@ struct eventcomm_proto_data { int cur_slot; ValuatorMask **last_mt_vals; int num_touches; + + struct libevdev *evdev; + enum libevdev_read_flag read_flag; }; struct eventcomm_proto_data * -EventProtoDataAlloc(void) +EventProtoDataAlloc(int fd) { struct eventcomm_proto_data *proto_data; + int rc; proto_data = calloc(1, sizeof(struct eventcomm_proto_data)); if (!proto_data) @@ -90,6 +95,13 @@ EventProtoDataAlloc(void) proto_data->st_to_mt_scale[0] = 1; proto_data->st_to_mt_scale[1] = 1; + rc = libevdev_new_from_fd(fd, &proto_data->evdev); + if (rc < 0) { + free(proto_data); + proto_data = NULL; + } else + proto_data->read_flag = LIBEVDEV_READ_FLAG_NORMAL; + return proto_data; } @@ -187,16 +199,32 @@ EventDeviceOnHook(InputInfoPtr pInfo, SynapticsParameters * para) /* Try to grab the event device so that data don't leak to /dev/input/mice */ int ret; - SYSCALL(ret = ioctl(pInfo->fd, EVIOCGRAB, (pointer) 1)); + ret = libevdev_grab(proto_data->evdev, LIBEVDEV_GRAB); if (ret < 0) { xf86IDrvMsg(pInfo, X_WARNING, "can't grab event device, errno=%d\n", - errno); + -ret); return FALSE; } } proto_data->need_grab = FALSE; + if (libevdev_get_fd(proto_data->evdev) != -1) { + struct input_event ev; + + libevdev_change_fd(proto_data->evdev, pInfo->fd); + + /* re-sync libevdev's state, but we don't care about the actual + events here */ + libevdev_next_event(proto_data->evdev, LIBEVDEV_READ_FLAG_FORCE_SYNC, &ev); + while (libevdev_next_event(proto_data->evdev, + LIBEVDEV_READ_FLAG_SYNC, &ev) == LIBEVDEV_READ_STATUS_SYNC) + ; + + } else + libevdev_set_fd(proto_data->evdev, pInfo->fd); + + InitializeTouch(pInfo); return TRUE; @@ -218,59 +246,48 @@ EventDeviceOffHook(InputInfoPtr pInfo) * - BTN_TOOL_FINGER * - BTN_TOOL_PEN is _not_ set * - * @param fd The file descriptor to an event device. + * @param evdev Libevdev handle * @param test_grab If true, test whether an EVIOCGRAB is possible on the * device. A failure to grab the event device returns in a failure. * * @return TRUE if the device is a touchpad or FALSE otherwise. */ static Bool -event_query_is_touchpad(int fd, BOOL test_grab) +event_query_is_touchpad(struct libevdev *evdev, BOOL test_grab) { int ret = FALSE, rc; - unsigned long evbits[NBITS(EV_MAX)] = { 0 }; - unsigned long absbits[NBITS(ABS_MAX)] = { 0 }; - unsigned long keybits[NBITS(KEY_MAX)] = { 0 }; if (test_grab) { - SYSCALL(rc = ioctl(fd, EVIOCGRAB, (pointer) 1)); + rc = libevdev_grab(evdev, LIBEVDEV_GRAB); if (rc < 0) return FALSE; } /* Check for ABS_X, ABS_Y, ABS_PRESSURE and BTN_TOOL_FINGER */ - - SYSCALL(rc = ioctl(fd, EVIOCGBIT(0, sizeof(evbits)), evbits)); - if (rc < 0) - goto unwind; - if (!TEST_BIT(EV_SYN, evbits) || - !TEST_BIT(EV_ABS, evbits) || !TEST_BIT(EV_KEY, evbits)) - goto unwind; - - SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits)); - if (rc < 0) - goto unwind; - if (!TEST_BIT(ABS_X, absbits) || !TEST_BIT(ABS_Y, absbits)) + if (!libevdev_has_event_type(evdev, EV_SYN) || + !libevdev_has_event_type(evdev, EV_ABS) || + !libevdev_has_event_type(evdev, EV_KEY)) goto unwind; - SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits)); - if (rc < 0) + if (!libevdev_has_event_code(evdev, EV_ABS, ABS_X) || + !libevdev_has_event_code(evdev, EV_ABS, ABS_Y)) goto unwind; /* we expect touchpad either report raw pressure or touches */ - if (!TEST_BIT(ABS_PRESSURE, absbits) && !TEST_BIT(BTN_TOUCH, keybits)) + if (!libevdev_has_event_code(evdev, EV_KEY, BTN_TOUCH) && + !libevdev_has_event_code(evdev, EV_ABS, ABS_PRESSURE)) goto unwind; + /* all Synaptics-like touchpad report BTN_TOOL_FINGER */ - if (!TEST_BIT(BTN_TOOL_FINGER, keybits)) + if (!libevdev_has_event_code(evdev, EV_KEY, BTN_TOOL_FINGER) || + libevdev_has_event_code(evdev, EV_ABS, BTN_TOOL_PEN)) /* Don't match wacom tablets */ goto unwind; - if (TEST_BIT(BTN_TOOL_PEN, keybits)) - goto unwind; /* Don't match wacom tablets */ ret = TRUE; unwind: if (test_grab) - SYSCALL(ioctl(fd, EVIOCGRAB, (pointer) 0)); + libevdev_grab(evdev, LIBEVDEV_UNGRAB); return (ret == TRUE); } @@ -305,29 +322,27 @@ static struct model_lookup_t model_lookup_table[] = { * @return TRUE on success or FALSE otherwise. */ static Bool -event_query_model(int fd, enum TouchpadModel *model_out, +event_query_model(struct libevdev *evdev, enum TouchpadModel *model_out, unsigned short *vendor_id, unsigned short *product_id) { - struct input_id id; - int rc; + int vendor, product; struct model_lookup_t *model_lookup; - SYSCALL(rc = ioctl(fd, EVIOCGID, &id)); - if (rc < 0) - return FALSE; + vendor = libevdev_get_id_vendor(evdev); + product = libevdev_get_id_product(evdev); for (model_lookup = model_lookup_table; model_lookup->vendor; model_lookup++) { - if (model_lookup->vendor == id.vendor && + if (model_lookup->vendor == vendor && (model_lookup->product_start == PRODUCT_ANY || - model_lookup->product_start <= id.product) && + model_lookup->product_start <= product) && (model_lookup->product_end == PRODUCT_ANY || - model_lookup->product_end >= id.product)) + model_lookup->product_end >= product)) *model_out = model_lookup->model; } - *vendor_id = id.vendor; - *product_id = id.product; + *vendor_id = vendor; + *product_id = product; return TRUE; } @@ -347,27 +362,21 @@ event_query_model(int fd, enum TouchpadModel *model_out, * @return Zero on success, or errno otherwise. */ static int -event_get_abs(InputInfoPtr pInfo, int fd, int code, +event_get_abs(struct libevdev *evdev, int code, int *min, int *max, int *fuzz, int *res) { - int rc; - struct input_absinfo abs = { 0 }; + const struct input_absinfo *abs; - SYSCALL(rc = ioctl(fd, EVIOCGABS(code), &abs)); - if (rc < 0) { - xf86IDrvMsg(pInfo, X_ERROR, "%s EVIOCGABS error on %d (%s)\n", - __func__, code, strerror(errno)); - return errno; - } + abs = libevdev_get_abs_info(evdev, code); + *min = abs->minimum; + *max = abs->maximum; - *min = abs.minimum; - *max = abs.maximum; /* We dont trust a zero fuzz as it probably is just a lazy value */ - if (fuzz && abs.fuzz > 0) - *fuzz = abs.fuzz; + if (fuzz && abs->fuzz > 0) + *fuzz = abs->fuzz; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30) if (res) - *res = abs.resolution; + *res = abs->resolution; #endif return 0; @@ -379,36 +388,25 @@ event_query_axis_ranges(InputInfoPtr pInfo) { SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private; struct eventcomm_proto_data *proto_data = priv->proto_data; - unsigned long absbits[NBITS(ABS_MAX)] = { 0 }; - unsigned long keybits[NBITS(KEY_MAX)] = { 0 }; char buf[256] = { 0 }; - int rc; /* The kernel's fuzziness concept seems a bit weird, but it can more or * less be applied as hysteresis directly, i.e. no factor here. */ - event_get_abs(pInfo, pInfo->fd, ABS_X, &priv->minx, &priv->maxx, + event_get_abs(proto_data->evdev, ABS_X, &priv->minx, &priv->maxx, &priv->synpara.hyst_x, &priv->resx); - event_get_abs(pInfo, pInfo->fd, ABS_Y, &priv->miny, &priv->maxy, + event_get_abs(proto_data->evdev, ABS_Y, &priv->miny, &priv->maxy, &priv->synpara.hyst_y, &priv->resy); - priv->has_pressure = FALSE; - priv->has_width = FALSE; - SYSCALL(rc = ioctl(pInfo->fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits)); - if (rc >= 0) { - priv->has_pressure = (TEST_BIT(ABS_PRESSURE, absbits) != 0); - priv->has_width = (TEST_BIT(ABS_TOOL_WIDTH, absbits) != 0); - } - else - xf86IDrvMsg(pInfo, X_ERROR, "failed to query ABS bits (%s)\n", - strerror(errno)); + priv->has_pressure = libevdev_has_event_code(proto_data->evdev, EV_ABS, ABS_PRESSURE); + priv->has_width = libevdev_has_event_code(proto_data->evdev, EV_ABS, ABS_TOOL_WIDTH); if (priv->has_pressure) - event_get_abs(pInfo, pInfo->fd, ABS_PRESSURE, &priv->minp, &priv->maxp, + event_get_abs(proto_data->evdev, ABS_PRESSURE, &priv->minp, &priv->maxp, NULL, NULL); if (priv->has_width) - event_get_abs(pInfo, pInfo->fd, ABS_TOOL_WIDTH, + event_get_abs(proto_data->evdev, ABS_TOOL_WIDTH, &priv->minw, &priv->maxw, NULL, NULL); if (priv->has_touch) { @@ -417,9 +415,9 @@ event_query_axis_ranges(InputInfoPtr pInfo) int st_miny = priv->miny; int st_maxy = priv->maxy; - event_get_abs(pInfo, pInfo->fd, ABS_MT_POSITION_X, &priv->minx, + event_get_abs(proto_data->evdev, ABS_MT_POSITION_X, &priv->minx, &priv->maxx, &priv->synpara.hyst_x, &priv->resx); - event_get_abs(pInfo, pInfo->fd, ABS_MT_POSITION_Y, &priv->miny, + event_get_abs(proto_data->evdev, ABS_MT_POSITION_Y, &priv->miny, &priv->maxy, &priv->synpara.hyst_y, &priv->resy); proto_data->st_to_mt_offset[0] = priv->minx - st_minx; @@ -430,19 +428,17 @@ event_query_axis_ranges(InputInfoPtr pInfo) (priv->maxy - priv->miny) / (st_maxy - st_miny); } - SYSCALL(rc = ioctl(pInfo->fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits)); - if (rc >= 0) { - priv->has_left = (TEST_BIT(BTN_LEFT, keybits) != 0); - priv->has_right = (TEST_BIT(BTN_RIGHT, keybits) != 0); - priv->has_middle = (TEST_BIT(BTN_MIDDLE, keybits) != 0); - priv->has_double = (TEST_BIT(BTN_TOOL_DOUBLETAP, keybits) != 0); - priv->has_triple = (TEST_BIT(BTN_TOOL_TRIPLETAP, keybits) != 0); - - if ((TEST_BIT(BTN_0, keybits) != 0) || - (TEST_BIT(BTN_1, keybits) != 0) || - (TEST_BIT(BTN_2, keybits) != 0) || (TEST_BIT(BTN_3, keybits) != 0)) - priv->has_scrollbuttons = 1; - } + priv->has_left = libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_LEFT); + priv->has_right = libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_RIGHT); + priv->has_middle = libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_MIDDLE); + priv->has_double = libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_TOOL_DOUBLETAP); + priv->has_triple = libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_TOOL_TRIPLETAP); + + if (libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_0) || + libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_1) || + libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_2) || + libevdev_has_event_code(proto_data->evdev, EV_KEY, BTN_3)) + priv->has_scrollbuttons = 1; /* Now print the device information */ xf86IDrvMsg(pInfo, X_PROBED, "x-axis range %d - %d (res %d)\n", @@ -483,8 +479,8 @@ EventQueryHardware(InputInfoPtr pInfo) SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private; struct eventcomm_proto_data *proto_data = priv->proto_data; - if (!event_query_is_touchpad - (pInfo->fd, (proto_data) ? proto_data->need_grab : TRUE)) + if (!event_query_is_touchpad(proto_data->evdev, + (proto_data) ? proto_data->need_grab : TRUE)) return FALSE; xf86IDrvMsg(pInfo, X_PROBED, "touchpad found\n"); @@ -497,27 +493,59 @@ SynapticsReadEvent(InputInfoPtr pInfo, struct input_event *ev) { SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private; struct eventcomm_proto_data *proto_data = priv->proto_data; - int rc = TRUE; - ssize_t len; + int rc; + int have_events = TRUE; + static struct timeval last_event_time; - if (proto_data->mtdev) - len = mtdev_get(proto_data->mtdev, pInfo->fd, ev, 1) * - sizeof(struct input_event); - else - len = read(pInfo->fd, ev, sizeof(*ev)); - if (len <= 0) { - /* We use X_NONE here because it doesn't alloc */ - if (errno != EAGAIN) - LogMessageVerbSigSafe(X_ERROR, 0, "%s: Read error %d\n", pInfo->name, - errno); - rc = FALSE; + /* empty mtdev queue first */ + if (proto_data->mtdev && !mtdev_empty(proto_data->mtdev)) { + mtdev_get_event(proto_data->mtdev, ev); + return TRUE; } - else if (len % sizeof(*ev)) { - LogMessageVerbSigSafe(X_ERROR, 0, "%s: Read error, invalid number of bytes.", - pInfo->name); - rc = FALSE; + + do { + rc = libevdev_next_event(proto_data->evdev, proto_data->read_flag, ev); + if (rc < 0) { + if (rc != -EAGAIN) { + LogMessageVerbSigSafe(X_ERROR, 0, "%s: Read error %d\n", pInfo->name, + errno); + } else if (proto_data->read_flag == LIBEVDEV_READ_FLAG_SYNC) + proto_data->read_flag = LIBEVDEV_READ_FLAG_NORMAL; + have_events = FALSE; + } else { + have_events = TRUE; + + /* SYN_DROPPED received in normal mode. Create a normal EV_SYN + so we process what's in the queue atm, then ensure we sync + next time */ + if (rc == LIBEVDEV_READ_STATUS_SYNC && + proto_data->read_flag == LIBEVDEV_READ_FLAG_NORMAL) { + proto_data->read_flag = LIBEVDEV_READ_FLAG_SYNC; + ev->type = EV_SYN; + ev->code = SYN_DROPPED; + ev->value = 0; + ev->time = last_event_time; + } else if (ev->type == EV_SYN) + last_event_time = ev->time; + + /* feed mtdev. nomnomnomnom */ + if (proto_data->mtdev) + mtdev_put_event(proto_data->mtdev, ev); + } + } while (have_events && proto_data->mtdev && mtdev_empty(proto_data->mtdev)); + + /* loop exits if: + - we don't have mtdev, ev is valid, rc is TRUE, let's return it + - we have mtdev and it has events for us, get those + - we don't have a new event and mtdev doesn't have events either. + */ + if (have_events && proto_data->mtdev) { + have_events = !mtdev_empty(proto_data->mtdev); + if (have_events) + mtdev_get_event(proto_data->mtdev, ev); } - return rc; + + return have_events; } static Bool @@ -745,21 +773,18 @@ event_query_touch(InputInfoPtr pInfo) struct eventcomm_proto_data *proto_data = priv->proto_data; struct mtdev *mtdev; int i; - int rc; - uint8_t prop; priv->max_touches = 0; priv->num_mt_axes = 0; #ifdef EVIOCGPROP - SYSCALL(rc = ioctl(pInfo->fd, EVIOCGPROP(sizeof(prop)), &prop)); - if (rc >= 0 && BitIsOn(&prop, INPUT_PROP_SEMI_MT)) { + if (libevdev_has_property(proto_data->evdev, INPUT_PROP_SEMI_MT)) { xf86IDrvMsg(pInfo, X_INFO, "ignoring touch events for semi-multitouch device\n"); priv->has_semi_mt = TRUE; } - if (rc >= 0 && BitIsOn(&prop, INPUT_PROP_BUTTONPAD)) { + if (libevdev_has_property(proto_data->evdev, INPUT_PROP_BUTTONPAD)) { xf86IDrvMsg(pInfo, X_INFO, "found clickpad property\n"); para->clickpad = TRUE; } @@ -865,18 +890,18 @@ EventReadDevDimensions(InputInfoPtr pInfo) struct eventcomm_proto_data *proto_data = priv->proto_data; int i; - proto_data = EventProtoDataAlloc(); + proto_data = EventProtoDataAlloc(pInfo->fd); priv->proto_data = proto_data; for (i = 0; i < MT_ABS_SIZE; i++) proto_data->axis_map[i] = -1; proto_data->cur_slot = -1; - if (event_query_is_touchpad(pInfo->fd, proto_data->need_grab)) { + if (event_query_is_touchpad(proto_data->evdev, proto_data->need_grab)) { event_query_touch(pInfo); event_query_axis_ranges(pInfo); } - event_query_model(pInfo->fd, &priv->model, &priv->id_vendor, + event_query_model(proto_data->evdev, &priv->model, &priv->id_vendor, &priv->id_product); xf86IDrvMsg(pInfo, X_PROBED, "Vendor %#hx Product %#hx\n", @@ -897,7 +922,14 @@ EventAutoDevProbe(InputInfoPtr pInfo, const char *device) SYSCALL(fd = open(device, O_RDONLY)); if (fd >= 0) { - touchpad_found = event_query_is_touchpad(fd, TRUE); + int rc; + struct libevdev *evdev; + + rc = libevdev_new_from_fd(fd, &evdev); + if (rc >= 0) { + touchpad_found = event_query_is_touchpad(evdev, TRUE); + libevdev_free(evdev); + } SYSCALL(close(fd)); /* if a device is set and not a touchpad (or already grabbed), @@ -925,17 +957,25 @@ EventAutoDevProbe(InputInfoPtr pInfo, const char *device) int fd = -1; if (!touchpad_found) { + int rc; + struct libevdev *evdev; + sprintf(fname, "%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name); SYSCALL(fd = open(fname, O_RDONLY)); if (fd < 0) continue; - if (event_query_is_touchpad(fd, TRUE)) { - touchpad_found = TRUE; - xf86IDrvMsg(pInfo, X_PROBED, "auto-dev sets device to %s\n", - fname); - pInfo->options = - xf86ReplaceStrOption(pInfo->options, "Device", fname); + rc = libevdev_new_from_fd(fd, &evdev); + if (rc >= 0) { + touchpad_found = event_query_is_touchpad(evdev, TRUE); + libevdev_free(evdev); + if (touchpad_found) { + xf86IDrvMsg(pInfo, X_PROBED, "auto-dev sets device to %s\n", + fname); + pInfo->options = xf86ReplaceStrOption(pInfo->options, + "Device", + fname); + } } SYSCALL(close(fd)); } diff --git a/src/eventcomm.h b/src/eventcomm.h index ef89108..4d759ff 100644 --- a/src/eventcomm.h +++ b/src/eventcomm.h @@ -38,7 +38,7 @@ struct eventcomm_proto_data; -extern struct eventcomm_proto_data *EventProtoDataAlloc(void); +extern struct eventcomm_proto_data *EventProtoDataAlloc(int fd); extern Bool EventReadHwState(InputInfoPtr pInfo, |