vserver 1.9.5.x5
[linux-2.6.git] / drivers / input / serio / i8042.c
index 151c29d..36e5011 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/config.h>
-#include <linux/reboot.h>
 #include <linux/init.h>
-#include <linux/sysdev.h>
-#include <linux/pm.h>
 #include <linux/serio.h>
 #include <linux/err.h>
 
@@ -57,6 +54,19 @@ static unsigned int i8042_noloop;
 module_param_named(noloop, i8042_noloop, bool, 0);
 MODULE_PARM_DESC(dumbkbd, "Disable the AUX Loopback command while probing for the AUX port");
 
+#ifdef CONFIG_ACPI
+static int i8042_noacpi;
+module_param_named(noacpi, i8042_noacpi, bool, 0);
+MODULE_PARM_DESC(noacpi, "Do not use ACPI to detect controller settings");
+#endif
+
+#define DEBUG
+#ifdef DEBUG
+static int i8042_debug;
+module_param_named(debug, i8042_debug, bool, 0600);
+MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off");
+#endif
+
 __obsolete_setup("i8042_noaux");
 __obsolete_setup("i8042_nomux");
 __obsolete_setup("i8042_unlock");
@@ -64,10 +74,9 @@ __obsolete_setup("i8042_reset");
 __obsolete_setup("i8042_direct");
 __obsolete_setup("i8042_dumbkbd");
 
-#undef DEBUG
 #include "i8042.h"
 
-spinlock_t i8042_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(i8042_lock);
 
 struct i8042_values {
        int irq;
@@ -101,7 +110,6 @@ static unsigned char i8042_initial_ctr;
 static unsigned char i8042_ctr;
 static unsigned char i8042_mux_open;
 static unsigned char i8042_mux_present;
-static struct pm_dev *i8042_pm_dev;
 static struct timer_list i8042_timer;
 static struct platform_device *i8042_platform_device;
 
@@ -450,12 +458,11 @@ out:
 }
 
 /*
- * i8042_enable_mux_mode checks whether the controller has an active
- * multiplexor and puts the chip into Multiplexed (as opposed to
- * Legacy) mode.
+ * i8042_set_mux_mode checks whether the controller has an active
+ * multiplexor and puts the chip into Multiplexed (1) or Legacy (0) mode.
  */
 
-static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux_version)
+static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version)
 {
 
        unsigned char param;
@@ -474,11 +481,11 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux
        param = 0xf0;
        if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0x0f)
                return -1;
-       param = 0x56;
-       if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9)
+       param = mode ? 0x56 : 0xf6;
+       if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != (mode ? 0xa9 : 0x09))
                return -1;
-       param = 0xa4;
-       if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b)
+       param = mode ? 0xa4 : 0xa5;
+       if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == (mode ? 0x5b : 0x5a))
                return -1;
 
        if (mux_version)
@@ -532,11 +539,11 @@ static int __init i8042_check_mux(struct i8042_values *values)
 {
        unsigned char mux_version;
 
-       if (i8042_enable_mux_mode(values, &mux_version))
+       if (i8042_set_mux_mode(1, &mux_version))
                return -1;
 
-       /* Workaround for broken chips which seem to support MUX, but in reality don't. */
-       /* They all report version 10.12 */
+       /* Workaround for interference with USB Legacy emulation */
+       /* that causes a v10.12 MUX to be found. */
        if (mux_version == 0xAC)
                return -1;
 
@@ -766,12 +773,22 @@ static int i8042_controller_init(void)
  */
 void i8042_controller_reset(void)
 {
-       if (i8042_reset) {
-               unsigned char param;
+       unsigned char param;
+
+/*
+ * Reset the controller if requested.
+ */
 
+       if (i8042_reset)
                if (i8042_command(&param, I8042_CMD_CTL_TEST))
                        printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n");
-       }
+
+/*
+ * Disable MUX mode if present.
+ */
+
+       if (i8042_mux_present)
+               i8042_set_mux_mode(0, NULL);
 
 /*
  * Restore the original control register setting.
@@ -813,14 +830,51 @@ void i8042_controller_cleanup(void)
 }
 
 
+static int blink_frequency = 500;
+module_param_named(panicblink, blink_frequency, int, 0600);
+
+/* Catch the case when the kbd interrupt is off */
+#define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0)
+
+/* Tell the user who may be running in X and not see the console that we have
+   panic'ed. This is to distingush panics from "real" lockups.  */
+static long i8042_panic_blink(long count)
+{
+       long delay = 0;
+       static long last_blink;
+       static char led;
+       /* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is
+          different. */
+       if (!blink_frequency)
+               return 0;
+       if (count - last_blink < blink_frequency)
+               return 0;
+       led ^= 0x01 | 0x04;
+       while (i8042_read_status() & I8042_STR_IBF)
+               DELAY;
+       i8042_write_data(0xed); /* set leds */
+       DELAY;
+       while (i8042_read_status() & I8042_STR_IBF)
+               DELAY;
+       DELAY;
+       i8042_write_data(led);
+       DELAY;
+       last_blink = count;
+       return delay;
+}
+
+#undef DELAY
+
 /*
  * Here we try to restore the original BIOS settings
  */
 
-static int i8042_controller_suspend(void)
+static int i8042_suspend(struct device *dev, u32 state, u32 level)
 {
-       del_timer_sync(&i8042_timer);
-       i8042_controller_reset();
+       if (level == SUSPEND_DISABLE) {
+               del_timer_sync(&i8042_timer);
+               i8042_controller_reset();
+       }
 
        return 0;
 }
@@ -830,17 +884,20 @@ static int i8042_controller_suspend(void)
  * Here we try to reset everything back to a state in which suspended
  */
 
-static int i8042_controller_resume(void)
+static int i8042_resume(struct device *dev, u32 level)
 {
        int i;
 
+       if (level != RESUME_ENABLE)
+               return 0;
+
        if (i8042_controller_init()) {
                printk(KERN_ERR "i8042: resume failed\n");
                return -1;
        }
 
        if (i8042_mux_present)
-               if (i8042_enable_mux_mode(&i8042_aux_values, NULL) ||
+               if (i8042_set_mux_mode(1, NULL) ||
                    i8042_enable_mux_ports(&i8042_aux_values)) {
                        printk(KERN_WARNING "i8042: failed to resume active multiplexor, mouse won't work.\n");
                }
@@ -863,43 +920,17 @@ static int i8042_controller_resume(void)
  */
        mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
 
+       panic_blink = i8042_panic_blink;
+
        return 0;
-}
 
+}
 
 /*
  * We need to reset the 8042 back to original mode on system shutdown,
  * because otherwise BIOSes will be confused.
  */
 
-static int i8042_notify_sys(struct notifier_block *this, unsigned long code,
-                           void *unused)
-{
-        if (code == SYS_DOWN || code == SYS_HALT)
-               i8042_controller_cleanup();
-        return NOTIFY_DONE;
-}
-
-static struct notifier_block i8042_notifier =
-{
-        i8042_notify_sys,
-        NULL,
-        0
-};
-
-/*
- * Suspend/resume handlers for the new PM scheme (driver model)
- */
-static int i8042_suspend(struct device *dev, u32 state, u32 level)
-{
-       return level == SUSPEND_DISABLE ? i8042_controller_suspend() : 0;
-}
-
-static int i8042_resume(struct device *dev, u32 level)
-{
-       return level == RESUME_ENABLE ? i8042_controller_resume() : 0;
-}
-
 static void i8042_shutdown(struct device *dev)
 {
        i8042_controller_cleanup();
@@ -913,22 +944,6 @@ static struct device_driver i8042_driver = {
        .shutdown       = i8042_shutdown,
 };
 
-/*
- * Suspend/resume handler for the old PM scheme (APM)
- */
-static int i8042_pm_callback(struct pm_dev *dev, pm_request_t request, void *dummy)
-{
-       switch (request) {
-               case PM_SUSPEND:
-                       return i8042_controller_suspend();
-
-               case PM_RESUME:
-                       return i8042_controller_resume();
-       }
-
-       return 0;
-}
-
 static struct serio * __init i8042_allocate_kbd_port(void)
 {
        struct serio *serio;
@@ -1043,10 +1058,6 @@ int __init i8042_init(void)
 
        mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
 
-       i8042_pm_dev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, i8042_pm_callback);
-
-       register_reboot_notifier(&i8042_notifier);
-
        return 0;
 }
 
@@ -1054,11 +1065,6 @@ void __exit i8042_exit(void)
 {
        int i;
 
-       unregister_reboot_notifier(&i8042_notifier);
-
-       if (i8042_pm_dev)
-               pm_unregister(i8042_pm_dev);
-
        i8042_controller_cleanup();
 
        if (i8042_kbd_values.exists)
@@ -1077,6 +1083,8 @@ void __exit i8042_exit(void)
        driver_unregister(&i8042_driver);
 
        i8042_platform_exit();
+
+       panic_blink = NULL;
 }
 
 module_init(i8042_init);