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 static const struct { 22 const char *name; 23 const char *trigger; 24 } input_led_info[LED_CNT] = { 25 [LED_NUML] = { "numlock", VT_TRIGGER("kbd-numlock") }, 26 [LED_CAPSL] = { "capslock", VT_TRIGGER("kbd-capslock") }, 27 [LED_SCROLLL] = { "scrolllock", VT_TRIGGER("kbd-scrolllock") }, 28 [LED_COMPOSE] = { "compose" }, 29 [LED_KANA] = { "kana", VT_TRIGGER("kbd-kanalock") }, 30 [LED_SLEEP] = { "sleep" } , 31 [LED_SUSPEND] = { "suspend" }, 32 [LED_MUTE] = { "mute" }, 33 [LED_MISC] = { "misc" }, 34 [LED_MAIL] = { "mail" }, 35 [LED_CHARGING] = { "charging" }, 36 }; 37 38 struct input_led { 39 struct led_classdev cdev; 40 struct input_handle *handle; 41 unsigned int code; /* One of LED_* constants */ 42 }; 43 44 struct input_leds { 45 struct input_handle handle; 46 unsigned int num_leds; 47 struct input_led leds[]; 48 }; 49 50 static enum led_brightness input_leds_brightness_get(struct led_classdev *cdev) 51 { 52 struct input_led *led = container_of(cdev, struct input_led, cdev); 53 struct input_dev *input = led->handle->dev; 54 55 return test_bit(led->code, input->led) ? cdev->max_brightness : 0; 56 } 57 58 static void input_leds_brightness_set(struct led_classdev *cdev, 59 enum led_brightness brightness) 60 { 61 struct input_led *led = container_of(cdev, struct input_led, cdev); 62 63 input_inject_event(led->handle, EV_LED, led->code, !!brightness); 64 } 65 66 static void input_leds_event(struct input_handle *handle, unsigned int type, 67 unsigned int code, int value) 68 { 69 } 70 71 static int input_leds_get_count(struct input_dev *dev) 72 { 73 unsigned int led_code; 74 int count = 0; 75 76 for_each_set_bit(led_code, dev->ledbit, LED_CNT) 77 if (input_led_info[led_code].name) 78 count++; 79 80 return count; 81 } 82 83 static int input_leds_connect(struct input_handler *handler, 84 struct input_dev *dev, 85 const struct input_device_id *id) 86 { 87 struct input_leds *leds; 88 struct input_led *led; 89 unsigned int num_leds; 90 unsigned int led_code; 91 int led_no; 92 int error; 93 94 num_leds = input_leds_get_count(dev); 95 if (!num_leds) 96 return -ENXIO; 97 98 leds = kzalloc(struct_size(leds, leds, num_leds), GFP_KERNEL); 99 if (!leds) 100 return -ENOMEM; 101 102 leds->num_leds = num_leds; 103 104 leds->handle.dev = dev; 105 leds->handle.handler = handler; 106 leds->handle.name = "leds"; 107 leds->handle.private = leds; 108 109 error = input_register_handle(&leds->handle); 110 if (error) 111 goto err_free_mem; 112 113 error = input_open_device(&leds->handle); 114 if (error) 115 goto err_unregister_handle; 116 117 led_no = 0; 118 for_each_set_bit(led_code, dev->ledbit, LED_CNT) { 119 if (!input_led_info[led_code].name) 120 continue; 121 122 led = &leds->leds[led_no]; 123 led->handle = &leds->handle; 124 led->code = led_code; 125 126 led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s", 127 dev_name(&dev->dev), 128 input_led_info[led_code].name); 129 if (!led->cdev.name) { 130 error = -ENOMEM; 131 goto err_unregister_leds; 132 } 133 134 led->cdev.max_brightness = 1; 135 led->cdev.brightness_get = input_leds_brightness_get; 136 led->cdev.brightness_set = input_leds_brightness_set; 137 led->cdev.default_trigger = input_led_info[led_code].trigger; 138 139 error = led_classdev_register(&dev->dev, &led->cdev); 140 if (error) { 141 dev_err(&dev->dev, "failed to register LED %s: %d\n", 142 led->cdev.name, error); 143 kfree(led->cdev.name); 144 goto err_unregister_leds; 145 } 146 147 led_no++; 148 } 149 150 return 0; 151 152 err_unregister_leds: 153 while (--led_no >= 0) { 154 struct input_led *led = &leds->leds[led_no]; 155 156 led_classdev_unregister(&led->cdev); 157 kfree(led->cdev.name); 158 } 159 160 input_close_device(&leds->handle); 161 162 err_unregister_handle: 163 input_unregister_handle(&leds->handle); 164 165 err_free_mem: 166 kfree(leds); 167 return error; 168 } 169 170 static void input_leds_disconnect(struct input_handle *handle) 171 { 172 struct input_leds *leds = handle->private; 173 int i; 174 175 for (i = 0; i < leds->num_leds; i++) { 176 struct input_led *led = &leds->leds[i]; 177 178 led_classdev_unregister(&led->cdev); 179 kfree(led->cdev.name); 180 } 181 182 input_close_device(handle); 183 input_unregister_handle(handle); 184 185 kfree(leds); 186 } 187 188 static const struct input_device_id input_leds_ids[] = { 189 { 190 .flags = INPUT_DEVICE_ID_MATCH_EVBIT, 191 .evbit = { BIT_MASK(EV_LED) }, 192 }, 193 { }, 194 }; 195 MODULE_DEVICE_TABLE(input, input_leds_ids); 196 197 static struct input_handler input_leds_handler = { 198 .event = input_leds_event, 199 .connect = input_leds_connect, 200 .disconnect = input_leds_disconnect, 201 .name = "leds", 202 .id_table = input_leds_ids, 203 }; 204 205 static int __init input_leds_init(void) 206 { 207 return input_register_handler(&input_leds_handler); 208 } 209 module_init(input_leds_init); 210 211 static void __exit input_leds_exit(void) 212 { 213 input_unregister_handler(&input_leds_handler); 214 } 215 module_exit(input_leds_exit); 216 217 MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>"); 218 MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>"); 219 MODULE_DESCRIPTION("Input -> LEDs Bridge"); 220 MODULE_LICENSE("GPL v2"); 221