]> Git Repo - linux.git/blame - drivers/input/input-leds.c
Merge tag 'chrome-platform-fixes-for-v6.11-rc2' of git://git.kernel.org/pub/scm/linux...
[linux.git] / drivers / input / input-leds.c
CommitLineData
d2912cb1 1// SPDX-License-Identifier: GPL-2.0-only
f60c8ba7
ST
2/*
3 * LED support for the input layer
4 *
5 * Copyright 2010-2015 Samuel Thibault <[email protected]>
f60c8ba7
ST
6 */
7
8#include <linux/kernel.h>
9#include <linux/slab.h>
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/leds.h>
13#include <linux/input.h>
14
15#if IS_ENABLED(CONFIG_VT)
16#define VT_TRIGGER(_name) .trigger = _name
17#else
18#define VT_TRIGGER(_name) .trigger = NULL
19#endif
20
849c34e6 21#if IS_ENABLED(CONFIG_SND_CTL_LED)
698b4378
BS
22#define AUDIO_TRIGGER(_name) .trigger = _name
23#else
24#define AUDIO_TRIGGER(_name) .trigger = NULL
25#endif
26
f60c8ba7
ST
27static const struct {
28 const char *name;
29 const char *trigger;
30} input_led_info[LED_CNT] = {
31 [LED_NUML] = { "numlock", VT_TRIGGER("kbd-numlock") },
32 [LED_CAPSL] = { "capslock", VT_TRIGGER("kbd-capslock") },
33 [LED_SCROLLL] = { "scrolllock", VT_TRIGGER("kbd-scrolllock") },
34 [LED_COMPOSE] = { "compose" },
35 [LED_KANA] = { "kana", VT_TRIGGER("kbd-kanalock") },
36 [LED_SLEEP] = { "sleep" } ,
37 [LED_SUSPEND] = { "suspend" },
698b4378 38 [LED_MUTE] = { "mute", AUDIO_TRIGGER("audio-mute") },
f60c8ba7
ST
39 [LED_MISC] = { "misc" },
40 [LED_MAIL] = { "mail" },
41 [LED_CHARGING] = { "charging" },
42};
43
44struct input_led {
45 struct led_classdev cdev;
46 struct input_handle *handle;
47 unsigned int code; /* One of LED_* constants */
48};
49
50struct input_leds {
51 struct input_handle handle;
52 unsigned int num_leds;
21d7ec79 53 struct input_led leds[] __counted_by(num_leds);
f60c8ba7
ST
54};
55
56static enum led_brightness input_leds_brightness_get(struct led_classdev *cdev)
57{
58 struct input_led *led = container_of(cdev, struct input_led, cdev);
59 struct input_dev *input = led->handle->dev;
60
61 return test_bit(led->code, input->led) ? cdev->max_brightness : 0;
62}
63
64static void input_leds_brightness_set(struct led_classdev *cdev,
65 enum led_brightness brightness)
66{
67 struct input_led *led = container_of(cdev, struct input_led, cdev);
68
69 input_inject_event(led->handle, EV_LED, led->code, !!brightness);
70}
71
72static void input_leds_event(struct input_handle *handle, unsigned int type,
73 unsigned int code, int value)
74{
75}
76
b38ebd1d
DT
77static int input_leds_get_count(struct input_dev *dev)
78{
79 unsigned int led_code;
80 int count = 0;
81
82 for_each_set_bit(led_code, dev->ledbit, LED_CNT)
83 if (input_led_info[led_code].name)
84 count++;
85
86 return count;
87}
88
f60c8ba7
ST
89static int input_leds_connect(struct input_handler *handler,
90 struct input_dev *dev,
91 const struct input_device_id *id)
92{
93 struct input_leds *leds;
6bd6ae63 94 struct input_led *led;
f60c8ba7
ST
95 unsigned int num_leds;
96 unsigned int led_code;
97 int led_no;
98 int error;
99
b38ebd1d 100 num_leds = input_leds_get_count(dev);
f60c8ba7
ST
101 if (!num_leds)
102 return -ENXIO;
103
acafe7e3 104 leds = kzalloc(struct_size(leds, leds, num_leds), GFP_KERNEL);
f60c8ba7
ST
105 if (!leds)
106 return -ENOMEM;
107
108 leds->num_leds = num_leds;
109
110 leds->handle.dev = dev;
111 leds->handle.handler = handler;
112 leds->handle.name = "leds";
113 leds->handle.private = leds;
114
115 error = input_register_handle(&leds->handle);
116 if (error)
117 goto err_free_mem;
118
119 error = input_open_device(&leds->handle);
120 if (error)
121 goto err_unregister_handle;
122
123 led_no = 0;
124 for_each_set_bit(led_code, dev->ledbit, LED_CNT) {
6bd6ae63
DT
125 if (!input_led_info[led_code].name)
126 continue;
f60c8ba7 127
6bd6ae63 128 led = &leds->leds[led_no];
f60c8ba7
ST
129 led->handle = &leds->handle;
130 led->code = led_code;
131
f60c8ba7
ST
132 led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s",
133 dev_name(&dev->dev),
134 input_led_info[led_code].name);
135 if (!led->cdev.name) {
136 error = -ENOMEM;
137 goto err_unregister_leds;
138 }
139
140 led->cdev.max_brightness = 1;
141 led->cdev.brightness_get = input_leds_brightness_get;
142 led->cdev.brightness_set = input_leds_brightness_set;
143 led->cdev.default_trigger = input_led_info[led_code].trigger;
144
145 error = led_classdev_register(&dev->dev, &led->cdev);
146 if (error) {
147 dev_err(&dev->dev, "failed to register LED %s: %d\n",
148 led->cdev.name, error);
149 kfree(led->cdev.name);
150 goto err_unregister_leds;
151 }
152
153 led_no++;
154 }
155
156 return 0;
157
158err_unregister_leds:
159 while (--led_no >= 0) {
160 struct input_led *led = &leds->leds[led_no];
161
162 led_classdev_unregister(&led->cdev);
163 kfree(led->cdev.name);
164 }
165
166 input_close_device(&leds->handle);
167
168err_unregister_handle:
169 input_unregister_handle(&leds->handle);
170
171err_free_mem:
172 kfree(leds);
173 return error;
174}
175
176static void input_leds_disconnect(struct input_handle *handle)
177{
178 struct input_leds *leds = handle->private;
179 int i;
180
181 for (i = 0; i < leds->num_leds; i++) {
182 struct input_led *led = &leds->leds[i];
183
184 led_classdev_unregister(&led->cdev);
185 kfree(led->cdev.name);
186 }
187
188 input_close_device(handle);
189 input_unregister_handle(handle);
190
191 kfree(leds);
192}
193
194static const struct input_device_id input_leds_ids[] = {
195 {
196 .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
197 .evbit = { BIT_MASK(EV_LED) },
198 },
199 { },
200};
201MODULE_DEVICE_TABLE(input, input_leds_ids);
202
203static struct input_handler input_leds_handler = {
204 .event = input_leds_event,
205 .connect = input_leds_connect,
206 .disconnect = input_leds_disconnect,
207 .name = "leds",
208 .id_table = input_leds_ids,
209};
210
211static int __init input_leds_init(void)
212{
213 return input_register_handler(&input_leds_handler);
214}
215module_init(input_leds_init);
216
217static void __exit input_leds_exit(void)
218{
219 input_unregister_handler(&input_leds_handler);
220}
221module_exit(input_leds_exit);
222
223MODULE_AUTHOR("Samuel Thibault <[email protected]>");
224MODULE_AUTHOR("Dmitry Torokhov <[email protected]>");
225MODULE_DESCRIPTION("Input -> LEDs Bridge");
226MODULE_LICENSE("GPL v2");
This page took 0.247463 seconds and 4 git commands to generate.