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