quirks: add trackpoint integration attribute

Some versions [1] of the Lenovo ThinkPad Compact USB Keyboard with TrackPoint USB
have the pointing stick on an event node that has keys but is not a regular
keyboard. Thus the stick falls through the cracks and gets disabled on tablet
mode switch. Instead of adding more hacks let's do this properly: tag the
pointing stick as external and have the code in place to deal with that.

[1] This may be caused by recent kernel changes

Fixes #291

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit 8dfe8c68eb)
This commit is contained in:
Peter Hutterer 2019-05-28 09:54:27 +10:00
parent 9694d91f7c
commit 6e60f8fb19
7 changed files with 91 additions and 10 deletions

View file

@ -183,3 +183,6 @@ AttrEventCodeDisable=EV_ABS;BTN_STYLUS;EV_KEY:0x123;
Disables the evdev event type/code tuples on the device. Entries may be
a named event type, or a named event code, or a named event type with a
hexadecimal event code, separated by a single colon.
AttrPointingStickIntegration=internal|external
Indicates the integration of the pointing stick. This is a string enum.
Only needed for external pointing sticks. These are rare.

View file

@ -76,13 +76,20 @@ MatchName=*TPPS/2 Elan TrackPoint*
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadX1Carbon6th*
AttrTrackpointMultiplier=0.4
[Lenovo ThinkPad Compact USB Keyboard with TrackPoint]
[Lenovo ThinkPad Compact USB Keyboard with TrackPoint (keyboard)]
MatchUdevType=keyboard
MatchBus=usb
MatchVendor=0x17EF
MatchProduct=0x6047
AttrKeyboardIntegration=external
[Lenovo ThinkPad Compact USB Keyboard with TrackPoint (trackpoint)]
MatchUdevType=pointingstick
MatchBus=usb
MatchVendor=0x17EF
MatchProduct=0x6047
AttrPointingStickIntegration=external
# Lenovo Thinkpad Yoga (not the consumer versions) disables the keyboard
# mechanically. We must not disable the keyboard because some keys are
# still accessible on the screen and volume rocker.

View file

@ -1382,8 +1382,8 @@ fallback_tablet_mode_switch_event(uint64_t time,
}
static void
fallback_keyboard_pair_tablet_mode(struct evdev_device *keyboard,
struct evdev_device *tablet_mode_switch)
fallback_pair_tablet_mode(struct evdev_device *keyboard,
struct evdev_device *tablet_mode_switch)
{
struct fallback_dispatch *dispatch =
fallback_dispatch(keyboard->dispatch);
@ -1391,8 +1391,12 @@ fallback_keyboard_pair_tablet_mode(struct evdev_device *keyboard,
if ((keyboard->tags & EVDEV_TAG_EXTERNAL_KEYBOARD))
return;
if ((keyboard->tags &
(EVDEV_TAG_TRACKPOINT|EVDEV_TAG_INTERNAL_KEYBOARD)) == 0)
if ((keyboard->tags & EVDEV_TAG_TRACKPOINT)) {
if (keyboard->tags & EVDEV_TAG_EXTERNAL_MOUSE)
return;
/* This filters out all internal keyboard-like devices (Video
* Switch) */
} else if ((keyboard->tags & EVDEV_TAG_INTERNAL_KEYBOARD) == 0)
return;
if (evdev_device_has_model_quirk(keyboard,
@ -1429,7 +1433,7 @@ fallback_interface_device_added(struct evdev_device *device,
struct evdev_device *added_device)
{
fallback_lid_pair_keyboard(device, added_device);
fallback_keyboard_pair_tablet_mode(device, added_device);
fallback_pair_tablet_mode(device, added_device);
}
static void

View file

@ -387,10 +387,34 @@ static void
evdev_tag_trackpoint(struct evdev_device *device,
struct udev_device *udev_device)
{
if (libevdev_has_property(device->evdev,
INPUT_PROP_POINTING_STICK) ||
parse_udev_flag(device, udev_device, "ID_INPUT_POINTINGSTICK"))
device->tags |= EVDEV_TAG_TRACKPOINT;
struct quirks_context *quirks;
struct quirks *q;
char *prop;
if (!libevdev_has_property(device->evdev,
INPUT_PROP_POINTING_STICK) &&
!parse_udev_flag(device, udev_device, "ID_INPUT_POINTINGSTICK"))
return;
device->tags |= EVDEV_TAG_TRACKPOINT;
quirks = evdev_libinput_context(device)->quirks;
q = quirks_fetch_for_device(quirks, device->udev_device);
if (q && quirks_get_string(q, QUIRK_ATTR_TRACKPOINT_INTEGRATION, &prop)) {
if (streq(prop, "internal")) {
/* noop, this is the default anyway */
} else if (streq(prop, "external")) {
device->tags |= EVDEV_TAG_EXTERNAL_MOUSE;
evdev_log_info(device,
"is an external pointing stick\n");
} else {
evdev_log_info(device,
"tagged with unknown value %s\n",
prop);
}
}
quirks_unref(q);
}
static inline void

View file

@ -261,6 +261,7 @@ quirk_get_name(enum quirk q)
case QUIRK_ATTR_PALM_SIZE_THRESHOLD: return "AttrPalmSizeThreshold";
case QUIRK_ATTR_LID_SWITCH_RELIABILITY: return "AttrLidSwitchReliability";
case QUIRK_ATTR_KEYBOARD_INTEGRATION: return "AttrKeyboardIntegration";
case QUIRK_ATTR_TRACKPOINT_INTEGRATION: return "AttrPointingStickIntegration";
case QUIRK_ATTR_TPKBCOMBO_LAYOUT: return "AttrTPKComboLayout";
case QUIRK_ATTR_PRESSURE_RANGE: return "AttrPressureRange";
case QUIRK_ATTR_PALM_PRESSURE_THRESHOLD: return "AttrPalmPressureThreshold";
@ -661,6 +662,13 @@ parse_attr(struct quirks_context *ctx,
p->type = PT_STRING;
p->value.s = safe_strdup(value);
rc = true;
} else if (streq(key, quirk_get_name(QUIRK_ATTR_TRACKPOINT_INTEGRATION))) {
p->id = QUIRK_ATTR_TRACKPOINT_INTEGRATION;
if (!streq(value, "internal") && !streq(value, "external"))
goto out;
p->type = PT_STRING;
p->value.s = safe_strdup(value);
rc = true;
} else if (streq(key, quirk_get_name(QUIRK_ATTR_TPKBCOMBO_LAYOUT))) {
p->id = QUIRK_ATTR_TPKBCOMBO_LAYOUT;
if (!streq(value, "below"))

View file

@ -96,6 +96,7 @@ enum quirk {
QUIRK_ATTR_PALM_SIZE_THRESHOLD,
QUIRK_ATTR_LID_SWITCH_RELIABILITY,
QUIRK_ATTR_KEYBOARD_INTEGRATION,
QUIRK_ATTR_TRACKPOINT_INTEGRATION,
QUIRK_ATTR_TPKBCOMBO_LAYOUT,
QUIRK_ATTR_PRESSURE_RANGE,
QUIRK_ATTR_PALM_PRESSURE_THRESHOLD,

View file

@ -1204,6 +1204,39 @@ START_TEST(quirks_parse_string_attr)
}
END_TEST
START_TEST(quirks_parse_integration_attr)
{
struct litest_device *dev = litest_current_device();
char *do_not_use; /* freed before we can use it */
bool
rc = test_attr_parse(dev,
QUIRK_ATTR_KEYBOARD_INTEGRATION,
"internal",
(qparsefunc)quirks_get_string,
&do_not_use);
ck_assert(rc);
rc = test_attr_parse(dev,
QUIRK_ATTR_KEYBOARD_INTEGRATION,
"external",
(qparsefunc)quirks_get_string,
&do_not_use);
ck_assert(rc);
rc = test_attr_parse(dev,
QUIRK_ATTR_TRACKPOINT_INTEGRATION,
"internal",
(qparsefunc)quirks_get_string,
&do_not_use);
ck_assert(rc);
rc = test_attr_parse(dev,
QUIRK_ATTR_TRACKPOINT_INTEGRATION,
"external",
(qparsefunc)quirks_get_string,
&do_not_use);
ck_assert(rc);
}
END_TEST
START_TEST(quirks_model_one)
{
struct litest_device *dev = litest_current_device();
@ -1432,6 +1465,7 @@ TEST_COLLECTION(quirks)
litest_add_for_device("quirks:parsing", quirks_parse_uint_attr, LITEST_MOUSE);
litest_add_for_device("quirks:parsing", quirks_parse_double_attr, LITEST_MOUSE);
litest_add_for_device("quirks:parsing", quirks_parse_string_attr, LITEST_MOUSE);
litest_add_for_device("quirks:parsing", quirks_parse_integration_attr, LITEST_MOUSE);
litest_add_for_device("quirks:model", quirks_model_one, LITEST_MOUSE);
litest_add_for_device("quirks:model", quirks_model_zero, LITEST_MOUSE);