diff options
Diffstat (limited to 'drivers/char/keyboard.c')
-rw-r--r-- | drivers/char/keyboard.c | 42 |
1 files changed, 36 insertions, 6 deletions
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 212276affa1..d54f4a3ae34 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -42,6 +42,7 @@ #include <linux/sysrq.h> #include <linux/input.h> #include <linux/reboot.h> +#include <linux/notifier.h> extern void ctrl_alt_del(void); @@ -81,7 +82,8 @@ void compute_shiftstate(void); typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, char up_flag); static k_handler_fn K_HANDLERS; -static k_handler_fn *k_handler[16] = { K_HANDLERS }; +k_handler_fn *k_handler[16] = { K_HANDLERS }; +EXPORT_SYMBOL_GPL(k_handler); #define FN_HANDLERS\ fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ @@ -160,6 +162,23 @@ static int sysrq_alt_use; static int sysrq_alt; /* + * Notifier list for console keyboard events + */ +static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list); + +int register_keyboard_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&keyboard_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(register_keyboard_notifier); + +int unregister_keyboard_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(unregister_keyboard_notifier); + +/* * Translation of scancodes to keycodes. We set them on only the first * keyboard in the list that accepts the scancode and keycode. * Explanation for not choosing the first attached keyboard anymore: @@ -1130,6 +1149,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) unsigned char type, raw_mode; struct tty_struct *tty; int shift_final; + struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down }; tty = vc->vc_tty; @@ -1217,10 +1237,11 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) return; } - shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate; + param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate; key_map = key_maps[shift_final]; - if (!key_map) { + if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYCODE, ¶m) == NOTIFY_STOP || !key_map) { + atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNBOUND_KEYCODE, ¶m); compute_shiftstate(); kbd->slockstate = 0; return; @@ -1237,6 +1258,9 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) type = KTYP(keysym); if (type < 0xf0) { + param.value = keysym; + if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNICODE, ¶m) == NOTIFY_STOP) + return; if (down && !raw_mode) to_utf8(vc, keysym); return; @@ -1244,9 +1268,6 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) type -= 0xf0; - if (raw_mode && type != KT_SPEC && type != KT_SHIFT) - return; - if (type == KT_LETTER) { type = KT_LATIN; if (vc_kbd_led(kbd, VC_CAPSLOCK)) { @@ -1255,9 +1276,18 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) keysym = key_map[keycode]; } } + param.value = keysym; + + if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYSYM, ¶m) == NOTIFY_STOP) + return; + + if (raw_mode && type != KT_SPEC && type != KT_SHIFT) + return; (*k_handler[type])(vc, keysym & 0xff, !down); + atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, ¶m); + if (type != KT_SLOCK) kbd->slockstate = 0; } |