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

tty/vt/keyboard: define LED triggers for VT LED states

Now that input core allows controlling keyboards LEDs via standard LED
subsystem triggers let's switch VT keyboard code to make use of this
feature. We will define the following standard triggers: "kbd-scrollock",
"kbd-numlock", "kbd-capslock", and "kbd-kanalock" which are default
triggers for respective LEDs on keyboards.

Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Tested-by: Pavel Machek <pavel@ucw.cz>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Samuel Thibault and committed by
Dmitry Torokhov
52355522 f60c8ba7

+117 -24
+117 -24
drivers/tty/vt/keyboard.c
··· 33 33 #include <linux/string.h> 34 34 #include <linux/init.h> 35 35 #include <linux/slab.h> 36 + #include <linux/leds.h> 36 37 37 38 #include <linux/kbd_kern.h> 38 39 #include <linux/kbd_diacr.h> ··· 962 961 } 963 962 } 964 963 964 + #if IS_ENABLED(CONFIG_INPUT_LEDS) && IS_ENABLED(CONFIG_LEDS_TRIGGERS) 965 + 966 + struct kbd_led_trigger { 967 + struct led_trigger trigger; 968 + unsigned int mask; 969 + }; 970 + 971 + static void kbd_led_trigger_activate(struct led_classdev *cdev) 972 + { 973 + struct kbd_led_trigger *trigger = 974 + container_of(cdev->trigger, struct kbd_led_trigger, trigger); 975 + 976 + tasklet_disable(&keyboard_tasklet); 977 + if (ledstate != 0xff) 978 + led_trigger_event(&trigger->trigger, 979 + ledstate & trigger->mask ? 980 + LED_FULL : LED_OFF); 981 + tasklet_enable(&keyboard_tasklet); 982 + } 983 + 984 + #define KBD_LED_TRIGGER(_led_bit, _name) { \ 985 + .trigger = { \ 986 + .name = _name, \ 987 + .activate = kbd_led_trigger_activate, \ 988 + }, \ 989 + .mask = BIT(_led_bit), \ 990 + } 991 + 992 + static struct kbd_led_trigger kbd_led_triggers[] = { 993 + KBD_LED_TRIGGER(VC_SCROLLOCK, "kbd-scrollock"), 994 + KBD_LED_TRIGGER(VC_NUMLOCK, "kbd-numlock"), 995 + KBD_LED_TRIGGER(VC_CAPSLOCK, "kbd-capslock"), 996 + KBD_LED_TRIGGER(VC_KANALOCK, "kbd-kanalock"), 997 + }; 998 + 999 + static void kbd_propagate_led_state(unsigned int old_state, 1000 + unsigned int new_state) 1001 + { 1002 + struct kbd_led_trigger *trigger; 1003 + unsigned int changed = old_state ^ new_state; 1004 + int i; 1005 + 1006 + for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) { 1007 + trigger = &kbd_led_triggers[i]; 1008 + 1009 + if (changed & trigger->mask) 1010 + led_trigger_event(&trigger->trigger, 1011 + new_state & trigger->mask ? 1012 + LED_FULL : LED_OFF); 1013 + } 1014 + } 1015 + 1016 + static int kbd_update_leds_helper(struct input_handle *handle, void *data) 1017 + { 1018 + unsigned int led_state = *(unsigned int *)data; 1019 + 1020 + if (test_bit(EV_LED, handle->dev->evbit)) 1021 + kbd_propagate_led_state(~led_state, led_state); 1022 + 1023 + return 0; 1024 + } 1025 + 1026 + static void kbd_init_leds(void) 1027 + { 1028 + int error; 1029 + int i; 1030 + 1031 + for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) { 1032 + error = led_trigger_register(&kbd_led_triggers[i].trigger); 1033 + if (error) 1034 + pr_err("error %d while registering trigger %s\n", 1035 + error, kbd_led_triggers[i].trigger.name); 1036 + } 1037 + } 1038 + 1039 + #else 1040 + 1041 + static int kbd_update_leds_helper(struct input_handle *handle, void *data) 1042 + { 1043 + unsigned int leds = *(unsigned int *)data; 1044 + 1045 + if (test_bit(EV_LED, handle->dev->evbit)) { 1046 + input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); 1047 + input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); 1048 + input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); 1049 + input_inject_event(handle, EV_SYN, SYN_REPORT, 0); 1050 + } 1051 + 1052 + return 0; 1053 + } 1054 + 1055 + static void kbd_propagate_led_state(unsigned int old_state, 1056 + unsigned int new_state) 1057 + { 1058 + input_handler_for_each_handle(&kbd_handler, &new_state, 1059 + kbd_update_leds_helper); 1060 + } 1061 + 1062 + static void kbd_init_leds(void) 1063 + { 1064 + } 1065 + 1066 + #endif 1067 + 965 1068 /* 966 1069 * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, 967 1070 * or (ii) whatever pattern of lights people want to show using KDSETLED, ··· 1098 993 return ledioctl; 1099 994 1100 995 return kb->ledflagstate; 1101 - } 1102 - 1103 - static int kbd_update_leds_helper(struct input_handle *handle, void *data) 1104 - { 1105 - unsigned char leds = *(unsigned char *)data; 1106 - 1107 - if (test_bit(EV_LED, handle->dev->evbit)) { 1108 - input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); 1109 - input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); 1110 - input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); 1111 - input_inject_event(handle, EV_SYN, SYN_REPORT, 0); 1112 - } 1113 - 1114 - return 0; 1115 996 } 1116 997 1117 998 /** ··· 1176 1085 } 1177 1086 1178 1087 /* 1179 - * This is the tasklet that updates LED state on all keyboards 1180 - * attached to the box. The reason we use tasklet is that we 1181 - * need to handle the scenario when keyboard handler is not 1182 - * registered yet but we already getting updates from the VT to 1183 - * update led state. 1088 + * This is the tasklet that updates LED state of LEDs using standard 1089 + * keyboard triggers. The reason we use tasklet is that we need to 1090 + * handle the scenario when keyboard handler is not registered yet 1091 + * but we already getting updates from the VT to update led state. 1184 1092 */ 1185 1093 static void kbd_bh(unsigned long dummy) 1186 1094 { 1187 1095 unsigned char leds; 1188 1096 unsigned long flags; 1189 - 1097 + 1190 1098 spin_lock_irqsave(&led_lock, flags); 1191 1099 leds = getleds(); 1192 1100 spin_unlock_irqrestore(&led_lock, flags); 1193 1101 1194 1102 if (leds != ledstate) { 1195 - input_handler_for_each_handle(&kbd_handler, &leds, 1196 - kbd_update_leds_helper); 1103 + kbd_propagate_led_state(ledstate, leds); 1197 1104 ledstate = leds; 1198 1105 } 1199 1106 } ··· 1539 1450 { 1540 1451 tasklet_disable(&keyboard_tasklet); 1541 1452 1542 - if (ledstate != 0xff) 1543 - kbd_update_leds_helper(handle, &ledstate); 1453 + if (ledstate != 0xff) { 1454 + unsigned int state = ledstate; 1455 + kbd_update_leds_helper(handle, &state); 1456 + } 1544 1457 1545 1458 tasklet_enable(&keyboard_tasklet); 1546 1459 } ··· 1587 1496 kbd_table[i].modeflags = KBD_DEFMODE; 1588 1497 kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; 1589 1498 } 1499 + 1500 + kbd_init_leds(); 1590 1501 1591 1502 error = input_register_handler(&kbd_handler); 1592 1503 if (error)