Signed-off-by: Peter Hutterer <[email protected]>
---
 src/evdev.c                                | 64 ++++++++++++++++++++-
 src/evdev.h                                |  4 ++
 src/libinput.h                             | 15 +++++
 test/Makefile.am                           |  1 +
 test/litest-device-thinkpad-extrabuttons.c | 89 +++++++++++++++++++++++++++++
 test/litest.c                              |  5 ++
 test/litest.h                              |  1 +
 test/test-switch.c                         | 90 ++++++++++++++++++++++++++++--
 8 files changed, 263 insertions(+), 6 deletions(-)
 create mode 100644 test/litest-device-thinkpad-extrabuttons.c

diff --git a/src/evdev.c b/src/evdev.c
index aa73fa1..4b91e5e 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -938,6 +938,32 @@ fallback_process_absolute_motion(struct fallback_dispatch 
*dispatch,
        }
 }
 
+static inline void
+fallback_process_switch(struct fallback_dispatch *dispatch,
+                       struct evdev_device *device,
+                       struct input_event *e,
+                       uint64_t time)
+{
+       enum libinput_switch_state state;
+
+       switch (e->code) {
+       case SW_RFKILL_ALL:
+               if (dispatch->sw.rfkill_all_state == e->value)
+                       return;
+
+               dispatch->sw.rfkill_all_state = e->value;
+               if (e->value)
+                       state = LIBINPUT_SWITCH_STATE_ON;
+               else
+                       state = LIBINPUT_SWITCH_STATE_OFF;
+               switch_notify_toggle(&device->base,
+                                    time,
+                                    LIBINPUT_SWITCH_RF_DISABLED,
+                                    state);
+               break;
+       }
+}
+
 void
 evdev_notify_axis(struct evdev_device *device,
                  uint64_t time,
@@ -1140,6 +1166,9 @@ fallback_process(struct evdev_dispatch *evdev_dispatch,
        case EV_KEY:
                fallback_process_key(dispatch, device, event, time);
                break;
+       case EV_SW:
+               fallback_process_switch(dispatch, device, event, time);
+               break;
        case EV_SYN:
                sent = fallback_flush_pending_event(dispatch, device, time);
                switch (sent) {
@@ -1258,6 +1287,21 @@ fallback_suspend(struct evdev_dispatch *evdev_dispatch,
 }
 
 static void
+fallback_sync_initial_state(struct evdev_device *device,
+                           struct evdev_dispatch *evdev_dispatch)
+{
+       struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
+
+       if (dispatch->sw.rfkill_all_state) {
+               uint64_t time = libinput_now(evdev_libinput_context(device));
+               switch_notify_toggle(&device->base,
+                                    time,
+                                    LIBINPUT_SWITCH_RF_DISABLED,
+                                    LIBINPUT_SWITCH_STATE_ON);
+       }
+}
+
+static void
 fallback_toggle_touch(struct evdev_dispatch *evdev_dispatch,
                      struct evdev_device *device,
                      bool enable)
@@ -1333,7 +1377,7 @@ struct evdev_dispatch_interface fallback_interface = {
        NULL, /* device_removed */
        NULL, /* device_suspended */
        NULL, /* device_resumed */
-       NULL, /* post_added */
+       fallback_sync_initial_state, /* post_added */
        fallback_toggle_touch, /* toggle_touch */
 };
 
@@ -1791,6 +1835,19 @@ fallback_dispatch_init_abs(struct fallback_dispatch 
*dispatch,
        evdev_device_init_abs_range_warnings(device);
 }
 
+static inline void
+fallback_dispatch_init_switch(struct fallback_dispatch *dispatch,
+                             struct evdev_device *device)
+{
+       if (!libevdev_has_event_code(device->evdev, EV_SW, SW_RFKILL_ALL))
+               return;
+
+       dispatch->sw.rfkill_all_state = libevdev_get_event_value(device->evdev,
+                                                                EV_SW,
+                                                                SW_RFKILL_ALL);
+       device->seat_caps |= EVDEV_DEVICE_SWITCH;
+}
+
 static struct evdev_dispatch *
 fallback_dispatch_create(struct libinput_device *libinput_device)
 {
@@ -1811,6 +1868,8 @@ fallback_dispatch_create(struct libinput_device 
*libinput_device)
                return NULL;
        }
 
+       fallback_dispatch_init_switch(dispatch, device);
+
        if (device->left_handed.want_enabled)
                evdev_init_left_handed(device,
                                       evdev_change_to_left_handed);
@@ -3149,6 +3208,9 @@ evdev_device_has_switch(struct evdev_device *device,
        case LIBINPUT_SWITCH_LID:
                code = SW_LID;
                break;
+       case LIBINPUT_SWITCH_RF_DISABLED:
+               code = SW_RFKILL_ALL;
+               break;
        default:
                return -1;
        }
diff --git a/src/evdev.h b/src/evdev.h
index 4a5f2ec..8366f4a 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -358,6 +358,10 @@ struct fallback_dispatch {
 
        struct device_coords rel;
 
+       struct {
+               int rfkill_all_state;
+       } sw;
+
        /* Bitmask of pressed keys used to ignore initial release events from
         * the kernel. */
        unsigned long hw_key_mask[NLONGS(KEY_CNT)];
diff --git a/src/libinput.h b/src/libinput.h
index 088949b..a944f0c 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -624,6 +624,21 @@ enum libinput_switch {
         * LIBINPUT_SWITCH_STATE_OFF.
         */
        LIBINPUT_SWITCH_LID = 1,
+
+       /**
+        * All wireless devices on this system should be disabled when the
+        * switch state is in @ref LIBINPUT_SWITCH_STATE_ON, or should be
+        * enabled when in @ref LIBINPUT_SWITCH_STATE_OFF.
+        *
+        * This switch only represents the physical switch on the system, it
+        * does not define how other devices react to a toggling of the
+        * switch. On some systems, the hardware may change state
+        * automatically. It is up to the caller to
+        * a) identify any wireless devices on this system, and
+        * b) verify the state of these devices, and
+        * c) toggle the state to match the switch state (if required)
+        */
+       LIBINPUT_SWITCH_RF_DISABLED,
 };
 
 /**
diff --git a/test/Makefile.am b/test/Makefile.am
index 542d9d2..b4d2cec 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -54,6 +54,7 @@ liblitest_la_SOURCES = \
        litest-device-synaptics-st.c \
        litest-device-synaptics-t440.c \
        litest-device-synaptics-x1-carbon-3rd.c \
+       litest-device-thinkpad-extrabuttons.c \
        litest-device-trackpoint.c \
        litest-device-touch-screen.c \
        litest-device-touchscreen-fuzz.c \
diff --git a/test/litest-device-thinkpad-extrabuttons.c 
b/test/litest-device-thinkpad-extrabuttons.c
new file mode 100644
index 0000000..d5ff430
--- /dev/null
+++ b/test/litest-device-thinkpad-extrabuttons.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright © 2017 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "litest.h"
+#include "litest-int.h"
+
+static void litest_extrabuttons_setup(void)
+{
+       struct litest_device *d = 
litest_create_device(LITEST_THINKPAD_EXTRABUTTONS);
+       litest_set_current_device(d);
+}
+
+static struct input_id input_id = {
+       .bustype = 0x19,
+       .vendor = 0x17aa,
+       .product = 0x5054,
+};
+
+static int events[] = {
+       EV_KEY, KEY_MUTE,
+       EV_KEY, KEY_VOLUMEUP,
+       EV_KEY, KEY_VOLUMEDOWN,
+       EV_KEY, KEY_SCALE,
+       EV_KEY, KEY_SLEEP,
+       EV_KEY, KEY_FILE,
+       EV_KEY, KEY_PROG1,
+       EV_KEY, KEY_COFFEE,
+       EV_KEY, KEY_BACK,
+       EV_KEY, KEY_CONFIG,
+       EV_KEY, KEY_REFRESH,
+       EV_KEY, KEY_F20,
+       EV_KEY, KEY_F21,
+       EV_KEY, KEY_F24,
+       EV_KEY, KEY_SUSPEND,
+       EV_KEY, KEY_CAMERA,
+       EV_KEY, KEY_SEARCH,
+       EV_KEY, KEY_BRIGHTNESSDOWN,
+       EV_KEY, KEY_BRIGHTNESSUP,
+       EV_KEY, KEY_SWITCHVIDEOMODE,
+       EV_KEY, KEY_KBDILLUMTOGGLE,
+       EV_KEY, KEY_BATTERY,
+       EV_KEY, KEY_WLAN,
+       EV_KEY, KEY_UNKNOWN,
+       EV_KEY, KEY_ZOOM,
+       EV_KEY, KEY_FN_F1,
+       EV_KEY, KEY_FN_F10,
+       EV_KEY, KEY_FN_F11,
+       EV_KEY, KEY_VOICECOMMAND,
+       EV_KEY, KEY_BRIGHTNESS_MIN,
+
+       EV_SW, SW_RFKILL_ALL,
+
+       -1, -1,
+};
+
+struct litest_test_device litest_thinkpad_extrabuttons_device = {
+       .type = LITEST_THINKPAD_EXTRABUTTONS,
+       .features = LITEST_KEYS | LITEST_SWITCH,
+       .shortname = "thinkpad-extrabuttons",
+       .setup = litest_extrabuttons_setup,
+       .interface = NULL,
+
+       .name = "ThinkPad Extra Buttons",
+       .id = &input_id,
+       .events = events,
+       .absinfo = NULL,
+};
diff --git a/test/litest.c b/test/litest.c
index 413ee6e..048ab94 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -411,6 +411,7 @@ extern struct litest_test_device 
litest_mouse_wheel_tilt_device;
 extern struct litest_test_device litest_lid_switch_device;
 extern struct litest_test_device litest_lid_switch_surface3_device;
 extern struct litest_test_device litest_appletouch_device;
+extern struct litest_test_device litest_thinkpad_extrabuttons_device;
 
 struct litest_test_device* devices[] = {
        &litest_synaptics_clickpad_device,
@@ -476,6 +477,7 @@ struct litest_test_device* devices[] = {
        &litest_lid_switch_device,
        &litest_lid_switch_surface3_device,
        &litest_appletouch_device,
+       &litest_thinkpad_extrabuttons_device,
        NULL,
 };
 
@@ -2159,6 +2161,9 @@ litest_switch_action(struct litest_device *dev,
        case LIBINPUT_SWITCH_LID:
                code = SW_LID;
                break;
+       case LIBINPUT_SWITCH_RF_DISABLED:
+               code = SW_RFKILL_ALL;
+               break;
        default:
                litest_abort_msg("Invalid switch %d", sw);
                break;
diff --git a/test/litest.h b/test/litest.h
index c3c87f3..d1b9ebb 100644
--- a/test/litest.h
+++ b/test/litest.h
@@ -232,6 +232,7 @@ enum litest_device_type {
        LITEST_LID_SWITCH,
        LITEST_LID_SWITCH_SURFACE3,
        LITEST_APPLETOUCH,
+       LITEST_THINKPAD_EXTRABUTTONS,
 };
 
 enum litest_device_feature {
diff --git a/test/test-switch.c b/test/test-switch.c
index 3fbd244..0bf9daa 100644
--- a/test/test-switch.c
+++ b/test/test-switch.c
@@ -29,6 +29,20 @@
 #include "libinput-util.h"
 #include "litest.h"
 
+static inline bool
+switch_has_lid(struct litest_device *dev)
+{
+       return libinput_device_switch_has_switch(dev->libinput_device,
+                                                LIBINPUT_SWITCH_LID);
+}
+
+static inline bool
+switch_has_rfkill(struct litest_device *dev)
+{
+       return libinput_device_switch_has_switch(dev->libinput_device,
+                                                LIBINPUT_SWITCH_RF_DISABLED);
+}
+
 START_TEST(switch_has_lid_switch)
 {
        struct litest_device *dev = litest_current_device();
@@ -52,12 +66,32 @@ START_TEST(switch_has_cap)
 }
 END_TEST
 
+START_TEST(switch_has_rfkill_switch)
+{
+       struct litest_device *dev = litest_current_device();
+
+       if (!libevdev_has_event_code(dev->evdev, EV_SW, SW_RFKILL_ALL))
+               return;
+
+       ck_assert_int_eq(libinput_device_switch_has_switch(dev->libinput_device,
+                                                          
LIBINPUT_SWITCH_RF_DISABLED),
+                        1);
+}
+END_TEST
+
 START_TEST(switch_toggle)
 {
        struct litest_device *dev = litest_current_device();
        struct libinput *li = dev->libinput;
        struct libinput_event *event;
-       enum libinput_switch sw = LIBINPUT_SWITCH_LID;
+       enum libinput_switch sw;
+
+       if (switch_has_lid(dev))
+               sw = LIBINPUT_SWITCH_LID;
+       else if (switch_has_rfkill(dev))
+               sw = LIBINPUT_SWITCH_RF_DISABLED;
+       else
+               litest_abort_msg("Missing switch for test");
 
        litest_drain_events(li);
 
@@ -84,7 +118,14 @@ START_TEST(switch_toggle_double)
        struct litest_device *dev = litest_current_device();
        struct libinput *li = dev->libinput;
        struct libinput_event *event;
-       enum libinput_switch sw = LIBINPUT_SWITCH_LID;
+       enum libinput_switch sw;
+
+       if (switch_has_lid(dev))
+               sw = LIBINPUT_SWITCH_LID;
+       else if (switch_has_rfkill(dev))
+               sw = LIBINPUT_SWITCH_RF_DISABLED;
+       else
+               litest_abort_msg("Missing switch for test");
 
        litest_drain_events(li);
 
@@ -128,8 +169,15 @@ START_TEST(switch_down_on_init)
        struct libinput_event *event;
        enum libinput_switch sw = LIBINPUT_SWITCH_LID;
 
-       if (!lid_switch_is_reliable(dev))
-               return;
+       if (switch_has_lid(dev)) {
+               sw = LIBINPUT_SWITCH_LID;
+               if (!lid_switch_is_reliable(dev))
+                       return;
+       } else if (switch_has_rfkill(dev)) {
+               sw = LIBINPUT_SWITCH_RF_DISABLED;
+       } else {
+               litest_abort_msg("Missing switch for test");
+       }
 
        litest_switch_action(dev, sw, LIBINPUT_SWITCH_STATE_ON);
 
@@ -169,8 +217,15 @@ START_TEST(switch_not_down_on_init)
        struct libinput_event *event;
        enum libinput_switch sw = LIBINPUT_SWITCH_LID;
 
-       if (lid_switch_is_reliable(dev))
+       if (switch_has_lid(dev)) {
+               sw = LIBINPUT_SWITCH_LID;
+               if (lid_switch_is_reliable(dev))
+                       return;
+       } else if (switch_has_rfkill(dev)) {
                return;
+       } else {
+               litest_abort_msg("Missing switch for test");
+       }
 
        litest_switch_action(dev, sw, LIBINPUT_SWITCH_STATE_ON);
 
@@ -206,6 +261,9 @@ START_TEST(lid_disable_touchpad)
        struct litest_device *touchpad;
        struct libinput *li = sw->libinput;
 
+       if (!switch_has_lid(sw))
+               return;
+
        touchpad = lid_init_paired_touchpad(li);
        litest_disable_tap(touchpad->libinput_device);
        litest_drain_events(li);
@@ -242,6 +300,9 @@ START_TEST(lid_disable_touchpad_during_touch)
        struct litest_device *touchpad;
        struct libinput *li = sw->libinput;
 
+       if (!switch_has_lid(sw))
+               return;
+
        touchpad = lid_init_paired_touchpad(li);
        litest_disable_tap(touchpad->libinput_device);
        litest_drain_events(li);
@@ -269,6 +330,9 @@ START_TEST(lid_disable_touchpad_edge_scroll)
        struct litest_device *touchpad;
        struct libinput *li = sw->libinput;
 
+       if (!switch_has_lid(sw))
+               return;
+
        touchpad = lid_init_paired_touchpad(li);
        litest_enable_edge_scroll(touchpad);
 
@@ -305,6 +369,9 @@ START_TEST(lid_disable_touchpad_edge_scroll_interrupt)
        struct libinput *li = sw->libinput;
        struct libinput_event *event;
 
+       if (!switch_has_lid(sw))
+               return;
+
        touchpad = lid_init_paired_touchpad(li);
        litest_enable_edge_scroll(touchpad);
 
@@ -344,6 +411,9 @@ START_TEST(lid_disable_touchpad_already_open)
        struct litest_device *touchpad;
        struct libinput *li = sw->libinput;
 
+       if (!switch_has_lid(sw))
+               return;
+
        touchpad = lid_init_paired_touchpad(li);
        litest_disable_tap(touchpad->libinput_device);
        litest_drain_events(li);
@@ -376,6 +446,9 @@ START_TEST(lid_open_on_key)
        struct libinput *li = sw->libinput;
        struct libinput_event *event;
 
+       if (!switch_has_lid(sw))
+               return;
+
        keyboard = litest_add_device(li, LITEST_KEYBOARD);
 
        litest_switch_action(sw,
@@ -413,6 +486,9 @@ START_TEST(lid_open_on_key_touchpad_enabled)
        struct litest_device *keyboard, *touchpad;
        struct libinput *li = sw->libinput;
 
+       if (!switch_has_lid(sw))
+               return;
+
        keyboard = litest_add_device(li, LITEST_KEYBOARD);
        touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C);
 
@@ -448,6 +524,9 @@ START_TEST(lid_update_hw_on_key)
        struct litest_device *keyboard;
        struct libinput_event *event;
 
+       if (!switch_has_lid(sw))
+               return;
+
        sleep(5);
        keyboard = litest_add_device(li, LITEST_KEYBOARD);
 
@@ -492,6 +571,7 @@ void
 litest_setup_tests_lid(void)
 {
        litest_add("switch:has", switch_has_lid_switch, LITEST_SWITCH, 
LITEST_ANY);
+       litest_add("switch:has", switch_has_rfkill_switch, LITEST_SWITCH, 
LITEST_ANY);
        litest_add("switch:has", switch_has_cap, LITEST_SWITCH, LITEST_ANY);
        litest_add("switch:toggle", switch_toggle, LITEST_SWITCH, LITEST_ANY);
        litest_add("switch:toggle", switch_toggle_double, LITEST_SWITCH, 
LITEST_ANY);
-- 
2.9.3

_______________________________________________
wayland-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to