Add support for EV_SW
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 14 Aug 2013 09:52:25 +0000 (19:52 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Thu, 29 Aug 2013 01:13:47 +0000 (11:13 +1000)
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
libevdev/libevdev-int.h
libevdev/libevdev.c
test/test-libevdev-events.c

index 28933ef88c5b114e88b896394d9a8392ddbd6af3..38375a5cbe4b9cd6e6595203f5c2a844c8b0bce0 100644 (file)
@@ -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 */
index b69259067a346acd0bdf4dc8bac7373e8522149f..c316e34ff2bcf7cebdd94e5251b69d6a3f7cfa9e 100644 (file)
@@ -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++)
@@ -324,6 +328,33 @@ out:
        return rc ? -errno : 0;
 }
 
+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)
 {
@@ -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))
@@ -554,6 +587,20 @@ update_led_state(struct libevdev *dev, const struct input_event *e)
        return 0;
 }
 
+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)
 {
@@ -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;
index 669de1266fd74ab7b07e4b9eba34127f20e75224..046f9573473d8ee15fb4e1f83790f262d4f95702 100644 (file)
@@ -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");