From b20becc9426f74201041f4b7d77113d3c7d9033e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 14 Aug 2013 19:52:25 +1000 Subject: [PATCH] Add support for EV_SW Signed-off-by: Peter Hutterer Reviewed-by: Benjamin Tissoires --- libevdev/libevdev-int.h | 1 + libevdev/libevdev.c | 52 ++++++++++++++++++++++++++++++++++++++++++ test/test-libevdev-events.c | 55 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) diff --git a/libevdev/libevdev-int.h b/libevdev/libevdev-int.h index 28933ef..38375a5 100644 --- a/libevdev/libevdev-int.h +++ b/libevdev/libevdev-int.h @@ -90,6 +90,7 @@ struct libevdev { unsigned long snd_bits[NLONGS(SND_CNT)]; unsigned long key_values[NLONGS(KEY_CNT)]; unsigned long led_values[NLONGS(LED_CNT)]; + unsigned long sw_values[NLONGS(SW_CNT)]; struct input_absinfo abs_info[ABS_CNT]; unsigned int mt_slot_vals[MAX_SLOTS][ABS_MT_CNT]; int num_slots; /**< valid slots in mt_slot_vals */ diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c index b692590..c316e34 100644 --- a/libevdev/libevdev.c +++ b/libevdev/libevdev.c @@ -239,6 +239,10 @@ libevdev_set_fd(struct libevdev* dev, int fd) if (rc < 0) goto out; + rc = ioctl(fd, EVIOCGSW(sizeof(dev->sw_values)), dev->sw_values); + if (rc < 0) + goto out; + /* rep is a special case, always set it to 1 for both values if EV_REP is set */ if (bit_is_set(dev->bits, EV_REP)) { for (i = 0; i < REP_CNT; i++) @@ -325,6 +329,33 @@ out: } static int +sync_sw_state(struct libevdev *dev) +{ + int rc; + int i; + unsigned long swstate[NLONGS(SW_CNT)]; + + rc = ioctl(dev->fd, EVIOCGSW(sizeof(swstate)), swstate); + if (rc < 0) + goto out; + + for (i = 0; i < SW_CNT; i++) { + int old, new; + old = bit_is_set(dev->sw_values, i); + new = bit_is_set(swstate, i); + if (old ^ new) { + struct input_event *ev = queue_push(dev); + init_event(dev, ev, EV_SW, i, new ? 1 : 0); + } + set_bit_state(dev->sw_values, i, new); + } + + rc = 0; +out: + return rc ? -errno : 0; +} + +static int sync_led_state(struct libevdev *dev) { int rc; @@ -472,6 +503,8 @@ sync_state(struct libevdev *dev) rc = sync_key_state(dev); if (libevdev_has_event_type(dev, EV_LED)) rc = sync_led_state(dev); + if (libevdev_has_event_type(dev, EV_SW)) + rc = sync_sw_state(dev); if (rc == 0 && libevdev_has_event_type(dev, EV_ABS)) rc = sync_abs_state(dev); if (rc == 0 && libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT)) @@ -555,6 +588,20 @@ update_led_state(struct libevdev *dev, const struct input_event *e) } static int +update_sw_state(struct libevdev *dev, const struct input_event *e) +{ + if (!libevdev_has_event_type(dev, EV_SW)) + return 1; + + if (e->code > SW_MAX) + return 1; + + set_bit_state(dev->sw_values, e->code, e->value != 0); + + return 0; +} + +static int update_state(struct libevdev *dev, const struct input_event *e) { int rc = 0; @@ -572,6 +619,9 @@ update_state(struct libevdev *dev, const struct input_event *e) case EV_LED: rc = update_led_state(dev, e); break; + case EV_SW: + rc = update_sw_state(dev, e); + break; } dev->last_event_time = e->time; @@ -821,6 +871,7 @@ libevdev_get_event_value(const struct libevdev *dev, unsigned int type, unsigned case EV_ABS: value = dev->abs_info[code].value; break; case EV_KEY: value = bit_is_set(dev->key_values, code); break; case EV_LED: value = bit_is_set(dev->led_values, code); break; + case EV_SW: value = bit_is_set(dev->sw_values, code); break; default: value = 0; break; @@ -845,6 +896,7 @@ int libevdev_set_event_value(struct libevdev *dev, unsigned int type, unsigned i case EV_ABS: rc = update_abs_state(dev, &e); break; case EV_KEY: rc = update_key_state(dev, &e); break; case EV_LED: rc = update_led_state(dev, &e); break; + case EV_SW: rc = update_sw_state(dev, &e); break; default: rc = -1; break; diff --git a/test/test-libevdev-events.c b/test/test-libevdev-events.c index 669de12..046f957 100644 --- a/test/test-libevdev-events.c +++ b/test/test-libevdev-events.c @@ -499,6 +499,52 @@ START_TEST(test_syn_delta_led) } END_TEST +START_TEST(test_syn_delta_sw) +{ + struct uinput_device* uidev; + struct libevdev *dev; + int rc; + struct input_event ev; + + rc = test_create_device(&uidev, &dev, + EV_SYN, SYN_REPORT, + EV_SYN, SYN_DROPPED, + EV_SW, SW_LID, + EV_SW, SW_MICROPHONE_INSERT, + -1); + ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc)); + + uinput_device_event(uidev, EV_SW, SW_LID, 1); + uinput_device_event(uidev, EV_SW, SW_MICROPHONE_INSERT, 1); + uinput_device_event(uidev, EV_SYN, SYN_REPORT, 0); + rc = libevdev_next_event(dev, LIBEVDEV_FORCE_SYNC, &ev); + ck_assert_int_eq(rc, 1); + + rc = libevdev_next_event(dev, LIBEVDEV_READ_SYNC, &ev); + ck_assert_int_eq(rc, 1); + ck_assert_int_eq(ev.type, EV_SW); + ck_assert_int_eq(ev.code, SW_LID); + ck_assert_int_eq(ev.value, 1); + rc = libevdev_next_event(dev, LIBEVDEV_READ_SYNC, &ev); + ck_assert_int_eq(rc, 1); + ck_assert_int_eq(ev.type, EV_SW); + ck_assert_int_eq(ev.code, SW_MICROPHONE_INSERT); + ck_assert_int_eq(ev.value, 1); + rc = libevdev_next_event(dev, LIBEVDEV_READ_SYNC, &ev); + ck_assert_int_eq(rc, 1); + ck_assert_int_eq(ev.type, EV_SYN); + ck_assert_int_eq(ev.code, SYN_REPORT); + rc = libevdev_next_event(dev, LIBEVDEV_READ_SYNC, &ev); + ck_assert_int_eq(rc, -EAGAIN); + + ck_assert_int_eq(libevdev_get_event_value(dev, EV_SW, SW_LID), 1); + ck_assert_int_eq(libevdev_get_event_value(dev, EV_SW, SW_MICROPHONE_INSERT), 1); + + uinput_device_free(uidev); + libevdev_free(dev); +} +END_TEST + START_TEST(test_skipped_sync) { struct uinput_device* uidev; @@ -876,6 +922,8 @@ START_TEST(test_event_value_setters) EV_KEY, BTN_RIGHT, EV_LED, LED_NUML, EV_LED, LED_CAPSL, + EV_SW, SW_LID, + EV_SW, SW_TABLET_MODE, -1); ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc)); @@ -903,6 +951,12 @@ START_TEST(test_event_value_setters) ck_assert_int_eq(libevdev_get_event_value(dev, EV_LED, LED_NUML), 1); ck_assert_int_eq(libevdev_get_event_value(dev, EV_LED, LED_CAPSL), 1); + ck_assert_int_eq(libevdev_set_event_value(dev, EV_SW, SW_LID, 1), 0); + ck_assert_int_eq(libevdev_set_event_value(dev, EV_SW, SW_TABLET_MODE, 1), 0); + + ck_assert_int_eq(libevdev_get_event_value(dev, EV_SW, SW_LID), 1); + ck_assert_int_eq(libevdev_get_event_value(dev, EV_SW, SW_TABLET_MODE), 1); + uinput_device_free(uidev); libevdev_free(dev); @@ -1104,6 +1158,7 @@ libevdev_events(void) tcase_add_test(tc, test_syn_delta_abs); tcase_add_test(tc, test_syn_delta_mt); tcase_add_test(tc, test_syn_delta_led); + tcase_add_test(tc, test_syn_delta_sw); suite_add_tcase(s, tc); tc = tcase_create("skipped syncs"); -- 2.7.4