aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-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;