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 27 static 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 44 struct input_led { 45 struct led_classdev cdev; 46 struct input_handle *handle; 47 unsigned int code; /* One of LED_* constants */ 48 }; 49 50 struct input_leds { 51 struct input_handle handle; 52 unsigned int num_leds; 53 struct input_led leds[] __counted_by(num_leds); 54 }; 55 56 static 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 64 static 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 72 static void input_leds_event(struct input_handle *handle, unsigned int type, 73 unsigned int code, int value) 74 { 75 } 76 77 static 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 89 static 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 158 err_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 168 err_unregister_handle: 169 input_unregister_handle(&leds->handle); 170 171 err_free_mem: 172 kfree(leds); 173 return error; 174 } 175 176 static 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 194 static 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 }; 201 MODULE_DEVICE_TABLE(input, input_leds_ids); 202 203 static 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 211 static int __init input_leds_init(void) 212 { 213 return input_register_handler(&input_leds_handler); 214 } 215 module_init(input_leds_init); 216 217 static void __exit input_leds_exit(void) 218 { 219 input_unregister_handler(&input_leds_handler); 220 } 221 module_exit(input_leds_exit); 222 223 MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>"); 224 MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>"); 225 MODULE_DESCRIPTION("Input -> LEDs Bridge"); 226 MODULE_LICENSE("GPL v2"); 227