xref: /linux/drivers/leds/trigger/ledtrig-input-events.c (revision e41d574b359ccd8d99be65c6f11502efa2b83136)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Input Events LED trigger
4  *
5  * Copyright (C) 2024 Hans de Goede <hansg@kernel.org>
6  * Partially based on Atsushi Nemoto's ledtrig-heartbeat.c.
7  */
8 
9 #include <linux/input.h>
10 #include <linux/jiffies.h>
11 #include <linux/leds.h>
12 #include <linux/module.h>
13 #include <linux/slab.h>
14 #include <linux/spinlock.h>
15 #include <linux/workqueue.h>
16 #include "../leds.h"
17 
18 #define DEFAULT_LED_OFF_DELAY_MS			5000
19 
20 struct input_events_data {
21 	struct input_handler handler;
22 	struct delayed_work work;
23 	spinlock_t lock;
24 	struct led_classdev *led_cdev;
25 	int led_cdev_saved_flags;
26 	/* To avoid repeatedly setting the brightness while there are events */
27 	bool led_on;
28 	unsigned long led_off_time;
29 	unsigned long led_off_delay;
30 };
31 
32 static void led_input_events_work(struct work_struct *work)
33 {
34 	struct input_events_data *data =
35 		container_of(work, struct input_events_data, work.work);
36 
37 	spin_lock_irq(&data->lock);
38 
39 	/*
40 	 * This time_after_eq() check avoids a race where this work starts
41 	 * running before a new event pushed led_off_time back.
42 	 */
43 	if (time_after_eq(jiffies, data->led_off_time)) {
44 		led_set_brightness_nosleep(data->led_cdev, LED_OFF);
45 		data->led_on = false;
46 	}
47 
48 	spin_unlock_irq(&data->lock);
49 }
50 
51 static ssize_t delay_show(struct device *dev, struct device_attribute *attr, char *buf)
52 {
53 	struct input_events_data *input_events_data = led_trigger_get_drvdata(dev);
54 
55 	return sysfs_emit(buf, "%lu\n", input_events_data->led_off_delay);
56 }
57 
58 static ssize_t delay_store(struct device *dev, struct device_attribute *attr,
59 			   const char *buf, size_t size)
60 {
61 	struct input_events_data *input_events_data = led_trigger_get_drvdata(dev);
62 	unsigned long delay;
63 	int ret;
64 
65 	ret = kstrtoul(buf, 0, &delay);
66 	if (ret)
67 		return ret;
68 
69 	/* Clamp between 0.5 and 1000 seconds */
70 	delay = clamp_val(delay, 500UL, 1000000UL);
71 	input_events_data->led_off_delay = msecs_to_jiffies(delay);
72 
73 	return size;
74 }
75 
76 static DEVICE_ATTR_RW(delay);
77 
78 static struct attribute *input_events_led_attrs[] = {
79 	&dev_attr_delay.attr,
80 	NULL
81 };
82 ATTRIBUTE_GROUPS(input_events_led);
83 
84 static void input_events_event(struct input_handle *handle, unsigned int type,
85 			       unsigned int code, int val)
86 {
87 	struct input_events_data *data =
88 		container_of(handle->handler, struct input_events_data, handler);
89 	unsigned long led_off_delay = READ_ONCE(data->led_off_delay);
90 	struct led_classdev *led_cdev = data->led_cdev;
91 	unsigned long flags;
92 
93 	if (test_and_clear_bit(LED_BLINK_BRIGHTNESS_CHANGE, &led_cdev->work_flags))
94 		led_cdev->blink_brightness = led_cdev->new_blink_brightness;
95 
96 	spin_lock_irqsave(&data->lock, flags);
97 
98 	if (!data->led_on) {
99 		led_set_brightness_nosleep(led_cdev, led_cdev->blink_brightness);
100 		data->led_on = true;
101 	}
102 	data->led_off_time = jiffies + led_off_delay;
103 
104 	spin_unlock_irqrestore(&data->lock, flags);
105 
106 	mod_delayed_work(system_wq, &data->work, led_off_delay);
107 }
108 
109 static int input_events_connect(struct input_handler *handler, struct input_dev *dev,
110 				const struct input_device_id *id)
111 {
112 	struct input_handle *handle;
113 	int ret;
114 
115 	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
116 	if (!handle)
117 		return -ENOMEM;
118 
119 	handle->dev = dev;
120 	handle->handler = handler;
121 	handle->name = "input-events";
122 
123 	ret = input_register_handle(handle);
124 	if (ret)
125 		goto err_free_handle;
126 
127 	ret = input_open_device(handle);
128 	if (ret)
129 		goto err_unregister_handle;
130 
131 	return 0;
132 
133 err_unregister_handle:
134 	input_unregister_handle(handle);
135 err_free_handle:
136 	kfree(handle);
137 	return ret;
138 }
139 
140 static void input_events_disconnect(struct input_handle *handle)
141 {
142 	input_close_device(handle);
143 	input_unregister_handle(handle);
144 	kfree(handle);
145 }
146 
147 static const struct input_device_id input_events_ids[] = {
148 	{
149 		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
150 		.evbit = { BIT_MASK(EV_KEY) },
151 	},
152 	{
153 		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
154 		.evbit = { BIT_MASK(EV_REL) },
155 	},
156 	{
157 		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
158 		.evbit = { BIT_MASK(EV_ABS) },
159 	},
160 	{ }
161 };
162 
163 static int input_events_activate(struct led_classdev *led_cdev)
164 {
165 	struct input_events_data *data;
166 	int ret;
167 
168 	data = kzalloc(sizeof(*data), GFP_KERNEL);
169 	if (!data)
170 		return -ENOMEM;
171 
172 	data->handler.name = "input-events";
173 	data->handler.event = input_events_event;
174 	data->handler.connect = input_events_connect;
175 	data->handler.disconnect = input_events_disconnect;
176 	data->handler.id_table = input_events_ids;
177 
178 	INIT_DELAYED_WORK(&data->work, led_input_events_work);
179 	spin_lock_init(&data->lock);
180 
181 	data->led_cdev = led_cdev;
182 	data->led_cdev_saved_flags = led_cdev->flags;
183 	data->led_off_delay = msecs_to_jiffies(DEFAULT_LED_OFF_DELAY_MS);
184 
185 	/*
186 	 * Use led_cdev->blink_brightness + LED_BLINK_SW flag so that sysfs
187 	 * brightness writes will change led_cdev->new_blink_brightness for
188 	 * configuring the on state brightness (like ledtrig-heartbeat).
189 	 */
190 	if (!led_cdev->blink_brightness)
191 		led_cdev->blink_brightness = led_cdev->max_brightness;
192 
193 	/* Start with LED off */
194 	led_set_brightness_nosleep(data->led_cdev, LED_OFF);
195 
196 	ret = input_register_handler(&data->handler);
197 	if (ret) {
198 		kfree(data);
199 		return ret;
200 	}
201 
202 	set_bit(LED_BLINK_SW, &led_cdev->work_flags);
203 
204 	/* Turn LED off during suspend, original flags are restored on deactivate() */
205 	led_cdev->flags |= LED_CORE_SUSPENDRESUME;
206 
207 	led_set_trigger_data(led_cdev, data);
208 	return 0;
209 }
210 
211 static void input_events_deactivate(struct led_classdev *led_cdev)
212 {
213 	struct input_events_data *data = led_get_trigger_data(led_cdev);
214 
215 	led_cdev->flags = data->led_cdev_saved_flags;
216 	clear_bit(LED_BLINK_SW, &led_cdev->work_flags);
217 	input_unregister_handler(&data->handler);
218 	cancel_delayed_work_sync(&data->work);
219 	kfree(data);
220 }
221 
222 static struct led_trigger input_events_led_trigger = {
223 	.name       = "input-events",
224 	.activate   = input_events_activate,
225 	.deactivate = input_events_deactivate,
226 	.groups     = input_events_led_groups,
227 };
228 module_led_trigger(input_events_led_trigger);
229 
230 MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
231 MODULE_DESCRIPTION("Input Events LED trigger");
232 MODULE_LICENSE("GPL");
233 MODULE_ALIAS("ledtrig:input-events");
234