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