Upgrade to 4.4.50-rt62
[kvmfornfv.git] / kernel / drivers / input / serio / i8042.c
index cb5ece7..89abfdb 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/platform_device.h>
 #include <linux/i8042.h>
 #include <linux/slab.h>
+#include <linux/suspend.h>
 
 #include <asm/io.h>
 
@@ -47,9 +48,39 @@ static bool i8042_unlock;
 module_param_named(unlock, i8042_unlock, bool, 0);
 MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
 
-static bool i8042_reset;
-module_param_named(reset, i8042_reset, bool, 0);
-MODULE_PARM_DESC(reset, "Reset controller during init and cleanup.");
+enum i8042_controller_reset_mode {
+       I8042_RESET_NEVER,
+       I8042_RESET_ALWAYS,
+       I8042_RESET_ON_S2RAM,
+#define I8042_RESET_DEFAULT    I8042_RESET_ON_S2RAM
+};
+static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT;
+static int i8042_set_reset(const char *val, const struct kernel_param *kp)
+{
+       enum i8042_controller_reset_mode *arg = kp->arg;
+       int error;
+       bool reset;
+
+       if (val) {
+               error = kstrtobool(val, &reset);
+               if (error)
+                       return error;
+       } else {
+               reset = true;
+       }
+
+       *arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER;
+       return 0;
+}
+
+static const struct kernel_param_ops param_ops_reset_param = {
+       .flags = KERNEL_PARAM_OPS_FL_NOARG,
+       .set = i8042_set_reset,
+};
+#define param_check_reset_param(name, p)       \
+       __param_check(name, p, enum i8042_controller_reset_mode)
+module_param_named(reset, i8042_reset, reset_param, 0);
+MODULE_PARM_DESC(reset, "Reset controller on resume, cleanup or both");
 
 static bool i8042_direct;
 module_param_named(direct, i8042_direct, bool, 0);
@@ -88,6 +119,10 @@ MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
 static bool i8042_debug;
 module_param_named(debug, i8042_debug, bool, 0600);
 MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off");
+
+static bool i8042_unmask_kbd_data;
+module_param_named(unmask_kbd_data, i8042_unmask_kbd_data, bool, 0600);
+MODULE_PARM_DESC(unmask_kbd_data, "Unconditional enable (may reveal sensitive data) of normally sanitize-filtered kbd data traffic debug log [pre-condition: i8042.debug=1 enabled]");
 #endif
 
 static bool i8042_bypass_aux_irq_test;
@@ -116,6 +151,7 @@ struct i8042_port {
        struct serio *serio;
        int irq;
        bool exists;
+       bool driver_bound;
        signed char mux;
 };
 
@@ -133,6 +169,7 @@ static bool i8042_kbd_irq_registered;
 static bool i8042_aux_irq_registered;
 static unsigned char i8042_suppress_kbd_ack;
 static struct platform_device *i8042_platform_device;
+static struct notifier_block i8042_kbd_bind_notifier_block;
 
 static irqreturn_t i8042_interrupt(int irq, void *dev_id);
 static bool (*i8042_platform_filter)(unsigned char data, unsigned char str,
@@ -528,10 +565,10 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
        port = &i8042_ports[port_no];
        serio = port->exists ? port->serio : NULL;
 
-       dbg("%02x <- i8042 (interrupt, %d, %d%s%s)\n",
-           data, port_no, irq,
-           dfl & SERIO_PARITY ? ", bad parity" : "",
-           dfl & SERIO_TIMEOUT ? ", timeout" : "");
+       filter_dbg(port->driver_bound, data, "<- i8042 (interrupt, %d, %d%s%s)\n",
+                  port_no, irq,
+                  dfl & SERIO_PARITY ? ", bad parity" : "",
+                  dfl & SERIO_TIMEOUT ? ", timeout" : "");
 
        filtered = i8042_filter(data, str, serio);
 
@@ -871,7 +908,7 @@ static int __init i8042_check_aux(void)
 static int i8042_controller_check(void)
 {
        if (i8042_flush()) {
-               pr_err("No controller found\n");
+               pr_info("No controller found\n");
                return -ENODEV;
        }
 
@@ -1012,7 +1049,7 @@ static int i8042_controller_init(void)
  * Reset the controller and reset CRT to the original value set by BIOS.
  */
 
-static void i8042_controller_reset(bool force_reset)
+static void i8042_controller_reset(bool s2r_wants_reset)
 {
        i8042_flush();
 
@@ -1037,8 +1074,10 @@ static void i8042_controller_reset(bool force_reset)
  * Reset the controller if requested.
  */
 
-       if (i8042_reset || force_reset)
+       if (i8042_reset == I8042_RESET_ALWAYS ||
+           (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
                i8042_controller_selftest();
+       }
 
 /*
  * Restore the original control register setting.
@@ -1103,7 +1142,7 @@ static void i8042_dritek_enable(void)
  * before suspending.
  */
 
-static int i8042_controller_resume(bool force_reset)
+static int i8042_controller_resume(bool s2r_wants_reset)
 {
        int error;
 
@@ -1111,7 +1150,8 @@ static int i8042_controller_resume(bool force_reset)
        if (error)
                return error;
 
-       if (i8042_reset || force_reset) {
+       if (i8042_reset == I8042_RESET_ALWAYS ||
+           (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
                error = i8042_controller_selftest();
                if (error)
                        return error;
@@ -1164,7 +1204,8 @@ static int i8042_pm_suspend(struct device *dev)
 {
        int i;
 
-       i8042_controller_reset(true);
+       if (pm_suspend_via_firmware())
+               i8042_controller_reset(true);
 
        /* Set up serio interrupts for system wakeup. */
        for (i = 0; i < I8042_NUM_PORTS; i++) {
@@ -1177,8 +1218,17 @@ static int i8042_pm_suspend(struct device *dev)
        return 0;
 }
 
+static int i8042_pm_resume_noirq(struct device *dev)
+{
+       if (!pm_resume_via_firmware())
+               i8042_interrupt(0, NULL);
+
+       return 0;
+}
+
 static int i8042_pm_resume(struct device *dev)
 {
+       bool want_reset;
        int i;
 
        for (i = 0; i < I8042_NUM_PORTS; i++) {
@@ -1189,11 +1239,21 @@ static int i8042_pm_resume(struct device *dev)
        }
 
        /*
-        * On resume from S2R we always try to reset the controller
-        * to bring it in a sane state. (In case of S2D we expect
-        * BIOS to reset the controller for us.)
+        * If platform firmware was not going to be involved in suspend, we did
+        * not restore the controller state to whatever it had been at boot
+        * time, so we do not need to do anything.
+        */
+       if (!pm_suspend_via_firmware())
+               return 0;
+
+       /*
+        * We only need to reset the controller if we are resuming after handing
+        * off control to the platform firmware, otherwise we can simply restore
+        * the mode.
         */
-       return i8042_controller_resume(true);
+       want_reset = pm_resume_via_firmware();
+
+       return i8042_controller_resume(want_reset);
 }
 
 static int i8042_pm_thaw(struct device *dev)
@@ -1217,6 +1277,7 @@ static int i8042_pm_restore(struct device *dev)
 
 static const struct dev_pm_ops i8042_pm_ops = {
        .suspend        = i8042_pm_suspend,
+       .resume_noirq   = i8042_pm_resume_noirq,
        .resume         = i8042_pm_resume,
        .thaw           = i8042_pm_thaw,
        .poweroff       = i8042_pm_reset,
@@ -1249,6 +1310,7 @@ static int __init i8042_create_kbd_port(void)
        serio->start            = i8042_start;
        serio->stop             = i8042_stop;
        serio->close            = i8042_port_close;
+       serio->ps2_cmd_mutex    = &i8042_mutex;
        serio->port_data        = port;
        serio->dev.parent       = &i8042_platform_device->dev;
        strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
@@ -1276,6 +1338,7 @@ static int __init i8042_create_aux_port(int idx)
        serio->write            = i8042_aux_write;
        serio->start            = i8042_start;
        serio->stop             = i8042_stop;
+       serio->ps2_cmd_mutex    = &i8042_mutex;
        serio->port_data        = port;
        serio->dev.parent       = &i8042_platform_device->dev;
        if (idx < 0) {
@@ -1345,21 +1408,6 @@ static void i8042_unregister_ports(void)
        }
 }
 
-/*
- * Checks whether port belongs to i8042 controller.
- */
-bool i8042_check_port_owner(const struct serio *port)
-{
-       int i;
-
-       for (i = 0; i < I8042_NUM_PORTS; i++)
-               if (i8042_ports[i].serio == port)
-                       return true;
-
-       return false;
-}
-EXPORT_SYMBOL(i8042_check_port_owner);
-
 static void i8042_free_irqs(void)
 {
        if (i8042_aux_irq_registered)
@@ -1438,13 +1486,36 @@ static int __init i8042_setup_kbd(void)
        return error;
 }
 
+static int i8042_kbd_bind_notifier(struct notifier_block *nb,
+                                  unsigned long action, void *data)
+{
+       struct device *dev = data;
+       struct serio *serio = to_serio_port(dev);
+       struct i8042_port *port = serio->port_data;
+
+       if (serio != i8042_ports[I8042_KBD_PORT_NO].serio)
+               return 0;
+
+       switch (action) {
+       case BUS_NOTIFY_BOUND_DRIVER:
+               port->driver_bound = true;
+               break;
+
+       case BUS_NOTIFY_UNBIND_DRIVER:
+               port->driver_bound = false;
+               break;
+       }
+
+       return 0;
+}
+
 static int __init i8042_probe(struct platform_device *dev)
 {
        int error;
 
        i8042_platform_device = dev;
 
-       if (i8042_reset) {
+       if (i8042_reset == I8042_RESET_ALWAYS) {
                error = i8042_controller_selftest();
                if (error)
                        return error;
@@ -1507,6 +1578,10 @@ static struct platform_driver i8042_driver = {
        .shutdown       = i8042_shutdown,
 };
 
+static struct notifier_block i8042_kbd_bind_notifier_block = {
+       .notifier_call = i8042_kbd_bind_notifier,
+};
+
 static int __init i8042_init(void)
 {
        struct platform_device *pdev;
@@ -1528,6 +1603,7 @@ static int __init i8042_init(void)
                goto err_platform_exit;
        }
 
+       bus_register_notifier(&serio_bus, &i8042_kbd_bind_notifier_block);
        panic_blink = i8042_panic_blink;
 
        return 0;
@@ -1543,6 +1619,7 @@ static void __exit i8042_exit(void)
        platform_driver_unregister(&i8042_driver);
        i8042_platform_exit();
 
+       bus_unregister_notifier(&serio_bus, &i8042_kbd_bind_notifier_block);
        panic_blink = NULL;
 }