Add support for EV_SW

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
This commit is contained in:
Peter Hutterer 2013-08-14 19:52:25 +10:00
parent 8b435a8534
commit b20becc942
3 changed files with 108 additions and 0 deletions

View 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 */

View 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;

View 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");