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> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #include <asm/io.h> 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); 281da177e4SLinus Torvalds MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); 291da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 301da177e4SLinus Torvalds 31386b3849SDmitry Torokhov static bool i8042_nokbd; 32945ef0d4SDmitry Torokhov module_param_named(nokbd, i8042_nokbd, bool, 0); 33945ef0d4SDmitry Torokhov MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port."); 34945ef0d4SDmitry Torokhov 35386b3849SDmitry Torokhov static bool i8042_noaux; 361da177e4SLinus Torvalds module_param_named(noaux, i8042_noaux, bool, 0); 371da177e4SLinus Torvalds MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port."); 381da177e4SLinus Torvalds 39386b3849SDmitry Torokhov static bool i8042_nomux; 401da177e4SLinus Torvalds module_param_named(nomux, i8042_nomux, bool, 0); 411da177e4SLinus Torvalds MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing conrtoller is present."); 421da177e4SLinus Torvalds 43386b3849SDmitry Torokhov static bool i8042_unlock; 441da177e4SLinus Torvalds module_param_named(unlock, i8042_unlock, bool, 0); 451da177e4SLinus Torvalds MODULE_PARM_DESC(unlock, "Ignore keyboard lock."); 461da177e4SLinus Torvalds 47386b3849SDmitry Torokhov static bool i8042_reset; 481da177e4SLinus Torvalds module_param_named(reset, i8042_reset, bool, 0); 491da177e4SLinus Torvalds MODULE_PARM_DESC(reset, "Reset controller during init and cleanup."); 501da177e4SLinus Torvalds 51386b3849SDmitry Torokhov static bool i8042_direct; 521da177e4SLinus Torvalds module_param_named(direct, i8042_direct, bool, 0); 531da177e4SLinus Torvalds MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode."); 541da177e4SLinus Torvalds 55386b3849SDmitry Torokhov static bool i8042_dumbkbd; 561da177e4SLinus Torvalds module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); 571da177e4SLinus Torvalds MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); 581da177e4SLinus Torvalds 59386b3849SDmitry Torokhov static bool i8042_noloop; 601da177e4SLinus Torvalds module_param_named(noloop, i8042_noloop, bool, 0); 611da177e4SLinus Torvalds MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port"); 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds static unsigned int i8042_blink_frequency = 500; 641da177e4SLinus Torvalds module_param_named(panicblink, i8042_blink_frequency, uint, 0600); 651da177e4SLinus Torvalds MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics"); 661da177e4SLinus Torvalds 678987fec0SCarlos Corbacho #ifdef CONFIG_X86 68386b3849SDmitry Torokhov static bool i8042_dritek; 698987fec0SCarlos Corbacho module_param_named(dritek, i8042_dritek, bool, 0); 708987fec0SCarlos Corbacho MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension"); 718987fec0SCarlos Corbacho #endif 728987fec0SCarlos Corbacho 731da177e4SLinus Torvalds #ifdef CONFIG_PNP 74386b3849SDmitry Torokhov static bool i8042_nopnp; 751da177e4SLinus Torvalds module_param_named(nopnp, i8042_nopnp, bool, 0); 761da177e4SLinus Torvalds MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings"); 771da177e4SLinus Torvalds #endif 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds #define DEBUG 801da177e4SLinus Torvalds #ifdef DEBUG 81386b3849SDmitry Torokhov static bool i8042_debug; 821da177e4SLinus Torvalds module_param_named(debug, i8042_debug, bool, 0600); 831da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off"); 841da177e4SLinus Torvalds #endif 851da177e4SLinus Torvalds 861c7827aeSDmitry Torokhov static bool i8042_bypass_aux_irq_test; 871c7827aeSDmitry Torokhov 881da177e4SLinus Torvalds #include "i8042.h" 891da177e4SLinus Torvalds 90181d683dSDmitry Torokhov /* 91181d683dSDmitry Torokhov * i8042_lock protects serialization between i8042_command and 92181d683dSDmitry Torokhov * the interrupt handler. 93181d683dSDmitry Torokhov */ 941da177e4SLinus Torvalds static DEFINE_SPINLOCK(i8042_lock); 951da177e4SLinus Torvalds 96181d683dSDmitry Torokhov /* 97181d683dSDmitry Torokhov * Writers to AUX and KBD ports as well as users issuing i8042_command 98181d683dSDmitry Torokhov * directly should acquire i8042_mutex (by means of calling 99181d683dSDmitry Torokhov * i8042_lock_chip() and i8042_unlock_ship() helpers) to ensure that 100181d683dSDmitry Torokhov * they do not disturb each other (unfortunately in many i8042 101181d683dSDmitry Torokhov * implementations write to one of the ports will immediately abort 102181d683dSDmitry Torokhov * command that is being processed by another port). 103181d683dSDmitry Torokhov */ 104181d683dSDmitry Torokhov static DEFINE_MUTEX(i8042_mutex); 105181d683dSDmitry Torokhov 1061da177e4SLinus Torvalds struct i8042_port { 1071da177e4SLinus Torvalds struct serio *serio; 1081da177e4SLinus Torvalds int irq; 109386b3849SDmitry Torokhov bool exists; 1101da177e4SLinus Torvalds signed char mux; 1111da177e4SLinus Torvalds }; 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds #define I8042_KBD_PORT_NO 0 1141da177e4SLinus Torvalds #define I8042_AUX_PORT_NO 1 1151da177e4SLinus Torvalds #define I8042_MUX_PORT_NO 2 1161da177e4SLinus Torvalds #define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2) 117de9ce703SDmitry Torokhov 118de9ce703SDmitry Torokhov static struct i8042_port i8042_ports[I8042_NUM_PORTS]; 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds static unsigned char i8042_initial_ctr; 1211da177e4SLinus Torvalds static unsigned char i8042_ctr; 122386b3849SDmitry Torokhov static bool i8042_mux_present; 123386b3849SDmitry Torokhov static bool i8042_kbd_irq_registered; 124386b3849SDmitry Torokhov static bool i8042_aux_irq_registered; 125817e6ba3SDmitry Torokhov static unsigned char i8042_suppress_kbd_ack; 1261da177e4SLinus Torvalds static struct platform_device *i8042_platform_device; 1271da177e4SLinus Torvalds 1287d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id); 129*967c9ef9SMatthew Garrett static bool (*i8042_platform_filter)(unsigned char data, unsigned char str, 130*967c9ef9SMatthew Garrett struct serio *serio); 1311da177e4SLinus Torvalds 132181d683dSDmitry Torokhov void i8042_lock_chip(void) 133181d683dSDmitry Torokhov { 134181d683dSDmitry Torokhov mutex_lock(&i8042_mutex); 135181d683dSDmitry Torokhov } 136181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_lock_chip); 137181d683dSDmitry Torokhov 138181d683dSDmitry Torokhov void i8042_unlock_chip(void) 139181d683dSDmitry Torokhov { 140181d683dSDmitry Torokhov mutex_unlock(&i8042_mutex); 141181d683dSDmitry Torokhov } 142181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_unlock_chip); 143181d683dSDmitry Torokhov 144*967c9ef9SMatthew Garrett int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, 145*967c9ef9SMatthew Garrett struct serio *serio)) 146*967c9ef9SMatthew Garrett { 147*967c9ef9SMatthew Garrett unsigned long flags; 148*967c9ef9SMatthew Garrett int ret = 0; 149*967c9ef9SMatthew Garrett 150*967c9ef9SMatthew Garrett spin_lock_irqsave(&i8042_lock, flags); 151*967c9ef9SMatthew Garrett 152*967c9ef9SMatthew Garrett if (i8042_platform_filter) { 153*967c9ef9SMatthew Garrett ret = -EBUSY; 154*967c9ef9SMatthew Garrett goto out; 155*967c9ef9SMatthew Garrett } 156*967c9ef9SMatthew Garrett 157*967c9ef9SMatthew Garrett i8042_platform_filter = filter; 158*967c9ef9SMatthew Garrett 159*967c9ef9SMatthew Garrett out: 160*967c9ef9SMatthew Garrett spin_unlock_irqrestore(&i8042_lock, flags); 161*967c9ef9SMatthew Garrett return ret; 162*967c9ef9SMatthew Garrett } 163*967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_install_filter); 164*967c9ef9SMatthew Garrett 165*967c9ef9SMatthew Garrett int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, 166*967c9ef9SMatthew Garrett struct serio *port)) 167*967c9ef9SMatthew Garrett { 168*967c9ef9SMatthew Garrett unsigned long flags; 169*967c9ef9SMatthew Garrett int ret = 0; 170*967c9ef9SMatthew Garrett 171*967c9ef9SMatthew Garrett spin_lock_irqsave(&i8042_lock, flags); 172*967c9ef9SMatthew Garrett 173*967c9ef9SMatthew Garrett if (i8042_platform_filter != filter) { 174*967c9ef9SMatthew Garrett ret = -EINVAL; 175*967c9ef9SMatthew Garrett goto out; 176*967c9ef9SMatthew Garrett } 177*967c9ef9SMatthew Garrett 178*967c9ef9SMatthew Garrett i8042_platform_filter = NULL; 179*967c9ef9SMatthew Garrett 180*967c9ef9SMatthew Garrett out: 181*967c9ef9SMatthew Garrett spin_unlock_irqrestore(&i8042_lock, flags); 182*967c9ef9SMatthew Garrett return ret; 183*967c9ef9SMatthew Garrett } 184*967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_remove_filter); 185*967c9ef9SMatthew Garrett 1861da177e4SLinus Torvalds /* 1871da177e4SLinus Torvalds * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to 1881da177e4SLinus Torvalds * be ready for reading values from it / writing values to it. 1891da177e4SLinus Torvalds * Called always with i8042_lock held. 1901da177e4SLinus Torvalds */ 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds static int i8042_wait_read(void) 1931da177e4SLinus Torvalds { 1941da177e4SLinus Torvalds int i = 0; 195de9ce703SDmitry Torokhov 1961da177e4SLinus Torvalds while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { 1971da177e4SLinus Torvalds udelay(50); 1981da177e4SLinus Torvalds i++; 1991da177e4SLinus Torvalds } 2001da177e4SLinus Torvalds return -(i == I8042_CTL_TIMEOUT); 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds static int i8042_wait_write(void) 2041da177e4SLinus Torvalds { 2051da177e4SLinus Torvalds int i = 0; 206de9ce703SDmitry Torokhov 2071da177e4SLinus Torvalds while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { 2081da177e4SLinus Torvalds udelay(50); 2091da177e4SLinus Torvalds i++; 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds return -(i == I8042_CTL_TIMEOUT); 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds /* 2151da177e4SLinus Torvalds * i8042_flush() flushes all data that may be in the keyboard and mouse buffers 2161da177e4SLinus Torvalds * of the i8042 down the toilet. 2171da177e4SLinus Torvalds */ 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds static int i8042_flush(void) 2201da177e4SLinus Torvalds { 2211da177e4SLinus Torvalds unsigned long flags; 2221da177e4SLinus Torvalds unsigned char data, str; 2231da177e4SLinus Torvalds int i = 0; 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) { 2281da177e4SLinus Torvalds udelay(50); 2291da177e4SLinus Torvalds data = i8042_read_data(); 2301da177e4SLinus Torvalds i++; 2311da177e4SLinus Torvalds dbg("%02x <- i8042 (flush, %s)", data, 2321da177e4SLinus Torvalds str & I8042_STR_AUXDATA ? "aux" : "kbd"); 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds return i; 2381da177e4SLinus Torvalds } 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds /* 2411da177e4SLinus Torvalds * i8042_command() executes a command on the i8042. It also sends the input 2421da177e4SLinus Torvalds * parameter(s) of the commands to it, and receives the output value(s). The 2431da177e4SLinus Torvalds * parameters are to be stored in the param array, and the output is placed 2441da177e4SLinus Torvalds * into the same array. The number of the parameters and output values is 2451da177e4SLinus Torvalds * encoded in bits 8-11 of the command number. 2461da177e4SLinus Torvalds */ 2471da177e4SLinus Torvalds 248de9ce703SDmitry Torokhov static int __i8042_command(unsigned char *param, int command) 2491da177e4SLinus Torvalds { 250de9ce703SDmitry Torokhov int i, error; 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds if (i8042_noloop && command == I8042_CMD_AUX_LOOP) 2531da177e4SLinus Torvalds return -1; 2541da177e4SLinus Torvalds 255de9ce703SDmitry Torokhov error = i8042_wait_write(); 256de9ce703SDmitry Torokhov if (error) 257de9ce703SDmitry Torokhov return error; 258463a4f76SDmitry Torokhov 2591da177e4SLinus Torvalds dbg("%02x -> i8042 (command)", command & 0xff); 2601da177e4SLinus Torvalds i8042_write_command(command & 0xff); 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds for (i = 0; i < ((command >> 12) & 0xf); i++) { 263de9ce703SDmitry Torokhov error = i8042_wait_write(); 264de9ce703SDmitry Torokhov if (error) 265de9ce703SDmitry Torokhov return error; 2661da177e4SLinus Torvalds dbg("%02x -> i8042 (parameter)", param[i]); 2671da177e4SLinus Torvalds i8042_write_data(param[i]); 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds for (i = 0; i < ((command >> 8) & 0xf); i++) { 271de9ce703SDmitry Torokhov error = i8042_wait_read(); 272de9ce703SDmitry Torokhov if (error) { 273de9ce703SDmitry Torokhov dbg(" -- i8042 (timeout)"); 274de9ce703SDmitry Torokhov return error; 275de9ce703SDmitry Torokhov } 276463a4f76SDmitry Torokhov 277463a4f76SDmitry Torokhov if (command == I8042_CMD_AUX_LOOP && 278463a4f76SDmitry Torokhov !(i8042_read_status() & I8042_STR_AUXDATA)) { 279de9ce703SDmitry Torokhov dbg(" -- i8042 (auxerr)"); 280de9ce703SDmitry Torokhov return -1; 281463a4f76SDmitry Torokhov } 282463a4f76SDmitry Torokhov 2831da177e4SLinus Torvalds param[i] = i8042_read_data(); 2841da177e4SLinus Torvalds dbg("%02x <- i8042 (return)", param[i]); 2851da177e4SLinus Torvalds } 2861da177e4SLinus Torvalds 287de9ce703SDmitry Torokhov return 0; 288de9ce703SDmitry Torokhov } 2891da177e4SLinus Torvalds 290553a05b8SMárton Németh int i8042_command(unsigned char *param, int command) 291de9ce703SDmitry Torokhov { 292de9ce703SDmitry Torokhov unsigned long flags; 293de9ce703SDmitry Torokhov int retval; 294de9ce703SDmitry Torokhov 295de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 296de9ce703SDmitry Torokhov retval = __i8042_command(param, command); 297463a4f76SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 298de9ce703SDmitry Torokhov 2991da177e4SLinus Torvalds return retval; 3001da177e4SLinus Torvalds } 301553a05b8SMárton Németh EXPORT_SYMBOL(i8042_command); 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds /* 3041da177e4SLinus Torvalds * i8042_kbd_write() sends a byte out through the keyboard interface. 3051da177e4SLinus Torvalds */ 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds static int i8042_kbd_write(struct serio *port, unsigned char c) 3081da177e4SLinus Torvalds { 3091da177e4SLinus Torvalds unsigned long flags; 3101da177e4SLinus Torvalds int retval = 0; 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds if (!(retval = i8042_wait_write())) { 3151da177e4SLinus Torvalds dbg("%02x -> i8042 (kbd-data)", c); 3161da177e4SLinus Torvalds i8042_write_data(c); 3171da177e4SLinus Torvalds } 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds return retval; 3221da177e4SLinus Torvalds } 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds /* 3251da177e4SLinus Torvalds * i8042_aux_write() sends a byte out through the aux interface. 3261da177e4SLinus Torvalds */ 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds static int i8042_aux_write(struct serio *serio, unsigned char c) 3291da177e4SLinus Torvalds { 3301da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 3311da177e4SLinus Torvalds 332f4e3c711SDmitry Torokhov return i8042_command(&c, port->mux == -1 ? 333f4e3c711SDmitry Torokhov I8042_CMD_AUX_SEND : 334f4e3c711SDmitry Torokhov I8042_CMD_MUX_SEND + port->mux); 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 3375ddbc77cSDmitry Torokhov 3385ddbc77cSDmitry Torokhov /* 3395ddbc77cSDmitry Torokhov * i8042_aux_close attempts to clear AUX or KBD port state by disabling 3405ddbc77cSDmitry Torokhov * and then re-enabling it. 3415ddbc77cSDmitry Torokhov */ 3425ddbc77cSDmitry Torokhov 3435ddbc77cSDmitry Torokhov static void i8042_port_close(struct serio *serio) 3445ddbc77cSDmitry Torokhov { 3455ddbc77cSDmitry Torokhov int irq_bit; 3465ddbc77cSDmitry Torokhov int disable_bit; 3475ddbc77cSDmitry Torokhov const char *port_name; 3485ddbc77cSDmitry Torokhov 3495ddbc77cSDmitry Torokhov if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) { 3505ddbc77cSDmitry Torokhov irq_bit = I8042_CTR_AUXINT; 3515ddbc77cSDmitry Torokhov disable_bit = I8042_CTR_AUXDIS; 3525ddbc77cSDmitry Torokhov port_name = "AUX"; 3535ddbc77cSDmitry Torokhov } else { 3545ddbc77cSDmitry Torokhov irq_bit = I8042_CTR_KBDINT; 3555ddbc77cSDmitry Torokhov disable_bit = I8042_CTR_KBDDIS; 3565ddbc77cSDmitry Torokhov port_name = "KBD"; 3575ddbc77cSDmitry Torokhov } 3585ddbc77cSDmitry Torokhov 3595ddbc77cSDmitry Torokhov i8042_ctr &= ~irq_bit; 3605ddbc77cSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 3615ddbc77cSDmitry Torokhov printk(KERN_WARNING 3625ddbc77cSDmitry Torokhov "i8042.c: Can't write CTR while closing %s port.\n", 3635ddbc77cSDmitry Torokhov port_name); 3645ddbc77cSDmitry Torokhov 3655ddbc77cSDmitry Torokhov udelay(50); 3665ddbc77cSDmitry Torokhov 3675ddbc77cSDmitry Torokhov i8042_ctr &= ~disable_bit; 3685ddbc77cSDmitry Torokhov i8042_ctr |= irq_bit; 3695ddbc77cSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 3705ddbc77cSDmitry Torokhov printk(KERN_ERR "i8042.c: Can't reactivate %s port.\n", 3715ddbc77cSDmitry Torokhov port_name); 3725ddbc77cSDmitry Torokhov 3735ddbc77cSDmitry Torokhov /* 3745ddbc77cSDmitry Torokhov * See if there is any data appeared while we were messing with 3755ddbc77cSDmitry Torokhov * port state. 3765ddbc77cSDmitry Torokhov */ 3775ddbc77cSDmitry Torokhov i8042_interrupt(0, NULL); 3785ddbc77cSDmitry Torokhov } 3795ddbc77cSDmitry Torokhov 3801da177e4SLinus Torvalds /* 3811da177e4SLinus Torvalds * i8042_start() is called by serio core when port is about to finish 3821da177e4SLinus Torvalds * registering. It will mark port as existing so i8042_interrupt can 3831da177e4SLinus Torvalds * start sending data through it. 3841da177e4SLinus Torvalds */ 3851da177e4SLinus Torvalds static int i8042_start(struct serio *serio) 3861da177e4SLinus Torvalds { 3871da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 3881da177e4SLinus Torvalds 389386b3849SDmitry Torokhov port->exists = true; 3901da177e4SLinus Torvalds mb(); 3911da177e4SLinus Torvalds return 0; 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds /* 3951da177e4SLinus Torvalds * i8042_stop() marks serio port as non-existing so i8042_interrupt 3961da177e4SLinus Torvalds * will not try to send data to the port that is about to go away. 3971da177e4SLinus Torvalds * The function is called by serio core as part of unregister procedure. 3981da177e4SLinus Torvalds */ 3991da177e4SLinus Torvalds static void i8042_stop(struct serio *serio) 4001da177e4SLinus Torvalds { 4011da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 4021da177e4SLinus Torvalds 403386b3849SDmitry Torokhov port->exists = false; 404a8399c51SDmitry Torokhov 405a8399c51SDmitry Torokhov /* 406a8399c51SDmitry Torokhov * We synchronize with both AUX and KBD IRQs because there is 407a8399c51SDmitry Torokhov * a (very unlikely) chance that AUX IRQ is raised for KBD port 408a8399c51SDmitry Torokhov * and vice versa. 409a8399c51SDmitry Torokhov */ 410a8399c51SDmitry Torokhov synchronize_irq(I8042_AUX_IRQ); 411a8399c51SDmitry Torokhov synchronize_irq(I8042_KBD_IRQ); 4121da177e4SLinus Torvalds port->serio = NULL; 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds /* 4164e8d340dSDmitry Torokhov * i8042_filter() filters out unwanted bytes from the input data stream. 4174e8d340dSDmitry Torokhov * It is called from i8042_interrupt and thus is running with interrupts 4184e8d340dSDmitry Torokhov * off and i8042_lock held. 4194e8d340dSDmitry Torokhov */ 420*967c9ef9SMatthew Garrett static bool i8042_filter(unsigned char data, unsigned char str, 421*967c9ef9SMatthew Garrett struct serio *serio) 4224e8d340dSDmitry Torokhov { 4234e8d340dSDmitry Torokhov if (unlikely(i8042_suppress_kbd_ack)) { 4244e8d340dSDmitry Torokhov if ((~str & I8042_STR_AUXDATA) && 4254e8d340dSDmitry Torokhov (data == 0xfa || data == 0xfe)) { 4264e8d340dSDmitry Torokhov i8042_suppress_kbd_ack--; 4274e8d340dSDmitry Torokhov dbg("Extra keyboard ACK - filtered out\n"); 4284e8d340dSDmitry Torokhov return true; 4294e8d340dSDmitry Torokhov } 4304e8d340dSDmitry Torokhov } 4314e8d340dSDmitry Torokhov 432*967c9ef9SMatthew Garrett if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) { 433*967c9ef9SMatthew Garrett dbg("Filtered out by platfrom filter\n"); 434*967c9ef9SMatthew Garrett return true; 435*967c9ef9SMatthew Garrett } 436*967c9ef9SMatthew Garrett 4374e8d340dSDmitry Torokhov return false; 4384e8d340dSDmitry Torokhov } 4394e8d340dSDmitry Torokhov 4404e8d340dSDmitry Torokhov /* 4411da177e4SLinus Torvalds * i8042_interrupt() is the most important function in this driver - 4421da177e4SLinus Torvalds * it handles the interrupts from the i8042, and sends incoming bytes 4431da177e4SLinus Torvalds * to the upper layers. 4441da177e4SLinus Torvalds */ 4451da177e4SLinus Torvalds 4467d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id) 4471da177e4SLinus Torvalds { 4481da177e4SLinus Torvalds struct i8042_port *port; 449*967c9ef9SMatthew Garrett struct serio *serio; 4501da177e4SLinus Torvalds unsigned long flags; 4511da177e4SLinus Torvalds unsigned char str, data; 4521da177e4SLinus Torvalds unsigned int dfl; 4531da177e4SLinus Torvalds unsigned int port_no; 4544e8d340dSDmitry Torokhov bool filtered; 455817e6ba3SDmitry Torokhov int ret = 1; 4561da177e4SLinus Torvalds 4571da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 4584e8d340dSDmitry Torokhov 4591da177e4SLinus Torvalds str = i8042_read_status(); 4601da177e4SLinus Torvalds if (unlikely(~str & I8042_STR_OBF)) { 4611da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 4621da177e4SLinus Torvalds if (irq) dbg("Interrupt %d, without any data", irq); 4631da177e4SLinus Torvalds ret = 0; 4641da177e4SLinus Torvalds goto out; 4651da177e4SLinus Torvalds } 4664e8d340dSDmitry Torokhov 4671da177e4SLinus Torvalds data = i8042_read_data(); 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { 4701da177e4SLinus Torvalds static unsigned long last_transmit; 4711da177e4SLinus Torvalds static unsigned char last_str; 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds dfl = 0; 4741da177e4SLinus Torvalds if (str & I8042_STR_MUXERR) { 4751da177e4SLinus Torvalds dbg("MUX error, status is %02x, data is %02x", str, data); 4761da177e4SLinus Torvalds /* 4771da177e4SLinus Torvalds * When MUXERR condition is signalled the data register can only contain 4781da177e4SLinus Torvalds * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately 479a216a4b6SDmitry Torokhov * it is not always the case. Some KBCs also report 0xfc when there is 480a216a4b6SDmitry Torokhov * nothing connected to the port while others sometimes get confused which 481a216a4b6SDmitry Torokhov * port the data came from and signal error leaving the data intact. They 482a216a4b6SDmitry Torokhov * _do not_ revert to legacy mode (actually I've never seen KBC reverting 483a216a4b6SDmitry Torokhov * to legacy mode yet, when we see one we'll add proper handling). 484a216a4b6SDmitry Torokhov * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the 485a216a4b6SDmitry Torokhov * rest assume that the data came from the same serio last byte 4861da177e4SLinus Torvalds * was transmitted (if transmission happened not too long ago). 4871da177e4SLinus Torvalds */ 488a216a4b6SDmitry Torokhov 489a216a4b6SDmitry Torokhov switch (data) { 490a216a4b6SDmitry Torokhov default: 4911da177e4SLinus Torvalds if (time_before(jiffies, last_transmit + HZ/10)) { 4921da177e4SLinus Torvalds str = last_str; 4931da177e4SLinus Torvalds break; 4941da177e4SLinus Torvalds } 4951da177e4SLinus Torvalds /* fall through - report timeout */ 496a216a4b6SDmitry Torokhov case 0xfc: 4971da177e4SLinus Torvalds case 0xfd: 4981da177e4SLinus Torvalds case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break; 4991da177e4SLinus Torvalds case 0xff: dfl = SERIO_PARITY; data = 0xfe; break; 5001da177e4SLinus Torvalds } 5011da177e4SLinus Torvalds } 5021da177e4SLinus Torvalds 5031da177e4SLinus Torvalds port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3); 5041da177e4SLinus Torvalds last_str = str; 5051da177e4SLinus Torvalds last_transmit = jiffies; 5061da177e4SLinus Torvalds } else { 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | 5091da177e4SLinus Torvalds ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds port_no = (str & I8042_STR_AUXDATA) ? 5121da177e4SLinus Torvalds I8042_AUX_PORT_NO : I8042_KBD_PORT_NO; 5131da177e4SLinus Torvalds } 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds port = &i8042_ports[port_no]; 516*967c9ef9SMatthew Garrett serio = port->exists ? port->serio : NULL; 5171da177e4SLinus Torvalds 518de9ce703SDmitry Torokhov dbg("%02x <- i8042 (interrupt, %d, %d%s%s)", 519de9ce703SDmitry Torokhov data, port_no, irq, 5201da177e4SLinus Torvalds dfl & SERIO_PARITY ? ", bad parity" : "", 5211da177e4SLinus Torvalds dfl & SERIO_TIMEOUT ? ", timeout" : ""); 5221da177e4SLinus Torvalds 523*967c9ef9SMatthew Garrett filtered = i8042_filter(data, str, serio); 524817e6ba3SDmitry Torokhov 5254e8d340dSDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 5264e8d340dSDmitry Torokhov 5274e8d340dSDmitry Torokhov if (likely(port->exists && !filtered)) 528*967c9ef9SMatthew Garrett serio_interrupt(serio, data, dfl); 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds out: 5311da177e4SLinus Torvalds return IRQ_RETVAL(ret); 5321da177e4SLinus Torvalds } 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds /* 5355ddbc77cSDmitry Torokhov * i8042_enable_kbd_port enables keyboard port on chip 536de9ce703SDmitry Torokhov */ 537de9ce703SDmitry Torokhov 538de9ce703SDmitry Torokhov static int i8042_enable_kbd_port(void) 539de9ce703SDmitry Torokhov { 540de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_KBDDIS; 541de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_KBDINT; 542de9ce703SDmitry Torokhov 543de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 544018db6bbSMarkus Armbruster i8042_ctr &= ~I8042_CTR_KBDINT; 545018db6bbSMarkus Armbruster i8042_ctr |= I8042_CTR_KBDDIS; 546de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n"); 547de9ce703SDmitry Torokhov return -EIO; 548de9ce703SDmitry Torokhov } 549de9ce703SDmitry Torokhov 550de9ce703SDmitry Torokhov return 0; 551de9ce703SDmitry Torokhov } 552de9ce703SDmitry Torokhov 553de9ce703SDmitry Torokhov /* 554de9ce703SDmitry Torokhov * i8042_enable_aux_port enables AUX (mouse) port on chip 555de9ce703SDmitry Torokhov */ 556de9ce703SDmitry Torokhov 557de9ce703SDmitry Torokhov static int i8042_enable_aux_port(void) 558de9ce703SDmitry Torokhov { 559de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_AUXDIS; 560de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXINT; 561de9ce703SDmitry Torokhov 562de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 563018db6bbSMarkus Armbruster i8042_ctr &= ~I8042_CTR_AUXINT; 564018db6bbSMarkus Armbruster i8042_ctr |= I8042_CTR_AUXDIS; 565de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n"); 566de9ce703SDmitry Torokhov return -EIO; 567de9ce703SDmitry Torokhov } 568de9ce703SDmitry Torokhov 569de9ce703SDmitry Torokhov return 0; 570de9ce703SDmitry Torokhov } 571de9ce703SDmitry Torokhov 572de9ce703SDmitry Torokhov /* 573de9ce703SDmitry Torokhov * i8042_enable_mux_ports enables 4 individual AUX ports after 574de9ce703SDmitry Torokhov * the controller has been switched into Multiplexed mode 575de9ce703SDmitry Torokhov */ 576de9ce703SDmitry Torokhov 577de9ce703SDmitry Torokhov static int i8042_enable_mux_ports(void) 578de9ce703SDmitry Torokhov { 579de9ce703SDmitry Torokhov unsigned char param; 580de9ce703SDmitry Torokhov int i; 581de9ce703SDmitry Torokhov 582de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { 583de9ce703SDmitry Torokhov i8042_command(¶m, I8042_CMD_MUX_PFX + i); 584de9ce703SDmitry Torokhov i8042_command(¶m, I8042_CMD_AUX_ENABLE); 585de9ce703SDmitry Torokhov } 586de9ce703SDmitry Torokhov 587de9ce703SDmitry Torokhov return i8042_enable_aux_port(); 588de9ce703SDmitry Torokhov } 589de9ce703SDmitry Torokhov 590de9ce703SDmitry Torokhov /* 591386b3849SDmitry Torokhov * i8042_set_mux_mode checks whether the controller has an 592386b3849SDmitry Torokhov * active multiplexor and puts the chip into Multiplexed (true) 593386b3849SDmitry Torokhov * or Legacy (false) mode. 5941da177e4SLinus Torvalds */ 5951da177e4SLinus Torvalds 596386b3849SDmitry Torokhov static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version) 5971da177e4SLinus Torvalds { 5981da177e4SLinus Torvalds 599386b3849SDmitry Torokhov unsigned char param, val; 6001da177e4SLinus Torvalds /* 6011da177e4SLinus Torvalds * Get rid of bytes in the queue. 6021da177e4SLinus Torvalds */ 6031da177e4SLinus Torvalds 6041da177e4SLinus Torvalds i8042_flush(); 6051da177e4SLinus Torvalds 6061da177e4SLinus Torvalds /* 6071da177e4SLinus Torvalds * Internal loopback test - send three bytes, they should come back from the 608de9ce703SDmitry Torokhov * mouse interface, the last should be version. 6091da177e4SLinus Torvalds */ 6101da177e4SLinus Torvalds 611386b3849SDmitry Torokhov param = val = 0xf0; 612386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != val) 6131da177e4SLinus Torvalds return -1; 614386b3849SDmitry Torokhov param = val = multiplex ? 0x56 : 0xf6; 615386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != val) 6161da177e4SLinus Torvalds return -1; 617386b3849SDmitry Torokhov param = val = multiplex ? 0xa4 : 0xa5; 618386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == val) 619386b3849SDmitry Torokhov return -1; 620386b3849SDmitry Torokhov 621386b3849SDmitry Torokhov /* 622386b3849SDmitry Torokhov * Workaround for interference with USB Legacy emulation 623386b3849SDmitry Torokhov * that causes a v10.12 MUX to be found. 624386b3849SDmitry Torokhov */ 625386b3849SDmitry Torokhov if (param == 0xac) 6261da177e4SLinus Torvalds return -1; 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds if (mux_version) 629463a4f76SDmitry Torokhov *mux_version = param; 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds return 0; 6321da177e4SLinus Torvalds } 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds /* 6351da177e4SLinus Torvalds * i8042_check_mux() checks whether the controller supports the PS/2 Active 6361da177e4SLinus Torvalds * Multiplexing specification by Synaptics, Phoenix, Insyde and 6371da177e4SLinus Torvalds * LCS/Telegraphics. 6381da177e4SLinus Torvalds */ 6391da177e4SLinus Torvalds 640f8113416SDmitry Torokhov static int __init i8042_check_mux(void) 6411da177e4SLinus Torvalds { 6421da177e4SLinus Torvalds unsigned char mux_version; 6431da177e4SLinus Torvalds 644386b3849SDmitry Torokhov if (i8042_set_mux_mode(true, &mux_version)) 6451da177e4SLinus Torvalds return -1; 6461da177e4SLinus Torvalds 6471da177e4SLinus Torvalds printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", 6481da177e4SLinus Torvalds (mux_version >> 4) & 0xf, mux_version & 0xf); 6491da177e4SLinus Torvalds 650de9ce703SDmitry Torokhov /* 651de9ce703SDmitry Torokhov * Disable all muxed ports by disabling AUX. 652de9ce703SDmitry Torokhov */ 653de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXDIS; 654de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_AUXINT; 655de9ce703SDmitry Torokhov 656de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 657de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n"); 658de9ce703SDmitry Torokhov return -EIO; 659de9ce703SDmitry Torokhov } 6601da177e4SLinus Torvalds 661386b3849SDmitry Torokhov i8042_mux_present = true; 662de9ce703SDmitry Torokhov 6631da177e4SLinus Torvalds return 0; 6641da177e4SLinus Torvalds } 6651da177e4SLinus Torvalds 666de9ce703SDmitry Torokhov /* 667de9ce703SDmitry Torokhov * The following is used to test AUX IRQ delivery. 668de9ce703SDmitry Torokhov */ 669f8113416SDmitry Torokhov static struct completion i8042_aux_irq_delivered __initdata; 670f8113416SDmitry Torokhov static bool i8042_irq_being_tested __initdata; 671de9ce703SDmitry Torokhov 672f8113416SDmitry Torokhov static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id) 673de9ce703SDmitry Torokhov { 674de9ce703SDmitry Torokhov unsigned long flags; 675de9ce703SDmitry Torokhov unsigned char str, data; 676e3758b2aSFernando Luis Vázquez Cao int ret = 0; 677de9ce703SDmitry Torokhov 678de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 679de9ce703SDmitry Torokhov str = i8042_read_status(); 680de9ce703SDmitry Torokhov if (str & I8042_STR_OBF) { 681de9ce703SDmitry Torokhov data = i8042_read_data(); 682d3d2dfe2SDmitry Torokhov dbg("%02x <- i8042 (aux_test_irq, %s)", 683d3d2dfe2SDmitry Torokhov data, str & I8042_STR_AUXDATA ? "aux" : "kbd"); 684de9ce703SDmitry Torokhov if (i8042_irq_being_tested && 685de9ce703SDmitry Torokhov data == 0xa5 && (str & I8042_STR_AUXDATA)) 686de9ce703SDmitry Torokhov complete(&i8042_aux_irq_delivered); 687e3758b2aSFernando Luis Vázquez Cao ret = 1; 688de9ce703SDmitry Torokhov } 689de9ce703SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 690de9ce703SDmitry Torokhov 691e3758b2aSFernando Luis Vázquez Cao return IRQ_RETVAL(ret); 692de9ce703SDmitry Torokhov } 693de9ce703SDmitry Torokhov 694d2ada559SRoland Scheidegger /* 695d2ada559SRoland Scheidegger * i8042_toggle_aux - enables or disables AUX port on i8042 via command and 696d2ada559SRoland Scheidegger * verifies success by readinng CTR. Used when testing for presence of AUX 697d2ada559SRoland Scheidegger * port. 698d2ada559SRoland Scheidegger */ 699f8113416SDmitry Torokhov static int __init i8042_toggle_aux(bool on) 700d2ada559SRoland Scheidegger { 701d2ada559SRoland Scheidegger unsigned char param; 702d2ada559SRoland Scheidegger int i; 703d2ada559SRoland Scheidegger 704d2ada559SRoland Scheidegger if (i8042_command(¶m, 705d2ada559SRoland Scheidegger on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE)) 706d2ada559SRoland Scheidegger return -1; 707d2ada559SRoland Scheidegger 708d2ada559SRoland Scheidegger /* some chips need some time to set the I8042_CTR_AUXDIS bit */ 709d2ada559SRoland Scheidegger for (i = 0; i < 100; i++) { 710d2ada559SRoland Scheidegger udelay(50); 711d2ada559SRoland Scheidegger 712d2ada559SRoland Scheidegger if (i8042_command(¶m, I8042_CMD_CTL_RCTR)) 713d2ada559SRoland Scheidegger return -1; 714d2ada559SRoland Scheidegger 715d2ada559SRoland Scheidegger if (!(param & I8042_CTR_AUXDIS) == on) 716d2ada559SRoland Scheidegger return 0; 717d2ada559SRoland Scheidegger } 718d2ada559SRoland Scheidegger 719d2ada559SRoland Scheidegger return -1; 720d2ada559SRoland Scheidegger } 7211da177e4SLinus Torvalds 7221da177e4SLinus Torvalds /* 7231da177e4SLinus Torvalds * i8042_check_aux() applies as much paranoia as it can at detecting 7241da177e4SLinus Torvalds * the presence of an AUX interface. 7251da177e4SLinus Torvalds */ 7261da177e4SLinus Torvalds 727f8113416SDmitry Torokhov static int __init i8042_check_aux(void) 7281da177e4SLinus Torvalds { 729de9ce703SDmitry Torokhov int retval = -1; 730386b3849SDmitry Torokhov bool irq_registered = false; 731386b3849SDmitry Torokhov bool aux_loop_broken = false; 732de9ce703SDmitry Torokhov unsigned long flags; 7331da177e4SLinus Torvalds unsigned char param; 7341da177e4SLinus Torvalds 7351da177e4SLinus Torvalds /* 7361da177e4SLinus Torvalds * Get rid of bytes in the queue. 7371da177e4SLinus Torvalds */ 7381da177e4SLinus Torvalds 7391da177e4SLinus Torvalds i8042_flush(); 7401da177e4SLinus Torvalds 7411da177e4SLinus Torvalds /* 7421da177e4SLinus Torvalds * Internal loopback test - filters out AT-type i8042's. Unfortunately 7431da177e4SLinus Torvalds * SiS screwed up and their 5597 doesn't support the LOOP command even 7441da177e4SLinus Torvalds * though it has an AUX port. 7451da177e4SLinus Torvalds */ 7461da177e4SLinus Torvalds 7471da177e4SLinus Torvalds param = 0x5a; 7483ca5de6dSDmitry Torokhov retval = i8042_command(¶m, I8042_CMD_AUX_LOOP); 7493ca5de6dSDmitry Torokhov if (retval || param != 0x5a) { 7501da177e4SLinus Torvalds 7511da177e4SLinus Torvalds /* 7521da177e4SLinus Torvalds * External connection test - filters out AT-soldered PS/2 i8042's 7531da177e4SLinus Torvalds * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error 7541da177e4SLinus Torvalds * 0xfa - no error on some notebooks which ignore the spec 7551da177e4SLinus Torvalds * Because it's common for chipsets to return error on perfectly functioning 7561da177e4SLinus Torvalds * AUX ports, we test for this only when the LOOP command failed. 7571da177e4SLinus Torvalds */ 7581da177e4SLinus Torvalds 759de9ce703SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_TEST) || 760de9ce703SDmitry Torokhov (param && param != 0xfa && param != 0xff)) 7611da177e4SLinus Torvalds return -1; 7621e4865f8SDmitry Torokhov 7633ca5de6dSDmitry Torokhov /* 7643ca5de6dSDmitry Torokhov * If AUX_LOOP completed without error but returned unexpected data 7653ca5de6dSDmitry Torokhov * mark it as broken 7663ca5de6dSDmitry Torokhov */ 7673ca5de6dSDmitry Torokhov if (!retval) 768386b3849SDmitry Torokhov aux_loop_broken = true; 7691da177e4SLinus Torvalds } 7701da177e4SLinus Torvalds 7711da177e4SLinus Torvalds /* 7721da177e4SLinus Torvalds * Bit assignment test - filters out PS/2 i8042's in AT mode 7731da177e4SLinus Torvalds */ 7741da177e4SLinus Torvalds 775386b3849SDmitry Torokhov if (i8042_toggle_aux(false)) { 7761da177e4SLinus Torvalds printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n"); 7771da177e4SLinus Torvalds printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n"); 7781da177e4SLinus Torvalds } 7791da177e4SLinus Torvalds 780386b3849SDmitry Torokhov if (i8042_toggle_aux(true)) 7811da177e4SLinus Torvalds return -1; 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds /* 784de9ce703SDmitry Torokhov * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and 785de9ce703SDmitry Torokhov * used it for a PCI card or somethig else. 786de9ce703SDmitry Torokhov */ 787de9ce703SDmitry Torokhov 7881c7827aeSDmitry Torokhov if (i8042_noloop || i8042_bypass_aux_irq_test || aux_loop_broken) { 789de9ce703SDmitry Torokhov /* 790de9ce703SDmitry Torokhov * Without LOOP command we can't test AUX IRQ delivery. Assume the port 791de9ce703SDmitry Torokhov * is working and hope we are right. 792de9ce703SDmitry Torokhov */ 793de9ce703SDmitry Torokhov retval = 0; 794de9ce703SDmitry Torokhov goto out; 795de9ce703SDmitry Torokhov } 796de9ce703SDmitry Torokhov 797de9ce703SDmitry Torokhov if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED, 798de9ce703SDmitry Torokhov "i8042", i8042_platform_device)) 799de9ce703SDmitry Torokhov goto out; 800de9ce703SDmitry Torokhov 801386b3849SDmitry Torokhov irq_registered = true; 802de9ce703SDmitry Torokhov 803de9ce703SDmitry Torokhov if (i8042_enable_aux_port()) 804de9ce703SDmitry Torokhov goto out; 805de9ce703SDmitry Torokhov 806de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 807de9ce703SDmitry Torokhov 808de9ce703SDmitry Torokhov init_completion(&i8042_aux_irq_delivered); 809386b3849SDmitry Torokhov i8042_irq_being_tested = true; 810de9ce703SDmitry Torokhov 811de9ce703SDmitry Torokhov param = 0xa5; 812de9ce703SDmitry Torokhov retval = __i8042_command(¶m, I8042_CMD_AUX_LOOP & 0xf0ff); 813de9ce703SDmitry Torokhov 814de9ce703SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 815de9ce703SDmitry Torokhov 816de9ce703SDmitry Torokhov if (retval) 817de9ce703SDmitry Torokhov goto out; 818de9ce703SDmitry Torokhov 819de9ce703SDmitry Torokhov if (wait_for_completion_timeout(&i8042_aux_irq_delivered, 820de9ce703SDmitry Torokhov msecs_to_jiffies(250)) == 0) { 821de9ce703SDmitry Torokhov /* 822de9ce703SDmitry Torokhov * AUX IRQ was never delivered so we need to flush the controller to 823de9ce703SDmitry Torokhov * get rid of the byte we put there; otherwise keyboard may not work. 824de9ce703SDmitry Torokhov */ 825d3d2dfe2SDmitry Torokhov dbg(" -- i8042 (aux irq test timeout)"); 826de9ce703SDmitry Torokhov i8042_flush(); 827de9ce703SDmitry Torokhov retval = -1; 828de9ce703SDmitry Torokhov } 829de9ce703SDmitry Torokhov 830de9ce703SDmitry Torokhov out: 831de9ce703SDmitry Torokhov 832de9ce703SDmitry Torokhov /* 8331da177e4SLinus Torvalds * Disable the interface. 8341da177e4SLinus Torvalds */ 8351da177e4SLinus Torvalds 8361da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_AUXDIS; 8371da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_AUXINT; 8381da177e4SLinus Torvalds 8391da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 840de9ce703SDmitry Torokhov retval = -1; 841de9ce703SDmitry Torokhov 842de9ce703SDmitry Torokhov if (irq_registered) 843de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 844de9ce703SDmitry Torokhov 845de9ce703SDmitry Torokhov return retval; 846de9ce703SDmitry Torokhov } 847de9ce703SDmitry Torokhov 848de9ce703SDmitry Torokhov static int i8042_controller_check(void) 849de9ce703SDmitry Torokhov { 850de9ce703SDmitry Torokhov if (i8042_flush() == I8042_BUFFER_SIZE) { 851de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: No controller found.\n"); 852de9ce703SDmitry Torokhov return -ENODEV; 853de9ce703SDmitry Torokhov } 8541da177e4SLinus Torvalds 8551da177e4SLinus Torvalds return 0; 8561da177e4SLinus Torvalds } 8571da177e4SLinus Torvalds 858de9ce703SDmitry Torokhov static int i8042_controller_selftest(void) 8592673c836SVojtech Pavlik { 8602673c836SVojtech Pavlik unsigned char param; 8615ea2fc64SArjan van de Ven int i = 0; 8622673c836SVojtech Pavlik 8632673c836SVojtech Pavlik if (!i8042_reset) 8642673c836SVojtech Pavlik return 0; 8652673c836SVojtech Pavlik 8665ea2fc64SArjan van de Ven /* 8675ea2fc64SArjan van de Ven * We try this 5 times; on some really fragile systems this does not 8685ea2fc64SArjan van de Ven * take the first time... 8695ea2fc64SArjan van de Ven */ 8705ea2fc64SArjan van de Ven do { 8715ea2fc64SArjan van de Ven 8722673c836SVojtech Pavlik if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { 8732673c836SVojtech Pavlik printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); 874de9ce703SDmitry Torokhov return -ENODEV; 8752673c836SVojtech Pavlik } 8762673c836SVojtech Pavlik 8775ea2fc64SArjan van de Ven if (param == I8042_RET_CTL_TEST) 8785ea2fc64SArjan van de Ven return 0; 8795ea2fc64SArjan van de Ven 8802673c836SVojtech Pavlik printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", 8812673c836SVojtech Pavlik param, I8042_RET_CTL_TEST); 8825ea2fc64SArjan van de Ven msleep(50); 8835ea2fc64SArjan van de Ven } while (i++ < 5); 8842673c836SVojtech Pavlik 8855ea2fc64SArjan van de Ven #ifdef CONFIG_X86 8865ea2fc64SArjan van de Ven /* 8875ea2fc64SArjan van de Ven * On x86, we don't fail entire i8042 initialization if controller 8885ea2fc64SArjan van de Ven * reset fails in hopes that keyboard port will still be functional 8895ea2fc64SArjan van de Ven * and user will still get a working keyboard. This is especially 8905ea2fc64SArjan van de Ven * important on netbooks. On other arches we trust hardware more. 8915ea2fc64SArjan van de Ven */ 8925ea2fc64SArjan van de Ven printk(KERN_INFO 8935ea2fc64SArjan van de Ven "i8042: giving up on controller selftest, continuing anyway...\n"); 8942673c836SVojtech Pavlik return 0; 8955ea2fc64SArjan van de Ven #else 8965ea2fc64SArjan van de Ven return -EIO; 8975ea2fc64SArjan van de Ven #endif 8982673c836SVojtech Pavlik } 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds /* 9011da177e4SLinus Torvalds * i8042_controller init initializes the i8042 controller, and, 9021da177e4SLinus Torvalds * most importantly, sets it into non-xlated mode if that's 9031da177e4SLinus Torvalds * desired. 9041da177e4SLinus Torvalds */ 9051da177e4SLinus Torvalds 9061da177e4SLinus Torvalds static int i8042_controller_init(void) 9071da177e4SLinus Torvalds { 9081da177e4SLinus Torvalds unsigned long flags; 909ee1e82ceSDmitry Torokhov int n = 0; 910ee1e82ceSDmitry Torokhov unsigned char ctr[2]; 9111da177e4SLinus Torvalds 9121da177e4SLinus Torvalds /* 913ee1e82ceSDmitry Torokhov * Save the CTR for restore on unload / reboot. 9141da177e4SLinus Torvalds */ 9151da177e4SLinus Torvalds 916ee1e82ceSDmitry Torokhov do { 917ee1e82ceSDmitry Torokhov if (n >= 10) { 918ee1e82ceSDmitry Torokhov printk(KERN_ERR 919ee1e82ceSDmitry Torokhov "i8042.c: Unable to get stable CTR read.\n"); 920de9ce703SDmitry Torokhov return -EIO; 9211da177e4SLinus Torvalds } 9221da177e4SLinus Torvalds 923ee1e82ceSDmitry Torokhov if (n != 0) 924ee1e82ceSDmitry Torokhov udelay(50); 925ee1e82ceSDmitry Torokhov 926ee1e82ceSDmitry Torokhov if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) { 927ee1e82ceSDmitry Torokhov printk(KERN_ERR 928ee1e82ceSDmitry Torokhov "i8042.c: Can't read CTR while initializing i8042.\n"); 929ee1e82ceSDmitry Torokhov return -EIO; 930ee1e82ceSDmitry Torokhov } 931ee1e82ceSDmitry Torokhov 932ee1e82ceSDmitry Torokhov } while (n < 2 || ctr[0] != ctr[1]); 933ee1e82ceSDmitry Torokhov 934ee1e82ceSDmitry Torokhov i8042_initial_ctr = i8042_ctr = ctr[0]; 9351da177e4SLinus Torvalds 9361da177e4SLinus Torvalds /* 9371da177e4SLinus Torvalds * Disable the keyboard interface and interrupt. 9381da177e4SLinus Torvalds */ 9391da177e4SLinus Torvalds 9401da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_KBDDIS; 9411da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_KBDINT; 9421da177e4SLinus Torvalds 9431da177e4SLinus Torvalds /* 9441da177e4SLinus Torvalds * Handle keylock. 9451da177e4SLinus Torvalds */ 9461da177e4SLinus Torvalds 9471da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 9481da177e4SLinus Torvalds if (~i8042_read_status() & I8042_STR_KEYLOCK) { 9491da177e4SLinus Torvalds if (i8042_unlock) 9501da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_IGNKEYLOCK; 9511da177e4SLinus Torvalds else 9521da177e4SLinus Torvalds printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); 9531da177e4SLinus Torvalds } 9541da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 9551da177e4SLinus Torvalds 9561da177e4SLinus Torvalds /* 9571da177e4SLinus Torvalds * If the chip is configured into nontranslated mode by the BIOS, don't 9581da177e4SLinus Torvalds * bother enabling translating and be happy. 9591da177e4SLinus Torvalds */ 9601da177e4SLinus Torvalds 9611da177e4SLinus Torvalds if (~i8042_ctr & I8042_CTR_XLATE) 962386b3849SDmitry Torokhov i8042_direct = true; 9631da177e4SLinus Torvalds 9641da177e4SLinus Torvalds /* 9651da177e4SLinus Torvalds * Set nontranslated mode for the kbd interface if requested by an option. 9661da177e4SLinus Torvalds * After this the kbd interface becomes a simple serial in/out, like the aux 9671da177e4SLinus Torvalds * interface is. We don't do this by default, since it can confuse notebook 9681da177e4SLinus Torvalds * BIOSes. 9691da177e4SLinus Torvalds */ 9701da177e4SLinus Torvalds 9711da177e4SLinus Torvalds if (i8042_direct) 9721da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_XLATE; 9731da177e4SLinus Torvalds 9741da177e4SLinus Torvalds /* 9751da177e4SLinus Torvalds * Write CTR back. 9761da177e4SLinus Torvalds */ 9771da177e4SLinus Torvalds 9781da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 9791da177e4SLinus Torvalds printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); 980de9ce703SDmitry Torokhov return -EIO; 9811da177e4SLinus Torvalds } 9821da177e4SLinus Torvalds 983ee1e82ceSDmitry Torokhov /* 984ee1e82ceSDmitry Torokhov * Flush whatever accumulated while we were disabling keyboard port. 985ee1e82ceSDmitry Torokhov */ 986ee1e82ceSDmitry Torokhov 987ee1e82ceSDmitry Torokhov i8042_flush(); 988ee1e82ceSDmitry Torokhov 9891da177e4SLinus Torvalds return 0; 9901da177e4SLinus Torvalds } 9911da177e4SLinus Torvalds 9921da177e4SLinus Torvalds 9931da177e4SLinus Torvalds /* 994de9ce703SDmitry Torokhov * Reset the controller and reset CRT to the original value set by BIOS. 9951da177e4SLinus Torvalds */ 9961da177e4SLinus Torvalds 997de9ce703SDmitry Torokhov static void i8042_controller_reset(void) 998de9ce703SDmitry Torokhov { 999de9ce703SDmitry Torokhov i8042_flush(); 10001da177e4SLinus Torvalds 10011da177e4SLinus Torvalds /* 10028d04ddb6SDmitry Torokhov * Disable both KBD and AUX interfaces so they don't get in the way 10038d04ddb6SDmitry Torokhov */ 10048d04ddb6SDmitry Torokhov 10058d04ddb6SDmitry Torokhov i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS; 10068d04ddb6SDmitry Torokhov i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT); 10078d04ddb6SDmitry Torokhov 1008ee1e82ceSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 10095ddbc77cSDmitry Torokhov printk(KERN_WARNING "i8042.c: Can't write CTR while resetting.\n"); 10105ddbc77cSDmitry Torokhov 10118d04ddb6SDmitry Torokhov /* 10121da177e4SLinus Torvalds * Disable MUX mode if present. 10131da177e4SLinus Torvalds */ 10141da177e4SLinus Torvalds 10151da177e4SLinus Torvalds if (i8042_mux_present) 1016386b3849SDmitry Torokhov i8042_set_mux_mode(false, NULL); 10171da177e4SLinus Torvalds 10181da177e4SLinus Torvalds /* 1019de9ce703SDmitry Torokhov * Reset the controller if requested. 1020de9ce703SDmitry Torokhov */ 1021de9ce703SDmitry Torokhov 1022de9ce703SDmitry Torokhov i8042_controller_selftest(); 1023de9ce703SDmitry Torokhov 1024de9ce703SDmitry Torokhov /* 10251da177e4SLinus Torvalds * Restore the original control register setting. 10261da177e4SLinus Torvalds */ 10271da177e4SLinus Torvalds 1028de9ce703SDmitry Torokhov if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR)) 10291da177e4SLinus Torvalds printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); 10301da177e4SLinus Torvalds } 10311da177e4SLinus Torvalds 10321da177e4SLinus Torvalds 10331da177e4SLinus Torvalds /* 10341da177e4SLinus Torvalds * i8042_panic_blink() will flash the keyboard LEDs and is called when 10351da177e4SLinus Torvalds * kernel panics. Flashing LEDs is useful for users running X who may 10361da177e4SLinus Torvalds * not see the console and will help distingushing panics from "real" 10371da177e4SLinus Torvalds * lockups. 10381da177e4SLinus Torvalds * 10391da177e4SLinus Torvalds * Note that DELAY has a limit of 10ms so we will not get stuck here 10401da177e4SLinus Torvalds * waiting for KBC to free up even if KBD interrupt is off 10411da177e4SLinus Torvalds */ 10421da177e4SLinus Torvalds 10431da177e4SLinus Torvalds #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0) 10441da177e4SLinus Torvalds 10451da177e4SLinus Torvalds static long i8042_panic_blink(long count) 10461da177e4SLinus Torvalds { 10471da177e4SLinus Torvalds long delay = 0; 10481da177e4SLinus Torvalds static long last_blink; 10491da177e4SLinus Torvalds static char led; 10501da177e4SLinus Torvalds 10511da177e4SLinus Torvalds /* 10521da177e4SLinus Torvalds * We expect frequency to be about 1/2s. KDB uses about 1s. 10531da177e4SLinus Torvalds * Make sure they are different. 10541da177e4SLinus Torvalds */ 10551da177e4SLinus Torvalds if (!i8042_blink_frequency) 10561da177e4SLinus Torvalds return 0; 10571da177e4SLinus Torvalds if (count - last_blink < i8042_blink_frequency) 10581da177e4SLinus Torvalds return 0; 10591da177e4SLinus Torvalds 10601da177e4SLinus Torvalds led ^= 0x01 | 0x04; 10611da177e4SLinus Torvalds while (i8042_read_status() & I8042_STR_IBF) 10621da177e4SLinus Torvalds DELAY; 106319f3c3e3SDmitry Torokhov dbg("%02x -> i8042 (panic blink)", 0xed); 106419f3c3e3SDmitry Torokhov i8042_suppress_kbd_ack = 2; 10651da177e4SLinus Torvalds i8042_write_data(0xed); /* set leds */ 10661da177e4SLinus Torvalds DELAY; 10671da177e4SLinus Torvalds while (i8042_read_status() & I8042_STR_IBF) 10681da177e4SLinus Torvalds DELAY; 10691da177e4SLinus Torvalds DELAY; 107019f3c3e3SDmitry Torokhov dbg("%02x -> i8042 (panic blink)", led); 10711da177e4SLinus Torvalds i8042_write_data(led); 10721da177e4SLinus Torvalds DELAY; 10731da177e4SLinus Torvalds last_blink = count; 10741da177e4SLinus Torvalds return delay; 10751da177e4SLinus Torvalds } 10761da177e4SLinus Torvalds 10771da177e4SLinus Torvalds #undef DELAY 10781da177e4SLinus Torvalds 1079d35895dbSBruno Prémont #ifdef CONFIG_X86 1080d35895dbSBruno Prémont static void i8042_dritek_enable(void) 1081d35895dbSBruno Prémont { 1082d35895dbSBruno Prémont char param = 0x90; 1083d35895dbSBruno Prémont int error; 1084d35895dbSBruno Prémont 1085d35895dbSBruno Prémont error = i8042_command(¶m, 0x1059); 1086d35895dbSBruno Prémont if (error) 1087d35895dbSBruno Prémont printk(KERN_WARNING 1088d35895dbSBruno Prémont "Failed to enable DRITEK extension: %d\n", 1089d35895dbSBruno Prémont error); 1090d35895dbSBruno Prémont } 1091d35895dbSBruno Prémont #endif 1092d35895dbSBruno Prémont 109382dd9effSDmitry Torokhov #ifdef CONFIG_PM 10947e044e05SDmitry Torokhov 10951da177e4SLinus Torvalds /* 1096ebd7768dSDmitry Torokhov * Here we try to restore the original BIOS settings to avoid 1097ebd7768dSDmitry Torokhov * upsetting it. 10981da177e4SLinus Torvalds */ 10991da177e4SLinus Torvalds 1100ebd7768dSDmitry Torokhov static int i8042_pm_reset(struct device *dev) 11011da177e4SLinus Torvalds { 110282dd9effSDmitry Torokhov i8042_controller_reset(); 1103ddaa4343SThadeu Lima de Souza Cascardo 11041da177e4SLinus Torvalds return 0; 11051da177e4SLinus Torvalds } 11061da177e4SLinus Torvalds 11071da177e4SLinus Torvalds /* 1108ebd7768dSDmitry Torokhov * Here we try to reset everything back to a state we had 1109ebd7768dSDmitry Torokhov * before suspending. 11101da177e4SLinus Torvalds */ 11111da177e4SLinus Torvalds 1112ebd7768dSDmitry Torokhov static int i8042_pm_restore(struct device *dev) 11131da177e4SLinus Torvalds { 1114de9ce703SDmitry Torokhov int error; 11151da177e4SLinus Torvalds 1116de9ce703SDmitry Torokhov error = i8042_controller_check(); 1117de9ce703SDmitry Torokhov if (error) 1118de9ce703SDmitry Torokhov return error; 11192673c836SVojtech Pavlik 1120de9ce703SDmitry Torokhov error = i8042_controller_selftest(); 1121de9ce703SDmitry Torokhov if (error) 1122de9ce703SDmitry Torokhov return error; 1123de9ce703SDmitry Torokhov 1124de9ce703SDmitry Torokhov /* 112582dd9effSDmitry Torokhov * Restore original CTR value and disable all ports 1126de9ce703SDmitry Torokhov */ 1127de9ce703SDmitry Torokhov 112882dd9effSDmitry Torokhov i8042_ctr = i8042_initial_ctr; 112982dd9effSDmitry Torokhov if (i8042_direct) 113082dd9effSDmitry Torokhov i8042_ctr &= ~I8042_CTR_XLATE; 1131de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS; 1132de9ce703SDmitry Torokhov i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT); 11332673c836SVojtech Pavlik if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 11342f6a77d5SJiri Kosina printk(KERN_WARNING "i8042: Can't write CTR to resume, retrying...\n"); 11352f6a77d5SJiri Kosina msleep(50); 11362f6a77d5SJiri Kosina if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 11372f6a77d5SJiri Kosina printk(KERN_ERR "i8042: CTR write retry failed\n"); 1138de9ce703SDmitry Torokhov return -EIO; 11391da177e4SLinus Torvalds } 11402f6a77d5SJiri Kosina } 11411da177e4SLinus Torvalds 1142d35895dbSBruno Prémont 1143d35895dbSBruno Prémont #ifdef CONFIG_X86 1144d35895dbSBruno Prémont if (i8042_dritek) 1145d35895dbSBruno Prémont i8042_dritek_enable(); 1146d35895dbSBruno Prémont #endif 1147d35895dbSBruno Prémont 1148de9ce703SDmitry Torokhov if (i8042_mux_present) { 1149386b3849SDmitry Torokhov if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports()) 1150de9ce703SDmitry Torokhov printk(KERN_WARNING 1151de9ce703SDmitry Torokhov "i8042: failed to resume active multiplexor, " 1152de9ce703SDmitry Torokhov "mouse won't work.\n"); 1153de9ce703SDmitry Torokhov } else if (i8042_ports[I8042_AUX_PORT_NO].serio) 1154de9ce703SDmitry Torokhov i8042_enable_aux_port(); 11551da177e4SLinus Torvalds 1156de9ce703SDmitry Torokhov if (i8042_ports[I8042_KBD_PORT_NO].serio) 1157de9ce703SDmitry Torokhov i8042_enable_kbd_port(); 11581da177e4SLinus Torvalds 11597d12e780SDavid Howells i8042_interrupt(0, NULL); 11601da177e4SLinus Torvalds 11611da177e4SLinus Torvalds return 0; 11621da177e4SLinus Torvalds } 1163ebd7768dSDmitry Torokhov 1164ebd7768dSDmitry Torokhov static const struct dev_pm_ops i8042_pm_ops = { 1165ebd7768dSDmitry Torokhov .suspend = i8042_pm_reset, 1166ebd7768dSDmitry Torokhov .resume = i8042_pm_restore, 1167ebd7768dSDmitry Torokhov .poweroff = i8042_pm_reset, 1168ebd7768dSDmitry Torokhov .restore = i8042_pm_restore, 1169ebd7768dSDmitry Torokhov }; 1170ebd7768dSDmitry Torokhov 117182dd9effSDmitry Torokhov #endif /* CONFIG_PM */ 11721da177e4SLinus Torvalds 11731da177e4SLinus Torvalds /* 11741da177e4SLinus Torvalds * We need to reset the 8042 back to original mode on system shutdown, 11751da177e4SLinus Torvalds * because otherwise BIOSes will be confused. 11761da177e4SLinus Torvalds */ 11771da177e4SLinus Torvalds 11783ae5eaecSRussell King static void i8042_shutdown(struct platform_device *dev) 11791da177e4SLinus Torvalds { 118082dd9effSDmitry Torokhov i8042_controller_reset(); 11811da177e4SLinus Torvalds } 11821da177e4SLinus Torvalds 1183f8113416SDmitry Torokhov static int __init i8042_create_kbd_port(void) 11841da177e4SLinus Torvalds { 11851da177e4SLinus Torvalds struct serio *serio; 11861da177e4SLinus Torvalds struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; 11871da177e4SLinus Torvalds 1188d39969deSDmitry Torokhov serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 11890854e52dSDmitry Torokhov if (!serio) 11900854e52dSDmitry Torokhov return -ENOMEM; 11910854e52dSDmitry Torokhov 11921da177e4SLinus Torvalds serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; 11931da177e4SLinus Torvalds serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; 11941da177e4SLinus Torvalds serio->start = i8042_start; 11951da177e4SLinus Torvalds serio->stop = i8042_stop; 11965ddbc77cSDmitry Torokhov serio->close = i8042_port_close; 11971da177e4SLinus Torvalds serio->port_data = port; 11981da177e4SLinus Torvalds serio->dev.parent = &i8042_platform_device->dev; 1199de9ce703SDmitry Torokhov strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); 12001da177e4SLinus Torvalds strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); 12011da177e4SLinus Torvalds 12021da177e4SLinus Torvalds port->serio = serio; 1203de9ce703SDmitry Torokhov port->irq = I8042_KBD_IRQ; 12040854e52dSDmitry Torokhov 1205de9ce703SDmitry Torokhov return 0; 12061da177e4SLinus Torvalds } 12071da177e4SLinus Torvalds 1208f8113416SDmitry Torokhov static int __init i8042_create_aux_port(int idx) 12091da177e4SLinus Torvalds { 12101da177e4SLinus Torvalds struct serio *serio; 1211de9ce703SDmitry Torokhov int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx; 1212de9ce703SDmitry Torokhov struct i8042_port *port = &i8042_ports[port_no]; 12131da177e4SLinus Torvalds 1214d39969deSDmitry Torokhov serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 12150854e52dSDmitry Torokhov if (!serio) 12160854e52dSDmitry Torokhov return -ENOMEM; 12170854e52dSDmitry Torokhov 12181da177e4SLinus Torvalds serio->id.type = SERIO_8042; 12191da177e4SLinus Torvalds serio->write = i8042_aux_write; 12201da177e4SLinus Torvalds serio->start = i8042_start; 12211da177e4SLinus Torvalds serio->stop = i8042_stop; 12221da177e4SLinus Torvalds serio->port_data = port; 12231da177e4SLinus Torvalds serio->dev.parent = &i8042_platform_device->dev; 1224de9ce703SDmitry Torokhov if (idx < 0) { 1225de9ce703SDmitry Torokhov strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name)); 12261da177e4SLinus Torvalds strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); 12275ddbc77cSDmitry Torokhov serio->close = i8042_port_close; 1228de9ce703SDmitry Torokhov } else { 1229de9ce703SDmitry Torokhov snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx); 1230de9ce703SDmitry Torokhov snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1); 12311da177e4SLinus Torvalds } 12321da177e4SLinus Torvalds 12331da177e4SLinus Torvalds port->serio = serio; 1234de9ce703SDmitry Torokhov port->mux = idx; 1235de9ce703SDmitry Torokhov port->irq = I8042_AUX_IRQ; 12360854e52dSDmitry Torokhov 1237de9ce703SDmitry Torokhov return 0; 1238de9ce703SDmitry Torokhov } 1239de9ce703SDmitry Torokhov 1240f8113416SDmitry Torokhov static void __init i8042_free_kbd_port(void) 1241de9ce703SDmitry Torokhov { 1242de9ce703SDmitry Torokhov kfree(i8042_ports[I8042_KBD_PORT_NO].serio); 1243de9ce703SDmitry Torokhov i8042_ports[I8042_KBD_PORT_NO].serio = NULL; 1244de9ce703SDmitry Torokhov } 1245de9ce703SDmitry Torokhov 1246f8113416SDmitry Torokhov static void __init i8042_free_aux_ports(void) 1247de9ce703SDmitry Torokhov { 1248de9ce703SDmitry Torokhov int i; 1249de9ce703SDmitry Torokhov 1250de9ce703SDmitry Torokhov for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) { 1251de9ce703SDmitry Torokhov kfree(i8042_ports[i].serio); 1252de9ce703SDmitry Torokhov i8042_ports[i].serio = NULL; 1253de9ce703SDmitry Torokhov } 1254de9ce703SDmitry Torokhov } 1255de9ce703SDmitry Torokhov 1256f8113416SDmitry Torokhov static void __init i8042_register_ports(void) 1257de9ce703SDmitry Torokhov { 1258de9ce703SDmitry Torokhov int i; 1259de9ce703SDmitry Torokhov 1260de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) { 1261de9ce703SDmitry Torokhov if (i8042_ports[i].serio) { 1262de9ce703SDmitry Torokhov printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n", 1263de9ce703SDmitry Torokhov i8042_ports[i].serio->name, 1264de9ce703SDmitry Torokhov (unsigned long) I8042_DATA_REG, 1265de9ce703SDmitry Torokhov (unsigned long) I8042_COMMAND_REG, 1266de9ce703SDmitry Torokhov i8042_ports[i].irq); 1267de9ce703SDmitry Torokhov serio_register_port(i8042_ports[i].serio); 1268de9ce703SDmitry Torokhov } 1269de9ce703SDmitry Torokhov } 1270de9ce703SDmitry Torokhov } 1271de9ce703SDmitry Torokhov 12727a1904c3SRalf Baechle static void __devexit i8042_unregister_ports(void) 1273de9ce703SDmitry Torokhov { 1274de9ce703SDmitry Torokhov int i; 1275de9ce703SDmitry Torokhov 1276de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) { 1277de9ce703SDmitry Torokhov if (i8042_ports[i].serio) { 1278de9ce703SDmitry Torokhov serio_unregister_port(i8042_ports[i].serio); 1279de9ce703SDmitry Torokhov i8042_ports[i].serio = NULL; 1280de9ce703SDmitry Torokhov } 1281de9ce703SDmitry Torokhov } 1282de9ce703SDmitry Torokhov } 1283de9ce703SDmitry Torokhov 1284181d683dSDmitry Torokhov /* 1285181d683dSDmitry Torokhov * Checks whether port belongs to i8042 controller. 1286181d683dSDmitry Torokhov */ 1287181d683dSDmitry Torokhov bool i8042_check_port_owner(const struct serio *port) 1288181d683dSDmitry Torokhov { 1289181d683dSDmitry Torokhov int i; 1290181d683dSDmitry Torokhov 1291181d683dSDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) 1292181d683dSDmitry Torokhov if (i8042_ports[i].serio == port) 1293181d683dSDmitry Torokhov return true; 1294181d683dSDmitry Torokhov 1295181d683dSDmitry Torokhov return false; 1296181d683dSDmitry Torokhov } 1297181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_check_port_owner); 1298181d683dSDmitry Torokhov 1299de9ce703SDmitry Torokhov static void i8042_free_irqs(void) 1300de9ce703SDmitry Torokhov { 1301de9ce703SDmitry Torokhov if (i8042_aux_irq_registered) 1302de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 1303de9ce703SDmitry Torokhov if (i8042_kbd_irq_registered) 1304de9ce703SDmitry Torokhov free_irq(I8042_KBD_IRQ, i8042_platform_device); 1305de9ce703SDmitry Torokhov 1306386b3849SDmitry Torokhov i8042_aux_irq_registered = i8042_kbd_irq_registered = false; 1307de9ce703SDmitry Torokhov } 1308de9ce703SDmitry Torokhov 1309f8113416SDmitry Torokhov static int __init i8042_setup_aux(void) 1310de9ce703SDmitry Torokhov { 1311de9ce703SDmitry Torokhov int (*aux_enable)(void); 1312de9ce703SDmitry Torokhov int error; 1313de9ce703SDmitry Torokhov int i; 1314de9ce703SDmitry Torokhov 1315de9ce703SDmitry Torokhov if (i8042_check_aux()) 1316de9ce703SDmitry Torokhov return -ENODEV; 1317de9ce703SDmitry Torokhov 1318de9ce703SDmitry Torokhov if (i8042_nomux || i8042_check_mux()) { 1319de9ce703SDmitry Torokhov error = i8042_create_aux_port(-1); 1320de9ce703SDmitry Torokhov if (error) 1321de9ce703SDmitry Torokhov goto err_free_ports; 1322de9ce703SDmitry Torokhov aux_enable = i8042_enable_aux_port; 1323de9ce703SDmitry Torokhov } else { 1324de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { 1325de9ce703SDmitry Torokhov error = i8042_create_aux_port(i); 1326de9ce703SDmitry Torokhov if (error) 1327de9ce703SDmitry Torokhov goto err_free_ports; 1328de9ce703SDmitry Torokhov } 1329de9ce703SDmitry Torokhov aux_enable = i8042_enable_mux_ports; 1330de9ce703SDmitry Torokhov } 1331de9ce703SDmitry Torokhov 1332de9ce703SDmitry Torokhov error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED, 1333de9ce703SDmitry Torokhov "i8042", i8042_platform_device); 1334de9ce703SDmitry Torokhov if (error) 1335de9ce703SDmitry Torokhov goto err_free_ports; 1336de9ce703SDmitry Torokhov 1337de9ce703SDmitry Torokhov if (aux_enable()) 1338de9ce703SDmitry Torokhov goto err_free_irq; 1339de9ce703SDmitry Torokhov 1340386b3849SDmitry Torokhov i8042_aux_irq_registered = true; 1341de9ce703SDmitry Torokhov return 0; 1342de9ce703SDmitry Torokhov 1343de9ce703SDmitry Torokhov err_free_irq: 1344de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 1345de9ce703SDmitry Torokhov err_free_ports: 1346de9ce703SDmitry Torokhov i8042_free_aux_ports(); 1347de9ce703SDmitry Torokhov return error; 1348de9ce703SDmitry Torokhov } 1349de9ce703SDmitry Torokhov 1350f8113416SDmitry Torokhov static int __init i8042_setup_kbd(void) 1351de9ce703SDmitry Torokhov { 1352de9ce703SDmitry Torokhov int error; 1353de9ce703SDmitry Torokhov 1354de9ce703SDmitry Torokhov error = i8042_create_kbd_port(); 1355de9ce703SDmitry Torokhov if (error) 1356de9ce703SDmitry Torokhov return error; 1357de9ce703SDmitry Torokhov 1358de9ce703SDmitry Torokhov error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED, 1359de9ce703SDmitry Torokhov "i8042", i8042_platform_device); 1360de9ce703SDmitry Torokhov if (error) 1361de9ce703SDmitry Torokhov goto err_free_port; 1362de9ce703SDmitry Torokhov 1363de9ce703SDmitry Torokhov error = i8042_enable_kbd_port(); 1364de9ce703SDmitry Torokhov if (error) 1365de9ce703SDmitry Torokhov goto err_free_irq; 1366de9ce703SDmitry Torokhov 1367386b3849SDmitry Torokhov i8042_kbd_irq_registered = true; 1368de9ce703SDmitry Torokhov return 0; 1369de9ce703SDmitry Torokhov 1370de9ce703SDmitry Torokhov err_free_irq: 1371de9ce703SDmitry Torokhov free_irq(I8042_KBD_IRQ, i8042_platform_device); 1372de9ce703SDmitry Torokhov err_free_port: 1373de9ce703SDmitry Torokhov i8042_free_kbd_port(); 1374de9ce703SDmitry Torokhov return error; 13751da177e4SLinus Torvalds } 13761da177e4SLinus Torvalds 1377f8113416SDmitry Torokhov static int __init i8042_probe(struct platform_device *dev) 13781da177e4SLinus Torvalds { 1379de9ce703SDmitry Torokhov int error; 13801da177e4SLinus Torvalds 1381de9ce703SDmitry Torokhov error = i8042_controller_selftest(); 1382de9ce703SDmitry Torokhov if (error) 1383de9ce703SDmitry Torokhov return error; 13841da177e4SLinus Torvalds 1385de9ce703SDmitry Torokhov error = i8042_controller_init(); 1386de9ce703SDmitry Torokhov if (error) 1387de9ce703SDmitry Torokhov return error; 13881da177e4SLinus Torvalds 1389d35895dbSBruno Prémont #ifdef CONFIG_X86 1390d35895dbSBruno Prémont if (i8042_dritek) 1391d35895dbSBruno Prémont i8042_dritek_enable(); 1392d35895dbSBruno Prémont #endif 1393d35895dbSBruno Prémont 1394de9ce703SDmitry Torokhov if (!i8042_noaux) { 1395de9ce703SDmitry Torokhov error = i8042_setup_aux(); 1396de9ce703SDmitry Torokhov if (error && error != -ENODEV && error != -EBUSY) 1397de9ce703SDmitry Torokhov goto out_fail; 13981da177e4SLinus Torvalds } 13991da177e4SLinus Torvalds 1400945ef0d4SDmitry Torokhov if (!i8042_nokbd) { 1401de9ce703SDmitry Torokhov error = i8042_setup_kbd(); 1402de9ce703SDmitry Torokhov if (error) 1403de9ce703SDmitry Torokhov goto out_fail; 1404945ef0d4SDmitry Torokhov } 1405de9ce703SDmitry Torokhov /* 1406de9ce703SDmitry Torokhov * Ok, everything is ready, let's register all serio ports 1407de9ce703SDmitry Torokhov */ 1408de9ce703SDmitry Torokhov i8042_register_ports(); 14091da177e4SLinus Torvalds 14101da177e4SLinus Torvalds return 0; 14110854e52dSDmitry Torokhov 1412de9ce703SDmitry Torokhov out_fail: 1413de9ce703SDmitry Torokhov i8042_free_aux_ports(); /* in case KBD failed but AUX not */ 1414de9ce703SDmitry Torokhov i8042_free_irqs(); 1415de9ce703SDmitry Torokhov i8042_controller_reset(); 14160854e52dSDmitry Torokhov 1417de9ce703SDmitry Torokhov return error; 14181da177e4SLinus Torvalds } 14191da177e4SLinus Torvalds 142087fd6318SDmitry Torokhov static int __devexit i8042_remove(struct platform_device *dev) 14211da177e4SLinus Torvalds { 1422de9ce703SDmitry Torokhov i8042_unregister_ports(); 1423de9ce703SDmitry Torokhov i8042_free_irqs(); 1424de9ce703SDmitry Torokhov i8042_controller_reset(); 14251da177e4SLinus Torvalds 142687fd6318SDmitry Torokhov return 0; 142787fd6318SDmitry Torokhov } 142887fd6318SDmitry Torokhov 142987fd6318SDmitry Torokhov static struct platform_driver i8042_driver = { 143087fd6318SDmitry Torokhov .driver = { 143187fd6318SDmitry Torokhov .name = "i8042", 143287fd6318SDmitry Torokhov .owner = THIS_MODULE, 1433ebd7768dSDmitry Torokhov #ifdef CONFIG_PM 1434ebd7768dSDmitry Torokhov .pm = &i8042_pm_ops, 1435ebd7768dSDmitry Torokhov #endif 143687fd6318SDmitry Torokhov }, 143787fd6318SDmitry Torokhov .remove = __devexit_p(i8042_remove), 143882dd9effSDmitry Torokhov .shutdown = i8042_shutdown, 143987fd6318SDmitry Torokhov }; 144087fd6318SDmitry Torokhov 144187fd6318SDmitry Torokhov static int __init i8042_init(void) 144287fd6318SDmitry Torokhov { 144387fd6318SDmitry Torokhov int err; 144487fd6318SDmitry Torokhov 144587fd6318SDmitry Torokhov dbg_init(); 144687fd6318SDmitry Torokhov 144787fd6318SDmitry Torokhov err = i8042_platform_init(); 144887fd6318SDmitry Torokhov if (err) 144987fd6318SDmitry Torokhov return err; 145087fd6318SDmitry Torokhov 1451de9ce703SDmitry Torokhov err = i8042_controller_check(); 1452de9ce703SDmitry Torokhov if (err) 1453de9ce703SDmitry Torokhov goto err_platform_exit; 145487fd6318SDmitry Torokhov 145587fd6318SDmitry Torokhov i8042_platform_device = platform_device_alloc("i8042", -1); 145687fd6318SDmitry Torokhov if (!i8042_platform_device) { 145787fd6318SDmitry Torokhov err = -ENOMEM; 1458f8113416SDmitry Torokhov goto err_platform_exit; 145987fd6318SDmitry Torokhov } 146087fd6318SDmitry Torokhov 146187fd6318SDmitry Torokhov err = platform_device_add(i8042_platform_device); 146287fd6318SDmitry Torokhov if (err) 146387fd6318SDmitry Torokhov goto err_free_device; 146487fd6318SDmitry Torokhov 1465f8113416SDmitry Torokhov err = platform_driver_probe(&i8042_driver, i8042_probe); 1466f8113416SDmitry Torokhov if (err) 1467f8113416SDmitry Torokhov goto err_del_device; 1468f8113416SDmitry Torokhov 1469de9ce703SDmitry Torokhov panic_blink = i8042_panic_blink; 1470de9ce703SDmitry Torokhov 147187fd6318SDmitry Torokhov return 0; 147287fd6318SDmitry Torokhov 1473f8113416SDmitry Torokhov err_del_device: 1474f8113416SDmitry Torokhov platform_device_del(i8042_platform_device); 147587fd6318SDmitry Torokhov err_free_device: 147687fd6318SDmitry Torokhov platform_device_put(i8042_platform_device); 147787fd6318SDmitry Torokhov err_platform_exit: 147887fd6318SDmitry Torokhov i8042_platform_exit(); 147987fd6318SDmitry Torokhov 148087fd6318SDmitry Torokhov return err; 148187fd6318SDmitry Torokhov } 148287fd6318SDmitry Torokhov 148387fd6318SDmitry Torokhov static void __exit i8042_exit(void) 148487fd6318SDmitry Torokhov { 14853ae5eaecSRussell King platform_driver_unregister(&i8042_driver); 1486f8113416SDmitry Torokhov platform_device_unregister(i8042_platform_device); 14871da177e4SLinus Torvalds i8042_platform_exit(); 14881da177e4SLinus Torvalds 14891da177e4SLinus Torvalds panic_blink = NULL; 14901da177e4SLinus Torvalds } 14911da177e4SLinus Torvalds 14921da177e4SLinus Torvalds module_init(i8042_init); 14931da177e4SLinus Torvalds module_exit(i8042_exit); 1494