Commit cbde0894 authored by Peter Hutterer's avatar Peter Hutterer

Merge branch 'serial-synaptics-cursor-jump'

parents fbc9be19 a87d51f9
......@@ -639,22 +639,19 @@ static enum libinput_config_click_method
tp_click_get_default_method(struct tp_dispatch *tp)
{
struct evdev_device *device = tp->device;
uint32_t clickfinger_models = EVDEV_MODEL_CHROMEBOOK |
EVDEV_MODEL_SYSTEM76_BONOBO |
EVDEV_MODEL_SYSTEM76_GALAGO |
EVDEV_MODEL_SYSTEM76_KUDU |
EVDEV_MODEL_CLEVO_W740SU;
if (!tp->buttons.is_clickpad)
return LIBINPUT_CONFIG_CLICK_METHOD_NONE;
else if (libevdev_get_id_vendor(tp->device->evdev) == VENDOR_ID_APPLE)
return LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
switch (device->model) {
case EVDEV_MODEL_CHROMEBOOK:
case EVDEV_MODEL_SYSTEM76_BONOBO:
case EVDEV_MODEL_SYSTEM76_GALAGO:
case EVDEV_MODEL_SYSTEM76_KUDU:
case EVDEV_MODEL_CLEVO_W740SU:
if (device->model_flags & clickfinger_models)
return LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
default:
break;
}
return LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
}
......@@ -686,7 +683,7 @@ tp_init_middlebutton_emulation(struct tp_dispatch *tp,
if (!libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE)) {
enable_by_default = true;
want_config_option = false;
} else if (device->model == EVDEV_MODEL_ALPS_TOUCHPAD) {
} else if (device->model_flags & EVDEV_MODEL_ALPS_TOUCHPAD) {
enable_by_default = true;
want_config_option = true;
} else
......
......@@ -341,6 +341,40 @@ tp_process_absolute_st(struct tp_dispatch *tp,
}
}
static inline void
tp_restore_synaptics_touches(struct tp_dispatch *tp,
uint64_t time)
{
unsigned int i;
unsigned int nfake_touches;
nfake_touches = tp_fake_finger_count(tp);
if (nfake_touches < 3)
return;
if (tp->nfingers_down >= nfake_touches ||
tp->nfingers_down == tp->num_slots)
return;
/* Synaptics devices may end touch 2 on BTN_TOOL_TRIPLETAP
* and start it again on the next frame with different coordinates
* (#91352). We search the touches we have, if there is one that has
* just ended despite us being on tripletap, we move it back to
* update.
*/
for (i = 0; i < tp->num_slots; i++) {
struct tp_touch *t = tp_get_touch(tp, i);
if (t->state != TOUCH_END)
continue;
/* new touch, move it through begin to update immediately */
tp_new_touch(tp, t, time);
tp_begin_touch(tp, t, time);
t->state = TOUCH_UPDATE;
}
}
static void
tp_process_fake_touches(struct tp_dispatch *tp,
uint64_t time)
......@@ -353,6 +387,10 @@ tp_process_fake_touches(struct tp_dispatch *tp,
if (nfake_touches == FAKE_FINGER_OVERFLOW)
return;
if (tp->device->model_flags &
EVDEV_MODEL_SYNAPTICS_SERIAL_TOUCHPAD)
tp_restore_synaptics_touches(tp, time);
start = tp->has_mt ? tp->num_slots : 0;
for (i = start; i < tp->ntouches; i++) {
t = tp_get_touch(tp, i);
......@@ -722,6 +760,24 @@ tp_unhover_touches(struct tp_dispatch *tp, uint64_t time)
}
static inline bool
tp_need_motion_history_reset(struct tp_dispatch *tp)
{
/* semi-mt finger postions may "jump" when nfingers changes */
if (tp->semi_mt && tp->nfingers_down != tp->old_nfingers_down)
return true;
/* if we're transitioning between slots and fake touches in either
* direction, we may get a coordinate jump
*/
if (tp->nfingers_down != tp->old_nfingers_down &&
(tp->nfingers_down > tp->num_slots ||
tp->old_nfingers_down > tp->num_slots))
return true;
return false;
}
static void
tp_process_state(struct tp_dispatch *tp, uint64_t time)
{
......@@ -729,16 +785,23 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
struct tp_touch *first = tp_get_touch(tp, 0);
unsigned int i;
bool restart_filter = false;
bool want_motion_reset;
tp_process_fake_touches(tp, time);
tp_unhover_touches(tp, time);
want_motion_reset = tp_need_motion_history_reset(tp);
for (i = 0; i < tp->ntouches; i++) {
t = tp_get_touch(tp, i);
/* semi-mt finger postions may "jump" when nfingers changes */
if (tp->semi_mt && tp->nfingers_down != tp->old_nfingers_down)
if (want_motion_reset) {
tp_motion_history_reset(t);
t->quirks.reset_motion_history = true;
} else if (t->quirks.reset_motion_history) {
tp_motion_history_reset(t);
t->quirks.reset_motion_history = false;
}
if (i >= tp->num_slots && t->state != TOUCH_NONE) {
t->point = first->point;
......@@ -1224,7 +1287,7 @@ evdev_tag_touchpad(struct evdev_device *device,
*/
bustype = libevdev_get_id_bustype(device->evdev);
if (bustype == BUS_USB) {
if (device->model == EVDEV_MODEL_APPLE_TOUCHPAD)
if (device->model_flags & EVDEV_MODEL_APPLE_TOUCHPAD)
device->tags |= EVDEV_TAG_INTERNAL_TOUCHPAD;
} else if (bustype != BUS_BLUETOOTH)
device->tags |= EVDEV_TAG_INTERNAL_TOUCHPAD;
......@@ -1350,14 +1413,10 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal)
tp->accel.x_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_x;
tp->accel.y_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_y;
switch (tp->device->model) {
case EVDEV_MODEL_LENOVO_X230:
if (tp->device->model_flags & EVDEV_MODEL_LENOVO_X230)
profile = touchpad_lenovo_x230_accel_profile;
break;
default:
else
profile = touchpad_accel_profile_linear;
break;
}
if (evdev_device_init_pointer_acceleration(tp->device, profile) == -1)
return -1;
......@@ -1460,7 +1519,7 @@ tp_init_palmdetect(struct tp_dispatch *tp,
/* Wacom doesn't have internal touchpads,
* Apple touchpads are always big enough to warrant palm detection */
if (device->model == EVDEV_MODEL_WACOM_TOUCHPAD)
if (device->model_flags & EVDEV_MODEL_WACOM_TOUCHPAD)
return 0;
/* Enable palm detection on touchpads >= 70 mm. Anything smaller
......
......@@ -147,6 +147,15 @@ struct tp_touch {
int distance; /* distance == 0 means touch */
int pressure;
struct {
/* A quirk mostly used on Synaptics touchpads. In a
transition to/from fake touches > num_slots, the current
event data is likely garbage and the subsequent event
is likely too. This marker tells us to reset the motion
history again -> this effectively swallows any motion */
bool reset_motion_history;
} quirks;
struct {
struct device_coords samples[TOUCHPAD_HISTORY_LENGTH];
unsigned int index;
......
......@@ -1525,8 +1525,8 @@ evdev_read_dpi_prop(struct evdev_device *device)
return dpi;
}
static inline enum evdev_device_model
evdev_read_model(struct evdev_device *device)
static inline uint32_t
evdev_read_model_flags(struct evdev_device *device)
{
const struct model_map {
const char *property;
......@@ -1541,18 +1541,20 @@ evdev_read_model(struct evdev_device *device)
{ "LIBINPUT_MODEL_APPLE_TOUCHPAD", EVDEV_MODEL_APPLE_TOUCHPAD },
{ "LIBINPUT_MODEL_WACOM_TOUCHPAD", EVDEV_MODEL_WACOM_TOUCHPAD },
{ "LIBINPUT_MODEL_ALPS_TOUCHPAD", EVDEV_MODEL_ALPS_TOUCHPAD },
{ "LIBINPUT_MODEL_SYNAPTICS_SERIAL_TOUCHPAD", EVDEV_MODEL_SYNAPTICS_SERIAL_TOUCHPAD },
{ NULL, EVDEV_MODEL_DEFAULT },
};
const struct model_map *m = model_map;
uint32_t model_flags = 0;
while (m->property) {
if (!!udev_device_get_property_value(device->udev_device,
m->property))
break;
model_flags |= m->model;
m++;
}
return m->model;
return model_flags;
}
static inline int
......@@ -2146,7 +2148,7 @@ evdev_device_create(struct libinput_seat *seat,
device->scroll.direction = 0;
device->scroll.wheel_click_angle =
evdev_read_wheel_click_prop(device);
device->model = evdev_read_model(device);
device->model_flags = evdev_read_model_flags(device);
device->dpi = DEFAULT_MOUSE_DPI;
/* at most 5 SYN_DROPPED log-messages per 30s */
......
......@@ -95,16 +95,17 @@ enum evdev_middlebutton_event {
};
enum evdev_device_model {
EVDEV_MODEL_DEFAULT,
EVDEV_MODEL_LENOVO_X230,
EVDEV_MODEL_CHROMEBOOK,
EVDEV_MODEL_SYSTEM76_BONOBO,
EVDEV_MODEL_SYSTEM76_GALAGO,
EVDEV_MODEL_SYSTEM76_KUDU,
EVDEV_MODEL_CLEVO_W740SU,
EVDEV_MODEL_APPLE_TOUCHPAD,
EVDEV_MODEL_WACOM_TOUCHPAD,
EVDEV_MODEL_ALPS_TOUCHPAD,
EVDEV_MODEL_DEFAULT = 0,
EVDEV_MODEL_LENOVO_X230 = (1 << 0),
EVDEV_MODEL_CHROMEBOOK = (1 << 1),
EVDEV_MODEL_SYSTEM76_BONOBO = (1 << 2),
EVDEV_MODEL_SYSTEM76_GALAGO = (1 << 3),
EVDEV_MODEL_SYSTEM76_KUDU = (1 << 4),
EVDEV_MODEL_CLEVO_W740SU = (1 << 5),
EVDEV_MODEL_APPLE_TOUCHPAD = (1 << 6),
EVDEV_MODEL_WACOM_TOUCHPAD = (1 << 7),
EVDEV_MODEL_ALPS_TOUCHPAD = (1 << 8),
EVDEV_MODEL_SYNAPTICS_SERIAL_TOUCHPAD = (1 << 9),
};
struct mt_slot {
......@@ -221,7 +222,7 @@ struct evdev_device {
int dpi; /* HW resolution */
struct ratelimit syn_drop_limit; /* ratelimit for SYN_DROPPED logging */
enum evdev_device_model model;
uint32_t model_flags;
};
#define EVDEV_UNHANDLED_DEVICE ((struct evdev_device *) 1)
......
......@@ -37,6 +37,8 @@
#define VENDOR_ID_APPLE 0x5ac
#define VENDOR_ID_WACOM 0x56a
#define VENDOR_ID_SYNAPTICS_SERIAL 0x002
#define PRODUCT_ID_SYNAPTICS_SERIAL 0x007
/* The HW DPI rate we normalize to before calculating pointer acceleration */
#define DEFAULT_MOUSE_DPI 1000
......
......@@ -1008,6 +1008,28 @@ START_TEST(device_udev_tag_apple)
udev_device_unref(d);
}
END_TEST
START_TEST(device_udev_tag_synaptics_serial)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *device = dev->libinput_device;
struct udev_device *d;
const char *prop;
d = libinput_device_get_udev_device(device);
prop = udev_device_get_property_value(d,
"LIBINPUT_MODEL_SYNAPTICS_SERIAL_TOUCHPAD");
if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_SYNAPTICS_SERIAL &&
libevdev_get_id_product(dev->evdev) == PRODUCT_ID_SYNAPTICS_SERIAL)
ck_assert_notnull(prop);
else
ck_assert(prop == NULL);
udev_device_unref(d);
}
END_TEST
void
litest_setup_tests(void)
{
......@@ -1054,4 +1076,5 @@ litest_setup_tests(void)
litest_add("device:udev tags", device_udev_tag_alps, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("device:udev tags", device_udev_tag_wacom, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("device:udev tags", device_udev_tag_apple, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("device:udev tags", device_udev_tag_synaptics_serial, LITEST_TOUCHPAD, LITEST_ANY);
}
......@@ -4323,6 +4323,120 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg_tap)
}
END_TEST
START_TEST(touchpad_tool_tripletap_touch_count)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_pointer *ptrev;
/* Synaptics touchpads sometimes end one touch point while
* simultaneously setting BTN_TOOL_TRIPLETAP.
* https://bugs.freedesktop.org/show_bug.cgi?id=91352
*/
litest_drain_events(li);
enable_clickfinger(dev);
/* touch 1 down */
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, 1);
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 1200);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 3200);
litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 78);
litest_event(dev, EV_ABS, ABS_X, 1200);
litest_event(dev, EV_ABS, ABS_Y, 3200);
litest_event(dev, EV_ABS, ABS_PRESSURE, 78);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1);
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
msleep(2);
/* touch 2 down */
litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, 1);
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 2200);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 3200);
litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 73);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
msleep(2);
/* touch 3 down, coordinate jump + ends slot 1 */
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 4000);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 4000);
litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 78);
litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
litest_event(dev, EV_ABS, ABS_X, 4000);
litest_event(dev, EV_ABS, ABS_Y, 4000);
litest_event(dev, EV_ABS, ABS_PRESSURE, 78);
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
msleep(2);
/* slot 2 reactivated:
* Note, slot is activated close enough that we don't accidentally
* trigger the clickfinger distance check, remains to be seen if
* that is true for real-world interaction.
*/
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 4000);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 4000);
litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 78);
litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, 3);
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, 3500);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, 3500);
litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 73);
litest_event(dev, EV_ABS, ABS_X, 4000);
litest_event(dev, EV_ABS, ABS_Y, 4000);
litest_event(dev, EV_ABS, ABS_PRESSURE, 78);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
msleep(2);
/* now a click should trigger middle click */
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
litest_wait_for_event(li);
event = libinput_get_event(li);
ptrev = litest_is_button_event(event,
BTN_MIDDLE,
LIBINPUT_BUTTON_STATE_PRESSED);
libinput_event_destroy(event);
event = libinput_get_event(li);
ptrev = litest_is_button_event(event,
BTN_MIDDLE,
LIBINPUT_BUTTON_STATE_RELEASED);
/* silence gcc set-but-not-used warning, litest_is_button_event
* checks what we care about */
event = libinput_event_pointer_get_base_event(ptrev);
libinput_event_destroy(event);
/* release everything */
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0);
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
}
END_TEST
void
litest_setup_tests(void)
{
......@@ -4457,4 +4571,6 @@ litest_setup_tests(void)
litest_add("touchpad:thumb", touchpad_thumb_tap_hold, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add_for_device("touchpad:bugs", touchpad_tool_tripletap_touch_count, LITEST_SYNAPTICS_TOPBUTTONPAD);
}
......@@ -70,6 +70,12 @@ libinput:name:Atmel maXTouch Touchpad:dmi:*svn*GOOGLE*:pn*Samus*
libinput:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*:pvrThinkPadX230*
LIBINPUT_MODEL_LENOVO_X230=1
##########################################
# Synaptics
##########################################
libinput:touchpad:input:b0011v0002p0007*
LIBINPUT_MODEL_SYNAPTICS_SERIAL_TOUCHPAD=1
##########################################
# System76
##########################################
......
......@@ -25,18 +25,12 @@ KERNELS=="*input*", \
IMPORT{builtin}="hwdb 'libinput:name:$attr{name}:fwversion:$env{LIBINPUT_MODEL_FIRMWARE_VERSION}'"
# End of touchpad firmware detection
# Matches below are exclusive, if one matches we skip the rest
# hwdb matches:
#
# libinput:touchpad:<modalias>
ENV{ID_INPUT_TOUCHPAD}=="1", \
IMPORT{builtin}="hwdb --subsystem=input --lookup-prefix=libinput:touchpad:", \
GOTO="libinput_model_quirks_end"
IMPORT{builtin}="hwdb --subsystem=input --lookup-prefix=libinput:touchpad:"
# libinput:name:<name>:dmi:<dmi string>
KERNELS=="input*", \
IMPORT{builtin}="hwdb 'libinput:name:$attr{name}:$attr{[dmi/id]modalias}'", \
GOTO="libinput_model_quirks_end"
IMPORT{builtin}="hwdb 'libinput:name:$attr{name}:$attr{[dmi/id]modalias}'"
LABEL="libinput_model_quirks_end"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment