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); 1291da177e4SLinus Torvalds 130181d683dSDmitry Torokhov void i8042_lock_chip(void) 131181d683dSDmitry Torokhov { 132181d683dSDmitry Torokhov mutex_lock(&i8042_mutex); 133181d683dSDmitry Torokhov } 134181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_lock_chip); 135181d683dSDmitry Torokhov 136181d683dSDmitry Torokhov void i8042_unlock_chip(void) 137181d683dSDmitry Torokhov { 138181d683dSDmitry Torokhov mutex_unlock(&i8042_mutex); 139181d683dSDmitry Torokhov } 140181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_unlock_chip); 141181d683dSDmitry Torokhov 1421da177e4SLinus Torvalds /* 1431da177e4SLinus Torvalds * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to 1441da177e4SLinus Torvalds * be ready for reading values from it / writing values to it. 1451da177e4SLinus Torvalds * Called always with i8042_lock held. 1461da177e4SLinus Torvalds */ 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds static int i8042_wait_read(void) 1491da177e4SLinus Torvalds { 1501da177e4SLinus Torvalds int i = 0; 151de9ce703SDmitry Torokhov 1521da177e4SLinus Torvalds while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { 1531da177e4SLinus Torvalds udelay(50); 1541da177e4SLinus Torvalds i++; 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds return -(i == I8042_CTL_TIMEOUT); 1571da177e4SLinus Torvalds } 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds static int i8042_wait_write(void) 1601da177e4SLinus Torvalds { 1611da177e4SLinus Torvalds int i = 0; 162de9ce703SDmitry Torokhov 1631da177e4SLinus Torvalds while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { 1641da177e4SLinus Torvalds udelay(50); 1651da177e4SLinus Torvalds i++; 1661da177e4SLinus Torvalds } 1671da177e4SLinus Torvalds return -(i == I8042_CTL_TIMEOUT); 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds /* 1711da177e4SLinus Torvalds * i8042_flush() flushes all data that may be in the keyboard and mouse buffers 1721da177e4SLinus Torvalds * of the i8042 down the toilet. 1731da177e4SLinus Torvalds */ 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds static int i8042_flush(void) 1761da177e4SLinus Torvalds { 1771da177e4SLinus Torvalds unsigned long flags; 1781da177e4SLinus Torvalds unsigned char data, str; 1791da177e4SLinus Torvalds int i = 0; 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) { 1841da177e4SLinus Torvalds udelay(50); 1851da177e4SLinus Torvalds data = i8042_read_data(); 1861da177e4SLinus Torvalds i++; 1871da177e4SLinus Torvalds dbg("%02x <- i8042 (flush, %s)", data, 1881da177e4SLinus Torvalds str & I8042_STR_AUXDATA ? "aux" : "kbd"); 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds return i; 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds /* 1971da177e4SLinus Torvalds * i8042_command() executes a command on the i8042. It also sends the input 1981da177e4SLinus Torvalds * parameter(s) of the commands to it, and receives the output value(s). The 1991da177e4SLinus Torvalds * parameters are to be stored in the param array, and the output is placed 2001da177e4SLinus Torvalds * into the same array. The number of the parameters and output values is 2011da177e4SLinus Torvalds * encoded in bits 8-11 of the command number. 2021da177e4SLinus Torvalds */ 2031da177e4SLinus Torvalds 204de9ce703SDmitry Torokhov static int __i8042_command(unsigned char *param, int command) 2051da177e4SLinus Torvalds { 206de9ce703SDmitry Torokhov int i, error; 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds if (i8042_noloop && command == I8042_CMD_AUX_LOOP) 2091da177e4SLinus Torvalds return -1; 2101da177e4SLinus Torvalds 211de9ce703SDmitry Torokhov error = i8042_wait_write(); 212de9ce703SDmitry Torokhov if (error) 213de9ce703SDmitry Torokhov return error; 214463a4f76SDmitry Torokhov 2151da177e4SLinus Torvalds dbg("%02x -> i8042 (command)", command & 0xff); 2161da177e4SLinus Torvalds i8042_write_command(command & 0xff); 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds for (i = 0; i < ((command >> 12) & 0xf); i++) { 219de9ce703SDmitry Torokhov error = i8042_wait_write(); 220de9ce703SDmitry Torokhov if (error) 221de9ce703SDmitry Torokhov return error; 2221da177e4SLinus Torvalds dbg("%02x -> i8042 (parameter)", param[i]); 2231da177e4SLinus Torvalds i8042_write_data(param[i]); 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds for (i = 0; i < ((command >> 8) & 0xf); i++) { 227de9ce703SDmitry Torokhov error = i8042_wait_read(); 228de9ce703SDmitry Torokhov if (error) { 229de9ce703SDmitry Torokhov dbg(" -- i8042 (timeout)"); 230de9ce703SDmitry Torokhov return error; 231de9ce703SDmitry Torokhov } 232463a4f76SDmitry Torokhov 233463a4f76SDmitry Torokhov if (command == I8042_CMD_AUX_LOOP && 234463a4f76SDmitry Torokhov !(i8042_read_status() & I8042_STR_AUXDATA)) { 235de9ce703SDmitry Torokhov dbg(" -- i8042 (auxerr)"); 236de9ce703SDmitry Torokhov return -1; 237463a4f76SDmitry Torokhov } 238463a4f76SDmitry Torokhov 2391da177e4SLinus Torvalds param[i] = i8042_read_data(); 2401da177e4SLinus Torvalds dbg("%02x <- i8042 (return)", param[i]); 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds 243de9ce703SDmitry Torokhov return 0; 244de9ce703SDmitry Torokhov } 2451da177e4SLinus Torvalds 246553a05b8SMárton Németh int i8042_command(unsigned char *param, int command) 247de9ce703SDmitry Torokhov { 248de9ce703SDmitry Torokhov unsigned long flags; 249de9ce703SDmitry Torokhov int retval; 250de9ce703SDmitry Torokhov 251de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 252de9ce703SDmitry Torokhov retval = __i8042_command(param, command); 253463a4f76SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 254de9ce703SDmitry Torokhov 2551da177e4SLinus Torvalds return retval; 2561da177e4SLinus Torvalds } 257553a05b8SMárton Németh EXPORT_SYMBOL(i8042_command); 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds /* 2601da177e4SLinus Torvalds * i8042_kbd_write() sends a byte out through the keyboard interface. 2611da177e4SLinus Torvalds */ 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds static int i8042_kbd_write(struct serio *port, unsigned char c) 2641da177e4SLinus Torvalds { 2651da177e4SLinus Torvalds unsigned long flags; 2661da177e4SLinus Torvalds int retval = 0; 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds if (!(retval = i8042_wait_write())) { 2711da177e4SLinus Torvalds dbg("%02x -> i8042 (kbd-data)", c); 2721da177e4SLinus Torvalds i8042_write_data(c); 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds return retval; 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds /* 2811da177e4SLinus Torvalds * i8042_aux_write() sends a byte out through the aux interface. 2821da177e4SLinus Torvalds */ 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds static int i8042_aux_write(struct serio *serio, unsigned char c) 2851da177e4SLinus Torvalds { 2861da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 2871da177e4SLinus Torvalds 288f4e3c711SDmitry Torokhov return i8042_command(&c, port->mux == -1 ? 289f4e3c711SDmitry Torokhov I8042_CMD_AUX_SEND : 290f4e3c711SDmitry Torokhov I8042_CMD_MUX_SEND + port->mux); 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 2935ddbc77cSDmitry Torokhov 2945ddbc77cSDmitry Torokhov /* 2955ddbc77cSDmitry Torokhov * i8042_aux_close attempts to clear AUX or KBD port state by disabling 2965ddbc77cSDmitry Torokhov * and then re-enabling it. 2975ddbc77cSDmitry Torokhov */ 2985ddbc77cSDmitry Torokhov 2995ddbc77cSDmitry Torokhov static void i8042_port_close(struct serio *serio) 3005ddbc77cSDmitry Torokhov { 3015ddbc77cSDmitry Torokhov int irq_bit; 3025ddbc77cSDmitry Torokhov int disable_bit; 3035ddbc77cSDmitry Torokhov const char *port_name; 3045ddbc77cSDmitry Torokhov 3055ddbc77cSDmitry Torokhov if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) { 3065ddbc77cSDmitry Torokhov irq_bit = I8042_CTR_AUXINT; 3075ddbc77cSDmitry Torokhov disable_bit = I8042_CTR_AUXDIS; 3085ddbc77cSDmitry Torokhov port_name = "AUX"; 3095ddbc77cSDmitry Torokhov } else { 3105ddbc77cSDmitry Torokhov irq_bit = I8042_CTR_KBDINT; 3115ddbc77cSDmitry Torokhov disable_bit = I8042_CTR_KBDDIS; 3125ddbc77cSDmitry Torokhov port_name = "KBD"; 3135ddbc77cSDmitry Torokhov } 3145ddbc77cSDmitry Torokhov 3155ddbc77cSDmitry Torokhov i8042_ctr &= ~irq_bit; 3165ddbc77cSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 3175ddbc77cSDmitry Torokhov printk(KERN_WARNING 3185ddbc77cSDmitry Torokhov "i8042.c: Can't write CTR while closing %s port.\n", 3195ddbc77cSDmitry Torokhov port_name); 3205ddbc77cSDmitry Torokhov 3215ddbc77cSDmitry Torokhov udelay(50); 3225ddbc77cSDmitry Torokhov 3235ddbc77cSDmitry Torokhov i8042_ctr &= ~disable_bit; 3245ddbc77cSDmitry Torokhov i8042_ctr |= irq_bit; 3255ddbc77cSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 3265ddbc77cSDmitry Torokhov printk(KERN_ERR "i8042.c: Can't reactivate %s port.\n", 3275ddbc77cSDmitry Torokhov port_name); 3285ddbc77cSDmitry Torokhov 3295ddbc77cSDmitry Torokhov /* 3305ddbc77cSDmitry Torokhov * See if there is any data appeared while we were messing with 3315ddbc77cSDmitry Torokhov * port state. 3325ddbc77cSDmitry Torokhov */ 3335ddbc77cSDmitry Torokhov i8042_interrupt(0, NULL); 3345ddbc77cSDmitry Torokhov } 3355ddbc77cSDmitry Torokhov 3361da177e4SLinus Torvalds /* 3371da177e4SLinus Torvalds * i8042_start() is called by serio core when port is about to finish 3381da177e4SLinus Torvalds * registering. It will mark port as existing so i8042_interrupt can 3391da177e4SLinus Torvalds * start sending data through it. 3401da177e4SLinus Torvalds */ 3411da177e4SLinus Torvalds static int i8042_start(struct serio *serio) 3421da177e4SLinus Torvalds { 3431da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 3441da177e4SLinus Torvalds 345386b3849SDmitry Torokhov port->exists = true; 3461da177e4SLinus Torvalds mb(); 3471da177e4SLinus Torvalds return 0; 3481da177e4SLinus Torvalds } 3491da177e4SLinus Torvalds 3501da177e4SLinus Torvalds /* 3511da177e4SLinus Torvalds * i8042_stop() marks serio port as non-existing so i8042_interrupt 3521da177e4SLinus Torvalds * will not try to send data to the port that is about to go away. 3531da177e4SLinus Torvalds * The function is called by serio core as part of unregister procedure. 3541da177e4SLinus Torvalds */ 3551da177e4SLinus Torvalds static void i8042_stop(struct serio *serio) 3561da177e4SLinus Torvalds { 3571da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 3581da177e4SLinus Torvalds 359386b3849SDmitry Torokhov port->exists = false; 360a8399c51SDmitry Torokhov 361a8399c51SDmitry Torokhov /* 362a8399c51SDmitry Torokhov * We synchronize with both AUX and KBD IRQs because there is 363a8399c51SDmitry Torokhov * a (very unlikely) chance that AUX IRQ is raised for KBD port 364a8399c51SDmitry Torokhov * and vice versa. 365a8399c51SDmitry Torokhov */ 366a8399c51SDmitry Torokhov synchronize_irq(I8042_AUX_IRQ); 367a8399c51SDmitry Torokhov synchronize_irq(I8042_KBD_IRQ); 3681da177e4SLinus Torvalds port->serio = NULL; 3691da177e4SLinus Torvalds } 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds /* 3721da177e4SLinus Torvalds * i8042_interrupt() is the most important function in this driver - 3731da177e4SLinus Torvalds * it handles the interrupts from the i8042, and sends incoming bytes 3741da177e4SLinus Torvalds * to the upper layers. 3751da177e4SLinus Torvalds */ 3761da177e4SLinus Torvalds 3777d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id) 3781da177e4SLinus Torvalds { 3791da177e4SLinus Torvalds struct i8042_port *port; 3801da177e4SLinus Torvalds unsigned long flags; 3811da177e4SLinus Torvalds unsigned char str, data; 3821da177e4SLinus Torvalds unsigned int dfl; 3831da177e4SLinus Torvalds unsigned int port_no; 384817e6ba3SDmitry Torokhov int ret = 1; 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 3871da177e4SLinus Torvalds str = i8042_read_status(); 3881da177e4SLinus Torvalds if (unlikely(~str & I8042_STR_OBF)) { 3891da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 3901da177e4SLinus Torvalds if (irq) dbg("Interrupt %d, without any data", irq); 3911da177e4SLinus Torvalds ret = 0; 3921da177e4SLinus Torvalds goto out; 3931da177e4SLinus Torvalds } 3941da177e4SLinus Torvalds data = i8042_read_data(); 3951da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { 3981da177e4SLinus Torvalds static unsigned long last_transmit; 3991da177e4SLinus Torvalds static unsigned char last_str; 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds dfl = 0; 4021da177e4SLinus Torvalds if (str & I8042_STR_MUXERR) { 4031da177e4SLinus Torvalds dbg("MUX error, status is %02x, data is %02x", str, data); 4041da177e4SLinus Torvalds /* 4051da177e4SLinus Torvalds * When MUXERR condition is signalled the data register can only contain 4061da177e4SLinus Torvalds * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately 407a216a4b6SDmitry Torokhov * it is not always the case. Some KBCs also report 0xfc when there is 408a216a4b6SDmitry Torokhov * nothing connected to the port while others sometimes get confused which 409a216a4b6SDmitry Torokhov * port the data came from and signal error leaving the data intact. They 410a216a4b6SDmitry Torokhov * _do not_ revert to legacy mode (actually I've never seen KBC reverting 411a216a4b6SDmitry Torokhov * to legacy mode yet, when we see one we'll add proper handling). 412a216a4b6SDmitry Torokhov * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the 413a216a4b6SDmitry Torokhov * rest assume that the data came from the same serio last byte 4141da177e4SLinus Torvalds * was transmitted (if transmission happened not too long ago). 4151da177e4SLinus Torvalds */ 416a216a4b6SDmitry Torokhov 417a216a4b6SDmitry Torokhov switch (data) { 418a216a4b6SDmitry Torokhov default: 4191da177e4SLinus Torvalds if (time_before(jiffies, last_transmit + HZ/10)) { 4201da177e4SLinus Torvalds str = last_str; 4211da177e4SLinus Torvalds break; 4221da177e4SLinus Torvalds } 4231da177e4SLinus Torvalds /* fall through - report timeout */ 424a216a4b6SDmitry Torokhov case 0xfc: 4251da177e4SLinus Torvalds case 0xfd: 4261da177e4SLinus Torvalds case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break; 4271da177e4SLinus Torvalds case 0xff: dfl = SERIO_PARITY; data = 0xfe; break; 4281da177e4SLinus Torvalds } 4291da177e4SLinus Torvalds } 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3); 4321da177e4SLinus Torvalds last_str = str; 4331da177e4SLinus Torvalds last_transmit = jiffies; 4341da177e4SLinus Torvalds } else { 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | 4371da177e4SLinus Torvalds ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds port_no = (str & I8042_STR_AUXDATA) ? 4401da177e4SLinus Torvalds I8042_AUX_PORT_NO : I8042_KBD_PORT_NO; 4411da177e4SLinus Torvalds } 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds port = &i8042_ports[port_no]; 4441da177e4SLinus Torvalds 445de9ce703SDmitry Torokhov dbg("%02x <- i8042 (interrupt, %d, %d%s%s)", 446de9ce703SDmitry Torokhov data, port_no, irq, 4471da177e4SLinus Torvalds dfl & SERIO_PARITY ? ", bad parity" : "", 4481da177e4SLinus Torvalds dfl & SERIO_TIMEOUT ? ", timeout" : ""); 4491da177e4SLinus Torvalds 450817e6ba3SDmitry Torokhov if (unlikely(i8042_suppress_kbd_ack)) 451817e6ba3SDmitry Torokhov if (port_no == I8042_KBD_PORT_NO && 452817e6ba3SDmitry Torokhov (data == 0xfa || data == 0xfe)) { 45319f3c3e3SDmitry Torokhov i8042_suppress_kbd_ack--; 454817e6ba3SDmitry Torokhov goto out; 455817e6ba3SDmitry Torokhov } 456817e6ba3SDmitry Torokhov 4571da177e4SLinus Torvalds if (likely(port->exists)) 4587d12e780SDavid Howells serio_interrupt(port->serio, data, dfl); 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds out: 4611da177e4SLinus Torvalds return IRQ_RETVAL(ret); 4621da177e4SLinus Torvalds } 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds /* 4655ddbc77cSDmitry Torokhov * i8042_enable_kbd_port enables keyboard port on chip 466de9ce703SDmitry Torokhov */ 467de9ce703SDmitry Torokhov 468de9ce703SDmitry Torokhov static int i8042_enable_kbd_port(void) 469de9ce703SDmitry Torokhov { 470de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_KBDDIS; 471de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_KBDINT; 472de9ce703SDmitry Torokhov 473de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 474018db6bbSMarkus Armbruster i8042_ctr &= ~I8042_CTR_KBDINT; 475018db6bbSMarkus Armbruster i8042_ctr |= I8042_CTR_KBDDIS; 476de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n"); 477de9ce703SDmitry Torokhov return -EIO; 478de9ce703SDmitry Torokhov } 479de9ce703SDmitry Torokhov 480de9ce703SDmitry Torokhov return 0; 481de9ce703SDmitry Torokhov } 482de9ce703SDmitry Torokhov 483de9ce703SDmitry Torokhov /* 484de9ce703SDmitry Torokhov * i8042_enable_aux_port enables AUX (mouse) port on chip 485de9ce703SDmitry Torokhov */ 486de9ce703SDmitry Torokhov 487de9ce703SDmitry Torokhov static int i8042_enable_aux_port(void) 488de9ce703SDmitry Torokhov { 489de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_AUXDIS; 490de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXINT; 491de9ce703SDmitry Torokhov 492de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 493018db6bbSMarkus Armbruster i8042_ctr &= ~I8042_CTR_AUXINT; 494018db6bbSMarkus Armbruster i8042_ctr |= I8042_CTR_AUXDIS; 495de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n"); 496de9ce703SDmitry Torokhov return -EIO; 497de9ce703SDmitry Torokhov } 498de9ce703SDmitry Torokhov 499de9ce703SDmitry Torokhov return 0; 500de9ce703SDmitry Torokhov } 501de9ce703SDmitry Torokhov 502de9ce703SDmitry Torokhov /* 503de9ce703SDmitry Torokhov * i8042_enable_mux_ports enables 4 individual AUX ports after 504de9ce703SDmitry Torokhov * the controller has been switched into Multiplexed mode 505de9ce703SDmitry Torokhov */ 506de9ce703SDmitry Torokhov 507de9ce703SDmitry Torokhov static int i8042_enable_mux_ports(void) 508de9ce703SDmitry Torokhov { 509de9ce703SDmitry Torokhov unsigned char param; 510de9ce703SDmitry Torokhov int i; 511de9ce703SDmitry Torokhov 512de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { 513de9ce703SDmitry Torokhov i8042_command(¶m, I8042_CMD_MUX_PFX + i); 514de9ce703SDmitry Torokhov i8042_command(¶m, I8042_CMD_AUX_ENABLE); 515de9ce703SDmitry Torokhov } 516de9ce703SDmitry Torokhov 517de9ce703SDmitry Torokhov return i8042_enable_aux_port(); 518de9ce703SDmitry Torokhov } 519de9ce703SDmitry Torokhov 520de9ce703SDmitry Torokhov /* 521386b3849SDmitry Torokhov * i8042_set_mux_mode checks whether the controller has an 522386b3849SDmitry Torokhov * active multiplexor and puts the chip into Multiplexed (true) 523386b3849SDmitry Torokhov * or Legacy (false) mode. 5241da177e4SLinus Torvalds */ 5251da177e4SLinus Torvalds 526386b3849SDmitry Torokhov static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version) 5271da177e4SLinus Torvalds { 5281da177e4SLinus Torvalds 529386b3849SDmitry Torokhov unsigned char param, val; 5301da177e4SLinus Torvalds /* 5311da177e4SLinus Torvalds * Get rid of bytes in the queue. 5321da177e4SLinus Torvalds */ 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds i8042_flush(); 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds /* 5371da177e4SLinus Torvalds * Internal loopback test - send three bytes, they should come back from the 538de9ce703SDmitry Torokhov * mouse interface, the last should be version. 5391da177e4SLinus Torvalds */ 5401da177e4SLinus Torvalds 541386b3849SDmitry Torokhov param = val = 0xf0; 542386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != val) 5431da177e4SLinus Torvalds return -1; 544386b3849SDmitry Torokhov param = val = multiplex ? 0x56 : 0xf6; 545386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != val) 5461da177e4SLinus Torvalds return -1; 547386b3849SDmitry Torokhov param = val = multiplex ? 0xa4 : 0xa5; 548386b3849SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == val) 549386b3849SDmitry Torokhov return -1; 550386b3849SDmitry Torokhov 551386b3849SDmitry Torokhov /* 552386b3849SDmitry Torokhov * Workaround for interference with USB Legacy emulation 553386b3849SDmitry Torokhov * that causes a v10.12 MUX to be found. 554386b3849SDmitry Torokhov */ 555386b3849SDmitry Torokhov if (param == 0xac) 5561da177e4SLinus Torvalds return -1; 5571da177e4SLinus Torvalds 5581da177e4SLinus Torvalds if (mux_version) 559463a4f76SDmitry Torokhov *mux_version = param; 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds return 0; 5621da177e4SLinus Torvalds } 5631da177e4SLinus Torvalds 5641da177e4SLinus Torvalds /* 5651da177e4SLinus Torvalds * i8042_check_mux() checks whether the controller supports the PS/2 Active 5661da177e4SLinus Torvalds * Multiplexing specification by Synaptics, Phoenix, Insyde and 5671da177e4SLinus Torvalds * LCS/Telegraphics. 5681da177e4SLinus Torvalds */ 5691da177e4SLinus Torvalds 570f8113416SDmitry Torokhov static int __init i8042_check_mux(void) 5711da177e4SLinus Torvalds { 5721da177e4SLinus Torvalds unsigned char mux_version; 5731da177e4SLinus Torvalds 574386b3849SDmitry Torokhov if (i8042_set_mux_mode(true, &mux_version)) 5751da177e4SLinus Torvalds return -1; 5761da177e4SLinus Torvalds 5771da177e4SLinus Torvalds printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", 5781da177e4SLinus Torvalds (mux_version >> 4) & 0xf, mux_version & 0xf); 5791da177e4SLinus Torvalds 580de9ce703SDmitry Torokhov /* 581de9ce703SDmitry Torokhov * Disable all muxed ports by disabling AUX. 582de9ce703SDmitry Torokhov */ 583de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXDIS; 584de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_AUXINT; 585de9ce703SDmitry Torokhov 586de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 587de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n"); 588de9ce703SDmitry Torokhov return -EIO; 589de9ce703SDmitry Torokhov } 5901da177e4SLinus Torvalds 591386b3849SDmitry Torokhov i8042_mux_present = true; 592de9ce703SDmitry Torokhov 5931da177e4SLinus Torvalds return 0; 5941da177e4SLinus Torvalds } 5951da177e4SLinus Torvalds 596de9ce703SDmitry Torokhov /* 597de9ce703SDmitry Torokhov * The following is used to test AUX IRQ delivery. 598de9ce703SDmitry Torokhov */ 599f8113416SDmitry Torokhov static struct completion i8042_aux_irq_delivered __initdata; 600f8113416SDmitry Torokhov static bool i8042_irq_being_tested __initdata; 601de9ce703SDmitry Torokhov 602f8113416SDmitry Torokhov static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id) 603de9ce703SDmitry Torokhov { 604de9ce703SDmitry Torokhov unsigned long flags; 605de9ce703SDmitry Torokhov unsigned char str, data; 606e3758b2aSFernando Luis Vázquez Cao int ret = 0; 607de9ce703SDmitry Torokhov 608de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 609de9ce703SDmitry Torokhov str = i8042_read_status(); 610de9ce703SDmitry Torokhov if (str & I8042_STR_OBF) { 611de9ce703SDmitry Torokhov data = i8042_read_data(); 612d3d2dfe2SDmitry Torokhov dbg("%02x <- i8042 (aux_test_irq, %s)", 613d3d2dfe2SDmitry Torokhov data, str & I8042_STR_AUXDATA ? "aux" : "kbd"); 614de9ce703SDmitry Torokhov if (i8042_irq_being_tested && 615de9ce703SDmitry Torokhov data == 0xa5 && (str & I8042_STR_AUXDATA)) 616de9ce703SDmitry Torokhov complete(&i8042_aux_irq_delivered); 617e3758b2aSFernando Luis Vázquez Cao ret = 1; 618de9ce703SDmitry Torokhov } 619de9ce703SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 620de9ce703SDmitry Torokhov 621e3758b2aSFernando Luis Vázquez Cao return IRQ_RETVAL(ret); 622de9ce703SDmitry Torokhov } 623de9ce703SDmitry Torokhov 624d2ada559SRoland Scheidegger /* 625d2ada559SRoland Scheidegger * i8042_toggle_aux - enables or disables AUX port on i8042 via command and 626d2ada559SRoland Scheidegger * verifies success by readinng CTR. Used when testing for presence of AUX 627d2ada559SRoland Scheidegger * port. 628d2ada559SRoland Scheidegger */ 629f8113416SDmitry Torokhov static int __init i8042_toggle_aux(bool on) 630d2ada559SRoland Scheidegger { 631d2ada559SRoland Scheidegger unsigned char param; 632d2ada559SRoland Scheidegger int i; 633d2ada559SRoland Scheidegger 634d2ada559SRoland Scheidegger if (i8042_command(¶m, 635d2ada559SRoland Scheidegger on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE)) 636d2ada559SRoland Scheidegger return -1; 637d2ada559SRoland Scheidegger 638d2ada559SRoland Scheidegger /* some chips need some time to set the I8042_CTR_AUXDIS bit */ 639d2ada559SRoland Scheidegger for (i = 0; i < 100; i++) { 640d2ada559SRoland Scheidegger udelay(50); 641d2ada559SRoland Scheidegger 642d2ada559SRoland Scheidegger if (i8042_command(¶m, I8042_CMD_CTL_RCTR)) 643d2ada559SRoland Scheidegger return -1; 644d2ada559SRoland Scheidegger 645d2ada559SRoland Scheidegger if (!(param & I8042_CTR_AUXDIS) == on) 646d2ada559SRoland Scheidegger return 0; 647d2ada559SRoland Scheidegger } 648d2ada559SRoland Scheidegger 649d2ada559SRoland Scheidegger return -1; 650d2ada559SRoland Scheidegger } 6511da177e4SLinus Torvalds 6521da177e4SLinus Torvalds /* 6531da177e4SLinus Torvalds * i8042_check_aux() applies as much paranoia as it can at detecting 6541da177e4SLinus Torvalds * the presence of an AUX interface. 6551da177e4SLinus Torvalds */ 6561da177e4SLinus Torvalds 657f8113416SDmitry Torokhov static int __init i8042_check_aux(void) 6581da177e4SLinus Torvalds { 659de9ce703SDmitry Torokhov int retval = -1; 660386b3849SDmitry Torokhov bool irq_registered = false; 661386b3849SDmitry Torokhov bool aux_loop_broken = false; 662de9ce703SDmitry Torokhov unsigned long flags; 6631da177e4SLinus Torvalds unsigned char param; 6641da177e4SLinus Torvalds 6651da177e4SLinus Torvalds /* 6661da177e4SLinus Torvalds * Get rid of bytes in the queue. 6671da177e4SLinus Torvalds */ 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds i8042_flush(); 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds /* 6721da177e4SLinus Torvalds * Internal loopback test - filters out AT-type i8042's. Unfortunately 6731da177e4SLinus Torvalds * SiS screwed up and their 5597 doesn't support the LOOP command even 6741da177e4SLinus Torvalds * though it has an AUX port. 6751da177e4SLinus Torvalds */ 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds param = 0x5a; 6783ca5de6dSDmitry Torokhov retval = i8042_command(¶m, I8042_CMD_AUX_LOOP); 6793ca5de6dSDmitry Torokhov if (retval || param != 0x5a) { 6801da177e4SLinus Torvalds 6811da177e4SLinus Torvalds /* 6821da177e4SLinus Torvalds * External connection test - filters out AT-soldered PS/2 i8042's 6831da177e4SLinus Torvalds * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error 6841da177e4SLinus Torvalds * 0xfa - no error on some notebooks which ignore the spec 6851da177e4SLinus Torvalds * Because it's common for chipsets to return error on perfectly functioning 6861da177e4SLinus Torvalds * AUX ports, we test for this only when the LOOP command failed. 6871da177e4SLinus Torvalds */ 6881da177e4SLinus Torvalds 689de9ce703SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_TEST) || 690de9ce703SDmitry Torokhov (param && param != 0xfa && param != 0xff)) 6911da177e4SLinus Torvalds return -1; 6921e4865f8SDmitry Torokhov 6933ca5de6dSDmitry Torokhov /* 6943ca5de6dSDmitry Torokhov * If AUX_LOOP completed without error but returned unexpected data 6953ca5de6dSDmitry Torokhov * mark it as broken 6963ca5de6dSDmitry Torokhov */ 6973ca5de6dSDmitry Torokhov if (!retval) 698386b3849SDmitry Torokhov aux_loop_broken = true; 6991da177e4SLinus Torvalds } 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds /* 7021da177e4SLinus Torvalds * Bit assignment test - filters out PS/2 i8042's in AT mode 7031da177e4SLinus Torvalds */ 7041da177e4SLinus Torvalds 705386b3849SDmitry Torokhov if (i8042_toggle_aux(false)) { 7061da177e4SLinus Torvalds printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n"); 7071da177e4SLinus Torvalds printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n"); 7081da177e4SLinus Torvalds } 7091da177e4SLinus Torvalds 710386b3849SDmitry Torokhov if (i8042_toggle_aux(true)) 7111da177e4SLinus Torvalds return -1; 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds /* 714de9ce703SDmitry Torokhov * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and 715de9ce703SDmitry Torokhov * used it for a PCI card or somethig else. 716de9ce703SDmitry Torokhov */ 717de9ce703SDmitry Torokhov 7181c7827aeSDmitry Torokhov if (i8042_noloop || i8042_bypass_aux_irq_test || aux_loop_broken) { 719de9ce703SDmitry Torokhov /* 720de9ce703SDmitry Torokhov * Without LOOP command we can't test AUX IRQ delivery. Assume the port 721de9ce703SDmitry Torokhov * is working and hope we are right. 722de9ce703SDmitry Torokhov */ 723de9ce703SDmitry Torokhov retval = 0; 724de9ce703SDmitry Torokhov goto out; 725de9ce703SDmitry Torokhov } 726de9ce703SDmitry Torokhov 727de9ce703SDmitry Torokhov if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED, 728de9ce703SDmitry Torokhov "i8042", i8042_platform_device)) 729de9ce703SDmitry Torokhov goto out; 730de9ce703SDmitry Torokhov 731386b3849SDmitry Torokhov irq_registered = true; 732de9ce703SDmitry Torokhov 733de9ce703SDmitry Torokhov if (i8042_enable_aux_port()) 734de9ce703SDmitry Torokhov goto out; 735de9ce703SDmitry Torokhov 736de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 737de9ce703SDmitry Torokhov 738de9ce703SDmitry Torokhov init_completion(&i8042_aux_irq_delivered); 739386b3849SDmitry Torokhov i8042_irq_being_tested = true; 740de9ce703SDmitry Torokhov 741de9ce703SDmitry Torokhov param = 0xa5; 742de9ce703SDmitry Torokhov retval = __i8042_command(¶m, I8042_CMD_AUX_LOOP & 0xf0ff); 743de9ce703SDmitry Torokhov 744de9ce703SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 745de9ce703SDmitry Torokhov 746de9ce703SDmitry Torokhov if (retval) 747de9ce703SDmitry Torokhov goto out; 748de9ce703SDmitry Torokhov 749de9ce703SDmitry Torokhov if (wait_for_completion_timeout(&i8042_aux_irq_delivered, 750de9ce703SDmitry Torokhov msecs_to_jiffies(250)) == 0) { 751de9ce703SDmitry Torokhov /* 752de9ce703SDmitry Torokhov * AUX IRQ was never delivered so we need to flush the controller to 753de9ce703SDmitry Torokhov * get rid of the byte we put there; otherwise keyboard may not work. 754de9ce703SDmitry Torokhov */ 755d3d2dfe2SDmitry Torokhov dbg(" -- i8042 (aux irq test timeout)"); 756de9ce703SDmitry Torokhov i8042_flush(); 757de9ce703SDmitry Torokhov retval = -1; 758de9ce703SDmitry Torokhov } 759de9ce703SDmitry Torokhov 760de9ce703SDmitry Torokhov out: 761de9ce703SDmitry Torokhov 762de9ce703SDmitry Torokhov /* 7631da177e4SLinus Torvalds * Disable the interface. 7641da177e4SLinus Torvalds */ 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_AUXDIS; 7671da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_AUXINT; 7681da177e4SLinus Torvalds 7691da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 770de9ce703SDmitry Torokhov retval = -1; 771de9ce703SDmitry Torokhov 772de9ce703SDmitry Torokhov if (irq_registered) 773de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 774de9ce703SDmitry Torokhov 775de9ce703SDmitry Torokhov return retval; 776de9ce703SDmitry Torokhov } 777de9ce703SDmitry Torokhov 778de9ce703SDmitry Torokhov static int i8042_controller_check(void) 779de9ce703SDmitry Torokhov { 780de9ce703SDmitry Torokhov if (i8042_flush() == I8042_BUFFER_SIZE) { 781de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: No controller found.\n"); 782de9ce703SDmitry Torokhov return -ENODEV; 783de9ce703SDmitry Torokhov } 7841da177e4SLinus Torvalds 7851da177e4SLinus Torvalds return 0; 7861da177e4SLinus Torvalds } 7871da177e4SLinus Torvalds 788de9ce703SDmitry Torokhov static int i8042_controller_selftest(void) 7892673c836SVojtech Pavlik { 7902673c836SVojtech Pavlik unsigned char param; 7915ea2fc64SArjan van de Ven int i = 0; 7922673c836SVojtech Pavlik 7932673c836SVojtech Pavlik if (!i8042_reset) 7942673c836SVojtech Pavlik return 0; 7952673c836SVojtech Pavlik 7965ea2fc64SArjan van de Ven /* 7975ea2fc64SArjan van de Ven * We try this 5 times; on some really fragile systems this does not 7985ea2fc64SArjan van de Ven * take the first time... 7995ea2fc64SArjan van de Ven */ 8005ea2fc64SArjan van de Ven do { 8015ea2fc64SArjan van de Ven 8022673c836SVojtech Pavlik if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { 8032673c836SVojtech Pavlik printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); 804de9ce703SDmitry Torokhov return -ENODEV; 8052673c836SVojtech Pavlik } 8062673c836SVojtech Pavlik 8075ea2fc64SArjan van de Ven if (param == I8042_RET_CTL_TEST) 8085ea2fc64SArjan van de Ven return 0; 8095ea2fc64SArjan van de Ven 8102673c836SVojtech Pavlik printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", 8112673c836SVojtech Pavlik param, I8042_RET_CTL_TEST); 8125ea2fc64SArjan van de Ven msleep(50); 8135ea2fc64SArjan van de Ven } while (i++ < 5); 8142673c836SVojtech Pavlik 8155ea2fc64SArjan van de Ven #ifdef CONFIG_X86 8165ea2fc64SArjan van de Ven /* 8175ea2fc64SArjan van de Ven * On x86, we don't fail entire i8042 initialization if controller 8185ea2fc64SArjan van de Ven * reset fails in hopes that keyboard port will still be functional 8195ea2fc64SArjan van de Ven * and user will still get a working keyboard. This is especially 8205ea2fc64SArjan van de Ven * important on netbooks. On other arches we trust hardware more. 8215ea2fc64SArjan van de Ven */ 8225ea2fc64SArjan van de Ven printk(KERN_INFO 8235ea2fc64SArjan van de Ven "i8042: giving up on controller selftest, continuing anyway...\n"); 8242673c836SVojtech Pavlik return 0; 8255ea2fc64SArjan van de Ven #else 8265ea2fc64SArjan van de Ven return -EIO; 8275ea2fc64SArjan van de Ven #endif 8282673c836SVojtech Pavlik } 8291da177e4SLinus Torvalds 8301da177e4SLinus Torvalds /* 8311da177e4SLinus Torvalds * i8042_controller init initializes the i8042 controller, and, 8321da177e4SLinus Torvalds * most importantly, sets it into non-xlated mode if that's 8331da177e4SLinus Torvalds * desired. 8341da177e4SLinus Torvalds */ 8351da177e4SLinus Torvalds 8361da177e4SLinus Torvalds static int i8042_controller_init(void) 8371da177e4SLinus Torvalds { 8381da177e4SLinus Torvalds unsigned long flags; 839*ee1e82ceSDmitry Torokhov int n = 0; 840*ee1e82ceSDmitry Torokhov unsigned char ctr[2]; 8411da177e4SLinus Torvalds 8421da177e4SLinus Torvalds /* 843*ee1e82ceSDmitry Torokhov * Save the CTR for restore on unload / reboot. 8441da177e4SLinus Torvalds */ 8451da177e4SLinus Torvalds 846*ee1e82ceSDmitry Torokhov do { 847*ee1e82ceSDmitry Torokhov if (n >= 10) { 848*ee1e82ceSDmitry Torokhov printk(KERN_ERR 849*ee1e82ceSDmitry Torokhov "i8042.c: Unable to get stable CTR read.\n"); 850de9ce703SDmitry Torokhov return -EIO; 8511da177e4SLinus Torvalds } 8521da177e4SLinus Torvalds 853*ee1e82ceSDmitry Torokhov if (n != 0) 854*ee1e82ceSDmitry Torokhov udelay(50); 855*ee1e82ceSDmitry Torokhov 856*ee1e82ceSDmitry Torokhov if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) { 857*ee1e82ceSDmitry Torokhov printk(KERN_ERR 858*ee1e82ceSDmitry Torokhov "i8042.c: Can't read CTR while initializing i8042.\n"); 859*ee1e82ceSDmitry Torokhov return -EIO; 860*ee1e82ceSDmitry Torokhov } 861*ee1e82ceSDmitry Torokhov 862*ee1e82ceSDmitry Torokhov } while (n < 2 || ctr[0] != ctr[1]); 863*ee1e82ceSDmitry Torokhov 864*ee1e82ceSDmitry Torokhov i8042_initial_ctr = i8042_ctr = ctr[0]; 8651da177e4SLinus Torvalds 8661da177e4SLinus Torvalds /* 8671da177e4SLinus Torvalds * Disable the keyboard interface and interrupt. 8681da177e4SLinus Torvalds */ 8691da177e4SLinus Torvalds 8701da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_KBDDIS; 8711da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_KBDINT; 8721da177e4SLinus Torvalds 8731da177e4SLinus Torvalds /* 8741da177e4SLinus Torvalds * Handle keylock. 8751da177e4SLinus Torvalds */ 8761da177e4SLinus Torvalds 8771da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 8781da177e4SLinus Torvalds if (~i8042_read_status() & I8042_STR_KEYLOCK) { 8791da177e4SLinus Torvalds if (i8042_unlock) 8801da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_IGNKEYLOCK; 8811da177e4SLinus Torvalds else 8821da177e4SLinus Torvalds printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); 8831da177e4SLinus Torvalds } 8841da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 8851da177e4SLinus Torvalds 8861da177e4SLinus Torvalds /* 8871da177e4SLinus Torvalds * If the chip is configured into nontranslated mode by the BIOS, don't 8881da177e4SLinus Torvalds * bother enabling translating and be happy. 8891da177e4SLinus Torvalds */ 8901da177e4SLinus Torvalds 8911da177e4SLinus Torvalds if (~i8042_ctr & I8042_CTR_XLATE) 892386b3849SDmitry Torokhov i8042_direct = true; 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds /* 8951da177e4SLinus Torvalds * Set nontranslated mode for the kbd interface if requested by an option. 8961da177e4SLinus Torvalds * After this the kbd interface becomes a simple serial in/out, like the aux 8971da177e4SLinus Torvalds * interface is. We don't do this by default, since it can confuse notebook 8981da177e4SLinus Torvalds * BIOSes. 8991da177e4SLinus Torvalds */ 9001da177e4SLinus Torvalds 9011da177e4SLinus Torvalds if (i8042_direct) 9021da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_XLATE; 9031da177e4SLinus Torvalds 9041da177e4SLinus Torvalds /* 9051da177e4SLinus Torvalds * Write CTR back. 9061da177e4SLinus Torvalds */ 9071da177e4SLinus Torvalds 9081da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 9091da177e4SLinus Torvalds printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); 910de9ce703SDmitry Torokhov return -EIO; 9111da177e4SLinus Torvalds } 9121da177e4SLinus Torvalds 913*ee1e82ceSDmitry Torokhov /* 914*ee1e82ceSDmitry Torokhov * Flush whatever accumulated while we were disabling keyboard port. 915*ee1e82ceSDmitry Torokhov */ 916*ee1e82ceSDmitry Torokhov 917*ee1e82ceSDmitry Torokhov i8042_flush(); 918*ee1e82ceSDmitry Torokhov 9191da177e4SLinus Torvalds return 0; 9201da177e4SLinus Torvalds } 9211da177e4SLinus Torvalds 9221da177e4SLinus Torvalds 9231da177e4SLinus Torvalds /* 924de9ce703SDmitry Torokhov * Reset the controller and reset CRT to the original value set by BIOS. 9251da177e4SLinus Torvalds */ 9261da177e4SLinus Torvalds 927de9ce703SDmitry Torokhov static void i8042_controller_reset(void) 928de9ce703SDmitry Torokhov { 929de9ce703SDmitry Torokhov i8042_flush(); 9301da177e4SLinus Torvalds 9311da177e4SLinus Torvalds /* 9328d04ddb6SDmitry Torokhov * Disable both KBD and AUX interfaces so they don't get in the way 9338d04ddb6SDmitry Torokhov */ 9348d04ddb6SDmitry Torokhov 9358d04ddb6SDmitry Torokhov i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS; 9368d04ddb6SDmitry Torokhov i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT); 9378d04ddb6SDmitry Torokhov 938*ee1e82ceSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 9395ddbc77cSDmitry Torokhov printk(KERN_WARNING "i8042.c: Can't write CTR while resetting.\n"); 9405ddbc77cSDmitry Torokhov 9418d04ddb6SDmitry Torokhov /* 9421da177e4SLinus Torvalds * Disable MUX mode if present. 9431da177e4SLinus Torvalds */ 9441da177e4SLinus Torvalds 9451da177e4SLinus Torvalds if (i8042_mux_present) 946386b3849SDmitry Torokhov i8042_set_mux_mode(false, NULL); 9471da177e4SLinus Torvalds 9481da177e4SLinus Torvalds /* 949de9ce703SDmitry Torokhov * Reset the controller if requested. 950de9ce703SDmitry Torokhov */ 951de9ce703SDmitry Torokhov 952de9ce703SDmitry Torokhov i8042_controller_selftest(); 953de9ce703SDmitry Torokhov 954de9ce703SDmitry Torokhov /* 9551da177e4SLinus Torvalds * Restore the original control register setting. 9561da177e4SLinus Torvalds */ 9571da177e4SLinus Torvalds 958de9ce703SDmitry Torokhov if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR)) 9591da177e4SLinus Torvalds printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); 9601da177e4SLinus Torvalds } 9611da177e4SLinus Torvalds 9621da177e4SLinus Torvalds 9631da177e4SLinus Torvalds /* 9641da177e4SLinus Torvalds * i8042_panic_blink() will flash the keyboard LEDs and is called when 9651da177e4SLinus Torvalds * kernel panics. Flashing LEDs is useful for users running X who may 9661da177e4SLinus Torvalds * not see the console and will help distingushing panics from "real" 9671da177e4SLinus Torvalds * lockups. 9681da177e4SLinus Torvalds * 9691da177e4SLinus Torvalds * Note that DELAY has a limit of 10ms so we will not get stuck here 9701da177e4SLinus Torvalds * waiting for KBC to free up even if KBD interrupt is off 9711da177e4SLinus Torvalds */ 9721da177e4SLinus Torvalds 9731da177e4SLinus Torvalds #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0) 9741da177e4SLinus Torvalds 9751da177e4SLinus Torvalds static long i8042_panic_blink(long count) 9761da177e4SLinus Torvalds { 9771da177e4SLinus Torvalds long delay = 0; 9781da177e4SLinus Torvalds static long last_blink; 9791da177e4SLinus Torvalds static char led; 9801da177e4SLinus Torvalds 9811da177e4SLinus Torvalds /* 9821da177e4SLinus Torvalds * We expect frequency to be about 1/2s. KDB uses about 1s. 9831da177e4SLinus Torvalds * Make sure they are different. 9841da177e4SLinus Torvalds */ 9851da177e4SLinus Torvalds if (!i8042_blink_frequency) 9861da177e4SLinus Torvalds return 0; 9871da177e4SLinus Torvalds if (count - last_blink < i8042_blink_frequency) 9881da177e4SLinus Torvalds return 0; 9891da177e4SLinus Torvalds 9901da177e4SLinus Torvalds led ^= 0x01 | 0x04; 9911da177e4SLinus Torvalds while (i8042_read_status() & I8042_STR_IBF) 9921da177e4SLinus Torvalds DELAY; 99319f3c3e3SDmitry Torokhov dbg("%02x -> i8042 (panic blink)", 0xed); 99419f3c3e3SDmitry Torokhov i8042_suppress_kbd_ack = 2; 9951da177e4SLinus Torvalds i8042_write_data(0xed); /* set leds */ 9961da177e4SLinus Torvalds DELAY; 9971da177e4SLinus Torvalds while (i8042_read_status() & I8042_STR_IBF) 9981da177e4SLinus Torvalds DELAY; 9991da177e4SLinus Torvalds DELAY; 100019f3c3e3SDmitry Torokhov dbg("%02x -> i8042 (panic blink)", led); 10011da177e4SLinus Torvalds i8042_write_data(led); 10021da177e4SLinus Torvalds DELAY; 10031da177e4SLinus Torvalds last_blink = count; 10041da177e4SLinus Torvalds return delay; 10051da177e4SLinus Torvalds } 10061da177e4SLinus Torvalds 10071da177e4SLinus Torvalds #undef DELAY 10081da177e4SLinus Torvalds 1009d35895dbSBruno Prémont #ifdef CONFIG_X86 1010d35895dbSBruno Prémont static void i8042_dritek_enable(void) 1011d35895dbSBruno Prémont { 1012d35895dbSBruno Prémont char param = 0x90; 1013d35895dbSBruno Prémont int error; 1014d35895dbSBruno Prémont 1015d35895dbSBruno Prémont error = i8042_command(¶m, 0x1059); 1016d35895dbSBruno Prémont if (error) 1017d35895dbSBruno Prémont printk(KERN_WARNING 1018d35895dbSBruno Prémont "Failed to enable DRITEK extension: %d\n", 1019d35895dbSBruno Prémont error); 1020d35895dbSBruno Prémont } 1021d35895dbSBruno Prémont #endif 1022d35895dbSBruno Prémont 102382dd9effSDmitry Torokhov #ifdef CONFIG_PM 10247e044e05SDmitry Torokhov 10251da177e4SLinus Torvalds /* 1026ebd7768dSDmitry Torokhov * Here we try to restore the original BIOS settings to avoid 1027ebd7768dSDmitry Torokhov * upsetting it. 10281da177e4SLinus Torvalds */ 10291da177e4SLinus Torvalds 1030ebd7768dSDmitry Torokhov static int i8042_pm_reset(struct device *dev) 10311da177e4SLinus Torvalds { 103282dd9effSDmitry Torokhov i8042_controller_reset(); 1033ddaa4343SThadeu Lima de Souza Cascardo 10341da177e4SLinus Torvalds return 0; 10351da177e4SLinus Torvalds } 10361da177e4SLinus Torvalds 10371da177e4SLinus Torvalds /* 1038ebd7768dSDmitry Torokhov * Here we try to reset everything back to a state we had 1039ebd7768dSDmitry Torokhov * before suspending. 10401da177e4SLinus Torvalds */ 10411da177e4SLinus Torvalds 1042ebd7768dSDmitry Torokhov static int i8042_pm_restore(struct device *dev) 10431da177e4SLinus Torvalds { 1044de9ce703SDmitry Torokhov int error; 10451da177e4SLinus Torvalds 1046de9ce703SDmitry Torokhov error = i8042_controller_check(); 1047de9ce703SDmitry Torokhov if (error) 1048de9ce703SDmitry Torokhov return error; 10492673c836SVojtech Pavlik 1050de9ce703SDmitry Torokhov error = i8042_controller_selftest(); 1051de9ce703SDmitry Torokhov if (error) 1052de9ce703SDmitry Torokhov return error; 1053de9ce703SDmitry Torokhov 1054de9ce703SDmitry Torokhov /* 105582dd9effSDmitry Torokhov * Restore original CTR value and disable all ports 1056de9ce703SDmitry Torokhov */ 1057de9ce703SDmitry Torokhov 105882dd9effSDmitry Torokhov i8042_ctr = i8042_initial_ctr; 105982dd9effSDmitry Torokhov if (i8042_direct) 106082dd9effSDmitry Torokhov i8042_ctr &= ~I8042_CTR_XLATE; 1061de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS; 1062de9ce703SDmitry Torokhov i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT); 10632673c836SVojtech Pavlik if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 10642f6a77d5SJiri Kosina printk(KERN_WARNING "i8042: Can't write CTR to resume, retrying...\n"); 10652f6a77d5SJiri Kosina msleep(50); 10662f6a77d5SJiri Kosina if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 10672f6a77d5SJiri Kosina printk(KERN_ERR "i8042: CTR write retry failed\n"); 1068de9ce703SDmitry Torokhov return -EIO; 10691da177e4SLinus Torvalds } 10702f6a77d5SJiri Kosina } 10711da177e4SLinus Torvalds 1072d35895dbSBruno Prémont 1073d35895dbSBruno Prémont #ifdef CONFIG_X86 1074d35895dbSBruno Prémont if (i8042_dritek) 1075d35895dbSBruno Prémont i8042_dritek_enable(); 1076d35895dbSBruno Prémont #endif 1077d35895dbSBruno Prémont 1078de9ce703SDmitry Torokhov if (i8042_mux_present) { 1079386b3849SDmitry Torokhov if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports()) 1080de9ce703SDmitry Torokhov printk(KERN_WARNING 1081de9ce703SDmitry Torokhov "i8042: failed to resume active multiplexor, " 1082de9ce703SDmitry Torokhov "mouse won't work.\n"); 1083de9ce703SDmitry Torokhov } else if (i8042_ports[I8042_AUX_PORT_NO].serio) 1084de9ce703SDmitry Torokhov i8042_enable_aux_port(); 10851da177e4SLinus Torvalds 1086de9ce703SDmitry Torokhov if (i8042_ports[I8042_KBD_PORT_NO].serio) 1087de9ce703SDmitry Torokhov i8042_enable_kbd_port(); 10881da177e4SLinus Torvalds 10897d12e780SDavid Howells i8042_interrupt(0, NULL); 10901da177e4SLinus Torvalds 10911da177e4SLinus Torvalds return 0; 10921da177e4SLinus Torvalds } 1093ebd7768dSDmitry Torokhov 1094ebd7768dSDmitry Torokhov static const struct dev_pm_ops i8042_pm_ops = { 1095ebd7768dSDmitry Torokhov .suspend = i8042_pm_reset, 1096ebd7768dSDmitry Torokhov .resume = i8042_pm_restore, 1097ebd7768dSDmitry Torokhov .poweroff = i8042_pm_reset, 1098ebd7768dSDmitry Torokhov .restore = i8042_pm_restore, 1099ebd7768dSDmitry Torokhov }; 1100ebd7768dSDmitry Torokhov 110182dd9effSDmitry Torokhov #endif /* CONFIG_PM */ 11021da177e4SLinus Torvalds 11031da177e4SLinus Torvalds /* 11041da177e4SLinus Torvalds * We need to reset the 8042 back to original mode on system shutdown, 11051da177e4SLinus Torvalds * because otherwise BIOSes will be confused. 11061da177e4SLinus Torvalds */ 11071da177e4SLinus Torvalds 11083ae5eaecSRussell King static void i8042_shutdown(struct platform_device *dev) 11091da177e4SLinus Torvalds { 111082dd9effSDmitry Torokhov i8042_controller_reset(); 11111da177e4SLinus Torvalds } 11121da177e4SLinus Torvalds 1113f8113416SDmitry Torokhov static int __init i8042_create_kbd_port(void) 11141da177e4SLinus Torvalds { 11151da177e4SLinus Torvalds struct serio *serio; 11161da177e4SLinus Torvalds struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; 11171da177e4SLinus Torvalds 1118d39969deSDmitry Torokhov serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 11190854e52dSDmitry Torokhov if (!serio) 11200854e52dSDmitry Torokhov return -ENOMEM; 11210854e52dSDmitry Torokhov 11221da177e4SLinus Torvalds serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; 11231da177e4SLinus Torvalds serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; 11241da177e4SLinus Torvalds serio->start = i8042_start; 11251da177e4SLinus Torvalds serio->stop = i8042_stop; 11265ddbc77cSDmitry Torokhov serio->close = i8042_port_close; 11271da177e4SLinus Torvalds serio->port_data = port; 11281da177e4SLinus Torvalds serio->dev.parent = &i8042_platform_device->dev; 1129de9ce703SDmitry Torokhov strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); 11301da177e4SLinus Torvalds strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); 11311da177e4SLinus Torvalds 11321da177e4SLinus Torvalds port->serio = serio; 1133de9ce703SDmitry Torokhov port->irq = I8042_KBD_IRQ; 11340854e52dSDmitry Torokhov 1135de9ce703SDmitry Torokhov return 0; 11361da177e4SLinus Torvalds } 11371da177e4SLinus Torvalds 1138f8113416SDmitry Torokhov static int __init i8042_create_aux_port(int idx) 11391da177e4SLinus Torvalds { 11401da177e4SLinus Torvalds struct serio *serio; 1141de9ce703SDmitry Torokhov int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx; 1142de9ce703SDmitry Torokhov struct i8042_port *port = &i8042_ports[port_no]; 11431da177e4SLinus Torvalds 1144d39969deSDmitry Torokhov serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 11450854e52dSDmitry Torokhov if (!serio) 11460854e52dSDmitry Torokhov return -ENOMEM; 11470854e52dSDmitry Torokhov 11481da177e4SLinus Torvalds serio->id.type = SERIO_8042; 11491da177e4SLinus Torvalds serio->write = i8042_aux_write; 11501da177e4SLinus Torvalds serio->start = i8042_start; 11511da177e4SLinus Torvalds serio->stop = i8042_stop; 11521da177e4SLinus Torvalds serio->port_data = port; 11531da177e4SLinus Torvalds serio->dev.parent = &i8042_platform_device->dev; 1154de9ce703SDmitry Torokhov if (idx < 0) { 1155de9ce703SDmitry Torokhov strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name)); 11561da177e4SLinus Torvalds strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); 11575ddbc77cSDmitry Torokhov serio->close = i8042_port_close; 1158de9ce703SDmitry Torokhov } else { 1159de9ce703SDmitry Torokhov snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx); 1160de9ce703SDmitry Torokhov snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1); 11611da177e4SLinus Torvalds } 11621da177e4SLinus Torvalds 11631da177e4SLinus Torvalds port->serio = serio; 1164de9ce703SDmitry Torokhov port->mux = idx; 1165de9ce703SDmitry Torokhov port->irq = I8042_AUX_IRQ; 11660854e52dSDmitry Torokhov 1167de9ce703SDmitry Torokhov return 0; 1168de9ce703SDmitry Torokhov } 1169de9ce703SDmitry Torokhov 1170f8113416SDmitry Torokhov static void __init i8042_free_kbd_port(void) 1171de9ce703SDmitry Torokhov { 1172de9ce703SDmitry Torokhov kfree(i8042_ports[I8042_KBD_PORT_NO].serio); 1173de9ce703SDmitry Torokhov i8042_ports[I8042_KBD_PORT_NO].serio = NULL; 1174de9ce703SDmitry Torokhov } 1175de9ce703SDmitry Torokhov 1176f8113416SDmitry Torokhov static void __init i8042_free_aux_ports(void) 1177de9ce703SDmitry Torokhov { 1178de9ce703SDmitry Torokhov int i; 1179de9ce703SDmitry Torokhov 1180de9ce703SDmitry Torokhov for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) { 1181de9ce703SDmitry Torokhov kfree(i8042_ports[i].serio); 1182de9ce703SDmitry Torokhov i8042_ports[i].serio = NULL; 1183de9ce703SDmitry Torokhov } 1184de9ce703SDmitry Torokhov } 1185de9ce703SDmitry Torokhov 1186f8113416SDmitry Torokhov static void __init i8042_register_ports(void) 1187de9ce703SDmitry Torokhov { 1188de9ce703SDmitry Torokhov int i; 1189de9ce703SDmitry Torokhov 1190de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) { 1191de9ce703SDmitry Torokhov if (i8042_ports[i].serio) { 1192de9ce703SDmitry Torokhov printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n", 1193de9ce703SDmitry Torokhov i8042_ports[i].serio->name, 1194de9ce703SDmitry Torokhov (unsigned long) I8042_DATA_REG, 1195de9ce703SDmitry Torokhov (unsigned long) I8042_COMMAND_REG, 1196de9ce703SDmitry Torokhov i8042_ports[i].irq); 1197de9ce703SDmitry Torokhov serio_register_port(i8042_ports[i].serio); 1198de9ce703SDmitry Torokhov } 1199de9ce703SDmitry Torokhov } 1200de9ce703SDmitry Torokhov } 1201de9ce703SDmitry Torokhov 12027a1904c3SRalf Baechle static void __devexit i8042_unregister_ports(void) 1203de9ce703SDmitry Torokhov { 1204de9ce703SDmitry Torokhov int i; 1205de9ce703SDmitry Torokhov 1206de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) { 1207de9ce703SDmitry Torokhov if (i8042_ports[i].serio) { 1208de9ce703SDmitry Torokhov serio_unregister_port(i8042_ports[i].serio); 1209de9ce703SDmitry Torokhov i8042_ports[i].serio = NULL; 1210de9ce703SDmitry Torokhov } 1211de9ce703SDmitry Torokhov } 1212de9ce703SDmitry Torokhov } 1213de9ce703SDmitry Torokhov 1214181d683dSDmitry Torokhov /* 1215181d683dSDmitry Torokhov * Checks whether port belongs to i8042 controller. 1216181d683dSDmitry Torokhov */ 1217181d683dSDmitry Torokhov bool i8042_check_port_owner(const struct serio *port) 1218181d683dSDmitry Torokhov { 1219181d683dSDmitry Torokhov int i; 1220181d683dSDmitry Torokhov 1221181d683dSDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) 1222181d683dSDmitry Torokhov if (i8042_ports[i].serio == port) 1223181d683dSDmitry Torokhov return true; 1224181d683dSDmitry Torokhov 1225181d683dSDmitry Torokhov return false; 1226181d683dSDmitry Torokhov } 1227181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_check_port_owner); 1228181d683dSDmitry Torokhov 1229de9ce703SDmitry Torokhov static void i8042_free_irqs(void) 1230de9ce703SDmitry Torokhov { 1231de9ce703SDmitry Torokhov if (i8042_aux_irq_registered) 1232de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 1233de9ce703SDmitry Torokhov if (i8042_kbd_irq_registered) 1234de9ce703SDmitry Torokhov free_irq(I8042_KBD_IRQ, i8042_platform_device); 1235de9ce703SDmitry Torokhov 1236386b3849SDmitry Torokhov i8042_aux_irq_registered = i8042_kbd_irq_registered = false; 1237de9ce703SDmitry Torokhov } 1238de9ce703SDmitry Torokhov 1239f8113416SDmitry Torokhov static int __init i8042_setup_aux(void) 1240de9ce703SDmitry Torokhov { 1241de9ce703SDmitry Torokhov int (*aux_enable)(void); 1242de9ce703SDmitry Torokhov int error; 1243de9ce703SDmitry Torokhov int i; 1244de9ce703SDmitry Torokhov 1245de9ce703SDmitry Torokhov if (i8042_check_aux()) 1246de9ce703SDmitry Torokhov return -ENODEV; 1247de9ce703SDmitry Torokhov 1248de9ce703SDmitry Torokhov if (i8042_nomux || i8042_check_mux()) { 1249de9ce703SDmitry Torokhov error = i8042_create_aux_port(-1); 1250de9ce703SDmitry Torokhov if (error) 1251de9ce703SDmitry Torokhov goto err_free_ports; 1252de9ce703SDmitry Torokhov aux_enable = i8042_enable_aux_port; 1253de9ce703SDmitry Torokhov } else { 1254de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { 1255de9ce703SDmitry Torokhov error = i8042_create_aux_port(i); 1256de9ce703SDmitry Torokhov if (error) 1257de9ce703SDmitry Torokhov goto err_free_ports; 1258de9ce703SDmitry Torokhov } 1259de9ce703SDmitry Torokhov aux_enable = i8042_enable_mux_ports; 1260de9ce703SDmitry Torokhov } 1261de9ce703SDmitry Torokhov 1262de9ce703SDmitry Torokhov error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED, 1263de9ce703SDmitry Torokhov "i8042", i8042_platform_device); 1264de9ce703SDmitry Torokhov if (error) 1265de9ce703SDmitry Torokhov goto err_free_ports; 1266de9ce703SDmitry Torokhov 1267de9ce703SDmitry Torokhov if (aux_enable()) 1268de9ce703SDmitry Torokhov goto err_free_irq; 1269de9ce703SDmitry Torokhov 1270386b3849SDmitry Torokhov i8042_aux_irq_registered = true; 1271de9ce703SDmitry Torokhov return 0; 1272de9ce703SDmitry Torokhov 1273de9ce703SDmitry Torokhov err_free_irq: 1274de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 1275de9ce703SDmitry Torokhov err_free_ports: 1276de9ce703SDmitry Torokhov i8042_free_aux_ports(); 1277de9ce703SDmitry Torokhov return error; 1278de9ce703SDmitry Torokhov } 1279de9ce703SDmitry Torokhov 1280f8113416SDmitry Torokhov static int __init i8042_setup_kbd(void) 1281de9ce703SDmitry Torokhov { 1282de9ce703SDmitry Torokhov int error; 1283de9ce703SDmitry Torokhov 1284de9ce703SDmitry Torokhov error = i8042_create_kbd_port(); 1285de9ce703SDmitry Torokhov if (error) 1286de9ce703SDmitry Torokhov return error; 1287de9ce703SDmitry Torokhov 1288de9ce703SDmitry Torokhov error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED, 1289de9ce703SDmitry Torokhov "i8042", i8042_platform_device); 1290de9ce703SDmitry Torokhov if (error) 1291de9ce703SDmitry Torokhov goto err_free_port; 1292de9ce703SDmitry Torokhov 1293de9ce703SDmitry Torokhov error = i8042_enable_kbd_port(); 1294de9ce703SDmitry Torokhov if (error) 1295de9ce703SDmitry Torokhov goto err_free_irq; 1296de9ce703SDmitry Torokhov 1297386b3849SDmitry Torokhov i8042_kbd_irq_registered = true; 1298de9ce703SDmitry Torokhov return 0; 1299de9ce703SDmitry Torokhov 1300de9ce703SDmitry Torokhov err_free_irq: 1301de9ce703SDmitry Torokhov free_irq(I8042_KBD_IRQ, i8042_platform_device); 1302de9ce703SDmitry Torokhov err_free_port: 1303de9ce703SDmitry Torokhov i8042_free_kbd_port(); 1304de9ce703SDmitry Torokhov return error; 13051da177e4SLinus Torvalds } 13061da177e4SLinus Torvalds 1307f8113416SDmitry Torokhov static int __init i8042_probe(struct platform_device *dev) 13081da177e4SLinus Torvalds { 1309de9ce703SDmitry Torokhov int error; 13101da177e4SLinus Torvalds 1311de9ce703SDmitry Torokhov error = i8042_controller_selftest(); 1312de9ce703SDmitry Torokhov if (error) 1313de9ce703SDmitry Torokhov return error; 13141da177e4SLinus Torvalds 1315de9ce703SDmitry Torokhov error = i8042_controller_init(); 1316de9ce703SDmitry Torokhov if (error) 1317de9ce703SDmitry Torokhov return error; 13181da177e4SLinus Torvalds 1319d35895dbSBruno Prémont #ifdef CONFIG_X86 1320d35895dbSBruno Prémont if (i8042_dritek) 1321d35895dbSBruno Prémont i8042_dritek_enable(); 1322d35895dbSBruno Prémont #endif 1323d35895dbSBruno Prémont 1324de9ce703SDmitry Torokhov if (!i8042_noaux) { 1325de9ce703SDmitry Torokhov error = i8042_setup_aux(); 1326de9ce703SDmitry Torokhov if (error && error != -ENODEV && error != -EBUSY) 1327de9ce703SDmitry Torokhov goto out_fail; 13281da177e4SLinus Torvalds } 13291da177e4SLinus Torvalds 1330945ef0d4SDmitry Torokhov if (!i8042_nokbd) { 1331de9ce703SDmitry Torokhov error = i8042_setup_kbd(); 1332de9ce703SDmitry Torokhov if (error) 1333de9ce703SDmitry Torokhov goto out_fail; 1334945ef0d4SDmitry Torokhov } 1335de9ce703SDmitry Torokhov /* 1336de9ce703SDmitry Torokhov * Ok, everything is ready, let's register all serio ports 1337de9ce703SDmitry Torokhov */ 1338de9ce703SDmitry Torokhov i8042_register_ports(); 13391da177e4SLinus Torvalds 13401da177e4SLinus Torvalds return 0; 13410854e52dSDmitry Torokhov 1342de9ce703SDmitry Torokhov out_fail: 1343de9ce703SDmitry Torokhov i8042_free_aux_ports(); /* in case KBD failed but AUX not */ 1344de9ce703SDmitry Torokhov i8042_free_irqs(); 1345de9ce703SDmitry Torokhov i8042_controller_reset(); 13460854e52dSDmitry Torokhov 1347de9ce703SDmitry Torokhov return error; 13481da177e4SLinus Torvalds } 13491da177e4SLinus Torvalds 135087fd6318SDmitry Torokhov static int __devexit i8042_remove(struct platform_device *dev) 13511da177e4SLinus Torvalds { 1352de9ce703SDmitry Torokhov i8042_unregister_ports(); 1353de9ce703SDmitry Torokhov i8042_free_irqs(); 1354de9ce703SDmitry Torokhov i8042_controller_reset(); 13551da177e4SLinus Torvalds 135687fd6318SDmitry Torokhov return 0; 135787fd6318SDmitry Torokhov } 135887fd6318SDmitry Torokhov 135987fd6318SDmitry Torokhov static struct platform_driver i8042_driver = { 136087fd6318SDmitry Torokhov .driver = { 136187fd6318SDmitry Torokhov .name = "i8042", 136287fd6318SDmitry Torokhov .owner = THIS_MODULE, 1363ebd7768dSDmitry Torokhov #ifdef CONFIG_PM 1364ebd7768dSDmitry Torokhov .pm = &i8042_pm_ops, 1365ebd7768dSDmitry Torokhov #endif 136687fd6318SDmitry Torokhov }, 136787fd6318SDmitry Torokhov .remove = __devexit_p(i8042_remove), 136882dd9effSDmitry Torokhov .shutdown = i8042_shutdown, 136987fd6318SDmitry Torokhov }; 137087fd6318SDmitry Torokhov 137187fd6318SDmitry Torokhov static int __init i8042_init(void) 137287fd6318SDmitry Torokhov { 137387fd6318SDmitry Torokhov int err; 137487fd6318SDmitry Torokhov 137587fd6318SDmitry Torokhov dbg_init(); 137687fd6318SDmitry Torokhov 137787fd6318SDmitry Torokhov err = i8042_platform_init(); 137887fd6318SDmitry Torokhov if (err) 137987fd6318SDmitry Torokhov return err; 138087fd6318SDmitry Torokhov 1381de9ce703SDmitry Torokhov err = i8042_controller_check(); 1382de9ce703SDmitry Torokhov if (err) 1383de9ce703SDmitry Torokhov goto err_platform_exit; 138487fd6318SDmitry Torokhov 138587fd6318SDmitry Torokhov i8042_platform_device = platform_device_alloc("i8042", -1); 138687fd6318SDmitry Torokhov if (!i8042_platform_device) { 138787fd6318SDmitry Torokhov err = -ENOMEM; 1388f8113416SDmitry Torokhov goto err_platform_exit; 138987fd6318SDmitry Torokhov } 139087fd6318SDmitry Torokhov 139187fd6318SDmitry Torokhov err = platform_device_add(i8042_platform_device); 139287fd6318SDmitry Torokhov if (err) 139387fd6318SDmitry Torokhov goto err_free_device; 139487fd6318SDmitry Torokhov 1395f8113416SDmitry Torokhov err = platform_driver_probe(&i8042_driver, i8042_probe); 1396f8113416SDmitry Torokhov if (err) 1397f8113416SDmitry Torokhov goto err_del_device; 1398f8113416SDmitry Torokhov 1399de9ce703SDmitry Torokhov panic_blink = i8042_panic_blink; 1400de9ce703SDmitry Torokhov 140187fd6318SDmitry Torokhov return 0; 140287fd6318SDmitry Torokhov 1403f8113416SDmitry Torokhov err_del_device: 1404f8113416SDmitry Torokhov platform_device_del(i8042_platform_device); 140587fd6318SDmitry Torokhov err_free_device: 140687fd6318SDmitry Torokhov platform_device_put(i8042_platform_device); 140787fd6318SDmitry Torokhov err_platform_exit: 140887fd6318SDmitry Torokhov i8042_platform_exit(); 140987fd6318SDmitry Torokhov 141087fd6318SDmitry Torokhov return err; 141187fd6318SDmitry Torokhov } 141287fd6318SDmitry Torokhov 141387fd6318SDmitry Torokhov static void __exit i8042_exit(void) 141487fd6318SDmitry Torokhov { 14153ae5eaecSRussell King platform_driver_unregister(&i8042_driver); 1416f8113416SDmitry Torokhov platform_device_unregister(i8042_platform_device); 14171da177e4SLinus Torvalds i8042_platform_exit(); 14181da177e4SLinus Torvalds 14191da177e4SLinus Torvalds panic_blink = NULL; 14201da177e4SLinus Torvalds } 14211da177e4SLinus Torvalds 14221da177e4SLinus Torvalds module_init(i8042_init); 14231da177e4SLinus Torvalds module_exit(i8042_exit); 1424