]> bbs.cooldavid.org Git - net-next-2.6.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, 12 Nov 2010 17:52:31 +0000 (09:52 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 12 Nov 2010 17:52:31 +0000 (09:52 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: do not pass injected events back to the originating handler
  Input: pcf8574_keypad - fix error handling in pcf8574_kp_probe
  Input: acecad - fix a memory leak in usb_acecad_probe error path
  Input: atkbd - add 'terminal' parameter for IBM Terminal keyboards
  Input: i8042 - add Sony VAIOs to MUX blacklist
  kgdboc: reset input devices (keyboards) when exiting debugger
  Input: export input_reset_device() for use in KGDB
  Input: adp5588-keys - unify common header defines

drivers/input/input.c
drivers/input/keyboard/adp5588-keys.c
drivers/input/keyboard/atkbd.c
drivers/input/misc/pcf8574_keypad.c
drivers/input/serio/i8042-x86ia64io.h
drivers/input/tablet/acecad.c
drivers/serial/kgdboc.c
include/linux/i2c/adp5588.h
include/linux/input.h

index d092ef9291dabe1301006bc94310bc1973037808..7f26ca6ecf75dc6f15185771a8bae6cfb24ce58d 100644 (file)
@@ -74,6 +74,7 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
  * dev->event_lock held and interrupts disabled.
  */
 static void input_pass_event(struct input_dev *dev,
+                            struct input_handler *src_handler,
                             unsigned int type, unsigned int code, int value)
 {
        struct input_handler *handler;
@@ -92,6 +93,15 @@ static void input_pass_event(struct input_dev *dev,
                                continue;
 
                        handler = handle->handler;
+
+                       /*
+                        * If this is the handler that injected this
+                        * particular event we want to skip it to avoid
+                        * filters firing again and again.
+                        */
+                       if (handler == src_handler)
+                               continue;
+
                        if (!handler->filter) {
                                if (filtered)
                                        break;
@@ -121,7 +131,7 @@ static void input_repeat_key(unsigned long data)
        if (test_bit(dev->repeat_key, dev->key) &&
            is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
 
-               input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
+               input_pass_event(dev, NULL, EV_KEY, dev->repeat_key, 2);
 
                if (dev->sync) {
                        /*
@@ -130,7 +140,7 @@ static void input_repeat_key(unsigned long data)
                         * Otherwise assume that the driver will send
                         * SYN_REPORT once it's done.
                         */
-                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+                       input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
                }
 
                if (dev->rep[REP_PERIOD])
@@ -163,6 +173,7 @@ static void input_stop_autorepeat(struct input_dev *dev)
 #define INPUT_PASS_TO_ALL      (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
 
 static int input_handle_abs_event(struct input_dev *dev,
+                                 struct input_handler *src_handler,
                                  unsigned int code, int *pval)
 {
        bool is_mt_event;
@@ -206,13 +217,15 @@ static int input_handle_abs_event(struct input_dev *dev,
        /* Flush pending "slot" event */
        if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
                input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
-               input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
+               input_pass_event(dev, src_handler,
+                                EV_ABS, ABS_MT_SLOT, dev->slot);
        }
 
        return INPUT_PASS_TO_HANDLERS;
 }
 
 static void input_handle_event(struct input_dev *dev,
+                              struct input_handler *src_handler,
                               unsigned int type, unsigned int code, int value)
 {
        int disposition = INPUT_IGNORE_EVENT;
@@ -265,7 +278,8 @@ static void input_handle_event(struct input_dev *dev,
 
        case EV_ABS:
                if (is_event_supported(code, dev->absbit, ABS_MAX))
-                       disposition = input_handle_abs_event(dev, code, &value);
+                       disposition = input_handle_abs_event(dev, src_handler,
+                                                            code, &value);
 
                break;
 
@@ -323,7 +337,7 @@ static void input_handle_event(struct input_dev *dev,
                dev->event(dev, type, code, value);
 
        if (disposition & INPUT_PASS_TO_HANDLERS)
-               input_pass_event(dev, type, code, value);
+               input_pass_event(dev, src_handler, type, code, value);
 }
 
 /**
@@ -352,7 +366,7 @@ void input_event(struct input_dev *dev,
 
                spin_lock_irqsave(&dev->event_lock, flags);
                add_input_randomness(type, code, value);
-               input_handle_event(dev, type, code, value);
+               input_handle_event(dev, NULL, type, code, value);
                spin_unlock_irqrestore(&dev->event_lock, flags);
        }
 }
@@ -382,7 +396,8 @@ void input_inject_event(struct input_handle *handle,
                rcu_read_lock();
                grab = rcu_dereference(dev->grab);
                if (!grab || grab == handle)
-                       input_handle_event(dev, type, code, value);
+                       input_handle_event(dev, handle->handler,
+                                          type, code, value);
                rcu_read_unlock();
 
                spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -595,10 +610,10 @@ static void input_dev_release_keys(struct input_dev *dev)
                for (code = 0; code <= KEY_MAX; code++) {
                        if (is_event_supported(code, dev->keybit, KEY_MAX) &&
                            __test_and_clear_bit(code, dev->key)) {
-                               input_pass_event(dev, EV_KEY, code, 0);
+                               input_pass_event(dev, NULL, EV_KEY, code, 0);
                        }
                }
-               input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+               input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
        }
 }
 
@@ -873,9 +888,9 @@ int input_set_keycode(struct input_dev *dev,
            !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
            __test_and_clear_bit(old_keycode, dev->key)) {
 
-               input_pass_event(dev, EV_KEY, old_keycode, 0);
+               input_pass_event(dev, NULL, EV_KEY, old_keycode, 0);
                if (dev->sync)
-                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+                       input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
        }
 
  out:
@@ -1565,8 +1580,7 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
                }                                                       \
        } while (0)
 
-#ifdef CONFIG_PM
-static void input_dev_reset(struct input_dev *dev, bool activate)
+static void input_dev_toggle(struct input_dev *dev, bool activate)
 {
        if (!dev->event)
                return;
@@ -1580,12 +1594,44 @@ static void input_dev_reset(struct input_dev *dev, bool activate)
        }
 }
 
+/**
+ * input_reset_device() - reset/restore the state of input device
+ * @dev: input device whose state needs to be reset
+ *
+ * This function tries to reset the state of an opened input device and
+ * bring internal state and state if the hardware in sync with each other.
+ * We mark all keys as released, restore LED state, repeat rate, etc.
+ */
+void input_reset_device(struct input_dev *dev)
+{
+       mutex_lock(&dev->mutex);
+
+       if (dev->users) {
+               input_dev_toggle(dev, true);
+
+               /*
+                * Keys that have been pressed at suspend time are unlikely
+                * to be still pressed when we resume.
+                */
+               spin_lock_irq(&dev->event_lock);
+               input_dev_release_keys(dev);
+               spin_unlock_irq(&dev->event_lock);
+       }
+
+       mutex_unlock(&dev->mutex);
+}
+EXPORT_SYMBOL(input_reset_device);
+
+#ifdef CONFIG_PM
 static int input_dev_suspend(struct device *dev)
 {
        struct input_dev *input_dev = to_input_dev(dev);
 
        mutex_lock(&input_dev->mutex);
-       input_dev_reset(input_dev, false);
+
+       if (input_dev->users)
+               input_dev_toggle(input_dev, false);
+
        mutex_unlock(&input_dev->mutex);
 
        return 0;
@@ -1595,18 +1641,7 @@ static int input_dev_resume(struct device *dev)
 {
        struct input_dev *input_dev = to_input_dev(dev);
 
-       mutex_lock(&input_dev->mutex);
-       input_dev_reset(input_dev, true);
-
-       /*
-        * Keys that have been pressed at suspend time are unlikely
-        * to be still pressed when we resume.
-        */
-       spin_lock_irq(&input_dev->event_lock);
-       input_dev_release_keys(input_dev);
-       spin_unlock_irq(&input_dev->event_lock);
-
-       mutex_unlock(&input_dev->mutex);
+       input_reset_device(input_dev);
 
        return 0;
 }
index b92d1cd5cba1e4ee83923b7bce43c80a7075f5b8..af45d275f6862924979f48def9b1aa43ece095eb 100644 (file)
@@ -4,7 +4,7 @@
  *              I2C QWERTY Keypad and IO Expander
  * Bugs: Enter bugs at http://blackfin.uclinux.org/
  *
- * Copyright (C) 2008-2009 Analog Devices Inc.
+ * Copyright (C) 2008-2010 Analog Devices Inc.
  * Licensed under the GPL-2 or later.
  */
 
 
 #include <linux/i2c/adp5588.h>
 
- /* Configuration Register1 */
-#define AUTO_INC       (1 << 7)
-#define GPIEM_CFG      (1 << 6)
-#define OVR_FLOW_M     (1 << 5)
-#define INT_CFG                (1 << 4)
-#define OVR_FLOW_IEN   (1 << 3)
-#define K_LCK_IM       (1 << 2)
-#define GPI_IEN                (1 << 1)
-#define KE_IEN         (1 << 0)
-
-/* Interrupt Status Register */
-#define CMP2_INT       (1 << 5)
-#define CMP1_INT       (1 << 4)
-#define OVR_FLOW_INT   (1 << 3)
-#define K_LCK_INT      (1 << 2)
-#define GPI_INT                (1 << 1)
-#define KE_INT         (1 << 0)
-
-/* Key Lock and Event Counter Register */
-#define K_LCK_EN       (1 << 6)
-#define LCK21          0x30
-#define KEC            0xF
-
 /* Key Event Register xy */
 #define KEY_EV_PRESSED         (1 << 7)
 #define KEY_EV_MASK            (0x7F)
 
 #define KEYP_MAX_EVENT         10
 
-#define MAXGPIO                        18
-#define ADP_BANK(offs)         ((offs) >> 3)
-#define ADP_BIT(offs)          (1u << ((offs) & 0x7))
-
 /*
  * Early pre 4.0 Silicon required to delay readout by at least 25ms,
  * since the Event Counter Register updated 25ms after the interrupt
@@ -75,7 +48,7 @@ struct adp5588_kpad {
        const struct adp5588_gpi_map *gpimap;
        unsigned short gpimapsize;
 #ifdef CONFIG_GPIOLIB
-       unsigned char gpiomap[MAXGPIO];
+       unsigned char gpiomap[ADP5588_MAXGPIO];
        bool export_gpio;
        struct gpio_chip gc;
        struct mutex gpio_lock; /* Protect cached dir, dat_out */
@@ -103,8 +76,8 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
 static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
 {
        struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
-       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
-       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
 
        return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
 }
@@ -113,8 +86,8 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip,
                                   unsigned off, int val)
 {
        struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
-       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
-       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
 
        mutex_lock(&kpad->gpio_lock);
 
@@ -132,8 +105,8 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip,
 static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
 {
        struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
-       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
-       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
        int ret;
 
        mutex_lock(&kpad->gpio_lock);
@@ -150,8 +123,8 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
                                         unsigned off, int val)
 {
        struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
-       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
-       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
        int ret;
 
        mutex_lock(&kpad->gpio_lock);
@@ -176,7 +149,7 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
 static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
                                const struct adp5588_kpad_platform_data *pdata)
 {
-       bool pin_used[MAXGPIO];
+       bool pin_used[ADP5588_MAXGPIO];
        int n_unused = 0;
        int i;
 
@@ -191,7 +164,7 @@ static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
        for (i = 0; i < kpad->gpimapsize; i++)
                pin_used[kpad->gpimap[i].pin - GPI_PIN_BASE] = true;
 
-       for (i = 0; i < MAXGPIO; i++)
+       for (i = 0; i < ADP5588_MAXGPIO; i++)
                if (!pin_used[i])
                        kpad->gpiomap[n_unused++] = i;
 
@@ -234,7 +207,7 @@ static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad)
                return error;
        }
 
-       for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+       for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
                kpad->dat_out[i] = adp5588_read(kpad->client,
                                                GPIO_DAT_OUT1 + i);
                kpad->dir[i] = adp5588_read(kpad->client, GPIO_DIR1 + i);
@@ -318,11 +291,11 @@ static void adp5588_work(struct work_struct *work)
 
        status = adp5588_read(client, INT_STAT);
 
-       if (status & OVR_FLOW_INT)      /* Unlikely and should never happen */
+       if (status & ADP5588_OVR_FLOW_INT)      /* Unlikely and should never happen */
                dev_err(&client->dev, "Event Overflow Error\n");
 
-       if (status & KE_INT) {
-               ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC;
+       if (status & ADP5588_KE_INT) {
+               ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & ADP5588_KEC;
                if (ev_cnt) {
                        adp5588_report_events(kpad, ev_cnt);
                        input_sync(kpad->input);
@@ -360,7 +333,7 @@ static int __devinit adp5588_setup(struct i2c_client *client)
        if (pdata->en_keylock) {
                ret |= adp5588_write(client, UNLOCK1, pdata->unlock_key1);
                ret |= adp5588_write(client, UNLOCK2, pdata->unlock_key2);
-               ret |= adp5588_write(client, KEY_LCK_EC_STAT, K_LCK_EN);
+               ret |= adp5588_write(client, KEY_LCK_EC_STAT, ADP5588_K_LCK_EN);
        }
 
        for (i = 0; i < KEYP_MAX_EVENT; i++)
@@ -384,7 +357,7 @@ static int __devinit adp5588_setup(struct i2c_client *client)
        }
 
        if (gpio_data) {
-               for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+               for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
                        int pull_mask = gpio_data->pullup_dis_mask;
 
                        ret |= adp5588_write(client, GPIO_PULL1 + i,
@@ -392,11 +365,14 @@ static int __devinit adp5588_setup(struct i2c_client *client)
                }
        }
 
-       ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
-                                       OVR_FLOW_INT | K_LCK_INT |
-                                       GPI_INT | KE_INT); /* Status is W1C */
+       ret |= adp5588_write(client, INT_STAT,
+                               ADP5588_CMP2_INT | ADP5588_CMP1_INT |
+                               ADP5588_OVR_FLOW_INT | ADP5588_K_LCK_INT |
+                               ADP5588_GPI_INT | ADP5588_KE_INT); /* Status is W1C */
 
-       ret |= adp5588_write(client, CFG, INT_CFG | OVR_FLOW_IEN | KE_IEN);
+       ret |= adp5588_write(client, CFG, ADP5588_INT_CFG |
+                                         ADP5588_OVR_FLOW_IEN |
+                                         ADP5588_KE_IEN);
 
        if (ret < 0) {
                dev_err(&client->dev, "Write Error\n");
index d358ef8623f490709875b901d82580b1afc7a7fc..11478eb2c27de1ec332b8f3e4a5b1a56408b49ce 100644 (file)
@@ -63,6 +63,10 @@ static bool atkbd_extra;
 module_param_named(extra, atkbd_extra, bool, 0);
 MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
 
+static bool atkbd_terminal;
+module_param_named(terminal, atkbd_terminal, bool, 0);
+MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
+
 /*
  * Scancode to keycode tables. These are just the default setting, and
  * are loadable via a userland utility.
@@ -136,7 +140,8 @@ static const unsigned short atkbd_unxlate_table[128] = {
 #define ATKBD_CMD_ENABLE       0x00f4
 #define ATKBD_CMD_RESET_DIS    0x00f5  /* Reset to defaults and disable */
 #define ATKBD_CMD_RESET_DEF    0x00f6  /* Reset to defaults */
-#define ATKBD_CMD_SETALL_MBR   0x00fa
+#define ATKBD_CMD_SETALL_MB    0x00f8  /* Set all keys to give break codes */
+#define ATKBD_CMD_SETALL_MBR   0x00fa  /* ... and repeat */
 #define ATKBD_CMD_RESET_BAT    0x02ff
 #define ATKBD_CMD_RESEND       0x00fe
 #define ATKBD_CMD_EX_ENABLE    0x10ea
@@ -764,6 +769,11 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
                }
        }
 
+       if (atkbd_terminal) {
+               ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MB);
+               return 3;
+       }
+
        if (target_set != 3)
                return 2;
 
index 4b42ffc0532af1c6a3b36ca64ab411decfac89d9..d1583aea17212b72e4b30f69c5a640d42652dfe2 100644 (file)
@@ -127,14 +127,6 @@ static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2
        idev->id.product = 0x0001;
        idev->id.version = 0x0100;
 
-       input_set_drvdata(idev, lp);
-
-       ret = input_register_device(idev);
-       if (ret) {
-               dev_err(&client->dev, "input_register_device() failed\n");
-               goto fail_register;
-       }
-
        lp->laststate = read_state(lp);
 
        ret = request_threaded_irq(client->irq, NULL, pcf8574_kp_irq_handler,
@@ -142,16 +134,21 @@ static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2
                                   DRV_NAME, lp);
        if (ret) {
                dev_err(&client->dev, "IRQ %d is not free\n", client->irq);
-               goto fail_irq;
+               goto fail_free_device;
+       }
+
+       ret = input_register_device(idev);
+       if (ret) {
+               dev_err(&client->dev, "input_register_device() failed\n");
+               goto fail_free_irq;
        }
 
        i2c_set_clientdata(client, lp);
        return 0;
 
- fail_irq:
-       input_unregister_device(idev);
- fail_register:
-       input_set_drvdata(idev, NULL);
+ fail_free_irq:
+       free_irq(client->irq, lp);
+ fail_free_device:
        input_free_device(idev);
  fail_allocate:
        kfree(lp);
index ed7ad7416b24d8f40c9cccd61d8371f732b73441..a5475b5770863298609f7ab40850e03286529046 100644 (file)
@@ -350,6 +350,17 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"),
                },
        },
+       {
+               /*
+                * Most (all?) VAIOs do not have external PS/2 ports nor
+                * they implement active multiplexing properly, and
+                * MUX discovery usually messes up keyboard/touchpad.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                       DMI_MATCH(DMI_BOARD_NAME, "VAIO"),
+               },
+       },
        {
                /* Amoi M636/A737 */
                .matches = {
index aea9a9399a36b43a18663b4fd46d8bd3c7303808..d94f7e9aa997f13cbafba7739d59a234bf117726 100644 (file)
@@ -229,12 +229,13 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
 
        err = input_register_device(acecad->input);
        if (err)
-               goto fail2;
+               goto fail3;
 
        usb_set_intfdata(intf, acecad);
 
        return 0;
 
+ fail3:        usb_free_urb(acecad->irq);
  fail2:        usb_free_coherent(dev, 8, acecad->data, acecad->data_dma);
  fail1: input_free_device(input_dev);
        kfree(acecad);
index d4b711c9a416c79bbfd242a248a51d3589eb2a15..3374618300af87c16ac3ef6a674e9cb650e62f8c 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/vt_kern.h>
+#include <linux/input.h>
 
 #define MAX_CONFIG_LEN         40
 
@@ -37,6 +38,61 @@ static struct tty_driver     *kgdb_tty_driver;
 static int                     kgdb_tty_line;
 
 #ifdef CONFIG_KDB_KEYBOARD
+static int kgdboc_reset_connect(struct input_handler *handler,
+                               struct input_dev *dev,
+                               const struct input_device_id *id)
+{
+       input_reset_device(dev);
+
+       /* Retrun an error - we do not want to bind, just to reset */
+       return -ENODEV;
+}
+
+static void kgdboc_reset_disconnect(struct input_handle *handle)
+{
+       /* We do not expect anyone to actually bind to us */
+       BUG();
+}
+
+static const struct input_device_id kgdboc_reset_ids[] = {
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+               .evbit = { BIT_MASK(EV_KEY) },
+       },
+       { }
+};
+
+static struct input_handler kgdboc_reset_handler = {
+       .connect        = kgdboc_reset_connect,
+       .disconnect     = kgdboc_reset_disconnect,
+       .name           = "kgdboc_reset",
+       .id_table       = kgdboc_reset_ids,
+};
+
+static DEFINE_MUTEX(kgdboc_reset_mutex);
+
+static void kgdboc_restore_input_helper(struct work_struct *dummy)
+{
+       /*
+        * We need to take a mutex to prevent several instances of
+        * this work running on different CPUs so they don't try
+        * to register again already registered handler.
+        */
+       mutex_lock(&kgdboc_reset_mutex);
+
+       if (input_register_handler(&kgdboc_reset_handler) == 0)
+               input_unregister_handler(&kgdboc_reset_handler);
+
+       mutex_unlock(&kgdboc_reset_mutex);
+}
+
+static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper);
+
+static void kgdboc_restore_input(void)
+{
+       schedule_work(&kgdboc_restore_input_work);
+}
+
 static int kgdboc_register_kbd(char **cptr)
 {
        if (strncmp(*cptr, "kbd", 3) == 0) {
@@ -64,10 +120,12 @@ static void kgdboc_unregister_kbd(void)
                        i--;
                }
        }
+       flush_work_sync(&kgdboc_restore_input_work);
 }
 #else /* ! CONFIG_KDB_KEYBOARD */
 #define kgdboc_register_kbd(x) 0
 #define kgdboc_unregister_kbd()
+#define kgdboc_restore_input()
 #endif /* ! CONFIG_KDB_KEYBOARD */
 
 static int kgdboc_option_setup(char *opt)
@@ -231,6 +289,7 @@ static void kgdboc_post_exp_handler(void)
                dbg_restore_graphics = 0;
                con_debug_leave();
        }
+       kgdboc_restore_input();
 }
 
 static struct kgdb_io kgdboc_io_ops = {
index 3c5d6b6e765c22b06f6125a606eef9b5107958aa..cec17cf6cac2b6044d820066419164d2faeccabc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Analog Devices ADP5588 I/O Expander and QWERTY Keypad Controller
  *
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2010 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later.
  */
  /* Configuration Register1 */
 #define ADP5588_AUTO_INC       (1 << 7)
 #define ADP5588_GPIEM_CFG      (1 << 6)
+#define ADP5588_OVR_FLOW_M     (1 << 5)
 #define ADP5588_INT_CFG                (1 << 4)
+#define ADP5588_OVR_FLOW_IEN   (1 << 3)
+#define ADP5588_K_LCK_IM       (1 << 2)
 #define ADP5588_GPI_IEN                (1 << 1)
+#define ADP5588_KE_IEN         (1 << 0)
 
 /* Interrupt Status Register */
+#define ADP5588_CMP2_INT       (1 << 5)
+#define ADP5588_CMP1_INT       (1 << 4)
+#define ADP5588_OVR_FLOW_INT   (1 << 3)
+#define ADP5588_K_LCK_INT      (1 << 2)
 #define ADP5588_GPI_INT                (1 << 1)
 #define ADP5588_KE_INT         (1 << 0)
 
+/* Key Lock and Event Counter Register */
+#define ADP5588_K_LCK_EN       (1 << 6)
+#define ADP5588_LCK21          0x30
+#define ADP5588_KEC            0xF
+
 #define ADP5588_MAXGPIO                18
 #define ADP5588_BANK(offs)     ((offs) >> 3)
 #define ADP5588_BIT(offs)      (1u << ((offs) & 0x7))
index 51af441f3a21268fe40f8b78810d801cdc5b6416..6ef44465db8ddc31c41be1de00eeef38c53b5fa5 100644 (file)
@@ -1406,6 +1406,8 @@ static inline void input_set_drvdata(struct input_dev *dev, void *data)
 int __must_check input_register_device(struct input_dev *);
 void input_unregister_device(struct input_dev *);
 
+void input_reset_device(struct input_dev *);
+
 int __must_check input_register_handler(struct input_handler *);
 void input_unregister_handler(struct input_handler *);
 
@@ -1421,7 +1423,7 @@ void input_release_device(struct input_handle *);
 int input_open_device(struct input_handle *);
 void input_close_device(struct input_handle *);
 
-int input_flush_device(struct input_handle* handle, struct file* file);
+int input_flush_device(struct input_handle *handle, struct file *file);
 
 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
 void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value);