1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * i8042 keyboard and mouse controller driver for Linux 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (c) 1999-2004 Vojtech Pavlik 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds 94eb3c30bSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 104eb3c30bSJoe Perches 117e044e05SDmitry Torokhov #include <linux/types.h> 121da177e4SLinus Torvalds #include <linux/delay.h> 131da177e4SLinus Torvalds #include <linux/module.h> 141da177e4SLinus Torvalds #include <linux/interrupt.h> 151da177e4SLinus Torvalds #include <linux/ioport.h> 161da177e4SLinus Torvalds #include <linux/init.h> 171da177e4SLinus Torvalds #include <linux/serio.h> 181da177e4SLinus Torvalds #include <linux/err.h> 191da177e4SLinus Torvalds #include <linux/rcupdate.h> 20d052d1beSRussell King #include <linux/platform_device.h> 21553a05b8SMárton Németh #include <linux/i8042.h> 225a0e3ad6STejun Heo #include <linux/slab.h> 231c5dd134SRafael J. Wysocki #include <linux/suspend.h> 24*6052abf8SRajat Jain #include <linux/property.h> 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #include <asm/io.h> 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); 291da177e4SLinus Torvalds MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); 301da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 311da177e4SLinus Torvalds 32386b3849SDmitry Torokhov static bool i8042_nokbd; 33945ef0d4SDmitry Torokhov module_param_named(nokbd, i8042_nokbd, bool, 0); 34945ef0d4SDmitry Torokhov MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port."); 35945ef0d4SDmitry Torokhov 36386b3849SDmitry Torokhov static bool i8042_noaux; 371da177e4SLinus Torvalds module_param_named(noaux, i8042_noaux, bool, 0); 381da177e4SLinus Torvalds MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port."); 391da177e4SLinus Torvalds 40e55a3366SDmitry Torokhov static bool i8042_nomux; 411da177e4SLinus Torvalds module_param_named(nomux, i8042_nomux, bool, 0); 422c860a11SDominik Brodowski MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing controller is present."); 431da177e4SLinus Torvalds 44386b3849SDmitry Torokhov static bool i8042_unlock; 451da177e4SLinus Torvalds module_param_named(unlock, i8042_unlock, bool, 0); 461da177e4SLinus Torvalds MODULE_PARM_DESC(unlock, "Ignore keyboard lock."); 471da177e4SLinus Torvalds 48930e1924SMarcos Paulo de Souza enum i8042_controller_reset_mode { 49930e1924SMarcos Paulo de Souza I8042_RESET_NEVER, 50930e1924SMarcos Paulo de Souza I8042_RESET_ALWAYS, 51930e1924SMarcos Paulo de Souza I8042_RESET_ON_S2RAM, 52930e1924SMarcos Paulo de Souza #define I8042_RESET_DEFAULT I8042_RESET_ON_S2RAM 53930e1924SMarcos Paulo de Souza }; 54930e1924SMarcos Paulo de Souza static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT; 55930e1924SMarcos Paulo de Souza static int i8042_set_reset(const char *val, const struct kernel_param *kp) 56930e1924SMarcos Paulo de Souza { 57930e1924SMarcos Paulo de Souza enum i8042_controller_reset_mode *arg = kp->arg; 58930e1924SMarcos Paulo de Souza int error; 59930e1924SMarcos Paulo de Souza bool reset; 60930e1924SMarcos Paulo de Souza 61930e1924SMarcos Paulo de Souza if (val) { 62930e1924SMarcos Paulo de Souza error = kstrtobool(val, &reset); 63930e1924SMarcos Paulo de Souza if (error) 64930e1924SMarcos Paulo de Souza return error; 65930e1924SMarcos Paulo de Souza } else { 66930e1924SMarcos Paulo de Souza reset = true; 67930e1924SMarcos Paulo de Souza } 68930e1924SMarcos Paulo de Souza 69930e1924SMarcos Paulo de Souza *arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER; 70930e1924SMarcos Paulo de Souza return 0; 71930e1924SMarcos Paulo de Souza } 72930e1924SMarcos Paulo de Souza 73930e1924SMarcos Paulo de Souza static const struct kernel_param_ops param_ops_reset_param = { 74930e1924SMarcos Paulo de Souza .flags = KERNEL_PARAM_OPS_FL_NOARG, 75930e1924SMarcos Paulo de Souza .set = i8042_set_reset, 76930e1924SMarcos Paulo de Souza }; 77930e1924SMarcos Paulo de Souza #define param_check_reset_param(name, p) \ 78930e1924SMarcos Paulo de Souza __param_check(name, p, enum i8042_controller_reset_mode) 79930e1924SMarcos Paulo de Souza module_param_named(reset, i8042_reset, reset_param, 0); 80930e1924SMarcos Paulo de Souza MODULE_PARM_DESC(reset, "Reset controller on resume, cleanup or both"); 811da177e4SLinus Torvalds 82386b3849SDmitry Torokhov static bool i8042_direct; 831da177e4SLinus Torvalds module_param_named(direct, i8042_direct, bool, 0); 841da177e4SLinus Torvalds MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode."); 851da177e4SLinus Torvalds 86386b3849SDmitry Torokhov static bool i8042_dumbkbd; 871da177e4SLinus Torvalds module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); 881da177e4SLinus Torvalds MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); 891da177e4SLinus Torvalds 90386b3849SDmitry Torokhov static bool i8042_noloop; 911da177e4SLinus Torvalds module_param_named(noloop, i8042_noloop, bool, 0); 921da177e4SLinus Torvalds MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port"); 931da177e4SLinus Torvalds 94f8313ef1SJiri Kosina static bool i8042_notimeout; 95f8313ef1SJiri Kosina module_param_named(notimeout, i8042_notimeout, bool, 0); 96f8313ef1SJiri Kosina MODULE_PARM_DESC(notimeout, "Ignore timeouts signalled by i8042"); 97f8313ef1SJiri Kosina 98148e9a71SSrihari Vijayaraghavan static bool i8042_kbdreset; 99148e9a71SSrihari Vijayaraghavan module_param_named(kbdreset, i8042_kbdreset, bool, 0); 100148e9a71SSrihari Vijayaraghavan MODULE_PARM_DESC(kbdreset, "Reset device connected to KBD port"); 101148e9a71SSrihari Vijayaraghavan 1028987fec0SCarlos Corbacho #ifdef CONFIG_X86 103386b3849SDmitry Torokhov static bool i8042_dritek; 1048987fec0SCarlos Corbacho module_param_named(dritek, i8042_dritek, bool, 0); 1058987fec0SCarlos Corbacho MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension"); 1068987fec0SCarlos Corbacho #endif 1078987fec0SCarlos Corbacho 1081da177e4SLinus Torvalds #ifdef CONFIG_PNP 109386b3849SDmitry Torokhov static bool i8042_nopnp; 1101da177e4SLinus Torvalds module_param_named(nopnp, i8042_nopnp, bool, 0); 1111da177e4SLinus Torvalds MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings"); 1121da177e4SLinus Torvalds #endif 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds #define DEBUG 1151da177e4SLinus Torvalds #ifdef DEBUG 116386b3849SDmitry Torokhov static bool i8042_debug; 1171da177e4SLinus Torvalds module_param_named(debug, i8042_debug, bool, 0600); 1181da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off"); 119e1443d28SStephen Chandler Paul 120e1443d28SStephen Chandler Paul static bool i8042_unmask_kbd_data; 121e1443d28SStephen Chandler Paul module_param_named(unmask_kbd_data, i8042_unmask_kbd_data, bool, 0600); 122e1443d28SStephen 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]"); 1231da177e4SLinus Torvalds #endif 1241da177e4SLinus Torvalds 1251c7827aeSDmitry Torokhov static bool i8042_bypass_aux_irq_test; 126a7c5868cSHans de Goede static char i8042_kbd_firmware_id[128]; 127a7c5868cSHans de Goede static char i8042_aux_firmware_id[128]; 128*6052abf8SRajat Jain static struct fwnode_handle *i8042_kbd_fwnode; 1291c7827aeSDmitry Torokhov 1301da177e4SLinus Torvalds #include "i8042.h" 1311da177e4SLinus Torvalds 132181d683dSDmitry Torokhov /* 133181d683dSDmitry Torokhov * i8042_lock protects serialization between i8042_command and 134181d683dSDmitry Torokhov * the interrupt handler. 135181d683dSDmitry Torokhov */ 1361da177e4SLinus Torvalds static DEFINE_SPINLOCK(i8042_lock); 1371da177e4SLinus Torvalds 138181d683dSDmitry Torokhov /* 139181d683dSDmitry Torokhov * Writers to AUX and KBD ports as well as users issuing i8042_command 140181d683dSDmitry Torokhov * directly should acquire i8042_mutex (by means of calling 141181d683dSDmitry Torokhov * i8042_lock_chip() and i8042_unlock_ship() helpers) to ensure that 142181d683dSDmitry Torokhov * they do not disturb each other (unfortunately in many i8042 143181d683dSDmitry Torokhov * implementations write to one of the ports will immediately abort 144181d683dSDmitry Torokhov * command that is being processed by another port). 145181d683dSDmitry Torokhov */ 146181d683dSDmitry Torokhov static DEFINE_MUTEX(i8042_mutex); 147181d683dSDmitry Torokhov 1481da177e4SLinus Torvalds struct i8042_port { 1491da177e4SLinus Torvalds struct serio *serio; 1501da177e4SLinus Torvalds int irq; 151386b3849SDmitry Torokhov bool exists; 152e1443d28SStephen Chandler Paul bool driver_bound; 1531da177e4SLinus Torvalds signed char mux; 1541da177e4SLinus Torvalds }; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds #define I8042_KBD_PORT_NO 0 1571da177e4SLinus Torvalds #define I8042_AUX_PORT_NO 1 1581da177e4SLinus Torvalds #define I8042_MUX_PORT_NO 2 1591da177e4SLinus Torvalds #define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2) 160de9ce703SDmitry Torokhov 161de9ce703SDmitry Torokhov static struct i8042_port i8042_ports[I8042_NUM_PORTS]; 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds static unsigned char i8042_initial_ctr; 1641da177e4SLinus Torvalds static unsigned char i8042_ctr; 165386b3849SDmitry Torokhov static bool i8042_mux_present; 166386b3849SDmitry Torokhov static bool i8042_kbd_irq_registered; 167386b3849SDmitry Torokhov static bool i8042_aux_irq_registered; 168817e6ba3SDmitry Torokhov static unsigned char i8042_suppress_kbd_ack; 1691da177e4SLinus Torvalds static struct platform_device *i8042_platform_device; 170e1443d28SStephen Chandler Paul static struct notifier_block i8042_kbd_bind_notifier_block; 1711da177e4SLinus Torvalds 1727d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id); 173967c9ef9SMatthew Garrett static bool (*i8042_platform_filter)(unsigned char data, unsigned char str, 174967c9ef9SMatthew Garrett struct serio *serio); 1751da177e4SLinus Torvalds 176181d683dSDmitry Torokhov void i8042_lock_chip(void) 177181d683dSDmitry Torokhov { 178181d683dSDmitry Torokhov mutex_lock(&i8042_mutex); 179181d683dSDmitry Torokhov } 180181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_lock_chip); 181181d683dSDmitry Torokhov 182181d683dSDmitry Torokhov void i8042_unlock_chip(void) 183181d683dSDmitry Torokhov { 184181d683dSDmitry Torokhov mutex_unlock(&i8042_mutex); 185181d683dSDmitry Torokhov } 186181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_unlock_chip); 187181d683dSDmitry Torokhov 188967c9ef9SMatthew Garrett int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, 189967c9ef9SMatthew Garrett struct serio *serio)) 190967c9ef9SMatthew Garrett { 191967c9ef9SMatthew Garrett unsigned long flags; 192967c9ef9SMatthew Garrett int ret = 0; 193967c9ef9SMatthew Garrett 194967c9ef9SMatthew Garrett spin_lock_irqsave(&i8042_lock, flags); 195967c9ef9SMatthew Garrett 196967c9ef9SMatthew Garrett if (i8042_platform_filter) { 197967c9ef9SMatthew Garrett ret = -EBUSY; 198967c9ef9SMatthew Garrett goto out; 199967c9ef9SMatthew Garrett } 200967c9ef9SMatthew Garrett 201967c9ef9SMatthew Garrett i8042_platform_filter = filter; 202967c9ef9SMatthew Garrett 203967c9ef9SMatthew Garrett out: 204967c9ef9SMatthew Garrett spin_unlock_irqrestore(&i8042_lock, flags); 205967c9ef9SMatthew Garrett return ret; 206967c9ef9SMatthew Garrett } 207967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_install_filter); 208967c9ef9SMatthew Garrett 209967c9ef9SMatthew Garrett int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, 210967c9ef9SMatthew Garrett struct serio *port)) 211967c9ef9SMatthew Garrett { 212967c9ef9SMatthew Garrett unsigned long flags; 213967c9ef9SMatthew Garrett int ret = 0; 214967c9ef9SMatthew Garrett 215967c9ef9SMatthew Garrett spin_lock_irqsave(&i8042_lock, flags); 216967c9ef9SMatthew Garrett 217967c9ef9SMatthew Garrett if (i8042_platform_filter != filter) { 218967c9ef9SMatthew Garrett ret = -EINVAL; 219967c9ef9SMatthew Garrett goto out; 220967c9ef9SMatthew Garrett } 221967c9ef9SMatthew Garrett 222967c9ef9SMatthew Garrett i8042_platform_filter = NULL; 223967c9ef9SMatthew Garrett 224967c9ef9SMatthew Garrett out: 225967c9ef9SMatthew Garrett spin_unlock_irqrestore(&i8042_lock, flags); 226967c9ef9SMatthew Garrett return ret; 227967c9ef9SMatthew Garrett } 228967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_remove_filter); 229967c9ef9SMatthew Garrett 2301da177e4SLinus Torvalds /* 2311da177e4SLinus Torvalds * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to 2321da177e4SLinus Torvalds * be ready for reading values from it / writing values to it. 2331da177e4SLinus Torvalds * Called always with i8042_lock held. 2341da177e4SLinus Torvalds */ 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds static int i8042_wait_read(void) 2371da177e4SLinus Torvalds { 2381da177e4SLinus Torvalds int i = 0; 239de9ce703SDmitry Torokhov 2401da177e4SLinus Torvalds while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { 2411da177e4SLinus Torvalds udelay(50); 2421da177e4SLinus Torvalds i++; 2431da177e4SLinus Torvalds } 2441da177e4SLinus Torvalds return -(i == I8042_CTL_TIMEOUT); 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds static int i8042_wait_write(void) 2481da177e4SLinus Torvalds { 2491da177e4SLinus Torvalds int i = 0; 250de9ce703SDmitry Torokhov 2511da177e4SLinus Torvalds while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { 2521da177e4SLinus Torvalds udelay(50); 2531da177e4SLinus Torvalds i++; 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds return -(i == I8042_CTL_TIMEOUT); 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvalds /* 2591da177e4SLinus Torvalds * i8042_flush() flushes all data that may be in the keyboard and mouse buffers 2601da177e4SLinus Torvalds * of the i8042 down the toilet. 2611da177e4SLinus Torvalds */ 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds static int i8042_flush(void) 2641da177e4SLinus Torvalds { 2651da177e4SLinus Torvalds unsigned long flags; 2661da177e4SLinus Torvalds unsigned char data, str; 2672f0d2604SAndrey Moiseev int count = 0; 2682f0d2604SAndrey Moiseev int retval = 0; 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 2711da177e4SLinus Torvalds 2722f0d2604SAndrey Moiseev while ((str = i8042_read_status()) & I8042_STR_OBF) { 2732f0d2604SAndrey Moiseev if (count++ < I8042_BUFFER_SIZE) { 2741da177e4SLinus Torvalds udelay(50); 2751da177e4SLinus Torvalds data = i8042_read_data(); 2764eb3c30bSJoe Perches dbg("%02x <- i8042 (flush, %s)\n", 2774eb3c30bSJoe Perches data, str & I8042_STR_AUXDATA ? "aux" : "kbd"); 2782f0d2604SAndrey Moiseev } else { 2792f0d2604SAndrey Moiseev retval = -EIO; 2802f0d2604SAndrey Moiseev break; 2812f0d2604SAndrey Moiseev } 2821da177e4SLinus Torvalds } 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 2851da177e4SLinus Torvalds 2862f0d2604SAndrey Moiseev return retval; 2871da177e4SLinus Torvalds } 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds /* 2901da177e4SLinus Torvalds * i8042_command() executes a command on the i8042. It also sends the input 2911da177e4SLinus Torvalds * parameter(s) of the commands to it, and receives the output value(s). The 2921da177e4SLinus Torvalds * parameters are to be stored in the param array, and the output is placed 2931da177e4SLinus Torvalds * into the same array. The number of the parameters and output values is 2941da177e4SLinus Torvalds * encoded in bits 8-11 of the command number. 2951da177e4SLinus Torvalds */ 2961da177e4SLinus Torvalds 297de9ce703SDmitry Torokhov static int __i8042_command(unsigned char *param, int command) 2981da177e4SLinus Torvalds { 299de9ce703SDmitry Torokhov int i, error; 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds if (i8042_noloop && command == I8042_CMD_AUX_LOOP) 3021da177e4SLinus Torvalds return -1; 3031da177e4SLinus Torvalds 304de9ce703SDmitry Torokhov error = i8042_wait_write(); 305de9ce703SDmitry Torokhov if (error) 306de9ce703SDmitry Torokhov return error; 307463a4f76SDmitry Torokhov 3084eb3c30bSJoe Perches dbg("%02x -> i8042 (command)\n", command & 0xff); 3091da177e4SLinus Torvalds i8042_write_command(command & 0xff); 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds for (i = 0; i < ((command >> 12) & 0xf); i++) { 312de9ce703SDmitry Torokhov error = i8042_wait_write(); 3132ea9c236SMarcos Paulo de Souza if (error) { 3142ea9c236SMarcos Paulo de Souza dbg(" -- i8042 (wait write timeout)\n"); 315de9ce703SDmitry Torokhov return error; 3162ea9c236SMarcos Paulo de Souza } 3174eb3c30bSJoe Perches dbg("%02x -> i8042 (parameter)\n", param[i]); 3181da177e4SLinus Torvalds i8042_write_data(param[i]); 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds for (i = 0; i < ((command >> 8) & 0xf); i++) { 322de9ce703SDmitry Torokhov error = i8042_wait_read(); 323de9ce703SDmitry Torokhov if (error) { 3242ea9c236SMarcos Paulo de Souza dbg(" -- i8042 (wait read timeout)\n"); 325de9ce703SDmitry Torokhov return error; 326de9ce703SDmitry Torokhov } 327463a4f76SDmitry Torokhov 328463a4f76SDmitry Torokhov if (command == I8042_CMD_AUX_LOOP && 329463a4f76SDmitry Torokhov !(i8042_read_status() & I8042_STR_AUXDATA)) { 3304eb3c30bSJoe Perches dbg(" -- i8042 (auxerr)\n"); 331de9ce703SDmitry Torokhov return -1; 332463a4f76SDmitry Torokhov } 333463a4f76SDmitry Torokhov 3341da177e4SLinus Torvalds param[i] = i8042_read_data(); 3354eb3c30bSJoe Perches dbg("%02x <- i8042 (return)\n", param[i]); 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds 338de9ce703SDmitry Torokhov return 0; 339de9ce703SDmitry Torokhov } 3401da177e4SLinus Torvalds 341553a05b8SMárton Németh int i8042_command(unsigned char *param, int command) 342de9ce703SDmitry Torokhov { 343de9ce703SDmitry Torokhov unsigned long flags; 344de9ce703SDmitry Torokhov int retval; 345de9ce703SDmitry Torokhov 346de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 347de9ce703SDmitry Torokhov retval = __i8042_command(param, command); 348463a4f76SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 349de9ce703SDmitry Torokhov 3501da177e4SLinus Torvalds return retval; 3511da177e4SLinus Torvalds } 352553a05b8SMárton Németh EXPORT_SYMBOL(i8042_command); 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds /* 3551da177e4SLinus Torvalds * i8042_kbd_write() sends a byte out through the keyboard interface. 3561da177e4SLinus Torvalds */ 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds static int i8042_kbd_write(struct serio *port, unsigned char c) 3591da177e4SLinus Torvalds { 3601da177e4SLinus Torvalds unsigned long flags; 3611da177e4SLinus Torvalds int retval = 0; 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 3641da177e4SLinus Torvalds 3651da177e4SLinus Torvalds if (!(retval = i8042_wait_write())) { 3664eb3c30bSJoe Perches dbg("%02x -> i8042 (kbd-data)\n", c); 3671da177e4SLinus Torvalds i8042_write_data(c); 3681da177e4SLinus Torvalds } 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds return retval; 3731da177e4SLinus Torvalds } 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds /* 3761da177e4SLinus Torvalds * i8042_aux_write() sends a byte out through the aux interface. 3771da177e4SLinus Torvalds */ 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds static int i8042_aux_write(struct serio *serio, unsigned char c) 3801da177e4SLinus Torvalds { 3811da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 3821da177e4SLinus Torvalds 383f4e3c711SDmitry Torokhov return i8042_command(&c, port->mux == -1 ? 384f4e3c711SDmitry Torokhov I8042_CMD_AUX_SEND : 385f4e3c711SDmitry Torokhov I8042_CMD_MUX_SEND + port->mux); 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds 3885ddbc77cSDmitry Torokhov 3895ddbc77cSDmitry Torokhov /* 3900e2b4458SMarcos Paulo de Souza * i8042_port_close attempts to clear AUX or KBD port state by disabling 3915ddbc77cSDmitry Torokhov * and then re-enabling it. 3925ddbc77cSDmitry Torokhov */ 3935ddbc77cSDmitry Torokhov 3945ddbc77cSDmitry Torokhov static void i8042_port_close(struct serio *serio) 3955ddbc77cSDmitry Torokhov { 3965ddbc77cSDmitry Torokhov int irq_bit; 3975ddbc77cSDmitry Torokhov int disable_bit; 3985ddbc77cSDmitry Torokhov const char *port_name; 3995ddbc77cSDmitry Torokhov 4005ddbc77cSDmitry Torokhov if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) { 4015ddbc77cSDmitry Torokhov irq_bit = I8042_CTR_AUXINT; 4025ddbc77cSDmitry Torokhov disable_bit = I8042_CTR_AUXDIS; 4035ddbc77cSDmitry Torokhov port_name = "AUX"; 4045ddbc77cSDmitry Torokhov } else { 4055ddbc77cSDmitry Torokhov irq_bit = I8042_CTR_KBDINT; 4065ddbc77cSDmitry Torokhov disable_bit = I8042_CTR_KBDDIS; 4075ddbc77cSDmitry Torokhov port_name = "KBD"; 4085ddbc77cSDmitry Torokhov } 4095ddbc77cSDmitry Torokhov 4105ddbc77cSDmitry Torokhov i8042_ctr &= ~irq_bit; 4115ddbc77cSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 4124eb3c30bSJoe Perches pr_warn("Can't write CTR while closing %s port\n", port_name); 4135ddbc77cSDmitry Torokhov 4145ddbc77cSDmitry Torokhov udelay(50); 4155ddbc77cSDmitry Torokhov 4165ddbc77cSDmitry Torokhov i8042_ctr &= ~disable_bit; 4175ddbc77cSDmitry Torokhov i8042_ctr |= irq_bit; 4185ddbc77cSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 4194eb3c30bSJoe Perches pr_err("Can't reactivate %s port\n", port_name); 4205ddbc77cSDmitry Torokhov 4215ddbc77cSDmitry Torokhov /* 4225ddbc77cSDmitry Torokhov * See if there is any data appeared while we were messing with 4235ddbc77cSDmitry Torokhov * port state. 4245ddbc77cSDmitry Torokhov */ 4255ddbc77cSDmitry Torokhov i8042_interrupt(0, NULL); 4265ddbc77cSDmitry Torokhov } 4275ddbc77cSDmitry Torokhov 4281da177e4SLinus Torvalds /* 4291da177e4SLinus Torvalds * i8042_start() is called by serio core when port is about to finish 4301da177e4SLinus Torvalds * registering. It will mark port as existing so i8042_interrupt can 4311da177e4SLinus Torvalds * start sending data through it. 4321da177e4SLinus Torvalds */ 4331da177e4SLinus Torvalds static int i8042_start(struct serio *serio) 4341da177e4SLinus Torvalds { 4351da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 4361da177e4SLinus Torvalds 437c8a144b2SStephen Boyd device_set_wakeup_capable(&serio->dev, true); 438c8a144b2SStephen Boyd 439c8a144b2SStephen Boyd /* 440c8a144b2SStephen Boyd * On platforms using suspend-to-idle, allow the keyboard to 441c8a144b2SStephen Boyd * wake up the system from sleep by enabling keyboard wakeups 442c8a144b2SStephen Boyd * by default. This is consistent with keyboard wakeup 443c8a144b2SStephen Boyd * behavior on many platforms using suspend-to-RAM (ACPI S3) 444c8a144b2SStephen Boyd * by default. 445c8a144b2SStephen Boyd */ 446c8a144b2SStephen Boyd if (pm_suspend_default_s2idle() && 447c8a144b2SStephen Boyd serio == i8042_ports[I8042_KBD_PORT_NO].serio) { 448c8a144b2SStephen Boyd device_set_wakeup_enable(&serio->dev, true); 449c8a144b2SStephen Boyd } 450c8a144b2SStephen Boyd 451340d394aSChen Hong spin_lock_irq(&i8042_lock); 452386b3849SDmitry Torokhov port->exists = true; 453340d394aSChen Hong spin_unlock_irq(&i8042_lock); 454340d394aSChen Hong 4551da177e4SLinus Torvalds return 0; 4561da177e4SLinus Torvalds } 4571da177e4SLinus Torvalds 4581da177e4SLinus Torvalds /* 4591da177e4SLinus Torvalds * i8042_stop() marks serio port as non-existing so i8042_interrupt 4601da177e4SLinus Torvalds * will not try to send data to the port that is about to go away. 4611da177e4SLinus Torvalds * The function is called by serio core as part of unregister procedure. 4621da177e4SLinus Torvalds */ 4631da177e4SLinus Torvalds static void i8042_stop(struct serio *serio) 4641da177e4SLinus Torvalds { 4651da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 4661da177e4SLinus Torvalds 467340d394aSChen Hong spin_lock_irq(&i8042_lock); 468386b3849SDmitry Torokhov port->exists = false; 469340d394aSChen Hong port->serio = NULL; 470340d394aSChen Hong spin_unlock_irq(&i8042_lock); 471a8399c51SDmitry Torokhov 472a8399c51SDmitry Torokhov /* 473340d394aSChen Hong * We need to make sure that interrupt handler finishes using 474340d394aSChen Hong * our serio port before we return from this function. 475a8399c51SDmitry Torokhov * We synchronize with both AUX and KBD IRQs because there is 476a8399c51SDmitry Torokhov * a (very unlikely) chance that AUX IRQ is raised for KBD port 477a8399c51SDmitry Torokhov * and vice versa. 478a8399c51SDmitry Torokhov */ 479a8399c51SDmitry Torokhov synchronize_irq(I8042_AUX_IRQ); 480a8399c51SDmitry Torokhov synchronize_irq(I8042_KBD_IRQ); 4811da177e4SLinus Torvalds } 4821da177e4SLinus Torvalds 4831da177e4SLinus Torvalds /* 4844e8d340dSDmitry Torokhov * i8042_filter() filters out unwanted bytes from the input data stream. 4854e8d340dSDmitry Torokhov * It is called from i8042_interrupt and thus is running with interrupts 4864e8d340dSDmitry Torokhov * off and i8042_lock held. 4874e8d340dSDmitry Torokhov */ 488967c9ef9SMatthew Garrett static bool i8042_filter(unsigned char data, unsigned char str, 489967c9ef9SMatthew Garrett struct serio *serio) 4904e8d340dSDmitry Torokhov { 4914e8d340dSDmitry Torokhov if (unlikely(i8042_suppress_kbd_ack)) { 4924e8d340dSDmitry Torokhov if ((~str & I8042_STR_AUXDATA) && 4934e8d340dSDmitry Torokhov (data == 0xfa || data == 0xfe)) { 4944e8d340dSDmitry Torokhov i8042_suppress_kbd_ack--; 4954e8d340dSDmitry Torokhov dbg("Extra keyboard ACK - filtered out\n"); 4964e8d340dSDmitry Torokhov return true; 4974e8d340dSDmitry Torokhov } 4984e8d340dSDmitry Torokhov } 4994e8d340dSDmitry Torokhov 500967c9ef9SMatthew Garrett if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) { 5010747e3bcSStefan Weil dbg("Filtered out by platform filter\n"); 502967c9ef9SMatthew Garrett return true; 503967c9ef9SMatthew Garrett } 504967c9ef9SMatthew Garrett 5054e8d340dSDmitry Torokhov return false; 5064e8d340dSDmitry Torokhov } 5074e8d340dSDmitry Torokhov 5084e8d340dSDmitry Torokhov /* 5091da177e4SLinus Torvalds * i8042_interrupt() is the most important function in this driver - 5101da177e4SLinus Torvalds * it handles the interrupts from the i8042, and sends incoming bytes 5111da177e4SLinus Torvalds * to the upper layers. 5121da177e4SLinus Torvalds */ 5131da177e4SLinus Torvalds 5147d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id) 5151da177e4SLinus Torvalds { 5161da177e4SLinus Torvalds struct i8042_port *port; 517967c9ef9SMatthew Garrett struct serio *serio; 5181da177e4SLinus Torvalds unsigned long flags; 5191da177e4SLinus Torvalds unsigned char str, data; 5201da177e4SLinus Torvalds unsigned int dfl; 5211da177e4SLinus Torvalds unsigned int port_no; 5224e8d340dSDmitry Torokhov bool filtered; 523817e6ba3SDmitry Torokhov int ret = 1; 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 5264e8d340dSDmitry Torokhov 5271da177e4SLinus Torvalds str = i8042_read_status(); 5281da177e4SLinus Torvalds if (unlikely(~str & I8042_STR_OBF)) { 5291da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 5304eb3c30bSJoe Perches if (irq) 5314eb3c30bSJoe Perches dbg("Interrupt %d, without any data\n", irq); 5321da177e4SLinus Torvalds ret = 0; 5331da177e4SLinus Torvalds goto out; 5341da177e4SLinus Torvalds } 5354e8d340dSDmitry Torokhov 5361da177e4SLinus Torvalds data = i8042_read_data(); 5371da177e4SLinus Torvalds 5381da177e4SLinus Torvalds if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { 5391da177e4SLinus Torvalds static unsigned long last_transmit; 5401da177e4SLinus Torvalds static unsigned char last_str; 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds dfl = 0; 5431da177e4SLinus Torvalds if (str & I8042_STR_MUXERR) { 5444eb3c30bSJoe Perches dbg("MUX error, status is %02x, data is %02x\n", 5454eb3c30bSJoe Perches str, data); 5461da177e4SLinus Torvalds /* 5471da177e4SLinus Torvalds * When MUXERR condition is signalled the data register can only contain 5481da177e4SLinus Torvalds * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately 549a216a4b6SDmitry Torokhov * it is not always the case. Some KBCs also report 0xfc when there is 550a216a4b6SDmitry Torokhov * nothing connected to the port while others sometimes get confused which 551a216a4b6SDmitry Torokhov * port the data came from and signal error leaving the data intact. They 552a216a4b6SDmitry Torokhov * _do not_ revert to legacy mode (actually I've never seen KBC reverting 553a216a4b6SDmitry Torokhov * to legacy mode yet, when we see one we'll add proper handling). 554a216a4b6SDmitry Torokhov * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the 555a216a4b6SDmitry Torokhov * rest assume that the data came from the same serio last byte 5561da177e4SLinus Torvalds * was transmitted (if transmission happened not too long ago). 5571da177e4SLinus Torvalds */ 558a216a4b6SDmitry Torokhov 559a216a4b6SDmitry Torokhov switch (data) { 560a216a4b6SDmitry Torokhov default: 5611da177e4SLinus Torvalds if (time_before(jiffies, last_transmit + HZ/10)) { 5621da177e4SLinus Torvalds str = last_str; 5631da177e4SLinus Torvalds break; 5641da177e4SLinus Torvalds } 5651da177e4SLinus Torvalds /* fall through - report timeout */ 566a216a4b6SDmitry Torokhov case 0xfc: 5671da177e4SLinus Torvalds case 0xfd: 5681da177e4SLinus Torvalds case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break; 5691da177e4SLinus Torvalds case 0xff: dfl = SERIO_PARITY; data = 0xfe; break; 5701da177e4SLinus Torvalds } 5711da177e4SLinus Torvalds } 5721da177e4SLinus Torvalds 5731da177e4SLinus Torvalds port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3); 5741da177e4SLinus Torvalds last_str = str; 5751da177e4SLinus Torvalds last_transmit = jiffies; 5761da177e4SLinus Torvalds } else { 5771da177e4SLinus Torvalds 5781da177e4SLinus Torvalds dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | 579f8313ef1SJiri Kosina ((str & I8042_STR_TIMEOUT && !i8042_notimeout) ? SERIO_TIMEOUT : 0); 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds port_no = (str & I8042_STR_AUXDATA) ? 5821da177e4SLinus Torvalds I8042_AUX_PORT_NO : I8042_KBD_PORT_NO; 5831da177e4SLinus Torvalds } 5841da177e4SLinus Torvalds 5851da177e4SLinus Torvalds port = &i8042_ports[port_no]; 586967c9ef9SMatthew Garrett serio = port->exists ? port->serio : NULL; 5871da177e4SLinus Torvalds 588e1443d28SStephen Chandler Paul filter_dbg(port->driver_bound, data, "<- i8042 (interrupt, %d, %d%s%s)\n", 589e1443d28SStephen Chandler Paul port_no, irq, 5901da177e4SLinus Torvalds dfl & SERIO_PARITY ? ", bad parity" : "", 5911da177e4SLinus Torvalds dfl & SERIO_TIMEOUT ? ", timeout" : ""); 5921da177e4SLinus Torvalds 593967c9ef9SMatthew Garrett filtered = i8042_filter(data, str, serio); 594817e6ba3SDmitry Torokhov 5954e8d340dSDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 5964e8d340dSDmitry Torokhov 597340d394aSChen Hong if (likely(serio && !filtered)) 598967c9ef9SMatthew Garrett serio_interrupt(serio, data, dfl); 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds out: 6011da177e4SLinus Torvalds return IRQ_RETVAL(ret); 6021da177e4SLinus Torvalds } 6031da177e4SLinus Torvalds 6041da177e4SLinus Torvalds /* 6055ddbc77cSDmitry Torokhov * i8042_enable_kbd_port enables keyboard port on chip 606de9ce703SDmitry Torokhov */ 607de9ce703SDmitry Torokhov 608de9ce703SDmitry Torokhov static int i8042_enable_kbd_port(void) 609de9ce703SDmitry Torokhov { 610de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_KBDDIS; 611de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_KBDINT; 612de9ce703SDmitry Torokhov 613de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 614018db6bbSMarkus Armbruster i8042_ctr &= ~I8042_CTR_KBDINT; 615018db6bbSMarkus Armbruster i8042_ctr |= I8042_CTR_KBDDIS; 6164eb3c30bSJoe Perches pr_err("Failed to enable KBD port\n"); 617de9ce703SDmitry Torokhov return -EIO; 618de9ce703SDmitry Torokhov } 619de9ce703SDmitry Torokhov 620de9ce703SDmitry Torokhov return 0; 621de9ce703SDmitry Torokhov } 622de9ce703SDmitry Torokhov 623de9ce703SDmitry Torokhov /* 624de9ce703SDmitry Torokhov * i8042_enable_aux_port enables AUX (mouse) port on chip 625de9ce703SDmitry Torokhov */ 626de9ce703SDmitry Torokhov 627de9ce703SDmitry Torokhov static int i8042_enable_aux_port(void) 628de9ce703SDmitry Torokhov { 629de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_AUXDIS; 630de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXINT; 631de9ce703SDmitry Torokhov 632de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 633018db6bbSMarkus Armbruster i8042_ctr &= ~I8042_CTR_AUXINT; 634018db6bbSMarkus Armbruster i8042_ctr |= I8042_CTR_AUXDIS; 6354eb3c30bSJoe Perches pr_err("Failed to enable AUX port\n"); 636de9ce703SDmitry Torokhov return -EIO; 637de9ce703SDmitry Torokhov } 638de9ce703SDmitry Torokhov 639de9ce703SDmitry Torokhov return 0; 640de9ce703SDmitry Torokhov } 641de9ce703SDmitry Torokhov 642de9ce703SDmitry Torokhov /* 643de9ce703SDmitry Torokhov * i8042_enable_mux_ports enables 4 individual AUX ports after 644de9ce703SDmitry Torokhov * the controller has been switched into Multiplexed mode 645de9ce703SDmitry Torokhov */ 646de9ce703SDmitry Torokhov 647de9ce703SDmitry Torokhov static int i8042_enable_mux_ports(void) 648de9ce703SDmitry Torokhov { 649de9ce703SDmitry Torokhov unsigned char param; 650de9ce703SDmitry Torokhov int i; 651de9ce703SDmitry Torokhov 652de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { 653de9ce703SDmitry Torokhov i8042_command(¶m, I8042_CMD_MUX_PFX + i); 654de9ce703SDmitry Torokhov i8042_command(¶m, I8042_CMD_AUX_ENABLE); 655de9ce703SDmitry Torokhov } 656de9ce703SDmitry Torokhov 657de9ce703SDmitry Torokhov return i8042_enable_aux_port(); 658de9ce703SDmitry Torokhov } 659de9ce703SDmitry Torokhov 660de9ce703SDmitry Torokhov /* 661386b3849SDmitry Torokhov * i8042_set_mux_mode checks whether the controller has an 662386b3849SDmitry Torokhov * active multiplexor and puts the chip into Multiplexed (true) 663386b3849SDmitry Torokhov * or Legacy (false) mode. 6641da177e4SLinus Torvalds */ 6651da177e4SLinus Torvalds 666386b3849SDmitry Torokhov static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version) 6671da177e4SLinus Torvalds { 6681da177e4SLinus Torvalds 669386b3849SDmitry Torokhov unsigned char param, val; 6701da177e4SLinus Torvalds /* 6711da177e4SLinus Torvalds * Get rid of bytes in the queue. 6721da177e4SLinus Torvalds */ 6731da177e4SLinus Torvalds 6741da177e4SLinus Torvalds i8042_flush(); 6751da177e4SLinus Torvalds 6761da177e4SLinus Torvalds /* 6771da177e4SLinus Torvalds * Internal loopback test - send three bytes, they should come back from the 678de9ce703SDmitry Torokhov * mouse interface, the last should be version. 6791da177e4SLinus Torvalds */ 6801da177e4SLinus Torvalds 681386b3849SDmitry Torokhov param = val = 0xf0; 682386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != val) 6831da177e4SLinus Torvalds return -1; 684386b3849SDmitry Torokhov param = val = multiplex ? 0x56 : 0xf6; 685386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != val) 6861da177e4SLinus Torvalds return -1; 687386b3849SDmitry Torokhov param = val = multiplex ? 0xa4 : 0xa5; 688386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == val) 689386b3849SDmitry Torokhov return -1; 690386b3849SDmitry Torokhov 691386b3849SDmitry Torokhov /* 692386b3849SDmitry Torokhov * Workaround for interference with USB Legacy emulation 693386b3849SDmitry Torokhov * that causes a v10.12 MUX to be found. 694386b3849SDmitry Torokhov */ 695386b3849SDmitry Torokhov if (param == 0xac) 6961da177e4SLinus Torvalds return -1; 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds if (mux_version) 699463a4f76SDmitry Torokhov *mux_version = param; 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds return 0; 7021da177e4SLinus Torvalds } 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds /* 7051da177e4SLinus Torvalds * i8042_check_mux() checks whether the controller supports the PS/2 Active 7061da177e4SLinus Torvalds * Multiplexing specification by Synaptics, Phoenix, Insyde and 7071da177e4SLinus Torvalds * LCS/Telegraphics. 7081da177e4SLinus Torvalds */ 7091da177e4SLinus Torvalds 710f8113416SDmitry Torokhov static int __init i8042_check_mux(void) 7111da177e4SLinus Torvalds { 7121da177e4SLinus Torvalds unsigned char mux_version; 7131da177e4SLinus Torvalds 714386b3849SDmitry Torokhov if (i8042_set_mux_mode(true, &mux_version)) 7151da177e4SLinus Torvalds return -1; 7161da177e4SLinus Torvalds 7174eb3c30bSJoe Perches pr_info("Detected active multiplexing controller, rev %d.%d\n", 7181da177e4SLinus Torvalds (mux_version >> 4) & 0xf, mux_version & 0xf); 7191da177e4SLinus Torvalds 720de9ce703SDmitry Torokhov /* 721de9ce703SDmitry Torokhov * Disable all muxed ports by disabling AUX. 722de9ce703SDmitry Torokhov */ 723de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXDIS; 724de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_AUXINT; 725de9ce703SDmitry Torokhov 726de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 7274eb3c30bSJoe Perches pr_err("Failed to disable AUX port, can't use MUX\n"); 728de9ce703SDmitry Torokhov return -EIO; 729de9ce703SDmitry Torokhov } 7301da177e4SLinus Torvalds 731386b3849SDmitry Torokhov i8042_mux_present = true; 732de9ce703SDmitry Torokhov 7331da177e4SLinus Torvalds return 0; 7341da177e4SLinus Torvalds } 7351da177e4SLinus Torvalds 736de9ce703SDmitry Torokhov /* 737de9ce703SDmitry Torokhov * The following is used to test AUX IRQ delivery. 738de9ce703SDmitry Torokhov */ 739f8113416SDmitry Torokhov static struct completion i8042_aux_irq_delivered __initdata; 740f8113416SDmitry Torokhov static bool i8042_irq_being_tested __initdata; 741de9ce703SDmitry Torokhov 742f8113416SDmitry Torokhov static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id) 743de9ce703SDmitry Torokhov { 744de9ce703SDmitry Torokhov unsigned long flags; 745de9ce703SDmitry Torokhov unsigned char str, data; 746e3758b2aSFernando Luis Vázquez Cao int ret = 0; 747de9ce703SDmitry Torokhov 748de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 749de9ce703SDmitry Torokhov str = i8042_read_status(); 750de9ce703SDmitry Torokhov if (str & I8042_STR_OBF) { 751de9ce703SDmitry Torokhov data = i8042_read_data(); 7524eb3c30bSJoe Perches dbg("%02x <- i8042 (aux_test_irq, %s)\n", 753d3d2dfe2SDmitry Torokhov data, str & I8042_STR_AUXDATA ? "aux" : "kbd"); 754de9ce703SDmitry Torokhov if (i8042_irq_being_tested && 755de9ce703SDmitry Torokhov data == 0xa5 && (str & I8042_STR_AUXDATA)) 756de9ce703SDmitry Torokhov complete(&i8042_aux_irq_delivered); 757e3758b2aSFernando Luis Vázquez Cao ret = 1; 758de9ce703SDmitry Torokhov } 759de9ce703SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 760de9ce703SDmitry Torokhov 761e3758b2aSFernando Luis Vázquez Cao return IRQ_RETVAL(ret); 762de9ce703SDmitry Torokhov } 763de9ce703SDmitry Torokhov 764d2ada559SRoland Scheidegger /* 765d2ada559SRoland Scheidegger * i8042_toggle_aux - enables or disables AUX port on i8042 via command and 766d2ada559SRoland Scheidegger * verifies success by readinng CTR. Used when testing for presence of AUX 767d2ada559SRoland Scheidegger * port. 768d2ada559SRoland Scheidegger */ 769f8113416SDmitry Torokhov static int __init i8042_toggle_aux(bool on) 770d2ada559SRoland Scheidegger { 771d2ada559SRoland Scheidegger unsigned char param; 772d2ada559SRoland Scheidegger int i; 773d2ada559SRoland Scheidegger 774d2ada559SRoland Scheidegger if (i8042_command(¶m, 775d2ada559SRoland Scheidegger on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE)) 776d2ada559SRoland Scheidegger return -1; 777d2ada559SRoland Scheidegger 778d2ada559SRoland Scheidegger /* some chips need some time to set the I8042_CTR_AUXDIS bit */ 779d2ada559SRoland Scheidegger for (i = 0; i < 100; i++) { 780d2ada559SRoland Scheidegger udelay(50); 781d2ada559SRoland Scheidegger 782d2ada559SRoland Scheidegger if (i8042_command(¶m, I8042_CMD_CTL_RCTR)) 783d2ada559SRoland Scheidegger return -1; 784d2ada559SRoland Scheidegger 785d2ada559SRoland Scheidegger if (!(param & I8042_CTR_AUXDIS) == on) 786d2ada559SRoland Scheidegger return 0; 787d2ada559SRoland Scheidegger } 788d2ada559SRoland Scheidegger 789d2ada559SRoland Scheidegger return -1; 790d2ada559SRoland Scheidegger } 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds /* 7931da177e4SLinus Torvalds * i8042_check_aux() applies as much paranoia as it can at detecting 7941da177e4SLinus Torvalds * the presence of an AUX interface. 7951da177e4SLinus Torvalds */ 7961da177e4SLinus Torvalds 797f8113416SDmitry Torokhov static int __init i8042_check_aux(void) 7981da177e4SLinus Torvalds { 799de9ce703SDmitry Torokhov int retval = -1; 800386b3849SDmitry Torokhov bool irq_registered = false; 801386b3849SDmitry Torokhov bool aux_loop_broken = false; 802de9ce703SDmitry Torokhov unsigned long flags; 8031da177e4SLinus Torvalds unsigned char param; 8041da177e4SLinus Torvalds 8051da177e4SLinus Torvalds /* 8061da177e4SLinus Torvalds * Get rid of bytes in the queue. 8071da177e4SLinus Torvalds */ 8081da177e4SLinus Torvalds 8091da177e4SLinus Torvalds i8042_flush(); 8101da177e4SLinus Torvalds 8111da177e4SLinus Torvalds /* 8121da177e4SLinus Torvalds * Internal loopback test - filters out AT-type i8042's. Unfortunately 8131da177e4SLinus Torvalds * SiS screwed up and their 5597 doesn't support the LOOP command even 8141da177e4SLinus Torvalds * though it has an AUX port. 8151da177e4SLinus Torvalds */ 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds param = 0x5a; 8183ca5de6dSDmitry Torokhov retval = i8042_command(¶m, I8042_CMD_AUX_LOOP); 8193ca5de6dSDmitry Torokhov if (retval || param != 0x5a) { 8201da177e4SLinus Torvalds 8211da177e4SLinus Torvalds /* 8221da177e4SLinus Torvalds * External connection test - filters out AT-soldered PS/2 i8042's 8231da177e4SLinus Torvalds * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error 8241da177e4SLinus Torvalds * 0xfa - no error on some notebooks which ignore the spec 8251da177e4SLinus Torvalds * Because it's common for chipsets to return error on perfectly functioning 8261da177e4SLinus Torvalds * AUX ports, we test for this only when the LOOP command failed. 8271da177e4SLinus Torvalds */ 8281da177e4SLinus Torvalds 829de9ce703SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_TEST) || 830de9ce703SDmitry Torokhov (param && param != 0xfa && param != 0xff)) 8311da177e4SLinus Torvalds return -1; 8321e4865f8SDmitry Torokhov 8333ca5de6dSDmitry Torokhov /* 8343ca5de6dSDmitry Torokhov * If AUX_LOOP completed without error but returned unexpected data 8353ca5de6dSDmitry Torokhov * mark it as broken 8363ca5de6dSDmitry Torokhov */ 8373ca5de6dSDmitry Torokhov if (!retval) 838386b3849SDmitry Torokhov aux_loop_broken = true; 8391da177e4SLinus Torvalds } 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds /* 8421da177e4SLinus Torvalds * Bit assignment test - filters out PS/2 i8042's in AT mode 8431da177e4SLinus Torvalds */ 8441da177e4SLinus Torvalds 845386b3849SDmitry Torokhov if (i8042_toggle_aux(false)) { 8464eb3c30bSJoe Perches pr_warn("Failed to disable AUX port, but continuing anyway... Is this a SiS?\n"); 8474eb3c30bSJoe Perches pr_warn("If AUX port is really absent please use the 'i8042.noaux' option\n"); 8481da177e4SLinus Torvalds } 8491da177e4SLinus Torvalds 850386b3849SDmitry Torokhov if (i8042_toggle_aux(true)) 8511da177e4SLinus Torvalds return -1; 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds /* 854148e9a71SSrihari Vijayaraghavan * Reset keyboard (needed on some laptops to successfully detect 855148e9a71SSrihari Vijayaraghavan * touchpad, e.g., some Gigabyte laptop models with Elantech 856148e9a71SSrihari Vijayaraghavan * touchpads). 857148e9a71SSrihari Vijayaraghavan */ 858148e9a71SSrihari Vijayaraghavan if (i8042_kbdreset) { 859148e9a71SSrihari Vijayaraghavan pr_warn("Attempting to reset device connected to KBD port\n"); 860148e9a71SSrihari Vijayaraghavan i8042_kbd_write(NULL, (unsigned char) 0xff); 861148e9a71SSrihari Vijayaraghavan } 862148e9a71SSrihari Vijayaraghavan 863148e9a71SSrihari Vijayaraghavan /* 864de9ce703SDmitry Torokhov * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and 865de9ce703SDmitry Torokhov * used it for a PCI card or somethig else. 866de9ce703SDmitry Torokhov */ 867de9ce703SDmitry Torokhov 8681c7827aeSDmitry Torokhov if (i8042_noloop || i8042_bypass_aux_irq_test || aux_loop_broken) { 869de9ce703SDmitry Torokhov /* 870de9ce703SDmitry Torokhov * Without LOOP command we can't test AUX IRQ delivery. Assume the port 871de9ce703SDmitry Torokhov * is working and hope we are right. 872de9ce703SDmitry Torokhov */ 873de9ce703SDmitry Torokhov retval = 0; 874de9ce703SDmitry Torokhov goto out; 875de9ce703SDmitry Torokhov } 876de9ce703SDmitry Torokhov 877de9ce703SDmitry Torokhov if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED, 878de9ce703SDmitry Torokhov "i8042", i8042_platform_device)) 879de9ce703SDmitry Torokhov goto out; 880de9ce703SDmitry Torokhov 881386b3849SDmitry Torokhov irq_registered = true; 882de9ce703SDmitry Torokhov 883de9ce703SDmitry Torokhov if (i8042_enable_aux_port()) 884de9ce703SDmitry Torokhov goto out; 885de9ce703SDmitry Torokhov 886de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 887de9ce703SDmitry Torokhov 888de9ce703SDmitry Torokhov init_completion(&i8042_aux_irq_delivered); 889386b3849SDmitry Torokhov i8042_irq_being_tested = true; 890de9ce703SDmitry Torokhov 891de9ce703SDmitry Torokhov param = 0xa5; 892de9ce703SDmitry Torokhov retval = __i8042_command(¶m, I8042_CMD_AUX_LOOP & 0xf0ff); 893de9ce703SDmitry Torokhov 894de9ce703SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 895de9ce703SDmitry Torokhov 896de9ce703SDmitry Torokhov if (retval) 897de9ce703SDmitry Torokhov goto out; 898de9ce703SDmitry Torokhov 899de9ce703SDmitry Torokhov if (wait_for_completion_timeout(&i8042_aux_irq_delivered, 900de9ce703SDmitry Torokhov msecs_to_jiffies(250)) == 0) { 901de9ce703SDmitry Torokhov /* 902de9ce703SDmitry Torokhov * AUX IRQ was never delivered so we need to flush the controller to 903de9ce703SDmitry Torokhov * get rid of the byte we put there; otherwise keyboard may not work. 904de9ce703SDmitry Torokhov */ 9054eb3c30bSJoe Perches dbg(" -- i8042 (aux irq test timeout)\n"); 906de9ce703SDmitry Torokhov i8042_flush(); 907de9ce703SDmitry Torokhov retval = -1; 908de9ce703SDmitry Torokhov } 909de9ce703SDmitry Torokhov 910de9ce703SDmitry Torokhov out: 911de9ce703SDmitry Torokhov 912de9ce703SDmitry Torokhov /* 9131da177e4SLinus Torvalds * Disable the interface. 9141da177e4SLinus Torvalds */ 9151da177e4SLinus Torvalds 9161da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_AUXDIS; 9171da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_AUXINT; 9181da177e4SLinus Torvalds 9191da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 920de9ce703SDmitry Torokhov retval = -1; 921de9ce703SDmitry Torokhov 922de9ce703SDmitry Torokhov if (irq_registered) 923de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 924de9ce703SDmitry Torokhov 925de9ce703SDmitry Torokhov return retval; 926de9ce703SDmitry Torokhov } 927de9ce703SDmitry Torokhov 928de9ce703SDmitry Torokhov static int i8042_controller_check(void) 929de9ce703SDmitry Torokhov { 9302f0d2604SAndrey Moiseev if (i8042_flush()) { 931f5d75341STakashi Iwai pr_info("No controller found\n"); 932de9ce703SDmitry Torokhov return -ENODEV; 933de9ce703SDmitry Torokhov } 9341da177e4SLinus Torvalds 9351da177e4SLinus Torvalds return 0; 9361da177e4SLinus Torvalds } 9371da177e4SLinus Torvalds 938de9ce703SDmitry Torokhov static int i8042_controller_selftest(void) 9392673c836SVojtech Pavlik { 9402673c836SVojtech Pavlik unsigned char param; 9415ea2fc64SArjan van de Ven int i = 0; 9422673c836SVojtech Pavlik 9435ea2fc64SArjan van de Ven /* 9445ea2fc64SArjan van de Ven * We try this 5 times; on some really fragile systems this does not 9455ea2fc64SArjan van de Ven * take the first time... 9465ea2fc64SArjan van de Ven */ 9475ea2fc64SArjan van de Ven do { 9485ea2fc64SArjan van de Ven 9492673c836SVojtech Pavlik if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { 9504eb3c30bSJoe Perches pr_err("i8042 controller selftest timeout\n"); 951de9ce703SDmitry Torokhov return -ENODEV; 9522673c836SVojtech Pavlik } 9532673c836SVojtech Pavlik 9545ea2fc64SArjan van de Ven if (param == I8042_RET_CTL_TEST) 9555ea2fc64SArjan van de Ven return 0; 9565ea2fc64SArjan van de Ven 957a2a94e73SPaul Bolle dbg("i8042 controller selftest: %#x != %#x\n", 9582673c836SVojtech Pavlik param, I8042_RET_CTL_TEST); 9595ea2fc64SArjan van de Ven msleep(50); 9605ea2fc64SArjan van de Ven } while (i++ < 5); 9612673c836SVojtech Pavlik 9625ea2fc64SArjan van de Ven #ifdef CONFIG_X86 9635ea2fc64SArjan van de Ven /* 9645ea2fc64SArjan van de Ven * On x86, we don't fail entire i8042 initialization if controller 9655ea2fc64SArjan van de Ven * reset fails in hopes that keyboard port will still be functional 9665ea2fc64SArjan van de Ven * and user will still get a working keyboard. This is especially 9675ea2fc64SArjan van de Ven * important on netbooks. On other arches we trust hardware more. 9685ea2fc64SArjan van de Ven */ 9694eb3c30bSJoe Perches pr_info("giving up on controller selftest, continuing anyway...\n"); 9702673c836SVojtech Pavlik return 0; 9715ea2fc64SArjan van de Ven #else 972a2a94e73SPaul Bolle pr_err("i8042 controller selftest failed\n"); 9735ea2fc64SArjan van de Ven return -EIO; 9745ea2fc64SArjan van de Ven #endif 9752673c836SVojtech Pavlik } 9761da177e4SLinus Torvalds 9771da177e4SLinus Torvalds /* 9781da177e4SLinus Torvalds * i8042_controller init initializes the i8042 controller, and, 9791da177e4SLinus Torvalds * most importantly, sets it into non-xlated mode if that's 9801da177e4SLinus Torvalds * desired. 9811da177e4SLinus Torvalds */ 9821da177e4SLinus Torvalds 9831da177e4SLinus Torvalds static int i8042_controller_init(void) 9841da177e4SLinus Torvalds { 9851da177e4SLinus Torvalds unsigned long flags; 986ee1e82ceSDmitry Torokhov int n = 0; 987ee1e82ceSDmitry Torokhov unsigned char ctr[2]; 9881da177e4SLinus Torvalds 9891da177e4SLinus Torvalds /* 990ee1e82ceSDmitry Torokhov * Save the CTR for restore on unload / reboot. 9911da177e4SLinus Torvalds */ 9921da177e4SLinus Torvalds 993ee1e82ceSDmitry Torokhov do { 994ee1e82ceSDmitry Torokhov if (n >= 10) { 9954eb3c30bSJoe Perches pr_err("Unable to get stable CTR read\n"); 996de9ce703SDmitry Torokhov return -EIO; 9971da177e4SLinus Torvalds } 9981da177e4SLinus Torvalds 999ee1e82ceSDmitry Torokhov if (n != 0) 1000ee1e82ceSDmitry Torokhov udelay(50); 1001ee1e82ceSDmitry Torokhov 1002ee1e82ceSDmitry Torokhov if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) { 10034eb3c30bSJoe Perches pr_err("Can't read CTR while initializing i8042\n"); 1004ee1e82ceSDmitry Torokhov return -EIO; 1005ee1e82ceSDmitry Torokhov } 1006ee1e82ceSDmitry Torokhov 1007ee1e82ceSDmitry Torokhov } while (n < 2 || ctr[0] != ctr[1]); 1008ee1e82ceSDmitry Torokhov 1009ee1e82ceSDmitry Torokhov i8042_initial_ctr = i8042_ctr = ctr[0]; 10101da177e4SLinus Torvalds 10111da177e4SLinus Torvalds /* 10121da177e4SLinus Torvalds * Disable the keyboard interface and interrupt. 10131da177e4SLinus Torvalds */ 10141da177e4SLinus Torvalds 10151da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_KBDDIS; 10161da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_KBDINT; 10171da177e4SLinus Torvalds 10181da177e4SLinus Torvalds /* 10191da177e4SLinus Torvalds * Handle keylock. 10201da177e4SLinus Torvalds */ 10211da177e4SLinus Torvalds 10221da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 10231da177e4SLinus Torvalds if (~i8042_read_status() & I8042_STR_KEYLOCK) { 10241da177e4SLinus Torvalds if (i8042_unlock) 10251da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_IGNKEYLOCK; 10261da177e4SLinus Torvalds else 10274eb3c30bSJoe Perches pr_warn("Warning: Keylock active\n"); 10281da177e4SLinus Torvalds } 10291da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 10301da177e4SLinus Torvalds 10311da177e4SLinus Torvalds /* 10321da177e4SLinus Torvalds * If the chip is configured into nontranslated mode by the BIOS, don't 10331da177e4SLinus Torvalds * bother enabling translating and be happy. 10341da177e4SLinus Torvalds */ 10351da177e4SLinus Torvalds 10361da177e4SLinus Torvalds if (~i8042_ctr & I8042_CTR_XLATE) 1037386b3849SDmitry Torokhov i8042_direct = true; 10381da177e4SLinus Torvalds 10391da177e4SLinus Torvalds /* 10401da177e4SLinus Torvalds * Set nontranslated mode for the kbd interface if requested by an option. 10411da177e4SLinus Torvalds * After this the kbd interface becomes a simple serial in/out, like the aux 10421da177e4SLinus Torvalds * interface is. We don't do this by default, since it can confuse notebook 10431da177e4SLinus Torvalds * BIOSes. 10441da177e4SLinus Torvalds */ 10451da177e4SLinus Torvalds 10461da177e4SLinus Torvalds if (i8042_direct) 10471da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_XLATE; 10481da177e4SLinus Torvalds 10491da177e4SLinus Torvalds /* 10501da177e4SLinus Torvalds * Write CTR back. 10511da177e4SLinus Torvalds */ 10521da177e4SLinus Torvalds 10531da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 10544eb3c30bSJoe Perches pr_err("Can't write CTR while initializing i8042\n"); 1055de9ce703SDmitry Torokhov return -EIO; 10561da177e4SLinus Torvalds } 10571da177e4SLinus Torvalds 1058ee1e82ceSDmitry Torokhov /* 1059ee1e82ceSDmitry Torokhov * Flush whatever accumulated while we were disabling keyboard port. 1060ee1e82ceSDmitry Torokhov */ 1061ee1e82ceSDmitry Torokhov 1062ee1e82ceSDmitry Torokhov i8042_flush(); 1063ee1e82ceSDmitry Torokhov 10641da177e4SLinus Torvalds return 0; 10651da177e4SLinus Torvalds } 10661da177e4SLinus Torvalds 10671da177e4SLinus Torvalds 10681da177e4SLinus Torvalds /* 1069de9ce703SDmitry Torokhov * Reset the controller and reset CRT to the original value set by BIOS. 10701da177e4SLinus Torvalds */ 10711da177e4SLinus Torvalds 1072930e1924SMarcos Paulo de Souza static void i8042_controller_reset(bool s2r_wants_reset) 1073de9ce703SDmitry Torokhov { 1074de9ce703SDmitry Torokhov i8042_flush(); 10751da177e4SLinus Torvalds 10761da177e4SLinus Torvalds /* 10778d04ddb6SDmitry Torokhov * Disable both KBD and AUX interfaces so they don't get in the way 10788d04ddb6SDmitry Torokhov */ 10798d04ddb6SDmitry Torokhov 10808d04ddb6SDmitry Torokhov i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS; 10818d04ddb6SDmitry Torokhov i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT); 10828d04ddb6SDmitry Torokhov 1083ee1e82ceSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 10844eb3c30bSJoe Perches pr_warn("Can't write CTR while resetting\n"); 10855ddbc77cSDmitry Torokhov 10868d04ddb6SDmitry Torokhov /* 10871da177e4SLinus Torvalds * Disable MUX mode if present. 10881da177e4SLinus Torvalds */ 10891da177e4SLinus Torvalds 10901da177e4SLinus Torvalds if (i8042_mux_present) 1091386b3849SDmitry Torokhov i8042_set_mux_mode(false, NULL); 10921da177e4SLinus Torvalds 10931da177e4SLinus Torvalds /* 1094de9ce703SDmitry Torokhov * Reset the controller if requested. 1095de9ce703SDmitry Torokhov */ 1096de9ce703SDmitry Torokhov 1097930e1924SMarcos Paulo de Souza if (i8042_reset == I8042_RESET_ALWAYS || 1098930e1924SMarcos Paulo de Souza (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) { 1099de9ce703SDmitry Torokhov i8042_controller_selftest(); 1100930e1924SMarcos Paulo de Souza } 1101de9ce703SDmitry Torokhov 1102de9ce703SDmitry Torokhov /* 11031da177e4SLinus Torvalds * Restore the original control register setting. 11041da177e4SLinus Torvalds */ 11051da177e4SLinus Torvalds 1106de9ce703SDmitry Torokhov if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR)) 11074eb3c30bSJoe Perches pr_warn("Can't restore CTR\n"); 11081da177e4SLinus Torvalds } 11091da177e4SLinus Torvalds 11101da177e4SLinus Torvalds 11111da177e4SLinus Torvalds /* 1112c7ff0d9cSTAMUKI Shoichi * i8042_panic_blink() will turn the keyboard LEDs on or off and is called 1113c7ff0d9cSTAMUKI Shoichi * when kernel panics. Flashing LEDs is useful for users running X who may 1114aa5e5dc2SMichael Opdenacker * not see the console and will help distinguishing panics from "real" 11151da177e4SLinus Torvalds * lockups. 11161da177e4SLinus Torvalds * 11171da177e4SLinus Torvalds * Note that DELAY has a limit of 10ms so we will not get stuck here 11181da177e4SLinus Torvalds * waiting for KBC to free up even if KBD interrupt is off 11191da177e4SLinus Torvalds */ 11201da177e4SLinus Torvalds 11211da177e4SLinus Torvalds #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0) 11221da177e4SLinus Torvalds 1123c7ff0d9cSTAMUKI Shoichi static long i8042_panic_blink(int state) 11241da177e4SLinus Torvalds { 11251da177e4SLinus Torvalds long delay = 0; 1126c7ff0d9cSTAMUKI Shoichi char led; 11271da177e4SLinus Torvalds 1128c7ff0d9cSTAMUKI Shoichi led = (state) ? 0x01 | 0x04 : 0; 11291da177e4SLinus Torvalds while (i8042_read_status() & I8042_STR_IBF) 11301da177e4SLinus Torvalds DELAY; 11314eb3c30bSJoe Perches dbg("%02x -> i8042 (panic blink)\n", 0xed); 113219f3c3e3SDmitry Torokhov i8042_suppress_kbd_ack = 2; 11331da177e4SLinus Torvalds i8042_write_data(0xed); /* set leds */ 11341da177e4SLinus Torvalds DELAY; 11351da177e4SLinus Torvalds while (i8042_read_status() & I8042_STR_IBF) 11361da177e4SLinus Torvalds DELAY; 11371da177e4SLinus Torvalds DELAY; 11384eb3c30bSJoe Perches dbg("%02x -> i8042 (panic blink)\n", led); 11391da177e4SLinus Torvalds i8042_write_data(led); 11401da177e4SLinus Torvalds DELAY; 11411da177e4SLinus Torvalds return delay; 11421da177e4SLinus Torvalds } 11431da177e4SLinus Torvalds 11441da177e4SLinus Torvalds #undef DELAY 11451da177e4SLinus Torvalds 1146d35895dbSBruno Prémont #ifdef CONFIG_X86 1147d35895dbSBruno Prémont static void i8042_dritek_enable(void) 1148d35895dbSBruno Prémont { 1149594d6363SChristoph Fritz unsigned char param = 0x90; 1150d35895dbSBruno Prémont int error; 1151d35895dbSBruno Prémont 1152d35895dbSBruno Prémont error = i8042_command(¶m, 0x1059); 1153d35895dbSBruno Prémont if (error) 11544eb3c30bSJoe Perches pr_warn("Failed to enable DRITEK extension: %d\n", error); 1155d35895dbSBruno Prémont } 1156d35895dbSBruno Prémont #endif 1157d35895dbSBruno Prémont 115882dd9effSDmitry Torokhov #ifdef CONFIG_PM 11597e044e05SDmitry Torokhov 11601da177e4SLinus Torvalds /* 1161ebd7768dSDmitry Torokhov * Here we try to reset everything back to a state we had 1162ebd7768dSDmitry Torokhov * before suspending. 11631da177e4SLinus Torvalds */ 11641da177e4SLinus Torvalds 1165930e1924SMarcos Paulo de Souza static int i8042_controller_resume(bool s2r_wants_reset) 11661da177e4SLinus Torvalds { 1167de9ce703SDmitry Torokhov int error; 11681da177e4SLinus Torvalds 1169de9ce703SDmitry Torokhov error = i8042_controller_check(); 1170de9ce703SDmitry Torokhov if (error) 1171de9ce703SDmitry Torokhov return error; 11722673c836SVojtech Pavlik 1173930e1924SMarcos Paulo de Souza if (i8042_reset == I8042_RESET_ALWAYS || 1174930e1924SMarcos Paulo de Souza (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) { 1175de9ce703SDmitry Torokhov error = i8042_controller_selftest(); 1176de9ce703SDmitry Torokhov if (error) 1177de9ce703SDmitry Torokhov return error; 11781ca56e51SDmitry Torokhov } 1179de9ce703SDmitry Torokhov 1180de9ce703SDmitry Torokhov /* 118182dd9effSDmitry Torokhov * Restore original CTR value and disable all ports 1182de9ce703SDmitry Torokhov */ 1183de9ce703SDmitry Torokhov 118482dd9effSDmitry Torokhov i8042_ctr = i8042_initial_ctr; 118582dd9effSDmitry Torokhov if (i8042_direct) 118682dd9effSDmitry Torokhov i8042_ctr &= ~I8042_CTR_XLATE; 1187de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS; 1188de9ce703SDmitry Torokhov i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT); 11892673c836SVojtech Pavlik if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 11904eb3c30bSJoe Perches pr_warn("Can't write CTR to resume, retrying...\n"); 11912f6a77d5SJiri Kosina msleep(50); 11922f6a77d5SJiri Kosina if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 11934eb3c30bSJoe Perches pr_err("CTR write retry failed\n"); 1194de9ce703SDmitry Torokhov return -EIO; 11951da177e4SLinus Torvalds } 11962f6a77d5SJiri Kosina } 11971da177e4SLinus Torvalds 1198d35895dbSBruno Prémont 1199d35895dbSBruno Prémont #ifdef CONFIG_X86 1200d35895dbSBruno Prémont if (i8042_dritek) 1201d35895dbSBruno Prémont i8042_dritek_enable(); 1202d35895dbSBruno Prémont #endif 1203d35895dbSBruno Prémont 1204de9ce703SDmitry Torokhov if (i8042_mux_present) { 1205386b3849SDmitry Torokhov if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports()) 12064eb3c30bSJoe Perches pr_warn("failed to resume active multiplexor, mouse won't work\n"); 1207de9ce703SDmitry Torokhov } else if (i8042_ports[I8042_AUX_PORT_NO].serio) 1208de9ce703SDmitry Torokhov i8042_enable_aux_port(); 12091da177e4SLinus Torvalds 1210de9ce703SDmitry Torokhov if (i8042_ports[I8042_KBD_PORT_NO].serio) 1211de9ce703SDmitry Torokhov i8042_enable_kbd_port(); 12121da177e4SLinus Torvalds 12137d12e780SDavid Howells i8042_interrupt(0, NULL); 12141da177e4SLinus Torvalds 12151da177e4SLinus Torvalds return 0; 12161da177e4SLinus Torvalds } 1217ebd7768dSDmitry Torokhov 12181ca56e51SDmitry Torokhov /* 12191ca56e51SDmitry Torokhov * Here we try to restore the original BIOS settings to avoid 12201ca56e51SDmitry Torokhov * upsetting it. 12211ca56e51SDmitry Torokhov */ 12221ca56e51SDmitry Torokhov 12231729ad1fSDmitry Torokhov static int i8042_pm_suspend(struct device *dev) 12241ca56e51SDmitry Torokhov { 1225f13b2065SRafael J. Wysocki int i; 1226f13b2065SRafael J. Wysocki 12271c5dd134SRafael J. Wysocki if (pm_suspend_via_firmware()) 12281729ad1fSDmitry Torokhov i8042_controller_reset(true); 12291ca56e51SDmitry Torokhov 1230f13b2065SRafael J. Wysocki /* Set up serio interrupts for system wakeup. */ 1231f13b2065SRafael J. Wysocki for (i = 0; i < I8042_NUM_PORTS; i++) { 1232f13b2065SRafael J. Wysocki struct serio *serio = i8042_ports[i].serio; 1233f13b2065SRafael J. Wysocki 1234f13b2065SRafael J. Wysocki if (serio && device_may_wakeup(&serio->dev)) 1235f13b2065SRafael J. Wysocki enable_irq_wake(i8042_ports[i].irq); 1236f13b2065SRafael J. Wysocki } 1237f13b2065SRafael J. Wysocki 12381ca56e51SDmitry Torokhov return 0; 12391ca56e51SDmitry Torokhov } 12401ca56e51SDmitry Torokhov 12411c5dd134SRafael J. Wysocki static int i8042_pm_resume_noirq(struct device *dev) 12421c5dd134SRafael J. Wysocki { 12431c5dd134SRafael J. Wysocki if (!pm_resume_via_firmware()) 12441c5dd134SRafael J. Wysocki i8042_interrupt(0, NULL); 12451c5dd134SRafael J. Wysocki 12461c5dd134SRafael J. Wysocki return 0; 12471c5dd134SRafael J. Wysocki } 12481c5dd134SRafael J. Wysocki 12491ca56e51SDmitry Torokhov static int i8042_pm_resume(struct device *dev) 12501ca56e51SDmitry Torokhov { 1251930e1924SMarcos Paulo de Souza bool want_reset; 1252f13b2065SRafael J. Wysocki int i; 1253f13b2065SRafael J. Wysocki 1254f13b2065SRafael J. Wysocki for (i = 0; i < I8042_NUM_PORTS; i++) { 1255f13b2065SRafael J. Wysocki struct serio *serio = i8042_ports[i].serio; 1256f13b2065SRafael J. Wysocki 1257f13b2065SRafael J. Wysocki if (serio && device_may_wakeup(&serio->dev)) 1258f13b2065SRafael J. Wysocki disable_irq_wake(i8042_ports[i].irq); 1259f13b2065SRafael J. Wysocki } 1260f13b2065SRafael J. Wysocki 12611ca56e51SDmitry Torokhov /* 12621c5dd134SRafael J. Wysocki * If platform firmware was not going to be involved in suspend, we did 12631c5dd134SRafael J. Wysocki * not restore the controller state to whatever it had been at boot 12641c5dd134SRafael J. Wysocki * time, so we do not need to do anything. 12651ca56e51SDmitry Torokhov */ 12661c5dd134SRafael J. Wysocki if (!pm_suspend_via_firmware()) 12671c5dd134SRafael J. Wysocki return 0; 12681c5dd134SRafael J. Wysocki 12691c5dd134SRafael J. Wysocki /* 12701c5dd134SRafael J. Wysocki * We only need to reset the controller if we are resuming after handing 12711c5dd134SRafael J. Wysocki * off control to the platform firmware, otherwise we can simply restore 12721c5dd134SRafael J. Wysocki * the mode. 12731c5dd134SRafael J. Wysocki */ 1274930e1924SMarcos Paulo de Souza want_reset = pm_resume_via_firmware(); 12751c5dd134SRafael J. Wysocki 1276930e1924SMarcos Paulo de Souza return i8042_controller_resume(want_reset); 12771ca56e51SDmitry Torokhov } 12781ca56e51SDmitry Torokhov 1279c2d1a2a1SAlan Jenkins static int i8042_pm_thaw(struct device *dev) 1280c2d1a2a1SAlan Jenkins { 1281c2d1a2a1SAlan Jenkins i8042_interrupt(0, NULL); 1282c2d1a2a1SAlan Jenkins 1283c2d1a2a1SAlan Jenkins return 0; 1284c2d1a2a1SAlan Jenkins } 1285c2d1a2a1SAlan Jenkins 12861729ad1fSDmitry Torokhov static int i8042_pm_reset(struct device *dev) 12871729ad1fSDmitry Torokhov { 12881729ad1fSDmitry Torokhov i8042_controller_reset(false); 12891729ad1fSDmitry Torokhov 12901729ad1fSDmitry Torokhov return 0; 12911729ad1fSDmitry Torokhov } 12921729ad1fSDmitry Torokhov 12931ca56e51SDmitry Torokhov static int i8042_pm_restore(struct device *dev) 12941ca56e51SDmitry Torokhov { 12951ca56e51SDmitry Torokhov return i8042_controller_resume(false); 12961ca56e51SDmitry Torokhov } 12971ca56e51SDmitry Torokhov 1298ebd7768dSDmitry Torokhov static const struct dev_pm_ops i8042_pm_ops = { 12991729ad1fSDmitry Torokhov .suspend = i8042_pm_suspend, 13001c5dd134SRafael J. Wysocki .resume_noirq = i8042_pm_resume_noirq, 13011ca56e51SDmitry Torokhov .resume = i8042_pm_resume, 1302c2d1a2a1SAlan Jenkins .thaw = i8042_pm_thaw, 1303ebd7768dSDmitry Torokhov .poweroff = i8042_pm_reset, 1304ebd7768dSDmitry Torokhov .restore = i8042_pm_restore, 1305ebd7768dSDmitry Torokhov }; 1306ebd7768dSDmitry Torokhov 130782dd9effSDmitry Torokhov #endif /* CONFIG_PM */ 13081da177e4SLinus Torvalds 13091da177e4SLinus Torvalds /* 13101da177e4SLinus Torvalds * We need to reset the 8042 back to original mode on system shutdown, 13111da177e4SLinus Torvalds * because otherwise BIOSes will be confused. 13121da177e4SLinus Torvalds */ 13131da177e4SLinus Torvalds 13143ae5eaecSRussell King static void i8042_shutdown(struct platform_device *dev) 13151da177e4SLinus Torvalds { 13161729ad1fSDmitry Torokhov i8042_controller_reset(false); 13171da177e4SLinus Torvalds } 13181da177e4SLinus Torvalds 1319f8113416SDmitry Torokhov static int __init i8042_create_kbd_port(void) 13201da177e4SLinus Torvalds { 13211da177e4SLinus Torvalds struct serio *serio; 13221da177e4SLinus Torvalds struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; 13231da177e4SLinus Torvalds 1324d39969deSDmitry Torokhov serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 13250854e52dSDmitry Torokhov if (!serio) 13260854e52dSDmitry Torokhov return -ENOMEM; 13270854e52dSDmitry Torokhov 13281da177e4SLinus Torvalds serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; 13291da177e4SLinus Torvalds serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; 13301da177e4SLinus Torvalds serio->start = i8042_start; 13311da177e4SLinus Torvalds serio->stop = i8042_stop; 13325ddbc77cSDmitry Torokhov serio->close = i8042_port_close; 133340974618SDmitry Torokhov serio->ps2_cmd_mutex = &i8042_mutex; 13341da177e4SLinus Torvalds serio->port_data = port; 13351da177e4SLinus Torvalds serio->dev.parent = &i8042_platform_device->dev; 1336de9ce703SDmitry Torokhov strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); 13371da177e4SLinus Torvalds strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); 1338a7c5868cSHans de Goede strlcpy(serio->firmware_id, i8042_kbd_firmware_id, 1339a7c5868cSHans de Goede sizeof(serio->firmware_id)); 1340*6052abf8SRajat Jain set_primary_fwnode(&serio->dev, i8042_kbd_fwnode); 13411da177e4SLinus Torvalds 13421da177e4SLinus Torvalds port->serio = serio; 1343de9ce703SDmitry Torokhov port->irq = I8042_KBD_IRQ; 13440854e52dSDmitry Torokhov 1345de9ce703SDmitry Torokhov return 0; 13461da177e4SLinus Torvalds } 13471da177e4SLinus Torvalds 1348f8113416SDmitry Torokhov static int __init i8042_create_aux_port(int idx) 13491da177e4SLinus Torvalds { 13501da177e4SLinus Torvalds struct serio *serio; 1351de9ce703SDmitry Torokhov int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx; 1352de9ce703SDmitry Torokhov struct i8042_port *port = &i8042_ports[port_no]; 13531da177e4SLinus Torvalds 1354d39969deSDmitry Torokhov serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 13550854e52dSDmitry Torokhov if (!serio) 13560854e52dSDmitry Torokhov return -ENOMEM; 13570854e52dSDmitry Torokhov 13581da177e4SLinus Torvalds serio->id.type = SERIO_8042; 13591da177e4SLinus Torvalds serio->write = i8042_aux_write; 13601da177e4SLinus Torvalds serio->start = i8042_start; 13611da177e4SLinus Torvalds serio->stop = i8042_stop; 136247af45d6SDmitry Torokhov serio->ps2_cmd_mutex = &i8042_mutex; 13631da177e4SLinus Torvalds serio->port_data = port; 13641da177e4SLinus Torvalds serio->dev.parent = &i8042_platform_device->dev; 1365de9ce703SDmitry Torokhov if (idx < 0) { 1366de9ce703SDmitry Torokhov strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name)); 13671da177e4SLinus Torvalds strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); 1368a7c5868cSHans de Goede strlcpy(serio->firmware_id, i8042_aux_firmware_id, 1369a7c5868cSHans de Goede sizeof(serio->firmware_id)); 13705ddbc77cSDmitry Torokhov serio->close = i8042_port_close; 1371de9ce703SDmitry Torokhov } else { 1372de9ce703SDmitry Torokhov snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx); 1373de9ce703SDmitry Torokhov snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1); 1374266e43c4SHans de Goede strlcpy(serio->firmware_id, i8042_aux_firmware_id, 1375266e43c4SHans de Goede sizeof(serio->firmware_id)); 13761da177e4SLinus Torvalds } 13771da177e4SLinus Torvalds 13781da177e4SLinus Torvalds port->serio = serio; 1379de9ce703SDmitry Torokhov port->mux = idx; 1380de9ce703SDmitry Torokhov port->irq = I8042_AUX_IRQ; 13810854e52dSDmitry Torokhov 1382de9ce703SDmitry Torokhov return 0; 1383de9ce703SDmitry Torokhov } 1384de9ce703SDmitry Torokhov 1385f8113416SDmitry Torokhov static void __init i8042_free_kbd_port(void) 1386de9ce703SDmitry Torokhov { 1387de9ce703SDmitry Torokhov kfree(i8042_ports[I8042_KBD_PORT_NO].serio); 1388de9ce703SDmitry Torokhov i8042_ports[I8042_KBD_PORT_NO].serio = NULL; 1389de9ce703SDmitry Torokhov } 1390de9ce703SDmitry Torokhov 1391f8113416SDmitry Torokhov static void __init i8042_free_aux_ports(void) 1392de9ce703SDmitry Torokhov { 1393de9ce703SDmitry Torokhov int i; 1394de9ce703SDmitry Torokhov 1395de9ce703SDmitry Torokhov for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) { 1396de9ce703SDmitry Torokhov kfree(i8042_ports[i].serio); 1397de9ce703SDmitry Torokhov i8042_ports[i].serio = NULL; 1398de9ce703SDmitry Torokhov } 1399de9ce703SDmitry Torokhov } 1400de9ce703SDmitry Torokhov 1401f8113416SDmitry Torokhov static void __init i8042_register_ports(void) 1402de9ce703SDmitry Torokhov { 1403de9ce703SDmitry Torokhov int i; 1404de9ce703SDmitry Torokhov 1405de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) { 1406f13b2065SRafael J. Wysocki struct serio *serio = i8042_ports[i].serio; 1407f13b2065SRafael J. Wysocki 1408684bec10SDaniel Drake if (!serio) 1409684bec10SDaniel Drake continue; 1410684bec10SDaniel Drake 1411de9ce703SDmitry Torokhov printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n", 1412f13b2065SRafael J. Wysocki serio->name, 1413de9ce703SDmitry Torokhov (unsigned long) I8042_DATA_REG, 1414de9ce703SDmitry Torokhov (unsigned long) I8042_COMMAND_REG, 1415de9ce703SDmitry Torokhov i8042_ports[i].irq); 1416f13b2065SRafael J. Wysocki serio_register_port(serio); 1417de9ce703SDmitry Torokhov } 1418de9ce703SDmitry Torokhov } 1419de9ce703SDmitry Torokhov 1420e2619cf7SBill Pemberton static void i8042_unregister_ports(void) 1421de9ce703SDmitry Torokhov { 1422de9ce703SDmitry Torokhov int i; 1423de9ce703SDmitry Torokhov 1424de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) { 1425de9ce703SDmitry Torokhov if (i8042_ports[i].serio) { 1426de9ce703SDmitry Torokhov serio_unregister_port(i8042_ports[i].serio); 1427de9ce703SDmitry Torokhov i8042_ports[i].serio = NULL; 1428de9ce703SDmitry Torokhov } 1429de9ce703SDmitry Torokhov } 1430de9ce703SDmitry Torokhov } 1431de9ce703SDmitry Torokhov 1432de9ce703SDmitry Torokhov static void i8042_free_irqs(void) 1433de9ce703SDmitry Torokhov { 1434de9ce703SDmitry Torokhov if (i8042_aux_irq_registered) 1435de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 1436de9ce703SDmitry Torokhov if (i8042_kbd_irq_registered) 1437de9ce703SDmitry Torokhov free_irq(I8042_KBD_IRQ, i8042_platform_device); 1438de9ce703SDmitry Torokhov 1439386b3849SDmitry Torokhov i8042_aux_irq_registered = i8042_kbd_irq_registered = false; 1440de9ce703SDmitry Torokhov } 1441de9ce703SDmitry Torokhov 1442f8113416SDmitry Torokhov static int __init i8042_setup_aux(void) 1443de9ce703SDmitry Torokhov { 1444de9ce703SDmitry Torokhov int (*aux_enable)(void); 1445de9ce703SDmitry Torokhov int error; 1446de9ce703SDmitry Torokhov int i; 1447de9ce703SDmitry Torokhov 1448de9ce703SDmitry Torokhov if (i8042_check_aux()) 1449de9ce703SDmitry Torokhov return -ENODEV; 1450de9ce703SDmitry Torokhov 1451de9ce703SDmitry Torokhov if (i8042_nomux || i8042_check_mux()) { 1452de9ce703SDmitry Torokhov error = i8042_create_aux_port(-1); 1453de9ce703SDmitry Torokhov if (error) 1454de9ce703SDmitry Torokhov goto err_free_ports; 1455de9ce703SDmitry Torokhov aux_enable = i8042_enable_aux_port; 1456de9ce703SDmitry Torokhov } else { 1457de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { 1458de9ce703SDmitry Torokhov error = i8042_create_aux_port(i); 1459de9ce703SDmitry Torokhov if (error) 1460de9ce703SDmitry Torokhov goto err_free_ports; 1461de9ce703SDmitry Torokhov } 1462de9ce703SDmitry Torokhov aux_enable = i8042_enable_mux_ports; 1463de9ce703SDmitry Torokhov } 1464de9ce703SDmitry Torokhov 1465de9ce703SDmitry Torokhov error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED, 1466de9ce703SDmitry Torokhov "i8042", i8042_platform_device); 1467de9ce703SDmitry Torokhov if (error) 1468de9ce703SDmitry Torokhov goto err_free_ports; 1469de9ce703SDmitry Torokhov 1470de9ce703SDmitry Torokhov if (aux_enable()) 1471de9ce703SDmitry Torokhov goto err_free_irq; 1472de9ce703SDmitry Torokhov 1473386b3849SDmitry Torokhov i8042_aux_irq_registered = true; 1474de9ce703SDmitry Torokhov return 0; 1475de9ce703SDmitry Torokhov 1476de9ce703SDmitry Torokhov err_free_irq: 1477de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 1478de9ce703SDmitry Torokhov err_free_ports: 1479de9ce703SDmitry Torokhov i8042_free_aux_ports(); 1480de9ce703SDmitry Torokhov return error; 1481de9ce703SDmitry Torokhov } 1482de9ce703SDmitry Torokhov 1483f8113416SDmitry Torokhov static int __init i8042_setup_kbd(void) 1484de9ce703SDmitry Torokhov { 1485de9ce703SDmitry Torokhov int error; 1486de9ce703SDmitry Torokhov 1487de9ce703SDmitry Torokhov error = i8042_create_kbd_port(); 1488de9ce703SDmitry Torokhov if (error) 1489de9ce703SDmitry Torokhov return error; 1490de9ce703SDmitry Torokhov 1491de9ce703SDmitry Torokhov error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED, 1492de9ce703SDmitry Torokhov "i8042", i8042_platform_device); 1493de9ce703SDmitry Torokhov if (error) 1494de9ce703SDmitry Torokhov goto err_free_port; 1495de9ce703SDmitry Torokhov 1496de9ce703SDmitry Torokhov error = i8042_enable_kbd_port(); 1497de9ce703SDmitry Torokhov if (error) 1498de9ce703SDmitry Torokhov goto err_free_irq; 1499de9ce703SDmitry Torokhov 1500386b3849SDmitry Torokhov i8042_kbd_irq_registered = true; 1501de9ce703SDmitry Torokhov return 0; 1502de9ce703SDmitry Torokhov 1503de9ce703SDmitry Torokhov err_free_irq: 1504de9ce703SDmitry Torokhov free_irq(I8042_KBD_IRQ, i8042_platform_device); 1505de9ce703SDmitry Torokhov err_free_port: 1506de9ce703SDmitry Torokhov i8042_free_kbd_port(); 1507de9ce703SDmitry Torokhov return error; 15081da177e4SLinus Torvalds } 15091da177e4SLinus Torvalds 1510e1443d28SStephen Chandler Paul static int i8042_kbd_bind_notifier(struct notifier_block *nb, 1511e1443d28SStephen Chandler Paul unsigned long action, void *data) 1512e1443d28SStephen Chandler Paul { 1513e1443d28SStephen Chandler Paul struct device *dev = data; 1514e1443d28SStephen Chandler Paul struct serio *serio = to_serio_port(dev); 1515e1443d28SStephen Chandler Paul struct i8042_port *port = serio->port_data; 1516e1443d28SStephen Chandler Paul 1517e1443d28SStephen Chandler Paul if (serio != i8042_ports[I8042_KBD_PORT_NO].serio) 1518e1443d28SStephen Chandler Paul return 0; 1519e1443d28SStephen Chandler Paul 1520e1443d28SStephen Chandler Paul switch (action) { 1521e1443d28SStephen Chandler Paul case BUS_NOTIFY_BOUND_DRIVER: 1522e1443d28SStephen Chandler Paul port->driver_bound = true; 1523e1443d28SStephen Chandler Paul break; 1524e1443d28SStephen Chandler Paul 1525e1443d28SStephen Chandler Paul case BUS_NOTIFY_UNBIND_DRIVER: 1526e1443d28SStephen Chandler Paul port->driver_bound = false; 1527e1443d28SStephen Chandler Paul break; 1528e1443d28SStephen Chandler Paul } 1529e1443d28SStephen Chandler Paul 1530e1443d28SStephen Chandler Paul return 0; 1531e1443d28SStephen Chandler Paul } 1532e1443d28SStephen Chandler Paul 1533f8113416SDmitry Torokhov static int __init i8042_probe(struct platform_device *dev) 15341da177e4SLinus Torvalds { 1535de9ce703SDmitry Torokhov int error; 15361da177e4SLinus Torvalds 1537ec62e1c8SDmitry Torokhov i8042_platform_device = dev; 1538ec62e1c8SDmitry Torokhov 1539930e1924SMarcos Paulo de Souza if (i8042_reset == I8042_RESET_ALWAYS) { 1540de9ce703SDmitry Torokhov error = i8042_controller_selftest(); 1541de9ce703SDmitry Torokhov if (error) 1542de9ce703SDmitry Torokhov return error; 15431ca56e51SDmitry Torokhov } 15441da177e4SLinus Torvalds 1545de9ce703SDmitry Torokhov error = i8042_controller_init(); 1546de9ce703SDmitry Torokhov if (error) 1547de9ce703SDmitry Torokhov return error; 15481da177e4SLinus Torvalds 1549d35895dbSBruno Prémont #ifdef CONFIG_X86 1550d35895dbSBruno Prémont if (i8042_dritek) 1551d35895dbSBruno Prémont i8042_dritek_enable(); 1552d35895dbSBruno Prémont #endif 1553d35895dbSBruno Prémont 1554de9ce703SDmitry Torokhov if (!i8042_noaux) { 1555de9ce703SDmitry Torokhov error = i8042_setup_aux(); 1556de9ce703SDmitry Torokhov if (error && error != -ENODEV && error != -EBUSY) 1557de9ce703SDmitry Torokhov goto out_fail; 15581da177e4SLinus Torvalds } 15591da177e4SLinus Torvalds 1560945ef0d4SDmitry Torokhov if (!i8042_nokbd) { 1561de9ce703SDmitry Torokhov error = i8042_setup_kbd(); 1562de9ce703SDmitry Torokhov if (error) 1563de9ce703SDmitry Torokhov goto out_fail; 1564945ef0d4SDmitry Torokhov } 1565de9ce703SDmitry Torokhov /* 1566de9ce703SDmitry Torokhov * Ok, everything is ready, let's register all serio ports 1567de9ce703SDmitry Torokhov */ 1568de9ce703SDmitry Torokhov i8042_register_ports(); 15691da177e4SLinus Torvalds 15701da177e4SLinus Torvalds return 0; 15710854e52dSDmitry Torokhov 1572de9ce703SDmitry Torokhov out_fail: 1573de9ce703SDmitry Torokhov i8042_free_aux_ports(); /* in case KBD failed but AUX not */ 1574de9ce703SDmitry Torokhov i8042_free_irqs(); 15751729ad1fSDmitry Torokhov i8042_controller_reset(false); 1576ec62e1c8SDmitry Torokhov i8042_platform_device = NULL; 15770854e52dSDmitry Torokhov 1578de9ce703SDmitry Torokhov return error; 15791da177e4SLinus Torvalds } 15801da177e4SLinus Torvalds 1581e2619cf7SBill Pemberton static int i8042_remove(struct platform_device *dev) 15821da177e4SLinus Torvalds { 1583de9ce703SDmitry Torokhov i8042_unregister_ports(); 1584de9ce703SDmitry Torokhov i8042_free_irqs(); 15851729ad1fSDmitry Torokhov i8042_controller_reset(false); 1586ec62e1c8SDmitry Torokhov i8042_platform_device = NULL; 15871da177e4SLinus Torvalds 158887fd6318SDmitry Torokhov return 0; 158987fd6318SDmitry Torokhov } 159087fd6318SDmitry Torokhov 159187fd6318SDmitry Torokhov static struct platform_driver i8042_driver = { 159287fd6318SDmitry Torokhov .driver = { 159387fd6318SDmitry Torokhov .name = "i8042", 1594ebd7768dSDmitry Torokhov #ifdef CONFIG_PM 1595ebd7768dSDmitry Torokhov .pm = &i8042_pm_ops, 1596ebd7768dSDmitry Torokhov #endif 159787fd6318SDmitry Torokhov }, 15981cb0aa88SBill Pemberton .remove = i8042_remove, 159982dd9effSDmitry Torokhov .shutdown = i8042_shutdown, 160087fd6318SDmitry Torokhov }; 160187fd6318SDmitry Torokhov 1602e1443d28SStephen Chandler Paul static struct notifier_block i8042_kbd_bind_notifier_block = { 1603e1443d28SStephen Chandler Paul .notifier_call = i8042_kbd_bind_notifier, 1604e1443d28SStephen Chandler Paul }; 1605e1443d28SStephen Chandler Paul 160687fd6318SDmitry Torokhov static int __init i8042_init(void) 160787fd6318SDmitry Torokhov { 1608ec62e1c8SDmitry Torokhov struct platform_device *pdev; 160987fd6318SDmitry Torokhov int err; 161087fd6318SDmitry Torokhov 161187fd6318SDmitry Torokhov dbg_init(); 161287fd6318SDmitry Torokhov 161387fd6318SDmitry Torokhov err = i8042_platform_init(); 161487fd6318SDmitry Torokhov if (err) 161587fd6318SDmitry Torokhov return err; 161687fd6318SDmitry Torokhov 1617de9ce703SDmitry Torokhov err = i8042_controller_check(); 1618de9ce703SDmitry Torokhov if (err) 1619de9ce703SDmitry Torokhov goto err_platform_exit; 162087fd6318SDmitry Torokhov 1621ec62e1c8SDmitry Torokhov pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0); 1622ec62e1c8SDmitry Torokhov if (IS_ERR(pdev)) { 1623ec62e1c8SDmitry Torokhov err = PTR_ERR(pdev); 1624f8113416SDmitry Torokhov goto err_platform_exit; 162587fd6318SDmitry Torokhov } 162687fd6318SDmitry Torokhov 1627e1443d28SStephen Chandler Paul bus_register_notifier(&serio_bus, &i8042_kbd_bind_notifier_block); 1628de9ce703SDmitry Torokhov panic_blink = i8042_panic_blink; 1629de9ce703SDmitry Torokhov 163087fd6318SDmitry Torokhov return 0; 163187fd6318SDmitry Torokhov 163287fd6318SDmitry Torokhov err_platform_exit: 163387fd6318SDmitry Torokhov i8042_platform_exit(); 163487fd6318SDmitry Torokhov return err; 163587fd6318SDmitry Torokhov } 163687fd6318SDmitry Torokhov 163787fd6318SDmitry Torokhov static void __exit i8042_exit(void) 163887fd6318SDmitry Torokhov { 1639f8113416SDmitry Torokhov platform_device_unregister(i8042_platform_device); 1640af045b86SDmitry Torokhov platform_driver_unregister(&i8042_driver); 16411da177e4SLinus Torvalds i8042_platform_exit(); 16421da177e4SLinus Torvalds 1643e1443d28SStephen Chandler Paul bus_unregister_notifier(&serio_bus, &i8042_kbd_bind_notifier_block); 16441da177e4SLinus Torvalds panic_blink = NULL; 16451da177e4SLinus Torvalds } 16461da177e4SLinus Torvalds 16471da177e4SLinus Torvalds module_init(i8042_init); 16481da177e4SLinus Torvalds module_exit(i8042_exit); 1649