switch: only sync the initial state if we know the state is reliable
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 25 Jan 2017 03:24:31 +0000 (13:24 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Thu, 26 Jan 2017 04:44:04 +0000 (14:44 +1000)
This changes the default behavior to "disable the touchpad on the first lid
close event", thus filtering any laptops where the switch state is buggy and
always in "on" state. Devices where we know the lid switch state is
reliable can be marked as such.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
src/evdev.c
src/libinput-util.c
src/libinput-util.h
test/litest-device-lid-switch.c
test/test-misc.c

index 50c8abd7f5a4e8dda5e58d6effede00212d31f8a..f15b8accc922b1e503bc16c967beb47ad48465fc 100644 (file)
@@ -1356,6 +1356,25 @@ lid_switch_process(struct evdev_dispatch *evdev_dispatch,
        }
 }
 
+static inline enum switch_reliability
+evdev_read_switch_reliability_prop(struct evdev_device *device)
+{
+       const char *prop;
+       enum switch_reliability r;
+
+       prop = udev_device_get_property_value(device->udev_device,
+                                             "LIBINPUT_ATTR_LID_SWITCH_RELIABILITY");
+       if (!parse_switch_reliability_property(prop, &r)) {
+               log_error(evdev_libinput_context(device),
+                         "%s: switch reliability set to unknown value '%s'\n",
+                         device->devname,
+                         prop);
+               r =  RELIABILITY_UNKNOWN;
+       }
+
+       return r;
+}
+
 static void
 lid_switch_destroy(struct evdev_dispatch *evdev_dispatch)
 {
@@ -1372,10 +1391,25 @@ lid_switch_sync_initial_state(struct evdev_device *device,
        struct lid_switch_dispatch *dispatch =
                (struct lid_switch_dispatch*)evdev_dispatch;
        struct libevdev *evdev = device->evdev;
+       bool is_closed = false;
+
+       /* For the initial state sync, we depend on whether the lid switch
+        * is reliable. If we know it's reliable, we sync as expected.
+        * If we're not sure, we ignore the initial state and only sync on
+        * the first future lid close event. Laptops with a broken switch
+        * that always have the switch in 'on' state thus don't mess up our
+        * touchpad.
+        */
+       switch(evdev_read_switch_reliability_prop(device)) {
+       case RELIABILITY_UNKNOWN:
+               is_closed = false;
+               break;
+       case RELIABILITY_RELIABLE:
+               is_closed = libevdev_get_event_value(evdev, EV_SW, SW_LID);
+               break;
+       }
 
-       dispatch->lid_is_closed = libevdev_get_event_value(evdev,
-                                                          EV_SW,
-                                                          SW_LID);
+       dispatch->lid_is_closed = is_closed;
        if (dispatch->lid_is_closed) {
                uint64_t time;
                time = libinput_now(evdev_libinput_context(device));
index 40e1e6e5b0eba4ce53d58b040336411cd54a541c..f5d0aa7f30e795337078d4d16b1e473e0be3b54d 100644 (file)
@@ -278,6 +278,23 @@ parse_dimension_property(const char *prop, size_t *w, size_t *h)
        return true;
 }
 
+bool
+parse_switch_reliability_property(const char *prop,
+                                 enum switch_reliability *reliability)
+{
+       if (!prop) {
+               *reliability = RELIABILITY_UNKNOWN;
+               return true;
+       }
+
+       if (streq(prop, "reliable"))
+               *reliability = RELIABILITY_RELIABLE;
+       else
+               return false;
+
+       return true;
+}
+
 /**
  * Return the next word in a string pointed to by state before the first
  * separator character. Call repeatedly to tokenize a whole string.
index ba09ab6e038aa564c0d9b07b7c8557438d903d15..ce3a5acce0cde894c61ac6fe5659dc2f8b74dcb6 100644 (file)
@@ -377,6 +377,15 @@ int parse_mouse_wheel_click_count_property(const char *prop);
 double parse_trackpoint_accel_property(const char *prop);
 bool parse_dimension_property(const char *prop, size_t *width, size_t *height);
 
+enum switch_reliability {
+       RELIABILITY_UNKNOWN,
+       RELIABILITY_RELIABLE,
+};
+
+bool
+parse_switch_reliability_property(const char *prop,
+                                 enum switch_reliability *reliability);
+
 static inline uint64_t
 us(uint64_t us)
 {
index 823a5c9d1a9f100ca781791ad70dd6fef0129285..b96592dc46d9105704de983e43441f13a5c41a92 100644 (file)
@@ -49,7 +49,8 @@ static const char udev_rule[] =
 "KERNEL!=\"event*\", GOTO=\"switch_end\"\n"
 "\n"
 "ATTRS{name}==\"litest Lid Switch*\",\\\n"
-"    ENV{ID_INPUT_SWITCH}=\"1\"\n"
+"    ENV{ID_INPUT_SWITCH}=\"1\",\\\n"
+"    ENV{LIBINPUT_ATTR_LID_SWITCH_RELIABILITY}=\"reliable\"\n"
 "\n"
 "LABEL=\"switch_end\"";
 
index 9517042dadb772be264910e55f2422c38db7309e..36cabdcfb25ce769d52017239f5a874bd62a9091 100644 (file)
@@ -908,6 +908,45 @@ START_TEST(dimension_prop_parser)
 }
 END_TEST
 
+struct parser_test_reliability {
+       char *tag;
+       bool success;
+       enum switch_reliability reliability;
+};
+
+START_TEST(reliability_prop_parser)
+{
+       struct parser_test_reliability tests[] = {
+               { "reliable", true, RELIABILITY_RELIABLE },
+               { "unreliable", false, 0 },
+               { "", false, 0 },
+               { "0", false, 0 },
+               { "1", false, 0 },
+               { NULL, false, 0, }
+       };
+       enum switch_reliability r;
+       bool success;
+       int i;
+
+       for (i = 0; tests[i].tag != NULL; i++) {
+               r = 0xaf;
+               success = parse_switch_reliability_property(tests[i].tag, &r);
+               ck_assert(success == tests[i].success);
+               if (success)
+                       ck_assert_int_eq(r, tests[i].reliability);
+               else
+                       ck_assert_int_eq(r, 0xaf);
+       }
+
+       success = parse_switch_reliability_property(NULL, &r);
+       ck_assert(success == true);
+       ck_assert_int_eq(r, RELIABILITY_UNKNOWN);
+
+       success = parse_switch_reliability_property("foo", NULL);
+       ck_assert(success == false);
+}
+END_TEST
+
 START_TEST(time_conversion)
 {
        ck_assert_int_eq(us(10), 10);
@@ -1180,6 +1219,7 @@ litest_setup_tests_misc(void)
        litest_add_no_device("misc:parser", wheel_click_count_parser);
        litest_add_no_device("misc:parser", trackpoint_accel_parser);
        litest_add_no_device("misc:parser", dimension_prop_parser);
+       litest_add_no_device("misc:parser", reliability_prop_parser);
        litest_add_no_device("misc:parser", safe_atoi_test);
        litest_add_no_device("misc:parser", safe_atod_test);
        litest_add_no_device("misc:parser", strsplit_test);