Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.13-rc6 165 lines 4.0 kB view raw
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 */ 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 starts 42 * 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");