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 131da177e4SLinus Torvalds #include <linux/delay.h> 141da177e4SLinus Torvalds #include <linux/module.h> 151da177e4SLinus Torvalds #include <linux/moduleparam.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> 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds #include <asm/io.h> 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); 271da177e4SLinus Torvalds MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); 281da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 291da177e4SLinus Torvalds 30945ef0d4SDmitry Torokhov static unsigned int i8042_nokbd; 31945ef0d4SDmitry Torokhov module_param_named(nokbd, i8042_nokbd, bool, 0); 32945ef0d4SDmitry Torokhov MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port."); 33945ef0d4SDmitry Torokhov 341da177e4SLinus Torvalds static unsigned int i8042_noaux; 351da177e4SLinus Torvalds module_param_named(noaux, i8042_noaux, bool, 0); 361da177e4SLinus Torvalds MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port."); 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds static unsigned int i8042_nomux; 391da177e4SLinus Torvalds module_param_named(nomux, i8042_nomux, bool, 0); 401da177e4SLinus Torvalds MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing conrtoller is present."); 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds static unsigned int i8042_unlock; 431da177e4SLinus Torvalds module_param_named(unlock, i8042_unlock, bool, 0); 441da177e4SLinus Torvalds MODULE_PARM_DESC(unlock, "Ignore keyboard lock."); 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds static unsigned int i8042_reset; 471da177e4SLinus Torvalds module_param_named(reset, i8042_reset, bool, 0); 481da177e4SLinus Torvalds MODULE_PARM_DESC(reset, "Reset controller during init and cleanup."); 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds static unsigned int i8042_direct; 511da177e4SLinus Torvalds module_param_named(direct, i8042_direct, bool, 0); 521da177e4SLinus Torvalds MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode."); 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds static unsigned int i8042_dumbkbd; 551da177e4SLinus Torvalds module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); 561da177e4SLinus Torvalds MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds static unsigned int i8042_noloop; 591da177e4SLinus Torvalds module_param_named(noloop, i8042_noloop, bool, 0); 601da177e4SLinus Torvalds MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port"); 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds static unsigned int i8042_blink_frequency = 500; 631da177e4SLinus Torvalds module_param_named(panicblink, i8042_blink_frequency, uint, 0600); 641da177e4SLinus Torvalds MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics"); 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds #ifdef CONFIG_PNP 671da177e4SLinus Torvalds static int i8042_nopnp; 681da177e4SLinus Torvalds module_param_named(nopnp, i8042_nopnp, bool, 0); 691da177e4SLinus Torvalds MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings"); 701da177e4SLinus Torvalds #endif 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds #define DEBUG 731da177e4SLinus Torvalds #ifdef DEBUG 741da177e4SLinus Torvalds static int i8042_debug; 751da177e4SLinus Torvalds module_param_named(debug, i8042_debug, bool, 0600); 761da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off"); 771da177e4SLinus Torvalds #endif 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds #include "i8042.h" 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds static DEFINE_SPINLOCK(i8042_lock); 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds struct i8042_port { 841da177e4SLinus Torvalds struct serio *serio; 851da177e4SLinus Torvalds int irq; 861da177e4SLinus Torvalds unsigned char exists; 871da177e4SLinus Torvalds signed char mux; 881da177e4SLinus Torvalds }; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds #define I8042_KBD_PORT_NO 0 911da177e4SLinus Torvalds #define I8042_AUX_PORT_NO 1 921da177e4SLinus Torvalds #define I8042_MUX_PORT_NO 2 931da177e4SLinus Torvalds #define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2) 94de9ce703SDmitry Torokhov 95de9ce703SDmitry Torokhov static struct i8042_port i8042_ports[I8042_NUM_PORTS]; 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds static unsigned char i8042_initial_ctr; 981da177e4SLinus Torvalds static unsigned char i8042_ctr; 991da177e4SLinus Torvalds static unsigned char i8042_mux_present; 100de9ce703SDmitry Torokhov static unsigned char i8042_kbd_irq_registered; 101de9ce703SDmitry Torokhov static unsigned char i8042_aux_irq_registered; 102817e6ba3SDmitry Torokhov static unsigned char i8042_suppress_kbd_ack; 1031da177e4SLinus Torvalds static struct platform_device *i8042_platform_device; 1041da177e4SLinus Torvalds 1057d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id); 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds /* 1081da177e4SLinus Torvalds * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to 1091da177e4SLinus Torvalds * be ready for reading values from it / writing values to it. 1101da177e4SLinus Torvalds * Called always with i8042_lock held. 1111da177e4SLinus Torvalds */ 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds static int i8042_wait_read(void) 1141da177e4SLinus Torvalds { 1151da177e4SLinus Torvalds int i = 0; 116de9ce703SDmitry Torokhov 1171da177e4SLinus Torvalds while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { 1181da177e4SLinus Torvalds udelay(50); 1191da177e4SLinus Torvalds i++; 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds return -(i == I8042_CTL_TIMEOUT); 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds static int i8042_wait_write(void) 1251da177e4SLinus Torvalds { 1261da177e4SLinus Torvalds int i = 0; 127de9ce703SDmitry Torokhov 1281da177e4SLinus Torvalds while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { 1291da177e4SLinus Torvalds udelay(50); 1301da177e4SLinus Torvalds i++; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds return -(i == I8042_CTL_TIMEOUT); 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds /* 1361da177e4SLinus Torvalds * i8042_flush() flushes all data that may be in the keyboard and mouse buffers 1371da177e4SLinus Torvalds * of the i8042 down the toilet. 1381da177e4SLinus Torvalds */ 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds static int i8042_flush(void) 1411da177e4SLinus Torvalds { 1421da177e4SLinus Torvalds unsigned long flags; 1431da177e4SLinus Torvalds unsigned char data, str; 1441da177e4SLinus Torvalds int i = 0; 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) { 1491da177e4SLinus Torvalds udelay(50); 1501da177e4SLinus Torvalds data = i8042_read_data(); 1511da177e4SLinus Torvalds i++; 1521da177e4SLinus Torvalds dbg("%02x <- i8042 (flush, %s)", data, 1531da177e4SLinus Torvalds str & I8042_STR_AUXDATA ? "aux" : "kbd"); 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds return i; 1591da177e4SLinus Torvalds } 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds /* 1621da177e4SLinus Torvalds * i8042_command() executes a command on the i8042. It also sends the input 1631da177e4SLinus Torvalds * parameter(s) of the commands to it, and receives the output value(s). The 1641da177e4SLinus Torvalds * parameters are to be stored in the param array, and the output is placed 1651da177e4SLinus Torvalds * into the same array. The number of the parameters and output values is 1661da177e4SLinus Torvalds * encoded in bits 8-11 of the command number. 1671da177e4SLinus Torvalds */ 1681da177e4SLinus Torvalds 169de9ce703SDmitry Torokhov static int __i8042_command(unsigned char *param, int command) 1701da177e4SLinus Torvalds { 171de9ce703SDmitry Torokhov int i, error; 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds if (i8042_noloop && command == I8042_CMD_AUX_LOOP) 1741da177e4SLinus Torvalds return -1; 1751da177e4SLinus Torvalds 176de9ce703SDmitry Torokhov error = i8042_wait_write(); 177de9ce703SDmitry Torokhov if (error) 178de9ce703SDmitry Torokhov return error; 179463a4f76SDmitry Torokhov 1801da177e4SLinus Torvalds dbg("%02x -> i8042 (command)", command & 0xff); 1811da177e4SLinus Torvalds i8042_write_command(command & 0xff); 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds for (i = 0; i < ((command >> 12) & 0xf); i++) { 184de9ce703SDmitry Torokhov error = i8042_wait_write(); 185de9ce703SDmitry Torokhov if (error) 186de9ce703SDmitry Torokhov return error; 1871da177e4SLinus Torvalds dbg("%02x -> i8042 (parameter)", param[i]); 1881da177e4SLinus Torvalds i8042_write_data(param[i]); 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds for (i = 0; i < ((command >> 8) & 0xf); i++) { 192de9ce703SDmitry Torokhov error = i8042_wait_read(); 193de9ce703SDmitry Torokhov if (error) { 194de9ce703SDmitry Torokhov dbg(" -- i8042 (timeout)"); 195de9ce703SDmitry Torokhov return error; 196de9ce703SDmitry Torokhov } 197463a4f76SDmitry Torokhov 198463a4f76SDmitry Torokhov if (command == I8042_CMD_AUX_LOOP && 199463a4f76SDmitry Torokhov !(i8042_read_status() & I8042_STR_AUXDATA)) { 200de9ce703SDmitry Torokhov dbg(" -- i8042 (auxerr)"); 201de9ce703SDmitry Torokhov return -1; 202463a4f76SDmitry Torokhov } 203463a4f76SDmitry Torokhov 2041da177e4SLinus Torvalds param[i] = i8042_read_data(); 2051da177e4SLinus Torvalds dbg("%02x <- i8042 (return)", param[i]); 2061da177e4SLinus Torvalds } 2071da177e4SLinus Torvalds 208de9ce703SDmitry Torokhov return 0; 209de9ce703SDmitry Torokhov } 2101da177e4SLinus Torvalds 211de9ce703SDmitry Torokhov static int i8042_command(unsigned char *param, int command) 212de9ce703SDmitry Torokhov { 213de9ce703SDmitry Torokhov unsigned long flags; 214de9ce703SDmitry Torokhov int retval; 215de9ce703SDmitry Torokhov 216de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 217de9ce703SDmitry Torokhov retval = __i8042_command(param, command); 218463a4f76SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 219de9ce703SDmitry Torokhov 2201da177e4SLinus Torvalds return retval; 2211da177e4SLinus Torvalds } 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds /* 2241da177e4SLinus Torvalds * i8042_kbd_write() sends a byte out through the keyboard interface. 2251da177e4SLinus Torvalds */ 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds static int i8042_kbd_write(struct serio *port, unsigned char c) 2281da177e4SLinus Torvalds { 2291da177e4SLinus Torvalds unsigned long flags; 2301da177e4SLinus Torvalds int retval = 0; 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds if (!(retval = i8042_wait_write())) { 2351da177e4SLinus Torvalds dbg("%02x -> i8042 (kbd-data)", c); 2361da177e4SLinus Torvalds i8042_write_data(c); 2371da177e4SLinus Torvalds } 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds return retval; 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds /* 2451da177e4SLinus Torvalds * i8042_aux_write() sends a byte out through the aux interface. 2461da177e4SLinus Torvalds */ 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds static int i8042_aux_write(struct serio *serio, unsigned char c) 2491da177e4SLinus Torvalds { 2501da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 2511da177e4SLinus Torvalds 252f4e3c711SDmitry Torokhov return i8042_command(&c, port->mux == -1 ? 253f4e3c711SDmitry Torokhov I8042_CMD_AUX_SEND : 254f4e3c711SDmitry Torokhov I8042_CMD_MUX_SEND + port->mux); 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds /* 2581da177e4SLinus Torvalds * i8042_start() is called by serio core when port is about to finish 2591da177e4SLinus Torvalds * registering. It will mark port as existing so i8042_interrupt can 2601da177e4SLinus Torvalds * start sending data through it. 2611da177e4SLinus Torvalds */ 2621da177e4SLinus Torvalds static int i8042_start(struct serio *serio) 2631da177e4SLinus Torvalds { 2641da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds port->exists = 1; 2671da177e4SLinus Torvalds mb(); 2681da177e4SLinus Torvalds return 0; 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds /* 2721da177e4SLinus Torvalds * i8042_stop() marks serio port as non-existing so i8042_interrupt 2731da177e4SLinus Torvalds * will not try to send data to the port that is about to go away. 2741da177e4SLinus Torvalds * The function is called by serio core as part of unregister procedure. 2751da177e4SLinus Torvalds */ 2761da177e4SLinus Torvalds static void i8042_stop(struct serio *serio) 2771da177e4SLinus Torvalds { 2781da177e4SLinus Torvalds struct i8042_port *port = serio->port_data; 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds port->exists = 0; 281b2b18660SPaul E. McKenney synchronize_sched(); 2821da177e4SLinus Torvalds port->serio = NULL; 2831da177e4SLinus Torvalds } 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds /* 2861da177e4SLinus Torvalds * i8042_interrupt() is the most important function in this driver - 2871da177e4SLinus Torvalds * it handles the interrupts from the i8042, and sends incoming bytes 2881da177e4SLinus Torvalds * to the upper layers. 2891da177e4SLinus Torvalds */ 2901da177e4SLinus Torvalds 2917d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id) 2921da177e4SLinus Torvalds { 2931da177e4SLinus Torvalds struct i8042_port *port; 2941da177e4SLinus Torvalds unsigned long flags; 2951da177e4SLinus Torvalds unsigned char str, data; 2961da177e4SLinus Torvalds unsigned int dfl; 2971da177e4SLinus Torvalds unsigned int port_no; 298817e6ba3SDmitry Torokhov int ret = 1; 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 3011da177e4SLinus Torvalds str = i8042_read_status(); 3021da177e4SLinus Torvalds if (unlikely(~str & I8042_STR_OBF)) { 3031da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 3041da177e4SLinus Torvalds if (irq) dbg("Interrupt %d, without any data", irq); 3051da177e4SLinus Torvalds ret = 0; 3061da177e4SLinus Torvalds goto out; 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds data = i8042_read_data(); 3091da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { 3121da177e4SLinus Torvalds static unsigned long last_transmit; 3131da177e4SLinus Torvalds static unsigned char last_str; 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds dfl = 0; 3161da177e4SLinus Torvalds if (str & I8042_STR_MUXERR) { 3171da177e4SLinus Torvalds dbg("MUX error, status is %02x, data is %02x", str, data); 3181da177e4SLinus Torvalds /* 3191da177e4SLinus Torvalds * When MUXERR condition is signalled the data register can only contain 3201da177e4SLinus Torvalds * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately 321a216a4b6SDmitry Torokhov * it is not always the case. Some KBCs also report 0xfc when there is 322a216a4b6SDmitry Torokhov * nothing connected to the port while others sometimes get confused which 323a216a4b6SDmitry Torokhov * port the data came from and signal error leaving the data intact. They 324a216a4b6SDmitry Torokhov * _do not_ revert to legacy mode (actually I've never seen KBC reverting 325a216a4b6SDmitry Torokhov * to legacy mode yet, when we see one we'll add proper handling). 326a216a4b6SDmitry Torokhov * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the 327a216a4b6SDmitry Torokhov * rest assume that the data came from the same serio last byte 3281da177e4SLinus Torvalds * was transmitted (if transmission happened not too long ago). 3291da177e4SLinus Torvalds */ 330a216a4b6SDmitry Torokhov 331a216a4b6SDmitry Torokhov switch (data) { 332a216a4b6SDmitry Torokhov default: 3331da177e4SLinus Torvalds if (time_before(jiffies, last_transmit + HZ/10)) { 3341da177e4SLinus Torvalds str = last_str; 3351da177e4SLinus Torvalds break; 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds /* fall through - report timeout */ 338a216a4b6SDmitry Torokhov case 0xfc: 3391da177e4SLinus Torvalds case 0xfd: 3401da177e4SLinus Torvalds case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break; 3411da177e4SLinus Torvalds case 0xff: dfl = SERIO_PARITY; data = 0xfe; break; 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3); 3461da177e4SLinus Torvalds last_str = str; 3471da177e4SLinus Torvalds last_transmit = jiffies; 3481da177e4SLinus Torvalds } else { 3491da177e4SLinus Torvalds 3501da177e4SLinus Torvalds dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | 3511da177e4SLinus Torvalds ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds port_no = (str & I8042_STR_AUXDATA) ? 3541da177e4SLinus Torvalds I8042_AUX_PORT_NO : I8042_KBD_PORT_NO; 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds port = &i8042_ports[port_no]; 3581da177e4SLinus Torvalds 359de9ce703SDmitry Torokhov dbg("%02x <- i8042 (interrupt, %d, %d%s%s)", 360de9ce703SDmitry Torokhov data, port_no, irq, 3611da177e4SLinus Torvalds dfl & SERIO_PARITY ? ", bad parity" : "", 3621da177e4SLinus Torvalds dfl & SERIO_TIMEOUT ? ", timeout" : ""); 3631da177e4SLinus Torvalds 364817e6ba3SDmitry Torokhov if (unlikely(i8042_suppress_kbd_ack)) 365817e6ba3SDmitry Torokhov if (port_no == I8042_KBD_PORT_NO && 366817e6ba3SDmitry Torokhov (data == 0xfa || data == 0xfe)) { 36719f3c3e3SDmitry Torokhov i8042_suppress_kbd_ack--; 368817e6ba3SDmitry Torokhov goto out; 369817e6ba3SDmitry Torokhov } 370817e6ba3SDmitry Torokhov 3711da177e4SLinus Torvalds if (likely(port->exists)) 3727d12e780SDavid Howells serio_interrupt(port->serio, data, dfl); 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds out: 3751da177e4SLinus Torvalds return IRQ_RETVAL(ret); 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds /* 379de9ce703SDmitry Torokhov * i8042_enable_kbd_port enables keybaord port on chip 380de9ce703SDmitry Torokhov */ 381de9ce703SDmitry Torokhov 382de9ce703SDmitry Torokhov static int i8042_enable_kbd_port(void) 383de9ce703SDmitry Torokhov { 384de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_KBDDIS; 385de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_KBDINT; 386de9ce703SDmitry Torokhov 387de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 388*018db6bbSMarkus Armbruster i8042_ctr &= ~I8042_CTR_KBDINT; 389*018db6bbSMarkus Armbruster i8042_ctr |= I8042_CTR_KBDDIS; 390de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n"); 391de9ce703SDmitry Torokhov return -EIO; 392de9ce703SDmitry Torokhov } 393de9ce703SDmitry Torokhov 394de9ce703SDmitry Torokhov return 0; 395de9ce703SDmitry Torokhov } 396de9ce703SDmitry Torokhov 397de9ce703SDmitry Torokhov /* 398de9ce703SDmitry Torokhov * i8042_enable_aux_port enables AUX (mouse) port on chip 399de9ce703SDmitry Torokhov */ 400de9ce703SDmitry Torokhov 401de9ce703SDmitry Torokhov static int i8042_enable_aux_port(void) 402de9ce703SDmitry Torokhov { 403de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_AUXDIS; 404de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXINT; 405de9ce703SDmitry Torokhov 406de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 407*018db6bbSMarkus Armbruster i8042_ctr &= ~I8042_CTR_AUXINT; 408*018db6bbSMarkus Armbruster i8042_ctr |= I8042_CTR_AUXDIS; 409de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n"); 410de9ce703SDmitry Torokhov return -EIO; 411de9ce703SDmitry Torokhov } 412de9ce703SDmitry Torokhov 413de9ce703SDmitry Torokhov return 0; 414de9ce703SDmitry Torokhov } 415de9ce703SDmitry Torokhov 416de9ce703SDmitry Torokhov /* 417de9ce703SDmitry Torokhov * i8042_enable_mux_ports enables 4 individual AUX ports after 418de9ce703SDmitry Torokhov * the controller has been switched into Multiplexed mode 419de9ce703SDmitry Torokhov */ 420de9ce703SDmitry Torokhov 421de9ce703SDmitry Torokhov static int i8042_enable_mux_ports(void) 422de9ce703SDmitry Torokhov { 423de9ce703SDmitry Torokhov unsigned char param; 424de9ce703SDmitry Torokhov int i; 425de9ce703SDmitry Torokhov 426de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { 427de9ce703SDmitry Torokhov i8042_command(¶m, I8042_CMD_MUX_PFX + i); 428de9ce703SDmitry Torokhov i8042_command(¶m, I8042_CMD_AUX_ENABLE); 429de9ce703SDmitry Torokhov } 430de9ce703SDmitry Torokhov 431de9ce703SDmitry Torokhov return i8042_enable_aux_port(); 432de9ce703SDmitry Torokhov } 433de9ce703SDmitry Torokhov 434de9ce703SDmitry Torokhov /* 4351da177e4SLinus Torvalds * i8042_set_mux_mode checks whether the controller has an active 4361da177e4SLinus Torvalds * multiplexor and puts the chip into Multiplexed (1) or Legacy (0) mode. 4371da177e4SLinus Torvalds */ 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version) 4401da177e4SLinus Torvalds { 4411da177e4SLinus Torvalds 4421da177e4SLinus Torvalds unsigned char param; 4431da177e4SLinus Torvalds /* 4441da177e4SLinus Torvalds * Get rid of bytes in the queue. 4451da177e4SLinus Torvalds */ 4461da177e4SLinus Torvalds 4471da177e4SLinus Torvalds i8042_flush(); 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds /* 4501da177e4SLinus Torvalds * Internal loopback test - send three bytes, they should come back from the 451de9ce703SDmitry Torokhov * mouse interface, the last should be version. 4521da177e4SLinus Torvalds */ 4531da177e4SLinus Torvalds 4541da177e4SLinus Torvalds param = 0xf0; 455463a4f76SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xf0) 4561da177e4SLinus Torvalds return -1; 4571da177e4SLinus Torvalds param = mode ? 0x56 : 0xf6; 458463a4f76SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != (mode ? 0x56 : 0xf6)) 4591da177e4SLinus Torvalds return -1; 4601da177e4SLinus Torvalds param = mode ? 0xa4 : 0xa5; 461463a4f76SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == (mode ? 0xa4 : 0xa5)) 4621da177e4SLinus Torvalds return -1; 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds if (mux_version) 465463a4f76SDmitry Torokhov *mux_version = param; 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds return 0; 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds /* 4711da177e4SLinus Torvalds * i8042_check_mux() checks whether the controller supports the PS/2 Active 4721da177e4SLinus Torvalds * Multiplexing specification by Synaptics, Phoenix, Insyde and 4731da177e4SLinus Torvalds * LCS/Telegraphics. 4741da177e4SLinus Torvalds */ 4751da177e4SLinus Torvalds 47687fd6318SDmitry Torokhov static int __devinit i8042_check_mux(void) 4771da177e4SLinus Torvalds { 4781da177e4SLinus Torvalds unsigned char mux_version; 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds if (i8042_set_mux_mode(1, &mux_version)) 4811da177e4SLinus Torvalds return -1; 4821da177e4SLinus Torvalds 483de9ce703SDmitry Torokhov /* 484de9ce703SDmitry Torokhov * Workaround for interference with USB Legacy emulation 485de9ce703SDmitry Torokhov * that causes a v10.12 MUX to be found. 486de9ce703SDmitry Torokhov */ 4871da177e4SLinus Torvalds if (mux_version == 0xAC) 4881da177e4SLinus Torvalds return -1; 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", 4911da177e4SLinus Torvalds (mux_version >> 4) & 0xf, mux_version & 0xf); 4921da177e4SLinus Torvalds 493de9ce703SDmitry Torokhov /* 494de9ce703SDmitry Torokhov * Disable all muxed ports by disabling AUX. 495de9ce703SDmitry Torokhov */ 496de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXDIS; 497de9ce703SDmitry Torokhov i8042_ctr &= ~I8042_CTR_AUXINT; 498de9ce703SDmitry Torokhov 499de9ce703SDmitry Torokhov if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 500de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n"); 501de9ce703SDmitry Torokhov return -EIO; 502de9ce703SDmitry Torokhov } 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds i8042_mux_present = 1; 505de9ce703SDmitry Torokhov 5061da177e4SLinus Torvalds return 0; 5071da177e4SLinus Torvalds } 5081da177e4SLinus Torvalds 509de9ce703SDmitry Torokhov /* 510de9ce703SDmitry Torokhov * The following is used to test AUX IRQ delivery. 511de9ce703SDmitry Torokhov */ 512de9ce703SDmitry Torokhov static struct completion i8042_aux_irq_delivered __devinitdata; 513de9ce703SDmitry Torokhov static int i8042_irq_being_tested __devinitdata; 514de9ce703SDmitry Torokhov 5157d12e780SDavid Howells static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id) 516de9ce703SDmitry Torokhov { 517de9ce703SDmitry Torokhov unsigned long flags; 518de9ce703SDmitry Torokhov unsigned char str, data; 519de9ce703SDmitry Torokhov 520de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 521de9ce703SDmitry Torokhov str = i8042_read_status(); 522de9ce703SDmitry Torokhov if (str & I8042_STR_OBF) { 523de9ce703SDmitry Torokhov data = i8042_read_data(); 524de9ce703SDmitry Torokhov if (i8042_irq_being_tested && 525de9ce703SDmitry Torokhov data == 0xa5 && (str & I8042_STR_AUXDATA)) 526de9ce703SDmitry Torokhov complete(&i8042_aux_irq_delivered); 527de9ce703SDmitry Torokhov } 528de9ce703SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 529de9ce703SDmitry Torokhov 530de9ce703SDmitry Torokhov return IRQ_HANDLED; 531de9ce703SDmitry Torokhov } 532de9ce703SDmitry Torokhov 533d2ada559SRoland Scheidegger /* 534d2ada559SRoland Scheidegger * i8042_toggle_aux - enables or disables AUX port on i8042 via command and 535d2ada559SRoland Scheidegger * verifies success by readinng CTR. Used when testing for presence of AUX 536d2ada559SRoland Scheidegger * port. 537d2ada559SRoland Scheidegger */ 538d2ada559SRoland Scheidegger static int __devinit i8042_toggle_aux(int on) 539d2ada559SRoland Scheidegger { 540d2ada559SRoland Scheidegger unsigned char param; 541d2ada559SRoland Scheidegger int i; 542d2ada559SRoland Scheidegger 543d2ada559SRoland Scheidegger if (i8042_command(¶m, 544d2ada559SRoland Scheidegger on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE)) 545d2ada559SRoland Scheidegger return -1; 546d2ada559SRoland Scheidegger 547d2ada559SRoland Scheidegger /* some chips need some time to set the I8042_CTR_AUXDIS bit */ 548d2ada559SRoland Scheidegger for (i = 0; i < 100; i++) { 549d2ada559SRoland Scheidegger udelay(50); 550d2ada559SRoland Scheidegger 551d2ada559SRoland Scheidegger if (i8042_command(¶m, I8042_CMD_CTL_RCTR)) 552d2ada559SRoland Scheidegger return -1; 553d2ada559SRoland Scheidegger 554d2ada559SRoland Scheidegger if (!(param & I8042_CTR_AUXDIS) == on) 555d2ada559SRoland Scheidegger return 0; 556d2ada559SRoland Scheidegger } 557d2ada559SRoland Scheidegger 558d2ada559SRoland Scheidegger return -1; 559d2ada559SRoland Scheidegger } 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds /* 5621da177e4SLinus Torvalds * i8042_check_aux() applies as much paranoia as it can at detecting 5631da177e4SLinus Torvalds * the presence of an AUX interface. 5641da177e4SLinus Torvalds */ 5651da177e4SLinus Torvalds 56687fd6318SDmitry Torokhov static int __devinit i8042_check_aux(void) 5671da177e4SLinus Torvalds { 568de9ce703SDmitry Torokhov int retval = -1; 569de9ce703SDmitry Torokhov int irq_registered = 0; 5701e4865f8SDmitry Torokhov int aux_loop_broken = 0; 571de9ce703SDmitry Torokhov unsigned long flags; 5721da177e4SLinus Torvalds unsigned char param; 5731da177e4SLinus Torvalds 5741da177e4SLinus Torvalds /* 5751da177e4SLinus Torvalds * Get rid of bytes in the queue. 5761da177e4SLinus Torvalds */ 5771da177e4SLinus Torvalds 5781da177e4SLinus Torvalds i8042_flush(); 5791da177e4SLinus Torvalds 5801da177e4SLinus Torvalds /* 5811da177e4SLinus Torvalds * Internal loopback test - filters out AT-type i8042's. Unfortunately 5821da177e4SLinus Torvalds * SiS screwed up and their 5597 doesn't support the LOOP command even 5831da177e4SLinus Torvalds * though it has an AUX port. 5841da177e4SLinus Torvalds */ 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds param = 0x5a; 5873ca5de6dSDmitry Torokhov retval = i8042_command(¶m, I8042_CMD_AUX_LOOP); 5883ca5de6dSDmitry Torokhov if (retval || param != 0x5a) { 5891da177e4SLinus Torvalds 5901da177e4SLinus Torvalds /* 5911da177e4SLinus Torvalds * External connection test - filters out AT-soldered PS/2 i8042's 5921da177e4SLinus Torvalds * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error 5931da177e4SLinus Torvalds * 0xfa - no error on some notebooks which ignore the spec 5941da177e4SLinus Torvalds * Because it's common for chipsets to return error on perfectly functioning 5951da177e4SLinus Torvalds * AUX ports, we test for this only when the LOOP command failed. 5961da177e4SLinus Torvalds */ 5971da177e4SLinus Torvalds 598de9ce703SDmitry Torokhov if (i8042_command(¶m, I8042_CMD_AUX_TEST) || 599de9ce703SDmitry Torokhov (param && param != 0xfa && param != 0xff)) 6001da177e4SLinus Torvalds return -1; 6011e4865f8SDmitry Torokhov 6023ca5de6dSDmitry Torokhov /* 6033ca5de6dSDmitry Torokhov * If AUX_LOOP completed without error but returned unexpected data 6043ca5de6dSDmitry Torokhov * mark it as broken 6053ca5de6dSDmitry Torokhov */ 6063ca5de6dSDmitry Torokhov if (!retval) 6071e4865f8SDmitry Torokhov aux_loop_broken = 1; 6081da177e4SLinus Torvalds } 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds /* 6111da177e4SLinus Torvalds * Bit assignment test - filters out PS/2 i8042's in AT mode 6121da177e4SLinus Torvalds */ 6131da177e4SLinus Torvalds 614d2ada559SRoland Scheidegger if (i8042_toggle_aux(0)) { 6151da177e4SLinus Torvalds printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n"); 6161da177e4SLinus Torvalds printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n"); 6171da177e4SLinus Torvalds } 6181da177e4SLinus Torvalds 619d2ada559SRoland Scheidegger if (i8042_toggle_aux(1)) 6201da177e4SLinus Torvalds return -1; 6211da177e4SLinus Torvalds 6221da177e4SLinus Torvalds /* 623de9ce703SDmitry Torokhov * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and 624de9ce703SDmitry Torokhov * used it for a PCI card or somethig else. 625de9ce703SDmitry Torokhov */ 626de9ce703SDmitry Torokhov 6271e4865f8SDmitry Torokhov if (i8042_noloop || aux_loop_broken) { 628de9ce703SDmitry Torokhov /* 629de9ce703SDmitry Torokhov * Without LOOP command we can't test AUX IRQ delivery. Assume the port 630de9ce703SDmitry Torokhov * is working and hope we are right. 631de9ce703SDmitry Torokhov */ 632de9ce703SDmitry Torokhov retval = 0; 633de9ce703SDmitry Torokhov goto out; 634de9ce703SDmitry Torokhov } 635de9ce703SDmitry Torokhov 636de9ce703SDmitry Torokhov if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED, 637de9ce703SDmitry Torokhov "i8042", i8042_platform_device)) 638de9ce703SDmitry Torokhov goto out; 639de9ce703SDmitry Torokhov 640de9ce703SDmitry Torokhov irq_registered = 1; 641de9ce703SDmitry Torokhov 642de9ce703SDmitry Torokhov if (i8042_enable_aux_port()) 643de9ce703SDmitry Torokhov goto out; 644de9ce703SDmitry Torokhov 645de9ce703SDmitry Torokhov spin_lock_irqsave(&i8042_lock, flags); 646de9ce703SDmitry Torokhov 647de9ce703SDmitry Torokhov init_completion(&i8042_aux_irq_delivered); 648de9ce703SDmitry Torokhov i8042_irq_being_tested = 1; 649de9ce703SDmitry Torokhov 650de9ce703SDmitry Torokhov param = 0xa5; 651de9ce703SDmitry Torokhov retval = __i8042_command(¶m, I8042_CMD_AUX_LOOP & 0xf0ff); 652de9ce703SDmitry Torokhov 653de9ce703SDmitry Torokhov spin_unlock_irqrestore(&i8042_lock, flags); 654de9ce703SDmitry Torokhov 655de9ce703SDmitry Torokhov if (retval) 656de9ce703SDmitry Torokhov goto out; 657de9ce703SDmitry Torokhov 658de9ce703SDmitry Torokhov if (wait_for_completion_timeout(&i8042_aux_irq_delivered, 659de9ce703SDmitry Torokhov msecs_to_jiffies(250)) == 0) { 660de9ce703SDmitry Torokhov /* 661de9ce703SDmitry Torokhov * AUX IRQ was never delivered so we need to flush the controller to 662de9ce703SDmitry Torokhov * get rid of the byte we put there; otherwise keyboard may not work. 663de9ce703SDmitry Torokhov */ 664de9ce703SDmitry Torokhov i8042_flush(); 665de9ce703SDmitry Torokhov retval = -1; 666de9ce703SDmitry Torokhov } 667de9ce703SDmitry Torokhov 668de9ce703SDmitry Torokhov out: 669de9ce703SDmitry Torokhov 670de9ce703SDmitry Torokhov /* 6711da177e4SLinus Torvalds * Disable the interface. 6721da177e4SLinus Torvalds */ 6731da177e4SLinus Torvalds 6741da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_AUXDIS; 6751da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_AUXINT; 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) 678de9ce703SDmitry Torokhov retval = -1; 679de9ce703SDmitry Torokhov 680de9ce703SDmitry Torokhov if (irq_registered) 681de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 682de9ce703SDmitry Torokhov 683de9ce703SDmitry Torokhov return retval; 684de9ce703SDmitry Torokhov } 685de9ce703SDmitry Torokhov 686de9ce703SDmitry Torokhov static int i8042_controller_check(void) 687de9ce703SDmitry Torokhov { 688de9ce703SDmitry Torokhov if (i8042_flush() == I8042_BUFFER_SIZE) { 689de9ce703SDmitry Torokhov printk(KERN_ERR "i8042.c: No controller found.\n"); 690de9ce703SDmitry Torokhov return -ENODEV; 691de9ce703SDmitry Torokhov } 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds return 0; 6941da177e4SLinus Torvalds } 6951da177e4SLinus Torvalds 696de9ce703SDmitry Torokhov static int i8042_controller_selftest(void) 6972673c836SVojtech Pavlik { 6982673c836SVojtech Pavlik unsigned char param; 6992673c836SVojtech Pavlik 7002673c836SVojtech Pavlik if (!i8042_reset) 7012673c836SVojtech Pavlik return 0; 7022673c836SVojtech Pavlik 7032673c836SVojtech Pavlik if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { 7042673c836SVojtech Pavlik printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); 705de9ce703SDmitry Torokhov return -ENODEV; 7062673c836SVojtech Pavlik } 7072673c836SVojtech Pavlik 7082673c836SVojtech Pavlik if (param != I8042_RET_CTL_TEST) { 7092673c836SVojtech Pavlik printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", 7102673c836SVojtech Pavlik param, I8042_RET_CTL_TEST); 711de9ce703SDmitry Torokhov return -EIO; 7122673c836SVojtech Pavlik } 7132673c836SVojtech Pavlik 7142673c836SVojtech Pavlik return 0; 7152673c836SVojtech Pavlik } 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds /* 7181da177e4SLinus Torvalds * i8042_controller init initializes the i8042 controller, and, 7191da177e4SLinus Torvalds * most importantly, sets it into non-xlated mode if that's 7201da177e4SLinus Torvalds * desired. 7211da177e4SLinus Torvalds */ 7221da177e4SLinus Torvalds 7231da177e4SLinus Torvalds static int i8042_controller_init(void) 7241da177e4SLinus Torvalds { 7251da177e4SLinus Torvalds unsigned long flags; 7261da177e4SLinus Torvalds 7271da177e4SLinus Torvalds /* 7281da177e4SLinus Torvalds * Save the CTR for restoral on unload / reboot. 7291da177e4SLinus Torvalds */ 7301da177e4SLinus Torvalds 7311da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { 7321da177e4SLinus Torvalds printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); 733de9ce703SDmitry Torokhov return -EIO; 7341da177e4SLinus Torvalds } 7351da177e4SLinus Torvalds 7361da177e4SLinus Torvalds i8042_initial_ctr = i8042_ctr; 7371da177e4SLinus Torvalds 7381da177e4SLinus Torvalds /* 7391da177e4SLinus Torvalds * Disable the keyboard interface and interrupt. 7401da177e4SLinus Torvalds */ 7411da177e4SLinus Torvalds 7421da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_KBDDIS; 7431da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_KBDINT; 7441da177e4SLinus Torvalds 7451da177e4SLinus Torvalds /* 7461da177e4SLinus Torvalds * Handle keylock. 7471da177e4SLinus Torvalds */ 7481da177e4SLinus Torvalds 7491da177e4SLinus Torvalds spin_lock_irqsave(&i8042_lock, flags); 7501da177e4SLinus Torvalds if (~i8042_read_status() & I8042_STR_KEYLOCK) { 7511da177e4SLinus Torvalds if (i8042_unlock) 7521da177e4SLinus Torvalds i8042_ctr |= I8042_CTR_IGNKEYLOCK; 7531da177e4SLinus Torvalds else 7541da177e4SLinus Torvalds printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); 7551da177e4SLinus Torvalds } 7561da177e4SLinus Torvalds spin_unlock_irqrestore(&i8042_lock, flags); 7571da177e4SLinus Torvalds 7581da177e4SLinus Torvalds /* 7591da177e4SLinus Torvalds * If the chip is configured into nontranslated mode by the BIOS, don't 7601da177e4SLinus Torvalds * bother enabling translating and be happy. 7611da177e4SLinus Torvalds */ 7621da177e4SLinus Torvalds 7631da177e4SLinus Torvalds if (~i8042_ctr & I8042_CTR_XLATE) 7641da177e4SLinus Torvalds i8042_direct = 1; 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds /* 7671da177e4SLinus Torvalds * Set nontranslated mode for the kbd interface if requested by an option. 7681da177e4SLinus Torvalds * After this the kbd interface becomes a simple serial in/out, like the aux 7691da177e4SLinus Torvalds * interface is. We don't do this by default, since it can confuse notebook 7701da177e4SLinus Torvalds * BIOSes. 7711da177e4SLinus Torvalds */ 7721da177e4SLinus Torvalds 7731da177e4SLinus Torvalds if (i8042_direct) 7741da177e4SLinus Torvalds i8042_ctr &= ~I8042_CTR_XLATE; 7751da177e4SLinus Torvalds 7761da177e4SLinus Torvalds /* 7771da177e4SLinus Torvalds * Write CTR back. 7781da177e4SLinus Torvalds */ 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 7811da177e4SLinus Torvalds printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); 782de9ce703SDmitry Torokhov return -EIO; 7831da177e4SLinus Torvalds } 7841da177e4SLinus Torvalds 7851da177e4SLinus Torvalds return 0; 7861da177e4SLinus Torvalds } 7871da177e4SLinus Torvalds 7881da177e4SLinus Torvalds 7891da177e4SLinus Torvalds /* 790de9ce703SDmitry Torokhov * Reset the controller and reset CRT to the original value set by BIOS. 7911da177e4SLinus Torvalds */ 7921da177e4SLinus Torvalds 793de9ce703SDmitry Torokhov static void i8042_controller_reset(void) 794de9ce703SDmitry Torokhov { 795de9ce703SDmitry Torokhov i8042_flush(); 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds /* 7988d04ddb6SDmitry Torokhov * Disable both KBD and AUX interfaces so they don't get in the way 7998d04ddb6SDmitry Torokhov */ 8008d04ddb6SDmitry Torokhov 8018d04ddb6SDmitry Torokhov i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS; 8028d04ddb6SDmitry Torokhov i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT); 8038d04ddb6SDmitry Torokhov 8048d04ddb6SDmitry Torokhov /* 8051da177e4SLinus Torvalds * Disable MUX mode if present. 8061da177e4SLinus Torvalds */ 8071da177e4SLinus Torvalds 8081da177e4SLinus Torvalds if (i8042_mux_present) 8091da177e4SLinus Torvalds i8042_set_mux_mode(0, NULL); 8101da177e4SLinus Torvalds 8111da177e4SLinus Torvalds /* 812de9ce703SDmitry Torokhov * Reset the controller if requested. 813de9ce703SDmitry Torokhov */ 814de9ce703SDmitry Torokhov 815de9ce703SDmitry Torokhov i8042_controller_selftest(); 816de9ce703SDmitry Torokhov 817de9ce703SDmitry Torokhov /* 8181da177e4SLinus Torvalds * Restore the original control register setting. 8191da177e4SLinus Torvalds */ 8201da177e4SLinus Torvalds 821de9ce703SDmitry Torokhov if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR)) 8221da177e4SLinus Torvalds printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); 8231da177e4SLinus Torvalds } 8241da177e4SLinus Torvalds 8251da177e4SLinus Torvalds 8261da177e4SLinus Torvalds /* 8271da177e4SLinus Torvalds * i8042_panic_blink() will flash the keyboard LEDs and is called when 8281da177e4SLinus Torvalds * kernel panics. Flashing LEDs is useful for users running X who may 8291da177e4SLinus Torvalds * not see the console and will help distingushing panics from "real" 8301da177e4SLinus Torvalds * lockups. 8311da177e4SLinus Torvalds * 8321da177e4SLinus Torvalds * Note that DELAY has a limit of 10ms so we will not get stuck here 8331da177e4SLinus Torvalds * waiting for KBC to free up even if KBD interrupt is off 8341da177e4SLinus Torvalds */ 8351da177e4SLinus Torvalds 8361da177e4SLinus Torvalds #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0) 8371da177e4SLinus Torvalds 8381da177e4SLinus Torvalds static long i8042_panic_blink(long count) 8391da177e4SLinus Torvalds { 8401da177e4SLinus Torvalds long delay = 0; 8411da177e4SLinus Torvalds static long last_blink; 8421da177e4SLinus Torvalds static char led; 8431da177e4SLinus Torvalds 8441da177e4SLinus Torvalds /* 8451da177e4SLinus Torvalds * We expect frequency to be about 1/2s. KDB uses about 1s. 8461da177e4SLinus Torvalds * Make sure they are different. 8471da177e4SLinus Torvalds */ 8481da177e4SLinus Torvalds if (!i8042_blink_frequency) 8491da177e4SLinus Torvalds return 0; 8501da177e4SLinus Torvalds if (count - last_blink < i8042_blink_frequency) 8511da177e4SLinus Torvalds return 0; 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds led ^= 0x01 | 0x04; 8541da177e4SLinus Torvalds while (i8042_read_status() & I8042_STR_IBF) 8551da177e4SLinus Torvalds DELAY; 85619f3c3e3SDmitry Torokhov dbg("%02x -> i8042 (panic blink)", 0xed); 85719f3c3e3SDmitry Torokhov i8042_suppress_kbd_ack = 2; 8581da177e4SLinus Torvalds i8042_write_data(0xed); /* set leds */ 8591da177e4SLinus Torvalds DELAY; 8601da177e4SLinus Torvalds while (i8042_read_status() & I8042_STR_IBF) 8611da177e4SLinus Torvalds DELAY; 8621da177e4SLinus Torvalds DELAY; 86319f3c3e3SDmitry Torokhov dbg("%02x -> i8042 (panic blink)", led); 8641da177e4SLinus Torvalds i8042_write_data(led); 8651da177e4SLinus Torvalds DELAY; 8661da177e4SLinus Torvalds last_blink = count; 8671da177e4SLinus Torvalds return delay; 8681da177e4SLinus Torvalds } 8691da177e4SLinus Torvalds 8701da177e4SLinus Torvalds #undef DELAY 8711da177e4SLinus Torvalds 87282dd9effSDmitry Torokhov #ifdef CONFIG_PM 8731da177e4SLinus Torvalds /* 87482dd9effSDmitry Torokhov * Here we try to restore the original BIOS settings. We only want to 87582dd9effSDmitry Torokhov * do that once, when we really suspend, not when we taking memory 87682dd9effSDmitry Torokhov * snapshot for swsusp (in this case we'll perform required cleanup 87782dd9effSDmitry Torokhov * as part of shutdown process). 8781da177e4SLinus Torvalds */ 8791da177e4SLinus Torvalds 8803ae5eaecSRussell King static int i8042_suspend(struct platform_device *dev, pm_message_t state) 8811da177e4SLinus Torvalds { 88282dd9effSDmitry Torokhov if (dev->dev.power.power_state.event != state.event) { 88382dd9effSDmitry Torokhov if (state.event == PM_EVENT_SUSPEND) 88482dd9effSDmitry Torokhov i8042_controller_reset(); 88582dd9effSDmitry Torokhov 88682dd9effSDmitry Torokhov dev->dev.power.power_state = state; 88782dd9effSDmitry Torokhov } 8881da177e4SLinus Torvalds 8891da177e4SLinus Torvalds return 0; 8901da177e4SLinus Torvalds } 8911da177e4SLinus Torvalds 8921da177e4SLinus Torvalds 8931da177e4SLinus Torvalds /* 8941da177e4SLinus Torvalds * Here we try to reset everything back to a state in which suspended 8951da177e4SLinus Torvalds */ 8961da177e4SLinus Torvalds 8973ae5eaecSRussell King static int i8042_resume(struct platform_device *dev) 8981da177e4SLinus Torvalds { 899de9ce703SDmitry Torokhov int error; 9001da177e4SLinus Torvalds 90182dd9effSDmitry Torokhov /* 90282dd9effSDmitry Torokhov * Do not bother with restoring state if we haven't suspened yet 90382dd9effSDmitry Torokhov */ 90482dd9effSDmitry Torokhov if (dev->dev.power.power_state.event == PM_EVENT_ON) 90582dd9effSDmitry Torokhov return 0; 90682dd9effSDmitry Torokhov 907de9ce703SDmitry Torokhov error = i8042_controller_check(); 908de9ce703SDmitry Torokhov if (error) 909de9ce703SDmitry Torokhov return error; 9102673c836SVojtech Pavlik 911de9ce703SDmitry Torokhov error = i8042_controller_selftest(); 912de9ce703SDmitry Torokhov if (error) 913de9ce703SDmitry Torokhov return error; 914de9ce703SDmitry Torokhov 915de9ce703SDmitry Torokhov /* 91682dd9effSDmitry Torokhov * Restore original CTR value and disable all ports 917de9ce703SDmitry Torokhov */ 918de9ce703SDmitry Torokhov 91982dd9effSDmitry Torokhov i8042_ctr = i8042_initial_ctr; 92082dd9effSDmitry Torokhov if (i8042_direct) 92182dd9effSDmitry Torokhov i8042_ctr &= ~I8042_CTR_XLATE; 922de9ce703SDmitry Torokhov i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS; 923de9ce703SDmitry Torokhov i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT); 9242673c836SVojtech Pavlik if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { 925de9ce703SDmitry Torokhov printk(KERN_ERR "i8042: Can't write CTR to resume\n"); 926de9ce703SDmitry Torokhov return -EIO; 9271da177e4SLinus Torvalds } 9281da177e4SLinus Torvalds 929de9ce703SDmitry Torokhov if (i8042_mux_present) { 9301da177e4SLinus Torvalds if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports()) 931de9ce703SDmitry Torokhov printk(KERN_WARNING 932de9ce703SDmitry Torokhov "i8042: failed to resume active multiplexor, " 933de9ce703SDmitry Torokhov "mouse won't work.\n"); 934de9ce703SDmitry Torokhov } else if (i8042_ports[I8042_AUX_PORT_NO].serio) 935de9ce703SDmitry Torokhov i8042_enable_aux_port(); 9361da177e4SLinus Torvalds 937de9ce703SDmitry Torokhov if (i8042_ports[I8042_KBD_PORT_NO].serio) 938de9ce703SDmitry Torokhov i8042_enable_kbd_port(); 9391da177e4SLinus Torvalds 9407d12e780SDavid Howells i8042_interrupt(0, NULL); 9411da177e4SLinus Torvalds 94282dd9effSDmitry Torokhov dev->dev.power.power_state = PMSG_ON; 94382dd9effSDmitry Torokhov 9441da177e4SLinus Torvalds return 0; 9451da177e4SLinus Torvalds } 94682dd9effSDmitry Torokhov #endif /* CONFIG_PM */ 9471da177e4SLinus Torvalds 9481da177e4SLinus Torvalds /* 9491da177e4SLinus Torvalds * We need to reset the 8042 back to original mode on system shutdown, 9501da177e4SLinus Torvalds * because otherwise BIOSes will be confused. 9511da177e4SLinus Torvalds */ 9521da177e4SLinus Torvalds 9533ae5eaecSRussell King static void i8042_shutdown(struct platform_device *dev) 9541da177e4SLinus Torvalds { 95582dd9effSDmitry Torokhov i8042_controller_reset(); 9561da177e4SLinus Torvalds } 9571da177e4SLinus Torvalds 95887fd6318SDmitry Torokhov static int __devinit i8042_create_kbd_port(void) 9591da177e4SLinus Torvalds { 9601da177e4SLinus Torvalds struct serio *serio; 9611da177e4SLinus Torvalds struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; 9621da177e4SLinus Torvalds 963d39969deSDmitry Torokhov serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 9640854e52dSDmitry Torokhov if (!serio) 9650854e52dSDmitry Torokhov return -ENOMEM; 9660854e52dSDmitry Torokhov 9671da177e4SLinus Torvalds serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; 9681da177e4SLinus Torvalds serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; 9691da177e4SLinus Torvalds serio->start = i8042_start; 9701da177e4SLinus Torvalds serio->stop = i8042_stop; 9711da177e4SLinus Torvalds serio->port_data = port; 9721da177e4SLinus Torvalds serio->dev.parent = &i8042_platform_device->dev; 973de9ce703SDmitry Torokhov strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); 9741da177e4SLinus Torvalds strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds port->serio = serio; 977de9ce703SDmitry Torokhov port->irq = I8042_KBD_IRQ; 9780854e52dSDmitry Torokhov 979de9ce703SDmitry Torokhov return 0; 9801da177e4SLinus Torvalds } 9811da177e4SLinus Torvalds 982de9ce703SDmitry Torokhov static int __devinit i8042_create_aux_port(int idx) 9831da177e4SLinus Torvalds { 9841da177e4SLinus Torvalds struct serio *serio; 985de9ce703SDmitry Torokhov int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx; 986de9ce703SDmitry Torokhov struct i8042_port *port = &i8042_ports[port_no]; 9871da177e4SLinus Torvalds 988d39969deSDmitry Torokhov serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 9890854e52dSDmitry Torokhov if (!serio) 9900854e52dSDmitry Torokhov return -ENOMEM; 9910854e52dSDmitry Torokhov 9921da177e4SLinus Torvalds serio->id.type = SERIO_8042; 9931da177e4SLinus Torvalds serio->write = i8042_aux_write; 9941da177e4SLinus Torvalds serio->start = i8042_start; 9951da177e4SLinus Torvalds serio->stop = i8042_stop; 9961da177e4SLinus Torvalds serio->port_data = port; 9971da177e4SLinus Torvalds serio->dev.parent = &i8042_platform_device->dev; 998de9ce703SDmitry Torokhov if (idx < 0) { 999de9ce703SDmitry Torokhov strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name)); 10001da177e4SLinus Torvalds strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); 1001de9ce703SDmitry Torokhov } else { 1002de9ce703SDmitry Torokhov snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx); 1003de9ce703SDmitry Torokhov snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1); 10041da177e4SLinus Torvalds } 10051da177e4SLinus Torvalds 10061da177e4SLinus Torvalds port->serio = serio; 1007de9ce703SDmitry Torokhov port->mux = idx; 1008de9ce703SDmitry Torokhov port->irq = I8042_AUX_IRQ; 10090854e52dSDmitry Torokhov 1010de9ce703SDmitry Torokhov return 0; 1011de9ce703SDmitry Torokhov } 1012de9ce703SDmitry Torokhov 1013de9ce703SDmitry Torokhov static void __devinit i8042_free_kbd_port(void) 1014de9ce703SDmitry Torokhov { 1015de9ce703SDmitry Torokhov kfree(i8042_ports[I8042_KBD_PORT_NO].serio); 1016de9ce703SDmitry Torokhov i8042_ports[I8042_KBD_PORT_NO].serio = NULL; 1017de9ce703SDmitry Torokhov } 1018de9ce703SDmitry Torokhov 1019de9ce703SDmitry Torokhov static void __devinit i8042_free_aux_ports(void) 1020de9ce703SDmitry Torokhov { 1021de9ce703SDmitry Torokhov int i; 1022de9ce703SDmitry Torokhov 1023de9ce703SDmitry Torokhov for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) { 1024de9ce703SDmitry Torokhov kfree(i8042_ports[i].serio); 1025de9ce703SDmitry Torokhov i8042_ports[i].serio = NULL; 1026de9ce703SDmitry Torokhov } 1027de9ce703SDmitry Torokhov } 1028de9ce703SDmitry Torokhov 1029de9ce703SDmitry Torokhov static void __devinit i8042_register_ports(void) 1030de9ce703SDmitry Torokhov { 1031de9ce703SDmitry Torokhov int i; 1032de9ce703SDmitry Torokhov 1033de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) { 1034de9ce703SDmitry Torokhov if (i8042_ports[i].serio) { 1035de9ce703SDmitry Torokhov printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n", 1036de9ce703SDmitry Torokhov i8042_ports[i].serio->name, 1037de9ce703SDmitry Torokhov (unsigned long) I8042_DATA_REG, 1038de9ce703SDmitry Torokhov (unsigned long) I8042_COMMAND_REG, 1039de9ce703SDmitry Torokhov i8042_ports[i].irq); 1040de9ce703SDmitry Torokhov serio_register_port(i8042_ports[i].serio); 1041de9ce703SDmitry Torokhov } 1042de9ce703SDmitry Torokhov } 1043de9ce703SDmitry Torokhov } 1044de9ce703SDmitry Torokhov 1045de9ce703SDmitry Torokhov static void __devinit i8042_unregister_ports(void) 1046de9ce703SDmitry Torokhov { 1047de9ce703SDmitry Torokhov int i; 1048de9ce703SDmitry Torokhov 1049de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_PORTS; i++) { 1050de9ce703SDmitry Torokhov if (i8042_ports[i].serio) { 1051de9ce703SDmitry Torokhov serio_unregister_port(i8042_ports[i].serio); 1052de9ce703SDmitry Torokhov i8042_ports[i].serio = NULL; 1053de9ce703SDmitry Torokhov } 1054de9ce703SDmitry Torokhov } 1055de9ce703SDmitry Torokhov } 1056de9ce703SDmitry Torokhov 1057de9ce703SDmitry Torokhov static void i8042_free_irqs(void) 1058de9ce703SDmitry Torokhov { 1059de9ce703SDmitry Torokhov if (i8042_aux_irq_registered) 1060de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 1061de9ce703SDmitry Torokhov if (i8042_kbd_irq_registered) 1062de9ce703SDmitry Torokhov free_irq(I8042_KBD_IRQ, i8042_platform_device); 1063de9ce703SDmitry Torokhov 1064de9ce703SDmitry Torokhov i8042_aux_irq_registered = i8042_kbd_irq_registered = 0; 1065de9ce703SDmitry Torokhov } 1066de9ce703SDmitry Torokhov 1067de9ce703SDmitry Torokhov static int __devinit i8042_setup_aux(void) 1068de9ce703SDmitry Torokhov { 1069de9ce703SDmitry Torokhov int (*aux_enable)(void); 1070de9ce703SDmitry Torokhov int error; 1071de9ce703SDmitry Torokhov int i; 1072de9ce703SDmitry Torokhov 1073de9ce703SDmitry Torokhov if (i8042_check_aux()) 1074de9ce703SDmitry Torokhov return -ENODEV; 1075de9ce703SDmitry Torokhov 1076de9ce703SDmitry Torokhov if (i8042_nomux || i8042_check_mux()) { 1077de9ce703SDmitry Torokhov error = i8042_create_aux_port(-1); 1078de9ce703SDmitry Torokhov if (error) 1079de9ce703SDmitry Torokhov goto err_free_ports; 1080de9ce703SDmitry Torokhov aux_enable = i8042_enable_aux_port; 1081de9ce703SDmitry Torokhov } else { 1082de9ce703SDmitry Torokhov for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { 1083de9ce703SDmitry Torokhov error = i8042_create_aux_port(i); 1084de9ce703SDmitry Torokhov if (error) 1085de9ce703SDmitry Torokhov goto err_free_ports; 1086de9ce703SDmitry Torokhov } 1087de9ce703SDmitry Torokhov aux_enable = i8042_enable_mux_ports; 1088de9ce703SDmitry Torokhov } 1089de9ce703SDmitry Torokhov 1090de9ce703SDmitry Torokhov error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED, 1091de9ce703SDmitry Torokhov "i8042", i8042_platform_device); 1092de9ce703SDmitry Torokhov if (error) 1093de9ce703SDmitry Torokhov goto err_free_ports; 1094de9ce703SDmitry Torokhov 1095de9ce703SDmitry Torokhov if (aux_enable()) 1096de9ce703SDmitry Torokhov goto err_free_irq; 1097de9ce703SDmitry Torokhov 1098de9ce703SDmitry Torokhov i8042_aux_irq_registered = 1; 1099de9ce703SDmitry Torokhov return 0; 1100de9ce703SDmitry Torokhov 1101de9ce703SDmitry Torokhov err_free_irq: 1102de9ce703SDmitry Torokhov free_irq(I8042_AUX_IRQ, i8042_platform_device); 1103de9ce703SDmitry Torokhov err_free_ports: 1104de9ce703SDmitry Torokhov i8042_free_aux_ports(); 1105de9ce703SDmitry Torokhov return error; 1106de9ce703SDmitry Torokhov } 1107de9ce703SDmitry Torokhov 1108de9ce703SDmitry Torokhov static int __devinit i8042_setup_kbd(void) 1109de9ce703SDmitry Torokhov { 1110de9ce703SDmitry Torokhov int error; 1111de9ce703SDmitry Torokhov 1112de9ce703SDmitry Torokhov error = i8042_create_kbd_port(); 1113de9ce703SDmitry Torokhov if (error) 1114de9ce703SDmitry Torokhov return error; 1115de9ce703SDmitry Torokhov 1116de9ce703SDmitry Torokhov error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED, 1117de9ce703SDmitry Torokhov "i8042", i8042_platform_device); 1118de9ce703SDmitry Torokhov if (error) 1119de9ce703SDmitry Torokhov goto err_free_port; 1120de9ce703SDmitry Torokhov 1121de9ce703SDmitry Torokhov error = i8042_enable_kbd_port(); 1122de9ce703SDmitry Torokhov if (error) 1123de9ce703SDmitry Torokhov goto err_free_irq; 1124de9ce703SDmitry Torokhov 1125de9ce703SDmitry Torokhov i8042_kbd_irq_registered = 1; 1126de9ce703SDmitry Torokhov return 0; 1127de9ce703SDmitry Torokhov 1128de9ce703SDmitry Torokhov err_free_irq: 1129de9ce703SDmitry Torokhov free_irq(I8042_KBD_IRQ, i8042_platform_device); 1130de9ce703SDmitry Torokhov err_free_port: 1131de9ce703SDmitry Torokhov i8042_free_kbd_port(); 1132de9ce703SDmitry Torokhov return error; 11331da177e4SLinus Torvalds } 11341da177e4SLinus Torvalds 113587fd6318SDmitry Torokhov static int __devinit i8042_probe(struct platform_device *dev) 11361da177e4SLinus Torvalds { 1137de9ce703SDmitry Torokhov int error; 11381da177e4SLinus Torvalds 1139de9ce703SDmitry Torokhov error = i8042_controller_selftest(); 1140de9ce703SDmitry Torokhov if (error) 1141de9ce703SDmitry Torokhov return error; 11421da177e4SLinus Torvalds 1143de9ce703SDmitry Torokhov error = i8042_controller_init(); 1144de9ce703SDmitry Torokhov if (error) 1145de9ce703SDmitry Torokhov return error; 11461da177e4SLinus Torvalds 1147de9ce703SDmitry Torokhov if (!i8042_noaux) { 1148de9ce703SDmitry Torokhov error = i8042_setup_aux(); 1149de9ce703SDmitry Torokhov if (error && error != -ENODEV && error != -EBUSY) 1150de9ce703SDmitry Torokhov goto out_fail; 11511da177e4SLinus Torvalds } 11521da177e4SLinus Torvalds 1153945ef0d4SDmitry Torokhov if (!i8042_nokbd) { 1154de9ce703SDmitry Torokhov error = i8042_setup_kbd(); 1155de9ce703SDmitry Torokhov if (error) 1156de9ce703SDmitry Torokhov goto out_fail; 1157945ef0d4SDmitry Torokhov } 1158945ef0d4SDmitry Torokhov 1159de9ce703SDmitry Torokhov /* 1160de9ce703SDmitry Torokhov * Ok, everything is ready, let's register all serio ports 1161de9ce703SDmitry Torokhov */ 1162de9ce703SDmitry Torokhov i8042_register_ports(); 11631da177e4SLinus Torvalds 11641da177e4SLinus Torvalds return 0; 11650854e52dSDmitry Torokhov 1166de9ce703SDmitry Torokhov out_fail: 1167de9ce703SDmitry Torokhov i8042_free_aux_ports(); /* in case KBD failed but AUX not */ 1168de9ce703SDmitry Torokhov i8042_free_irqs(); 1169de9ce703SDmitry Torokhov i8042_controller_reset(); 11700854e52dSDmitry Torokhov 1171de9ce703SDmitry Torokhov return error; 11721da177e4SLinus Torvalds } 11731da177e4SLinus Torvalds 117487fd6318SDmitry Torokhov static int __devexit i8042_remove(struct platform_device *dev) 11751da177e4SLinus Torvalds { 1176de9ce703SDmitry Torokhov i8042_unregister_ports(); 1177de9ce703SDmitry Torokhov i8042_free_irqs(); 1178de9ce703SDmitry Torokhov i8042_controller_reset(); 11791da177e4SLinus Torvalds 118087fd6318SDmitry Torokhov return 0; 118187fd6318SDmitry Torokhov } 118287fd6318SDmitry Torokhov 118387fd6318SDmitry Torokhov static struct platform_driver i8042_driver = { 118487fd6318SDmitry Torokhov .driver = { 118587fd6318SDmitry Torokhov .name = "i8042", 118687fd6318SDmitry Torokhov .owner = THIS_MODULE, 118787fd6318SDmitry Torokhov }, 118887fd6318SDmitry Torokhov .probe = i8042_probe, 118987fd6318SDmitry Torokhov .remove = __devexit_p(i8042_remove), 119082dd9effSDmitry Torokhov .shutdown = i8042_shutdown, 119182dd9effSDmitry Torokhov #ifdef CONFIG_PM 119287fd6318SDmitry Torokhov .suspend = i8042_suspend, 119387fd6318SDmitry Torokhov .resume = i8042_resume, 119482dd9effSDmitry Torokhov #endif 119587fd6318SDmitry Torokhov }; 119687fd6318SDmitry Torokhov 119787fd6318SDmitry Torokhov static int __init i8042_init(void) 119887fd6318SDmitry Torokhov { 119987fd6318SDmitry Torokhov int err; 120087fd6318SDmitry Torokhov 120187fd6318SDmitry Torokhov dbg_init(); 120287fd6318SDmitry Torokhov 120387fd6318SDmitry Torokhov err = i8042_platform_init(); 120487fd6318SDmitry Torokhov if (err) 120587fd6318SDmitry Torokhov return err; 120687fd6318SDmitry Torokhov 1207de9ce703SDmitry Torokhov err = i8042_controller_check(); 1208de9ce703SDmitry Torokhov if (err) 1209de9ce703SDmitry Torokhov goto err_platform_exit; 121087fd6318SDmitry Torokhov 121187fd6318SDmitry Torokhov err = platform_driver_register(&i8042_driver); 121287fd6318SDmitry Torokhov if (err) 121387fd6318SDmitry Torokhov goto err_platform_exit; 121487fd6318SDmitry Torokhov 121587fd6318SDmitry Torokhov i8042_platform_device = platform_device_alloc("i8042", -1); 121687fd6318SDmitry Torokhov if (!i8042_platform_device) { 121787fd6318SDmitry Torokhov err = -ENOMEM; 121887fd6318SDmitry Torokhov goto err_unregister_driver; 121987fd6318SDmitry Torokhov } 122087fd6318SDmitry Torokhov 122187fd6318SDmitry Torokhov err = platform_device_add(i8042_platform_device); 122287fd6318SDmitry Torokhov if (err) 122387fd6318SDmitry Torokhov goto err_free_device; 122487fd6318SDmitry Torokhov 1225de9ce703SDmitry Torokhov panic_blink = i8042_panic_blink; 1226de9ce703SDmitry Torokhov 122787fd6318SDmitry Torokhov return 0; 122887fd6318SDmitry Torokhov 122987fd6318SDmitry Torokhov err_free_device: 123087fd6318SDmitry Torokhov platform_device_put(i8042_platform_device); 123187fd6318SDmitry Torokhov err_unregister_driver: 123287fd6318SDmitry Torokhov platform_driver_unregister(&i8042_driver); 123387fd6318SDmitry Torokhov err_platform_exit: 123487fd6318SDmitry Torokhov i8042_platform_exit(); 123587fd6318SDmitry Torokhov 123687fd6318SDmitry Torokhov return err; 123787fd6318SDmitry Torokhov } 123887fd6318SDmitry Torokhov 123987fd6318SDmitry Torokhov static void __exit i8042_exit(void) 124087fd6318SDmitry Torokhov { 12411da177e4SLinus Torvalds platform_device_unregister(i8042_platform_device); 12423ae5eaecSRussell King platform_driver_unregister(&i8042_driver); 12431da177e4SLinus Torvalds i8042_platform_exit(); 12441da177e4SLinus Torvalds 12451da177e4SLinus Torvalds panic_blink = NULL; 12461da177e4SLinus Torvalds } 12471da177e4SLinus Torvalds 12481da177e4SLinus Torvalds module_init(i8042_init); 12491da177e4SLinus Torvalds module_exit(i8042_exit); 1250