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 137e044e05SDmitry Torokhov #include <linux/types.h> 141da177e4SLinus Torvalds #include <linux/delay.h> 151da177e4SLinus Torvalds #include <linux/module.h> 161da177e4SLinus Torvalds #include <linux/interrupt.h> 171da177e4SLinus Torvalds #include <linux/ioport.h> 181da177e4SLinus Torvalds #include <linux/init.h> 191da177e4SLinus Torvalds #include <linux/serio.h> 201da177e4SLinus Torvalds #include <linux/err.h> 211da177e4SLinus Torvalds #include <linux/rcupdate.h> 22d052d1beSRussell King #include <linux/platform_device.h> 23553a05b8SMárton Németh #include <linux/i8042.h> 245a0e3ad6STejun Heo #include <linux/slab.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 40386b3849SDmitry 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 48386b3849SDmitry Torokhov static bool i8042_reset; 491da177e4SLinus Torvalds module_param_named(reset, i8042_reset, bool, 0); 501da177e4SLinus Torvalds MODULE_PARM_DESC(reset, "Reset controller during init and cleanup."); 511da177e4SLinus Torvalds 52386b3849SDmitry Torokhov static bool i8042_direct; 531da177e4SLinus Torvalds module_param_named(direct, i8042_direct, bool, 0); 541da177e4SLinus Torvalds MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode."); 551da177e4SLinus Torvalds 56386b3849SDmitry Torokhov static bool i8042_dumbkbd; 571da177e4SLinus Torvalds module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); 581da177e4SLinus Torvalds MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); 591da177e4SLinus Torvalds 60386b3849SDmitry Torokhov static bool i8042_noloop; 611da177e4SLinus Torvalds module_param_named(noloop, i8042_noloop, bool, 0); 621da177e4SLinus Torvalds MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port"); 631da177e4SLinus Torvalds 648987fec0SCarlos Corbacho #ifdef CONFIG_X86 65386b3849SDmitry Torokhov static bool i8042_dritek; 668987fec0SCarlos Corbacho module_param_named(dritek, i8042_dritek, bool, 0); 678987fec0SCarlos Corbacho MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension"); 688987fec0SCarlos Corbacho #endif 698987fec0SCarlos Corbacho 701da177e4SLinus Torvalds #ifdef CONFIG_PNP 71386b3849SDmitry Torokhov static bool i8042_nopnp; 721da177e4SLinus Torvalds module_param_named(nopnp, i8042_nopnp, bool, 0); 731da177e4SLinus Torvalds MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings"); 741da177e4SLinus Torvalds #endif 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds #define DEBUG 771da177e4SLinus Torvalds #ifdef DEBUG 78386b3849SDmitry Torokhov static bool i8042_debug; 791da177e4SLinus Torvalds module_param_named(debug, i8042_debug, bool, 0600); 801da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off"); 811da177e4SLinus Torvalds #endif 821da177e4SLinus Torvalds 831c7827aeSDmitry Torokhov static bool i8042_bypass_aux_irq_test; 841c7827aeSDmitry Torokhov 851da177e4SLinus Torvalds #include "i8042.h" 861da177e4SLinus Torvalds 87181d683dSDmitry Torokhov /* 88181d683dSDmitry Torokhov * i8042_lock protects serialization between i8042_command and 89181d683dSDmitry Torokhov * the interrupt handler. 90181d683dSDmitry Torokhov */ 911da177e4SLinus Torvalds static DEFINE_SPINLOCK(i8042_lock); 921da177e4SLinus Torvalds 93181d683dSDmitry Torokhov /* 94181d683dSDmitry Torokhov * Writers to AUX and KBD ports as well as users issuing i8042_command 95181d683dSDmitry Torokhov * directly should acquire i8042_mutex (by means of calling 96181d683dSDmitry Torokhov * i8042_lock_chip() and i8042_unlock_ship() helpers) to ensure that 97181d683dSDmitry Torokhov * they do not disturb each other (unfortunately in many i8042 98181d683dSDmitry Torokhov * implementations write to one of the ports will immediately abort 99181d683dSDmitry Torokhov * command that is being processed by another port). 100181d683dSDmitry Torokhov */ 101181d683dSDmitry Torokhov static DEFINE_MUTEX(i8042_mutex); 102181d683dSDmitry Torokhov 1031da177e4SLinus Torvalds struct i8042_port { 1041da177e4SLinus Torvalds struct serio *serio; 1051da177e4SLinus Torvalds int irq; 106386b3849SDmitry Torokhov bool exists; 1071da177e4SLinus Torvalds signed char mux; 1081da177e4SLinus Torvalds }; 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds #define I8042_KBD_PORT_NO 0 1111da177e4SLinus Torvalds #define I8042_AUX_PORT_NO 1 1121da177e4SLinus Torvalds #define I8042_MUX_PORT_NO 2 1131da177e4SLinus Torvalds #define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2) 114de9ce703SDmitry Torokhov 115de9ce703SDmitry Torokhov static struct i8042_port i8042_ports[I8042_NUM_PORTS]; 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds static unsigned char i8042_initial_ctr; 1181da177e4SLinus Torvalds static unsigned char i8042_ctr; 119386b3849SDmitry Torokhov static bool i8042_mux_present; 120386b3849SDmitry Torokhov static bool i8042_kbd_irq_registered; 121386b3849SDmitry Torokhov static bool i8042_aux_irq_registered; 122817e6ba3SDmitry Torokhov static unsigned char i8042_suppress_kbd_ack; 1231da177e4SLinus Torvalds static struct platform_device *i8042_platform_device; 1241da177e4SLinus Torvalds 1257d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id); 126967c9ef9SMatthew Garrett static bool (*i8042_platform_filter)(unsigned char data, unsigned char str, 127967c9ef9SMatthew Garrett struct serio *serio); 1281da177e4SLinus Torvalds 129181d683dSDmitry Torokhov void i8042_lock_chip(void) 130181d683dSDmitry Torokhov { 131181d683dSDmitry Torokhov mutex_lock(&i8042_mutex); 132181d683dSDmitry Torokhov } 133181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_lock_chip); 134181d683dSDmitry Torokhov 135181d683dSDmitry Torokhov void i8042_unlock_chip(void) 136181d683dSDmitry Torokhov { 137181d683dSDmitry Torokhov mutex_unlock(&i8042_mutex); 138181d683dSDmitry Torokhov } 139181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_unlock_chip); 140181d683dSDmitry Torokhov 141967c9ef9SMatthew Garrett int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, 142967c9ef9SMatthew Garrett struct serio *serio)) 143967c9ef9SMatthew Garrett { 144967c9ef9SMatthew Garrett unsigned long flags; 145967c9ef9SMatthew Garrett int ret = 0; 146967c9ef9SMatthew Garrett 147967c9ef9SMatthew Garrett spin_lock_irqsave(&i8042_lock, flags); 148967c9ef9SMatthew Garrett 149967c9ef9SMatthew Garrett if (i8042_platform_filter) { 150967c9ef9SMatthew Garrett ret = -EBUSY; 151967c9ef9SMatthew Garrett goto out; 152967c9ef9SMatthew Garrett } 153967c9ef9SMatthew Garrett 154967c9ef9SMatthew Garrett i8042_platform_filter = filter; 155967c9ef9SMatthew Garrett 156967c9ef9SMatthew Garrett out: 157967c9ef9SMatthew Garrett spin_unlock_irqrestore(&i8042_lock, flags); 158967c9ef9SMatthew Garrett return ret; 159967c9ef9SMatthew Garrett } 160967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_install_filter); 161967c9ef9SMatthew Garrett 162967c9ef9SMatthew Garrett int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, 163967c9ef9SMatthew Garrett struct serio *port)) 164967c9ef9SMatthew Garrett { 165967c9ef9SMatthew Garrett unsigned long flags; 166967c9ef9SMatthew Garrett int ret = 0; 167967c9ef9SMatthew Garrett 168967c9ef9SMatthew Garrett spin_lock_irqsave(&i8042_lock, flags); 169967c9ef9SMatthew Garrett 170967c9ef9SMatthew Garrett if (i8042_platform_filter != filter) { 171967c9ef9SMatthew Garrett ret = -EINVAL; 172967c9ef9SMatthew Garrett goto out; 173967c9ef9SMatthew Garrett } 174967c9ef9SMatthew Garrett 175967c9ef9SMatthew Garrett i8042_platform_filter = NULL; 176967c9ef9SMatthew Garrett 177967c9ef9SMatthew Garrett out: 178967c9ef9SMatthew Garrett spin_unlock_irqrestore(&i8042_lock, flags); 179967c9ef9SMatthew Garrett return ret; 180967c9ef9SMatthew Garrett } 181967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_remove_filter); 182967c9ef9SMatthew Garrett 1831da177e4SLinus Torvalds /* 1841da177e4SLinus Torvalds * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to 1851da177e4SLinus Torvalds * be ready for reading values from it / writing values to it. 1861da177e4SLinus Torvalds * Called always with i8042_lock held. 1871da177e4SLinus Torvalds */ 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds static int i8042_wait_read(void) 1901da177e4SLinus Torvalds { 1911da177e4SLinus Torvalds int i = 0; 192de9ce703SDmitry Torokhov 1931da177e4SLinus Torvalds while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { 1941da177e4SLinus Torvalds udelay(50); 1951da177e4SLinus Torvalds i++; 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds return -(i == I8042_CTL_TIMEOUT); 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds static int i8042_wait_write(void) 2011da177e4SLinus Torvalds { 2021da177e4SLinus Torvalds int i = 0; 203de9ce703SDmitry Torokhov 2041da177e4SLinus Torvalds while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { 2051da177e4SLinus Torvalds udelay(50); 2061da177e4SLinus Torvalds i++; 2071da177e4SLinus Torvalds } 2081da177e4SLinus Torvalds return -(i == I8042_CTL_TIMEOUT); 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds /* 2121da177e4SLinus Torvalds * i8042_flush() flushes all data that may be in the keyboard and mouse buffers 2131da177e4SLinus Torvalds * of the i8042 down the toilet. 2141da177e4SLinus Torvalds */ 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds static int i8042_flush(void) 2171da177e4SLinus Torvalds { 2181da177e4SLinus Torvalds unsigned long flags; 2191da177e4SLinus Torvalds unsigned char data, str; 2201da177e4SLinus Torvalds int i = 0; 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) { 2251da177e4SLinus Torvalds udelay(50); 2261da177e4SLinus Torvalds data = i8042_read_data(); 2271da177e4SLinus Torvalds i++; 2281da177e4SLinus Torvalds dbg("%02x <- i8042 (flush, %s)", data, 2291da177e4SLinus Torvalds str & I8042_STR_AUXDATA ? "aux" : "kbd"); 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds return i; 2351da177e4SLinus Torvalds } 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds /* 2381da177e4SLinus Torvalds * i8042_command() executes a command on the i8042. It also sends the input 2391da177e4SLinus Torvalds * parameter(s) of the commands to it, and receives the output value(s). The 2401da177e4SLinus Torvalds * parameters are to be stored in the param array, and the output is placed 2411da177e4SLinus Torvalds * into the same array. The number of the parameters and output values is 2421da177e4SLinus Torvalds * encoded in bits 8-11 of the command number. 2431da177e4SLinus Torvalds */ 2441da177e4SLinus Torvalds 245de9ce703SDmitry Torokhov static int __i8042_command(unsigned char *param, int command) 2461da177e4SLinus Torvalds { 247de9ce703SDmitry Torokhov int i, error; 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds if (i8042_noloop && command == I8042_CMD_AUX_LOOP) 2501da177e4SLinus Torvalds return -1; 2511da177e4SLinus Torvalds 252de9ce703SDmitry Torokhov error = i8042_wait_write(); 253de9ce703SDmitry Torokhov if (error) 254de9ce703SDmitry Torokhov return error; 255463a4f76SDmitry Torokhov 2561da177e4SLinus Torvalds dbg("%02x -> i8042 (command)", command & 0xff); 2571da177e4SLinus Torvalds i8042_write_command(command & 0xff); 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds for (i = 0; i < ((command >> 12) & 0xf); i++) { 260de9ce703SDmitry Torokhov error = i8042_wait_write(); 261de9ce703SDmitry Torokhov if (error) 262de9ce703SDmitry Torokhov return error; 2631da177e4SLinus Torvalds dbg("%02x -> i8042 (parameter)", param[i]); 2641da177e4SLinus Torvalds i8042_write_data(param[i]); 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds for (i = 0; i < ((command >> 8) & 0xf); i++) { 268de9ce703SDmitry Torokhov error = i8042_wait_read(); 269de9ce703SDmitry Torokhov if (error) { 270de9ce703SDmitry Torokhov dbg(" -- i8042 (timeout)"); 271de9ce703SDmitry Torokhov return error; 272de9ce703SDmitry Torokhov } 273463a4f76SDmitry Torokhov 274463a4f76SDmitry Torokhov if (command == I8042_CMD_AUX_LOOP && 275463a4f76SDmitry Torokhov !(i8042_read_status() & I8042_STR_AUXDATA)) { 276de9ce703SDmitry Torokhov dbg(" -- i8042 (auxerr)"); 277de9ce703SDmitry Torokhov return -1; 278463a4f76SDmitry Torokhov } 279463a4f76SDmitry Torokhov 2801da177e4SLinus Torvalds param[i] = i8042_read_data(); 2811da177e4SLinus Torvalds dbg("%02x <- i8042 (return)", param[i]); 2821da177e4SLinus Torvalds } 2831da177e4SLinus Torvalds 284de9ce703SDmitry Torokhov return 0; 285de9ce703SDmitry Torokhov } 2861da177e4SLinus Torvalds 287553a05b8SMárton Németh int i8042_command(unsigned char *param, int command) 288de9ce703SDmitry Torokhov { 289de9ce703SDmitry Torokhov unsigned long flags; 290de9ce703SDmitry Torokhov int retval; 291de9ce703SDmitry Torokhov 292de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 293de9ce703SDmitry Torokhov retval = __i8042_command(param, command); 294463a4f76SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 295de9ce703SDmitry Torokhov 2961da177e4SLinus Torvalds return retval; 2971da177e4SLinus Torvalds } 298553a05b8SMárton Németh EXPORT_SYMBOL(i8042_command); 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds /* 3011da177e4SLinus Torvalds * i8042_kbd_write() sends a byte out through the keyboard interface. 3021da177e4SLinus Torvalds */ 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds static int i8042_kbd_write(struct serio *port, unsigned char c) 3051da177e4SLinus Torvalds { 3061da177e4SLinus Torvalds unsigned long flags; 3071da177e4SLinus Torvalds int retval = 0; 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds if (!(retval = i8042_wait_write())) { 3121da177e4SLinus Torvalds dbg("%02x -> i8042 (kbd-data)", c); 3131da177e4SLinus Torvalds i8042_write_data(c); 3141da177e4SLinus Torvalds } 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds return retval; 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds /* 3221da177e4SLinus Torvalds * i8042_aux_write() sends a byte out through the aux interface. 3231da177e4SLinus Torvalds */ 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds static int i8042_aux_write(struct serio *serio, unsigned char c) 3261da177e4SLinus Torvalds { 3271da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 3281da177e4SLinus Torvalds 329f4e3c711SDmitry Torokhov return i8042_command(&c, port->mux == -1 ? 330f4e3c711SDmitry Torokhov I8042_CMD_AUX_SEND : 331f4e3c711SDmitry Torokhov I8042_CMD_MUX_SEND + port->mux); 3321da177e4SLinus Torvalds } 3331da177e4SLinus Torvalds 3345ddbc77cSDmitry Torokhov 3355ddbc77cSDmitry Torokhov /* 3365ddbc77cSDmitry Torokhov * i8042_aux_close attempts to clear AUX or KBD port state by disabling 3375ddbc77cSDmitry Torokhov * and then re-enabling it. 3385ddbc77cSDmitry Torokhov */ 3395ddbc77cSDmitry Torokhov 3405ddbc77cSDmitry Torokhov static void i8042_port_close(struct serio *serio) 3415ddbc77cSDmitry Torokhov { 3425ddbc77cSDmitry Torokhov int irq_bit; 3435ddbc77cSDmitry Torokhov int disable_bit; 3445ddbc77cSDmitry Torokhov const char *port_name; 3455ddbc77cSDmitry Torokhov 3465ddbc77cSDmitry Torokhov if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) { 3475ddbc77cSDmitry Torokhov irq_bit = I8042_CTR_AUXINT; 3485ddbc77cSDmitry Torokhov disable_bit = I8042_CTR_AUXDIS; 3495ddbc77cSDmitry Torokhov port_name = "AUX"; 3505ddbc77cSDmitry Torokhov } else { 3515ddbc77cSDmitry Torokhov irq_bit = I8042_CTR_KBDINT; 3525ddbc77cSDmitry Torokhov disable_bit = I8042_CTR_KBDDIS; 3535ddbc77cSDmitry Torokhov port_name = "KBD"; 3545ddbc77cSDmitry Torokhov } 3555ddbc77cSDmitry Torokhov 3565ddbc77cSDmitry Torokhov i8042_ctr &= ~irq_bit; 3575ddbc77cSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 3585ddbc77cSDmitry Torokhov printk(KERN_WARNING 3595ddbc77cSDmitry Torokhov "i8042.c: Can't write CTR while closing %s port.\n", 3605ddbc77cSDmitry Torokhov port_name); 3615ddbc77cSDmitry Torokhov 3625ddbc77cSDmitry Torokhov udelay(50); 3635ddbc77cSDmitry Torokhov 3645ddbc77cSDmitry Torokhov i8042_ctr &= ~disable_bit; 3655ddbc77cSDmitry Torokhov i8042_ctr |= irq_bit; 3665ddbc77cSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 3675ddbc77cSDmitry Torokhov printk(KERN_ERR "i8042.c: Can't reactivate %s port.\n", 3685ddbc77cSDmitry Torokhov port_name); 3695ddbc77cSDmitry Torokhov 3705ddbc77cSDmitry Torokhov /* 3715ddbc77cSDmitry Torokhov * See if there is any data appeared while we were messing with 3725ddbc77cSDmitry Torokhov * port state. 3735ddbc77cSDmitry Torokhov */ 3745ddbc77cSDmitry Torokhov i8042_interrupt(0, NULL); 3755ddbc77cSDmitry Torokhov } 3765ddbc77cSDmitry Torokhov 3771da177e4SLinus Torvalds /* 3781da177e4SLinus Torvalds * i8042_start() is called by serio core when port is about to finish 3791da177e4SLinus Torvalds * registering. It will mark port as existing so i8042_interrupt can 3801da177e4SLinus Torvalds * start sending data through it. 3811da177e4SLinus Torvalds */ 3821da177e4SLinus Torvalds static int i8042_start(struct serio *serio) 3831da177e4SLinus Torvalds { 3841da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 3851da177e4SLinus Torvalds 386386b3849SDmitry Torokhov port->exists = true; 3871da177e4SLinus Torvalds mb(); 3881da177e4SLinus Torvalds return 0; 3891da177e4SLinus Torvalds } 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds /* 3921da177e4SLinus Torvalds * i8042_stop() marks serio port as non-existing so i8042_interrupt 3931da177e4SLinus Torvalds * will not try to send data to the port that is about to go away. 3941da177e4SLinus Torvalds * The function is called by serio core as part of unregister procedure. 3951da177e4SLinus Torvalds */ 3961da177e4SLinus Torvalds static void i8042_stop(struct serio *serio) 3971da177e4SLinus Torvalds { 3981da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 3991da177e4SLinus Torvalds 400386b3849SDmitry Torokhov port->exists = false; 401a8399c51SDmitry Torokhov 402a8399c51SDmitry Torokhov /* 403a8399c51SDmitry Torokhov * We synchronize with both AUX and KBD IRQs because there is 404a8399c51SDmitry Torokhov * a (very unlikely) chance that AUX IRQ is raised for KBD port 405a8399c51SDmitry Torokhov * and vice versa. 406a8399c51SDmitry Torokhov */ 407a8399c51SDmitry Torokhov synchronize_irq(I8042_AUX_IRQ); 408a8399c51SDmitry Torokhov synchronize_irq(I8042_KBD_IRQ); 4091da177e4SLinus Torvalds port->serio = NULL; 4101da177e4SLinus Torvalds } 4111da177e4SLinus Torvalds 4121da177e4SLinus Torvalds /* 4134e8d340dSDmitry Torokhov * i8042_filter() filters out unwanted bytes from the input data stream. 4144e8d340dSDmitry Torokhov * It is called from i8042_interrupt and thus is running with interrupts 4154e8d340dSDmitry Torokhov * off and i8042_lock held. 4164e8d340dSDmitry Torokhov */ 417967c9ef9SMatthew Garrett static bool i8042_filter(unsigned char data, unsigned char str, 418967c9ef9SMatthew Garrett struct serio *serio) 4194e8d340dSDmitry Torokhov { 4204e8d340dSDmitry Torokhov if (unlikely(i8042_suppress_kbd_ack)) { 4214e8d340dSDmitry Torokhov if ((~str & I8042_STR_AUXDATA) && 4224e8d340dSDmitry Torokhov (data == 0xfa || data == 0xfe)) { 4234e8d340dSDmitry Torokhov i8042_suppress_kbd_ack--; 4244e8d340dSDmitry Torokhov dbg("Extra keyboard ACK - filtered out\n"); 4254e8d340dSDmitry Torokhov return true; 4264e8d340dSDmitry Torokhov } 4274e8d340dSDmitry Torokhov } 4284e8d340dSDmitry Torokhov 429967c9ef9SMatthew Garrett if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) { 4300747e3bcSStefan Weil dbg("Filtered out by platform filter\n"); 431967c9ef9SMatthew Garrett return true; 432967c9ef9SMatthew Garrett } 433967c9ef9SMatthew Garrett 4344e8d340dSDmitry Torokhov return false; 4354e8d340dSDmitry Torokhov } 4364e8d340dSDmitry Torokhov 4374e8d340dSDmitry Torokhov /* 4381da177e4SLinus Torvalds * i8042_interrupt() is the most important function in this driver - 4391da177e4SLinus Torvalds * it handles the interrupts from the i8042, and sends incoming bytes 4401da177e4SLinus Torvalds * to the upper layers. 4411da177e4SLinus Torvalds */ 4421da177e4SLinus Torvalds 4437d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id) 4441da177e4SLinus Torvalds { 4451da177e4SLinus Torvalds struct i8042_port *port; 446967c9ef9SMatthew Garrett struct serio *serio; 4471da177e4SLinus Torvalds unsigned long flags; 4481da177e4SLinus Torvalds unsigned char str, data; 4491da177e4SLinus Torvalds unsigned int dfl; 4501da177e4SLinus Torvalds unsigned int port_no; 4514e8d340dSDmitry Torokhov bool filtered; 452817e6ba3SDmitry Torokhov int ret = 1; 4531da177e4SLinus Torvalds 4541da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 4554e8d340dSDmitry Torokhov 4561da177e4SLinus Torvalds str = i8042_read_status(); 4571da177e4SLinus Torvalds if (unlikely(~str & I8042_STR_OBF)) { 4581da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 4591da177e4SLinus Torvalds if (irq) dbg("Interrupt %d, without any data", irq); 4601da177e4SLinus Torvalds ret = 0; 4611da177e4SLinus Torvalds goto out; 4621da177e4SLinus Torvalds } 4634e8d340dSDmitry Torokhov 4641da177e4SLinus Torvalds data = i8042_read_data(); 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { 4671da177e4SLinus Torvalds static unsigned long last_transmit; 4681da177e4SLinus Torvalds static unsigned char last_str; 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds dfl = 0; 4711da177e4SLinus Torvalds if (str & I8042_STR_MUXERR) { 4721da177e4SLinus Torvalds dbg("MUX error, status is %02x, data is %02x", str, data); 4731da177e4SLinus Torvalds /* 4741da177e4SLinus Torvalds * When MUXERR condition is signalled the data register can only contain 4751da177e4SLinus Torvalds * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately 476a216a4b6SDmitry Torokhov * it is not always the case. Some KBCs also report 0xfc when there is 477a216a4b6SDmitry Torokhov * nothing connected to the port while others sometimes get confused which 478a216a4b6SDmitry Torokhov * port the data came from and signal error leaving the data intact. They 479a216a4b6SDmitry Torokhov * _do not_ revert to legacy mode (actually I've never seen KBC reverting 480a216a4b6SDmitry Torokhov * to legacy mode yet, when we see one we'll add proper handling). 481a216a4b6SDmitry Torokhov * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the 482a216a4b6SDmitry Torokhov * rest assume that the data came from the same serio last byte 4831da177e4SLinus Torvalds * was transmitted (if transmission happened not too long ago). 4841da177e4SLinus Torvalds */ 485a216a4b6SDmitry Torokhov 486a216a4b6SDmitry Torokhov switch (data) { 487a216a4b6SDmitry Torokhov default: 4881da177e4SLinus Torvalds if (time_before(jiffies, last_transmit + HZ/10)) { 4891da177e4SLinus Torvalds str = last_str; 4901da177e4SLinus Torvalds break; 4911da177e4SLinus Torvalds } 4921da177e4SLinus Torvalds /* fall through - report timeout */ 493a216a4b6SDmitry Torokhov case 0xfc: 4941da177e4SLinus Torvalds case 0xfd: 4951da177e4SLinus Torvalds case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break; 4961da177e4SLinus Torvalds case 0xff: dfl = SERIO_PARITY; data = 0xfe; break; 4971da177e4SLinus Torvalds } 4981da177e4SLinus Torvalds } 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3); 5011da177e4SLinus Torvalds last_str = str; 5021da177e4SLinus Torvalds last_transmit = jiffies; 5031da177e4SLinus Torvalds } else { 5041da177e4SLinus Torvalds 5051da177e4SLinus Torvalds dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | 5061da177e4SLinus Torvalds ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds port_no = (str & I8042_STR_AUXDATA) ? 5091da177e4SLinus Torvalds I8042_AUX_PORT_NO : I8042_KBD_PORT_NO; 5101da177e4SLinus Torvalds } 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds port = &i8042_ports[port_no]; 513967c9ef9SMatthew Garrett serio = port->exists ? port->serio : NULL; 5141da177e4SLinus Torvalds 515de9ce703SDmitry Torokhov dbg("%02x <- i8042 (interrupt, %d, %d%s%s)", 516de9ce703SDmitry Torokhov data, port_no, irq, 5171da177e4SLinus Torvalds dfl & SERIO_PARITY ? ", bad parity" : "", 5181da177e4SLinus Torvalds dfl & SERIO_TIMEOUT ? ", timeout" : ""); 5191da177e4SLinus Torvalds 520967c9ef9SMatthew Garrett filtered = i8042_filter(data, str, serio); 521817e6ba3SDmitry Torokhov 5224e8d340dSDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 5234e8d340dSDmitry Torokhov 5244e8d340dSDmitry Torokhov if (likely(port->exists && !filtered)) 525967c9ef9SMatthew Garrett serio_interrupt(serio, data, dfl); 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds out: 5281da177e4SLinus Torvalds return IRQ_RETVAL(ret); 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds /* 5325ddbc77cSDmitry Torokhov * i8042_enable_kbd_port enables keyboard port on chip 533de9ce703SDmitry Torokhov */ 534de9ce703SDmitry Torokhov 535de9ce703SDmitry Torokhov static int i8042_enable_kbd_port(void) 536de9ce703SDmitry Torokhov { 537de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_KBDDIS; 538de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_KBDINT; 539de9ce703SDmitry Torokhov 540de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 541018db6bbSMarkus Armbruster i8042_ctr &= ~I8042_CTR_KBDINT; 542018db6bbSMarkus Armbruster i8042_ctr |= I8042_CTR_KBDDIS; 543de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n"); 544de9ce703SDmitry Torokhov return -EIO; 545de9ce703SDmitry Torokhov } 546de9ce703SDmitry Torokhov 547de9ce703SDmitry Torokhov return 0; 548de9ce703SDmitry Torokhov } 549de9ce703SDmitry Torokhov 550de9ce703SDmitry Torokhov /* 551de9ce703SDmitry Torokhov * i8042_enable_aux_port enables AUX (mouse) port on chip 552de9ce703SDmitry Torokhov */ 553de9ce703SDmitry Torokhov 554de9ce703SDmitry Torokhov static int i8042_enable_aux_port(void) 555de9ce703SDmitry Torokhov { 556de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_AUXDIS; 557de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXINT; 558de9ce703SDmitry Torokhov 559de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 560018db6bbSMarkus Armbruster i8042_ctr &= ~I8042_CTR_AUXINT; 561018db6bbSMarkus Armbruster i8042_ctr |= I8042_CTR_AUXDIS; 562de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n"); 563de9ce703SDmitry Torokhov return -EIO; 564de9ce703SDmitry Torokhov } 565de9ce703SDmitry Torokhov 566de9ce703SDmitry Torokhov return 0; 567de9ce703SDmitry Torokhov } 568de9ce703SDmitry Torokhov 569de9ce703SDmitry Torokhov /* 570de9ce703SDmitry Torokhov * i8042_enable_mux_ports enables 4 individual AUX ports after 571de9ce703SDmitry Torokhov * the controller has been switched into Multiplexed mode 572de9ce703SDmitry Torokhov */ 573de9ce703SDmitry Torokhov 574de9ce703SDmitry Torokhov static int i8042_enable_mux_ports(void) 575de9ce703SDmitry Torokhov { 576de9ce703SDmitry Torokhov unsigned char param; 577de9ce703SDmitry Torokhov int i; 578de9ce703SDmitry Torokhov 579de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { 580de9ce703SDmitry Torokhov i8042_command(¶m, I8042_CMD_MUX_PFX + i); 581de9ce703SDmitry Torokhov i8042_command(¶m, I8042_CMD_AUX_ENABLE); 582de9ce703SDmitry Torokhov } 583de9ce703SDmitry Torokhov 584de9ce703SDmitry Torokhov return i8042_enable_aux_port(); 585de9ce703SDmitry Torokhov } 586de9ce703SDmitry Torokhov 587de9ce703SDmitry Torokhov /* 588386b3849SDmitry Torokhov * i8042_set_mux_mode checks whether the controller has an 589386b3849SDmitry Torokhov * active multiplexor and puts the chip into Multiplexed (true) 590386b3849SDmitry Torokhov * or Legacy (false) mode. 5911da177e4SLinus Torvalds */ 5921da177e4SLinus Torvalds 593386b3849SDmitry Torokhov static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version) 5941da177e4SLinus Torvalds { 5951da177e4SLinus Torvalds 596386b3849SDmitry Torokhov unsigned char param, val; 5971da177e4SLinus Torvalds /* 5981da177e4SLinus Torvalds * Get rid of bytes in the queue. 5991da177e4SLinus Torvalds */ 6001da177e4SLinus Torvalds 6011da177e4SLinus Torvalds i8042_flush(); 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds /* 6041da177e4SLinus Torvalds * Internal loopback test - send three bytes, they should come back from the 605de9ce703SDmitry Torokhov * mouse interface, the last should be version. 6061da177e4SLinus Torvalds */ 6071da177e4SLinus Torvalds 608386b3849SDmitry Torokhov param = val = 0xf0; 609386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != val) 6101da177e4SLinus Torvalds return -1; 611386b3849SDmitry Torokhov param = val = multiplex ? 0x56 : 0xf6; 612386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != val) 6131da177e4SLinus Torvalds return -1; 614386b3849SDmitry Torokhov param = val = multiplex ? 0xa4 : 0xa5; 615386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == val) 616386b3849SDmitry Torokhov return -1; 617386b3849SDmitry Torokhov 618386b3849SDmitry Torokhov /* 619386b3849SDmitry Torokhov * Workaround for interference with USB Legacy emulation 620386b3849SDmitry Torokhov * that causes a v10.12 MUX to be found. 621386b3849SDmitry Torokhov */ 622386b3849SDmitry Torokhov if (param == 0xac) 6231da177e4SLinus Torvalds return -1; 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds if (mux_version) 626463a4f76SDmitry Torokhov *mux_version = param; 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds return 0; 6291da177e4SLinus Torvalds } 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds /* 6321da177e4SLinus Torvalds * i8042_check_mux() checks whether the controller supports the PS/2 Active 6331da177e4SLinus Torvalds * Multiplexing specification by Synaptics, Phoenix, Insyde and 6341da177e4SLinus Torvalds * LCS/Telegraphics. 6351da177e4SLinus Torvalds */ 6361da177e4SLinus Torvalds 637f8113416SDmitry Torokhov static int __init i8042_check_mux(void) 6381da177e4SLinus Torvalds { 6391da177e4SLinus Torvalds unsigned char mux_version; 6401da177e4SLinus Torvalds 641386b3849SDmitry Torokhov if (i8042_set_mux_mode(true, &mux_version)) 6421da177e4SLinus Torvalds return -1; 6431da177e4SLinus Torvalds 6441da177e4SLinus Torvalds printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", 6451da177e4SLinus Torvalds (mux_version >> 4) & 0xf, mux_version & 0xf); 6461da177e4SLinus Torvalds 647de9ce703SDmitry Torokhov /* 648de9ce703SDmitry Torokhov * Disable all muxed ports by disabling AUX. 649de9ce703SDmitry Torokhov */ 650de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXDIS; 651de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_AUXINT; 652de9ce703SDmitry Torokhov 653de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 654de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n"); 655de9ce703SDmitry Torokhov return -EIO; 656de9ce703SDmitry Torokhov } 6571da177e4SLinus Torvalds 658386b3849SDmitry Torokhov i8042_mux_present = true; 659de9ce703SDmitry Torokhov 6601da177e4SLinus Torvalds return 0; 6611da177e4SLinus Torvalds } 6621da177e4SLinus Torvalds 663de9ce703SDmitry Torokhov /* 664de9ce703SDmitry Torokhov * The following is used to test AUX IRQ delivery. 665de9ce703SDmitry Torokhov */ 666f8113416SDmitry Torokhov static struct completion i8042_aux_irq_delivered __initdata; 667f8113416SDmitry Torokhov static bool i8042_irq_being_tested __initdata; 668de9ce703SDmitry Torokhov 669f8113416SDmitry Torokhov static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id) 670de9ce703SDmitry Torokhov { 671de9ce703SDmitry Torokhov unsigned long flags; 672de9ce703SDmitry Torokhov unsigned char str, data; 673e3758b2aSFernando Luis Vázquez Cao int ret = 0; 674de9ce703SDmitry Torokhov 675de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 676de9ce703SDmitry Torokhov str = i8042_read_status(); 677de9ce703SDmitry Torokhov if (str & I8042_STR_OBF) { 678de9ce703SDmitry Torokhov data = i8042_read_data(); 679d3d2dfe2SDmitry Torokhov dbg("%02x <- i8042 (aux_test_irq, %s)", 680d3d2dfe2SDmitry Torokhov data, str & I8042_STR_AUXDATA ? "aux" : "kbd"); 681de9ce703SDmitry Torokhov if (i8042_irq_being_tested && 682de9ce703SDmitry Torokhov data == 0xa5 && (str & I8042_STR_AUXDATA)) 683de9ce703SDmitry Torokhov complete(&i8042_aux_irq_delivered); 684e3758b2aSFernando Luis Vázquez Cao ret = 1; 685de9ce703SDmitry Torokhov } 686de9ce703SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 687de9ce703SDmitry Torokhov 688e3758b2aSFernando Luis Vázquez Cao return IRQ_RETVAL(ret); 689de9ce703SDmitry Torokhov } 690de9ce703SDmitry Torokhov 691d2ada559SRoland Scheidegger /* 692d2ada559SRoland Scheidegger * i8042_toggle_aux - enables or disables AUX port on i8042 via command and 693d2ada559SRoland Scheidegger * verifies success by readinng CTR. Used when testing for presence of AUX 694d2ada559SRoland Scheidegger * port. 695d2ada559SRoland Scheidegger */ 696f8113416SDmitry Torokhov static int __init i8042_toggle_aux(bool on) 697d2ada559SRoland Scheidegger { 698d2ada559SRoland Scheidegger unsigned char param; 699d2ada559SRoland Scheidegger int i; 700d2ada559SRoland Scheidegger 701d2ada559SRoland Scheidegger if (i8042_command(¶m, 702d2ada559SRoland Scheidegger on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE)) 703d2ada559SRoland Scheidegger return -1; 704d2ada559SRoland Scheidegger 705d2ada559SRoland Scheidegger /* some chips need some time to set the I8042_CTR_AUXDIS bit */ 706d2ada559SRoland Scheidegger for (i = 0; i < 100; i++) { 707d2ada559SRoland Scheidegger udelay(50); 708d2ada559SRoland Scheidegger 709d2ada559SRoland Scheidegger if (i8042_command(¶m, I8042_CMD_CTL_RCTR)) 710d2ada559SRoland Scheidegger return -1; 711d2ada559SRoland Scheidegger 712d2ada559SRoland Scheidegger if (!(param & I8042_CTR_AUXDIS) == on) 713d2ada559SRoland Scheidegger return 0; 714d2ada559SRoland Scheidegger } 715d2ada559SRoland Scheidegger 716d2ada559SRoland Scheidegger return -1; 717d2ada559SRoland Scheidegger } 7181da177e4SLinus Torvalds 7191da177e4SLinus Torvalds /* 7201da177e4SLinus Torvalds * i8042_check_aux() applies as much paranoia as it can at detecting 7211da177e4SLinus Torvalds * the presence of an AUX interface. 7221da177e4SLinus Torvalds */ 7231da177e4SLinus Torvalds 724f8113416SDmitry Torokhov static int __init i8042_check_aux(void) 7251da177e4SLinus Torvalds { 726de9ce703SDmitry Torokhov int retval = -1; 727386b3849SDmitry Torokhov bool irq_registered = false; 728386b3849SDmitry Torokhov bool aux_loop_broken = false; 729de9ce703SDmitry Torokhov unsigned long flags; 7301da177e4SLinus Torvalds unsigned char param; 7311da177e4SLinus Torvalds 7321da177e4SLinus Torvalds /* 7331da177e4SLinus Torvalds * Get rid of bytes in the queue. 7341da177e4SLinus Torvalds */ 7351da177e4SLinus Torvalds 7361da177e4SLinus Torvalds i8042_flush(); 7371da177e4SLinus Torvalds 7381da177e4SLinus Torvalds /* 7391da177e4SLinus Torvalds * Internal loopback test - filters out AT-type i8042's. Unfortunately 7401da177e4SLinus Torvalds * SiS screwed up and their 5597 doesn't support the LOOP command even 7411da177e4SLinus Torvalds * though it has an AUX port. 7421da177e4SLinus Torvalds */ 7431da177e4SLinus Torvalds 7441da177e4SLinus Torvalds param = 0x5a; 7453ca5de6dSDmitry Torokhov retval = i8042_command(¶m, I8042_CMD_AUX_LOOP); 7463ca5de6dSDmitry Torokhov if (retval || param != 0x5a) { 7471da177e4SLinus Torvalds 7481da177e4SLinus Torvalds /* 7491da177e4SLinus Torvalds * External connection test - filters out AT-soldered PS/2 i8042's 7501da177e4SLinus Torvalds * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error 7511da177e4SLinus Torvalds * 0xfa - no error on some notebooks which ignore the spec 7521da177e4SLinus Torvalds * Because it's common for chipsets to return error on perfectly functioning 7531da177e4SLinus Torvalds * AUX ports, we test for this only when the LOOP command failed. 7541da177e4SLinus Torvalds */ 7551da177e4SLinus Torvalds 756de9ce703SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_TEST) || 757de9ce703SDmitry Torokhov (param && param != 0xfa && param != 0xff)) 7581da177e4SLinus Torvalds return -1; 7591e4865f8SDmitry Torokhov 7603ca5de6dSDmitry Torokhov /* 7613ca5de6dSDmitry Torokhov * If AUX_LOOP completed without error but returned unexpected data 7623ca5de6dSDmitry Torokhov * mark it as broken 7633ca5de6dSDmitry Torokhov */ 7643ca5de6dSDmitry Torokhov if (!retval) 765386b3849SDmitry Torokhov aux_loop_broken = true; 7661da177e4SLinus Torvalds } 7671da177e4SLinus Torvalds 7681da177e4SLinus Torvalds /* 7691da177e4SLinus Torvalds * Bit assignment test - filters out PS/2 i8042's in AT mode 7701da177e4SLinus Torvalds */ 7711da177e4SLinus Torvalds 772386b3849SDmitry Torokhov if (i8042_toggle_aux(false)) { 7731da177e4SLinus Torvalds printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n"); 7741da177e4SLinus Torvalds printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n"); 7751da177e4SLinus Torvalds } 7761da177e4SLinus Torvalds 777386b3849SDmitry Torokhov if (i8042_toggle_aux(true)) 7781da177e4SLinus Torvalds return -1; 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds /* 781de9ce703SDmitry Torokhov * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and 782de9ce703SDmitry Torokhov * used it for a PCI card or somethig else. 783de9ce703SDmitry Torokhov */ 784de9ce703SDmitry Torokhov 7851c7827aeSDmitry Torokhov if (i8042_noloop || i8042_bypass_aux_irq_test || aux_loop_broken) { 786de9ce703SDmitry Torokhov /* 787de9ce703SDmitry Torokhov * Without LOOP command we can't test AUX IRQ delivery. Assume the port 788de9ce703SDmitry Torokhov * is working and hope we are right. 789de9ce703SDmitry Torokhov */ 790de9ce703SDmitry Torokhov retval = 0; 791de9ce703SDmitry Torokhov goto out; 792de9ce703SDmitry Torokhov } 793de9ce703SDmitry Torokhov 794de9ce703SDmitry Torokhov if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED, 795de9ce703SDmitry Torokhov "i8042", i8042_platform_device)) 796de9ce703SDmitry Torokhov goto out; 797de9ce703SDmitry Torokhov 798386b3849SDmitry Torokhov irq_registered = true; 799de9ce703SDmitry Torokhov 800de9ce703SDmitry Torokhov if (i8042_enable_aux_port()) 801de9ce703SDmitry Torokhov goto out; 802de9ce703SDmitry Torokhov 803de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 804de9ce703SDmitry Torokhov 805de9ce703SDmitry Torokhov init_completion(&i8042_aux_irq_delivered); 806386b3849SDmitry Torokhov i8042_irq_being_tested = true; 807de9ce703SDmitry Torokhov 808de9ce703SDmitry Torokhov param = 0xa5; 809de9ce703SDmitry Torokhov retval = __i8042_command(¶m, I8042_CMD_AUX_LOOP & 0xf0ff); 810de9ce703SDmitry Torokhov 811de9ce703SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 812de9ce703SDmitry Torokhov 813de9ce703SDmitry Torokhov if (retval) 814de9ce703SDmitry Torokhov goto out; 815de9ce703SDmitry Torokhov 816de9ce703SDmitry Torokhov if (wait_for_completion_timeout(&i8042_aux_irq_delivered, 817de9ce703SDmitry Torokhov msecs_to_jiffies(250)) == 0) { 818de9ce703SDmitry Torokhov /* 819de9ce703SDmitry Torokhov * AUX IRQ was never delivered so we need to flush the controller to 820de9ce703SDmitry Torokhov * get rid of the byte we put there; otherwise keyboard may not work. 821de9ce703SDmitry Torokhov */ 822d3d2dfe2SDmitry Torokhov dbg(" -- i8042 (aux irq test timeout)"); 823de9ce703SDmitry Torokhov i8042_flush(); 824de9ce703SDmitry Torokhov retval = -1; 825de9ce703SDmitry Torokhov } 826de9ce703SDmitry Torokhov 827de9ce703SDmitry Torokhov out: 828de9ce703SDmitry Torokhov 829de9ce703SDmitry Torokhov /* 8301da177e4SLinus Torvalds * Disable the interface. 8311da177e4SLinus Torvalds */ 8321da177e4SLinus Torvalds 8331da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_AUXDIS; 8341da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_AUXINT; 8351da177e4SLinus Torvalds 8361da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 837de9ce703SDmitry Torokhov retval = -1; 838de9ce703SDmitry Torokhov 839de9ce703SDmitry Torokhov if (irq_registered) 840de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 841de9ce703SDmitry Torokhov 842de9ce703SDmitry Torokhov return retval; 843de9ce703SDmitry Torokhov } 844de9ce703SDmitry Torokhov 845de9ce703SDmitry Torokhov static int i8042_controller_check(void) 846de9ce703SDmitry Torokhov { 847de9ce703SDmitry Torokhov if (i8042_flush() == I8042_BUFFER_SIZE) { 848de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: No controller found.\n"); 849de9ce703SDmitry Torokhov return -ENODEV; 850de9ce703SDmitry Torokhov } 8511da177e4SLinus Torvalds 8521da177e4SLinus Torvalds return 0; 8531da177e4SLinus Torvalds } 8541da177e4SLinus Torvalds 855de9ce703SDmitry Torokhov static int i8042_controller_selftest(void) 8562673c836SVojtech Pavlik { 8572673c836SVojtech Pavlik unsigned char param; 8585ea2fc64SArjan van de Ven int i = 0; 8592673c836SVojtech Pavlik 8605ea2fc64SArjan van de Ven /* 8615ea2fc64SArjan van de Ven * We try this 5 times; on some really fragile systems this does not 8625ea2fc64SArjan van de Ven * take the first time... 8635ea2fc64SArjan van de Ven */ 8645ea2fc64SArjan van de Ven do { 8655ea2fc64SArjan van de Ven 8662673c836SVojtech Pavlik if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { 8672673c836SVojtech Pavlik printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); 868de9ce703SDmitry Torokhov return -ENODEV; 8692673c836SVojtech Pavlik } 8702673c836SVojtech Pavlik 8715ea2fc64SArjan van de Ven if (param == I8042_RET_CTL_TEST) 8725ea2fc64SArjan van de Ven return 0; 8735ea2fc64SArjan van de Ven 8742673c836SVojtech Pavlik printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", 8752673c836SVojtech Pavlik param, I8042_RET_CTL_TEST); 8765ea2fc64SArjan van de Ven msleep(50); 8775ea2fc64SArjan van de Ven } while (i++ < 5); 8782673c836SVojtech Pavlik 8795ea2fc64SArjan van de Ven #ifdef CONFIG_X86 8805ea2fc64SArjan van de Ven /* 8815ea2fc64SArjan van de Ven * On x86, we don't fail entire i8042 initialization if controller 8825ea2fc64SArjan van de Ven * reset fails in hopes that keyboard port will still be functional 8835ea2fc64SArjan van de Ven * and user will still get a working keyboard. This is especially 8845ea2fc64SArjan van de Ven * important on netbooks. On other arches we trust hardware more. 8855ea2fc64SArjan van de Ven */ 8865ea2fc64SArjan van de Ven printk(KERN_INFO 8875ea2fc64SArjan van de Ven "i8042: giving up on controller selftest, continuing anyway...\n"); 8882673c836SVojtech Pavlik return 0; 8895ea2fc64SArjan van de Ven #else 8905ea2fc64SArjan van de Ven return -EIO; 8915ea2fc64SArjan van de Ven #endif 8922673c836SVojtech Pavlik } 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds /* 8951da177e4SLinus Torvalds * i8042_controller init initializes the i8042 controller, and, 8961da177e4SLinus Torvalds * most importantly, sets it into non-xlated mode if that's 8971da177e4SLinus Torvalds * desired. 8981da177e4SLinus Torvalds */ 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds static int i8042_controller_init(void) 9011da177e4SLinus Torvalds { 9021da177e4SLinus Torvalds unsigned long flags; 903ee1e82ceSDmitry Torokhov int n = 0; 904ee1e82ceSDmitry Torokhov unsigned char ctr[2]; 9051da177e4SLinus Torvalds 9061da177e4SLinus Torvalds /* 907ee1e82ceSDmitry Torokhov * Save the CTR for restore on unload / reboot. 9081da177e4SLinus Torvalds */ 9091da177e4SLinus Torvalds 910ee1e82ceSDmitry Torokhov do { 911ee1e82ceSDmitry Torokhov if (n >= 10) { 912ee1e82ceSDmitry Torokhov printk(KERN_ERR 913ee1e82ceSDmitry Torokhov "i8042.c: Unable to get stable CTR read.\n"); 914de9ce703SDmitry Torokhov return -EIO; 9151da177e4SLinus Torvalds } 9161da177e4SLinus Torvalds 917ee1e82ceSDmitry Torokhov if (n != 0) 918ee1e82ceSDmitry Torokhov udelay(50); 919ee1e82ceSDmitry Torokhov 920ee1e82ceSDmitry Torokhov if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) { 921ee1e82ceSDmitry Torokhov printk(KERN_ERR 922ee1e82ceSDmitry Torokhov "i8042.c: Can't read CTR while initializing i8042.\n"); 923ee1e82ceSDmitry Torokhov return -EIO; 924ee1e82ceSDmitry Torokhov } 925ee1e82ceSDmitry Torokhov 926ee1e82ceSDmitry Torokhov } while (n < 2 || ctr[0] != ctr[1]); 927ee1e82ceSDmitry Torokhov 928ee1e82ceSDmitry Torokhov i8042_initial_ctr = i8042_ctr = ctr[0]; 9291da177e4SLinus Torvalds 9301da177e4SLinus Torvalds /* 9311da177e4SLinus Torvalds * Disable the keyboard interface and interrupt. 9321da177e4SLinus Torvalds */ 9331da177e4SLinus Torvalds 9341da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_KBDDIS; 9351da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_KBDINT; 9361da177e4SLinus Torvalds 9371da177e4SLinus Torvalds /* 9381da177e4SLinus Torvalds * Handle keylock. 9391da177e4SLinus Torvalds */ 9401da177e4SLinus Torvalds 9411da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 9421da177e4SLinus Torvalds if (~i8042_read_status() & I8042_STR_KEYLOCK) { 9431da177e4SLinus Torvalds if (i8042_unlock) 9441da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_IGNKEYLOCK; 9451da177e4SLinus Torvalds else 9461da177e4SLinus Torvalds printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); 9471da177e4SLinus Torvalds } 9481da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 9491da177e4SLinus Torvalds 9501da177e4SLinus Torvalds /* 9511da177e4SLinus Torvalds * If the chip is configured into nontranslated mode by the BIOS, don't 9521da177e4SLinus Torvalds * bother enabling translating and be happy. 9531da177e4SLinus Torvalds */ 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds if (~i8042_ctr & I8042_CTR_XLATE) 956386b3849SDmitry Torokhov i8042_direct = true; 9571da177e4SLinus Torvalds 9581da177e4SLinus Torvalds /* 9591da177e4SLinus Torvalds * Set nontranslated mode for the kbd interface if requested by an option. 9601da177e4SLinus Torvalds * After this the kbd interface becomes a simple serial in/out, like the aux 9611da177e4SLinus Torvalds * interface is. We don't do this by default, since it can confuse notebook 9621da177e4SLinus Torvalds * BIOSes. 9631da177e4SLinus Torvalds */ 9641da177e4SLinus Torvalds 9651da177e4SLinus Torvalds if (i8042_direct) 9661da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_XLATE; 9671da177e4SLinus Torvalds 9681da177e4SLinus Torvalds /* 9691da177e4SLinus Torvalds * Write CTR back. 9701da177e4SLinus Torvalds */ 9711da177e4SLinus Torvalds 9721da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 9731da177e4SLinus Torvalds printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); 974de9ce703SDmitry Torokhov return -EIO; 9751da177e4SLinus Torvalds } 9761da177e4SLinus Torvalds 977ee1e82ceSDmitry Torokhov /* 978ee1e82ceSDmitry Torokhov * Flush whatever accumulated while we were disabling keyboard port. 979ee1e82ceSDmitry Torokhov */ 980ee1e82ceSDmitry Torokhov 981ee1e82ceSDmitry Torokhov i8042_flush(); 982ee1e82ceSDmitry Torokhov 9831da177e4SLinus Torvalds return 0; 9841da177e4SLinus Torvalds } 9851da177e4SLinus Torvalds 9861da177e4SLinus Torvalds 9871da177e4SLinus Torvalds /* 988de9ce703SDmitry Torokhov * Reset the controller and reset CRT to the original value set by BIOS. 9891da177e4SLinus Torvalds */ 9901da177e4SLinus Torvalds 991de9ce703SDmitry Torokhov static void i8042_controller_reset(void) 992de9ce703SDmitry Torokhov { 993de9ce703SDmitry Torokhov i8042_flush(); 9941da177e4SLinus Torvalds 9951da177e4SLinus Torvalds /* 9968d04ddb6SDmitry Torokhov * Disable both KBD and AUX interfaces so they don't get in the way 9978d04ddb6SDmitry Torokhov */ 9988d04ddb6SDmitry Torokhov 9998d04ddb6SDmitry Torokhov i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS; 10008d04ddb6SDmitry Torokhov i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT); 10018d04ddb6SDmitry Torokhov 1002ee1e82ceSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 10035ddbc77cSDmitry Torokhov printk(KERN_WARNING "i8042.c: Can't write CTR while resetting.\n"); 10045ddbc77cSDmitry Torokhov 10058d04ddb6SDmitry Torokhov /* 10061da177e4SLinus Torvalds * Disable MUX mode if present. 10071da177e4SLinus Torvalds */ 10081da177e4SLinus Torvalds 10091da177e4SLinus Torvalds if (i8042_mux_present) 1010386b3849SDmitry Torokhov i8042_set_mux_mode(false, NULL); 10111da177e4SLinus Torvalds 10121da177e4SLinus Torvalds /* 1013de9ce703SDmitry Torokhov * Reset the controller if requested. 1014de9ce703SDmitry Torokhov */ 1015de9ce703SDmitry Torokhov 10161ca56e51SDmitry Torokhov if (i8042_reset) 1017de9ce703SDmitry Torokhov i8042_controller_selftest(); 1018de9ce703SDmitry Torokhov 1019de9ce703SDmitry Torokhov /* 10201da177e4SLinus Torvalds * Restore the original control register setting. 10211da177e4SLinus Torvalds */ 10221da177e4SLinus Torvalds 1023de9ce703SDmitry Torokhov if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR)) 10241da177e4SLinus Torvalds printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); 10251da177e4SLinus Torvalds } 10261da177e4SLinus Torvalds 10271da177e4SLinus Torvalds 10281da177e4SLinus Torvalds /* 1029c7ff0d9cSTAMUKI Shoichi * i8042_panic_blink() will turn the keyboard LEDs on or off and is called 1030c7ff0d9cSTAMUKI Shoichi * when kernel panics. Flashing LEDs is useful for users running X who may 10311da177e4SLinus Torvalds * not see the console and will help distingushing panics from "real" 10321da177e4SLinus Torvalds * lockups. 10331da177e4SLinus Torvalds * 10341da177e4SLinus Torvalds * Note that DELAY has a limit of 10ms so we will not get stuck here 10351da177e4SLinus Torvalds * waiting for KBC to free up even if KBD interrupt is off 10361da177e4SLinus Torvalds */ 10371da177e4SLinus Torvalds 10381da177e4SLinus Torvalds #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0) 10391da177e4SLinus Torvalds 1040c7ff0d9cSTAMUKI Shoichi static long i8042_panic_blink(int state) 10411da177e4SLinus Torvalds { 10421da177e4SLinus Torvalds long delay = 0; 1043c7ff0d9cSTAMUKI Shoichi char led; 10441da177e4SLinus Torvalds 1045c7ff0d9cSTAMUKI Shoichi led = (state) ? 0x01 | 0x04 : 0; 10461da177e4SLinus Torvalds while (i8042_read_status() & I8042_STR_IBF) 10471da177e4SLinus Torvalds DELAY; 104819f3c3e3SDmitry Torokhov dbg("%02x -> i8042 (panic blink)", 0xed); 104919f3c3e3SDmitry Torokhov i8042_suppress_kbd_ack = 2; 10501da177e4SLinus Torvalds i8042_write_data(0xed); /* set leds */ 10511da177e4SLinus Torvalds DELAY; 10521da177e4SLinus Torvalds while (i8042_read_status() & I8042_STR_IBF) 10531da177e4SLinus Torvalds DELAY; 10541da177e4SLinus Torvalds DELAY; 105519f3c3e3SDmitry Torokhov dbg("%02x -> i8042 (panic blink)", led); 10561da177e4SLinus Torvalds i8042_write_data(led); 10571da177e4SLinus Torvalds DELAY; 10581da177e4SLinus Torvalds return delay; 10591da177e4SLinus Torvalds } 10601da177e4SLinus Torvalds 10611da177e4SLinus Torvalds #undef DELAY 10621da177e4SLinus Torvalds 1063d35895dbSBruno Prémont #ifdef CONFIG_X86 1064d35895dbSBruno Prémont static void i8042_dritek_enable(void) 1065d35895dbSBruno Prémont { 1066d35895dbSBruno Prémont char param = 0x90; 1067d35895dbSBruno Prémont int error; 1068d35895dbSBruno Prémont 1069d35895dbSBruno Prémont error = i8042_command(¶m, 0x1059); 1070d35895dbSBruno Prémont if (error) 1071d35895dbSBruno Prémont printk(KERN_WARNING 1072d35895dbSBruno Prémont "Failed to enable DRITEK extension: %d\n", 1073d35895dbSBruno Prémont error); 1074d35895dbSBruno Prémont } 1075d35895dbSBruno Prémont #endif 1076d35895dbSBruno Prémont 107782dd9effSDmitry Torokhov #ifdef CONFIG_PM 10787e044e05SDmitry Torokhov 10791da177e4SLinus Torvalds /* 1080ebd7768dSDmitry Torokhov * Here we try to reset everything back to a state we had 1081ebd7768dSDmitry Torokhov * before suspending. 10821da177e4SLinus Torvalds */ 10831da177e4SLinus Torvalds 10841ca56e51SDmitry Torokhov static int i8042_controller_resume(bool force_reset) 10851da177e4SLinus Torvalds { 1086de9ce703SDmitry Torokhov int error; 10871da177e4SLinus Torvalds 1088de9ce703SDmitry Torokhov error = i8042_controller_check(); 1089de9ce703SDmitry Torokhov if (error) 1090de9ce703SDmitry Torokhov return error; 10912673c836SVojtech Pavlik 10921ca56e51SDmitry Torokhov if (i8042_reset || force_reset) { 1093de9ce703SDmitry Torokhov error = i8042_controller_selftest(); 1094de9ce703SDmitry Torokhov if (error) 1095de9ce703SDmitry Torokhov return error; 10961ca56e51SDmitry Torokhov } 1097de9ce703SDmitry Torokhov 1098de9ce703SDmitry Torokhov /* 109982dd9effSDmitry Torokhov * Restore original CTR value and disable all ports 1100de9ce703SDmitry Torokhov */ 1101de9ce703SDmitry Torokhov 110282dd9effSDmitry Torokhov i8042_ctr = i8042_initial_ctr; 110382dd9effSDmitry Torokhov if (i8042_direct) 110482dd9effSDmitry Torokhov i8042_ctr &= ~I8042_CTR_XLATE; 1105de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS; 1106de9ce703SDmitry Torokhov i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT); 11072673c836SVojtech Pavlik if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 11082f6a77d5SJiri Kosina printk(KERN_WARNING "i8042: Can't write CTR to resume, retrying...\n"); 11092f6a77d5SJiri Kosina msleep(50); 11102f6a77d5SJiri Kosina if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 11112f6a77d5SJiri Kosina printk(KERN_ERR "i8042: CTR write retry failed\n"); 1112de9ce703SDmitry Torokhov return -EIO; 11131da177e4SLinus Torvalds } 11142f6a77d5SJiri Kosina } 11151da177e4SLinus Torvalds 1116d35895dbSBruno Prémont 1117d35895dbSBruno Prémont #ifdef CONFIG_X86 1118d35895dbSBruno Prémont if (i8042_dritek) 1119d35895dbSBruno Prémont i8042_dritek_enable(); 1120d35895dbSBruno Prémont #endif 1121d35895dbSBruno Prémont 1122de9ce703SDmitry Torokhov if (i8042_mux_present) { 1123386b3849SDmitry Torokhov if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports()) 1124de9ce703SDmitry Torokhov printk(KERN_WARNING 1125de9ce703SDmitry Torokhov "i8042: failed to resume active multiplexor, " 1126de9ce703SDmitry Torokhov "mouse won't work.\n"); 1127de9ce703SDmitry Torokhov } else if (i8042_ports[I8042_AUX_PORT_NO].serio) 1128de9ce703SDmitry Torokhov i8042_enable_aux_port(); 11291da177e4SLinus Torvalds 1130de9ce703SDmitry Torokhov if (i8042_ports[I8042_KBD_PORT_NO].serio) 1131de9ce703SDmitry Torokhov i8042_enable_kbd_port(); 11321da177e4SLinus Torvalds 11337d12e780SDavid Howells i8042_interrupt(0, NULL); 11341da177e4SLinus Torvalds 11351da177e4SLinus Torvalds return 0; 11361da177e4SLinus Torvalds } 1137ebd7768dSDmitry Torokhov 11381ca56e51SDmitry Torokhov /* 11391ca56e51SDmitry Torokhov * Here we try to restore the original BIOS settings to avoid 11401ca56e51SDmitry Torokhov * upsetting it. 11411ca56e51SDmitry Torokhov */ 11421ca56e51SDmitry Torokhov 11431ca56e51SDmitry Torokhov static int i8042_pm_reset(struct device *dev) 11441ca56e51SDmitry Torokhov { 11451ca56e51SDmitry Torokhov i8042_controller_reset(); 11461ca56e51SDmitry Torokhov 11471ca56e51SDmitry Torokhov return 0; 11481ca56e51SDmitry Torokhov } 11491ca56e51SDmitry Torokhov 11501ca56e51SDmitry Torokhov static int i8042_pm_resume(struct device *dev) 11511ca56e51SDmitry Torokhov { 11521ca56e51SDmitry Torokhov /* 11531ca56e51SDmitry Torokhov * On resume from S2R we always try to reset the controller 11541ca56e51SDmitry Torokhov * to bring it in a sane state. (In case of S2D we expect 11551ca56e51SDmitry Torokhov * BIOS to reset the controller for us.) 11561ca56e51SDmitry Torokhov */ 11571ca56e51SDmitry Torokhov return i8042_controller_resume(true); 11581ca56e51SDmitry Torokhov } 11591ca56e51SDmitry Torokhov 1160c2d1a2a1SAlan Jenkins static int i8042_pm_thaw(struct device *dev) 1161c2d1a2a1SAlan Jenkins { 1162c2d1a2a1SAlan Jenkins i8042_interrupt(0, NULL); 1163c2d1a2a1SAlan Jenkins 1164c2d1a2a1SAlan Jenkins return 0; 1165c2d1a2a1SAlan Jenkins } 1166c2d1a2a1SAlan Jenkins 11671ca56e51SDmitry Torokhov static int i8042_pm_restore(struct device *dev) 11681ca56e51SDmitry Torokhov { 11691ca56e51SDmitry Torokhov return i8042_controller_resume(false); 11701ca56e51SDmitry Torokhov } 11711ca56e51SDmitry Torokhov 1172ebd7768dSDmitry Torokhov static const struct dev_pm_ops i8042_pm_ops = { 1173ebd7768dSDmitry Torokhov .suspend = i8042_pm_reset, 11741ca56e51SDmitry Torokhov .resume = i8042_pm_resume, 1175c2d1a2a1SAlan Jenkins .thaw = i8042_pm_thaw, 1176ebd7768dSDmitry Torokhov .poweroff = i8042_pm_reset, 1177ebd7768dSDmitry Torokhov .restore = i8042_pm_restore, 1178ebd7768dSDmitry Torokhov }; 1179ebd7768dSDmitry Torokhov 118082dd9effSDmitry Torokhov #endif /* CONFIG_PM */ 11811da177e4SLinus Torvalds 11821da177e4SLinus Torvalds /* 11831da177e4SLinus Torvalds * We need to reset the 8042 back to original mode on system shutdown, 11841da177e4SLinus Torvalds * because otherwise BIOSes will be confused. 11851da177e4SLinus Torvalds */ 11861da177e4SLinus Torvalds 11873ae5eaecSRussell King static void i8042_shutdown(struct platform_device *dev) 11881da177e4SLinus Torvalds { 118982dd9effSDmitry Torokhov i8042_controller_reset(); 11901da177e4SLinus Torvalds } 11911da177e4SLinus Torvalds 1192f8113416SDmitry Torokhov static int __init i8042_create_kbd_port(void) 11931da177e4SLinus Torvalds { 11941da177e4SLinus Torvalds struct serio *serio; 11951da177e4SLinus Torvalds struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; 11961da177e4SLinus Torvalds 1197d39969deSDmitry Torokhov serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 11980854e52dSDmitry Torokhov if (!serio) 11990854e52dSDmitry Torokhov return -ENOMEM; 12000854e52dSDmitry Torokhov 12011da177e4SLinus Torvalds serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; 12021da177e4SLinus Torvalds serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; 12031da177e4SLinus Torvalds serio->start = i8042_start; 12041da177e4SLinus Torvalds serio->stop = i8042_stop; 12055ddbc77cSDmitry Torokhov serio->close = i8042_port_close; 12061da177e4SLinus Torvalds serio->port_data = port; 12071da177e4SLinus Torvalds serio->dev.parent = &i8042_platform_device->dev; 1208de9ce703SDmitry Torokhov strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); 12091da177e4SLinus Torvalds strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); 12101da177e4SLinus Torvalds 12111da177e4SLinus Torvalds port->serio = serio; 1212de9ce703SDmitry Torokhov port->irq = I8042_KBD_IRQ; 12130854e52dSDmitry Torokhov 1214de9ce703SDmitry Torokhov return 0; 12151da177e4SLinus Torvalds } 12161da177e4SLinus Torvalds 1217f8113416SDmitry Torokhov static int __init i8042_create_aux_port(int idx) 12181da177e4SLinus Torvalds { 12191da177e4SLinus Torvalds struct serio *serio; 1220de9ce703SDmitry Torokhov int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx; 1221de9ce703SDmitry Torokhov struct i8042_port *port = &i8042_ports[port_no]; 12221da177e4SLinus Torvalds 1223d39969deSDmitry Torokhov serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 12240854e52dSDmitry Torokhov if (!serio) 12250854e52dSDmitry Torokhov return -ENOMEM; 12260854e52dSDmitry Torokhov 12271da177e4SLinus Torvalds serio->id.type = SERIO_8042; 12281da177e4SLinus Torvalds serio->write = i8042_aux_write; 12291da177e4SLinus Torvalds serio->start = i8042_start; 12301da177e4SLinus Torvalds serio->stop = i8042_stop; 12311da177e4SLinus Torvalds serio->port_data = port; 12321da177e4SLinus Torvalds serio->dev.parent = &i8042_platform_device->dev; 1233de9ce703SDmitry Torokhov if (idx < 0) { 1234de9ce703SDmitry Torokhov strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name)); 12351da177e4SLinus Torvalds strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); 12365ddbc77cSDmitry Torokhov serio->close = i8042_port_close; 1237de9ce703SDmitry Torokhov } else { 1238de9ce703SDmitry Torokhov snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx); 1239de9ce703SDmitry Torokhov snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1); 12401da177e4SLinus Torvalds } 12411da177e4SLinus Torvalds 12421da177e4SLinus Torvalds port->serio = serio; 1243de9ce703SDmitry Torokhov port->mux = idx; 1244de9ce703SDmitry Torokhov port->irq = I8042_AUX_IRQ; 12450854e52dSDmitry Torokhov 1246de9ce703SDmitry Torokhov return 0; 1247de9ce703SDmitry Torokhov } 1248de9ce703SDmitry Torokhov 1249f8113416SDmitry Torokhov static void __init i8042_free_kbd_port(void) 1250de9ce703SDmitry Torokhov { 1251de9ce703SDmitry Torokhov kfree(i8042_ports[I8042_KBD_PORT_NO].serio); 1252de9ce703SDmitry Torokhov i8042_ports[I8042_KBD_PORT_NO].serio = NULL; 1253de9ce703SDmitry Torokhov } 1254de9ce703SDmitry Torokhov 1255f8113416SDmitry Torokhov static void __init i8042_free_aux_ports(void) 1256de9ce703SDmitry Torokhov { 1257de9ce703SDmitry Torokhov int i; 1258de9ce703SDmitry Torokhov 1259de9ce703SDmitry Torokhov for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) { 1260de9ce703SDmitry Torokhov kfree(i8042_ports[i].serio); 1261de9ce703SDmitry Torokhov i8042_ports[i].serio = NULL; 1262de9ce703SDmitry Torokhov } 1263de9ce703SDmitry Torokhov } 1264de9ce703SDmitry Torokhov 1265f8113416SDmitry Torokhov static void __init i8042_register_ports(void) 1266de9ce703SDmitry Torokhov { 1267de9ce703SDmitry Torokhov int i; 1268de9ce703SDmitry Torokhov 1269de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) { 1270de9ce703SDmitry Torokhov if (i8042_ports[i].serio) { 1271de9ce703SDmitry Torokhov printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n", 1272de9ce703SDmitry Torokhov i8042_ports[i].serio->name, 1273de9ce703SDmitry Torokhov (unsigned long) I8042_DATA_REG, 1274de9ce703SDmitry Torokhov (unsigned long) I8042_COMMAND_REG, 1275de9ce703SDmitry Torokhov i8042_ports[i].irq); 1276de9ce703SDmitry Torokhov serio_register_port(i8042_ports[i].serio); 1277de9ce703SDmitry Torokhov } 1278de9ce703SDmitry Torokhov } 1279de9ce703SDmitry Torokhov } 1280de9ce703SDmitry Torokhov 12817a1904c3SRalf Baechle static void __devexit i8042_unregister_ports(void) 1282de9ce703SDmitry Torokhov { 1283de9ce703SDmitry Torokhov int i; 1284de9ce703SDmitry Torokhov 1285de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) { 1286de9ce703SDmitry Torokhov if (i8042_ports[i].serio) { 1287de9ce703SDmitry Torokhov serio_unregister_port(i8042_ports[i].serio); 1288de9ce703SDmitry Torokhov i8042_ports[i].serio = NULL; 1289de9ce703SDmitry Torokhov } 1290de9ce703SDmitry Torokhov } 1291de9ce703SDmitry Torokhov } 1292de9ce703SDmitry Torokhov 1293181d683dSDmitry Torokhov /* 1294181d683dSDmitry Torokhov * Checks whether port belongs to i8042 controller. 1295181d683dSDmitry Torokhov */ 1296181d683dSDmitry Torokhov bool i8042_check_port_owner(const struct serio *port) 1297181d683dSDmitry Torokhov { 1298181d683dSDmitry Torokhov int i; 1299181d683dSDmitry Torokhov 1300181d683dSDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) 1301181d683dSDmitry Torokhov if (i8042_ports[i].serio == port) 1302181d683dSDmitry Torokhov return true; 1303181d683dSDmitry Torokhov 1304181d683dSDmitry Torokhov return false; 1305181d683dSDmitry Torokhov } 1306181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_check_port_owner); 1307181d683dSDmitry Torokhov 1308de9ce703SDmitry Torokhov static void i8042_free_irqs(void) 1309de9ce703SDmitry Torokhov { 1310de9ce703SDmitry Torokhov if (i8042_aux_irq_registered) 1311de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 1312de9ce703SDmitry Torokhov if (i8042_kbd_irq_registered) 1313de9ce703SDmitry Torokhov free_irq(I8042_KBD_IRQ, i8042_platform_device); 1314de9ce703SDmitry Torokhov 1315386b3849SDmitry Torokhov i8042_aux_irq_registered = i8042_kbd_irq_registered = false; 1316de9ce703SDmitry Torokhov } 1317de9ce703SDmitry Torokhov 1318f8113416SDmitry Torokhov static int __init i8042_setup_aux(void) 1319de9ce703SDmitry Torokhov { 1320de9ce703SDmitry Torokhov int (*aux_enable)(void); 1321de9ce703SDmitry Torokhov int error; 1322de9ce703SDmitry Torokhov int i; 1323de9ce703SDmitry Torokhov 1324de9ce703SDmitry Torokhov if (i8042_check_aux()) 1325de9ce703SDmitry Torokhov return -ENODEV; 1326de9ce703SDmitry Torokhov 1327de9ce703SDmitry Torokhov if (i8042_nomux || i8042_check_mux()) { 1328de9ce703SDmitry Torokhov error = i8042_create_aux_port(-1); 1329de9ce703SDmitry Torokhov if (error) 1330de9ce703SDmitry Torokhov goto err_free_ports; 1331de9ce703SDmitry Torokhov aux_enable = i8042_enable_aux_port; 1332de9ce703SDmitry Torokhov } else { 1333de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { 1334de9ce703SDmitry Torokhov error = i8042_create_aux_port(i); 1335de9ce703SDmitry Torokhov if (error) 1336de9ce703SDmitry Torokhov goto err_free_ports; 1337de9ce703SDmitry Torokhov } 1338de9ce703SDmitry Torokhov aux_enable = i8042_enable_mux_ports; 1339de9ce703SDmitry Torokhov } 1340de9ce703SDmitry Torokhov 1341de9ce703SDmitry Torokhov error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED, 1342de9ce703SDmitry Torokhov "i8042", i8042_platform_device); 1343de9ce703SDmitry Torokhov if (error) 1344de9ce703SDmitry Torokhov goto err_free_ports; 1345de9ce703SDmitry Torokhov 1346de9ce703SDmitry Torokhov if (aux_enable()) 1347de9ce703SDmitry Torokhov goto err_free_irq; 1348de9ce703SDmitry Torokhov 1349386b3849SDmitry Torokhov i8042_aux_irq_registered = true; 1350de9ce703SDmitry Torokhov return 0; 1351de9ce703SDmitry Torokhov 1352de9ce703SDmitry Torokhov err_free_irq: 1353de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 1354de9ce703SDmitry Torokhov err_free_ports: 1355de9ce703SDmitry Torokhov i8042_free_aux_ports(); 1356de9ce703SDmitry Torokhov return error; 1357de9ce703SDmitry Torokhov } 1358de9ce703SDmitry Torokhov 1359f8113416SDmitry Torokhov static int __init i8042_setup_kbd(void) 1360de9ce703SDmitry Torokhov { 1361de9ce703SDmitry Torokhov int error; 1362de9ce703SDmitry Torokhov 1363de9ce703SDmitry Torokhov error = i8042_create_kbd_port(); 1364de9ce703SDmitry Torokhov if (error) 1365de9ce703SDmitry Torokhov return error; 1366de9ce703SDmitry Torokhov 1367de9ce703SDmitry Torokhov error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED, 1368de9ce703SDmitry Torokhov "i8042", i8042_platform_device); 1369de9ce703SDmitry Torokhov if (error) 1370de9ce703SDmitry Torokhov goto err_free_port; 1371de9ce703SDmitry Torokhov 1372de9ce703SDmitry Torokhov error = i8042_enable_kbd_port(); 1373de9ce703SDmitry Torokhov if (error) 1374de9ce703SDmitry Torokhov goto err_free_irq; 1375de9ce703SDmitry Torokhov 1376386b3849SDmitry Torokhov i8042_kbd_irq_registered = true; 1377de9ce703SDmitry Torokhov return 0; 1378de9ce703SDmitry Torokhov 1379de9ce703SDmitry Torokhov err_free_irq: 1380de9ce703SDmitry Torokhov free_irq(I8042_KBD_IRQ, i8042_platform_device); 1381de9ce703SDmitry Torokhov err_free_port: 1382de9ce703SDmitry Torokhov i8042_free_kbd_port(); 1383de9ce703SDmitry Torokhov return error; 13841da177e4SLinus Torvalds } 13851da177e4SLinus Torvalds 1386f8113416SDmitry Torokhov static int __init i8042_probe(struct platform_device *dev) 13871da177e4SLinus Torvalds { 1388de9ce703SDmitry Torokhov int error; 13891da177e4SLinus Torvalds 1390ec62e1c8SDmitry Torokhov i8042_platform_device = dev; 1391ec62e1c8SDmitry Torokhov 13921ca56e51SDmitry Torokhov if (i8042_reset) { 1393de9ce703SDmitry Torokhov error = i8042_controller_selftest(); 1394de9ce703SDmitry Torokhov if (error) 1395de9ce703SDmitry Torokhov return error; 13961ca56e51SDmitry Torokhov } 13971da177e4SLinus Torvalds 1398de9ce703SDmitry Torokhov error = i8042_controller_init(); 1399de9ce703SDmitry Torokhov if (error) 1400de9ce703SDmitry Torokhov return error; 14011da177e4SLinus Torvalds 1402d35895dbSBruno Prémont #ifdef CONFIG_X86 1403d35895dbSBruno Prémont if (i8042_dritek) 1404d35895dbSBruno Prémont i8042_dritek_enable(); 1405d35895dbSBruno Prémont #endif 1406d35895dbSBruno Prémont 1407de9ce703SDmitry Torokhov if (!i8042_noaux) { 1408de9ce703SDmitry Torokhov error = i8042_setup_aux(); 1409de9ce703SDmitry Torokhov if (error && error != -ENODEV && error != -EBUSY) 1410de9ce703SDmitry Torokhov goto out_fail; 14111da177e4SLinus Torvalds } 14121da177e4SLinus Torvalds 1413945ef0d4SDmitry Torokhov if (!i8042_nokbd) { 1414de9ce703SDmitry Torokhov error = i8042_setup_kbd(); 1415de9ce703SDmitry Torokhov if (error) 1416de9ce703SDmitry Torokhov goto out_fail; 1417945ef0d4SDmitry Torokhov } 1418de9ce703SDmitry Torokhov /* 1419de9ce703SDmitry Torokhov * Ok, everything is ready, let's register all serio ports 1420de9ce703SDmitry Torokhov */ 1421de9ce703SDmitry Torokhov i8042_register_ports(); 14221da177e4SLinus Torvalds 14231da177e4SLinus Torvalds return 0; 14240854e52dSDmitry Torokhov 1425de9ce703SDmitry Torokhov out_fail: 1426de9ce703SDmitry Torokhov i8042_free_aux_ports(); /* in case KBD failed but AUX not */ 1427de9ce703SDmitry Torokhov i8042_free_irqs(); 1428de9ce703SDmitry Torokhov i8042_controller_reset(); 1429ec62e1c8SDmitry Torokhov i8042_platform_device = NULL; 14300854e52dSDmitry Torokhov 1431de9ce703SDmitry Torokhov return error; 14321da177e4SLinus Torvalds } 14331da177e4SLinus Torvalds 143487fd6318SDmitry Torokhov static int __devexit i8042_remove(struct platform_device *dev) 14351da177e4SLinus Torvalds { 1436de9ce703SDmitry Torokhov i8042_unregister_ports(); 1437de9ce703SDmitry Torokhov i8042_free_irqs(); 1438de9ce703SDmitry Torokhov i8042_controller_reset(); 1439ec62e1c8SDmitry Torokhov i8042_platform_device = NULL; 14401da177e4SLinus Torvalds 144187fd6318SDmitry Torokhov return 0; 144287fd6318SDmitry Torokhov } 144387fd6318SDmitry Torokhov 144487fd6318SDmitry Torokhov static struct platform_driver i8042_driver = { 144587fd6318SDmitry Torokhov .driver = { 144687fd6318SDmitry Torokhov .name = "i8042", 144787fd6318SDmitry Torokhov .owner = THIS_MODULE, 1448ebd7768dSDmitry Torokhov #ifdef CONFIG_PM 1449ebd7768dSDmitry Torokhov .pm = &i8042_pm_ops, 1450ebd7768dSDmitry Torokhov #endif 145187fd6318SDmitry Torokhov }, 145287fd6318SDmitry Torokhov .remove = __devexit_p(i8042_remove), 145382dd9effSDmitry Torokhov .shutdown = i8042_shutdown, 145487fd6318SDmitry Torokhov }; 145587fd6318SDmitry Torokhov 145687fd6318SDmitry Torokhov static int __init i8042_init(void) 145787fd6318SDmitry Torokhov { 1458ec62e1c8SDmitry Torokhov struct platform_device *pdev; 145987fd6318SDmitry Torokhov int err; 146087fd6318SDmitry Torokhov 146187fd6318SDmitry Torokhov dbg_init(); 146287fd6318SDmitry Torokhov 146387fd6318SDmitry Torokhov err = i8042_platform_init(); 146487fd6318SDmitry Torokhov if (err) 146587fd6318SDmitry Torokhov return err; 146687fd6318SDmitry Torokhov 1467de9ce703SDmitry Torokhov err = i8042_controller_check(); 1468de9ce703SDmitry Torokhov if (err) 1469de9ce703SDmitry Torokhov goto err_platform_exit; 147087fd6318SDmitry Torokhov 1471ec62e1c8SDmitry Torokhov pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0); 1472ec62e1c8SDmitry Torokhov if (IS_ERR(pdev)) { 1473ec62e1c8SDmitry Torokhov err = PTR_ERR(pdev); 1474f8113416SDmitry Torokhov goto err_platform_exit; 147587fd6318SDmitry Torokhov } 147687fd6318SDmitry Torokhov 1477de9ce703SDmitry Torokhov panic_blink = i8042_panic_blink; 1478de9ce703SDmitry Torokhov 147987fd6318SDmitry Torokhov return 0; 148087fd6318SDmitry Torokhov 148187fd6318SDmitry Torokhov err_platform_exit: 148287fd6318SDmitry Torokhov i8042_platform_exit(); 148387fd6318SDmitry Torokhov return err; 148487fd6318SDmitry Torokhov } 148587fd6318SDmitry Torokhov 148687fd6318SDmitry Torokhov static void __exit i8042_exit(void) 148787fd6318SDmitry Torokhov { 1488f8113416SDmitry Torokhov platform_device_unregister(i8042_platform_device); 1489*af045b86SDmitry Torokhov platform_driver_unregister(&i8042_driver); 14901da177e4SLinus Torvalds i8042_platform_exit(); 14911da177e4SLinus Torvalds 14921da177e4SLinus Torvalds panic_blink = NULL; 14931da177e4SLinus Torvalds } 14941da177e4SLinus Torvalds 14951da177e4SLinus Torvalds module_init(i8042_init); 14961da177e4SLinus Torvalds module_exit(i8042_exit); 1497