Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * LED support for the input layer
  4 *
  5 * Copyright 2010-2015 Samuel Thibault <samuel.thibault@ens-lyon.org>
  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
 21static const struct {
 22	const char *name;
 23	const char *trigger;
 24} input_led_info[LED_CNT] = {
 25	[LED_NUML]	= { "numlock", VT_TRIGGER("kbd-numlock") },
 26	[LED_CAPSL]	= { "capslock", VT_TRIGGER("kbd-capslock") },
 27	[LED_SCROLLL]	= { "scrolllock", VT_TRIGGER("kbd-scrolllock") },
 28	[LED_COMPOSE]	= { "compose" },
 29	[LED_KANA]	= { "kana", VT_TRIGGER("kbd-kanalock") },
 30	[LED_SLEEP]	= { "sleep" } ,
 31	[LED_SUSPEND]	= { "suspend" },
 32	[LED_MUTE]	= { "mute" },
 33	[LED_MISC]	= { "misc" },
 34	[LED_MAIL]	= { "mail" },
 35	[LED_CHARGING]	= { "charging" },
 36};
 37
 38struct input_led {
 39	struct led_classdev cdev;
 40	struct input_handle *handle;
 41	unsigned int code; /* One of LED_* constants */
 42};
 43
 44struct input_leds {
 45	struct input_handle handle;
 46	unsigned int num_leds;
 47	struct input_led leds[] __counted_by(num_leds);
 48};
 49
 50static enum led_brightness input_leds_brightness_get(struct led_classdev *cdev)
 51{
 52	struct input_led *led = container_of(cdev, struct input_led, cdev);
 53	struct input_dev *input = led->handle->dev;
 54
 55	return test_bit(led->code, input->led) ? cdev->max_brightness : 0;
 56}
 57
 58static void input_leds_brightness_set(struct led_classdev *cdev,
 59				      enum led_brightness brightness)
 60{
 61	struct input_led *led = container_of(cdev, struct input_led, cdev);
 62
 63	input_inject_event(led->handle, EV_LED, led->code, !!brightness);
 64}
 65
 66static void input_leds_event(struct input_handle *handle, unsigned int type,
 67			     unsigned int code, int value)
 68{
 69}
 70
 71static int input_leds_get_count(struct input_dev *dev)
 72{
 73	unsigned int led_code;
 74	int count = 0;
 75
 76	for_each_set_bit(led_code, dev->ledbit, LED_CNT)
 77		if (input_led_info[led_code].name)
 78			count++;
 79
 80	return count;
 81}
 82
 83static int input_leds_connect(struct input_handler *handler,
 84			      struct input_dev *dev,
 85			      const struct input_device_id *id)
 86{
 87	struct input_leds *leds;
 88	struct input_led *led;
 89	unsigned int num_leds;
 90	unsigned int led_code;
 91	int led_no;
 92	int error;
 93
 94	num_leds = input_leds_get_count(dev);
 95	if (!num_leds)
 96		return -ENXIO;
 97
 98	leds = kzalloc(struct_size(leds, leds, num_leds), GFP_KERNEL);
 99	if (!leds)
100		return -ENOMEM;
101
102	leds->num_leds = num_leds;
103
104	leds->handle.dev = dev;
105	leds->handle.handler = handler;
106	leds->handle.name = "leds";
107	leds->handle.private = leds;
108
109	error = input_register_handle(&leds->handle);
110	if (error)
111		goto err_free_mem;
112
113	error = input_open_device(&leds->handle);
114	if (error)
115		goto err_unregister_handle;
116
117	led_no = 0;
118	for_each_set_bit(led_code, dev->ledbit, LED_CNT) {
119		if (!input_led_info[led_code].name)
120			continue;
121
122		led = &leds->leds[led_no];
123		led->handle = &leds->handle;
124		led->code = led_code;
125
126		led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s",
127					   dev_name(&dev->dev),
128					   input_led_info[led_code].name);
129		if (!led->cdev.name) {
130			error = -ENOMEM;
131			goto err_unregister_leds;
132		}
133
134		led->cdev.max_brightness = 1;
135		led->cdev.brightness_get = input_leds_brightness_get;
136		led->cdev.brightness_set = input_leds_brightness_set;
137		led->cdev.default_trigger = input_led_info[led_code].trigger;
138
139		error = led_classdev_register(&dev->dev, &led->cdev);
140		if (error) {
141			dev_err(&dev->dev, "failed to register LED %s: %d\n",
142				led->cdev.name, error);
143			kfree(led->cdev.name);
144			goto err_unregister_leds;
145		}
146
147		led_no++;
148	}
149
150	return 0;
151
152err_unregister_leds:
153	while (--led_no >= 0) {
154		struct input_led *led = &leds->leds[led_no];
155
156		led_classdev_unregister(&led->cdev);
157		kfree(led->cdev.name);
158	}
159
160	input_close_device(&leds->handle);
161
162err_unregister_handle:
163	input_unregister_handle(&leds->handle);
164
165err_free_mem:
166	kfree(leds);
167	return error;
168}
169
170static void input_leds_disconnect(struct input_handle *handle)
171{
172	struct input_leds *leds = handle->private;
173	int i;
174
175	for (i = 0; i < leds->num_leds; i++) {
176		struct input_led *led = &leds->leds[i];
177
178		led_classdev_unregister(&led->cdev);
179		kfree(led->cdev.name);
180	}
181
182	input_close_device(handle);
183	input_unregister_handle(handle);
184
185	kfree(leds);
186}
187
188static const struct input_device_id input_leds_ids[] = {
189	{
190		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
191		.evbit = { BIT_MASK(EV_LED) },
192	},
193	{ },
194};
195MODULE_DEVICE_TABLE(input, input_leds_ids);
196
197static struct input_handler input_leds_handler = {
198	.event =	input_leds_event,
199	.connect =	input_leds_connect,
200	.disconnect =	input_leds_disconnect,
201	.name =		"leds",
202	.id_table =	input_leds_ids,
203};
204
205static int __init input_leds_init(void)
206{
207	return input_register_handler(&input_leds_handler);
208}
209module_init(input_leds_init);
210
211static void __exit input_leds_exit(void)
212{
213	input_unregister_handler(&input_leds_handler);
214}
215module_exit(input_leds_exit);
216
217MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>");
218MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>");
219MODULE_DESCRIPTION("Input -> LEDs Bridge");
220MODULE_LICENSE("GPL v2");