1 // SPDX-License-Identifier: GPL-2.0-only
3 * LED support for the input layer
5 * Copyright 2010-2015 Samuel Thibault <samuel.thibault@ens-lyon.org>
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>
15 #if IS_ENABLED(CONFIG_VT)
16 #define VT_TRIGGER(_name) .trigger = _name
18 #define VT_TRIGGER(_name) .trigger = NULL
21 #if IS_ENABLED(CONFIG_SND_CTL_LED)
22 #define AUDIO_TRIGGER(_name) .trigger = _name
24 #define AUDIO_TRIGGER(_name) .trigger = NULL
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" },
38 [LED_MUTE
] = { "mute", AUDIO_TRIGGER("audio-mute") },
39 [LED_MISC
] = { "misc" },
40 [LED_MAIL
] = { "mail" },
41 [LED_CHARGING
] = { "charging" },
45 struct led_classdev cdev
;
46 struct input_handle
*handle
;
47 unsigned int code
; /* One of LED_* constants */
51 struct input_handle handle
;
52 unsigned int num_leds
;
53 struct input_led leds
[] __counted_by(num_leds
);
56 static enum led_brightness
input_leds_brightness_get(struct led_classdev
*cdev
)
58 struct input_led
*led
= container_of(cdev
, struct input_led
, cdev
);
59 struct input_dev
*input
= led
->handle
->dev
;
61 return test_bit(led
->code
, input
->led
) ? cdev
->max_brightness
: 0;
64 static void input_leds_brightness_set(struct led_classdev
*cdev
,
65 enum led_brightness brightness
)
67 struct input_led
*led
= container_of(cdev
, struct input_led
, cdev
);
69 input_inject_event(led
->handle
, EV_LED
, led
->code
, !!brightness
);
72 static void input_leds_event(struct input_handle
*handle
, unsigned int type
,
73 unsigned int code
, int value
)
77 static int input_leds_get_count(struct input_dev
*dev
)
79 unsigned int led_code
;
82 for_each_set_bit(led_code
, dev
->ledbit
, LED_CNT
)
83 if (input_led_info
[led_code
].name
)
89 static int input_leds_connect(struct input_handler
*handler
,
90 struct input_dev
*dev
,
91 const struct input_device_id
*id
)
93 struct input_leds
*leds
;
94 struct input_led
*led
;
95 unsigned int num_leds
;
96 unsigned int led_code
;
100 num_leds
= input_leds_get_count(dev
);
104 leds
= kzalloc(struct_size(leds
, leds
, num_leds
), GFP_KERNEL
);
108 leds
->num_leds
= num_leds
;
110 leds
->handle
.dev
= dev
;
111 leds
->handle
.handler
= handler
;
112 leds
->handle
.name
= "leds";
113 leds
->handle
.private = leds
;
115 error
= input_register_handle(&leds
->handle
);
119 error
= input_open_device(&leds
->handle
);
121 goto err_unregister_handle
;
124 for_each_set_bit(led_code
, dev
->ledbit
, LED_CNT
) {
125 if (!input_led_info
[led_code
].name
)
128 led
= &leds
->leds
[led_no
];
129 led
->handle
= &leds
->handle
;
130 led
->code
= led_code
;
132 led
->cdev
.name
= kasprintf(GFP_KERNEL
, "%s::%s",
134 input_led_info
[led_code
].name
);
135 if (!led
->cdev
.name
) {
137 goto err_unregister_leds
;
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
;
145 error
= led_classdev_register(&dev
->dev
, &led
->cdev
);
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
;
159 while (--led_no
>= 0) {
160 struct input_led
*led
= &leds
->leds
[led_no
];
162 led_classdev_unregister(&led
->cdev
);
163 kfree(led
->cdev
.name
);
166 input_close_device(&leds
->handle
);
168 err_unregister_handle
:
169 input_unregister_handle(&leds
->handle
);
176 static void input_leds_disconnect(struct input_handle
*handle
)
178 struct input_leds
*leds
= handle
->private;
181 for (i
= 0; i
< leds
->num_leds
; i
++) {
182 struct input_led
*led
= &leds
->leds
[i
];
184 led_classdev_unregister(&led
->cdev
);
185 kfree(led
->cdev
.name
);
188 input_close_device(handle
);
189 input_unregister_handle(handle
);
194 static const struct input_device_id input_leds_ids
[] = {
196 .flags
= INPUT_DEVICE_ID_MATCH_EVBIT
,
197 .evbit
= { BIT_MASK(EV_LED
) },
201 MODULE_DEVICE_TABLE(input
, input_leds_ids
);
203 static struct input_handler input_leds_handler
= {
204 .event
= input_leds_event
,
205 .connect
= input_leds_connect
,
206 .disconnect
= input_leds_disconnect
,
208 .id_table
= input_leds_ids
,
211 static int __init
input_leds_init(void)
213 return input_register_handler(&input_leds_handler
);
215 module_init(input_leds_init
);
217 static void __exit
input_leds_exit(void)
219 input_unregister_handler(&input_leds_handler
);
221 module_exit(input_leds_exit
);
223 MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>");
224 MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>");
225 MODULE_DESCRIPTION("Input -> LEDs Bridge");
226 MODULE_LICENSE("GPL v2");