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 31945ef0d4SDmitry Torokhov static unsigned int 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 351da177e4SLinus Torvalds static unsigned int 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 391da177e4SLinus Torvalds static unsigned int 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 431da177e4SLinus Torvalds static unsigned int i8042_unlock; 441da177e4SLinus Torvalds module_param_named(unlock, i8042_unlock, bool, 0); 451da177e4SLinus Torvalds MODULE_PARM_DESC(unlock, "Ignore keyboard lock."); 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds static unsigned int 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 511da177e4SLinus Torvalds static unsigned int 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 551da177e4SLinus Torvalds static unsigned int 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 591da177e4SLinus Torvalds static unsigned int 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 688987fec0SCarlos Corbacho static unsigned int 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 741da177e4SLinus Torvalds static int 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 811da177e4SLinus Torvalds static int 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 901da177e4SLinus Torvalds static DEFINE_SPINLOCK(i8042_lock); 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds struct i8042_port { 931da177e4SLinus Torvalds struct serio *serio; 941da177e4SLinus Torvalds int irq; 951da177e4SLinus Torvalds unsigned char exists; 961da177e4SLinus Torvalds signed char mux; 971da177e4SLinus Torvalds }; 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds #define I8042_KBD_PORT_NO 0 1001da177e4SLinus Torvalds #define I8042_AUX_PORT_NO 1 1011da177e4SLinus Torvalds #define I8042_MUX_PORT_NO 2 1021da177e4SLinus Torvalds #define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2) 103de9ce703SDmitry Torokhov 104de9ce703SDmitry Torokhov static struct i8042_port i8042_ports[I8042_NUM_PORTS]; 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds static unsigned char i8042_initial_ctr; 1071da177e4SLinus Torvalds static unsigned char i8042_ctr; 1081da177e4SLinus Torvalds static unsigned char i8042_mux_present; 109de9ce703SDmitry Torokhov static unsigned char i8042_kbd_irq_registered; 110de9ce703SDmitry Torokhov static unsigned char i8042_aux_irq_registered; 111817e6ba3SDmitry Torokhov static unsigned char i8042_suppress_kbd_ack; 1121da177e4SLinus Torvalds static struct platform_device *i8042_platform_device; 1131da177e4SLinus Torvalds 1147d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id); 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds /* 1171da177e4SLinus Torvalds * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to 1181da177e4SLinus Torvalds * be ready for reading values from it / writing values to it. 1191da177e4SLinus Torvalds * Called always with i8042_lock held. 1201da177e4SLinus Torvalds */ 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds static int i8042_wait_read(void) 1231da177e4SLinus Torvalds { 1241da177e4SLinus Torvalds int i = 0; 125de9ce703SDmitry Torokhov 1261da177e4SLinus Torvalds while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { 1271da177e4SLinus Torvalds udelay(50); 1281da177e4SLinus Torvalds i++; 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds return -(i == I8042_CTL_TIMEOUT); 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds static int i8042_wait_write(void) 1341da177e4SLinus Torvalds { 1351da177e4SLinus Torvalds int i = 0; 136de9ce703SDmitry Torokhov 1371da177e4SLinus Torvalds while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { 1381da177e4SLinus Torvalds udelay(50); 1391da177e4SLinus Torvalds i++; 1401da177e4SLinus Torvalds } 1411da177e4SLinus Torvalds return -(i == I8042_CTL_TIMEOUT); 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds /* 1451da177e4SLinus Torvalds * i8042_flush() flushes all data that may be in the keyboard and mouse buffers 1461da177e4SLinus Torvalds * of the i8042 down the toilet. 1471da177e4SLinus Torvalds */ 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds static int i8042_flush(void) 1501da177e4SLinus Torvalds { 1511da177e4SLinus Torvalds unsigned long flags; 1521da177e4SLinus Torvalds unsigned char data, str; 1531da177e4SLinus Torvalds int i = 0; 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) { 1581da177e4SLinus Torvalds udelay(50); 1591da177e4SLinus Torvalds data = i8042_read_data(); 1601da177e4SLinus Torvalds i++; 1611da177e4SLinus Torvalds dbg("%02x <- i8042 (flush, %s)", data, 1621da177e4SLinus Torvalds str & I8042_STR_AUXDATA ? "aux" : "kbd"); 1631da177e4SLinus Torvalds } 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds return i; 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds /* 1711da177e4SLinus Torvalds * i8042_command() executes a command on the i8042. It also sends the input 1721da177e4SLinus Torvalds * parameter(s) of the commands to it, and receives the output value(s). The 1731da177e4SLinus Torvalds * parameters are to be stored in the param array, and the output is placed 1741da177e4SLinus Torvalds * into the same array. The number of the parameters and output values is 1751da177e4SLinus Torvalds * encoded in bits 8-11 of the command number. 1761da177e4SLinus Torvalds */ 1771da177e4SLinus Torvalds 178de9ce703SDmitry Torokhov static int __i8042_command(unsigned char *param, int command) 1791da177e4SLinus Torvalds { 180de9ce703SDmitry Torokhov int i, error; 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds if (i8042_noloop && command == I8042_CMD_AUX_LOOP) 1831da177e4SLinus Torvalds return -1; 1841da177e4SLinus Torvalds 185de9ce703SDmitry Torokhov error = i8042_wait_write(); 186de9ce703SDmitry Torokhov if (error) 187de9ce703SDmitry Torokhov return error; 188463a4f76SDmitry Torokhov 1891da177e4SLinus Torvalds dbg("%02x -> i8042 (command)", command & 0xff); 1901da177e4SLinus Torvalds i8042_write_command(command & 0xff); 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds for (i = 0; i < ((command >> 12) & 0xf); i++) { 193de9ce703SDmitry Torokhov error = i8042_wait_write(); 194de9ce703SDmitry Torokhov if (error) 195de9ce703SDmitry Torokhov return error; 1961da177e4SLinus Torvalds dbg("%02x -> i8042 (parameter)", param[i]); 1971da177e4SLinus Torvalds i8042_write_data(param[i]); 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds for (i = 0; i < ((command >> 8) & 0xf); i++) { 201de9ce703SDmitry Torokhov error = i8042_wait_read(); 202de9ce703SDmitry Torokhov if (error) { 203de9ce703SDmitry Torokhov dbg(" -- i8042 (timeout)"); 204de9ce703SDmitry Torokhov return error; 205de9ce703SDmitry Torokhov } 206463a4f76SDmitry Torokhov 207463a4f76SDmitry Torokhov if (command == I8042_CMD_AUX_LOOP && 208463a4f76SDmitry Torokhov !(i8042_read_status() & I8042_STR_AUXDATA)) { 209de9ce703SDmitry Torokhov dbg(" -- i8042 (auxerr)"); 210de9ce703SDmitry Torokhov return -1; 211463a4f76SDmitry Torokhov } 212463a4f76SDmitry Torokhov 2131da177e4SLinus Torvalds param[i] = i8042_read_data(); 2141da177e4SLinus Torvalds dbg("%02x <- i8042 (return)", param[i]); 2151da177e4SLinus Torvalds } 2161da177e4SLinus Torvalds 217de9ce703SDmitry Torokhov return 0; 218de9ce703SDmitry Torokhov } 2191da177e4SLinus Torvalds 220553a05b8SMárton Németh int i8042_command(unsigned char *param, int command) 221de9ce703SDmitry Torokhov { 222de9ce703SDmitry Torokhov unsigned long flags; 223de9ce703SDmitry Torokhov int retval; 224de9ce703SDmitry Torokhov 225de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 226de9ce703SDmitry Torokhov retval = __i8042_command(param, command); 227463a4f76SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 228de9ce703SDmitry Torokhov 2291da177e4SLinus Torvalds return retval; 2301da177e4SLinus Torvalds } 231553a05b8SMárton Németh EXPORT_SYMBOL(i8042_command); 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds /* 2341da177e4SLinus Torvalds * i8042_kbd_write() sends a byte out through the keyboard interface. 2351da177e4SLinus Torvalds */ 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds static int i8042_kbd_write(struct serio *port, unsigned char c) 2381da177e4SLinus Torvalds { 2391da177e4SLinus Torvalds unsigned long flags; 2401da177e4SLinus Torvalds int retval = 0; 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds if (!(retval = i8042_wait_write())) { 2451da177e4SLinus Torvalds dbg("%02x -> i8042 (kbd-data)", c); 2461da177e4SLinus Torvalds i8042_write_data(c); 2471da177e4SLinus Torvalds } 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds return retval; 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds /* 2551da177e4SLinus Torvalds * i8042_aux_write() sends a byte out through the aux interface. 2561da177e4SLinus Torvalds */ 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvalds static int i8042_aux_write(struct serio *serio, unsigned char c) 2591da177e4SLinus Torvalds { 2601da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 2611da177e4SLinus Torvalds 262f4e3c711SDmitry Torokhov return i8042_command(&c, port->mux == -1 ? 263f4e3c711SDmitry Torokhov I8042_CMD_AUX_SEND : 264f4e3c711SDmitry Torokhov I8042_CMD_MUX_SEND + port->mux); 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds 267*5ddbc77cSDmitry Torokhov 268*5ddbc77cSDmitry Torokhov /* 269*5ddbc77cSDmitry Torokhov * i8042_aux_close attempts to clear AUX or KBD port state by disabling 270*5ddbc77cSDmitry Torokhov * and then re-enabling it. 271*5ddbc77cSDmitry Torokhov */ 272*5ddbc77cSDmitry Torokhov 273*5ddbc77cSDmitry Torokhov static void i8042_port_close(struct serio *serio) 274*5ddbc77cSDmitry Torokhov { 275*5ddbc77cSDmitry Torokhov int irq_bit; 276*5ddbc77cSDmitry Torokhov int disable_bit; 277*5ddbc77cSDmitry Torokhov const char *port_name; 278*5ddbc77cSDmitry Torokhov 279*5ddbc77cSDmitry Torokhov if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) { 280*5ddbc77cSDmitry Torokhov irq_bit = I8042_CTR_AUXINT; 281*5ddbc77cSDmitry Torokhov disable_bit = I8042_CTR_AUXDIS; 282*5ddbc77cSDmitry Torokhov port_name = "AUX"; 283*5ddbc77cSDmitry Torokhov } else { 284*5ddbc77cSDmitry Torokhov irq_bit = I8042_CTR_KBDINT; 285*5ddbc77cSDmitry Torokhov disable_bit = I8042_CTR_KBDDIS; 286*5ddbc77cSDmitry Torokhov port_name = "KBD"; 287*5ddbc77cSDmitry Torokhov } 288*5ddbc77cSDmitry Torokhov 289*5ddbc77cSDmitry Torokhov i8042_ctr &= ~irq_bit; 290*5ddbc77cSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 291*5ddbc77cSDmitry Torokhov printk(KERN_WARNING 292*5ddbc77cSDmitry Torokhov "i8042.c: Can't write CTR while closing %s port.\n", 293*5ddbc77cSDmitry Torokhov port_name); 294*5ddbc77cSDmitry Torokhov 295*5ddbc77cSDmitry Torokhov udelay(50); 296*5ddbc77cSDmitry Torokhov 297*5ddbc77cSDmitry Torokhov i8042_ctr &= ~disable_bit; 298*5ddbc77cSDmitry Torokhov i8042_ctr |= irq_bit; 299*5ddbc77cSDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 300*5ddbc77cSDmitry Torokhov printk(KERN_ERR "i8042.c: Can't reactivate %s port.\n", 301*5ddbc77cSDmitry Torokhov port_name); 302*5ddbc77cSDmitry Torokhov 303*5ddbc77cSDmitry Torokhov /* 304*5ddbc77cSDmitry Torokhov * See if there is any data appeared while we were messing with 305*5ddbc77cSDmitry Torokhov * port state. 306*5ddbc77cSDmitry Torokhov */ 307*5ddbc77cSDmitry Torokhov i8042_interrupt(0, NULL); 308*5ddbc77cSDmitry Torokhov } 309*5ddbc77cSDmitry Torokhov 3101da177e4SLinus Torvalds /* 3111da177e4SLinus Torvalds * i8042_start() is called by serio core when port is about to finish 3121da177e4SLinus Torvalds * registering. It will mark port as existing so i8042_interrupt can 3131da177e4SLinus Torvalds * start sending data through it. 3141da177e4SLinus Torvalds */ 3151da177e4SLinus Torvalds static int i8042_start(struct serio *serio) 3161da177e4SLinus Torvalds { 3171da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds port->exists = 1; 3201da177e4SLinus Torvalds mb(); 3211da177e4SLinus Torvalds return 0; 3221da177e4SLinus Torvalds } 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds /* 3251da177e4SLinus Torvalds * i8042_stop() marks serio port as non-existing so i8042_interrupt 3261da177e4SLinus Torvalds * will not try to send data to the port that is about to go away. 3271da177e4SLinus Torvalds * The function is called by serio core as part of unregister procedure. 3281da177e4SLinus Torvalds */ 3291da177e4SLinus Torvalds static void i8042_stop(struct serio *serio) 3301da177e4SLinus Torvalds { 3311da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds port->exists = 0; 334a8399c51SDmitry Torokhov 335a8399c51SDmitry Torokhov /* 336a8399c51SDmitry Torokhov * We synchronize with both AUX and KBD IRQs because there is 337a8399c51SDmitry Torokhov * a (very unlikely) chance that AUX IRQ is raised for KBD port 338a8399c51SDmitry Torokhov * and vice versa. 339a8399c51SDmitry Torokhov */ 340a8399c51SDmitry Torokhov synchronize_irq(I8042_AUX_IRQ); 341a8399c51SDmitry Torokhov synchronize_irq(I8042_KBD_IRQ); 3421da177e4SLinus Torvalds port->serio = NULL; 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds /* 3461da177e4SLinus Torvalds * i8042_interrupt() is the most important function in this driver - 3471da177e4SLinus Torvalds * it handles the interrupts from the i8042, and sends incoming bytes 3481da177e4SLinus Torvalds * to the upper layers. 3491da177e4SLinus Torvalds */ 3501da177e4SLinus Torvalds 3517d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id) 3521da177e4SLinus Torvalds { 3531da177e4SLinus Torvalds struct i8042_port *port; 3541da177e4SLinus Torvalds unsigned long flags; 3551da177e4SLinus Torvalds unsigned char str, data; 3561da177e4SLinus Torvalds unsigned int dfl; 3571da177e4SLinus Torvalds unsigned int port_no; 358817e6ba3SDmitry Torokhov int ret = 1; 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 3611da177e4SLinus Torvalds str = i8042_read_status(); 3621da177e4SLinus Torvalds if (unlikely(~str & I8042_STR_OBF)) { 3631da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 3641da177e4SLinus Torvalds if (irq) dbg("Interrupt %d, without any data", irq); 3651da177e4SLinus Torvalds ret = 0; 3661da177e4SLinus Torvalds goto out; 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds data = i8042_read_data(); 3691da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { 3721da177e4SLinus Torvalds static unsigned long last_transmit; 3731da177e4SLinus Torvalds static unsigned char last_str; 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds dfl = 0; 3761da177e4SLinus Torvalds if (str & I8042_STR_MUXERR) { 3771da177e4SLinus Torvalds dbg("MUX error, status is %02x, data is %02x", str, data); 3781da177e4SLinus Torvalds /* 3791da177e4SLinus Torvalds * When MUXERR condition is signalled the data register can only contain 3801da177e4SLinus Torvalds * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately 381a216a4b6SDmitry Torokhov * it is not always the case. Some KBCs also report 0xfc when there is 382a216a4b6SDmitry Torokhov * nothing connected to the port while others sometimes get confused which 383a216a4b6SDmitry Torokhov * port the data came from and signal error leaving the data intact. They 384a216a4b6SDmitry Torokhov * _do not_ revert to legacy mode (actually I've never seen KBC reverting 385a216a4b6SDmitry Torokhov * to legacy mode yet, when we see one we'll add proper handling). 386a216a4b6SDmitry Torokhov * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the 387a216a4b6SDmitry Torokhov * rest assume that the data came from the same serio last byte 3881da177e4SLinus Torvalds * was transmitted (if transmission happened not too long ago). 3891da177e4SLinus Torvalds */ 390a216a4b6SDmitry Torokhov 391a216a4b6SDmitry Torokhov switch (data) { 392a216a4b6SDmitry Torokhov default: 3931da177e4SLinus Torvalds if (time_before(jiffies, last_transmit + HZ/10)) { 3941da177e4SLinus Torvalds str = last_str; 3951da177e4SLinus Torvalds break; 3961da177e4SLinus Torvalds } 3971da177e4SLinus Torvalds /* fall through - report timeout */ 398a216a4b6SDmitry Torokhov case 0xfc: 3991da177e4SLinus Torvalds case 0xfd: 4001da177e4SLinus Torvalds case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break; 4011da177e4SLinus Torvalds case 0xff: dfl = SERIO_PARITY; data = 0xfe; break; 4021da177e4SLinus Torvalds } 4031da177e4SLinus Torvalds } 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3); 4061da177e4SLinus Torvalds last_str = str; 4071da177e4SLinus Torvalds last_transmit = jiffies; 4081da177e4SLinus Torvalds } else { 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | 4111da177e4SLinus Torvalds ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds port_no = (str & I8042_STR_AUXDATA) ? 4141da177e4SLinus Torvalds I8042_AUX_PORT_NO : I8042_KBD_PORT_NO; 4151da177e4SLinus Torvalds } 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds port = &i8042_ports[port_no]; 4181da177e4SLinus Torvalds 419de9ce703SDmitry Torokhov dbg("%02x <- i8042 (interrupt, %d, %d%s%s)", 420de9ce703SDmitry Torokhov data, port_no, irq, 4211da177e4SLinus Torvalds dfl & SERIO_PARITY ? ", bad parity" : "", 4221da177e4SLinus Torvalds dfl & SERIO_TIMEOUT ? ", timeout" : ""); 4231da177e4SLinus Torvalds 424817e6ba3SDmitry Torokhov if (unlikely(i8042_suppress_kbd_ack)) 425817e6ba3SDmitry Torokhov if (port_no == I8042_KBD_PORT_NO && 426817e6ba3SDmitry Torokhov (data == 0xfa || data == 0xfe)) { 42719f3c3e3SDmitry Torokhov i8042_suppress_kbd_ack--; 428817e6ba3SDmitry Torokhov goto out; 429817e6ba3SDmitry Torokhov } 430817e6ba3SDmitry Torokhov 4311da177e4SLinus Torvalds if (likely(port->exists)) 4327d12e780SDavid Howells serio_interrupt(port->serio, data, dfl); 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds out: 4351da177e4SLinus Torvalds return IRQ_RETVAL(ret); 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds /* 439*5ddbc77cSDmitry Torokhov * i8042_enable_kbd_port enables keyboard port on chip 440de9ce703SDmitry Torokhov */ 441de9ce703SDmitry Torokhov 442de9ce703SDmitry Torokhov static int i8042_enable_kbd_port(void) 443de9ce703SDmitry Torokhov { 444de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_KBDDIS; 445de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_KBDINT; 446de9ce703SDmitry Torokhov 447de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 448018db6bbSMarkus Armbruster i8042_ctr &= ~I8042_CTR_KBDINT; 449018db6bbSMarkus Armbruster i8042_ctr |= I8042_CTR_KBDDIS; 450de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n"); 451de9ce703SDmitry Torokhov return -EIO; 452de9ce703SDmitry Torokhov } 453de9ce703SDmitry Torokhov 454de9ce703SDmitry Torokhov return 0; 455de9ce703SDmitry Torokhov } 456de9ce703SDmitry Torokhov 457de9ce703SDmitry Torokhov /* 458de9ce703SDmitry Torokhov * i8042_enable_aux_port enables AUX (mouse) port on chip 459de9ce703SDmitry Torokhov */ 460de9ce703SDmitry Torokhov 461de9ce703SDmitry Torokhov static int i8042_enable_aux_port(void) 462de9ce703SDmitry Torokhov { 463de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_AUXDIS; 464de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXINT; 465de9ce703SDmitry Torokhov 466de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 467018db6bbSMarkus Armbruster i8042_ctr &= ~I8042_CTR_AUXINT; 468018db6bbSMarkus Armbruster i8042_ctr |= I8042_CTR_AUXDIS; 469de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n"); 470de9ce703SDmitry Torokhov return -EIO; 471de9ce703SDmitry Torokhov } 472de9ce703SDmitry Torokhov 473de9ce703SDmitry Torokhov return 0; 474de9ce703SDmitry Torokhov } 475de9ce703SDmitry Torokhov 476de9ce703SDmitry Torokhov /* 477de9ce703SDmitry Torokhov * i8042_enable_mux_ports enables 4 individual AUX ports after 478de9ce703SDmitry Torokhov * the controller has been switched into Multiplexed mode 479de9ce703SDmitry Torokhov */ 480de9ce703SDmitry Torokhov 481de9ce703SDmitry Torokhov static int i8042_enable_mux_ports(void) 482de9ce703SDmitry Torokhov { 483de9ce703SDmitry Torokhov unsigned char param; 484de9ce703SDmitry Torokhov int i; 485de9ce703SDmitry Torokhov 486de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { 487de9ce703SDmitry Torokhov i8042_command(¶m, I8042_CMD_MUX_PFX + i); 488de9ce703SDmitry Torokhov i8042_command(¶m, I8042_CMD_AUX_ENABLE); 489de9ce703SDmitry Torokhov } 490de9ce703SDmitry Torokhov 491de9ce703SDmitry Torokhov return i8042_enable_aux_port(); 492de9ce703SDmitry Torokhov } 493de9ce703SDmitry Torokhov 494de9ce703SDmitry Torokhov /* 4951da177e4SLinus Torvalds * i8042_set_mux_mode checks whether the controller has an active 4961da177e4SLinus Torvalds * multiplexor and puts the chip into Multiplexed (1) or Legacy (0) mode. 4971da177e4SLinus Torvalds */ 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version) 5001da177e4SLinus Torvalds { 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds unsigned char param; 5031da177e4SLinus Torvalds /* 5041da177e4SLinus Torvalds * Get rid of bytes in the queue. 5051da177e4SLinus Torvalds */ 5061da177e4SLinus Torvalds 5071da177e4SLinus Torvalds i8042_flush(); 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds /* 5101da177e4SLinus Torvalds * Internal loopback test - send three bytes, they should come back from the 511de9ce703SDmitry Torokhov * mouse interface, the last should be version. 5121da177e4SLinus Torvalds */ 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds param = 0xf0; 515463a4f76SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xf0) 5161da177e4SLinus Torvalds return -1; 5171da177e4SLinus Torvalds param = mode ? 0x56 : 0xf6; 518463a4f76SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != (mode ? 0x56 : 0xf6)) 5191da177e4SLinus Torvalds return -1; 5201da177e4SLinus Torvalds param = mode ? 0xa4 : 0xa5; 521463a4f76SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == (mode ? 0xa4 : 0xa5)) 5221da177e4SLinus Torvalds return -1; 5231da177e4SLinus Torvalds 5241da177e4SLinus Torvalds if (mux_version) 525463a4f76SDmitry Torokhov *mux_version = param; 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds return 0; 5281da177e4SLinus Torvalds } 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds /* 5311da177e4SLinus Torvalds * i8042_check_mux() checks whether the controller supports the PS/2 Active 5321da177e4SLinus Torvalds * Multiplexing specification by Synaptics, Phoenix, Insyde and 5331da177e4SLinus Torvalds * LCS/Telegraphics. 5341da177e4SLinus Torvalds */ 5351da177e4SLinus Torvalds 53687fd6318SDmitry Torokhov static int __devinit i8042_check_mux(void) 5371da177e4SLinus Torvalds { 5381da177e4SLinus Torvalds unsigned char mux_version; 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds if (i8042_set_mux_mode(1, &mux_version)) 5411da177e4SLinus Torvalds return -1; 5421da177e4SLinus Torvalds 543de9ce703SDmitry Torokhov /* 544de9ce703SDmitry Torokhov * Workaround for interference with USB Legacy emulation 545de9ce703SDmitry Torokhov * that causes a v10.12 MUX to be found. 546de9ce703SDmitry Torokhov */ 5471da177e4SLinus Torvalds if (mux_version == 0xAC) 5481da177e4SLinus Torvalds return -1; 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", 5511da177e4SLinus Torvalds (mux_version >> 4) & 0xf, mux_version & 0xf); 5521da177e4SLinus Torvalds 553de9ce703SDmitry Torokhov /* 554de9ce703SDmitry Torokhov * Disable all muxed ports by disabling AUX. 555de9ce703SDmitry Torokhov */ 556de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXDIS; 557de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_AUXINT; 558de9ce703SDmitry Torokhov 559de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 560de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n"); 561de9ce703SDmitry Torokhov return -EIO; 562de9ce703SDmitry Torokhov } 5631da177e4SLinus Torvalds 5641da177e4SLinus Torvalds i8042_mux_present = 1; 565de9ce703SDmitry Torokhov 5661da177e4SLinus Torvalds return 0; 5671da177e4SLinus Torvalds } 5681da177e4SLinus Torvalds 569de9ce703SDmitry Torokhov /* 570de9ce703SDmitry Torokhov * The following is used to test AUX IRQ delivery. 571de9ce703SDmitry Torokhov */ 572de9ce703SDmitry Torokhov static struct completion i8042_aux_irq_delivered __devinitdata; 573de9ce703SDmitry Torokhov static int i8042_irq_being_tested __devinitdata; 574de9ce703SDmitry Torokhov 5757d12e780SDavid Howells static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id) 576de9ce703SDmitry Torokhov { 577de9ce703SDmitry Torokhov unsigned long flags; 578de9ce703SDmitry Torokhov unsigned char str, data; 579e3758b2aSFernando Luis Vázquez Cao int ret = 0; 580de9ce703SDmitry Torokhov 581de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 582de9ce703SDmitry Torokhov str = i8042_read_status(); 583de9ce703SDmitry Torokhov if (str & I8042_STR_OBF) { 584de9ce703SDmitry Torokhov data = i8042_read_data(); 585de9ce703SDmitry Torokhov if (i8042_irq_being_tested && 586de9ce703SDmitry Torokhov data == 0xa5 && (str & I8042_STR_AUXDATA)) 587de9ce703SDmitry Torokhov complete(&i8042_aux_irq_delivered); 588e3758b2aSFernando Luis Vázquez Cao ret = 1; 589de9ce703SDmitry Torokhov } 590de9ce703SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 591de9ce703SDmitry Torokhov 592e3758b2aSFernando Luis Vázquez Cao return IRQ_RETVAL(ret); 593de9ce703SDmitry Torokhov } 594de9ce703SDmitry Torokhov 595d2ada559SRoland Scheidegger /* 596d2ada559SRoland Scheidegger * i8042_toggle_aux - enables or disables AUX port on i8042 via command and 597d2ada559SRoland Scheidegger * verifies success by readinng CTR. Used when testing for presence of AUX 598d2ada559SRoland Scheidegger * port. 599d2ada559SRoland Scheidegger */ 600d2ada559SRoland Scheidegger static int __devinit i8042_toggle_aux(int on) 601d2ada559SRoland Scheidegger { 602d2ada559SRoland Scheidegger unsigned char param; 603d2ada559SRoland Scheidegger int i; 604d2ada559SRoland Scheidegger 605d2ada559SRoland Scheidegger if (i8042_command(¶m, 606d2ada559SRoland Scheidegger on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE)) 607d2ada559SRoland Scheidegger return -1; 608d2ada559SRoland Scheidegger 609d2ada559SRoland Scheidegger /* some chips need some time to set the I8042_CTR_AUXDIS bit */ 610d2ada559SRoland Scheidegger for (i = 0; i < 100; i++) { 611d2ada559SRoland Scheidegger udelay(50); 612d2ada559SRoland Scheidegger 613d2ada559SRoland Scheidegger if (i8042_command(¶m, I8042_CMD_CTL_RCTR)) 614d2ada559SRoland Scheidegger return -1; 615d2ada559SRoland Scheidegger 616d2ada559SRoland Scheidegger if (!(param & I8042_CTR_AUXDIS) == on) 617d2ada559SRoland Scheidegger return 0; 618d2ada559SRoland Scheidegger } 619d2ada559SRoland Scheidegger 620d2ada559SRoland Scheidegger return -1; 621d2ada559SRoland Scheidegger } 6221da177e4SLinus Torvalds 6231da177e4SLinus Torvalds /* 6241da177e4SLinus Torvalds * i8042_check_aux() applies as much paranoia as it can at detecting 6251da177e4SLinus Torvalds * the presence of an AUX interface. 6261da177e4SLinus Torvalds */ 6271da177e4SLinus Torvalds 62887fd6318SDmitry Torokhov static int __devinit i8042_check_aux(void) 6291da177e4SLinus Torvalds { 630de9ce703SDmitry Torokhov int retval = -1; 631de9ce703SDmitry Torokhov int irq_registered = 0; 6321e4865f8SDmitry Torokhov int aux_loop_broken = 0; 633de9ce703SDmitry Torokhov unsigned long flags; 6341da177e4SLinus Torvalds unsigned char param; 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds /* 6371da177e4SLinus Torvalds * Get rid of bytes in the queue. 6381da177e4SLinus Torvalds */ 6391da177e4SLinus Torvalds 6401da177e4SLinus Torvalds i8042_flush(); 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds /* 6431da177e4SLinus Torvalds * Internal loopback test - filters out AT-type i8042's. Unfortunately 6441da177e4SLinus Torvalds * SiS screwed up and their 5597 doesn't support the LOOP command even 6451da177e4SLinus Torvalds * though it has an AUX port. 6461da177e4SLinus Torvalds */ 6471da177e4SLinus Torvalds 6481da177e4SLinus Torvalds param = 0x5a; 6493ca5de6dSDmitry Torokhov retval = i8042_command(¶m, I8042_CMD_AUX_LOOP); 6503ca5de6dSDmitry Torokhov if (retval || param != 0x5a) { 6511da177e4SLinus Torvalds 6521da177e4SLinus Torvalds /* 6531da177e4SLinus Torvalds * External connection test - filters out AT-soldered PS/2 i8042's 6541da177e4SLinus Torvalds * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error 6551da177e4SLinus Torvalds * 0xfa - no error on some notebooks which ignore the spec 6561da177e4SLinus Torvalds * Because it's common for chipsets to return error on perfectly functioning 6571da177e4SLinus Torvalds * AUX ports, we test for this only when the LOOP command failed. 6581da177e4SLinus Torvalds */ 6591da177e4SLinus Torvalds 660de9ce703SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_TEST) || 661de9ce703SDmitry Torokhov (param && param != 0xfa && param != 0xff)) 6621da177e4SLinus Torvalds return -1; 6631e4865f8SDmitry Torokhov 6643ca5de6dSDmitry Torokhov /* 6653ca5de6dSDmitry Torokhov * If AUX_LOOP completed without error but returned unexpected data 6663ca5de6dSDmitry Torokhov * mark it as broken 6673ca5de6dSDmitry Torokhov */ 6683ca5de6dSDmitry Torokhov if (!retval) 6691e4865f8SDmitry Torokhov aux_loop_broken = 1; 6701da177e4SLinus Torvalds } 6711da177e4SLinus Torvalds 6721da177e4SLinus Torvalds /* 6731da177e4SLinus Torvalds * Bit assignment test - filters out PS/2 i8042's in AT mode 6741da177e4SLinus Torvalds */ 6751da177e4SLinus Torvalds 676d2ada559SRoland Scheidegger if (i8042_toggle_aux(0)) { 6771da177e4SLinus Torvalds printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n"); 6781da177e4SLinus Torvalds printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n"); 6791da177e4SLinus Torvalds } 6801da177e4SLinus Torvalds 681d2ada559SRoland Scheidegger if (i8042_toggle_aux(1)) 6821da177e4SLinus Torvalds return -1; 6831da177e4SLinus Torvalds 6841da177e4SLinus Torvalds /* 685de9ce703SDmitry Torokhov * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and 686de9ce703SDmitry Torokhov * used it for a PCI card or somethig else. 687de9ce703SDmitry Torokhov */ 688de9ce703SDmitry Torokhov 6891c7827aeSDmitry Torokhov if (i8042_noloop || i8042_bypass_aux_irq_test || aux_loop_broken) { 690de9ce703SDmitry Torokhov /* 691de9ce703SDmitry Torokhov * Without LOOP command we can't test AUX IRQ delivery. Assume the port 692de9ce703SDmitry Torokhov * is working and hope we are right. 693de9ce703SDmitry Torokhov */ 694de9ce703SDmitry Torokhov retval = 0; 695de9ce703SDmitry Torokhov goto out; 696de9ce703SDmitry Torokhov } 697de9ce703SDmitry Torokhov 698de9ce703SDmitry Torokhov if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED, 699de9ce703SDmitry Torokhov "i8042", i8042_platform_device)) 700de9ce703SDmitry Torokhov goto out; 701de9ce703SDmitry Torokhov 702de9ce703SDmitry Torokhov irq_registered = 1; 703de9ce703SDmitry Torokhov 704de9ce703SDmitry Torokhov if (i8042_enable_aux_port()) 705de9ce703SDmitry Torokhov goto out; 706de9ce703SDmitry Torokhov 707de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 708de9ce703SDmitry Torokhov 709de9ce703SDmitry Torokhov init_completion(&i8042_aux_irq_delivered); 710de9ce703SDmitry Torokhov i8042_irq_being_tested = 1; 711de9ce703SDmitry Torokhov 712de9ce703SDmitry Torokhov param = 0xa5; 713de9ce703SDmitry Torokhov retval = __i8042_command(¶m, I8042_CMD_AUX_LOOP & 0xf0ff); 714de9ce703SDmitry Torokhov 715de9ce703SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 716de9ce703SDmitry Torokhov 717de9ce703SDmitry Torokhov if (retval) 718de9ce703SDmitry Torokhov goto out; 719de9ce703SDmitry Torokhov 720de9ce703SDmitry Torokhov if (wait_for_completion_timeout(&i8042_aux_irq_delivered, 721de9ce703SDmitry Torokhov msecs_to_jiffies(250)) == 0) { 722de9ce703SDmitry Torokhov /* 723de9ce703SDmitry Torokhov * AUX IRQ was never delivered so we need to flush the controller to 724de9ce703SDmitry Torokhov * get rid of the byte we put there; otherwise keyboard may not work. 725de9ce703SDmitry Torokhov */ 726de9ce703SDmitry Torokhov i8042_flush(); 727de9ce703SDmitry Torokhov retval = -1; 728de9ce703SDmitry Torokhov } 729de9ce703SDmitry Torokhov 730de9ce703SDmitry Torokhov out: 731de9ce703SDmitry Torokhov 732de9ce703SDmitry Torokhov /* 7331da177e4SLinus Torvalds * Disable the interface. 7341da177e4SLinus Torvalds */ 7351da177e4SLinus Torvalds 7361da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_AUXDIS; 7371da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_AUXINT; 7381da177e4SLinus Torvalds 7391da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 740de9ce703SDmitry Torokhov retval = -1; 741de9ce703SDmitry Torokhov 742de9ce703SDmitry Torokhov if (irq_registered) 743de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 744de9ce703SDmitry Torokhov 745de9ce703SDmitry Torokhov return retval; 746de9ce703SDmitry Torokhov } 747de9ce703SDmitry Torokhov 748de9ce703SDmitry Torokhov static int i8042_controller_check(void) 749de9ce703SDmitry Torokhov { 750de9ce703SDmitry Torokhov if (i8042_flush() == I8042_BUFFER_SIZE) { 751de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: No controller found.\n"); 752de9ce703SDmitry Torokhov return -ENODEV; 753de9ce703SDmitry Torokhov } 7541da177e4SLinus Torvalds 7551da177e4SLinus Torvalds return 0; 7561da177e4SLinus Torvalds } 7571da177e4SLinus Torvalds 758de9ce703SDmitry Torokhov static int i8042_controller_selftest(void) 7592673c836SVojtech Pavlik { 7602673c836SVojtech Pavlik unsigned char param; 7615ea2fc64SArjan van de Ven int i = 0; 7622673c836SVojtech Pavlik 7632673c836SVojtech Pavlik if (!i8042_reset) 7642673c836SVojtech Pavlik return 0; 7652673c836SVojtech Pavlik 7665ea2fc64SArjan van de Ven /* 7675ea2fc64SArjan van de Ven * We try this 5 times; on some really fragile systems this does not 7685ea2fc64SArjan van de Ven * take the first time... 7695ea2fc64SArjan van de Ven */ 7705ea2fc64SArjan van de Ven do { 7715ea2fc64SArjan van de Ven 7722673c836SVojtech Pavlik if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { 7732673c836SVojtech Pavlik printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); 774de9ce703SDmitry Torokhov return -ENODEV; 7752673c836SVojtech Pavlik } 7762673c836SVojtech Pavlik 7775ea2fc64SArjan van de Ven if (param == I8042_RET_CTL_TEST) 7785ea2fc64SArjan van de Ven return 0; 7795ea2fc64SArjan van de Ven 7802673c836SVojtech Pavlik printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", 7812673c836SVojtech Pavlik param, I8042_RET_CTL_TEST); 7825ea2fc64SArjan van de Ven msleep(50); 7835ea2fc64SArjan van de Ven } while (i++ < 5); 7842673c836SVojtech Pavlik 7855ea2fc64SArjan van de Ven #ifdef CONFIG_X86 7865ea2fc64SArjan van de Ven /* 7875ea2fc64SArjan van de Ven * On x86, we don't fail entire i8042 initialization if controller 7885ea2fc64SArjan van de Ven * reset fails in hopes that keyboard port will still be functional 7895ea2fc64SArjan van de Ven * and user will still get a working keyboard. This is especially 7905ea2fc64SArjan van de Ven * important on netbooks. On other arches we trust hardware more. 7915ea2fc64SArjan van de Ven */ 7925ea2fc64SArjan van de Ven printk(KERN_INFO 7935ea2fc64SArjan van de Ven "i8042: giving up on controller selftest, continuing anyway...\n"); 7942673c836SVojtech Pavlik return 0; 7955ea2fc64SArjan van de Ven #else 7965ea2fc64SArjan van de Ven return -EIO; 7975ea2fc64SArjan van de Ven #endif 7982673c836SVojtech Pavlik } 7991da177e4SLinus Torvalds 8001da177e4SLinus Torvalds /* 8011da177e4SLinus Torvalds * i8042_controller init initializes the i8042 controller, and, 8021da177e4SLinus Torvalds * most importantly, sets it into non-xlated mode if that's 8031da177e4SLinus Torvalds * desired. 8041da177e4SLinus Torvalds */ 8051da177e4SLinus Torvalds 8061da177e4SLinus Torvalds static int i8042_controller_init(void) 8071da177e4SLinus Torvalds { 8081da177e4SLinus Torvalds unsigned long flags; 8091da177e4SLinus Torvalds 8101da177e4SLinus Torvalds /* 8111da177e4SLinus Torvalds * Save the CTR for restoral on unload / reboot. 8121da177e4SLinus Torvalds */ 8131da177e4SLinus Torvalds 8141da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { 8151da177e4SLinus Torvalds printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); 816de9ce703SDmitry Torokhov return -EIO; 8171da177e4SLinus Torvalds } 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds i8042_initial_ctr = i8042_ctr; 8201da177e4SLinus Torvalds 8211da177e4SLinus Torvalds /* 8221da177e4SLinus Torvalds * Disable the keyboard interface and interrupt. 8231da177e4SLinus Torvalds */ 8241da177e4SLinus Torvalds 8251da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_KBDDIS; 8261da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_KBDINT; 8271da177e4SLinus Torvalds 8281da177e4SLinus Torvalds /* 8291da177e4SLinus Torvalds * Handle keylock. 8301da177e4SLinus Torvalds */ 8311da177e4SLinus Torvalds 8321da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 8331da177e4SLinus Torvalds if (~i8042_read_status() & I8042_STR_KEYLOCK) { 8341da177e4SLinus Torvalds if (i8042_unlock) 8351da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_IGNKEYLOCK; 8361da177e4SLinus Torvalds else 8371da177e4SLinus Torvalds printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); 8381da177e4SLinus Torvalds } 8391da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds /* 8421da177e4SLinus Torvalds * If the chip is configured into nontranslated mode by the BIOS, don't 8431da177e4SLinus Torvalds * bother enabling translating and be happy. 8441da177e4SLinus Torvalds */ 8451da177e4SLinus Torvalds 8461da177e4SLinus Torvalds if (~i8042_ctr & I8042_CTR_XLATE) 8471da177e4SLinus Torvalds i8042_direct = 1; 8481da177e4SLinus Torvalds 8491da177e4SLinus Torvalds /* 8501da177e4SLinus Torvalds * Set nontranslated mode for the kbd interface if requested by an option. 8511da177e4SLinus Torvalds * After this the kbd interface becomes a simple serial in/out, like the aux 8521da177e4SLinus Torvalds * interface is. We don't do this by default, since it can confuse notebook 8531da177e4SLinus Torvalds * BIOSes. 8541da177e4SLinus Torvalds */ 8551da177e4SLinus Torvalds 8561da177e4SLinus Torvalds if (i8042_direct) 8571da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_XLATE; 8581da177e4SLinus Torvalds 8591da177e4SLinus Torvalds /* 8601da177e4SLinus Torvalds * Write CTR back. 8611da177e4SLinus Torvalds */ 8621da177e4SLinus Torvalds 8631da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 8641da177e4SLinus Torvalds printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); 865de9ce703SDmitry Torokhov return -EIO; 8661da177e4SLinus Torvalds } 8671da177e4SLinus Torvalds 8681da177e4SLinus Torvalds return 0; 8691da177e4SLinus Torvalds } 8701da177e4SLinus Torvalds 8711da177e4SLinus Torvalds 8721da177e4SLinus Torvalds /* 873de9ce703SDmitry Torokhov * Reset the controller and reset CRT to the original value set by BIOS. 8741da177e4SLinus Torvalds */ 8751da177e4SLinus Torvalds 876de9ce703SDmitry Torokhov static void i8042_controller_reset(void) 877de9ce703SDmitry Torokhov { 878de9ce703SDmitry Torokhov i8042_flush(); 8791da177e4SLinus Torvalds 8801da177e4SLinus Torvalds /* 8818d04ddb6SDmitry Torokhov * Disable both KBD and AUX interfaces so they don't get in the way 8828d04ddb6SDmitry Torokhov */ 8838d04ddb6SDmitry Torokhov 8848d04ddb6SDmitry Torokhov i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS; 8858d04ddb6SDmitry Torokhov i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT); 8868d04ddb6SDmitry Torokhov 887*5ddbc77cSDmitry Torokhov if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR)) 888*5ddbc77cSDmitry Torokhov printk(KERN_WARNING "i8042.c: Can't write CTR while resetting.\n"); 889*5ddbc77cSDmitry Torokhov 8908d04ddb6SDmitry Torokhov /* 8911da177e4SLinus Torvalds * Disable MUX mode if present. 8921da177e4SLinus Torvalds */ 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds if (i8042_mux_present) 8951da177e4SLinus Torvalds i8042_set_mux_mode(0, NULL); 8961da177e4SLinus Torvalds 8971da177e4SLinus Torvalds /* 898de9ce703SDmitry Torokhov * Reset the controller if requested. 899de9ce703SDmitry Torokhov */ 900de9ce703SDmitry Torokhov 901de9ce703SDmitry Torokhov i8042_controller_selftest(); 902de9ce703SDmitry Torokhov 903de9ce703SDmitry Torokhov /* 9041da177e4SLinus Torvalds * Restore the original control register setting. 9051da177e4SLinus Torvalds */ 9061da177e4SLinus Torvalds 907de9ce703SDmitry Torokhov if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR)) 9081da177e4SLinus Torvalds printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); 9091da177e4SLinus Torvalds } 9101da177e4SLinus Torvalds 9111da177e4SLinus Torvalds 9121da177e4SLinus Torvalds /* 9131da177e4SLinus Torvalds * i8042_panic_blink() will flash the keyboard LEDs and is called when 9141da177e4SLinus Torvalds * kernel panics. Flashing LEDs is useful for users running X who may 9151da177e4SLinus Torvalds * not see the console and will help distingushing panics from "real" 9161da177e4SLinus Torvalds * lockups. 9171da177e4SLinus Torvalds * 9181da177e4SLinus Torvalds * Note that DELAY has a limit of 10ms so we will not get stuck here 9191da177e4SLinus Torvalds * waiting for KBC to free up even if KBD interrupt is off 9201da177e4SLinus Torvalds */ 9211da177e4SLinus Torvalds 9221da177e4SLinus Torvalds #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0) 9231da177e4SLinus Torvalds 9241da177e4SLinus Torvalds static long i8042_panic_blink(long count) 9251da177e4SLinus Torvalds { 9261da177e4SLinus Torvalds long delay = 0; 9271da177e4SLinus Torvalds static long last_blink; 9281da177e4SLinus Torvalds static char led; 9291da177e4SLinus Torvalds 9301da177e4SLinus Torvalds /* 9311da177e4SLinus Torvalds * We expect frequency to be about 1/2s. KDB uses about 1s. 9321da177e4SLinus Torvalds * Make sure they are different. 9331da177e4SLinus Torvalds */ 9341da177e4SLinus Torvalds if (!i8042_blink_frequency) 9351da177e4SLinus Torvalds return 0; 9361da177e4SLinus Torvalds if (count - last_blink < i8042_blink_frequency) 9371da177e4SLinus Torvalds return 0; 9381da177e4SLinus Torvalds 9391da177e4SLinus Torvalds led ^= 0x01 | 0x04; 9401da177e4SLinus Torvalds while (i8042_read_status() & I8042_STR_IBF) 9411da177e4SLinus Torvalds DELAY; 94219f3c3e3SDmitry Torokhov dbg("%02x -> i8042 (panic blink)", 0xed); 94319f3c3e3SDmitry Torokhov i8042_suppress_kbd_ack = 2; 9441da177e4SLinus Torvalds i8042_write_data(0xed); /* set leds */ 9451da177e4SLinus Torvalds DELAY; 9461da177e4SLinus Torvalds while (i8042_read_status() & I8042_STR_IBF) 9471da177e4SLinus Torvalds DELAY; 9481da177e4SLinus Torvalds DELAY; 94919f3c3e3SDmitry Torokhov dbg("%02x -> i8042 (panic blink)", led); 9501da177e4SLinus Torvalds i8042_write_data(led); 9511da177e4SLinus Torvalds DELAY; 9521da177e4SLinus Torvalds last_blink = count; 9531da177e4SLinus Torvalds return delay; 9541da177e4SLinus Torvalds } 9551da177e4SLinus Torvalds 9561da177e4SLinus Torvalds #undef DELAY 9571da177e4SLinus Torvalds 958d35895dbSBruno Prémont #ifdef CONFIG_X86 959d35895dbSBruno Prémont static void i8042_dritek_enable(void) 960d35895dbSBruno Prémont { 961d35895dbSBruno Prémont char param = 0x90; 962d35895dbSBruno Prémont int error; 963d35895dbSBruno Prémont 964d35895dbSBruno Prémont error = i8042_command(¶m, 0x1059); 965d35895dbSBruno Prémont if (error) 966d35895dbSBruno Prémont printk(KERN_WARNING 967d35895dbSBruno Prémont "Failed to enable DRITEK extension: %d\n", 968d35895dbSBruno Prémont error); 969d35895dbSBruno Prémont } 970d35895dbSBruno Prémont #endif 971d35895dbSBruno Prémont 97282dd9effSDmitry Torokhov #ifdef CONFIG_PM 9737e044e05SDmitry Torokhov 9741da177e4SLinus Torvalds /* 975ebd7768dSDmitry Torokhov * Here we try to restore the original BIOS settings to avoid 976ebd7768dSDmitry Torokhov * upsetting it. 9771da177e4SLinus Torvalds */ 9781da177e4SLinus Torvalds 979ebd7768dSDmitry Torokhov static int i8042_pm_reset(struct device *dev) 9801da177e4SLinus Torvalds { 98182dd9effSDmitry Torokhov i8042_controller_reset(); 982ddaa4343SThadeu Lima de Souza Cascardo 9831da177e4SLinus Torvalds return 0; 9841da177e4SLinus Torvalds } 9851da177e4SLinus Torvalds 9861da177e4SLinus Torvalds /* 987ebd7768dSDmitry Torokhov * Here we try to reset everything back to a state we had 988ebd7768dSDmitry Torokhov * before suspending. 9891da177e4SLinus Torvalds */ 9901da177e4SLinus Torvalds 991ebd7768dSDmitry Torokhov static int i8042_pm_restore(struct device *dev) 9921da177e4SLinus Torvalds { 993de9ce703SDmitry Torokhov int error; 9941da177e4SLinus Torvalds 995de9ce703SDmitry Torokhov error = i8042_controller_check(); 996de9ce703SDmitry Torokhov if (error) 997de9ce703SDmitry Torokhov return error; 9982673c836SVojtech Pavlik 999de9ce703SDmitry Torokhov error = i8042_controller_selftest(); 1000de9ce703SDmitry Torokhov if (error) 1001de9ce703SDmitry Torokhov return error; 1002de9ce703SDmitry Torokhov 1003de9ce703SDmitry Torokhov /* 100482dd9effSDmitry Torokhov * Restore original CTR value and disable all ports 1005de9ce703SDmitry Torokhov */ 1006de9ce703SDmitry Torokhov 100782dd9effSDmitry Torokhov i8042_ctr = i8042_initial_ctr; 100882dd9effSDmitry Torokhov if (i8042_direct) 100982dd9effSDmitry Torokhov i8042_ctr &= ~I8042_CTR_XLATE; 1010de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS; 1011de9ce703SDmitry Torokhov i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT); 10122673c836SVojtech Pavlik if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 10132f6a77d5SJiri Kosina printk(KERN_WARNING "i8042: Can't write CTR to resume, retrying...\n"); 10142f6a77d5SJiri Kosina msleep(50); 10152f6a77d5SJiri Kosina if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 10162f6a77d5SJiri Kosina printk(KERN_ERR "i8042: CTR write retry failed\n"); 1017de9ce703SDmitry Torokhov return -EIO; 10181da177e4SLinus Torvalds } 10192f6a77d5SJiri Kosina } 10201da177e4SLinus Torvalds 1021d35895dbSBruno Prémont 1022d35895dbSBruno Prémont #ifdef CONFIG_X86 1023d35895dbSBruno Prémont if (i8042_dritek) 1024d35895dbSBruno Prémont i8042_dritek_enable(); 1025d35895dbSBruno Prémont #endif 1026d35895dbSBruno Prémont 1027de9ce703SDmitry Torokhov if (i8042_mux_present) { 10281da177e4SLinus Torvalds if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports()) 1029de9ce703SDmitry Torokhov printk(KERN_WARNING 1030de9ce703SDmitry Torokhov "i8042: failed to resume active multiplexor, " 1031de9ce703SDmitry Torokhov "mouse won't work.\n"); 1032de9ce703SDmitry Torokhov } else if (i8042_ports[I8042_AUX_PORT_NO].serio) 1033de9ce703SDmitry Torokhov i8042_enable_aux_port(); 10341da177e4SLinus Torvalds 1035de9ce703SDmitry Torokhov if (i8042_ports[I8042_KBD_PORT_NO].serio) 1036de9ce703SDmitry Torokhov i8042_enable_kbd_port(); 10371da177e4SLinus Torvalds 10387d12e780SDavid Howells i8042_interrupt(0, NULL); 10391da177e4SLinus Torvalds 10401da177e4SLinus Torvalds return 0; 10411da177e4SLinus Torvalds } 1042ebd7768dSDmitry Torokhov 1043ebd7768dSDmitry Torokhov static const struct dev_pm_ops i8042_pm_ops = { 1044ebd7768dSDmitry Torokhov .suspend = i8042_pm_reset, 1045ebd7768dSDmitry Torokhov .resume = i8042_pm_restore, 1046ebd7768dSDmitry Torokhov .poweroff = i8042_pm_reset, 1047ebd7768dSDmitry Torokhov .restore = i8042_pm_restore, 1048ebd7768dSDmitry Torokhov }; 1049ebd7768dSDmitry Torokhov 105082dd9effSDmitry Torokhov #endif /* CONFIG_PM */ 10511da177e4SLinus Torvalds 10521da177e4SLinus Torvalds /* 10531da177e4SLinus Torvalds * We need to reset the 8042 back to original mode on system shutdown, 10541da177e4SLinus Torvalds * because otherwise BIOSes will be confused. 10551da177e4SLinus Torvalds */ 10561da177e4SLinus Torvalds 10573ae5eaecSRussell King static void i8042_shutdown(struct platform_device *dev) 10581da177e4SLinus Torvalds { 105982dd9effSDmitry Torokhov i8042_controller_reset(); 10601da177e4SLinus Torvalds } 10611da177e4SLinus Torvalds 106287fd6318SDmitry Torokhov static int __devinit i8042_create_kbd_port(void) 10631da177e4SLinus Torvalds { 10641da177e4SLinus Torvalds struct serio *serio; 10651da177e4SLinus Torvalds struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; 10661da177e4SLinus Torvalds 1067d39969deSDmitry Torokhov serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 10680854e52dSDmitry Torokhov if (!serio) 10690854e52dSDmitry Torokhov return -ENOMEM; 10700854e52dSDmitry Torokhov 10711da177e4SLinus Torvalds serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; 10721da177e4SLinus Torvalds serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; 10731da177e4SLinus Torvalds serio->start = i8042_start; 10741da177e4SLinus Torvalds serio->stop = i8042_stop; 1075*5ddbc77cSDmitry Torokhov serio->close = i8042_port_close; 10761da177e4SLinus Torvalds serio->port_data = port; 10771da177e4SLinus Torvalds serio->dev.parent = &i8042_platform_device->dev; 1078de9ce703SDmitry Torokhov strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); 10791da177e4SLinus Torvalds strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); 10801da177e4SLinus Torvalds 10811da177e4SLinus Torvalds port->serio = serio; 1082de9ce703SDmitry Torokhov port->irq = I8042_KBD_IRQ; 10830854e52dSDmitry Torokhov 1084de9ce703SDmitry Torokhov return 0; 10851da177e4SLinus Torvalds } 10861da177e4SLinus Torvalds 1087de9ce703SDmitry Torokhov static int __devinit i8042_create_aux_port(int idx) 10881da177e4SLinus Torvalds { 10891da177e4SLinus Torvalds struct serio *serio; 1090de9ce703SDmitry Torokhov int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx; 1091de9ce703SDmitry Torokhov struct i8042_port *port = &i8042_ports[port_no]; 10921da177e4SLinus Torvalds 1093d39969deSDmitry Torokhov serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 10940854e52dSDmitry Torokhov if (!serio) 10950854e52dSDmitry Torokhov return -ENOMEM; 10960854e52dSDmitry Torokhov 10971da177e4SLinus Torvalds serio->id.type = SERIO_8042; 10981da177e4SLinus Torvalds serio->write = i8042_aux_write; 10991da177e4SLinus Torvalds serio->start = i8042_start; 11001da177e4SLinus Torvalds serio->stop = i8042_stop; 11011da177e4SLinus Torvalds serio->port_data = port; 11021da177e4SLinus Torvalds serio->dev.parent = &i8042_platform_device->dev; 1103de9ce703SDmitry Torokhov if (idx < 0) { 1104de9ce703SDmitry Torokhov strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name)); 11051da177e4SLinus Torvalds strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); 1106*5ddbc77cSDmitry Torokhov serio->close = i8042_port_close; 1107de9ce703SDmitry Torokhov } else { 1108de9ce703SDmitry Torokhov snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx); 1109de9ce703SDmitry Torokhov snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1); 11101da177e4SLinus Torvalds } 11111da177e4SLinus Torvalds 11121da177e4SLinus Torvalds port->serio = serio; 1113de9ce703SDmitry Torokhov port->mux = idx; 1114de9ce703SDmitry Torokhov port->irq = I8042_AUX_IRQ; 11150854e52dSDmitry Torokhov 1116de9ce703SDmitry Torokhov return 0; 1117de9ce703SDmitry Torokhov } 1118de9ce703SDmitry Torokhov 1119de9ce703SDmitry Torokhov static void __devinit i8042_free_kbd_port(void) 1120de9ce703SDmitry Torokhov { 1121de9ce703SDmitry Torokhov kfree(i8042_ports[I8042_KBD_PORT_NO].serio); 1122de9ce703SDmitry Torokhov i8042_ports[I8042_KBD_PORT_NO].serio = NULL; 1123de9ce703SDmitry Torokhov } 1124de9ce703SDmitry Torokhov 1125de9ce703SDmitry Torokhov static void __devinit i8042_free_aux_ports(void) 1126de9ce703SDmitry Torokhov { 1127de9ce703SDmitry Torokhov int i; 1128de9ce703SDmitry Torokhov 1129de9ce703SDmitry Torokhov for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) { 1130de9ce703SDmitry Torokhov kfree(i8042_ports[i].serio); 1131de9ce703SDmitry Torokhov i8042_ports[i].serio = NULL; 1132de9ce703SDmitry Torokhov } 1133de9ce703SDmitry Torokhov } 1134de9ce703SDmitry Torokhov 1135de9ce703SDmitry Torokhov static void __devinit i8042_register_ports(void) 1136de9ce703SDmitry Torokhov { 1137de9ce703SDmitry Torokhov int i; 1138de9ce703SDmitry Torokhov 1139de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) { 1140de9ce703SDmitry Torokhov if (i8042_ports[i].serio) { 1141de9ce703SDmitry Torokhov printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n", 1142de9ce703SDmitry Torokhov i8042_ports[i].serio->name, 1143de9ce703SDmitry Torokhov (unsigned long) I8042_DATA_REG, 1144de9ce703SDmitry Torokhov (unsigned long) I8042_COMMAND_REG, 1145de9ce703SDmitry Torokhov i8042_ports[i].irq); 1146de9ce703SDmitry Torokhov serio_register_port(i8042_ports[i].serio); 1147de9ce703SDmitry Torokhov } 1148de9ce703SDmitry Torokhov } 1149de9ce703SDmitry Torokhov } 1150de9ce703SDmitry Torokhov 11517a1904c3SRalf Baechle static void __devexit i8042_unregister_ports(void) 1152de9ce703SDmitry Torokhov { 1153de9ce703SDmitry Torokhov int i; 1154de9ce703SDmitry Torokhov 1155de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) { 1156de9ce703SDmitry Torokhov if (i8042_ports[i].serio) { 1157de9ce703SDmitry Torokhov serio_unregister_port(i8042_ports[i].serio); 1158de9ce703SDmitry Torokhov i8042_ports[i].serio = NULL; 1159de9ce703SDmitry Torokhov } 1160de9ce703SDmitry Torokhov } 1161de9ce703SDmitry Torokhov } 1162de9ce703SDmitry Torokhov 1163de9ce703SDmitry Torokhov static void i8042_free_irqs(void) 1164de9ce703SDmitry Torokhov { 1165de9ce703SDmitry Torokhov if (i8042_aux_irq_registered) 1166de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 1167de9ce703SDmitry Torokhov if (i8042_kbd_irq_registered) 1168de9ce703SDmitry Torokhov free_irq(I8042_KBD_IRQ, i8042_platform_device); 1169de9ce703SDmitry Torokhov 1170de9ce703SDmitry Torokhov i8042_aux_irq_registered = i8042_kbd_irq_registered = 0; 1171de9ce703SDmitry Torokhov } 1172de9ce703SDmitry Torokhov 1173de9ce703SDmitry Torokhov static int __devinit i8042_setup_aux(void) 1174de9ce703SDmitry Torokhov { 1175de9ce703SDmitry Torokhov int (*aux_enable)(void); 1176de9ce703SDmitry Torokhov int error; 1177de9ce703SDmitry Torokhov int i; 1178de9ce703SDmitry Torokhov 1179de9ce703SDmitry Torokhov if (i8042_check_aux()) 1180de9ce703SDmitry Torokhov return -ENODEV; 1181de9ce703SDmitry Torokhov 1182de9ce703SDmitry Torokhov if (i8042_nomux || i8042_check_mux()) { 1183de9ce703SDmitry Torokhov error = i8042_create_aux_port(-1); 1184de9ce703SDmitry Torokhov if (error) 1185de9ce703SDmitry Torokhov goto err_free_ports; 1186de9ce703SDmitry Torokhov aux_enable = i8042_enable_aux_port; 1187de9ce703SDmitry Torokhov } else { 1188de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { 1189de9ce703SDmitry Torokhov error = i8042_create_aux_port(i); 1190de9ce703SDmitry Torokhov if (error) 1191de9ce703SDmitry Torokhov goto err_free_ports; 1192de9ce703SDmitry Torokhov } 1193de9ce703SDmitry Torokhov aux_enable = i8042_enable_mux_ports; 1194de9ce703SDmitry Torokhov } 1195de9ce703SDmitry Torokhov 1196de9ce703SDmitry Torokhov error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED, 1197de9ce703SDmitry Torokhov "i8042", i8042_platform_device); 1198de9ce703SDmitry Torokhov if (error) 1199de9ce703SDmitry Torokhov goto err_free_ports; 1200de9ce703SDmitry Torokhov 1201de9ce703SDmitry Torokhov if (aux_enable()) 1202de9ce703SDmitry Torokhov goto err_free_irq; 1203de9ce703SDmitry Torokhov 1204de9ce703SDmitry Torokhov i8042_aux_irq_registered = 1; 1205de9ce703SDmitry Torokhov return 0; 1206de9ce703SDmitry Torokhov 1207de9ce703SDmitry Torokhov err_free_irq: 1208de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 1209de9ce703SDmitry Torokhov err_free_ports: 1210de9ce703SDmitry Torokhov i8042_free_aux_ports(); 1211de9ce703SDmitry Torokhov return error; 1212de9ce703SDmitry Torokhov } 1213de9ce703SDmitry Torokhov 1214de9ce703SDmitry Torokhov static int __devinit i8042_setup_kbd(void) 1215de9ce703SDmitry Torokhov { 1216de9ce703SDmitry Torokhov int error; 1217de9ce703SDmitry Torokhov 1218de9ce703SDmitry Torokhov error = i8042_create_kbd_port(); 1219de9ce703SDmitry Torokhov if (error) 1220de9ce703SDmitry Torokhov return error; 1221de9ce703SDmitry Torokhov 1222de9ce703SDmitry Torokhov error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED, 1223de9ce703SDmitry Torokhov "i8042", i8042_platform_device); 1224de9ce703SDmitry Torokhov if (error) 1225de9ce703SDmitry Torokhov goto err_free_port; 1226de9ce703SDmitry Torokhov 1227de9ce703SDmitry Torokhov error = i8042_enable_kbd_port(); 1228de9ce703SDmitry Torokhov if (error) 1229de9ce703SDmitry Torokhov goto err_free_irq; 1230de9ce703SDmitry Torokhov 1231de9ce703SDmitry Torokhov i8042_kbd_irq_registered = 1; 1232de9ce703SDmitry Torokhov return 0; 1233de9ce703SDmitry Torokhov 1234de9ce703SDmitry Torokhov err_free_irq: 1235de9ce703SDmitry Torokhov free_irq(I8042_KBD_IRQ, i8042_platform_device); 1236de9ce703SDmitry Torokhov err_free_port: 1237de9ce703SDmitry Torokhov i8042_free_kbd_port(); 1238de9ce703SDmitry Torokhov return error; 12391da177e4SLinus Torvalds } 12401da177e4SLinus Torvalds 124187fd6318SDmitry Torokhov static int __devinit i8042_probe(struct platform_device *dev) 12421da177e4SLinus Torvalds { 1243de9ce703SDmitry Torokhov int error; 12441da177e4SLinus Torvalds 1245de9ce703SDmitry Torokhov error = i8042_controller_selftest(); 1246de9ce703SDmitry Torokhov if (error) 1247de9ce703SDmitry Torokhov return error; 12481da177e4SLinus Torvalds 1249de9ce703SDmitry Torokhov error = i8042_controller_init(); 1250de9ce703SDmitry Torokhov if (error) 1251de9ce703SDmitry Torokhov return error; 12521da177e4SLinus Torvalds 1253d35895dbSBruno Prémont #ifdef CONFIG_X86 1254d35895dbSBruno Prémont if (i8042_dritek) 1255d35895dbSBruno Prémont i8042_dritek_enable(); 1256d35895dbSBruno Prémont #endif 1257d35895dbSBruno Prémont 1258de9ce703SDmitry Torokhov if (!i8042_noaux) { 1259de9ce703SDmitry Torokhov error = i8042_setup_aux(); 1260de9ce703SDmitry Torokhov if (error && error != -ENODEV && error != -EBUSY) 1261de9ce703SDmitry Torokhov goto out_fail; 12621da177e4SLinus Torvalds } 12631da177e4SLinus Torvalds 1264945ef0d4SDmitry Torokhov if (!i8042_nokbd) { 1265de9ce703SDmitry Torokhov error = i8042_setup_kbd(); 1266de9ce703SDmitry Torokhov if (error) 1267de9ce703SDmitry Torokhov goto out_fail; 1268945ef0d4SDmitry Torokhov } 1269de9ce703SDmitry Torokhov /* 1270de9ce703SDmitry Torokhov * Ok, everything is ready, let's register all serio ports 1271de9ce703SDmitry Torokhov */ 1272de9ce703SDmitry Torokhov i8042_register_ports(); 12731da177e4SLinus Torvalds 12741da177e4SLinus Torvalds return 0; 12750854e52dSDmitry Torokhov 1276de9ce703SDmitry Torokhov out_fail: 1277de9ce703SDmitry Torokhov i8042_free_aux_ports(); /* in case KBD failed but AUX not */ 1278de9ce703SDmitry Torokhov i8042_free_irqs(); 1279de9ce703SDmitry Torokhov i8042_controller_reset(); 12800854e52dSDmitry Torokhov 1281de9ce703SDmitry Torokhov return error; 12821da177e4SLinus Torvalds } 12831da177e4SLinus Torvalds 128487fd6318SDmitry Torokhov static int __devexit i8042_remove(struct platform_device *dev) 12851da177e4SLinus Torvalds { 1286de9ce703SDmitry Torokhov i8042_unregister_ports(); 1287de9ce703SDmitry Torokhov i8042_free_irqs(); 1288de9ce703SDmitry Torokhov i8042_controller_reset(); 12891da177e4SLinus Torvalds 129087fd6318SDmitry Torokhov return 0; 129187fd6318SDmitry Torokhov } 129287fd6318SDmitry Torokhov 129387fd6318SDmitry Torokhov static struct platform_driver i8042_driver = { 129487fd6318SDmitry Torokhov .driver = { 129587fd6318SDmitry Torokhov .name = "i8042", 129687fd6318SDmitry Torokhov .owner = THIS_MODULE, 1297ebd7768dSDmitry Torokhov #ifdef CONFIG_PM 1298ebd7768dSDmitry Torokhov .pm = &i8042_pm_ops, 1299ebd7768dSDmitry Torokhov #endif 130087fd6318SDmitry Torokhov }, 130187fd6318SDmitry Torokhov .probe = i8042_probe, 130287fd6318SDmitry Torokhov .remove = __devexit_p(i8042_remove), 130382dd9effSDmitry Torokhov .shutdown = i8042_shutdown, 130487fd6318SDmitry Torokhov }; 130587fd6318SDmitry Torokhov 130687fd6318SDmitry Torokhov static int __init i8042_init(void) 130787fd6318SDmitry Torokhov { 130887fd6318SDmitry Torokhov int err; 130987fd6318SDmitry Torokhov 131087fd6318SDmitry Torokhov dbg_init(); 131187fd6318SDmitry Torokhov 131287fd6318SDmitry Torokhov err = i8042_platform_init(); 131387fd6318SDmitry Torokhov if (err) 131487fd6318SDmitry Torokhov return err; 131587fd6318SDmitry Torokhov 1316de9ce703SDmitry Torokhov err = i8042_controller_check(); 1317de9ce703SDmitry Torokhov if (err) 1318de9ce703SDmitry Torokhov goto err_platform_exit; 131987fd6318SDmitry Torokhov 132087fd6318SDmitry Torokhov err = platform_driver_register(&i8042_driver); 132187fd6318SDmitry Torokhov if (err) 132287fd6318SDmitry Torokhov goto err_platform_exit; 132387fd6318SDmitry Torokhov 132487fd6318SDmitry Torokhov i8042_platform_device = platform_device_alloc("i8042", -1); 132587fd6318SDmitry Torokhov if (!i8042_platform_device) { 132687fd6318SDmitry Torokhov err = -ENOMEM; 132787fd6318SDmitry Torokhov goto err_unregister_driver; 132887fd6318SDmitry Torokhov } 132987fd6318SDmitry Torokhov 133087fd6318SDmitry Torokhov err = platform_device_add(i8042_platform_device); 133187fd6318SDmitry Torokhov if (err) 133287fd6318SDmitry Torokhov goto err_free_device; 133387fd6318SDmitry Torokhov 1334de9ce703SDmitry Torokhov panic_blink = i8042_panic_blink; 1335de9ce703SDmitry Torokhov 133687fd6318SDmitry Torokhov return 0; 133787fd6318SDmitry Torokhov 133887fd6318SDmitry Torokhov err_free_device: 133987fd6318SDmitry Torokhov platform_device_put(i8042_platform_device); 134087fd6318SDmitry Torokhov err_unregister_driver: 134187fd6318SDmitry Torokhov platform_driver_unregister(&i8042_driver); 134287fd6318SDmitry Torokhov err_platform_exit: 134387fd6318SDmitry Torokhov i8042_platform_exit(); 134487fd6318SDmitry Torokhov 134587fd6318SDmitry Torokhov return err; 134687fd6318SDmitry Torokhov } 134787fd6318SDmitry Torokhov 134887fd6318SDmitry Torokhov static void __exit i8042_exit(void) 134987fd6318SDmitry Torokhov { 13501da177e4SLinus Torvalds platform_device_unregister(i8042_platform_device); 13513ae5eaecSRussell King platform_driver_unregister(&i8042_driver); 13521da177e4SLinus Torvalds i8042_platform_exit(); 13531da177e4SLinus Torvalds 13541da177e4SLinus Torvalds panic_blink = NULL; 13551da177e4SLinus Torvalds } 13561da177e4SLinus Torvalds 13571da177e4SLinus Torvalds module_init(i8042_init); 13581da177e4SLinus Torvalds module_exit(i8042_exit); 1359