aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/leds/leds-class.txt3
-rw-r--r--drivers/input/Kconfig13
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/input-leds.c212
-rw-r--r--drivers/leds/Kconfig3
5 files changed, 226 insertions, 6 deletions
diff --git a/Documentation/leds/leds-class.txt b/Documentation/leds/leds-class.txt
index 79699c200766..62261c04060a 100644
--- a/Documentation/leds/leds-class.txt
+++ b/Documentation/leds/leds-class.txt
@@ -2,9 +2,6 @@
2LED handling under Linux 2LED handling under Linux
3======================== 3========================
4 4
5If you're reading this and thinking about keyboard leds, these are
6handled by the input subsystem and the led class is *not* needed.
7
8In its simplest form, the LED class just allows control of LEDs from 5In its simplest form, the LED class just allows control of LEDs from
9userspace. LEDs appear in /sys/class/leds/. The maximum brightness of the 6userspace. LEDs appear in /sys/class/leds/. The maximum brightness of the
10LED is defined in max_brightness file. The brightness file will set the brightness 7LED is defined in max_brightness file. The brightness file will set the brightness
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index a11ff74a5127..a35532ec00e4 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -25,6 +25,19 @@ config INPUT
25 25
26if INPUT 26if INPUT
27 27
28config INPUT_LEDS
29 tristate "Export input device LEDs in sysfs"
30 depends on LEDS_CLASS
31 default INPUT
32 help
33 Say Y here if you would like to export LEDs on input devices
34 as standard LED class devices in sysfs.
35
36 If unsure, say Y.
37
38 To compile this driver as a module, choose M here: the
39 module will be called input-leds.
40
28config INPUT_FF_MEMLESS 41config INPUT_FF_MEMLESS
29 tristate "Support for memoryless force-feedback devices" 42 tristate "Support for memoryless force-feedback devices"
30 help 43 help
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 5ca3f631497f..0c9302ca9954 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
12obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o 12obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
13obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o 13obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o
14 14
15obj-$(CONFIG_INPUT_LEDS) += input-leds.o
15obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o 16obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
16obj-$(CONFIG_INPUT_JOYDEV) += joydev.o 17obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
17obj-$(CONFIG_INPUT_EVDEV) += evdev.o 18obj-$(CONFIG_INPUT_EVDEV) += evdev.o
diff --git a/drivers/input/input-leds.c b/drivers/input/input-leds.c
new file mode 100644
index 000000000000..074a65ed17bb
--- /dev/null
+++ b/drivers/input/input-leds.c
@@ -0,0 +1,212 @@
1/*
2 * LED support for the input layer
3 *
4 * Copyright 2010-2015 Samuel Thibault <samuel.thibault@ens-lyon.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/kernel.h>
12#include <linux/slab.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/leds.h>
16#include <linux/input.h>
17
18#if IS_ENABLED(CONFIG_VT)
19#define VT_TRIGGER(_name) .trigger = _name
20#else
21#define VT_TRIGGER(_name) .trigger = NULL
22#endif
23
24static const struct {
25 const char *name;
26 const char *trigger;
27} input_led_info[LED_CNT] = {
28 [LED_NUML] = { "numlock", VT_TRIGGER("kbd-numlock") },
29 [LED_CAPSL] = { "capslock", VT_TRIGGER("kbd-capslock") },
30 [LED_SCROLLL] = { "scrolllock", VT_TRIGGER("kbd-scrolllock") },
31 [LED_COMPOSE] = { "compose" },
32 [LED_KANA] = { "kana", VT_TRIGGER("kbd-kanalock") },
33 [LED_SLEEP] = { "sleep" } ,
34 [LED_SUSPEND] = { "suspend" },
35 [LED_MUTE] = { "mute" },
36 [LED_MISC] = { "misc" },
37 [LED_MAIL] = { "mail" },
38 [LED_CHARGING] = { "charging" },
39};
40
41struct input_led {
42 struct led_classdev cdev;
43 struct input_handle *handle;
44 unsigned int code; /* One of LED_* constants */
45};
46
47struct input_leds {
48 struct input_handle handle;
49 unsigned int num_leds;
50 struct input_led leds[];
51};
52
53static enum led_brightness input_leds_brightness_get(struct led_classdev *cdev)
54{
55 struct input_led *led = container_of(cdev, struct input_led, cdev);
56 struct input_dev *input = led->handle->dev;
57
58 return test_bit(led->code, input->led) ? cdev->max_brightness : 0;
59}
60
61static void input_leds_brightness_set(struct led_classdev *cdev,
62 enum led_brightness brightness)
63{
64 struct input_led *led = container_of(cdev, struct input_led, cdev);
65
66 input_inject_event(led->handle, EV_LED, led->code, !!brightness);
67}
68
69static void input_leds_event(struct input_handle *handle, unsigned int type,
70 unsigned int code, int value)
71{
72}
73
74static int input_leds_connect(struct input_handler *handler,
75 struct input_dev *dev,
76 const struct input_device_id *id)
77{
78 struct input_leds *leds;
79 unsigned int num_leds;
80 unsigned int led_code;
81 int led_no;
82 int error;
83
84 num_leds = bitmap_weight(dev->ledbit, LED_CNT);
85 if (!num_leds)
86 return -ENXIO;
87
88 leds = kzalloc(sizeof(*leds) + num_leds * sizeof(*leds->leds),
89 GFP_KERNEL);
90 if (!leds)
91 return -ENOMEM;
92
93 leds->num_leds = num_leds;
94
95 leds->handle.dev = dev;
96 leds->handle.handler = handler;
97 leds->handle.name = "leds";
98 leds->handle.private = leds;
99
100 error = input_register_handle(&leds->handle);
101 if (error)
102 goto err_free_mem;
103
104 error = input_open_device(&leds->handle);
105 if (error)
106 goto err_unregister_handle;
107
108 led_no = 0;
109 for_each_set_bit(led_code, dev->ledbit, LED_CNT) {
110 struct input_led *led = &leds->leds[led_no];
111
112 led->handle = &leds->handle;
113 led->code = led_code;
114
115 if (WARN_ON(!input_led_info[led_code].name))
116 continue;
117
118 led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s",
119 dev_name(&dev->dev),
120 input_led_info[led_code].name);
121 if (!led->cdev.name) {
122 error = -ENOMEM;
123 goto err_unregister_leds;
124 }
125
126 led->cdev.max_brightness = 1;
127 led->cdev.brightness_get = input_leds_brightness_get;
128 led->cdev.brightness_set = input_leds_brightness_set;
129 led->cdev.default_trigger = input_led_info[led_code].trigger;
130
131 error = led_classdev_register(&dev->dev, &led->cdev);
132 if (error) {
133 dev_err(&dev->dev, "failed to register LED %s: %d\n",
134 led->cdev.name, error);
135 kfree(led->cdev.name);
136 goto err_unregister_leds;
137 }
138
139 led_no++;
140 }
141
142 return 0;
143
144err_unregister_leds:
145 while (--led_no >= 0) {
146 struct input_led *led = &leds->leds[led_no];
147
148 led_classdev_unregister(&led->cdev);
149 kfree(led->cdev.name);
150 }
151
152 input_close_device(&leds->handle);
153
154err_unregister_handle:
155 input_unregister_handle(&leds->handle);
156
157err_free_mem:
158 kfree(leds);
159 return error;
160}
161
162static void input_leds_disconnect(struct input_handle *handle)
163{
164 struct input_leds *leds = handle->private;
165 int i;
166
167 for (i = 0; i < leds->num_leds; i++) {
168 struct input_led *led = &leds->leds[i];
169
170 led_classdev_unregister(&led->cdev);
171 kfree(led->cdev.name);
172 }
173
174 input_close_device(handle);
175 input_unregister_handle(handle);
176
177 kfree(leds);
178}
179
180static const struct input_device_id input_leds_ids[] = {
181 {
182 .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
183 .evbit = { BIT_MASK(EV_LED) },
184 },
185 { },
186};
187MODULE_DEVICE_TABLE(input, input_leds_ids);
188
189static struct input_handler input_leds_handler = {
190 .event = input_leds_event,
191 .connect = input_leds_connect,
192 .disconnect = input_leds_disconnect,
193 .name = "leds",
194 .id_table = input_leds_ids,
195};
196
197static int __init input_leds_init(void)
198{
199 return input_register_handler(&input_leds_handler);
200}
201module_init(input_leds_init);
202
203static void __exit input_leds_exit(void)
204{
205 input_unregister_handler(&input_leds_handler);
206}
207module_exit(input_leds_exit);
208
209MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>");
210MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>");
211MODULE_DESCRIPTION("Input -> LEDs Bridge");
212MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 25b320d64e26..95029dfd311a 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -11,9 +11,6 @@ menuconfig NEW_LEDS
11 Say Y to enable Linux LED support. This allows control of supported 11 Say Y to enable Linux LED support. This allows control of supported
12 LEDs from both userspace and optionally, by kernel events (triggers). 12 LEDs from both userspace and optionally, by kernel events (triggers).
13 13
14 This is not related to standard keyboard LEDs which are controlled
15 via the input system.
16
17if NEW_LEDS 14if NEW_LEDS
18 15
19config LEDS_CLASS 16config LEDS_CLASS