Linux Audio

Check our new training course

Loading...
v4.6
 
  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_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
 86static 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	unsigned int num_leds;
 92	unsigned int led_code;
 93	int led_no;
 94	int error;
 95
 96	num_leds = input_leds_get_count(dev);
 97	if (!num_leds)
 98		return -ENXIO;
 99
100	leds = kzalloc(sizeof(*leds) + num_leds * sizeof(*leds->leds),
101		       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		struct input_led *led = &leds->leds[led_no];
 
123
 
124		led->handle = &leds->handle;
125		led->code = led_code;
126
127		if (!input_led_info[led_code].name)
128			continue;
129
130		led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s",
131					   dev_name(&dev->dev),
132					   input_led_info[led_code].name);
133		if (!led->cdev.name) {
134			error = -ENOMEM;
135			goto err_unregister_leds;
136		}
137
138		led->cdev.max_brightness = 1;
139		led->cdev.brightness_get = input_leds_brightness_get;
140		led->cdev.brightness_set = input_leds_brightness_set;
141		led->cdev.default_trigger = input_led_info[led_code].trigger;
142
143		error = led_classdev_register(&dev->dev, &led->cdev);
144		if (error) {
145			dev_err(&dev->dev, "failed to register LED %s: %d\n",
146				led->cdev.name, error);
147			kfree(led->cdev.name);
148			goto err_unregister_leds;
149		}
150
151		led_no++;
152	}
153
154	return 0;
155
156err_unregister_leds:
157	while (--led_no >= 0) {
158		struct input_led *led = &leds->leds[led_no];
159
160		led_classdev_unregister(&led->cdev);
161		kfree(led->cdev.name);
162	}
163
164	input_close_device(&leds->handle);
165
166err_unregister_handle:
167	input_unregister_handle(&leds->handle);
168
169err_free_mem:
170	kfree(leds);
171	return error;
172}
173
174static void input_leds_disconnect(struct input_handle *handle)
175{
176	struct input_leds *leds = handle->private;
177	int i;
178
179	for (i = 0; i < leds->num_leds; i++) {
180		struct input_led *led = &leds->leds[i];
181
182		led_classdev_unregister(&led->cdev);
183		kfree(led->cdev.name);
184	}
185
186	input_close_device(handle);
187	input_unregister_handle(handle);
188
189	kfree(leds);
190}
191
192static const struct input_device_id input_leds_ids[] = {
193	{
194		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
195		.evbit = { BIT_MASK(EV_LED) },
196	},
197	{ },
198};
199MODULE_DEVICE_TABLE(input, input_leds_ids);
200
201static struct input_handler input_leds_handler = {
202	.event =	input_leds_event,
203	.connect =	input_leds_connect,
204	.disconnect =	input_leds_disconnect,
205	.name =		"leds",
206	.id_table =	input_leds_ids,
207};
208
209static int __init input_leds_init(void)
210{
211	return input_register_handler(&input_leds_handler);
212}
213module_init(input_leds_init);
214
215static void __exit input_leds_exit(void)
216{
217	input_unregister_handler(&input_leds_handler);
218}
219module_exit(input_leds_exit);
220
221MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>");
222MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>");
223MODULE_DESCRIPTION("Input -> LEDs Bridge");
224MODULE_LICENSE("GPL v2");
v6.9.4
  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
 21#if IS_ENABLED(CONFIG_SND_CTL_LED)
 22#define AUDIO_TRIGGER(_name)	.trigger = _name
 23#else
 24#define AUDIO_TRIGGER(_name)	.trigger = NULL
 25#endif
 26
 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" },
 38	[LED_MUTE]	= { "mute", AUDIO_TRIGGER("audio-mute") },
 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;
 53	struct input_led leds[] __counted_by(num_leds);
 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
 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
 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;
 94	struct input_led *led;
 95	unsigned int num_leds;
 96	unsigned int led_code;
 97	int led_no;
 98	int error;
 99
100	num_leds = input_leds_get_count(dev);
101	if (!num_leds)
102		return -ENXIO;
103
104	leds = kzalloc(struct_size(leds, leds, num_leds), GFP_KERNEL);
 
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) {
125		if (!input_led_info[led_code].name)
126			continue;
127
128		led = &leds->leds[led_no];
129		led->handle = &leds->handle;
130		led->code = led_code;
 
 
 
131
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 <samuel.thibault@ens-lyon.org>");
224MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>");
225MODULE_DESCRIPTION("Input -> LEDs Bridge");
226MODULE_LICENSE("GPL v2");