11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * i8042 keyboard and mouse controller driver for Linux 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 1999-2004 Vojtech Pavlik 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds 71da177e4SLinus Torvalds /* 81da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify it 91da177e4SLinus Torvalds * under the terms of the GNU General Public License version 2 as published by 101da177e4SLinus Torvalds * the Free Software Foundation. 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 134eb3c30bSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 144eb3c30bSJoe Perches 157e044e05SDmitry Torokhov #include <linux/types.h> 161da177e4SLinus Torvalds #include <linux/delay.h> 171da177e4SLinus Torvalds #include <linux/module.h> 181da177e4SLinus Torvalds #include <linux/interrupt.h> 191da177e4SLinus Torvalds #include <linux/ioport.h> 201da177e4SLinus Torvalds #include <linux/init.h> 211da177e4SLinus Torvalds #include <linux/serio.h> 221da177e4SLinus Torvalds #include <linux/err.h> 231da177e4SLinus Torvalds #include <linux/rcupdate.h> 24d052d1beSRussell King #include <linux/platform_device.h> 25553a05b8SMárton Németh #include <linux/i8042.h> 265a0e3ad6STejun Heo #include <linux/slab.h> 271c5dd134SRafael J. Wysocki #include <linux/suspend.h> 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds #include <asm/io.h> 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); 321da177e4SLinus Torvalds MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); 331da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 341da177e4SLinus Torvalds 35386b3849SDmitry Torokhov static bool i8042_nokbd; 36945ef0d4SDmitry Torokhov module_param_named(nokbd, i8042_nokbd, bool, 0); 37945ef0d4SDmitry Torokhov MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port."); 38945ef0d4SDmitry Torokhov 39386b3849SDmitry Torokhov static bool i8042_noaux; 401da177e4SLinus Torvalds module_param_named(noaux, i8042_noaux, bool, 0); 411da177e4SLinus Torvalds MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port."); 421da177e4SLinus Torvalds 43e55a3366SDmitry Torokhov static bool i8042_nomux; 441da177e4SLinus Torvalds module_param_named(nomux, i8042_nomux, bool, 0); 452c860a11SDominik Brodowski MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing controller is present."); 461da177e4SLinus Torvalds 47386b3849SDmitry Torokhov static bool i8042_unlock; 481da177e4SLinus Torvalds module_param_named(unlock, i8042_unlock, bool, 0); 491da177e4SLinus Torvalds MODULE_PARM_DESC(unlock, "Ignore keyboard lock."); 501da177e4SLinus Torvalds 51930e1924SMarcos Paulo de Souza enum i8042_controller_reset_mode { 52930e1924SMarcos Paulo de Souza I8042_RESET_NEVER, 53930e1924SMarcos Paulo de Souza I8042_RESET_ALWAYS, 54930e1924SMarcos Paulo de Souza I8042_RESET_ON_S2RAM, 55930e1924SMarcos Paulo de Souza #define I8042_RESET_DEFAULT I8042_RESET_ON_S2RAM 56930e1924SMarcos Paulo de Souza }; 57930e1924SMarcos Paulo de Souza static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT; 58930e1924SMarcos Paulo de Souza static int i8042_set_reset(const char *val, const struct kernel_param *kp) 59930e1924SMarcos Paulo de Souza { 60930e1924SMarcos Paulo de Souza enum i8042_controller_reset_mode *arg = kp->arg; 61930e1924SMarcos Paulo de Souza int error; 62930e1924SMarcos Paulo de Souza bool reset; 63930e1924SMarcos Paulo de Souza 64930e1924SMarcos Paulo de Souza if (val) { 65930e1924SMarcos Paulo de Souza error = kstrtobool(val, &reset); 66930e1924SMarcos Paulo de Souza if (error) 67930e1924SMarcos Paulo de Souza return error; 68930e1924SMarcos Paulo de Souza } else { 69930e1924SMarcos Paulo de Souza reset = true; 70930e1924SMarcos Paulo de Souza } 71930e1924SMarcos Paulo de Souza 72930e1924SMarcos Paulo de Souza *arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER; 73930e1924SMarcos Paulo de Souza return 0; 74930e1924SMarcos Paulo de Souza } 75930e1924SMarcos Paulo de Souza 76930e1924SMarcos Paulo de Souza static const struct kernel_param_ops param_ops_reset_param = { 77930e1924SMarcos Paulo de Souza .flags = KERNEL_PARAM_OPS_FL_NOARG, 78930e1924SMarcos Paulo de Souza .set = i8042_set_reset, 79930e1924SMarcos Paulo de Souza }; 80930e1924SMarcos Paulo de Souza #define param_check_reset_param(name, p) \ 81930e1924SMarcos Paulo de Souza __param_check(name, p, enum i8042_controller_reset_mode) 82930e1924SMarcos Paulo de Souza module_param_named(reset, i8042_reset, reset_param, 0); 83930e1924SMarcos Paulo de Souza MODULE_PARM_DESC(reset, "Reset controller on resume, cleanup or both"); 841da177e4SLinus Torvalds 85386b3849SDmitry Torokhov static bool i8042_direct; 861da177e4SLinus Torvalds module_param_named(direct, i8042_direct, bool, 0); 871da177e4SLinus Torvalds MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode."); 881da177e4SLinus Torvalds 89386b3849SDmitry Torokhov static bool i8042_dumbkbd; 901da177e4SLinus Torvalds module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); 911da177e4SLinus Torvalds MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); 921da177e4SLinus Torvalds 93386b3849SDmitry Torokhov static bool i8042_noloop; 941da177e4SLinus Torvalds module_param_named(noloop, i8042_noloop, bool, 0); 951da177e4SLinus Torvalds MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port"); 961da177e4SLinus Torvalds 97f8313ef1SJiri Kosina static bool i8042_notimeout; 98f8313ef1SJiri Kosina module_param_named(notimeout, i8042_notimeout, bool, 0); 99f8313ef1SJiri Kosina MODULE_PARM_DESC(notimeout, "Ignore timeouts signalled by i8042"); 100f8313ef1SJiri Kosina 101148e9a71SSrihari Vijayaraghavan static bool i8042_kbdreset; 102148e9a71SSrihari Vijayaraghavan module_param_named(kbdreset, i8042_kbdreset, bool, 0); 103148e9a71SSrihari Vijayaraghavan MODULE_PARM_DESC(kbdreset, "Reset device connected to KBD port"); 104148e9a71SSrihari Vijayaraghavan 1058987fec0SCarlos Corbacho #ifdef CONFIG_X86 106386b3849SDmitry Torokhov static bool i8042_dritek; 1078987fec0SCarlos Corbacho module_param_named(dritek, i8042_dritek, bool, 0); 1088987fec0SCarlos Corbacho MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension"); 1098987fec0SCarlos Corbacho #endif 1108987fec0SCarlos Corbacho 1111da177e4SLinus Torvalds #ifdef CONFIG_PNP 112386b3849SDmitry Torokhov static bool i8042_nopnp; 1131da177e4SLinus Torvalds module_param_named(nopnp, i8042_nopnp, bool, 0); 1141da177e4SLinus Torvalds MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings"); 1151da177e4SLinus Torvalds #endif 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds #define DEBUG 1181da177e4SLinus Torvalds #ifdef DEBUG 119386b3849SDmitry Torokhov static bool i8042_debug; 1201da177e4SLinus Torvalds module_param_named(debug, i8042_debug, bool, 0600); 1211da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off"); 122e1443d28SStephen Chandler Paul 123e1443d28SStephen Chandler Paul static bool i8042_unmask_kbd_data; 124e1443d28SStephen Chandler Paul module_param_named(unmask_kbd_data, i8042_unmask_kbd_data, bool, 0600); 125e1443d28SStephen Chandler Paul 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]"); 1261da177e4SLinus Torvalds #endif 1271da177e4SLinus Torvalds 1281c7827aeSDmitry Torokhov static bool i8042_bypass_aux_irq_test; 129a7c5868cSHans de Goede static char i8042_kbd_firmware_id[128]; 130a7c5868cSHans de Goede static char i8042_aux_firmware_id[128]; 1311c7827aeSDmitry Torokhov 1321da177e4SLinus Torvalds #include "i8042.h" 1331da177e4SLinus Torvalds 134181d683dSDmitry Torokhov /* 135181d683dSDmitry Torokhov * i8042_lock protects serialization between i8042_command and 136181d683dSDmitry Torokhov * the interrupt handler. 137181d683dSDmitry Torokhov */ 1381da177e4SLinus Torvalds static DEFINE_SPINLOCK(i8042_lock); 1391da177e4SLinus Torvalds 140181d683dSDmitry Torokhov /* 141181d683dSDmitry Torokhov * Writers to AUX and KBD ports as well as users issuing i8042_command 142181d683dSDmitry Torokhov * directly should acquire i8042_mutex (by means of calling 143181d683dSDmitry Torokhov * i8042_lock_chip() and i8042_unlock_ship() helpers) to ensure that 144181d683dSDmitry Torokhov * they do not disturb each other (unfortunately in many i8042 145181d683dSDmitry Torokhov * implementations write to one of the ports will immediately abort 146181d683dSDmitry Torokhov * command that is being processed by another port). 147181d683dSDmitry Torokhov */ 148181d683dSDmitry Torokhov static DEFINE_MUTEX(i8042_mutex); 149181d683dSDmitry Torokhov 1501da177e4SLinus Torvalds struct i8042_port { 1511da177e4SLinus Torvalds struct serio *serio; 1521da177e4SLinus Torvalds int irq; 153386b3849SDmitry Torokhov bool exists; 154e1443d28SStephen Chandler Paul bool driver_bound; 1551da177e4SLinus Torvalds signed char mux; 1561da177e4SLinus Torvalds }; 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds #define I8042_KBD_PORT_NO 0 1591da177e4SLinus Torvalds #define I8042_AUX_PORT_NO 1 1601da177e4SLinus Torvalds #define I8042_MUX_PORT_NO 2 1611da177e4SLinus Torvalds #define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2) 162de9ce703SDmitry Torokhov 163de9ce703SDmitry Torokhov static struct i8042_port i8042_ports[I8042_NUM_PORTS]; 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds static unsigned char i8042_initial_ctr; 1661da177e4SLinus Torvalds static unsigned char i8042_ctr; 167386b3849SDmitry Torokhov static bool i8042_mux_present; 168386b3849SDmitry Torokhov static bool i8042_kbd_irq_registered; 169386b3849SDmitry Torokhov static bool i8042_aux_irq_registered; 170817e6ba3SDmitry Torokhov static unsigned char i8042_suppress_kbd_ack; 1711da177e4SLinus Torvalds static struct platform_device *i8042_platform_device; 172e1443d28SStephen Chandler Paul static struct notifier_block i8042_kbd_bind_notifier_block; 1731da177e4SLinus Torvalds 1747d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id); 175967c9ef9SMatthew Garrett static bool (*i8042_platform_filter)(unsigned char data, unsigned char str, 176967c9ef9SMatthew Garrett struct serio *serio); 1771da177e4SLinus Torvalds 178181d683dSDmitry Torokhov void i8042_lock_chip(void) 179181d683dSDmitry Torokhov { 180181d683dSDmitry Torokhov mutex_lock(&i8042_mutex); 181181d683dSDmitry Torokhov } 182181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_lock_chip); 183181d683dSDmitry Torokhov 184181d683dSDmitry Torokhov void i8042_unlock_chip(void) 185181d683dSDmitry Torokhov { 186181d683dSDmitry Torokhov mutex_unlock(&i8042_mutex); 187181d683dSDmitry Torokhov } 188181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_unlock_chip); 189181d683dSDmitry Torokhov 190967c9ef9SMatthew Garrett int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, 191967c9ef9SMatthew Garrett struct serio *serio)) 192967c9ef9SMatthew Garrett { 193967c9ef9SMatthew Garrett unsigned long flags; 194967c9ef9SMatthew Garrett int ret = 0; 195967c9ef9SMatthew Garrett 196967c9ef9SMatthew Garrett spin_lock_irqsave(&i8042_lock, flags); 197967c9ef9SMatthew Garrett 198967c9ef9SMatthew Garrett if (i8042_platform_filter) { 199967c9ef9SMatthew Garrett ret = -EBUSY; 200967c9ef9SMatthew Garrett goto out; 201967c9ef9SMatthew Garrett } 202967c9ef9SMatthew Garrett 203967c9ef9SMatthew Garrett i8042_platform_filter = filter; 204967c9ef9SMatthew Garrett 205967c9ef9SMatthew Garrett out: 206967c9ef9SMatthew Garrett spin_unlock_irqrestore(&i8042_lock, flags); 207967c9ef9SMatthew Garrett return ret; 208967c9ef9SMatthew Garrett } 209967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_install_filter); 210967c9ef9SMatthew Garrett 211967c9ef9SMatthew Garrett int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, 212967c9ef9SMatthew Garrett struct serio *port)) 213967c9ef9SMatthew Garrett { 214967c9ef9SMatthew Garrett unsigned long flags; 215967c9ef9SMatthew Garrett int ret = 0; 216967c9ef9SMatthew Garrett 217967c9ef9SMatthew Garrett spin_lock_irqsave(&i8042_lock, flags); 218967c9ef9SMatthew Garrett 219967c9ef9SMatthew Garrett if (i8042_platform_filter != filter) { 220967c9ef9SMatthew Garrett ret = -EINVAL; 221967c9ef9SMatthew Garrett goto out; 222967c9ef9SMatthew Garrett } 223967c9ef9SMatthew Garrett 224967c9ef9SMatthew Garrett i8042_platform_filter = NULL; 225967c9ef9SMatthew Garrett 226967c9ef9SMatthew Garrett out: 227967c9ef9SMatthew Garrett spin_unlock_irqrestore(&i8042_lock, flags); 228967c9ef9SMatthew Garrett return ret; 229967c9ef9SMatthew Garrett } 230967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_remove_filter); 231967c9ef9SMatthew Garrett 2321da177e4SLinus Torvalds /* 2331da177e4SLinus Torvalds * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to 2341da177e4SLinus Torvalds * be ready for reading values from it / writing values to it. 2351da177e4SLinus Torvalds * Called always with i8042_lock held. 2361da177e4SLinus Torvalds */ 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds static int i8042_wait_read(void) 2391da177e4SLinus Torvalds { 2401da177e4SLinus Torvalds int i = 0; 241de9ce703SDmitry Torokhov 2421da177e4SLinus Torvalds while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { 2431da177e4SLinus Torvalds udelay(50); 2441da177e4SLinus Torvalds i++; 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds return -(i == I8042_CTL_TIMEOUT); 2471da177e4SLinus Torvalds } 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds static int i8042_wait_write(void) 2501da177e4SLinus Torvalds { 2511da177e4SLinus Torvalds int i = 0; 252de9ce703SDmitry Torokhov 2531da177e4SLinus Torvalds while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { 2541da177e4SLinus Torvalds udelay(50); 2551da177e4SLinus Torvalds i++; 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds return -(i == I8042_CTL_TIMEOUT); 2581da177e4SLinus Torvalds } 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds /* 2611da177e4SLinus Torvalds * i8042_flush() flushes all data that may be in the keyboard and mouse buffers 2621da177e4SLinus Torvalds * of the i8042 down the toilet. 2631da177e4SLinus Torvalds */ 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds static int i8042_flush(void) 2661da177e4SLinus Torvalds { 2671da177e4SLinus Torvalds unsigned long flags; 2681da177e4SLinus Torvalds unsigned char data, str; 2692f0d2604SAndrey Moiseev int count = 0; 2702f0d2604SAndrey Moiseev int retval = 0; 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 2731da177e4SLinus Torvalds 2742f0d2604SAndrey Moiseev while ((str = i8042_read_status()) & I8042_STR_OBF) { 2752f0d2604SAndrey Moiseev if (count++ < I8042_BUFFER_SIZE) { 2761da177e4SLinus Torvalds udelay(50); 2771da177e4SLinus Torvalds data = i8042_read_data(); 2784eb3c30bSJoe Perches dbg("%02x <- i8042 (flush, %s)\n", 2794eb3c30bSJoe Perches data, str & I8042_STR_AUXDATA ? "aux" : "kbd"); 2802f0d2604SAndrey Moiseev } else { 2812f0d2604SAndrey Moiseev retval = -EIO; 2822f0d2604SAndrey Moiseev break; 2832f0d2604SAndrey Moiseev } 2841da177e4SLinus Torvalds } 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 2871da177e4SLinus Torvalds 2882f0d2604SAndrey Moiseev return retval; 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds /* 2921da177e4SLinus Torvalds * i8042_command() executes a command on the i8042. It also sends the input 2931da177e4SLinus Torvalds * parameter(s) of the commands to it, and receives the output value(s). The 2941da177e4SLinus Torvalds * parameters are to be stored in the param array, and the output is placed 2951da177e4SLinus Torvalds * into the same array. The number of the parameters and output values is 2961da177e4SLinus Torvalds * encoded in bits 8-11 of the command number. 2971da177e4SLinus Torvalds */ 2981da177e4SLinus Torvalds 299de9ce703SDmitry Torokhov static int __i8042_command(unsigned char *param, int command) 3001da177e4SLinus Torvalds { 301de9ce703SDmitry Torokhov int i, error; 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds if (i8042_noloop && command == I8042_CMD_AUX_LOOP) 3041da177e4SLinus Torvalds return -1; 3051da177e4SLinus Torvalds 306de9ce703SDmitry Torokhov error = i8042_wait_write(); 307de9ce703SDmitry Torokhov if (error) 308de9ce703SDmitry Torokhov return error; 309463a4f76SDmitry Torokhov 3104eb3c30bSJoe Perches dbg("%02x -> i8042 (command)\n", command & 0xff); 3111da177e4SLinus Torvalds i8042_write_command(command & 0xff); 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds for (i = 0; i < ((command >> 12) & 0xf); i++) { 314de9ce703SDmitry Torokhov error = i8042_wait_write(); 3152ea9c236SMarcos Paulo de Souza if (error) { 3162ea9c236SMarcos Paulo de Souza dbg(" -- i8042 (wait write timeout)\n"); 317de9ce703SDmitry Torokhov return error; 3182ea9c236SMarcos Paulo de Souza } 3194eb3c30bSJoe Perches dbg("%02x -> i8042 (parameter)\n", param[i]); 3201da177e4SLinus Torvalds i8042_write_data(param[i]); 3211da177e4SLinus Torvalds } 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds for (i = 0; i < ((command >> 8) & 0xf); i++) { 324de9ce703SDmitry Torokhov error = i8042_wait_read(); 325de9ce703SDmitry Torokhov if (error) { 3262ea9c236SMarcos Paulo de Souza dbg(" -- i8042 (wait read timeout)\n"); 327de9ce703SDmitry Torokhov return error; 328de9ce703SDmitry Torokhov } 329463a4f76SDmitry Torokhov 330463a4f76SDmitry Torokhov if (command == I8042_CMD_AUX_LOOP && 331463a4f76SDmitry Torokhov !(i8042_read_status() & I8042_STR_AUXDATA)) { 3324eb3c30bSJoe Perches dbg(" -- i8042 (auxerr)\n"); 333de9ce703SDmitry Torokhov return -1; 334463a4f76SDmitry Torokhov } 335463a4f76SDmitry Torokhov 3361da177e4SLinus Torvalds param[i] = i8042_read_data(); 3374eb3c30bSJoe Perches dbg("%02x <- i8042 (return)\n", param[i]); 3381da177e4SLinus Torvalds } 3391da177e4SLinus Torvalds 340de9ce703SDmitry Torokhov return 0; 341de9ce703SDmitry Torokhov } 3421da177e4SLinus Torvalds 343553a05b8SMárton Németh int i8042_command(unsigned char *param, int command) 344de9ce703SDmitry Torokhov { 345de9ce703SDmitry Torokhov unsigned long flags; 346de9ce703SDmitry Torokhov int retval; 347de9ce703SDmitry Torokhov 348de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 349de9ce703SDmitry Torokhov retval = __i8042_command(param, command); 350463a4f76SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 351de9ce703SDmitry Torokhov 3521da177e4SLinus Torvalds return retval; 3531da177e4SLinus Torvalds } 354553a05b8SMárton Németh EXPORT_SYMBOL(i8042_command); 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds /* 3571da177e4SLinus Torvalds * i8042_kbd_write() sends a byte out through the keyboard interface. 3581da177e4SLinus Torvalds */ 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds static int i8042_kbd_write(struct serio *port, unsigned char c) 3611da177e4SLinus Torvalds { 3621da177e4SLinus Torvalds unsigned long flags; 3631da177e4SLinus Torvalds int retval = 0; 3641da177e4SLinus Torvalds 3651da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds if (!(retval = i8042_wait_write())) { 3684eb3c30bSJoe Perches dbg("%02x -> i8042 (kbd-data)\n", c); 3691da177e4SLinus Torvalds i8042_write_data(c); 3701da177e4SLinus Torvalds } 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds return retval; 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds /* 3781da177e4SLinus Torvalds * i8042_aux_write() sends a byte out through the aux interface. 3791da177e4SLinus Torvalds */ 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds static int i8042_aux_write(struct serio *serio, unsigned char c) 3821da177e4SLinus Torvalds { 3831da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 3841da177e4SLinus Torvalds 385f4e3c711SDmitry Torokhov return i8042_command(&c, port->mux == -1 ? 386f4e3c711SDmitry Torokhov I8042_CMD_AUX_SEND : 387f4e3c711SDmitry Torokhov I8042_CMD_MUX_SEND + port->mux); 3881da177e4SLinus Torvalds } 3891da177e4SLinus Torvalds 3905ddbc77cSDmitry Torokhov 3915ddbc77cSDmitry Torokhov /* 3920e2b4458SMarcos Paulo de Souza * i8042_port_close attempts to clear AUX or KBD port state by disabling 3935ddbc77cSDmitry Torokhov * and then re-enabling it. 3945ddbc77cSDmitry Torokhov */ 3955ddbc77cSDmitry Torokhov 3965ddbc77cSDmitry Torokhov static void i8042_port_close(struct serio *serio) 3975ddbc77cSDmitry Torokhov { 3985ddbc77cSDmitry Torokhov int irq_bit; 3995ddbc77cSDmitry Torokhov int disable_bit; 4005ddbc77cSDmitry Torokhov const char *port_name; 4015ddbc77cSDmitry Torokhov 4025ddbc77cSDmitry Torokhov if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) { 4035ddbc77cSDmitry Torokhov irq_bit = I8042_CTR_AUXINT; 4045ddbc77cSDmitry Torokhov disable_bit = I8042_CTR_AUXDIS; 4055ddbc77cSDmitry Torokhov port_name = "AUX"; 4065ddbc77cSDmitry Torokhov } else { 4075ddbc77cSDmitry Torokhov irq_bit = I8042_CTR_KBDINT; 4085ddbc77cSDmitry Torokhov disable_bit = I8042_CTR_KBDDIS; 4095ddbc77cSDmitry Torokhov port_name = "KBD"; 4105ddbc77cSDmitry Torokhov } 4115ddbc77cSDmitry Torokhov 4125ddbc77cSDmitry Torokhov i8042_ctr &= ~irq_bit; 4135ddbc77cSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 4144eb3c30bSJoe Perches pr_warn("Can't write CTR while closing %s port\n", port_name); 4155ddbc77cSDmitry Torokhov 4165ddbc77cSDmitry Torokhov udelay(50); 4175ddbc77cSDmitry Torokhov 4185ddbc77cSDmitry Torokhov i8042_ctr &= ~disable_bit; 4195ddbc77cSDmitry Torokhov i8042_ctr |= irq_bit; 4205ddbc77cSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 4214eb3c30bSJoe Perches pr_err("Can't reactivate %s port\n", port_name); 4225ddbc77cSDmitry Torokhov 4235ddbc77cSDmitry Torokhov /* 4245ddbc77cSDmitry Torokhov * See if there is any data appeared while we were messing with 4255ddbc77cSDmitry Torokhov * port state. 4265ddbc77cSDmitry Torokhov */ 4275ddbc77cSDmitry Torokhov i8042_interrupt(0, NULL); 4285ddbc77cSDmitry Torokhov } 4295ddbc77cSDmitry Torokhov 4301da177e4SLinus Torvalds /* 4311da177e4SLinus Torvalds * i8042_start() is called by serio core when port is about to finish 4321da177e4SLinus Torvalds * registering. It will mark port as existing so i8042_interrupt can 4331da177e4SLinus Torvalds * start sending data through it. 4341da177e4SLinus Torvalds */ 4351da177e4SLinus Torvalds static int i8042_start(struct serio *serio) 4361da177e4SLinus Torvalds { 4371da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 4381da177e4SLinus Torvalds 439*340d394aSChen Hong spin_lock_irq(&i8042_lock); 440386b3849SDmitry Torokhov port->exists = true; 441*340d394aSChen Hong spin_unlock_irq(&i8042_lock); 442*340d394aSChen Hong 4431da177e4SLinus Torvalds return 0; 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds /* 4471da177e4SLinus Torvalds * i8042_stop() marks serio port as non-existing so i8042_interrupt 4481da177e4SLinus Torvalds * will not try to send data to the port that is about to go away. 4491da177e4SLinus Torvalds * The function is called by serio core as part of unregister procedure. 4501da177e4SLinus Torvalds */ 4511da177e4SLinus Torvalds static void i8042_stop(struct serio *serio) 4521da177e4SLinus Torvalds { 4531da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 4541da177e4SLinus Torvalds 455*340d394aSChen Hong spin_lock_irq(&i8042_lock); 456386b3849SDmitry Torokhov port->exists = false; 457*340d394aSChen Hong port->serio = NULL; 458*340d394aSChen Hong spin_unlock_irq(&i8042_lock); 459a8399c51SDmitry Torokhov 460a8399c51SDmitry Torokhov /* 461*340d394aSChen Hong * We need to make sure that interrupt handler finishes using 462*340d394aSChen Hong * our serio port before we return from this function. 463a8399c51SDmitry Torokhov * We synchronize with both AUX and KBD IRQs because there is 464a8399c51SDmitry Torokhov * a (very unlikely) chance that AUX IRQ is raised for KBD port 465a8399c51SDmitry Torokhov * and vice versa. 466a8399c51SDmitry Torokhov */ 467a8399c51SDmitry Torokhov synchronize_irq(I8042_AUX_IRQ); 468a8399c51SDmitry Torokhov synchronize_irq(I8042_KBD_IRQ); 4691da177e4SLinus Torvalds } 4701da177e4SLinus Torvalds 4711da177e4SLinus Torvalds /* 4724e8d340dSDmitry Torokhov * i8042_filter() filters out unwanted bytes from the input data stream. 4734e8d340dSDmitry Torokhov * It is called from i8042_interrupt and thus is running with interrupts 4744e8d340dSDmitry Torokhov * off and i8042_lock held. 4754e8d340dSDmitry Torokhov */ 476967c9ef9SMatthew Garrett static bool i8042_filter(unsigned char data, unsigned char str, 477967c9ef9SMatthew Garrett struct serio *serio) 4784e8d340dSDmitry Torokhov { 4794e8d340dSDmitry Torokhov if (unlikely(i8042_suppress_kbd_ack)) { 4804e8d340dSDmitry Torokhov if ((~str & I8042_STR_AUXDATA) && 4814e8d340dSDmitry Torokhov (data == 0xfa || data == 0xfe)) { 4824e8d340dSDmitry Torokhov i8042_suppress_kbd_ack--; 4834e8d340dSDmitry Torokhov dbg("Extra keyboard ACK - filtered out\n"); 4844e8d340dSDmitry Torokhov return true; 4854e8d340dSDmitry Torokhov } 4864e8d340dSDmitry Torokhov } 4874e8d340dSDmitry Torokhov 488967c9ef9SMatthew Garrett if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) { 4890747e3bcSStefan Weil dbg("Filtered out by platform filter\n"); 490967c9ef9SMatthew Garrett return true; 491967c9ef9SMatthew Garrett } 492967c9ef9SMatthew Garrett 4934e8d340dSDmitry Torokhov return false; 4944e8d340dSDmitry Torokhov } 4954e8d340dSDmitry Torokhov 4964e8d340dSDmitry Torokhov /* 4971da177e4SLinus Torvalds * i8042_interrupt() is the most important function in this driver - 4981da177e4SLinus Torvalds * it handles the interrupts from the i8042, and sends incoming bytes 4991da177e4SLinus Torvalds * to the upper layers. 5001da177e4SLinus Torvalds */ 5011da177e4SLinus Torvalds 5027d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id) 5031da177e4SLinus Torvalds { 5041da177e4SLinus Torvalds struct i8042_port *port; 505967c9ef9SMatthew Garrett struct serio *serio; 5061da177e4SLinus Torvalds unsigned long flags; 5071da177e4SLinus Torvalds unsigned char str, data; 5081da177e4SLinus Torvalds unsigned int dfl; 5091da177e4SLinus Torvalds unsigned int port_no; 5104e8d340dSDmitry Torokhov bool filtered; 511817e6ba3SDmitry Torokhov int ret = 1; 5121da177e4SLinus Torvalds 5131da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 5144e8d340dSDmitry Torokhov 5151da177e4SLinus Torvalds str = i8042_read_status(); 5161da177e4SLinus Torvalds if (unlikely(~str & I8042_STR_OBF)) { 5171da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 5184eb3c30bSJoe Perches if (irq) 5194eb3c30bSJoe Perches dbg("Interrupt %d, without any data\n", irq); 5201da177e4SLinus Torvalds ret = 0; 5211da177e4SLinus Torvalds goto out; 5221da177e4SLinus Torvalds } 5234e8d340dSDmitry Torokhov 5241da177e4SLinus Torvalds data = i8042_read_data(); 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { 5271da177e4SLinus Torvalds static unsigned long last_transmit; 5281da177e4SLinus Torvalds static unsigned char last_str; 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds dfl = 0; 5311da177e4SLinus Torvalds if (str & I8042_STR_MUXERR) { 5324eb3c30bSJoe Perches dbg("MUX error, status is %02x, data is %02x\n", 5334eb3c30bSJoe Perches str, data); 5341da177e4SLinus Torvalds /* 5351da177e4SLinus Torvalds * When MUXERR condition is signalled the data register can only contain 5361da177e4SLinus Torvalds * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately 537a216a4b6SDmitry Torokhov * it is not always the case. Some KBCs also report 0xfc when there is 538a216a4b6SDmitry Torokhov * nothing connected to the port while others sometimes get confused which 539a216a4b6SDmitry Torokhov * port the data came from and signal error leaving the data intact. They 540a216a4b6SDmitry Torokhov * _do not_ revert to legacy mode (actually I've never seen KBC reverting 541a216a4b6SDmitry Torokhov * to legacy mode yet, when we see one we'll add proper handling). 542a216a4b6SDmitry Torokhov * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the 543a216a4b6SDmitry Torokhov * rest assume that the data came from the same serio last byte 5441da177e4SLinus Torvalds * was transmitted (if transmission happened not too long ago). 5451da177e4SLinus Torvalds */ 546a216a4b6SDmitry Torokhov 547a216a4b6SDmitry Torokhov switch (data) { 548a216a4b6SDmitry Torokhov default: 5491da177e4SLinus Torvalds if (time_before(jiffies, last_transmit + HZ/10)) { 5501da177e4SLinus Torvalds str = last_str; 5511da177e4SLinus Torvalds break; 5521da177e4SLinus Torvalds } 5531da177e4SLinus Torvalds /* fall through - report timeout */ 554a216a4b6SDmitry Torokhov case 0xfc: 5551da177e4SLinus Torvalds case 0xfd: 5561da177e4SLinus Torvalds case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break; 5571da177e4SLinus Torvalds case 0xff: dfl = SERIO_PARITY; data = 0xfe; break; 5581da177e4SLinus Torvalds } 5591da177e4SLinus Torvalds } 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3); 5621da177e4SLinus Torvalds last_str = str; 5631da177e4SLinus Torvalds last_transmit = jiffies; 5641da177e4SLinus Torvalds } else { 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | 567f8313ef1SJiri Kosina ((str & I8042_STR_TIMEOUT && !i8042_notimeout) ? SERIO_TIMEOUT : 0); 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds port_no = (str & I8042_STR_AUXDATA) ? 5701da177e4SLinus Torvalds I8042_AUX_PORT_NO : I8042_KBD_PORT_NO; 5711da177e4SLinus Torvalds } 5721da177e4SLinus Torvalds 5731da177e4SLinus Torvalds port = &i8042_ports[port_no]; 574967c9ef9SMatthew Garrett serio = port->exists ? port->serio : NULL; 5751da177e4SLinus Torvalds 576e1443d28SStephen Chandler Paul filter_dbg(port->driver_bound, data, "<- i8042 (interrupt, %d, %d%s%s)\n", 577e1443d28SStephen Chandler Paul port_no, irq, 5781da177e4SLinus Torvalds dfl & SERIO_PARITY ? ", bad parity" : "", 5791da177e4SLinus Torvalds dfl & SERIO_TIMEOUT ? ", timeout" : ""); 5801da177e4SLinus Torvalds 581967c9ef9SMatthew Garrett filtered = i8042_filter(data, str, serio); 582817e6ba3SDmitry Torokhov 5834e8d340dSDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 5844e8d340dSDmitry Torokhov 585*340d394aSChen Hong if (likely(serio && !filtered)) 586967c9ef9SMatthew Garrett serio_interrupt(serio, data, dfl); 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds out: 5891da177e4SLinus Torvalds return IRQ_RETVAL(ret); 5901da177e4SLinus Torvalds } 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds /* 5935ddbc77cSDmitry Torokhov * i8042_enable_kbd_port enables keyboard port on chip 594de9ce703SDmitry Torokhov */ 595de9ce703SDmitry Torokhov 596de9ce703SDmitry Torokhov static int i8042_enable_kbd_port(void) 597de9ce703SDmitry Torokhov { 598de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_KBDDIS; 599de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_KBDINT; 600de9ce703SDmitry Torokhov 601de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 602018db6bbSMarkus Armbruster i8042_ctr &= ~I8042_CTR_KBDINT; 603018db6bbSMarkus Armbruster i8042_ctr |= I8042_CTR_KBDDIS; 6044eb3c30bSJoe Perches pr_err("Failed to enable KBD port\n"); 605de9ce703SDmitry Torokhov return -EIO; 606de9ce703SDmitry Torokhov } 607de9ce703SDmitry Torokhov 608de9ce703SDmitry Torokhov return 0; 609de9ce703SDmitry Torokhov } 610de9ce703SDmitry Torokhov 611de9ce703SDmitry Torokhov /* 612de9ce703SDmitry Torokhov * i8042_enable_aux_port enables AUX (mouse) port on chip 613de9ce703SDmitry Torokhov */ 614de9ce703SDmitry Torokhov 615de9ce703SDmitry Torokhov static int i8042_enable_aux_port(void) 616de9ce703SDmitry Torokhov { 617de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_AUXDIS; 618de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXINT; 619de9ce703SDmitry Torokhov 620de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 621018db6bbSMarkus Armbruster i8042_ctr &= ~I8042_CTR_AUXINT; 622018db6bbSMarkus Armbruster i8042_ctr |= I8042_CTR_AUXDIS; 6234eb3c30bSJoe Perches pr_err("Failed to enable AUX port\n"); 624de9ce703SDmitry Torokhov return -EIO; 625de9ce703SDmitry Torokhov } 626de9ce703SDmitry Torokhov 627de9ce703SDmitry Torokhov return 0; 628de9ce703SDmitry Torokhov } 629de9ce703SDmitry Torokhov 630de9ce703SDmitry Torokhov /* 631de9ce703SDmitry Torokhov * i8042_enable_mux_ports enables 4 individual AUX ports after 632de9ce703SDmitry Torokhov * the controller has been switched into Multiplexed mode 633de9ce703SDmitry Torokhov */ 634de9ce703SDmitry Torokhov 635de9ce703SDmitry Torokhov static int i8042_enable_mux_ports(void) 636de9ce703SDmitry Torokhov { 637de9ce703SDmitry Torokhov unsigned char param; 638de9ce703SDmitry Torokhov int i; 639de9ce703SDmitry Torokhov 640de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { 641de9ce703SDmitry Torokhov i8042_command(¶m, I8042_CMD_MUX_PFX + i); 642de9ce703SDmitry Torokhov i8042_command(¶m, I8042_CMD_AUX_ENABLE); 643de9ce703SDmitry Torokhov } 644de9ce703SDmitry Torokhov 645de9ce703SDmitry Torokhov return i8042_enable_aux_port(); 646de9ce703SDmitry Torokhov } 647de9ce703SDmitry Torokhov 648de9ce703SDmitry Torokhov /* 649386b3849SDmitry Torokhov * i8042_set_mux_mode checks whether the controller has an 650386b3849SDmitry Torokhov * active multiplexor and puts the chip into Multiplexed (true) 651386b3849SDmitry Torokhov * or Legacy (false) mode. 6521da177e4SLinus Torvalds */ 6531da177e4SLinus Torvalds 654386b3849SDmitry Torokhov static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version) 6551da177e4SLinus Torvalds { 6561da177e4SLinus Torvalds 657386b3849SDmitry Torokhov unsigned char param, val; 6581da177e4SLinus Torvalds /* 6591da177e4SLinus Torvalds * Get rid of bytes in the queue. 6601da177e4SLinus Torvalds */ 6611da177e4SLinus Torvalds 6621da177e4SLinus Torvalds i8042_flush(); 6631da177e4SLinus Torvalds 6641da177e4SLinus Torvalds /* 6651da177e4SLinus Torvalds * Internal loopback test - send three bytes, they should come back from the 666de9ce703SDmitry Torokhov * mouse interface, the last should be version. 6671da177e4SLinus Torvalds */ 6681da177e4SLinus Torvalds 669386b3849SDmitry Torokhov param = val = 0xf0; 670386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != val) 6711da177e4SLinus Torvalds return -1; 672386b3849SDmitry Torokhov param = val = multiplex ? 0x56 : 0xf6; 673386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != val) 6741da177e4SLinus Torvalds return -1; 675386b3849SDmitry Torokhov param = val = multiplex ? 0xa4 : 0xa5; 676386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == val) 677386b3849SDmitry Torokhov return -1; 678386b3849SDmitry Torokhov 679386b3849SDmitry Torokhov /* 680386b3849SDmitry Torokhov * Workaround for interference with USB Legacy emulation 681386b3849SDmitry Torokhov * that causes a v10.12 MUX to be found. 682386b3849SDmitry Torokhov */ 683386b3849SDmitry Torokhov if (param == 0xac) 6841da177e4SLinus Torvalds return -1; 6851da177e4SLinus Torvalds 6861da177e4SLinus Torvalds if (mux_version) 687463a4f76SDmitry Torokhov *mux_version = param; 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds return 0; 6901da177e4SLinus Torvalds } 6911da177e4SLinus Torvalds 6921da177e4SLinus Torvalds /* 6931da177e4SLinus Torvalds * i8042_check_mux() checks whether the controller supports the PS/2 Active 6941da177e4SLinus Torvalds * Multiplexing specification by Synaptics, Phoenix, Insyde and 6951da177e4SLinus Torvalds * LCS/Telegraphics. 6961da177e4SLinus Torvalds */ 6971da177e4SLinus Torvalds 698f8113416SDmitry Torokhov static int __init i8042_check_mux(void) 6991da177e4SLinus Torvalds { 7001da177e4SLinus Torvalds unsigned char mux_version; 7011da177e4SLinus Torvalds 702386b3849SDmitry Torokhov if (i8042_set_mux_mode(true, &mux_version)) 7031da177e4SLinus Torvalds return -1; 7041da177e4SLinus Torvalds 7054eb3c30bSJoe Perches pr_info("Detected active multiplexing controller, rev %d.%d\n", 7061da177e4SLinus Torvalds (mux_version >> 4) & 0xf, mux_version & 0xf); 7071da177e4SLinus Torvalds 708de9ce703SDmitry Torokhov /* 709de9ce703SDmitry Torokhov * Disable all muxed ports by disabling AUX. 710de9ce703SDmitry Torokhov */ 711de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXDIS; 712de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_AUXINT; 713de9ce703SDmitry Torokhov 714de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 7154eb3c30bSJoe Perches pr_err("Failed to disable AUX port, can't use MUX\n"); 716de9ce703SDmitry Torokhov return -EIO; 717de9ce703SDmitry Torokhov } 7181da177e4SLinus Torvalds 719386b3849SDmitry Torokhov i8042_mux_present = true; 720de9ce703SDmitry Torokhov 7211da177e4SLinus Torvalds return 0; 7221da177e4SLinus Torvalds } 7231da177e4SLinus Torvalds 724de9ce703SDmitry Torokhov /* 725de9ce703SDmitry Torokhov * The following is used to test AUX IRQ delivery. 726de9ce703SDmitry Torokhov */ 727f8113416SDmitry Torokhov static struct completion i8042_aux_irq_delivered __initdata; 728f8113416SDmitry Torokhov static bool i8042_irq_being_tested __initdata; 729de9ce703SDmitry Torokhov 730f8113416SDmitry Torokhov static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id) 731de9ce703SDmitry Torokhov { 732de9ce703SDmitry Torokhov unsigned long flags; 733de9ce703SDmitry Torokhov unsigned char str, data; 734e3758b2aSFernando Luis Vázquez Cao int ret = 0; 735de9ce703SDmitry Torokhov 736de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 737de9ce703SDmitry Torokhov str = i8042_read_status(); 738de9ce703SDmitry Torokhov if (str & I8042_STR_OBF) { 739de9ce703SDmitry Torokhov data = i8042_read_data(); 7404eb3c30bSJoe Perches dbg("%02x <- i8042 (aux_test_irq, %s)\n", 741d3d2dfe2SDmitry Torokhov data, str & I8042_STR_AUXDATA ? "aux" : "kbd"); 742de9ce703SDmitry Torokhov if (i8042_irq_being_tested && 743de9ce703SDmitry Torokhov data == 0xa5 && (str & I8042_STR_AUXDATA)) 744de9ce703SDmitry Torokhov complete(&i8042_aux_irq_delivered); 745e3758b2aSFernando Luis Vázquez Cao ret = 1; 746de9ce703SDmitry Torokhov } 747de9ce703SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 748de9ce703SDmitry Torokhov 749e3758b2aSFernando Luis Vázquez Cao return IRQ_RETVAL(ret); 750de9ce703SDmitry Torokhov } 751de9ce703SDmitry Torokhov 752d2ada559SRoland Scheidegger /* 753d2ada559SRoland Scheidegger * i8042_toggle_aux - enables or disables AUX port on i8042 via command and 754d2ada559SRoland Scheidegger * verifies success by readinng CTR. Used when testing for presence of AUX 755d2ada559SRoland Scheidegger * port. 756d2ada559SRoland Scheidegger */ 757f8113416SDmitry Torokhov static int __init i8042_toggle_aux(bool on) 758d2ada559SRoland Scheidegger { 759d2ada559SRoland Scheidegger unsigned char param; 760d2ada559SRoland Scheidegger int i; 761d2ada559SRoland Scheidegger 762d2ada559SRoland Scheidegger if (i8042_command(¶m, 763d2ada559SRoland Scheidegger on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE)) 764d2ada559SRoland Scheidegger return -1; 765d2ada559SRoland Scheidegger 766d2ada559SRoland Scheidegger /* some chips need some time to set the I8042_CTR_AUXDIS bit */ 767d2ada559SRoland Scheidegger for (i = 0; i < 100; i++) { 768d2ada559SRoland Scheidegger udelay(50); 769d2ada559SRoland Scheidegger 770d2ada559SRoland Scheidegger if (i8042_command(¶m, I8042_CMD_CTL_RCTR)) 771d2ada559SRoland Scheidegger return -1; 772d2ada559SRoland Scheidegger 773d2ada559SRoland Scheidegger if (!(param & I8042_CTR_AUXDIS) == on) 774d2ada559SRoland Scheidegger return 0; 775d2ada559SRoland Scheidegger } 776d2ada559SRoland Scheidegger 777d2ada559SRoland Scheidegger return -1; 778d2ada559SRoland Scheidegger } 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds /* 7811da177e4SLinus Torvalds * i8042_check_aux() applies as much paranoia as it can at detecting 7821da177e4SLinus Torvalds * the presence of an AUX interface. 7831da177e4SLinus Torvalds */ 7841da177e4SLinus Torvalds 785f8113416SDmitry Torokhov static int __init i8042_check_aux(void) 7861da177e4SLinus Torvalds { 787de9ce703SDmitry Torokhov int retval = -1; 788386b3849SDmitry Torokhov bool irq_registered = false; 789386b3849SDmitry Torokhov bool aux_loop_broken = false; 790de9ce703SDmitry Torokhov unsigned long flags; 7911da177e4SLinus Torvalds unsigned char param; 7921da177e4SLinus Torvalds 7931da177e4SLinus Torvalds /* 7941da177e4SLinus Torvalds * Get rid of bytes in the queue. 7951da177e4SLinus Torvalds */ 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds i8042_flush(); 7981da177e4SLinus Torvalds 7991da177e4SLinus Torvalds /* 8001da177e4SLinus Torvalds * Internal loopback test - filters out AT-type i8042's. Unfortunately 8011da177e4SLinus Torvalds * SiS screwed up and their 5597 doesn't support the LOOP command even 8021da177e4SLinus Torvalds * though it has an AUX port. 8031da177e4SLinus Torvalds */ 8041da177e4SLinus Torvalds 8051da177e4SLinus Torvalds param = 0x5a; 8063ca5de6dSDmitry Torokhov retval = i8042_command(¶m, I8042_CMD_AUX_LOOP); 8073ca5de6dSDmitry Torokhov if (retval || param != 0x5a) { 8081da177e4SLinus Torvalds 8091da177e4SLinus Torvalds /* 8101da177e4SLinus Torvalds * External connection test - filters out AT-soldered PS/2 i8042's 8111da177e4SLinus Torvalds * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error 8121da177e4SLinus Torvalds * 0xfa - no error on some notebooks which ignore the spec 8131da177e4SLinus Torvalds * Because it's common for chipsets to return error on perfectly functioning 8141da177e4SLinus Torvalds * AUX ports, we test for this only when the LOOP command failed. 8151da177e4SLinus Torvalds */ 8161da177e4SLinus Torvalds 817de9ce703SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_TEST) || 818de9ce703SDmitry Torokhov (param && param != 0xfa && param != 0xff)) 8191da177e4SLinus Torvalds return -1; 8201e4865f8SDmitry Torokhov 8213ca5de6dSDmitry Torokhov /* 8223ca5de6dSDmitry Torokhov * If AUX_LOOP completed without error but returned unexpected data 8233ca5de6dSDmitry Torokhov * mark it as broken 8243ca5de6dSDmitry Torokhov */ 8253ca5de6dSDmitry Torokhov if (!retval) 826386b3849SDmitry Torokhov aux_loop_broken = true; 8271da177e4SLinus Torvalds } 8281da177e4SLinus Torvalds 8291da177e4SLinus Torvalds /* 8301da177e4SLinus Torvalds * Bit assignment test - filters out PS/2 i8042's in AT mode 8311da177e4SLinus Torvalds */ 8321da177e4SLinus Torvalds 833386b3849SDmitry Torokhov if (i8042_toggle_aux(false)) { 8344eb3c30bSJoe Perches pr_warn("Failed to disable AUX port, but continuing anyway... Is this a SiS?\n"); 8354eb3c30bSJoe Perches pr_warn("If AUX port is really absent please use the 'i8042.noaux' option\n"); 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds 838386b3849SDmitry Torokhov if (i8042_toggle_aux(true)) 8391da177e4SLinus Torvalds return -1; 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds /* 842148e9a71SSrihari Vijayaraghavan * Reset keyboard (needed on some laptops to successfully detect 843148e9a71SSrihari Vijayaraghavan * touchpad, e.g., some Gigabyte laptop models with Elantech 844148e9a71SSrihari Vijayaraghavan * touchpads). 845148e9a71SSrihari Vijayaraghavan */ 846148e9a71SSrihari Vijayaraghavan if (i8042_kbdreset) { 847148e9a71SSrihari Vijayaraghavan pr_warn("Attempting to reset device connected to KBD port\n"); 848148e9a71SSrihari Vijayaraghavan i8042_kbd_write(NULL, (unsigned char) 0xff); 849148e9a71SSrihari Vijayaraghavan } 850148e9a71SSrihari Vijayaraghavan 851148e9a71SSrihari Vijayaraghavan /* 852de9ce703SDmitry Torokhov * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and 853de9ce703SDmitry Torokhov * used it for a PCI card or somethig else. 854de9ce703SDmitry Torokhov */ 855de9ce703SDmitry Torokhov 8561c7827aeSDmitry Torokhov if (i8042_noloop || i8042_bypass_aux_irq_test || aux_loop_broken) { 857de9ce703SDmitry Torokhov /* 858de9ce703SDmitry Torokhov * Without LOOP command we can't test AUX IRQ delivery. Assume the port 859de9ce703SDmitry Torokhov * is working and hope we are right. 860de9ce703SDmitry Torokhov */ 861de9ce703SDmitry Torokhov retval = 0; 862de9ce703SDmitry Torokhov goto out; 863de9ce703SDmitry Torokhov } 864de9ce703SDmitry Torokhov 865de9ce703SDmitry Torokhov if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED, 866de9ce703SDmitry Torokhov "i8042", i8042_platform_device)) 867de9ce703SDmitry Torokhov goto out; 868de9ce703SDmitry Torokhov 869386b3849SDmitry Torokhov irq_registered = true; 870de9ce703SDmitry Torokhov 871de9ce703SDmitry Torokhov if (i8042_enable_aux_port()) 872de9ce703SDmitry Torokhov goto out; 873de9ce703SDmitry Torokhov 874de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 875de9ce703SDmitry Torokhov 876de9ce703SDmitry Torokhov init_completion(&i8042_aux_irq_delivered); 877386b3849SDmitry Torokhov i8042_irq_being_tested = true; 878de9ce703SDmitry Torokhov 879de9ce703SDmitry Torokhov param = 0xa5; 880de9ce703SDmitry Torokhov retval = __i8042_command(¶m, I8042_CMD_AUX_LOOP & 0xf0ff); 881de9ce703SDmitry Torokhov 882de9ce703SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 883de9ce703SDmitry Torokhov 884de9ce703SDmitry Torokhov if (retval) 885de9ce703SDmitry Torokhov goto out; 886de9ce703SDmitry Torokhov 887de9ce703SDmitry Torokhov if (wait_for_completion_timeout(&i8042_aux_irq_delivered, 888de9ce703SDmitry Torokhov msecs_to_jiffies(250)) == 0) { 889de9ce703SDmitry Torokhov /* 890de9ce703SDmitry Torokhov * AUX IRQ was never delivered so we need to flush the controller to 891de9ce703SDmitry Torokhov * get rid of the byte we put there; otherwise keyboard may not work. 892de9ce703SDmitry Torokhov */ 8934eb3c30bSJoe Perches dbg(" -- i8042 (aux irq test timeout)\n"); 894de9ce703SDmitry Torokhov i8042_flush(); 895de9ce703SDmitry Torokhov retval = -1; 896de9ce703SDmitry Torokhov } 897de9ce703SDmitry Torokhov 898de9ce703SDmitry Torokhov out: 899de9ce703SDmitry Torokhov 900de9ce703SDmitry Torokhov /* 9011da177e4SLinus Torvalds * Disable the interface. 9021da177e4SLinus Torvalds */ 9031da177e4SLinus Torvalds 9041da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_AUXDIS; 9051da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_AUXINT; 9061da177e4SLinus Torvalds 9071da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 908de9ce703SDmitry Torokhov retval = -1; 909de9ce703SDmitry Torokhov 910de9ce703SDmitry Torokhov if (irq_registered) 911de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 912de9ce703SDmitry Torokhov 913de9ce703SDmitry Torokhov return retval; 914de9ce703SDmitry Torokhov } 915de9ce703SDmitry Torokhov 916de9ce703SDmitry Torokhov static int i8042_controller_check(void) 917de9ce703SDmitry Torokhov { 9182f0d2604SAndrey Moiseev if (i8042_flush()) { 919f5d75341STakashi Iwai pr_info("No controller found\n"); 920de9ce703SDmitry Torokhov return -ENODEV; 921de9ce703SDmitry Torokhov } 9221da177e4SLinus Torvalds 9231da177e4SLinus Torvalds return 0; 9241da177e4SLinus Torvalds } 9251da177e4SLinus Torvalds 926de9ce703SDmitry Torokhov static int i8042_controller_selftest(void) 9272673c836SVojtech Pavlik { 9282673c836SVojtech Pavlik unsigned char param; 9295ea2fc64SArjan van de Ven int i = 0; 9302673c836SVojtech Pavlik 9315ea2fc64SArjan van de Ven /* 9325ea2fc64SArjan van de Ven * We try this 5 times; on some really fragile systems this does not 9335ea2fc64SArjan van de Ven * take the first time... 9345ea2fc64SArjan van de Ven */ 9355ea2fc64SArjan van de Ven do { 9365ea2fc64SArjan van de Ven 9372673c836SVojtech Pavlik if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { 9384eb3c30bSJoe Perches pr_err("i8042 controller selftest timeout\n"); 939de9ce703SDmitry Torokhov return -ENODEV; 9402673c836SVojtech Pavlik } 9412673c836SVojtech Pavlik 9425ea2fc64SArjan van de Ven if (param == I8042_RET_CTL_TEST) 9435ea2fc64SArjan van de Ven return 0; 9445ea2fc64SArjan van de Ven 945a2a94e73SPaul Bolle dbg("i8042 controller selftest: %#x != %#x\n", 9462673c836SVojtech Pavlik param, I8042_RET_CTL_TEST); 9475ea2fc64SArjan van de Ven msleep(50); 9485ea2fc64SArjan van de Ven } while (i++ < 5); 9492673c836SVojtech Pavlik 9505ea2fc64SArjan van de Ven #ifdef CONFIG_X86 9515ea2fc64SArjan van de Ven /* 9525ea2fc64SArjan van de Ven * On x86, we don't fail entire i8042 initialization if controller 9535ea2fc64SArjan van de Ven * reset fails in hopes that keyboard port will still be functional 9545ea2fc64SArjan van de Ven * and user will still get a working keyboard. This is especially 9555ea2fc64SArjan van de Ven * important on netbooks. On other arches we trust hardware more. 9565ea2fc64SArjan van de Ven */ 9574eb3c30bSJoe Perches pr_info("giving up on controller selftest, continuing anyway...\n"); 9582673c836SVojtech Pavlik return 0; 9595ea2fc64SArjan van de Ven #else 960a2a94e73SPaul Bolle pr_err("i8042 controller selftest failed\n"); 9615ea2fc64SArjan van de Ven return -EIO; 9625ea2fc64SArjan van de Ven #endif 9632673c836SVojtech Pavlik } 9641da177e4SLinus Torvalds 9651da177e4SLinus Torvalds /* 9661da177e4SLinus Torvalds * i8042_controller init initializes the i8042 controller, and, 9671da177e4SLinus Torvalds * most importantly, sets it into non-xlated mode if that's 9681da177e4SLinus Torvalds * desired. 9691da177e4SLinus Torvalds */ 9701da177e4SLinus Torvalds 9711da177e4SLinus Torvalds static int i8042_controller_init(void) 9721da177e4SLinus Torvalds { 9731da177e4SLinus Torvalds unsigned long flags; 974ee1e82ceSDmitry Torokhov int n = 0; 975ee1e82ceSDmitry Torokhov unsigned char ctr[2]; 9761da177e4SLinus Torvalds 9771da177e4SLinus Torvalds /* 978ee1e82ceSDmitry Torokhov * Save the CTR for restore on unload / reboot. 9791da177e4SLinus Torvalds */ 9801da177e4SLinus Torvalds 981ee1e82ceSDmitry Torokhov do { 982ee1e82ceSDmitry Torokhov if (n >= 10) { 9834eb3c30bSJoe Perches pr_err("Unable to get stable CTR read\n"); 984de9ce703SDmitry Torokhov return -EIO; 9851da177e4SLinus Torvalds } 9861da177e4SLinus Torvalds 987ee1e82ceSDmitry Torokhov if (n != 0) 988ee1e82ceSDmitry Torokhov udelay(50); 989ee1e82ceSDmitry Torokhov 990ee1e82ceSDmitry Torokhov if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) { 9914eb3c30bSJoe Perches pr_err("Can't read CTR while initializing i8042\n"); 992ee1e82ceSDmitry Torokhov return -EIO; 993ee1e82ceSDmitry Torokhov } 994ee1e82ceSDmitry Torokhov 995ee1e82ceSDmitry Torokhov } while (n < 2 || ctr[0] != ctr[1]); 996ee1e82ceSDmitry Torokhov 997ee1e82ceSDmitry Torokhov i8042_initial_ctr = i8042_ctr = ctr[0]; 9981da177e4SLinus Torvalds 9991da177e4SLinus Torvalds /* 10001da177e4SLinus Torvalds * Disable the keyboard interface and interrupt. 10011da177e4SLinus Torvalds */ 10021da177e4SLinus Torvalds 10031da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_KBDDIS; 10041da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_KBDINT; 10051da177e4SLinus Torvalds 10061da177e4SLinus Torvalds /* 10071da177e4SLinus Torvalds * Handle keylock. 10081da177e4SLinus Torvalds */ 10091da177e4SLinus Torvalds 10101da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 10111da177e4SLinus Torvalds if (~i8042_read_status() & I8042_STR_KEYLOCK) { 10121da177e4SLinus Torvalds if (i8042_unlock) 10131da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_IGNKEYLOCK; 10141da177e4SLinus Torvalds else 10154eb3c30bSJoe Perches pr_warn("Warning: Keylock active\n"); 10161da177e4SLinus Torvalds } 10171da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 10181da177e4SLinus Torvalds 10191da177e4SLinus Torvalds /* 10201da177e4SLinus Torvalds * If the chip is configured into nontranslated mode by the BIOS, don't 10211da177e4SLinus Torvalds * bother enabling translating and be happy. 10221da177e4SLinus Torvalds */ 10231da177e4SLinus Torvalds 10241da177e4SLinus Torvalds if (~i8042_ctr & I8042_CTR_XLATE) 1025386b3849SDmitry Torokhov i8042_direct = true; 10261da177e4SLinus Torvalds 10271da177e4SLinus Torvalds /* 10281da177e4SLinus Torvalds * Set nontranslated mode for the kbd interface if requested by an option. 10291da177e4SLinus Torvalds * After this the kbd interface becomes a simple serial in/out, like the aux 10301da177e4SLinus Torvalds * interface is. We don't do this by default, since it can confuse notebook 10311da177e4SLinus Torvalds * BIOSes. 10321da177e4SLinus Torvalds */ 10331da177e4SLinus Torvalds 10341da177e4SLinus Torvalds if (i8042_direct) 10351da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_XLATE; 10361da177e4SLinus Torvalds 10371da177e4SLinus Torvalds /* 10381da177e4SLinus Torvalds * Write CTR back. 10391da177e4SLinus Torvalds */ 10401da177e4SLinus Torvalds 10411da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 10424eb3c30bSJoe Perches pr_err("Can't write CTR while initializing i8042\n"); 1043de9ce703SDmitry Torokhov return -EIO; 10441da177e4SLinus Torvalds } 10451da177e4SLinus Torvalds 1046ee1e82ceSDmitry Torokhov /* 1047ee1e82ceSDmitry Torokhov * Flush whatever accumulated while we were disabling keyboard port. 1048ee1e82ceSDmitry Torokhov */ 1049ee1e82ceSDmitry Torokhov 1050ee1e82ceSDmitry Torokhov i8042_flush(); 1051ee1e82ceSDmitry Torokhov 10521da177e4SLinus Torvalds return 0; 10531da177e4SLinus Torvalds } 10541da177e4SLinus Torvalds 10551da177e4SLinus Torvalds 10561da177e4SLinus Torvalds /* 1057de9ce703SDmitry Torokhov * Reset the controller and reset CRT to the original value set by BIOS. 10581da177e4SLinus Torvalds */ 10591da177e4SLinus Torvalds 1060930e1924SMarcos Paulo de Souza static void i8042_controller_reset(bool s2r_wants_reset) 1061de9ce703SDmitry Torokhov { 1062de9ce703SDmitry Torokhov i8042_flush(); 10631da177e4SLinus Torvalds 10641da177e4SLinus Torvalds /* 10658d04ddb6SDmitry Torokhov * Disable both KBD and AUX interfaces so they don't get in the way 10668d04ddb6SDmitry Torokhov */ 10678d04ddb6SDmitry Torokhov 10688d04ddb6SDmitry Torokhov i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS; 10698d04ddb6SDmitry Torokhov i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT); 10708d04ddb6SDmitry Torokhov 1071ee1e82ceSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 10724eb3c30bSJoe Perches pr_warn("Can't write CTR while resetting\n"); 10735ddbc77cSDmitry Torokhov 10748d04ddb6SDmitry Torokhov /* 10751da177e4SLinus Torvalds * Disable MUX mode if present. 10761da177e4SLinus Torvalds */ 10771da177e4SLinus Torvalds 10781da177e4SLinus Torvalds if (i8042_mux_present) 1079386b3849SDmitry Torokhov i8042_set_mux_mode(false, NULL); 10801da177e4SLinus Torvalds 10811da177e4SLinus Torvalds /* 1082de9ce703SDmitry Torokhov * Reset the controller if requested. 1083de9ce703SDmitry Torokhov */ 1084de9ce703SDmitry Torokhov 1085930e1924SMarcos Paulo de Souza if (i8042_reset == I8042_RESET_ALWAYS || 1086930e1924SMarcos Paulo de Souza (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) { 1087de9ce703SDmitry Torokhov i8042_controller_selftest(); 1088930e1924SMarcos Paulo de Souza } 1089de9ce703SDmitry Torokhov 1090de9ce703SDmitry Torokhov /* 10911da177e4SLinus Torvalds * Restore the original control register setting. 10921da177e4SLinus Torvalds */ 10931da177e4SLinus Torvalds 1094de9ce703SDmitry Torokhov if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR)) 10954eb3c30bSJoe Perches pr_warn("Can't restore CTR\n"); 10961da177e4SLinus Torvalds } 10971da177e4SLinus Torvalds 10981da177e4SLinus Torvalds 10991da177e4SLinus Torvalds /* 1100c7ff0d9cSTAMUKI Shoichi * i8042_panic_blink() will turn the keyboard LEDs on or off and is called 1101c7ff0d9cSTAMUKI Shoichi * when kernel panics. Flashing LEDs is useful for users running X who may 1102aa5e5dc2SMichael Opdenacker * not see the console and will help distinguishing panics from "real" 11031da177e4SLinus Torvalds * lockups. 11041da177e4SLinus Torvalds * 11051da177e4SLinus Torvalds * Note that DELAY has a limit of 10ms so we will not get stuck here 11061da177e4SLinus Torvalds * waiting for KBC to free up even if KBD interrupt is off 11071da177e4SLinus Torvalds */ 11081da177e4SLinus Torvalds 11091da177e4SLinus Torvalds #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0) 11101da177e4SLinus Torvalds 1111c7ff0d9cSTAMUKI Shoichi static long i8042_panic_blink(int state) 11121da177e4SLinus Torvalds { 11131da177e4SLinus Torvalds long delay = 0; 1114c7ff0d9cSTAMUKI Shoichi char led; 11151da177e4SLinus Torvalds 1116c7ff0d9cSTAMUKI Shoichi led = (state) ? 0x01 | 0x04 : 0; 11171da177e4SLinus Torvalds while (i8042_read_status() & I8042_STR_IBF) 11181da177e4SLinus Torvalds DELAY; 11194eb3c30bSJoe Perches dbg("%02x -> i8042 (panic blink)\n", 0xed); 112019f3c3e3SDmitry Torokhov i8042_suppress_kbd_ack = 2; 11211da177e4SLinus Torvalds i8042_write_data(0xed); /* set leds */ 11221da177e4SLinus Torvalds DELAY; 11231da177e4SLinus Torvalds while (i8042_read_status() & I8042_STR_IBF) 11241da177e4SLinus Torvalds DELAY; 11251da177e4SLinus Torvalds DELAY; 11264eb3c30bSJoe Perches dbg("%02x -> i8042 (panic blink)\n", led); 11271da177e4SLinus Torvalds i8042_write_data(led); 11281da177e4SLinus Torvalds DELAY; 11291da177e4SLinus Torvalds return delay; 11301da177e4SLinus Torvalds } 11311da177e4SLinus Torvalds 11321da177e4SLinus Torvalds #undef DELAY 11331da177e4SLinus Torvalds 1134d35895dbSBruno Prémont #ifdef CONFIG_X86 1135d35895dbSBruno Prémont static void i8042_dritek_enable(void) 1136d35895dbSBruno Prémont { 1137594d6363SChristoph Fritz unsigned char param = 0x90; 1138d35895dbSBruno Prémont int error; 1139d35895dbSBruno Prémont 1140d35895dbSBruno Prémont error = i8042_command(¶m, 0x1059); 1141d35895dbSBruno Prémont if (error) 11424eb3c30bSJoe Perches pr_warn("Failed to enable DRITEK extension: %d\n", error); 1143d35895dbSBruno Prémont } 1144d35895dbSBruno Prémont #endif 1145d35895dbSBruno Prémont 114682dd9effSDmitry Torokhov #ifdef CONFIG_PM 11477e044e05SDmitry Torokhov 11481da177e4SLinus Torvalds /* 1149ebd7768dSDmitry Torokhov * Here we try to reset everything back to a state we had 1150ebd7768dSDmitry Torokhov * before suspending. 11511da177e4SLinus Torvalds */ 11521da177e4SLinus Torvalds 1153930e1924SMarcos Paulo de Souza static int i8042_controller_resume(bool s2r_wants_reset) 11541da177e4SLinus Torvalds { 1155de9ce703SDmitry Torokhov int error; 11561da177e4SLinus Torvalds 1157de9ce703SDmitry Torokhov error = i8042_controller_check(); 1158de9ce703SDmitry Torokhov if (error) 1159de9ce703SDmitry Torokhov return error; 11602673c836SVojtech Pavlik 1161930e1924SMarcos Paulo de Souza if (i8042_reset == I8042_RESET_ALWAYS || 1162930e1924SMarcos Paulo de Souza (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) { 1163de9ce703SDmitry Torokhov error = i8042_controller_selftest(); 1164de9ce703SDmitry Torokhov if (error) 1165de9ce703SDmitry Torokhov return error; 11661ca56e51SDmitry Torokhov } 1167de9ce703SDmitry Torokhov 1168de9ce703SDmitry Torokhov /* 116982dd9effSDmitry Torokhov * Restore original CTR value and disable all ports 1170de9ce703SDmitry Torokhov */ 1171de9ce703SDmitry Torokhov 117282dd9effSDmitry Torokhov i8042_ctr = i8042_initial_ctr; 117382dd9effSDmitry Torokhov if (i8042_direct) 117482dd9effSDmitry Torokhov i8042_ctr &= ~I8042_CTR_XLATE; 1175de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS; 1176de9ce703SDmitry Torokhov i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT); 11772673c836SVojtech Pavlik if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 11784eb3c30bSJoe Perches pr_warn("Can't write CTR to resume, retrying...\n"); 11792f6a77d5SJiri Kosina msleep(50); 11802f6a77d5SJiri Kosina if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 11814eb3c30bSJoe Perches pr_err("CTR write retry failed\n"); 1182de9ce703SDmitry Torokhov return -EIO; 11831da177e4SLinus Torvalds } 11842f6a77d5SJiri Kosina } 11851da177e4SLinus Torvalds 1186d35895dbSBruno Prémont 1187d35895dbSBruno Prémont #ifdef CONFIG_X86 1188d35895dbSBruno Prémont if (i8042_dritek) 1189d35895dbSBruno Prémont i8042_dritek_enable(); 1190d35895dbSBruno Prémont #endif 1191d35895dbSBruno Prémont 1192de9ce703SDmitry Torokhov if (i8042_mux_present) { 1193386b3849SDmitry Torokhov if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports()) 11944eb3c30bSJoe Perches pr_warn("failed to resume active multiplexor, mouse won't work\n"); 1195de9ce703SDmitry Torokhov } else if (i8042_ports[I8042_AUX_PORT_NO].serio) 1196de9ce703SDmitry Torokhov i8042_enable_aux_port(); 11971da177e4SLinus Torvalds 1198de9ce703SDmitry Torokhov if (i8042_ports[I8042_KBD_PORT_NO].serio) 1199de9ce703SDmitry Torokhov i8042_enable_kbd_port(); 12001da177e4SLinus Torvalds 12017d12e780SDavid Howells i8042_interrupt(0, NULL); 12021da177e4SLinus Torvalds 12031da177e4SLinus Torvalds return 0; 12041da177e4SLinus Torvalds } 1205ebd7768dSDmitry Torokhov 12061ca56e51SDmitry Torokhov /* 12071ca56e51SDmitry Torokhov * Here we try to restore the original BIOS settings to avoid 12081ca56e51SDmitry Torokhov * upsetting it. 12091ca56e51SDmitry Torokhov */ 12101ca56e51SDmitry Torokhov 12111729ad1fSDmitry Torokhov static int i8042_pm_suspend(struct device *dev) 12121ca56e51SDmitry Torokhov { 1213f13b2065SRafael J. Wysocki int i; 1214f13b2065SRafael J. Wysocki 12151c5dd134SRafael J. Wysocki if (pm_suspend_via_firmware()) 12161729ad1fSDmitry Torokhov i8042_controller_reset(true); 12171ca56e51SDmitry Torokhov 1218f13b2065SRafael J. Wysocki /* Set up serio interrupts for system wakeup. */ 1219f13b2065SRafael J. Wysocki for (i = 0; i < I8042_NUM_PORTS; i++) { 1220f13b2065SRafael J. Wysocki struct serio *serio = i8042_ports[i].serio; 1221f13b2065SRafael J. Wysocki 1222f13b2065SRafael J. Wysocki if (serio && device_may_wakeup(&serio->dev)) 1223f13b2065SRafael J. Wysocki enable_irq_wake(i8042_ports[i].irq); 1224f13b2065SRafael J. Wysocki } 1225f13b2065SRafael J. Wysocki 12261ca56e51SDmitry Torokhov return 0; 12271ca56e51SDmitry Torokhov } 12281ca56e51SDmitry Torokhov 12291c5dd134SRafael J. Wysocki static int i8042_pm_resume_noirq(struct device *dev) 12301c5dd134SRafael J. Wysocki { 12311c5dd134SRafael J. Wysocki if (!pm_resume_via_firmware()) 12321c5dd134SRafael J. Wysocki i8042_interrupt(0, NULL); 12331c5dd134SRafael J. Wysocki 12341c5dd134SRafael J. Wysocki return 0; 12351c5dd134SRafael J. Wysocki } 12361c5dd134SRafael J. Wysocki 12371ca56e51SDmitry Torokhov static int i8042_pm_resume(struct device *dev) 12381ca56e51SDmitry Torokhov { 1239930e1924SMarcos Paulo de Souza bool want_reset; 1240f13b2065SRafael J. Wysocki int i; 1241f13b2065SRafael J. Wysocki 1242f13b2065SRafael J. Wysocki for (i = 0; i < I8042_NUM_PORTS; i++) { 1243f13b2065SRafael J. Wysocki struct serio *serio = i8042_ports[i].serio; 1244f13b2065SRafael J. Wysocki 1245f13b2065SRafael J. Wysocki if (serio && device_may_wakeup(&serio->dev)) 1246f13b2065SRafael J. Wysocki disable_irq_wake(i8042_ports[i].irq); 1247f13b2065SRafael J. Wysocki } 1248f13b2065SRafael J. Wysocki 12491ca56e51SDmitry Torokhov /* 12501c5dd134SRafael J. Wysocki * If platform firmware was not going to be involved in suspend, we did 12511c5dd134SRafael J. Wysocki * not restore the controller state to whatever it had been at boot 12521c5dd134SRafael J. Wysocki * time, so we do not need to do anything. 12531ca56e51SDmitry Torokhov */ 12541c5dd134SRafael J. Wysocki if (!pm_suspend_via_firmware()) 12551c5dd134SRafael J. Wysocki return 0; 12561c5dd134SRafael J. Wysocki 12571c5dd134SRafael J. Wysocki /* 12581c5dd134SRafael J. Wysocki * We only need to reset the controller if we are resuming after handing 12591c5dd134SRafael J. Wysocki * off control to the platform firmware, otherwise we can simply restore 12601c5dd134SRafael J. Wysocki * the mode. 12611c5dd134SRafael J. Wysocki */ 1262930e1924SMarcos Paulo de Souza want_reset = pm_resume_via_firmware(); 12631c5dd134SRafael J. Wysocki 1264930e1924SMarcos Paulo de Souza return i8042_controller_resume(want_reset); 12651ca56e51SDmitry Torokhov } 12661ca56e51SDmitry Torokhov 1267c2d1a2a1SAlan Jenkins static int i8042_pm_thaw(struct device *dev) 1268c2d1a2a1SAlan Jenkins { 1269c2d1a2a1SAlan Jenkins i8042_interrupt(0, NULL); 1270c2d1a2a1SAlan Jenkins 1271c2d1a2a1SAlan Jenkins return 0; 1272c2d1a2a1SAlan Jenkins } 1273c2d1a2a1SAlan Jenkins 12741729ad1fSDmitry Torokhov static int i8042_pm_reset(struct device *dev) 12751729ad1fSDmitry Torokhov { 12761729ad1fSDmitry Torokhov i8042_controller_reset(false); 12771729ad1fSDmitry Torokhov 12781729ad1fSDmitry Torokhov return 0; 12791729ad1fSDmitry Torokhov } 12801729ad1fSDmitry Torokhov 12811ca56e51SDmitry Torokhov static int i8042_pm_restore(struct device *dev) 12821ca56e51SDmitry Torokhov { 12831ca56e51SDmitry Torokhov return i8042_controller_resume(false); 12841ca56e51SDmitry Torokhov } 12851ca56e51SDmitry Torokhov 1286ebd7768dSDmitry Torokhov static const struct dev_pm_ops i8042_pm_ops = { 12871729ad1fSDmitry Torokhov .suspend = i8042_pm_suspend, 12881c5dd134SRafael J. Wysocki .resume_noirq = i8042_pm_resume_noirq, 12891ca56e51SDmitry Torokhov .resume = i8042_pm_resume, 1290c2d1a2a1SAlan Jenkins .thaw = i8042_pm_thaw, 1291ebd7768dSDmitry Torokhov .poweroff = i8042_pm_reset, 1292ebd7768dSDmitry Torokhov .restore = i8042_pm_restore, 1293ebd7768dSDmitry Torokhov }; 1294ebd7768dSDmitry Torokhov 129582dd9effSDmitry Torokhov #endif /* CONFIG_PM */ 12961da177e4SLinus Torvalds 12971da177e4SLinus Torvalds /* 12981da177e4SLinus Torvalds * We need to reset the 8042 back to original mode on system shutdown, 12991da177e4SLinus Torvalds * because otherwise BIOSes will be confused. 13001da177e4SLinus Torvalds */ 13011da177e4SLinus Torvalds 13023ae5eaecSRussell King static void i8042_shutdown(struct platform_device *dev) 13031da177e4SLinus Torvalds { 13041729ad1fSDmitry Torokhov i8042_controller_reset(false); 13051da177e4SLinus Torvalds } 13061da177e4SLinus Torvalds 1307f8113416SDmitry Torokhov static int __init i8042_create_kbd_port(void) 13081da177e4SLinus Torvalds { 13091da177e4SLinus Torvalds struct serio *serio; 13101da177e4SLinus Torvalds struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; 13111da177e4SLinus Torvalds 1312d39969deSDmitry Torokhov serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 13130854e52dSDmitry Torokhov if (!serio) 13140854e52dSDmitry Torokhov return -ENOMEM; 13150854e52dSDmitry Torokhov 13161da177e4SLinus Torvalds serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; 13171da177e4SLinus Torvalds serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; 13181da177e4SLinus Torvalds serio->start = i8042_start; 13191da177e4SLinus Torvalds serio->stop = i8042_stop; 13205ddbc77cSDmitry Torokhov serio->close = i8042_port_close; 132140974618SDmitry Torokhov serio->ps2_cmd_mutex = &i8042_mutex; 13221da177e4SLinus Torvalds serio->port_data = port; 13231da177e4SLinus Torvalds serio->dev.parent = &i8042_platform_device->dev; 1324de9ce703SDmitry Torokhov strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); 13251da177e4SLinus Torvalds strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); 1326a7c5868cSHans de Goede strlcpy(serio->firmware_id, i8042_kbd_firmware_id, 1327a7c5868cSHans de Goede sizeof(serio->firmware_id)); 13281da177e4SLinus Torvalds 13291da177e4SLinus Torvalds port->serio = serio; 1330de9ce703SDmitry Torokhov port->irq = I8042_KBD_IRQ; 13310854e52dSDmitry Torokhov 1332de9ce703SDmitry Torokhov return 0; 13331da177e4SLinus Torvalds } 13341da177e4SLinus Torvalds 1335f8113416SDmitry Torokhov static int __init i8042_create_aux_port(int idx) 13361da177e4SLinus Torvalds { 13371da177e4SLinus Torvalds struct serio *serio; 1338de9ce703SDmitry Torokhov int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx; 1339de9ce703SDmitry Torokhov struct i8042_port *port = &i8042_ports[port_no]; 13401da177e4SLinus Torvalds 1341d39969deSDmitry Torokhov serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 13420854e52dSDmitry Torokhov if (!serio) 13430854e52dSDmitry Torokhov return -ENOMEM; 13440854e52dSDmitry Torokhov 13451da177e4SLinus Torvalds serio->id.type = SERIO_8042; 13461da177e4SLinus Torvalds serio->write = i8042_aux_write; 13471da177e4SLinus Torvalds serio->start = i8042_start; 13481da177e4SLinus Torvalds serio->stop = i8042_stop; 134947af45d6SDmitry Torokhov serio->ps2_cmd_mutex = &i8042_mutex; 13501da177e4SLinus Torvalds serio->port_data = port; 13511da177e4SLinus Torvalds serio->dev.parent = &i8042_platform_device->dev; 1352de9ce703SDmitry Torokhov if (idx < 0) { 1353de9ce703SDmitry Torokhov strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name)); 13541da177e4SLinus Torvalds strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); 1355a7c5868cSHans de Goede strlcpy(serio->firmware_id, i8042_aux_firmware_id, 1356a7c5868cSHans de Goede sizeof(serio->firmware_id)); 13575ddbc77cSDmitry Torokhov serio->close = i8042_port_close; 1358de9ce703SDmitry Torokhov } else { 1359de9ce703SDmitry Torokhov snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx); 1360de9ce703SDmitry Torokhov snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1); 1361266e43c4SHans de Goede strlcpy(serio->firmware_id, i8042_aux_firmware_id, 1362266e43c4SHans de Goede sizeof(serio->firmware_id)); 13631da177e4SLinus Torvalds } 13641da177e4SLinus Torvalds 13651da177e4SLinus Torvalds port->serio = serio; 1366de9ce703SDmitry Torokhov port->mux = idx; 1367de9ce703SDmitry Torokhov port->irq = I8042_AUX_IRQ; 13680854e52dSDmitry Torokhov 1369de9ce703SDmitry Torokhov return 0; 1370de9ce703SDmitry Torokhov } 1371de9ce703SDmitry Torokhov 1372f8113416SDmitry Torokhov static void __init i8042_free_kbd_port(void) 1373de9ce703SDmitry Torokhov { 1374de9ce703SDmitry Torokhov kfree(i8042_ports[I8042_KBD_PORT_NO].serio); 1375de9ce703SDmitry Torokhov i8042_ports[I8042_KBD_PORT_NO].serio = NULL; 1376de9ce703SDmitry Torokhov } 1377de9ce703SDmitry Torokhov 1378f8113416SDmitry Torokhov static void __init i8042_free_aux_ports(void) 1379de9ce703SDmitry Torokhov { 1380de9ce703SDmitry Torokhov int i; 1381de9ce703SDmitry Torokhov 1382de9ce703SDmitry Torokhov for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) { 1383de9ce703SDmitry Torokhov kfree(i8042_ports[i].serio); 1384de9ce703SDmitry Torokhov i8042_ports[i].serio = NULL; 1385de9ce703SDmitry Torokhov } 1386de9ce703SDmitry Torokhov } 1387de9ce703SDmitry Torokhov 1388f8113416SDmitry Torokhov static void __init i8042_register_ports(void) 1389de9ce703SDmitry Torokhov { 1390de9ce703SDmitry Torokhov int i; 1391de9ce703SDmitry Torokhov 1392de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) { 1393f13b2065SRafael J. Wysocki struct serio *serio = i8042_ports[i].serio; 1394f13b2065SRafael J. Wysocki 1395f13b2065SRafael J. Wysocki if (serio) { 1396de9ce703SDmitry Torokhov printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n", 1397f13b2065SRafael J. Wysocki serio->name, 1398de9ce703SDmitry Torokhov (unsigned long) I8042_DATA_REG, 1399de9ce703SDmitry Torokhov (unsigned long) I8042_COMMAND_REG, 1400de9ce703SDmitry Torokhov i8042_ports[i].irq); 1401f13b2065SRafael J. Wysocki serio_register_port(serio); 1402f13b2065SRafael J. Wysocki device_set_wakeup_capable(&serio->dev, true); 1403de9ce703SDmitry Torokhov } 1404de9ce703SDmitry Torokhov } 1405de9ce703SDmitry Torokhov } 1406de9ce703SDmitry Torokhov 1407e2619cf7SBill Pemberton static void i8042_unregister_ports(void) 1408de9ce703SDmitry Torokhov { 1409de9ce703SDmitry Torokhov int i; 1410de9ce703SDmitry Torokhov 1411de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) { 1412de9ce703SDmitry Torokhov if (i8042_ports[i].serio) { 1413de9ce703SDmitry Torokhov serio_unregister_port(i8042_ports[i].serio); 1414de9ce703SDmitry Torokhov i8042_ports[i].serio = NULL; 1415de9ce703SDmitry Torokhov } 1416de9ce703SDmitry Torokhov } 1417de9ce703SDmitry Torokhov } 1418de9ce703SDmitry Torokhov 1419de9ce703SDmitry Torokhov static void i8042_free_irqs(void) 1420de9ce703SDmitry Torokhov { 1421de9ce703SDmitry Torokhov if (i8042_aux_irq_registered) 1422de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 1423de9ce703SDmitry Torokhov if (i8042_kbd_irq_registered) 1424de9ce703SDmitry Torokhov free_irq(I8042_KBD_IRQ, i8042_platform_device); 1425de9ce703SDmitry Torokhov 1426386b3849SDmitry Torokhov i8042_aux_irq_registered = i8042_kbd_irq_registered = false; 1427de9ce703SDmitry Torokhov } 1428de9ce703SDmitry Torokhov 1429f8113416SDmitry Torokhov static int __init i8042_setup_aux(void) 1430de9ce703SDmitry Torokhov { 1431de9ce703SDmitry Torokhov int (*aux_enable)(void); 1432de9ce703SDmitry Torokhov int error; 1433de9ce703SDmitry Torokhov int i; 1434de9ce703SDmitry Torokhov 1435de9ce703SDmitry Torokhov if (i8042_check_aux()) 1436de9ce703SDmitry Torokhov return -ENODEV; 1437de9ce703SDmitry Torokhov 1438de9ce703SDmitry Torokhov if (i8042_nomux || i8042_check_mux()) { 1439de9ce703SDmitry Torokhov error = i8042_create_aux_port(-1); 1440de9ce703SDmitry Torokhov if (error) 1441de9ce703SDmitry Torokhov goto err_free_ports; 1442de9ce703SDmitry Torokhov aux_enable = i8042_enable_aux_port; 1443de9ce703SDmitry Torokhov } else { 1444de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { 1445de9ce703SDmitry Torokhov error = i8042_create_aux_port(i); 1446de9ce703SDmitry Torokhov if (error) 1447de9ce703SDmitry Torokhov goto err_free_ports; 1448de9ce703SDmitry Torokhov } 1449de9ce703SDmitry Torokhov aux_enable = i8042_enable_mux_ports; 1450de9ce703SDmitry Torokhov } 1451de9ce703SDmitry Torokhov 1452de9ce703SDmitry Torokhov error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED, 1453de9ce703SDmitry Torokhov "i8042", i8042_platform_device); 1454de9ce703SDmitry Torokhov if (error) 1455de9ce703SDmitry Torokhov goto err_free_ports; 1456de9ce703SDmitry Torokhov 1457de9ce703SDmitry Torokhov if (aux_enable()) 1458de9ce703SDmitry Torokhov goto err_free_irq; 1459de9ce703SDmitry Torokhov 1460386b3849SDmitry Torokhov i8042_aux_irq_registered = true; 1461de9ce703SDmitry Torokhov return 0; 1462de9ce703SDmitry Torokhov 1463de9ce703SDmitry Torokhov err_free_irq: 1464de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 1465de9ce703SDmitry Torokhov err_free_ports: 1466de9ce703SDmitry Torokhov i8042_free_aux_ports(); 1467de9ce703SDmitry Torokhov return error; 1468de9ce703SDmitry Torokhov } 1469de9ce703SDmitry Torokhov 1470f8113416SDmitry Torokhov static int __init i8042_setup_kbd(void) 1471de9ce703SDmitry Torokhov { 1472de9ce703SDmitry Torokhov int error; 1473de9ce703SDmitry Torokhov 1474de9ce703SDmitry Torokhov error = i8042_create_kbd_port(); 1475de9ce703SDmitry Torokhov if (error) 1476de9ce703SDmitry Torokhov return error; 1477de9ce703SDmitry Torokhov 1478de9ce703SDmitry Torokhov error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED, 1479de9ce703SDmitry Torokhov "i8042", i8042_platform_device); 1480de9ce703SDmitry Torokhov if (error) 1481de9ce703SDmitry Torokhov goto err_free_port; 1482de9ce703SDmitry Torokhov 1483de9ce703SDmitry Torokhov error = i8042_enable_kbd_port(); 1484de9ce703SDmitry Torokhov if (error) 1485de9ce703SDmitry Torokhov goto err_free_irq; 1486de9ce703SDmitry Torokhov 1487386b3849SDmitry Torokhov i8042_kbd_irq_registered = true; 1488de9ce703SDmitry Torokhov return 0; 1489de9ce703SDmitry Torokhov 1490de9ce703SDmitry Torokhov err_free_irq: 1491de9ce703SDmitry Torokhov free_irq(I8042_KBD_IRQ, i8042_platform_device); 1492de9ce703SDmitry Torokhov err_free_port: 1493de9ce703SDmitry Torokhov i8042_free_kbd_port(); 1494de9ce703SDmitry Torokhov return error; 14951da177e4SLinus Torvalds } 14961da177e4SLinus Torvalds 1497e1443d28SStephen Chandler Paul static int i8042_kbd_bind_notifier(struct notifier_block *nb, 1498e1443d28SStephen Chandler Paul unsigned long action, void *data) 1499e1443d28SStephen Chandler Paul { 1500e1443d28SStephen Chandler Paul struct device *dev = data; 1501e1443d28SStephen Chandler Paul struct serio *serio = to_serio_port(dev); 1502e1443d28SStephen Chandler Paul struct i8042_port *port = serio->port_data; 1503e1443d28SStephen Chandler Paul 1504e1443d28SStephen Chandler Paul if (serio != i8042_ports[I8042_KBD_PORT_NO].serio) 1505e1443d28SStephen Chandler Paul return 0; 1506e1443d28SStephen Chandler Paul 1507e1443d28SStephen Chandler Paul switch (action) { 1508e1443d28SStephen Chandler Paul case BUS_NOTIFY_BOUND_DRIVER: 1509e1443d28SStephen Chandler Paul port->driver_bound = true; 1510e1443d28SStephen Chandler Paul break; 1511e1443d28SStephen Chandler Paul 1512e1443d28SStephen Chandler Paul case BUS_NOTIFY_UNBIND_DRIVER: 1513e1443d28SStephen Chandler Paul port->driver_bound = false; 1514e1443d28SStephen Chandler Paul break; 1515e1443d28SStephen Chandler Paul } 1516e1443d28SStephen Chandler Paul 1517e1443d28SStephen Chandler Paul return 0; 1518e1443d28SStephen Chandler Paul } 1519e1443d28SStephen Chandler Paul 1520f8113416SDmitry Torokhov static int __init i8042_probe(struct platform_device *dev) 15211da177e4SLinus Torvalds { 1522de9ce703SDmitry Torokhov int error; 15231da177e4SLinus Torvalds 1524ec62e1c8SDmitry Torokhov i8042_platform_device = dev; 1525ec62e1c8SDmitry Torokhov 1526930e1924SMarcos Paulo de Souza if (i8042_reset == I8042_RESET_ALWAYS) { 1527de9ce703SDmitry Torokhov error = i8042_controller_selftest(); 1528de9ce703SDmitry Torokhov if (error) 1529de9ce703SDmitry Torokhov return error; 15301ca56e51SDmitry Torokhov } 15311da177e4SLinus Torvalds 1532de9ce703SDmitry Torokhov error = i8042_controller_init(); 1533de9ce703SDmitry Torokhov if (error) 1534de9ce703SDmitry Torokhov return error; 15351da177e4SLinus Torvalds 1536d35895dbSBruno Prémont #ifdef CONFIG_X86 1537d35895dbSBruno Prémont if (i8042_dritek) 1538d35895dbSBruno Prémont i8042_dritek_enable(); 1539d35895dbSBruno Prémont #endif 1540d35895dbSBruno Prémont 1541de9ce703SDmitry Torokhov if (!i8042_noaux) { 1542de9ce703SDmitry Torokhov error = i8042_setup_aux(); 1543de9ce703SDmitry Torokhov if (error && error != -ENODEV && error != -EBUSY) 1544de9ce703SDmitry Torokhov goto out_fail; 15451da177e4SLinus Torvalds } 15461da177e4SLinus Torvalds 1547945ef0d4SDmitry Torokhov if (!i8042_nokbd) { 1548de9ce703SDmitry Torokhov error = i8042_setup_kbd(); 1549de9ce703SDmitry Torokhov if (error) 1550de9ce703SDmitry Torokhov goto out_fail; 1551945ef0d4SDmitry Torokhov } 1552de9ce703SDmitry Torokhov /* 1553de9ce703SDmitry Torokhov * Ok, everything is ready, let's register all serio ports 1554de9ce703SDmitry Torokhov */ 1555de9ce703SDmitry Torokhov i8042_register_ports(); 15561da177e4SLinus Torvalds 15571da177e4SLinus Torvalds return 0; 15580854e52dSDmitry Torokhov 1559de9ce703SDmitry Torokhov out_fail: 1560de9ce703SDmitry Torokhov i8042_free_aux_ports(); /* in case KBD failed but AUX not */ 1561de9ce703SDmitry Torokhov i8042_free_irqs(); 15621729ad1fSDmitry Torokhov i8042_controller_reset(false); 1563ec62e1c8SDmitry Torokhov i8042_platform_device = NULL; 15640854e52dSDmitry Torokhov 1565de9ce703SDmitry Torokhov return error; 15661da177e4SLinus Torvalds } 15671da177e4SLinus Torvalds 1568e2619cf7SBill Pemberton static int i8042_remove(struct platform_device *dev) 15691da177e4SLinus Torvalds { 1570de9ce703SDmitry Torokhov i8042_unregister_ports(); 1571de9ce703SDmitry Torokhov i8042_free_irqs(); 15721729ad1fSDmitry Torokhov i8042_controller_reset(false); 1573ec62e1c8SDmitry Torokhov i8042_platform_device = NULL; 15741da177e4SLinus Torvalds 157587fd6318SDmitry Torokhov return 0; 157687fd6318SDmitry Torokhov } 157787fd6318SDmitry Torokhov 157887fd6318SDmitry Torokhov static struct platform_driver i8042_driver = { 157987fd6318SDmitry Torokhov .driver = { 158087fd6318SDmitry Torokhov .name = "i8042", 1581ebd7768dSDmitry Torokhov #ifdef CONFIG_PM 1582ebd7768dSDmitry Torokhov .pm = &i8042_pm_ops, 1583ebd7768dSDmitry Torokhov #endif 158487fd6318SDmitry Torokhov }, 15851cb0aa88SBill Pemberton .remove = i8042_remove, 158682dd9effSDmitry Torokhov .shutdown = i8042_shutdown, 158787fd6318SDmitry Torokhov }; 158887fd6318SDmitry Torokhov 1589e1443d28SStephen Chandler Paul static struct notifier_block i8042_kbd_bind_notifier_block = { 1590e1443d28SStephen Chandler Paul .notifier_call = i8042_kbd_bind_notifier, 1591e1443d28SStephen Chandler Paul }; 1592e1443d28SStephen Chandler Paul 159387fd6318SDmitry Torokhov static int __init i8042_init(void) 159487fd6318SDmitry Torokhov { 1595ec62e1c8SDmitry Torokhov struct platform_device *pdev; 159687fd6318SDmitry Torokhov int err; 159787fd6318SDmitry Torokhov 159887fd6318SDmitry Torokhov dbg_init(); 159987fd6318SDmitry Torokhov 160087fd6318SDmitry Torokhov err = i8042_platform_init(); 160187fd6318SDmitry Torokhov if (err) 160287fd6318SDmitry Torokhov return err; 160387fd6318SDmitry Torokhov 1604de9ce703SDmitry Torokhov err = i8042_controller_check(); 1605de9ce703SDmitry Torokhov if (err) 1606de9ce703SDmitry Torokhov goto err_platform_exit; 160787fd6318SDmitry Torokhov 1608ec62e1c8SDmitry Torokhov pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0); 1609ec62e1c8SDmitry Torokhov if (IS_ERR(pdev)) { 1610ec62e1c8SDmitry Torokhov err = PTR_ERR(pdev); 1611f8113416SDmitry Torokhov goto err_platform_exit; 161287fd6318SDmitry Torokhov } 161387fd6318SDmitry Torokhov 1614e1443d28SStephen Chandler Paul bus_register_notifier(&serio_bus, &i8042_kbd_bind_notifier_block); 1615de9ce703SDmitry Torokhov panic_blink = i8042_panic_blink; 1616de9ce703SDmitry Torokhov 161787fd6318SDmitry Torokhov return 0; 161887fd6318SDmitry Torokhov 161987fd6318SDmitry Torokhov err_platform_exit: 162087fd6318SDmitry Torokhov i8042_platform_exit(); 162187fd6318SDmitry Torokhov return err; 162287fd6318SDmitry Torokhov } 162387fd6318SDmitry Torokhov 162487fd6318SDmitry Torokhov static void __exit i8042_exit(void) 162587fd6318SDmitry Torokhov { 1626f8113416SDmitry Torokhov platform_device_unregister(i8042_platform_device); 1627af045b86SDmitry Torokhov platform_driver_unregister(&i8042_driver); 16281da177e4SLinus Torvalds i8042_platform_exit(); 16291da177e4SLinus Torvalds 1630e1443d28SStephen Chandler Paul bus_unregister_notifier(&serio_bus, &i8042_kbd_bind_notifier_block); 16311da177e4SLinus Torvalds panic_blink = NULL; 16321da177e4SLinus Torvalds } 16331da177e4SLinus Torvalds 16341da177e4SLinus Torvalds module_init(i8042_init); 16351da177e4SLinus Torvalds module_exit(i8042_exit); 1636