#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>
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");
__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;
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;
}
/*
- * 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;
param = 0xf0;
if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0x0f)
return -1;
- param = 0x56;
- if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xa9)
+ param = mode ? 0x56 : 0xf6;
+ if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != (mode ? 0xa9 : 0x09))
return -1;
- param = 0xa4;
- if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == 0x5b)
+ param = mode ? 0xa4 : 0xa5;
+ if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == (mode ? 0x5b : 0x5a))
return -1;
if (mux_version)
{
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;
*/
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(¶m, 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.
}
+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;
}
* 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");
}
*/
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();
.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;
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;
}
{
int i;
- unregister_reboot_notifier(&i8042_notifier);
-
- if (i8042_pm_dev)
- pm_unregister(i8042_pm_dev);
-
i8042_controller_cleanup();
if (i8042_kbd_values.exists)
driver_unregister(&i8042_driver);
i8042_platform_exit();
+
+ panic_blink = NULL;
}
module_init(i8042_init);