Merge tag 'pinctrl-v5.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[sfrench/cifs-2.6.git] / drivers / input / input-leds.c
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
24 static 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
41 struct input_led {
42         struct led_classdev cdev;
43         struct input_handle *handle;
44         unsigned int code; /* One of LED_* constants */
45 };
46
47 struct input_leds {
48         struct input_handle handle;
49         unsigned int num_leds;
50         struct input_led leds[];
51 };
52
53 static 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
61 static 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
69 static void input_leds_event(struct input_handle *handle, unsigned int type,
70                              unsigned int code, int value)
71 {
72 }
73
74 static int input_leds_get_count(struct input_dev *dev)
75 {
76         unsigned int led_code;
77         int count = 0;
78
79         for_each_set_bit(led_code, dev->ledbit, LED_CNT)
80                 if (input_led_info[led_code].name)
81                         count++;
82
83         return count;
84 }
85
86 static int input_leds_connect(struct input_handler *handler,
87                               struct input_dev *dev,
88                               const struct input_device_id *id)
89 {
90         struct input_leds *leds;
91         struct input_led *led;
92         unsigned int num_leds;
93         unsigned int led_code;
94         int led_no;
95         int error;
96
97         num_leds = input_leds_get_count(dev);
98         if (!num_leds)
99                 return -ENXIO;
100
101         leds = kzalloc(struct_size(leds, leds, num_leds), GFP_KERNEL);
102         if (!leds)
103                 return -ENOMEM;
104
105         leds->num_leds = num_leds;
106
107         leds->handle.dev = dev;
108         leds->handle.handler = handler;
109         leds->handle.name = "leds";
110         leds->handle.private = leds;
111
112         error = input_register_handle(&leds->handle);
113         if (error)
114                 goto err_free_mem;
115
116         error = input_open_device(&leds->handle);
117         if (error)
118                 goto err_unregister_handle;
119
120         led_no = 0;
121         for_each_set_bit(led_code, dev->ledbit, LED_CNT) {
122                 if (!input_led_info[led_code].name)
123                         continue;
124
125                 led = &leds->leds[led_no];
126                 led->handle = &leds->handle;
127                 led->code = led_code;
128
129                 led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s",
130                                            dev_name(&dev->dev),
131                                            input_led_info[led_code].name);
132                 if (!led->cdev.name) {
133                         error = -ENOMEM;
134                         goto err_unregister_leds;
135                 }
136
137                 led->cdev.max_brightness = 1;
138                 led->cdev.brightness_get = input_leds_brightness_get;
139                 led->cdev.brightness_set = input_leds_brightness_set;
140                 led->cdev.default_trigger = input_led_info[led_code].trigger;
141
142                 error = led_classdev_register(&dev->dev, &led->cdev);
143                 if (error) {
144                         dev_err(&dev->dev, "failed to register LED %s: %d\n",
145                                 led->cdev.name, error);
146                         kfree(led->cdev.name);
147                         goto err_unregister_leds;
148                 }
149
150                 led_no++;
151         }
152
153         return 0;
154
155 err_unregister_leds:
156         while (--led_no >= 0) {
157                 struct input_led *led = &leds->leds[led_no];
158
159                 led_classdev_unregister(&led->cdev);
160                 kfree(led->cdev.name);
161         }
162
163         input_close_device(&leds->handle);
164
165 err_unregister_handle:
166         input_unregister_handle(&leds->handle);
167
168 err_free_mem:
169         kfree(leds);
170         return error;
171 }
172
173 static void input_leds_disconnect(struct input_handle *handle)
174 {
175         struct input_leds *leds = handle->private;
176         int i;
177
178         for (i = 0; i < leds->num_leds; i++) {
179                 struct input_led *led = &leds->leds[i];
180
181                 led_classdev_unregister(&led->cdev);
182                 kfree(led->cdev.name);
183         }
184
185         input_close_device(handle);
186         input_unregister_handle(handle);
187
188         kfree(leds);
189 }
190
191 static const struct input_device_id input_leds_ids[] = {
192         {
193                 .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
194                 .evbit = { BIT_MASK(EV_LED) },
195         },
196         { },
197 };
198 MODULE_DEVICE_TABLE(input, input_leds_ids);
199
200 static struct input_handler input_leds_handler = {
201         .event =        input_leds_event,
202         .connect =      input_leds_connect,
203         .disconnect =   input_leds_disconnect,
204         .name =         "leds",
205         .id_table =     input_leds_ids,
206 };
207
208 static int __init input_leds_init(void)
209 {
210         return input_register_handler(&input_leds_handler);
211 }
212 module_init(input_leds_init);
213
214 static void __exit input_leds_exit(void)
215 {
216         input_unregister_handler(&input_leds_handler);
217 }
218 module_exit(input_leds_exit);
219
220 MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>");
221 MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>");
222 MODULE_DESCRIPTION("Input -> LEDs Bridge");
223 MODULE_LICENSE("GPL v2");