brintos

brintos / linux-shallow public Read only

0
0
Text · 3.9 KiB · 1c79731 Raw
166 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Input Events LED trigger4 *5 * Copyright (C) 2024 Hans de Goede <hansg@kernel.org>6 */7 8#include <linux/input.h>9#include <linux/jiffies.h>10#include <linux/leds.h>11#include <linux/module.h>12#include <linux/moduleparam.h>13#include <linux/slab.h>14#include <linux/spinlock.h>15#include <linux/workqueue.h>16#include "../leds.h"17 18static unsigned long led_off_delay_ms = 5000;19module_param(led_off_delay_ms, ulong, 0644);20MODULE_PARM_DESC(led_off_delay_ms,21	"Specify delay in ms for turning LEDs off after last input event");22 23static struct input_events_data {24	struct delayed_work work;25	spinlock_t lock;26	/* To avoid repeatedly setting the brightness while there are events */27	bool led_on;28	unsigned long led_off_time;29} input_events_data;30 31static struct led_trigger *input_events_led_trigger;32 33static void led_input_events_work(struct work_struct *work)34{35	struct input_events_data *data =36		container_of(work, struct input_events_data, work.work);37 38	spin_lock_irq(&data->lock);39 40	/*41	 * This time_after_eq() check avoids a race where this work starts42	 * running before a new event pushed led_off_time back.43	 */44	if (time_after_eq(jiffies, data->led_off_time)) {45		led_trigger_event(input_events_led_trigger, LED_OFF);46		data->led_on = false;47	}48 49	spin_unlock_irq(&data->lock);50}51 52static void input_events_event(struct input_handle *handle, unsigned int type,53			       unsigned int code, int val)54{55	struct input_events_data *data = &input_events_data;56	unsigned long led_off_delay = msecs_to_jiffies(led_off_delay_ms);57	unsigned long flags;58 59	spin_lock_irqsave(&data->lock, flags);60 61	if (!data->led_on) {62		led_trigger_event(input_events_led_trigger, LED_FULL);63		data->led_on = true;64	}65	data->led_off_time = jiffies + led_off_delay;66 67	spin_unlock_irqrestore(&data->lock, flags);68 69	mod_delayed_work(system_wq, &data->work, led_off_delay);70}71 72static int input_events_connect(struct input_handler *handler, struct input_dev *dev,73				const struct input_device_id *id)74{75	struct input_handle *handle;76	int ret;77 78	handle = kzalloc(sizeof(*handle), GFP_KERNEL);79	if (!handle)80		return -ENOMEM;81 82	handle->dev = dev;83	handle->handler = handler;84	handle->name = KBUILD_MODNAME;85 86	ret = input_register_handle(handle);87	if (ret)88		goto err_free_handle;89 90	ret = input_open_device(handle);91	if (ret)92		goto err_unregister_handle;93 94	return 0;95 96err_unregister_handle:97	input_unregister_handle(handle);98err_free_handle:99	kfree(handle);100	return ret;101}102 103static void input_events_disconnect(struct input_handle *handle)104{105	input_close_device(handle);106	input_unregister_handle(handle);107	kfree(handle);108}109 110static const struct input_device_id input_events_ids[] = {111	{112		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,113		.evbit = { BIT_MASK(EV_KEY) },114	},115	{116		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,117		.evbit = { BIT_MASK(EV_REL) },118	},119	{120		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,121		.evbit = { BIT_MASK(EV_ABS) },122	},123	{ }124};125 126static struct input_handler input_events_handler = {127	.name = KBUILD_MODNAME,128	.event = input_events_event,129	.connect = input_events_connect,130	.disconnect = input_events_disconnect,131	.id_table = input_events_ids,132};133 134static int __init input_events_init(void)135{136	int ret;137 138	INIT_DELAYED_WORK(&input_events_data.work, led_input_events_work);139	spin_lock_init(&input_events_data.lock);140 141	led_trigger_register_simple("input-events", &input_events_led_trigger);142 143	ret = input_register_handler(&input_events_handler);144	if (ret) {145		led_trigger_unregister_simple(input_events_led_trigger);146		return ret;147	}148 149	return 0;150}151 152static void __exit input_events_exit(void)153{154	input_unregister_handler(&input_events_handler);155	cancel_delayed_work_sync(&input_events_data.work);156	led_trigger_unregister_simple(input_events_led_trigger);157}158 159module_init(input_events_init);160module_exit(input_events_exit);161 162MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");163MODULE_DESCRIPTION("Input Events LED trigger");164MODULE_LICENSE("GPL");165MODULE_ALIAS("ledtrig:input-events");166