Skip to content

Commit

Permalink
lid: force the lid to open when the keyboard device is removed
Browse files Browse the repository at this point in the history
On unreliable tablets (Surface3), always force the lid switch to open when the
paired keyboard is removed. This way the lid can't be stuck in a closed state
when there's nothing attached that can actually trigger that state.

https://bugs.freedesktop.org/show_bug.cgi?id=101100

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
  • Loading branch information
whot committed May 23, 2017
1 parent 8fbdef3 commit d35d122
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 11 deletions.
34 changes: 23 additions & 11 deletions src/evdev-lid.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,23 @@ lid_switch_notify_toggle(struct lid_switch_dispatch *dispatch,
}
}

static void
lid_switch_update_kernel_state(struct lid_switch_dispatch *dispatch,
uint64_t time)
{
int fd;
const struct input_event ev[2] = {
{{ 0, 0 }, EV_SW, SW_LID, 0 },
{{ 0, 0 }, EV_SYN, SYN_REPORT, 0 },
};

if (dispatch->reliability != RELIABILITY_WRITE_OPEN)
return;

fd = libevdev_get_fd(dispatch->device->evdev);
(void)write(fd, ev, sizeof(ev));
}

static void
lid_switch_keyboard_event(uint64_t time,
struct libinput_event *event,
Expand All @@ -77,17 +94,7 @@ lid_switch_keyboard_event(uint64_t time,
if (event->type != LIBINPUT_EVENT_KEYBOARD_KEY)
return;

if (dispatch->reliability == RELIABILITY_WRITE_OPEN) {
int fd = libevdev_get_fd(dispatch->device->evdev);
struct input_event ev[2] = {
{{ 0, 0 }, EV_SW, SW_LID, 0 },
{{ 0, 0 }, EV_SYN, SYN_REPORT, 0 },
};

(void)write(fd, ev, sizeof(ev));
/* In case write() fails, we sync the lid state manually
* regardless. */
}
lid_switch_update_kernel_state(dispatch, time);

/* Posting the event here means we preempt the keyboard events that
* caused us to wake up, so the lid event is always passed on before
Expand Down Expand Up @@ -246,11 +253,16 @@ lid_switch_interface_device_removed(struct evdev_device *device,
struct lid_switch_dispatch *dispatch = lid_dispatch(device->dispatch);

if (removed_device == dispatch->keyboard.keyboard) {
uint64_t time;

libinput_device_remove_event_listener(
&dispatch->keyboard.listener);
libinput_device_init_event_listener(
&dispatch->keyboard.listener);
dispatch->keyboard.keyboard = NULL;

time = libinput_now(evdev_libinput_context(device));
lid_switch_update_kernel_state(dispatch, time);
}
}

Expand Down
36 changes: 36 additions & 0 deletions test/test-lid.c
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,41 @@ START_TEST(lid_update_hw_on_key_closed_on_init)
}
END_TEST

START_TEST(lid_force_open_if_no_keyboard)
{
struct litest_device *sw = litest_current_device();
struct libinput *li;
struct litest_device *keyboard;

litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
keyboard = litest_add_device(sw->libinput, LITEST_KEYBOARD);

/* separate context for the right state on init */
li = litest_create_context();
libinput_path_add_device(li,
libevdev_uinput_get_devnode(sw->uinput));

/* We only have the switch device in this context, not the keyboard.
* So don't expect any switch event to be in the pipe and don't
* expect the event to change if we type or toggle the state
*/
while (libinput_next_event_type(li) != LIBINPUT_EVENT_NONE) {
ck_assert_int_ne(libinput_next_event_type(li),
LIBINPUT_EVENT_SWITCH_TOGGLE);
libinput_event_destroy(libinput_get_event(li));
}

litest_event(keyboard, EV_KEY, KEY_A, 1);
litest_event(keyboard, EV_SYN, SYN_REPORT, 0);
litest_event(keyboard, EV_KEY, KEY_A, 0);
litest_event(keyboard, EV_SYN, SYN_REPORT, 0);
litest_lid_action(sw, LIBINPUT_SWITCH_STATE_OFF);
litest_assert_empty_queue(li);

libinput_unref(li);
litest_delete_device(keyboard);
}
END_TEST
void
litest_setup_tests_lid(void)
{
Expand All @@ -576,4 +611,5 @@ litest_setup_tests_lid(void)

litest_add_for_device("lid:buggy", lid_update_hw_on_key, LITEST_LID_SWITCH_SURFACE3);
litest_add_for_device("lid:buggy", lid_update_hw_on_key_closed_on_init, LITEST_LID_SWITCH_SURFACE3);
litest_add_for_device("lid:buggy", lid_force_open_if_no_keyboard, LITEST_LID_SWITCH_SURFACE3);
}

0 comments on commit d35d122

Please sign in to comment.