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