]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 19 Nov 2010 18:31:04 +0000 (10:31 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 19 Nov 2010 18:31:04 +0000 (10:31 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: fix typo in keycode validation supporting large scancodes
  Input: aiptek - tighten up permissions on sysfs attributes
  Input: sysrq - pass along lone Alt + SysRq

1  2 
drivers/input/input.c
drivers/tty/sysrq.c

diff --combined drivers/input/input.c
index 90b7ecfb625757ee9505480566c26f6baed32a6a,5edc41aa08f8cf56336365f75b514b2274d31dd5..db409d6bd5d2b9672ad94f370564f870bed25b19
@@@ -24,6 -24,7 +24,6 @@@
  #include <linux/device.h>
  #include <linux/mutex.h>
  #include <linux/rcupdate.h>
 -#include <linux/smp_lock.h>
  #include "input-compat.h"
  
  MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
@@@ -752,7 -753,7 +752,7 @@@ static int input_default_setkeycode(str
        if (index >= dev->keycodemax)
                return -EINVAL;
  
-       if (dev->keycodesize < sizeof(dev->keycode) &&
+       if (dev->keycodesize < sizeof(ke->keycode) &&
                        (ke->keycode >> (dev->keycodesize * 8)))
                return -EINVAL;
  
diff --combined drivers/tty/sysrq.c
index eaa5d3efa79da4cb061b4fbaf9d6acb6f21afd5e,c556ed9db13d82a4bd7dcff1bb599dce6abd8341..c556ed9db13d82a4bd7dcff1bb599dce6abd8341
@@@ -554,7 -554,7 +554,7 @@@ EXPORT_SYMBOL(handle_sysrq)
  #ifdef CONFIG_INPUT
  
  /* Simple translation table for the SysRq keys */
- static const unsigned char sysrq_xlate[KEY_MAX + 1] =
+ static const unsigned char sysrq_xlate[KEY_CNT] =
          "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
          "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
          "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
          "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
          "\r\000/";                                      /* 0x60 - 0x6f */
  
- static bool sysrq_down;
- static int sysrq_alt_use;
- static int sysrq_alt;
- static DEFINE_SPINLOCK(sysrq_event_lock);
+ struct sysrq_state {
+       struct input_handle handle;
+       struct work_struct reinject_work;
+       unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];
+       unsigned int alt;
+       unsigned int alt_use;
+       bool active;
+       bool need_reinject;
+ };
+ static void sysrq_reinject_alt_sysrq(struct work_struct *work)
+ {
+       struct sysrq_state *sysrq =
+                       container_of(work, struct sysrq_state, reinject_work);
+       struct input_handle *handle = &sysrq->handle;
+       unsigned int alt_code = sysrq->alt_use;
+       if (sysrq->need_reinject) {
+               /* Simulate press and release of Alt + SysRq */
+               input_inject_event(handle, EV_KEY, alt_code, 1);
+               input_inject_event(handle, EV_KEY, KEY_SYSRQ, 1);
+               input_inject_event(handle, EV_SYN, SYN_REPORT, 1);
+               input_inject_event(handle, EV_KEY, KEY_SYSRQ, 0);
+               input_inject_event(handle, EV_KEY, alt_code, 0);
+               input_inject_event(handle, EV_SYN, SYN_REPORT, 1);
+       }
+ }
  
- static bool sysrq_filter(struct input_handle *handle, unsigned int type,
-                        unsigned int code, int value)
+ static bool sysrq_filter(struct input_handle *handle,
+                        unsigned int type, unsigned int code, int value)
  {
+       struct sysrq_state *sysrq = handle->private;
+       bool was_active = sysrq->active;
        bool suppress;
  
-       /* We are called with interrupts disabled, just take the lock */
-       spin_lock(&sysrq_event_lock);
+       switch (type) {
  
-       if (type != EV_KEY)
-               goto out;
+       case EV_SYN:
+               suppress = false;
+               break;
  
-       switch (code) {
+       case EV_KEY:
+               switch (code) {
  
-       case KEY_LEFTALT:
-       case KEY_RIGHTALT:
-               if (value)
-                       sysrq_alt = code;
-               else {
-                       if (sysrq_down && code == sysrq_alt_use)
-                               sysrq_down = false;
+               case KEY_LEFTALT:
+               case KEY_RIGHTALT:
+                       if (!value) {
+                               /* One of ALTs is being released */
+                               if (sysrq->active && code == sysrq->alt_use)
+                                       sysrq->active = false;
  
-                       sysrq_alt = 0;
+                               sysrq->alt = KEY_RESERVED;
+                       } else if (value != 2) {
+                               sysrq->alt = code;
+                               sysrq->need_reinject = false;
+                       }
+                       break;
+               case KEY_SYSRQ:
+                       if (value == 1 && sysrq->alt != KEY_RESERVED) {
+                               sysrq->active = true;
+                               sysrq->alt_use = sysrq->alt;
+                               /*
+                                * If nothing else will be pressed we'll need
+                                * to * re-inject Alt-SysRq keysroke.
+                                */
+                               sysrq->need_reinject = true;
+                       }
+                       /*
+                        * Pretend that sysrq was never pressed at all. This
+                        * is needed to properly handle KGDB which will try
+                        * to release all keys after exiting debugger. If we
+                        * do not clear key bit it KGDB will end up sending
+                        * release events for Alt and SysRq, potentially
+                        * triggering print screen function.
+                        */
+                       if (sysrq->active)
+                               clear_bit(KEY_SYSRQ, handle->dev->key);
+                       break;
+               default:
+                       if (sysrq->active && value && value != 2) {
+                               sysrq->need_reinject = false;
+                               __handle_sysrq(sysrq_xlate[code], true);
+                       }
+                       break;
                }
-               break;
  
-       case KEY_SYSRQ:
-               if (value == 1 && sysrq_alt) {
-                       sysrq_down = true;
-                       sysrq_alt_use = sysrq_alt;
+               suppress = sysrq->active;
+               if (!sysrq->active) {
+                       /*
+                        * If we are not suppressing key presses keep track of
+                        * keyboard state so we can release keys that have been
+                        * pressed before entering SysRq mode.
+                        */
+                       if (value)
+                               set_bit(code, sysrq->key_down);
+                       else
+                               clear_bit(code, sysrq->key_down);
+                       if (was_active)
+                               schedule_work(&sysrq->reinject_work);
+               } else if (value == 0 &&
+                          test_and_clear_bit(code, sysrq->key_down)) {
+                       /*
+                        * Pass on release events for keys that was pressed before
+                        * entering SysRq mode.
+                        */
+                       suppress = false;
                }
                break;
  
        default:
-               if (sysrq_down && value && value != 2)
-                       __handle_sysrq(sysrq_xlate[code], true);
+               suppress = sysrq->active;
                break;
        }
  
- out:
-       suppress = sysrq_down;
-       spin_unlock(&sysrq_event_lock);
        return suppress;
  }
  
@@@ -617,28 -693,28 +693,28 @@@ static int sysrq_connect(struct input_h
                         struct input_dev *dev,
                         const struct input_device_id *id)
  {
-       struct input_handle *handle;
+       struct sysrq_state *sysrq;
        int error;
  
-       sysrq_down = false;
-       sysrq_alt = 0;
-       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
-       if (!handle)
+       sysrq = kzalloc(sizeof(struct sysrq_state), GFP_KERNEL);
+       if (!sysrq)
                return -ENOMEM;
  
-       handle->dev = dev;
-       handle->handler = handler;
-       handle->name = "sysrq";
+       INIT_WORK(&sysrq->reinject_work, sysrq_reinject_alt_sysrq);
+       sysrq->handle.dev = dev;
+       sysrq->handle.handler = handler;
+       sysrq->handle.name = "sysrq";
+       sysrq->handle.private = sysrq;
  
-       error = input_register_handle(handle);
+       error = input_register_handle(&sysrq->handle);
        if (error) {
                pr_err("Failed to register input sysrq handler, error %d\n",
                        error);
                goto err_free;
        }
  
-       error = input_open_device(handle);
+       error = input_open_device(&sysrq->handle);
        if (error) {
                pr_err("Failed to open input device, error %d\n", error);
                goto err_unregister;
        return 0;
  
   err_unregister:
-       input_unregister_handle(handle);
+       input_unregister_handle(&sysrq->handle);
   err_free:
-       kfree(handle);
+       kfree(sysrq);
        return error;
  }
  
  static void sysrq_disconnect(struct input_handle *handle)
  {
+       struct sysrq_state *sysrq = handle->private;
        input_close_device(handle);
+       cancel_work_sync(&sysrq->reinject_work);
        input_unregister_handle(handle);
-       kfree(handle);
+       kfree(sysrq);
  }
  
  /*