aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2015-03-17 00:19:44 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-06-16 17:59:46 -0400
commit5235552273e6b68abbed3b3047af6344e2e60c2c (patch)
tree158189f30ba2452730991cdeec9a7b7a3230bb12
parentf60c8ba77dcea80af8facfd786a0d2c3ace86f3d (diff)
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>
-rw-r--r--drivers/tty/vt/keyboard.c141
1 files changed, 117 insertions, 24 deletions
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 8a89f6e7715d..fc080bf1c4d2 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -33,6 +33,7 @@
33#include <linux/string.h> 33#include <linux/string.h>
34#include <linux/init.h> 34#include <linux/init.h>
35#include <linux/slab.h> 35#include <linux/slab.h>
36#include <linux/leds.h>
36 37
37#include <linux/kbd_kern.h> 38#include <linux/kbd_kern.h>
38#include <linux/kbd_diacr.h> 39#include <linux/kbd_diacr.h>
@@ -961,6 +962,110 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
961 } 962 }
962} 963}
963 964
965#if IS_ENABLED(CONFIG_INPUT_LEDS) && IS_ENABLED(CONFIG_LEDS_TRIGGERS)
966
967struct kbd_led_trigger {
968 struct led_trigger trigger;
969 unsigned int mask;
970};
971
972static void kbd_led_trigger_activate(struct led_classdev *cdev)
973{
974 struct kbd_led_trigger *trigger =
975 container_of(cdev->trigger, struct kbd_led_trigger, trigger);
976
977 tasklet_disable(&keyboard_tasklet);
978 if (ledstate != 0xff)
979 led_trigger_event(&trigger->trigger,
980 ledstate & trigger->mask ?
981 LED_FULL : LED_OFF);
982 tasklet_enable(&keyboard_tasklet);
983}
984
985#define KBD_LED_TRIGGER(_led_bit, _name) { \
986 .trigger = { \
987 .name = _name, \
988 .activate = kbd_led_trigger_activate, \
989 }, \
990 .mask = BIT(_led_bit), \
991 }
992
993static struct kbd_led_trigger kbd_led_triggers[] = {
994 KBD_LED_TRIGGER(VC_SCROLLOCK, "kbd-scrollock"),
995 KBD_LED_TRIGGER(VC_NUMLOCK, "kbd-numlock"),
996 KBD_LED_TRIGGER(VC_CAPSLOCK, "kbd-capslock"),
997 KBD_LED_TRIGGER(VC_KANALOCK, "kbd-kanalock"),
998};
999
1000static void kbd_propagate_led_state(unsigned int old_state,
1001 unsigned int new_state)
1002{
1003 struct kbd_led_trigger *trigger;
1004 unsigned int changed = old_state ^ new_state;
1005 int i;
1006
1007 for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) {
1008 trigger = &kbd_led_triggers[i];
1009
1010 if (changed & trigger->mask)
1011 led_trigger_event(&trigger->trigger,
1012 new_state & trigger->mask ?
1013 LED_FULL : LED_OFF);
1014 }
1015}
1016
1017static int kbd_update_leds_helper(struct input_handle *handle, void *data)
1018{
1019 unsigned int led_state = *(unsigned int *)data;
1020
1021 if (test_bit(EV_LED, handle->dev->evbit))
1022 kbd_propagate_led_state(~led_state, led_state);
1023
1024 return 0;
1025}
1026
1027static void kbd_init_leds(void)
1028{
1029 int error;
1030 int i;
1031
1032 for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) {
1033 error = led_trigger_register(&kbd_led_triggers[i].trigger);
1034 if (error)
1035 pr_err("error %d while registering trigger %s\n",
1036 error, kbd_led_triggers[i].trigger.name);
1037 }
1038}
1039
1040#else
1041
1042static int kbd_update_leds_helper(struct input_handle *handle, void *data)
1043{
1044 unsigned int leds = *(unsigned int *)data;
1045
1046 if (test_bit(EV_LED, handle->dev->evbit)) {
1047 input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
1048 input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02));
1049 input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04));
1050 input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
1051 }
1052
1053 return 0;
1054}
1055
1056static void kbd_propagate_led_state(unsigned int old_state,
1057 unsigned int new_state)
1058{
1059 input_handler_for_each_handle(&kbd_handler, &new_state,
1060 kbd_update_leds_helper);
1061}
1062
1063static void kbd_init_leds(void)
1064{
1065}
1066
1067#endif
1068
964/* 1069/*
965 * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, 1070 * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
966 * or (ii) whatever pattern of lights people want to show using KDSETLED, 1071 * or (ii) whatever pattern of lights people want to show using KDSETLED,
@@ -995,20 +1100,6 @@ static inline unsigned char getleds(void)
995 return kb->ledflagstate; 1100 return kb->ledflagstate;
996} 1101}
997 1102
998static int kbd_update_leds_helper(struct input_handle *handle, void *data)
999{
1000 unsigned char leds = *(unsigned char *)data;
1001
1002 if (test_bit(EV_LED, handle->dev->evbit)) {
1003 input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
1004 input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02));
1005 input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04));
1006 input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
1007 }
1008
1009 return 0;
1010}
1011
1012/** 1103/**
1013 * vt_get_leds - helper for braille console 1104 * vt_get_leds - helper for braille console
1014 * @console: console to read 1105 * @console: console to read
@@ -1085,24 +1176,22 @@ void vt_kbd_con_stop(int console)
1085} 1176}
1086 1177
1087/* 1178/*
1088 * This is the tasklet that updates LED state on all keyboards 1179 * This is the tasklet that updates LED state of LEDs using standard
1089 * attached to the box. The reason we use tasklet is that we 1180 * keyboard triggers. The reason we use tasklet is that we need to
1090 * need to handle the scenario when keyboard handler is not 1181 * handle the scenario when keyboard handler is not registered yet
1091 * registered yet but we already getting updates from the VT to 1182 * but we already getting updates from the VT to update led state.
1092 * update led state.
1093 */ 1183 */
1094static void kbd_bh(unsigned long dummy) 1184static void kbd_bh(unsigned long dummy)
1095{ 1185{
1096 unsigned char leds; 1186 unsigned char leds;
1097 unsigned long flags; 1187 unsigned long flags;
1098 1188
1099 spin_lock_irqsave(&led_lock, flags); 1189 spin_lock_irqsave(&led_lock, flags);
1100 leds = getleds(); 1190 leds = getleds();
1101 spin_unlock_irqrestore(&led_lock, flags); 1191 spin_unlock_irqrestore(&led_lock, flags);
1102 1192
1103 if (leds != ledstate) { 1193 if (leds != ledstate) {
1104 input_handler_for_each_handle(&kbd_handler, &leds, 1194 kbd_propagate_led_state(ledstate, leds);
1105 kbd_update_leds_helper);
1106 ledstate = leds; 1195 ledstate = leds;
1107 } 1196 }
1108} 1197}
@@ -1450,8 +1539,10 @@ static void kbd_start(struct input_handle *handle)
1450{ 1539{
1451 tasklet_disable(&keyboard_tasklet); 1540 tasklet_disable(&keyboard_tasklet);
1452 1541
1453 if (ledstate != 0xff) 1542 if (ledstate != 0xff) {
1454 kbd_update_leds_helper(handle, &ledstate); 1543 unsigned int state = ledstate;
1544 kbd_update_leds_helper(handle, &state);
1545 }
1455 1546
1456 tasklet_enable(&keyboard_tasklet); 1547 tasklet_enable(&keyboard_tasklet);
1457} 1548}
@@ -1497,6 +1588,8 @@ int __init kbd_init(void)
1497 kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; 1588 kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
1498 } 1589 }
1499 1590
1591 kbd_init_leds();
1592
1500 error = input_register_handler(&kbd_handler); 1593 error = input_register_handler(&kbd_handler);
1501 if (error) 1594 if (error)
1502 return error; 1595 return error;