[PATCH libevdev 5/7] Add functions to toggle LEDs on the device

Benjamin Tissoires benjamin.tissoires at gmail.com
Wed Aug 14 07:56:09 PDT 2013


On Wed, Aug 14, 2013 at 2:50 AM, Peter Hutterer
<peter.hutterer at who-t.net> wrote:
> Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> ---

It looks to me that this should not be specific to LEDs. However, I
can not manage to find another use case which would use to write on a
input node, besides the LED one.

So,
Reviewed-by: Benjamin Tissoires <benjamin.tissoires at gmail.com>

Cheers,
Benjamin

>  libevdev/libevdev.c            |  59 ++++++++++++++++
>  libevdev/libevdev.h            |  46 +++++++++++++
>  test/test-libevdev-has-event.c | 153 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 258 insertions(+)
>
> diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c
> index bd0c58c..25d33e7 100644
> --- a/libevdev/libevdev.c
> +++ b/libevdev/libevdev.c
> @@ -1179,3 +1179,62 @@ libevdev_get_repeat(struct libevdev *dev, int *delay, int *period)
>
>         return 0;
>  }
> +
> +int
> +libevdev_kernel_set_led_value(struct libevdev *dev, unsigned int code, enum EvdevLEDValues value)
> +{
> +       return libevdev_kernel_set_led_values(dev, code, value, -1);
> +}
> +
> +int
> +libevdev_kernel_set_led_values(struct libevdev *dev, ...)
> +{
> +       struct input_event ev[LED_MAX];
> +       enum EvdevLEDValues val;
> +       va_list args;
> +       int code;
> +       int rc = 0;
> +       size_t nleds = 0;
> +
> +       memset(ev, 0, sizeof(ev));
> +
> +       va_start(args, dev);
> +       code = va_arg(args, unsigned int);
> +       while (code != -1) {
> +               if (code > LED_MAX) {
> +                       rc = -EINVAL;
> +                       break;
> +               }
> +               val = va_arg(args, enum EvdevLEDValues);
> +               if (val != LIBEVDEV_LED_ON && val != LIBEVDEV_LED_OFF) {
> +                       rc = -EINVAL;
> +                       break;
> +               }
> +
> +               if (libevdev_has_event_code(dev, EV_LED, code)) {
> +                       struct input_event *e = ev;
> +
> +                       while (e->type > 0 && e->code != code)
> +                               e++;
> +
> +                       if (e->type == 0)
> +                               nleds++;
> +                       e->type = EV_LED;
> +                       e->code = code;
> +                       e->value = (val == LIBEVDEV_LED_ON);
> +               }
> +               code = va_arg(args, unsigned int);
> +       }
> +       va_end(args);
> +
> +       if (rc == 0 && nleds > 0) {
> +               rc = write(libevdev_get_fd(dev), ev, nleds * sizeof(ev[0]));
> +               if (rc > 0) {
> +                       while (nleds--)
> +                               update_led_state(dev, &ev[nleds]);
> +               }
> +               rc = (rc != -1) ? 0 : -errno;
> +       }
> +
> +       return rc;
> +}
> diff --git a/libevdev/libevdev.h b/libevdev/libevdev.h
> index 4c01847..db6a2ec 100644
> --- a/libevdev/libevdev.h
> +++ b/libevdev/libevdev.h
> @@ -1146,6 +1146,52 @@ int libevdev_disable_event_code(struct libevdev *dev, unsigned int type, unsigne
>   */
>  int libevdev_kernel_set_abs_info(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs);
>
> +
> +enum EvdevLEDValues {
> +       LIBEVDEV_LED_ON = 3,
> +       LIBEVDEV_LED_OFF = 4,
> +};
> +
> +/**
> + * @ingroup kernel
> + *
> + * Turn an LED on or off. Convenience function, if you need to modify multiple
> + * LEDs simultaneously, use libevdev_kernel_set_led_values() instead.
> + *
> + * @note enabling an LED requires write permissions on the device's file descriptor.
> + *
> + * @param dev The evdev device, already initialized with libevdev_set_fd()
> + * @param code The EV_LED event code to modify, one of LED_NUML, LED_CAPSL, ...
> + * @param value Specifies whether to turn the LED on or off
> + * @return zero on success, or a negative errno on failure
> + */
> +int libevdev_kernel_set_led_value(struct libevdev *dev, unsigned int code, enum EvdevLEDValues value);
> +
> +/**
> + * @ingroup kernel
> + *
> + * Turn multiple LEDs on or off simultaneously. This function expects a pair
> + * of LED codes and values to set them to, terminated by a -1. For example, to
> + * switch the NumLock LED on but the CapsLock LED off, use:
> + *
> + * @code
> + *     libevdev_kernel_set_led_values(dev, LED_NUML, LIBEVDEV_LED_ON,
> + *                                         LED_CAPSL, LIBEVDEV_LED_OFF,
> + *                                         -1);
> + * @endcode
> + *
> + * If any LED code or value is invalid, this function returns -EINVAL and no
> + * LEDs are modified.
> + *
> + * @note enabling an LED requires write permissions on the device's file descriptor.
> + *
> + * @param dev The evdev device, already initialized with libevdev_set_fd()
> + * @param ... A pair of LED_* event codes and enum EvdevLEDValues, followed by
> + * -1 to terminate the list.
> + * @return zero on success, or a negative errno on failure
> + */
> +int libevdev_kernel_set_led_values(struct libevdev *dev, ...);
> +
>  /**
>   * @ingroup misc
>   *
> diff --git a/test/test-libevdev-has-event.c b/test/test-libevdev-has-event.c
> index 307ea58..31a46ab 100644
> --- a/test/test-libevdev-has-event.c
> +++ b/test/test-libevdev-has-event.c
> @@ -923,6 +923,153 @@ START_TEST(test_device_kernel_change_axis_invalid)
>  }
>  END_TEST
>
> +START_TEST(test_led_valid)
> +{
> +       struct uinput_device* uidev;
> +       struct libevdev *dev;
> +       int rc;
> +
> +       rc = test_create_device(&uidev, &dev,
> +                               EV_LED, LED_NUML,
> +                               EV_LED, LED_CAPSL,
> +                               EV_LED, LED_COMPOSE,
> +                               -1);
> +       ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc));
> +
> +       rc = libevdev_kernel_set_led_value(dev, LED_NUML, LIBEVDEV_LED_ON);
> +       ck_assert_int_eq(rc, 0);
> +       rc = libevdev_kernel_set_led_value(dev, LED_NUML, LIBEVDEV_LED_OFF);
> +       ck_assert_int_eq(rc, 0);
> +
> +       rc = libevdev_kernel_set_led_values(dev,
> +                                           LED_NUML, LIBEVDEV_LED_OFF,
> +                                           LED_CAPSL, LIBEVDEV_LED_ON,
> +                                           LED_COMPOSE, LIBEVDEV_LED_OFF,
> +                                           -1);
> +       ck_assert_int_eq(rc, 0);
> +       ck_assert_int_eq(0, libevdev_get_event_value(dev, EV_LED, LED_NUML));
> +       ck_assert_int_eq(1, libevdev_get_event_value(dev, EV_LED, LED_CAPSL));
> +       ck_assert_int_eq(0, libevdev_get_event_value(dev, EV_LED, LED_COMPOSE));
> +
> +       rc = libevdev_kernel_set_led_values(dev,
> +                                           LED_NUML, LIBEVDEV_LED_ON,
> +                                           LED_CAPSL, LIBEVDEV_LED_OFF,
> +                                           LED_COMPOSE, LIBEVDEV_LED_ON,
> +                                           -1);
> +       ck_assert_int_eq(rc, 0);
> +       ck_assert_int_eq(1, libevdev_get_event_value(dev, EV_LED, LED_NUML));
> +       ck_assert_int_eq(0, libevdev_get_event_value(dev, EV_LED, LED_CAPSL));
> +       ck_assert_int_eq(1, libevdev_get_event_value(dev, EV_LED, LED_COMPOSE));
> +
> +       /* make sure we ignore unset leds */
> +       rc = libevdev_kernel_set_led_values(dev,
> +                                           LED_NUML, LIBEVDEV_LED_ON,
> +                                           LED_CAPSL, LIBEVDEV_LED_OFF,
> +                                           LED_SCROLLL, LIBEVDEV_LED_OFF,
> +                                           LED_COMPOSE, LIBEVDEV_LED_ON,
> +                                           -1);
> +       ck_assert_int_eq(rc, 0);
> +       ck_assert_int_eq(1, libevdev_get_event_value(dev, EV_LED, LED_NUML));
> +       ck_assert_int_eq(0, libevdev_get_event_value(dev, EV_LED, LED_CAPSL));
> +       ck_assert_int_eq(1, libevdev_get_event_value(dev, EV_LED, LED_COMPOSE));
> +
> +       libevdev_free(dev);
> +       uinput_device_free(uidev);
> +}
> +END_TEST
> +
> +START_TEST(test_led_invalid)
> +{
> +       struct uinput_device* uidev;
> +       struct libevdev *dev;
> +       int rc;
> +
> +       rc = test_create_device(&uidev, &dev,
> +                               EV_LED, LED_NUML,
> +                               EV_LED, LED_CAPSL,
> +                               EV_LED, LED_COMPOSE,
> +                               -1);
> +       ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc));
> +
> +       rc = libevdev_kernel_set_led_value(dev, LED_MAX + 1, LIBEVDEV_LED_ON);
> +       ck_assert_int_eq(rc, -EINVAL);
> +
> +       rc = libevdev_kernel_set_led_value(dev, LED_NUML, LIBEVDEV_LED_OFF + 1);
> +       ck_assert_int_eq(rc, -EINVAL);
> +
> +       rc = libevdev_kernel_set_led_value(dev, LED_SCROLLL, LIBEVDEV_LED_ON);
> +       ck_assert_int_eq(rc, 0);
> +
> +       rc = libevdev_kernel_set_led_values(dev,
> +                                           LED_NUML, LIBEVDEV_LED_OFF + 1,
> +                                           -1);
> +       ck_assert_int_eq(rc, -EINVAL);
> +
> +       rc = libevdev_kernel_set_led_values(dev,
> +                                           LED_MAX + 1, LIBEVDEV_LED_ON,
> +                                           LED_NUML, LIBEVDEV_LED_OFF + 1,
> +                                           -1);
> +       ck_assert_int_eq(rc, -EINVAL);
> +
> +       rc = libevdev_kernel_set_led_values(dev,
> +                                           LED_SCROLLL, LIBEVDEV_LED_OFF,
> +                                           -1);
> +       ck_assert_int_eq(rc, 0);
> +
> +       libevdev_free(dev);
> +       uinput_device_free(uidev);
> +}
> +END_TEST
> +
> +START_TEST(test_led_same)
> +{
> +       struct uinput_device* uidev;
> +       struct libevdev *dev;
> +       int rc;
> +
> +       rc = test_create_device(&uidev, &dev,
> +                               EV_LED, LED_NUML,
> +                               EV_LED, LED_CAPSL,
> +                               EV_LED, LED_COMPOSE,
> +                               -1);
> +       ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc));
> +
> +       rc = libevdev_kernel_set_led_values(dev,
> +                                           LED_NUML, LIBEVDEV_LED_OFF,
> +                                           LED_NUML, LIBEVDEV_LED_ON,
> +                                           LED_NUML, LIBEVDEV_LED_OFF,
> +                                           LED_NUML, LIBEVDEV_LED_ON,
> +                                           LED_NUML, LIBEVDEV_LED_OFF,
> +                                           LED_NUML, LIBEVDEV_LED_ON,
> +                                           LED_NUML, LIBEVDEV_LED_OFF,
> +                                           LED_NUML, LIBEVDEV_LED_ON,
> +                                           LED_NUML, LIBEVDEV_LED_OFF,
> +                                           LED_NUML, LIBEVDEV_LED_ON,
> +                                           LED_NUML, LIBEVDEV_LED_OFF,
> +                                           LED_NUML, LIBEVDEV_LED_ON,
> +                                           LED_NUML, LIBEVDEV_LED_OFF,
> +                                           LED_NUML, LIBEVDEV_LED_ON,
> +                                           LED_NUML, LIBEVDEV_LED_OFF,
> +                                           LED_NUML, LIBEVDEV_LED_ON,
> +                                           LED_NUML, LIBEVDEV_LED_OFF,
> +                                           LED_NUML, LIBEVDEV_LED_ON,
> +                                           LED_NUML, LIBEVDEV_LED_OFF,
> +                                           LED_NUML, LIBEVDEV_LED_ON,
> +                                           LED_NUML, LIBEVDEV_LED_OFF,
> +                                           LED_NUML, LIBEVDEV_LED_ON,
> +                                           LED_NUML, LIBEVDEV_LED_OFF,
> +                                           LED_NUML, LIBEVDEV_LED_ON,
> +                                           /* more than LED_CNT */
> +                                           -1);
> +       ck_assert_int_eq(rc, 0);
> +       ck_assert_int_eq(1, libevdev_get_event_value(dev, EV_LED, LED_NUML));
> +       ck_assert_int_eq(0, libevdev_get_event_value(dev, EV_LED, LED_CAPSL));
> +       ck_assert_int_eq(0, libevdev_get_event_value(dev, EV_LED, LED_COMPOSE));
> +
> +       libevdev_free(dev);
> +       uinput_device_free(uidev);
> +}
> +END_TEST
>  Suite *
>  libevdev_has_event_test(void)
>  {
> @@ -971,6 +1118,12 @@ libevdev_has_event_test(void)
>         tcase_add_test(tc, test_device_kernel_change_axis_invalid);
>         suite_add_tcase(s, tc);
>
> +       tc = tcase_create("led manipulation");
> +       tcase_add_test(tc, test_led_valid);
> +       tcase_add_test(tc, test_led_invalid);
> +       tcase_add_test(tc, test_led_same);
> +       suite_add_tcase(s, tc);
> +
>         return s;
>  }
>
> --
> 1.8.2.1
>
> _______________________________________________
> Input-tools mailing list
> Input-tools at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/input-tools


More information about the Input-tools mailing list