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

Peter Hutterer peter.hutterer at who-t.net
Wed Aug 14 18:43:23 PDT 2013


On Wed, Aug 14, 2013 at 04:56:09PM +0200, Benjamin Tissoires wrote:
> 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.

ftr, the reason I made a specific API here is that the LED case is a
relatively common one. You could write switch states, etc. but really I
don't think that's as common a use-case. The generic version of this would
essentially be a libevdev_kernel_set_event_value(). But at least for now, I
don't see the common need for this.

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

thanks

Cheers,
   Peter

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