lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Sun, 6 Apr 2014 12:02:23 +0200
From:	Pali Rohár <pali.rohar@...il.com>
To:	Samuel Thibault <samuel.thibault@...-lyon.org>,
	Dmitry Torokhov <dmitry.torokhov@...il.com>,
	Pavel Machek <pavel@....cz>,
	David Herrmann <dh.herrmann@...il.com>,
	Andrew Morton <akpm@...ux-foundation.org>, jslaby@...e.cz,
	Bryan Wu <cooloney@...il.com>,
	Richard Purdie <rpurdie@...ys.net>,
	LKML <linux-kernel@...r.kernel.org>,
	Evan Broder <evan@...oder.net>,
	Arnaud Patard <arnaud.patard@...-net.org>,
	Peter Korsgaard <jacmet@...site.dk>,
	Sascha Hauer <s.hauer@...gutronix.de>,
	Rob Clark <robdclark@...il.com>,
	Niels de Vos <devos@...oraproject.org>,
	linux-arm-kernel@...ts.infradead.org, blogic@...nwrt.org,
	Pali Rohár <pali.rohar@...il.com>,
	linux-input <linux-input@...r.kernel.org>,
	Sebastian Reichel <sre@...g0.de>
Subject: Re: [PATCH] INPUT: Route keyboard LEDs through the generic LEDs layer.

2014-04-01 9:02 GMT+02:00 Pali Rohár <pali.rohar@...il.com>:
> 2014-03-31 14:23 GMT+02:00 Samuel Thibault <samuel.thibault@...-lyon.org>:
>> This permits to reassign keyboard LEDs to something else than keyboard "leds"
>> state, by adding keyboard led and modifier triggers connected to a series
>> of VT input LEDs, themselves connected to VT input triggers, which
>> per-input device LEDs use by default.  Userland can thus easily change the LED
>> behavior of (a priori) all input devices, or of particular input devices.
>>
>> This also permits to fix #7063 from userland by using a modifier to implement
>> proper CapsLock behavior and have the keyboard caps lock led show that modifier
>> state.
>>
>> [ebroder@...afive.com: Rebased to 3.2-rc1 or so, cleaned up some includes, and fixed some constants]
>> [blogic@...nwrt.org: CONFIG_INPUT_LEDS stubs should be static inline]
>> [akpm@...ux-foundation.org: remove unneeded `extern', fix comment layout]
>> Signed-off-by: Samuel Thibault <samuel.thibault@...-lyon.org>
>> Signed-off-by: Evan Broder <evan@...oder.net>
>> Reviewed-by: David Herrmann <dh.herrmann@...il.com>
>> Tested-by: Pavel Machek <pavel@....cz>
>> Acked-by: Peter Korsgaard <jacmet@...site.dk>
>> Signed-off-by: John Crispin <blogic@...nwrt.org>
>> Signed-off-by: Andrew Morton <akpm@...ux-foundation.org>
>> ---
>> Changed in this version:
>> - fixes symbol dependencies between input.c and leds.c (notably
>>   input_led_connect/disconnect) by stuffing them together in input.ko.
>> - documents the new leds field of struct input_dev.
>>
>> --- a/Documentation/leds/leds-class.txt
>> +++ b/Documentation/leds/leds-class.txt
>> @@ -2,9 +2,6 @@
>>  LED handling under Linux
>>  ========================
>>
>> -If you're reading this and thinking about keyboard leds, these are
>> -handled by the input subsystem and the led class is *not* needed.
>> -
>>  In its simplest form, the LED class just allows control of LEDs from
>>  userspace. LEDs appear in /sys/class/leds/. The maximum brightness of the
>>  LED is defined in max_brightness file. The brightness file will set the brightness
>> --- a/drivers/input/input.c
>> +++ b/drivers/input/input.c
>> @@ -708,6 +708,9 @@ static void input_disconnect_device(stru
>>                 handle->open = 0;
>>
>>         spin_unlock_irq(&dev->event_lock);
>> +
>> +       if (is_event_supported(EV_LED, dev->evbit, EV_MAX))
>> +               input_led_disconnect(dev);
>>  }
>>
>>  /**
>> @@ -2134,6 +2137,9 @@ int input_register_device(struct input_d
>>
>>         list_add_tail(&dev->node, &input_dev_list);
>>
>> +       if (is_event_supported(EV_LED, dev->evbit, EV_MAX))
>> +               input_led_connect(dev);
>> +
>>         list_for_each_entry(handler, &input_handler_list, node)
>>                 input_attach_handler(dev, handler);
>>
>> --- a/drivers/input/Kconfig
>> +++ b/drivers/input/Kconfig
>> @@ -178,6 +178,15 @@ comment "Input Device Drivers"
>>
>>  source "drivers/input/keyboard/Kconfig"
>>
>> +config INPUT_LEDS
>> +       bool "LED Support"
>> +       depends on LEDS_CLASS = INPUT || LEDS_CLASS = y
>> +       select LEDS_TRIGGERS
>> +       default y
>> +       help
>> +         This option enables support for LEDs on keyboards managed
>> +         by the input layer.
>> +
>>  source "drivers/input/mouse/Kconfig"
>>
>>  source "drivers/input/joystick/Kconfig"
>> --- a/drivers/input/Makefile
>> +++ b/drivers/input/Makefile
>> @@ -6,6 +6,9 @@
>>
>>  obj-$(CONFIG_INPUT)            += input-core.o
>>  input-core-y := input.o input-compat.o input-mt.o ff-core.o
>> +ifeq ($(CONFIG_INPUT_LEDS),y)
>> +input-core-y += leds.o
>> +endif
>>
>>  obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
>>  obj-$(CONFIG_INPUT_POLLDEV)    += input-polldev.o
>> --- a/drivers/leds/Kconfig
>> +++ b/drivers/leds/Kconfig
>> @@ -11,9 +11,6 @@ menuconfig NEW_LEDS
>>           Say Y to enable Linux LED support.  This allows control of supported
>>           LEDs from both userspace and optionally, by kernel events (triggers).
>>
>> -         This is not related to standard keyboard LEDs which are controlled
>> -         via the input system.
>> -
>>  if NEW_LEDS
>>
>>  config LEDS_CLASS
>> --- a/drivers/tty/Kconfig
>> +++ b/drivers/tty/Kconfig
>> @@ -13,6 +13,10 @@ config VT
>>         bool "Virtual terminal" if EXPERT
>>         depends on !S390 && !UML
>>         select INPUT
>> +       select NEW_LEDS
>> +       select LEDS_CLASS
>> +       select LEDS_TRIGGERS
>> +       select INPUT_LEDS
>>         default y
>>         ---help---
>>           If you say Y here, you will get support for terminal devices with
>> --- a/drivers/tty/vt/keyboard.c
>> +++ b/drivers/tty/vt/keyboard.c
>> @@ -33,6 +33,7 @@
>>  #include <linux/string.h>
>>  #include <linux/init.h>
>>  #include <linux/slab.h>
>> +#include <linux/leds.h>
>>
>>  #include <linux/kbd_kern.h>
>>  #include <linux/kbd_diacr.h>
>> @@ -130,6 +131,7 @@ static char rep;                                    /* flag telling cha
>>  static int shift_state = 0;
>>
>>  static unsigned char ledstate = 0xff;                  /* undefined */
>> +static unsigned char lockstate = 0xff;                 /* undefined */
>>  static unsigned char ledioctl;
>>
>>  /*
>> @@ -961,6 +963,41 @@ static void k_brl(struct vc_data *vc, un
>>         }
>>  }
>>
>> +/* We route VT keyboard "leds" through triggers */
>> +static void kbd_ledstate_trigger_activate(struct led_classdev *cdev);
>> +
>> +static struct led_trigger ledtrig_ledstate[] = {
>> +#define DEFINE_LEDSTATE_TRIGGER(kbd_led, nam) \
>> +       [kbd_led] = { \
>> +               .name = nam, \
>> +               .activate = kbd_ledstate_trigger_activate, \
>> +       }
>> +       DEFINE_LEDSTATE_TRIGGER(VC_SCROLLOCK, "kbd-scrollock"),
>> +       DEFINE_LEDSTATE_TRIGGER(VC_NUMLOCK,   "kbd-numlock"),
>> +       DEFINE_LEDSTATE_TRIGGER(VC_CAPSLOCK,  "kbd-capslock"),
>> +       DEFINE_LEDSTATE_TRIGGER(VC_KANALOCK,  "kbd-kanalock"),
>> +#undef DEFINE_LEDSTATE_TRIGGER
>> +};
>> +
>> +static void kbd_lockstate_trigger_activate(struct led_classdev *cdev);
>> +
>> +static struct led_trigger ledtrig_lockstate[] = {
>> +#define DEFINE_LOCKSTATE_TRIGGER(kbd_led, nam) \
>> +       [kbd_led] = { \
>> +               .name = nam, \
>> +               .activate = kbd_lockstate_trigger_activate, \
>> +       }
>> +       DEFINE_LOCKSTATE_TRIGGER(VC_SHIFTLOCK,  "kbd-shiftlock"),
>> +       DEFINE_LOCKSTATE_TRIGGER(VC_ALTGRLOCK,  "kbd-altgrlock"),
>> +       DEFINE_LOCKSTATE_TRIGGER(VC_CTRLLOCK,   "kbd-ctrllock"),
>> +       DEFINE_LOCKSTATE_TRIGGER(VC_ALTLOCK,    "kbd-altlock"),
>> +       DEFINE_LOCKSTATE_TRIGGER(VC_SHIFTLLOCK, "kbd-shiftllock"),
>> +       DEFINE_LOCKSTATE_TRIGGER(VC_SHIFTRLOCK, "kbd-shiftrlock"),
>> +       DEFINE_LOCKSTATE_TRIGGER(VC_CTRLLLOCK,  "kbd-ctrlllock"),
>> +       DEFINE_LOCKSTATE_TRIGGER(VC_CTRLRLOCK,  "kbd-ctrlrlock"),
>> +#undef DEFINE_LOCKSTATE_TRIGGER
>> +};
>> +
>>  /*
>>   * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
>>   * or (ii) whatever pattern of lights people want to show using KDSETLED,
>> @@ -995,18 +1032,25 @@ static inline unsigned char getleds(void
>>         return kbd->ledflagstate;
>>  }
>>
>> -static int kbd_update_leds_helper(struct input_handle *handle, void *data)
>> +/* Called on trigger connection, to set initial state */
>> +static void kbd_ledstate_trigger_activate(struct led_classdev *cdev)
>>  {
>> -       unsigned char leds = *(unsigned char *)data;
>> +       struct led_trigger *trigger = cdev->trigger;
>> +       int led = trigger - ledtrig_ledstate;
>>
>> -       if (test_bit(EV_LED, handle->dev->evbit)) {
>> -               input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
>> -               input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
>> -               input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
>> -               input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
>> -       }
>> +       tasklet_disable(&keyboard_tasklet);
>> +       led_trigger_event(trigger, ledstate & (1 << led) ? LED_FULL : LED_OFF);
>> +       tasklet_enable(&keyboard_tasklet);
>> +}
>>
>> -       return 0;
>> +static void kbd_lockstate_trigger_activate(struct led_classdev *cdev)
>> +{
>> +       struct led_trigger *trigger = cdev->trigger;
>> +       int led = trigger - ledtrig_lockstate;
>> +
>> +       tasklet_disable(&keyboard_tasklet);
>> +       led_trigger_event(trigger, lockstate & (1 << led) ? LED_FULL : LED_OFF);
>> +       tasklet_enable(&keyboard_tasklet);
>>  }
>>
>>  /**
>> @@ -1095,16 +1139,29 @@ static void kbd_bh(unsigned long dummy)
>>  {
>>         unsigned char leds;
>>         unsigned long flags;
>> -
>> +       int i;
>> +
>>         spin_lock_irqsave(&led_lock, flags);
>>         leds = getleds();
>>         spin_unlock_irqrestore(&led_lock, flags);
>>
>>         if (leds != ledstate) {
>> -               input_handler_for_each_handle(&kbd_handler, &leds,
>> -                                             kbd_update_leds_helper);
>> +               for (i = 0; i < ARRAY_SIZE(ledtrig_ledstate); i++)
>> +                       if ((leds ^ ledstate) & (1 << i))
>> +                               led_trigger_event(&ledtrig_ledstate[i],
>> +                                               leds & (1 << i)
>> +                                               ? LED_FULL : LED_OFF);
>>                 ledstate = leds;
>>         }
>> +
>> +       if (kbd->lockstate != lockstate) {
>> +               for (i = 0; i < ARRAY_SIZE(ledtrig_lockstate); i++)
>> +                       if ((kbd->lockstate ^ lockstate) & (1 << i))
>> +                               led_trigger_event(&ledtrig_lockstate[i],
>> +                                               kbd->lockstate & (1 << i)
>> +                                               ? LED_FULL : LED_OFF);
>> +               lockstate = kbd->lockstate;
>> +       }
>>  }
>>
>>  DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
>> @@ -1442,20 +1499,6 @@ static void kbd_disconnect(struct input_
>>         kfree(handle);
>>  }
>>
>> -/*
>> - * Start keyboard handler on the new keyboard by refreshing LED state to
>> - * match the rest of the system.
>> - */
>> -static void kbd_start(struct input_handle *handle)
>> -{
>> -       tasklet_disable(&keyboard_tasklet);
>> -
>> -       if (ledstate != 0xff)
>> -               kbd_update_leds_helper(handle, &ledstate);
>> -
>> -       tasklet_enable(&keyboard_tasklet);
>> -}
>> -
>>  static const struct input_device_id kbd_ids[] = {
>>         {
>>                 .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
>> @@ -1477,7 +1520,6 @@ static struct input_handler kbd_handler
>>         .match          = kbd_match,
>>         .connect        = kbd_connect,
>>         .disconnect     = kbd_disconnect,
>> -       .start          = kbd_start,
>>         .name           = "kbd",
>>         .id_table       = kbd_ids,
>>  };
>> @@ -1501,6 +1543,20 @@ int __init kbd_init(void)
>>         if (error)
>>                 return error;
>>
>> +       for (i = 0; i < ARRAY_SIZE(ledtrig_ledstate); i++) {
>> +               error = led_trigger_register(&ledtrig_ledstate[i]);
>> +               if (error)
>> +                       pr_err("error %d while registering trigger %s\n",
>> +                                       error, ledtrig_ledstate[i].name);
>> +       }
>> +
>> +       for (i = 0; i < ARRAY_SIZE(ledtrig_lockstate); i++) {
>> +               error = led_trigger_register(&ledtrig_lockstate[i]);
>> +               if (error)
>> +                       pr_err("error %d while registering trigger %s\n",
>> +                                       error, ledtrig_lockstate[i].name);
>> +       }
>> +
>>         tasklet_enable(&keyboard_tasklet);
>>         tasklet_schedule(&keyboard_tasklet);
>>
>> --- a/include/linux/input.h
>> +++ b/include/linux/input.h
>> @@ -79,6 +79,7 @@ struct input_value {
>>   * @led: reflects current state of device's LEDs
>>   * @snd: reflects current state of sound effects
>>   * @sw: reflects current state of device's switches
>> + * @leds: leds objects for the device's LEDs
>>   * @open: this method is called when the very first user calls
>>   *     input_open_device(). The driver must prepare the device
>>   *     to start generating events (start polling thread,
>> @@ -164,6 +165,8 @@ struct input_dev {
>>         unsigned long snd[BITS_TO_LONGS(SND_CNT)];
>>         unsigned long sw[BITS_TO_LONGS(SW_CNT)];
>>
>> +       struct led_classdev *leds;
>> +
>>         int (*open)(struct input_dev *dev);
>>         void (*close)(struct input_dev *dev);
>>         int (*flush)(struct input_dev *dev, struct file *file);
>> @@ -531,4 +534,22 @@ int input_ff_erase(struct input_dev *dev
>>  int input_ff_create_memless(struct input_dev *dev, void *data,
>>                 int (*play_effect)(struct input_dev *, void *, struct ff_effect *));
>>
>> +#ifdef CONFIG_INPUT_LEDS
>> +
>> +int input_led_connect(struct input_dev *dev);
>> +void input_led_disconnect(struct input_dev *dev);
>> +
>> +#else
>> +
>> +static inline int input_led_connect(struct input_dev *dev)
>> +{
>> +       return 0;
>> +}
>> +
>> +static inline void input_led_disconnect(struct input_dev *dev)
>> +{
>> +}
>> +
>> +#endif
>> +
>>  #endif
>> --- /dev/null
>> +++ b/drivers/input/leds.c
>> @@ -0,0 +1,249 @@
>> +/*
>> + * LED support for the input layer
>> + *
>> + * Copyright 2010-2014 Samuel Thibault <samuel.thibault@...-lyon.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/slab.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/leds.h>
>> +#include <linux/input.h>
>> +
>> +/*
>> + * Keyboard LEDs are propagated by default like the following example:
>> + *
>> + * VT keyboard numlock trigger
>> + * -> vt::numl VT LED
>> + * -> vt-numl VT trigger
>> + * -> per-device inputX::numl LED
>> + *
>> + * Userland can however choose the trigger for the vt::numl LED, or
>> + * independently choose the trigger for any inputx::numl LED.
>> + *
>> + *
>> + * VT LED classes and triggers are registered on-demand according to
>> + * existing LED devices
>> + */
>> +
>> +/* Handler for VT LEDs, just triggers the corresponding VT trigger. */
>> +static void vt_led_set(struct led_classdev *cdev,
>> +                         enum led_brightness brightness);
>> +static struct led_classdev vt_leds[LED_CNT] = {
>> +#define DEFINE_INPUT_LED(vt_led, nam, deftrig) \
>> +       [vt_led] = { \
>> +               .name = "vt::"nam, \
>> +               .max_brightness = 1, \
>> +               .brightness_set = vt_led_set, \
>> +               .default_trigger = deftrig, \
>> +       }
>> +/* Default triggers for the VT LEDs just correspond to the legacy
>> + * usage. */
>> +       DEFINE_INPUT_LED(LED_NUML, "numl", "kbd-numlock"),
>> +       DEFINE_INPUT_LED(LED_CAPSL, "capsl", "kbd-capslock"),
>> +       DEFINE_INPUT_LED(LED_SCROLLL, "scrolll", "kbd-scrollock"),
>> +       DEFINE_INPUT_LED(LED_COMPOSE, "compose", NULL),
>> +       DEFINE_INPUT_LED(LED_KANA, "kana", "kbd-kanalock"),
>> +       DEFINE_INPUT_LED(LED_SLEEP, "sleep", NULL),
>> +       DEFINE_INPUT_LED(LED_SUSPEND, "suspend", NULL),
>> +       DEFINE_INPUT_LED(LED_MUTE, "mute", NULL),
>> +       DEFINE_INPUT_LED(LED_MISC, "misc", NULL),
>> +       DEFINE_INPUT_LED(LED_MAIL, "mail", NULL),
>> +       DEFINE_INPUT_LED(LED_CHARGING, "charging", NULL),
>> +};
>> +static const char *const vt_led_names[LED_CNT] = {
>> +       [LED_NUML] = "numl",
>> +       [LED_CAPSL] = "capsl",
>> +       [LED_SCROLLL] = "scrolll",
>> +       [LED_COMPOSE] = "compose",
>> +       [LED_KANA] = "kana",
>> +       [LED_SLEEP] = "sleep",
>> +       [LED_SUSPEND] = "suspend",
>> +       [LED_MUTE] = "mute",
>> +       [LED_MISC] = "misc",
>> +       [LED_MAIL] = "mail",
>> +       [LED_CHARGING] = "charging",
>> +};
>> +/* Handler for hotplug initialization */
>> +static void vt_led_trigger_activate(struct led_classdev *cdev);
>> +/* VT triggers */
>> +static struct led_trigger vt_led_triggers[LED_CNT] = {
>> +#define DEFINE_INPUT_LED_TRIGGER(vt_led, nam) \
>> +       [vt_led] = { \
>> +               .name = "vt-"nam, \
>> +               .activate = vt_led_trigger_activate, \
>> +       }
>> +       DEFINE_INPUT_LED_TRIGGER(LED_NUML, "numl"),
>> +       DEFINE_INPUT_LED_TRIGGER(LED_CAPSL, "capsl"),
>> +       DEFINE_INPUT_LED_TRIGGER(LED_SCROLLL, "scrolll"),
>> +       DEFINE_INPUT_LED_TRIGGER(LED_COMPOSE, "compose"),
>> +       DEFINE_INPUT_LED_TRIGGER(LED_KANA, "kana"),
>> +       DEFINE_INPUT_LED_TRIGGER(LED_SLEEP, "sleep"),
>> +       DEFINE_INPUT_LED_TRIGGER(LED_SUSPEND, "suspend"),
>> +       DEFINE_INPUT_LED_TRIGGER(LED_MUTE, "mute"),
>> +       DEFINE_INPUT_LED_TRIGGER(LED_MISC, "misc"),
>> +       DEFINE_INPUT_LED_TRIGGER(LED_MAIL, "mail"),
>> +       DEFINE_INPUT_LED_TRIGGER(LED_CHARGING, "charging"),
>> +};
>> +
>> +/* Lock for registration coherency */
>> +static DEFINE_MUTEX(vt_led_registered_lock);
>> +
>> +/* Which VT LED classes and triggers are registered */
>> +static unsigned long vt_led_registered[BITS_TO_LONGS(LED_CNT)];
>> +
>> +/* Number of input devices having each LED */
>> +static int vt_led_references[LED_CNT];
>> +
>> +/* VT LED state change, tell the VT trigger.  */
>> +static void vt_led_set(struct led_classdev *cdev,
>> +                         enum led_brightness brightness)
>> +{
>> +       int led = cdev - vt_leds;
>> +
>> +       led_trigger_event(&vt_led_triggers[led], !!brightness);
>> +}
>> +
>> +/* LED state change for some keyboard, notify that keyboard.  */
>> +static void perdevice_input_led_set(struct led_classdev *cdev,
>> +                         enum led_brightness brightness)
>> +{
>> +       struct input_dev *dev;
>> +       struct led_classdev *leds;
>> +       int led;
>> +
>> +       dev = cdev->dev->platform_data;
>> +       if (!dev)
>> +               /* Still initializing */
>> +               return;
>> +       leds = dev->leds;
>> +       led = cdev - leds;
>> +
>> +       input_event(dev, EV_LED, led, !!brightness);
>> +       input_event(dev, EV_SYN, SYN_REPORT, 0);
>> +}
>> +
>> +/* Keyboard hotplug, initialize its LED status */
>> +static void vt_led_trigger_activate(struct led_classdev *cdev)
>> +{
>> +       struct led_trigger *trigger = cdev->trigger;
>> +       int led = trigger - vt_led_triggers;
>> +
>> +       if (cdev->brightness_set)
>> +               cdev->brightness_set(cdev, vt_leds[led].brightness);
>> +}
>> +
>> +/* Free led stuff from input device, used at abortion and disconnection.  */
>> +static void input_led_delete(struct input_dev *dev)
>> +{
>> +       if (dev) {
>> +               struct led_classdev *leds = dev->leds;
>> +               if (leds) {
>> +                       int i;
>> +                       for (i = 0; i < LED_CNT; i++)
>> +                               kfree(leds[i].name);
>> +                       kfree(leds);
>> +                       dev->leds = NULL;
>> +               }
>> +       }
>> +}
>> +
>> +/* A new input device with potential LEDs to connect.  */
>> +int input_led_connect(struct input_dev *dev)
>> +{
>> +       int i, error = 0;
>> +       struct led_classdev *leds;
>> +
>> +       dev->leds = leds = kcalloc(LED_CNT, sizeof(*leds), GFP_KERNEL);
>> +       if (!dev->leds)
>> +               return -ENOMEM;
>> +
>> +       /* lazily register missing VT LEDs */
>> +       mutex_lock(&vt_led_registered_lock);
>> +       for (i = 0; i < LED_CNT; i++)
>> +               if (vt_leds[i].name && test_bit(i, dev->ledbit)) {
>> +                       if (!vt_led_references[i]) {
>> +                               led_trigger_register(&vt_led_triggers[i]);
>> +                               /* This keyboard is first to have led i,
>> +                                * try to register it */
>> +                               if (!led_classdev_register(NULL, &vt_leds[i]))
>> +                                       vt_led_references[i] = 1;
>> +                               else
>> +                                       led_trigger_unregister(&vt_led_triggers[i]);
>> +                       } else
>> +                               vt_led_references[i]++;
>> +               }
>> +       mutex_unlock(&vt_led_registered_lock);
>> +
>> +       /* and register this device's LEDs */
>> +       for (i = 0; i < LED_CNT; i++)
>> +               if (vt_leds[i].name && test_bit(i, dev->ledbit)) {
>> +                       leds[i].name = kasprintf(GFP_KERNEL, "%s::%s",
>> +                                               dev_name(&dev->dev),
>> +                                               vt_led_names[i]);
>> +                       if (!leds[i].name) {
>> +                               error = -ENOMEM;
>> +                               goto err;
>> +                       }
>> +                       leds[i].max_brightness = 1;
>> +                       leds[i].brightness_set = perdevice_input_led_set;
>> +                       leds[i].default_trigger = vt_led_triggers[i].name;
>> +               }
>> +
>> +       /* No issue so far, we can register for real.  */
>> +       for (i = 0; i < LED_CNT; i++)
>> +               if (leds[i].name) {
>> +                       led_classdev_register(&dev->dev, &leds[i]);
>> +                       leds[i].dev->platform_data = dev;
>> +                       perdevice_input_led_set(&leds[i],
>> +                                       vt_leds[i].brightness);
>> +               }
>> +
>> +       return 0;
>> +
>> +err:
>> +       input_led_delete(dev);
>> +       return error;
>> +}
>> +
>> +/*
>> + * Disconnected input device. Clean it, and deregister now-useless VT LEDs
>> + * and triggers.
>> + */
>> +void input_led_disconnect(struct input_dev *dev)
>> +{
>> +       int i;
>> +       struct led_classdev *leds = dev->leds;
>> +
>> +       for (i = 0; i < LED_CNT; i++)
>> +               if (leds[i].name)
>> +                       led_classdev_unregister(&leds[i]);
>> +
>> +       input_led_delete(dev);
>> +
>> +       mutex_lock(&vt_led_registered_lock);
>> +       for (i = 0; i < LED_CNT; i++) {
>> +               if (!vt_leds[i].name || !test_bit(i, dev->ledbit))
>> +                       continue;
>> +
>> +               vt_led_references[i]--;
>> +               if (vt_led_references[i]) {
>> +                       /* Still some devices needing it */
>> +                       continue;
>> +               }
>> +
>> +               led_classdev_unregister(&vt_leds[i]);
>> +               led_trigger_unregister(&vt_led_triggers[i]);
>> +               clear_bit(i, vt_led_registered);
>> +       }
>> +       mutex_unlock(&vt_led_registered_lock);
>> +}
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_DESCRIPTION("User LED support for input layer");
>> +MODULE_AUTHOR("Samuel Thibault <samuel.thibault@...-lyon.org>");
>>
>
> Dmitry, can you review this patch and include it into 3.15?
>

(Per Pavel and Sebastian suggestion resending email with included
keyword INPUT in subject)

-- 
Pali Rohár
pali.rohar@...il.com
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ