Staging: phison: depends on ATA_BMDMA
[safe/jmp/linux-2.6] / drivers / char / keyboard.c
index d95f316..54109dc 100644 (file)
@@ -24,6 +24,8 @@
  * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/consolemap.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/kbd_kern.h>
 #include <linux/kbd_diacr.h>
 #include <linux/vt_kern.h>
-#include <linux/sysrq.h>
 #include <linux/input.h>
 #include <linux/reboot.h>
+#include <linux/notifier.h>
+#include <linux/jiffies.h>
 
 extern void ctrl_alt_del(void);
 
@@ -107,6 +110,7 @@ const int max_vals[] = {
 const int NR_TYPES = ARRAY_SIZE(max_vals);
 
 struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+EXPORT_SYMBOL_GPL(kbd_table);
 static struct kbd_struct *kbd = kbd_table;
 
 struct vt_spawn_console vt_spawn_con = {
@@ -126,9 +130,10 @@ int shift_state = 0;
  */
 
 static struct input_handler kbd_handler;
-static unsigned long key_down[NBITS(KEY_MAX)];         /* keyboard key bitmap */
+static DEFINE_SPINLOCK(kbd_event_lock);
+static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
 static unsigned char shift_down[NR_SHIFT];             /* shift state counters.. */
-static int dead_key_next;
+static bool dead_key_next;
 static int npadch = -1;                                        /* -1 or number assembled on pad */
 static unsigned int diacr;
 static char rep;                                       /* flag telling character repeat */
@@ -142,21 +147,22 @@ static struct ledptr {
        unsigned char valid:1;
 } ledptrs[3];
 
-/* Simple translation table for the SysRq keys */
-
-#ifdef CONFIG_MAGIC_SYSRQ
-unsigned char kbd_sysrq_xlate[KEY_MAX + 1] =
-        "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
-        "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
-        "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
-        "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
-        "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
-        "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
-        "\r\000/";                                      /* 0x60 - 0x6f */
-static int sysrq_down;
-static int sysrq_alt_use;
-#endif
-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
@@ -167,105 +173,124 @@ static int sysrq_alt;
  *  etc.). So this means that scancodes for the extra function keys won't
  *  be valid for the first event device, but will be for the second.
  */
+
+struct getset_keycode_data {
+       unsigned int scancode;
+       unsigned int keycode;
+       int error;
+};
+
+static int getkeycode_helper(struct input_handle *handle, void *data)
+{
+       struct getset_keycode_data *d = data;
+
+       d->error = input_get_keycode(handle->dev, d->scancode, &d->keycode);
+
+       return d->error == 0; /* stop as soon as we successfully get one */
+}
+
 int getkeycode(unsigned int scancode)
 {
-       struct input_handle *handle;
-       int keycode;
-       int error = -ENODEV;
+       struct getset_keycode_data d = { scancode, 0, -ENODEV };
 
-       list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
-               error = handle->dev->getkeycode(handle->dev, scancode, &keycode);
-               if (!error)
-                       return keycode;
-       }
+       input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper);
 
-       return error;
+       return d.error ?: d.keycode;
+}
+
+static int setkeycode_helper(struct input_handle *handle, void *data)
+{
+       struct getset_keycode_data *d = data;
+
+       d->error = input_set_keycode(handle->dev, d->scancode, d->keycode);
+
+       return d->error == 0; /* stop as soon as we successfully set one */
 }
 
 int setkeycode(unsigned int scancode, unsigned int keycode)
 {
-       struct input_handle *handle;
-       int error = -ENODEV;
+       struct getset_keycode_data d = { scancode, keycode, -ENODEV };
 
-       list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
-               error = handle->dev->setkeycode(handle->dev, scancode, keycode);
-               if (!error)
-                       break;
-       }
+       input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper);
 
-       return error;
+       return d.error;
 }
 
 /*
- * Making beeps and bells.
+ * Making beeps and bells. Note that we prefer beeps to bells, but when
+ * shutting the sound off we do both.
  */
-static void kd_nosound(unsigned long ignored)
-{
-       struct input_handle *handle;
 
-       list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
-               if (test_bit(EV_SND, handle->dev->evbit)) {
-                       if (test_bit(SND_TONE, handle->dev->sndbit))
-                               input_inject_event(handle, EV_SND, SND_TONE, 0);
-                       if (test_bit(SND_BELL, handle->dev->sndbit))
-                               input_inject_event(handle, EV_SND, SND_BELL, 0);
+static int kd_sound_helper(struct input_handle *handle, void *data)
+{
+       unsigned int *hz = data;
+       struct input_dev *dev = handle->dev;
+
+       if (test_bit(EV_SND, dev->evbit)) {
+               if (test_bit(SND_TONE, dev->sndbit)) {
+                       input_inject_event(handle, EV_SND, SND_TONE, *hz);
+                       if (*hz)
+                               return 0;
                }
+               if (test_bit(SND_BELL, dev->sndbit))
+                       input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0);
        }
+
+       return 0;
+}
+
+static void kd_nosound(unsigned long ignored)
+{
+       static unsigned int zero;
+
+       input_handler_for_each_handle(&kbd_handler, &zero, kd_sound_helper);
 }
 
 static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0);
 
 void kd_mksound(unsigned int hz, unsigned int ticks)
 {
-       struct list_head *node;
-
-       del_timer(&kd_mksound_timer);
-
-       if (hz) {
-               list_for_each_prev(node, &kbd_handler.h_list) {
-                       struct input_handle *handle = to_handle_h(node);
-                       if (test_bit(EV_SND, handle->dev->evbit)) {
-                               if (test_bit(SND_TONE, handle->dev->sndbit)) {
-                                       input_inject_event(handle, EV_SND, SND_TONE, hz);
-                                       break;
-                               }
-                               if (test_bit(SND_BELL, handle->dev->sndbit)) {
-                                       input_inject_event(handle, EV_SND, SND_BELL, 1);
-                                       break;
-                               }
-                       }
-               }
-               if (ticks)
-                       mod_timer(&kd_mksound_timer, jiffies + ticks);
-       } else
-               kd_nosound(0);
+       del_timer_sync(&kd_mksound_timer);
+
+       input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper);
+
+       if (hz && ticks)
+               mod_timer(&kd_mksound_timer, jiffies + ticks);
 }
+EXPORT_SYMBOL(kd_mksound);
 
 /*
  * Setting the keyboard rate.
  */
 
-int kbd_rate(struct kbd_repeat *rep)
+static int kbd_rate_helper(struct input_handle *handle, void *data)
 {
-       struct list_head *node;
-       unsigned int d = 0;
-       unsigned int p = 0;
-
-       list_for_each(node, &kbd_handler.h_list) {
-               struct input_handle *handle = to_handle_h(node);
-               struct input_dev *dev = handle->dev;
-
-               if (test_bit(EV_REP, dev->evbit)) {
-                       if (rep->delay > 0)
-                               input_inject_event(handle, EV_REP, REP_DELAY, rep->delay);
-                       if (rep->period > 0)
-                               input_inject_event(handle, EV_REP, REP_PERIOD, rep->period);
-                       d = dev->rep[REP_DELAY];
-                       p = dev->rep[REP_PERIOD];
-               }
+       struct input_dev *dev = handle->dev;
+       struct kbd_repeat *rep = data;
+
+       if (test_bit(EV_REP, dev->evbit)) {
+
+               if (rep[0].delay > 0)
+                       input_inject_event(handle,
+                                          EV_REP, REP_DELAY, rep[0].delay);
+               if (rep[0].period > 0)
+                       input_inject_event(handle,
+                                          EV_REP, REP_PERIOD, rep[0].period);
+
+               rep[1].delay = dev->rep[REP_DELAY];
+               rep[1].period = dev->rep[REP_PERIOD];
        }
-       rep->delay  = d;
-       rep->period = p;
+
+       return 0;
+}
+
+int kbd_rate(struct kbd_repeat *rep)
+{
+       struct kbd_repeat data[2] = { *rep };
+
+       input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper);
+       *rep = data[1]; /* Copy currently used settings */
+
        return 0;
 }
 
@@ -320,8 +345,8 @@ static void to_utf8(struct vc_data *vc, uint c)
                /* 110***** 10****** */
                put_queue(vc, 0xc0 | (c >> 6));
                put_queue(vc, 0x80 | (c & 0x3f));
-       } else if (c < 0x10000) {
-               if (c >= 0xD800 && c < 0xE000)
+       } else if (c < 0x10000) {
+               if (c >= 0xD800 && c < 0xE000)
                        return;
                if (c == 0xFFFF)
                        return;
@@ -329,7 +354,7 @@ static void to_utf8(struct vc_data *vc, uint c)
                put_queue(vc, 0xe0 | (c >> 12));
                put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
                put_queue(vc, 0x80 | (c & 0x3f));
-       } else if (c < 0x110000) {
+       } else if (c < 0x110000) {
                /* 11110*** 10****** 10****** 10****** */
                put_queue(vc, 0xf0 | (c >> 18));
                put_queue(vc, 0x80 | ((c >> 12) & 0x3f));
@@ -403,9 +428,12 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
                return d;
 
        if (kbd->kbdmode == VC_UNICODE)
-               to_utf8(vc, conv_8bit_to_uni(d));
-       else if (d < 0x100)
-               put_queue(vc, d);
+               to_utf8(vc, d);
+       else {
+               int c = conv_uni_to_8bit(d);
+               if (c != -1)
+                       put_queue(vc, c);
+       }
 
        return ch;
 }
@@ -417,11 +445,15 @@ static void fn_enter(struct vc_data *vc)
 {
        if (diacr) {
                if (kbd->kbdmode == VC_UNICODE)
-                       to_utf8(vc, conv_8bit_to_uni(diacr));
-               else if (diacr < 0x100)
-                       put_queue(vc, diacr);
+                       to_utf8(vc, diacr);
+               else {
+                       int c = conv_uni_to_8bit(diacr);
+                       if (c != -1)
+                               put_queue(vc, c);
+               }
                diacr = 0;
        }
+
        put_queue(vc, 13);
        if (vc_kbd_mode(kbd, VC_CRLF))
                put_queue(vc, 10);
@@ -431,6 +463,7 @@ static void fn_caps_toggle(struct vc_data *vc)
 {
        if (rep)
                return;
+
        chg_vc_kbd_led(kbd, VC_CAPSLOCK);
 }
 
@@ -438,12 +471,14 @@ static void fn_caps_on(struct vc_data *vc)
 {
        if (rep)
                return;
+
        set_vc_kbd_led(kbd, VC_CAPSLOCK);
 }
 
 static void fn_show_ptregs(struct vc_data *vc)
 {
        struct pt_regs *regs = get_irq_regs();
+
        if (regs)
                show_regs(regs);
 }
@@ -468,7 +503,7 @@ static void fn_hold(struct vc_data *vc)
 
 static void fn_num(struct vc_data *vc)
 {
-       if (vc_kbd_mode(kbd,VC_APPLIC))
+       if (vc_kbd_mode(kbd, VC_APPLIC))
                applkey(vc, 'P', 1);
        else
                fn_bare_num(vc);
@@ -563,7 +598,7 @@ static void fn_boot_it(struct vc_data *vc)
 
 static void fn_compose(struct vc_data *vc)
 {
-       dead_key_next = 1;
+       dead_key_next = true;
 }
 
 static void fn_spawn_con(struct vc_data *vc)
@@ -610,7 +645,7 @@ static void k_spec(struct vc_data *vc, unsigned char value, char up_flag)
 
 static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag)
 {
-       printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n");
+       pr_err("k_lowercase was called - impossible\n");
 }
 
 static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
@@ -622,14 +657,17 @@ static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
                value = handle_diacr(vc, value);
 
        if (dead_key_next) {
-               dead_key_next = 0;
+               dead_key_next = false;
                diacr = value;
                return;
        }
        if (kbd->kbdmode == VC_UNICODE)
-               to_utf8(vc, conv_8bit_to_uni(value));
-       else if (value < 0x100)
-               put_queue(vc, value);
+               to_utf8(vc, value);
+       else {
+               int c = conv_uni_to_8bit(value);
+               if (c != -1)
+                       put_queue(vc, c);
+       }
 }
 
 /*
@@ -641,12 +679,13 @@ static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag)
 {
        if (up_flag)
                return;
+
        diacr = (diacr ? handle_diacr(vc, value) : value);
 }
 
 static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
 {
-       k_unicode(vc, value, up_flag);
+       k_unicode(vc, conv_8bit_to_uni(value), up_flag);
 }
 
 static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
@@ -660,29 +699,28 @@ static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
 static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
 {
        static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
-       value = ret_diacr[value];
-       k_deadunicode(vc, value, up_flag);
+
+       k_deadunicode(vc, ret_diacr[value], up_flag);
 }
 
 static void k_cons(struct vc_data *vc, unsigned char value, char up_flag)
 {
        if (up_flag)
                return;
+
        set_console(value);
 }
 
 static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
 {
-       unsigned v;
-
        if (up_flag)
                return;
-       v = value;
-       if (v < ARRAY_SIZE(func_table)) {
+
+       if ((unsigned)value < ARRAY_SIZE(func_table)) {
                if (func_table[value])
                        puts_queue(vc, func_table[value]);
        } else
-               printk(KERN_ERR "k_fn called with value=%d\n", value);
+               pr_err("k_fn called with value=%d\n", value);
 }
 
 static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
@@ -691,6 +729,7 @@ static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
 
        if (up_flag)
                return;
+
        applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
 }
 
@@ -708,43 +747,45 @@ static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)
                return;
        }
 
-       if (!vc_kbd_led(kbd, VC_NUMLOCK))
+       if (!vc_kbd_led(kbd, VC_NUMLOCK)) {
+
                switch (value) {
-                       case KVAL(K_PCOMMA):
-                       case KVAL(K_PDOT):
-                               k_fn(vc, KVAL(K_REMOVE), 0);
-                               return;
-                       case KVAL(K_P0):
-                               k_fn(vc, KVAL(K_INSERT), 0);
-                               return;
-                       case KVAL(K_P1):
-                               k_fn(vc, KVAL(K_SELECT), 0);
-                               return;
-                       case KVAL(K_P2):
-                               k_cur(vc, KVAL(K_DOWN), 0);
-                               return;
-                       case KVAL(K_P3):
-                               k_fn(vc, KVAL(K_PGDN), 0);
-                               return;
-                       case KVAL(K_P4):
-                               k_cur(vc, KVAL(K_LEFT), 0);
-                               return;
-                       case KVAL(K_P6):
-                               k_cur(vc, KVAL(K_RIGHT), 0);
-                               return;
-                       case KVAL(K_P7):
-                               k_fn(vc, KVAL(K_FIND), 0);
-                               return;
-                       case KVAL(K_P8):
-                               k_cur(vc, KVAL(K_UP), 0);
-                               return;
-                       case KVAL(K_P9):
-                               k_fn(vc, KVAL(K_PGUP), 0);
-                               return;
-                       case KVAL(K_P5):
-                               applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC));
-                               return;
+               case KVAL(K_PCOMMA):
+               case KVAL(K_PDOT):
+                       k_fn(vc, KVAL(K_REMOVE), 0);
+                       return;
+               case KVAL(K_P0):
+                       k_fn(vc, KVAL(K_INSERT), 0);
+                       return;
+               case KVAL(K_P1):
+                       k_fn(vc, KVAL(K_SELECT), 0);
+                       return;
+               case KVAL(K_P2):
+                       k_cur(vc, KVAL(K_DOWN), 0);
+                       return;
+               case KVAL(K_P3):
+                       k_fn(vc, KVAL(K_PGDN), 0);
+                       return;
+               case KVAL(K_P4):
+                       k_cur(vc, KVAL(K_LEFT), 0);
+                       return;
+               case KVAL(K_P6):
+                       k_cur(vc, KVAL(K_RIGHT), 0);
+                       return;
+               case KVAL(K_P7):
+                       k_fn(vc, KVAL(K_FIND), 0);
+                       return;
+               case KVAL(K_P8):
+                       k_cur(vc, KVAL(K_UP), 0);
+                       return;
+               case KVAL(K_P9):
+                       k_fn(vc, KVAL(K_PGUP), 0);
+                       return;
+               case KVAL(K_P5):
+                       applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC));
+                       return;
                }
+       }
 
        put_queue(vc, pad_chars[value]);
        if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
@@ -830,6 +871,7 @@ static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
 {
        if (up_flag || rep)
                return;
+
        chg_vc_kbd_lock(kbd, value);
 }
 
@@ -838,6 +880,7 @@ static void k_slock(struct vc_data *vc, unsigned char value, char up_flag)
        k_shift(vc, value, up_flag);
        if (up_flag || rep)
                return;
+
        chg_vc_kbd_slock(kbd, value);
        /* try to make Alt, oops, AltGr and such work */
        if (!key_maps[kbd->lockstate ^ kbd->slockstate]) {
@@ -875,12 +918,12 @@ static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag)
 
 static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
 {
-       static unsigned pressed,committing;
+       static unsigned pressed, committing;
        static unsigned long releasestart;
 
        if (kbd->kbdmode != VC_UNICODE) {
                if (!up_flag)
-                       printk("keyboard mode must be unicode for braille patterns\n");
+                       pr_warning("keyboard mode must be unicode for braille patterns\n");
                return;
        }
 
@@ -892,31 +935,28 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
        if (value > 8)
                return;
 
-       if (up_flag) {
-               if (brl_timeout) {
-                       if (!committing ||
-                           jiffies - releasestart > (brl_timeout * HZ) / 1000) {
-                               committing = pressed;
-                               releasestart = jiffies;
-                       }
-                       pressed &= ~(1 << (value - 1));
-                       if (!pressed) {
-                               if (committing) {
-                                       k_brlcommit(vc, committing, 0);
-                                       committing = 0;
-                               }
-                       }
-               } else {
-                       if (committing) {
-                               k_brlcommit(vc, committing, 0);
-                               committing = 0;
-                       }
-                       pressed &= ~(1 << (value - 1));
-               }
-       } else {
+       if (!up_flag) {
                pressed |= 1 << (value - 1);
                if (!brl_timeout)
                        committing = pressed;
+       } else if (brl_timeout) {
+               if (!committing ||
+                   time_after(jiffies,
+                              releasestart + msecs_to_jiffies(brl_timeout))) {
+                       committing = pressed;
+                       releasestart = jiffies;
+               }
+               pressed &= ~(1 << (value - 1));
+               if (!pressed && committing) {
+                       k_brlcommit(vc, committing, 0);
+                       committing = 0;
+               }
+       } else {
+               if (committing) {
+                       k_brlcommit(vc, committing, 0);
+                       committing = 0;
+               }
+               pressed &= ~(1 << (value - 1));
        }
 }
 
@@ -937,6 +977,7 @@ void setledstate(struct kbd_struct *kbd, unsigned int led)
                kbd->ledmode = LED_SHOW_IOCTL;
        } else
                kbd->ledmode = LED_SHOW_FLAGS;
+
        set_leds();
 }
 
@@ -963,36 +1004,36 @@ static inline unsigned char getleds(void)
        return leds;
 }
 
+static int kbd_update_leds_helper(struct input_handle *handle, void *data)
+{
+       unsigned char leds = *(unsigned char *)data;
+
+       if (test_bit(EV_LED, handle->dev->evbit)) {
+               input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
+               input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
+               input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
+               input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
+       }
+
+       return 0;
+}
+
 /*
- * This routine is the bottom half of the keyboard interrupt
- * routine, and runs with all interrupts enabled. It does
- * console changing, led setting and copy_to_cooked, which can
- * take a reasonably long time.
- *
- * Aside from timing (which isn't really that important for
- * keyboard interrupts as they happen often), using the software
- * interrupt routines for this thing allows us to easily mask
- * this when we don't want any of the above to happen.
- * This allows for easy and efficient race-condition prevention
- * for kbd_start => input_inject_event(dev, EV_LED, ...) => ...
+ * This is the tasklet that updates LED state on all keyboards
+ * attached to the box. The reason we use tasklet is that we
+ * need to handle the scenario when keyboard handler is not
+ * registered yet but we already getting updates form VT to
+ * update led state.
  */
-
 static void kbd_bh(unsigned long dummy)
 {
-       struct list_head *node;
        unsigned char leds = getleds();
 
        if (leds != ledstate) {
-               list_for_each(node, &kbd_handler.h_list) {
-                       struct input_handle *handle = to_handle_h(node);
-                       input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
-                       input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
-                       input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
-                       input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
-               }
+               input_handler_for_each_handle(&kbd_handler, &leds,
+                                             kbd_update_leds_helper);
+               ledstate = leds;
        }
-
-       ledstate = leds;
 }
 
 DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
@@ -1000,7 +1041,8 @@ DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
 #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
     defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
     defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
-    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC))
+    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\
+    defined(CONFIG_AVR32)
 
 #define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
                        ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
@@ -1023,7 +1065,7 @@ static const unsigned short x86_keycodes[256] =
        332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 };
 
 #ifdef CONFIG_SPARC
-static int sparc_l1_a_state = 0;
+static int sparc_l1_a_state;
 extern void sun_do_break(void);
 #endif
 
@@ -1033,52 +1075,54 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode,
        int code;
 
        switch (keycode) {
-               case KEY_PAUSE:
-                       put_queue(vc, 0xe1);
-                       put_queue(vc, 0x1d | up_flag);
-                       put_queue(vc, 0x45 | up_flag);
-                       break;
 
-               case KEY_HANGEUL:
-                       if (!up_flag)
-                               put_queue(vc, 0xf2);
-                       break;
+       case KEY_PAUSE:
+               put_queue(vc, 0xe1);
+               put_queue(vc, 0x1d | up_flag);
+               put_queue(vc, 0x45 | up_flag);
+               break;
 
-               case KEY_HANJA:
-                       if (!up_flag)
-                               put_queue(vc, 0xf1);
-                       break;
+       case KEY_HANGEUL:
+               if (!up_flag)
+                       put_queue(vc, 0xf2);
+               break;
 
-               case KEY_SYSRQ:
-                       /*
-                        * Real AT keyboards (that's what we're trying
-                        * to emulate here emit 0xe0 0x2a 0xe0 0x37 when
-                        * pressing PrtSc/SysRq alone, but simply 0x54
-                        * when pressing Alt+PrtSc/SysRq.
-                        */
-                       if (sysrq_alt) {
-                               put_queue(vc, 0x54 | up_flag);
-                       } else {
-                               put_queue(vc, 0xe0);
-                               put_queue(vc, 0x2a | up_flag);
-                               put_queue(vc, 0xe0);
-                               put_queue(vc, 0x37 | up_flag);
-                       }
-                       break;
+       case KEY_HANJA:
+               if (!up_flag)
+                       put_queue(vc, 0xf1);
+               break;
 
-               default:
-                       if (keycode > 255)
-                               return -1;
+       case KEY_SYSRQ:
+               /*
+                * Real AT keyboards (that's what we're trying
+                * to emulate here emit 0xe0 0x2a 0xe0 0x37 when
+                * pressing PrtSc/SysRq alone, but simply 0x54
+                * when pressing Alt+PrtSc/SysRq.
+                */
+               if (test_bit(KEY_LEFTALT, key_down) ||
+                   test_bit(KEY_RIGHTALT, key_down)) {
+                       put_queue(vc, 0x54 | up_flag);
+               } else {
+                       put_queue(vc, 0xe0);
+                       put_queue(vc, 0x2a | up_flag);
+                       put_queue(vc, 0xe0);
+                       put_queue(vc, 0x37 | up_flag);
+               }
+               break;
 
-                       code = x86_keycodes[keycode];
-                       if (!code)
-                               return -1;
+       default:
+               if (keycode > 255)
+                       return -1;
 
-                       if (code & 0x100)
-                               put_queue(vc, 0xe0);
-                       put_queue(vc, (code & 0x7f) | up_flag);
+               code = x86_keycodes[keycode];
+               if (!code)
+                       return -1;
 
-                       break;
+               if (code & 0x100)
+                       put_queue(vc, 0xe0);
+               put_queue(vc, (code & 0x7f) | up_flag);
+
+               break;
        }
 
        return 0;
@@ -1088,8 +1132,6 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode,
 
 #define HW_RAW(dev)    0
 
-#warning "Cannot generate rawmode keyboard for your architecture yet."
-
 static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag)
 {
        if (keycode > 127)
@@ -1103,7 +1145,8 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char u
 static void kbd_rawcode(unsigned char data)
 {
        struct vc_data *vc = vc_cons[fg_console].d;
-       kbd = kbd_table + fg_console;
+
+       kbd = kbd_table + vc->vc_num;
        if (kbd->kbdmode == VC_RAW)
                put_queue(vc, data);
 }
@@ -1112,9 +1155,12 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
 {
        struct vc_data *vc = vc_cons[fg_console].d;
        unsigned short keysym, *key_map;
-       unsigned char type, raw_mode;
+       unsigned char type;
+       bool raw_mode;
        struct tty_struct *tty;
        int shift_final;
+       struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
+       int rc;
 
        tty = vc->vc_tty;
 
@@ -1123,10 +1169,8 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
                tty->driver_data = vc;
        }
 
-       kbd = kbd_table + fg_console;
+       kbd = kbd_table + vc->vc_num;
 
-       if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT)
-               sysrq_alt = down ? keycode : 0;
 #ifdef CONFIG_SPARC
        if (keycode == KEY_STOP)
                sparc_l1_a_state = down;
@@ -1134,34 +1178,16 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
 
        rep = (down == 2);
 
-#ifdef CONFIG_MAC_EMUMOUSEBTN
-       if (mac_hid_mouse_emulate_buttons(1, keycode, down))
-               return;
-#endif /* CONFIG_MAC_EMUMOUSEBTN */
-
-       if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
+       raw_mode = (kbd->kbdmode == VC_RAW);
+       if (raw_mode && !hw_raw)
                if (emulate_raw(vc, keycode, !down << 7))
                        if (keycode < BTN_MISC && printk_ratelimit())
-                               printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode);
+                               pr_warning("can't emulate rawmode for keycode %d\n",
+                                          keycode);
 
-#ifdef CONFIG_MAGIC_SYSRQ             /* Handle the SysRq Hack */
-       if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) {
-               if (!sysrq_down) {
-                       sysrq_down = down;
-                       sysrq_alt_use = sysrq_alt;
-               }
-               return;
-       }
-       if (sysrq_down && !down && keycode == sysrq_alt_use)
-               sysrq_down = 0;
-       if (sysrq_down && down && !rep) {
-               handle_sysrq(kbd_sysrq_xlate[keycode], tty);
-               return;
-       }
-#endif
 #ifdef CONFIG_SPARC
        if (keycode == KEY_A && sparc_l1_a_state) {
-               sparc_l1_a_state = 0;
+               sparc_l1_a_state = false;
                sun_do_break();
        }
 #endif
@@ -1183,7 +1209,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
                        put_queue(vc, (keycode >> 7) | 0x80);
                        put_queue(vc, keycode | 0x80);
                }
-               raw_mode = 1;
+               raw_mode = true;
        }
 
        if (down)
@@ -1193,7 +1219,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
 
        if (rep &&
            (!vc_kbd_mode(kbd, VC_REPEAT) ||
-            (tty && !L_ECHO(tty) && tty->driver->chars_in_buffer(tty)))) {
+            (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) {
                /*
                 * Don't repeat a key if the input buffers are not empty and the
                 * characters get aren't echoed locally. This makes key repeat
@@ -1202,36 +1228,41 @@ 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;
+       param.ledstate = kbd->ledflagstate;
        key_map = key_maps[shift_final];
 
-       if (!key_map) {
+       rc = atomic_notifier_call_chain(&keyboard_notifier_list,
+                                       KBD_KEYCODE, &param);
+       if (rc == NOTIFY_STOP || !key_map) {
+               atomic_notifier_call_chain(&keyboard_notifier_list,
+                                          KBD_UNBOUND_KEYCODE, &param);
                compute_shiftstate();
                kbd->slockstate = 0;
                return;
        }
 
-       if (keycode > NR_KEYS)
-               if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8)
-                       keysym = K(KT_BRL, keycode - KEY_BRL_DOT1 + 1);
-               else
-                       return;
-       else
+       if (keycode < NR_KEYS)
                keysym = key_map[keycode];
+       else if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8)
+               keysym = U(K(KT_BRL, keycode - KEY_BRL_DOT1 + 1));
+       else
+               return;
 
        type = KTYP(keysym);
 
        if (type < 0xf0) {
-               if (down && !raw_mode)
-                       to_utf8(vc, keysym);
+               param.value = keysym;
+               rc = atomic_notifier_call_chain(&keyboard_notifier_list,
+                                               KBD_UNICODE, &param);
+               if (rc != NOTIFY_STOP)
+                       if (down && !raw_mode)
+                               to_utf8(vc, keysym);
                return;
        }
 
        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)) {
@@ -1241,8 +1272,20 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
                }
        }
 
+       param.value = keysym;
+       rc = atomic_notifier_call_chain(&keyboard_notifier_list,
+                                       KBD_KEYSYM, &param);
+       if (rc == NOTIFY_STOP)
+               return;
+
+       if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
+               return;
+
        (*k_handler[type])(vc, keysym & 0xff, !down);
 
+       param.ledstate = kbd->ledflagstate;
+       atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, &param);
+
        if (type != KT_SLOCK)
                kbd->slockstate = 0;
 }
@@ -1250,15 +1293,36 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
 static void kbd_event(struct input_handle *handle, unsigned int event_type,
                      unsigned int event_code, int value)
 {
+       /* We are called with interrupts disabled, just take the lock */
+       spin_lock(&kbd_event_lock);
+
        if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
                kbd_rawcode(value);
        if (event_type == EV_KEY)
                kbd_keycode(event_code, value, HW_RAW(handle->dev));
+
+       spin_unlock(&kbd_event_lock);
+
        tasklet_schedule(&keyboard_tasklet);
        do_poke_blanked_console = 1;
        schedule_console_callback();
 }
 
+static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
+{
+       int i;
+
+       if (test_bit(EV_SND, dev->evbit))
+               return true;
+
+       if (test_bit(EV_KEY, dev->evbit))
+               for (i = KEY_RESERVED; i < BTN_MISC; i++)
+                       if (test_bit(i, dev->keybit))
+                               return true;
+
+       return false;
+}
+
 /*
  * When a keyboard (or other input device) is found, the kbd_connect
  * function is called. The function then looks at the device, and if it
@@ -1270,14 +1334,6 @@ static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
 {
        struct input_handle *handle;
        int error;
-       int i;
-
-       for (i = KEY_RESERVED; i < BTN_MISC; i++)
-               if (test_bit(i, dev->keybit))
-                       break;
-
-       if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
-               return -ENODEV;
 
        handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
        if (!handle)
@@ -1317,27 +1373,23 @@ static void kbd_disconnect(struct input_handle *handle)
  */
 static void kbd_start(struct input_handle *handle)
 {
-       unsigned char leds = ledstate;
-
        tasklet_disable(&keyboard_tasklet);
-       if (leds != 0xff) {
-               input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
-               input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
-               input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
-               input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
-       }
+
+       if (ledstate != 0xff)
+               kbd_update_leds_helper(handle, &ledstate);
+
        tasklet_enable(&keyboard_tasklet);
 }
 
 static const struct input_device_id kbd_ids[] = {
        {
                 .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-                .evbit = { BIT(EV_KEY) },
+                .evbit = { BIT_MASK(EV_KEY) },
         },
 
        {
                 .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-                .evbit = { BIT(EV_SND) },
+                .evbit = { BIT_MASK(EV_SND) },
         },
 
        { },    /* Terminating entry */
@@ -1347,6 +1399,7 @@ MODULE_DEVICE_TABLE(input, kbd_ids);
 
 static struct input_handler kbd_handler = {
        .event          = kbd_event,
+       .match          = kbd_match,
        .connect        = kbd_connect,
        .disconnect     = kbd_disconnect,
        .start          = kbd_start,
@@ -1366,7 +1419,7 @@ int __init kbd_init(void)
                kbd_table[i].lockstate = KBD_DEFLOCK;
                kbd_table[i].slockstate = 0;
                kbd_table[i].modeflags = KBD_DEFMODE;
-               kbd_table[i].kbdmode = VC_XLATE;
+               kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
        }
 
        error = input_register_handler(&kbd_handler);