xref: /linux/drivers/input/serio/i8042.c (revision e55a3366984cda7d179e194a772f5ae4fe551b80)
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 
134eb3c30bSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
144eb3c30bSJoe Perches 
157e044e05SDmitry Torokhov #include <linux/types.h>
161da177e4SLinus Torvalds #include <linux/delay.h>
171da177e4SLinus Torvalds #include <linux/module.h>
181da177e4SLinus Torvalds #include <linux/interrupt.h>
191da177e4SLinus Torvalds #include <linux/ioport.h>
201da177e4SLinus Torvalds #include <linux/init.h>
211da177e4SLinus Torvalds #include <linux/serio.h>
221da177e4SLinus Torvalds #include <linux/err.h>
231da177e4SLinus Torvalds #include <linux/rcupdate.h>
24d052d1beSRussell King #include <linux/platform_device.h>
25553a05b8SMárton Németh #include <linux/i8042.h>
265a0e3ad6STejun Heo #include <linux/slab.h>
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds #include <asm/io.h>
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
311da177e4SLinus Torvalds MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
321da177e4SLinus Torvalds MODULE_LICENSE("GPL");
331da177e4SLinus Torvalds 
34386b3849SDmitry Torokhov static bool i8042_nokbd;
35945ef0d4SDmitry Torokhov module_param_named(nokbd, i8042_nokbd, bool, 0);
36945ef0d4SDmitry Torokhov MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port.");
37945ef0d4SDmitry Torokhov 
38386b3849SDmitry Torokhov static bool i8042_noaux;
391da177e4SLinus Torvalds module_param_named(noaux, i8042_noaux, bool, 0);
401da177e4SLinus Torvalds MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port.");
411da177e4SLinus Torvalds 
42*e55a3366SDmitry Torokhov static bool i8042_nomux;
431da177e4SLinus Torvalds module_param_named(nomux, i8042_nomux, bool, 0);
442c860a11SDominik Brodowski MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing controller is present.");
451da177e4SLinus Torvalds 
46386b3849SDmitry Torokhov static bool i8042_unlock;
471da177e4SLinus Torvalds module_param_named(unlock, i8042_unlock, bool, 0);
481da177e4SLinus Torvalds MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
491da177e4SLinus Torvalds 
50386b3849SDmitry Torokhov static bool i8042_reset;
511da177e4SLinus Torvalds module_param_named(reset, i8042_reset, bool, 0);
521da177e4SLinus Torvalds MODULE_PARM_DESC(reset, "Reset controller during init and cleanup.");
531da177e4SLinus Torvalds 
54386b3849SDmitry Torokhov static bool i8042_direct;
551da177e4SLinus Torvalds module_param_named(direct, i8042_direct, bool, 0);
561da177e4SLinus Torvalds MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode.");
571da177e4SLinus Torvalds 
58386b3849SDmitry Torokhov static bool i8042_dumbkbd;
591da177e4SLinus Torvalds module_param_named(dumbkbd, i8042_dumbkbd, bool, 0);
601da177e4SLinus Torvalds MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard");
611da177e4SLinus Torvalds 
62386b3849SDmitry Torokhov static bool i8042_noloop;
631da177e4SLinus Torvalds module_param_named(noloop, i8042_noloop, bool, 0);
641da177e4SLinus Torvalds MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port");
651da177e4SLinus Torvalds 
66f8313ef1SJiri Kosina static bool i8042_notimeout;
67f8313ef1SJiri Kosina module_param_named(notimeout, i8042_notimeout, bool, 0);
68f8313ef1SJiri Kosina MODULE_PARM_DESC(notimeout, "Ignore timeouts signalled by i8042");
69f8313ef1SJiri Kosina 
708987fec0SCarlos Corbacho #ifdef CONFIG_X86
71386b3849SDmitry Torokhov static bool i8042_dritek;
728987fec0SCarlos Corbacho module_param_named(dritek, i8042_dritek, bool, 0);
738987fec0SCarlos Corbacho MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension");
748987fec0SCarlos Corbacho #endif
758987fec0SCarlos Corbacho 
761da177e4SLinus Torvalds #ifdef CONFIG_PNP
77386b3849SDmitry Torokhov static bool i8042_nopnp;
781da177e4SLinus Torvalds module_param_named(nopnp, i8042_nopnp, bool, 0);
791da177e4SLinus Torvalds MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
801da177e4SLinus Torvalds #endif
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds #define DEBUG
831da177e4SLinus Torvalds #ifdef DEBUG
84386b3849SDmitry Torokhov static bool i8042_debug;
851da177e4SLinus Torvalds module_param_named(debug, i8042_debug, bool, 0600);
861da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off");
871da177e4SLinus Torvalds #endif
881da177e4SLinus Torvalds 
891c7827aeSDmitry Torokhov static bool i8042_bypass_aux_irq_test;
90a7c5868cSHans de Goede static char i8042_kbd_firmware_id[128];
91a7c5868cSHans de Goede static char i8042_aux_firmware_id[128];
921c7827aeSDmitry Torokhov 
931da177e4SLinus Torvalds #include "i8042.h"
941da177e4SLinus Torvalds 
95181d683dSDmitry Torokhov /*
96181d683dSDmitry Torokhov  * i8042_lock protects serialization between i8042_command and
97181d683dSDmitry Torokhov  * the interrupt handler.
98181d683dSDmitry Torokhov  */
991da177e4SLinus Torvalds static DEFINE_SPINLOCK(i8042_lock);
1001da177e4SLinus Torvalds 
101181d683dSDmitry Torokhov /*
102181d683dSDmitry Torokhov  * Writers to AUX and KBD ports as well as users issuing i8042_command
103181d683dSDmitry Torokhov  * directly should acquire i8042_mutex (by means of calling
104181d683dSDmitry Torokhov  * i8042_lock_chip() and i8042_unlock_ship() helpers) to ensure that
105181d683dSDmitry Torokhov  * they do not disturb each other (unfortunately in many i8042
106181d683dSDmitry Torokhov  * implementations write to one of the ports will immediately abort
107181d683dSDmitry Torokhov  * command that is being processed by another port).
108181d683dSDmitry Torokhov  */
109181d683dSDmitry Torokhov static DEFINE_MUTEX(i8042_mutex);
110181d683dSDmitry Torokhov 
1111da177e4SLinus Torvalds struct i8042_port {
1121da177e4SLinus Torvalds 	struct serio *serio;
1131da177e4SLinus Torvalds 	int irq;
114386b3849SDmitry Torokhov 	bool exists;
1151da177e4SLinus Torvalds 	signed char mux;
1161da177e4SLinus Torvalds };
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds #define I8042_KBD_PORT_NO	0
1191da177e4SLinus Torvalds #define I8042_AUX_PORT_NO	1
1201da177e4SLinus Torvalds #define I8042_MUX_PORT_NO	2
1211da177e4SLinus Torvalds #define I8042_NUM_PORTS		(I8042_NUM_MUX_PORTS + 2)
122de9ce703SDmitry Torokhov 
123de9ce703SDmitry Torokhov static struct i8042_port i8042_ports[I8042_NUM_PORTS];
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds static unsigned char i8042_initial_ctr;
1261da177e4SLinus Torvalds static unsigned char i8042_ctr;
127386b3849SDmitry Torokhov static bool i8042_mux_present;
128386b3849SDmitry Torokhov static bool i8042_kbd_irq_registered;
129386b3849SDmitry Torokhov static bool i8042_aux_irq_registered;
130817e6ba3SDmitry Torokhov static unsigned char i8042_suppress_kbd_ack;
1311da177e4SLinus Torvalds static struct platform_device *i8042_platform_device;
1321da177e4SLinus Torvalds 
1337d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id);
134967c9ef9SMatthew Garrett static bool (*i8042_platform_filter)(unsigned char data, unsigned char str,
135967c9ef9SMatthew Garrett 				     struct serio *serio);
1361da177e4SLinus Torvalds 
137181d683dSDmitry Torokhov void i8042_lock_chip(void)
138181d683dSDmitry Torokhov {
139181d683dSDmitry Torokhov 	mutex_lock(&i8042_mutex);
140181d683dSDmitry Torokhov }
141181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_lock_chip);
142181d683dSDmitry Torokhov 
143181d683dSDmitry Torokhov void i8042_unlock_chip(void)
144181d683dSDmitry Torokhov {
145181d683dSDmitry Torokhov 	mutex_unlock(&i8042_mutex);
146181d683dSDmitry Torokhov }
147181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_unlock_chip);
148181d683dSDmitry Torokhov 
149967c9ef9SMatthew Garrett int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
150967c9ef9SMatthew Garrett 					struct serio *serio))
151967c9ef9SMatthew Garrett {
152967c9ef9SMatthew Garrett 	unsigned long flags;
153967c9ef9SMatthew Garrett 	int ret = 0;
154967c9ef9SMatthew Garrett 
155967c9ef9SMatthew Garrett 	spin_lock_irqsave(&i8042_lock, flags);
156967c9ef9SMatthew Garrett 
157967c9ef9SMatthew Garrett 	if (i8042_platform_filter) {
158967c9ef9SMatthew Garrett 		ret = -EBUSY;
159967c9ef9SMatthew Garrett 		goto out;
160967c9ef9SMatthew Garrett 	}
161967c9ef9SMatthew Garrett 
162967c9ef9SMatthew Garrett 	i8042_platform_filter = filter;
163967c9ef9SMatthew Garrett 
164967c9ef9SMatthew Garrett out:
165967c9ef9SMatthew Garrett 	spin_unlock_irqrestore(&i8042_lock, flags);
166967c9ef9SMatthew Garrett 	return ret;
167967c9ef9SMatthew Garrett }
168967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_install_filter);
169967c9ef9SMatthew Garrett 
170967c9ef9SMatthew Garrett int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
171967c9ef9SMatthew Garrett 				       struct serio *port))
172967c9ef9SMatthew Garrett {
173967c9ef9SMatthew Garrett 	unsigned long flags;
174967c9ef9SMatthew Garrett 	int ret = 0;
175967c9ef9SMatthew Garrett 
176967c9ef9SMatthew Garrett 	spin_lock_irqsave(&i8042_lock, flags);
177967c9ef9SMatthew Garrett 
178967c9ef9SMatthew Garrett 	if (i8042_platform_filter != filter) {
179967c9ef9SMatthew Garrett 		ret = -EINVAL;
180967c9ef9SMatthew Garrett 		goto out;
181967c9ef9SMatthew Garrett 	}
182967c9ef9SMatthew Garrett 
183967c9ef9SMatthew Garrett 	i8042_platform_filter = NULL;
184967c9ef9SMatthew Garrett 
185967c9ef9SMatthew Garrett out:
186967c9ef9SMatthew Garrett 	spin_unlock_irqrestore(&i8042_lock, flags);
187967c9ef9SMatthew Garrett 	return ret;
188967c9ef9SMatthew Garrett }
189967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_remove_filter);
190967c9ef9SMatthew Garrett 
1911da177e4SLinus Torvalds /*
1921da177e4SLinus Torvalds  * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
1931da177e4SLinus Torvalds  * be ready for reading values from it / writing values to it.
1941da177e4SLinus Torvalds  * Called always with i8042_lock held.
1951da177e4SLinus Torvalds  */
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds static int i8042_wait_read(void)
1981da177e4SLinus Torvalds {
1991da177e4SLinus Torvalds 	int i = 0;
200de9ce703SDmitry Torokhov 
2011da177e4SLinus Torvalds 	while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
2021da177e4SLinus Torvalds 		udelay(50);
2031da177e4SLinus Torvalds 		i++;
2041da177e4SLinus Torvalds 	}
2051da177e4SLinus Torvalds 	return -(i == I8042_CTL_TIMEOUT);
2061da177e4SLinus Torvalds }
2071da177e4SLinus Torvalds 
2081da177e4SLinus Torvalds static int i8042_wait_write(void)
2091da177e4SLinus Torvalds {
2101da177e4SLinus Torvalds 	int i = 0;
211de9ce703SDmitry Torokhov 
2121da177e4SLinus Torvalds 	while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
2131da177e4SLinus Torvalds 		udelay(50);
2141da177e4SLinus Torvalds 		i++;
2151da177e4SLinus Torvalds 	}
2161da177e4SLinus Torvalds 	return -(i == I8042_CTL_TIMEOUT);
2171da177e4SLinus Torvalds }
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds /*
2201da177e4SLinus Torvalds  * i8042_flush() flushes all data that may be in the keyboard and mouse buffers
2211da177e4SLinus Torvalds  * of the i8042 down the toilet.
2221da177e4SLinus Torvalds  */
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds static int i8042_flush(void)
2251da177e4SLinus Torvalds {
2261da177e4SLinus Torvalds 	unsigned long flags;
2271da177e4SLinus Torvalds 	unsigned char data, str;
2282f0d2604SAndrey Moiseev 	int count = 0;
2292f0d2604SAndrey Moiseev 	int retval = 0;
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
2321da177e4SLinus Torvalds 
2332f0d2604SAndrey Moiseev 	while ((str = i8042_read_status()) & I8042_STR_OBF) {
2342f0d2604SAndrey Moiseev 		if (count++ < I8042_BUFFER_SIZE) {
2351da177e4SLinus Torvalds 			udelay(50);
2361da177e4SLinus Torvalds 			data = i8042_read_data();
2374eb3c30bSJoe Perches 			dbg("%02x <- i8042 (flush, %s)\n",
2384eb3c30bSJoe Perches 			    data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
2392f0d2604SAndrey Moiseev 		} else {
2402f0d2604SAndrey Moiseev 			retval = -EIO;
2412f0d2604SAndrey Moiseev 			break;
2422f0d2604SAndrey Moiseev 		}
2431da177e4SLinus Torvalds 	}
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
2461da177e4SLinus Torvalds 
2472f0d2604SAndrey Moiseev 	return retval;
2481da177e4SLinus Torvalds }
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds /*
2511da177e4SLinus Torvalds  * i8042_command() executes a command on the i8042. It also sends the input
2521da177e4SLinus Torvalds  * parameter(s) of the commands to it, and receives the output value(s). The
2531da177e4SLinus Torvalds  * parameters are to be stored in the param array, and the output is placed
2541da177e4SLinus Torvalds  * into the same array. The number of the parameters and output values is
2551da177e4SLinus Torvalds  * encoded in bits 8-11 of the command number.
2561da177e4SLinus Torvalds  */
2571da177e4SLinus Torvalds 
258de9ce703SDmitry Torokhov static int __i8042_command(unsigned char *param, int command)
2591da177e4SLinus Torvalds {
260de9ce703SDmitry Torokhov 	int i, error;
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 	if (i8042_noloop && command == I8042_CMD_AUX_LOOP)
2631da177e4SLinus Torvalds 		return -1;
2641da177e4SLinus Torvalds 
265de9ce703SDmitry Torokhov 	error = i8042_wait_write();
266de9ce703SDmitry Torokhov 	if (error)
267de9ce703SDmitry Torokhov 		return error;
268463a4f76SDmitry Torokhov 
2694eb3c30bSJoe Perches 	dbg("%02x -> i8042 (command)\n", command & 0xff);
2701da177e4SLinus Torvalds 	i8042_write_command(command & 0xff);
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 	for (i = 0; i < ((command >> 12) & 0xf); i++) {
273de9ce703SDmitry Torokhov 		error = i8042_wait_write();
274de9ce703SDmitry Torokhov 		if (error)
275de9ce703SDmitry Torokhov 			return error;
2764eb3c30bSJoe Perches 		dbg("%02x -> i8042 (parameter)\n", param[i]);
2771da177e4SLinus Torvalds 		i8042_write_data(param[i]);
2781da177e4SLinus Torvalds 	}
2791da177e4SLinus Torvalds 
2801da177e4SLinus Torvalds 	for (i = 0; i < ((command >> 8) & 0xf); i++) {
281de9ce703SDmitry Torokhov 		error = i8042_wait_read();
282de9ce703SDmitry Torokhov 		if (error) {
2834eb3c30bSJoe Perches 			dbg("     -- i8042 (timeout)\n");
284de9ce703SDmitry Torokhov 			return error;
285de9ce703SDmitry Torokhov 		}
286463a4f76SDmitry Torokhov 
287463a4f76SDmitry Torokhov 		if (command == I8042_CMD_AUX_LOOP &&
288463a4f76SDmitry Torokhov 		    !(i8042_read_status() & I8042_STR_AUXDATA)) {
2894eb3c30bSJoe Perches 			dbg("     -- i8042 (auxerr)\n");
290de9ce703SDmitry Torokhov 			return -1;
291463a4f76SDmitry Torokhov 		}
292463a4f76SDmitry Torokhov 
2931da177e4SLinus Torvalds 		param[i] = i8042_read_data();
2944eb3c30bSJoe Perches 		dbg("%02x <- i8042 (return)\n", param[i]);
2951da177e4SLinus Torvalds 	}
2961da177e4SLinus Torvalds 
297de9ce703SDmitry Torokhov 	return 0;
298de9ce703SDmitry Torokhov }
2991da177e4SLinus Torvalds 
300553a05b8SMárton Németh int i8042_command(unsigned char *param, int command)
301de9ce703SDmitry Torokhov {
302de9ce703SDmitry Torokhov 	unsigned long flags;
303de9ce703SDmitry Torokhov 	int retval;
304de9ce703SDmitry Torokhov 
305de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
306de9ce703SDmitry Torokhov 	retval = __i8042_command(param, command);
307463a4f76SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
308de9ce703SDmitry Torokhov 
3091da177e4SLinus Torvalds 	return retval;
3101da177e4SLinus Torvalds }
311553a05b8SMárton Németh EXPORT_SYMBOL(i8042_command);
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds /*
3141da177e4SLinus Torvalds  * i8042_kbd_write() sends a byte out through the keyboard interface.
3151da177e4SLinus Torvalds  */
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds static int i8042_kbd_write(struct serio *port, unsigned char c)
3181da177e4SLinus Torvalds {
3191da177e4SLinus Torvalds 	unsigned long flags;
3201da177e4SLinus Torvalds 	int retval = 0;
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds 	if (!(retval = i8042_wait_write())) {
3254eb3c30bSJoe Perches 		dbg("%02x -> i8042 (kbd-data)\n", c);
3261da177e4SLinus Torvalds 		i8042_write_data(c);
3271da177e4SLinus Torvalds 	}
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds 	return retval;
3321da177e4SLinus Torvalds }
3331da177e4SLinus Torvalds 
3341da177e4SLinus Torvalds /*
3351da177e4SLinus Torvalds  * i8042_aux_write() sends a byte out through the aux interface.
3361da177e4SLinus Torvalds  */
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds static int i8042_aux_write(struct serio *serio, unsigned char c)
3391da177e4SLinus Torvalds {
3401da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
3411da177e4SLinus Torvalds 
342f4e3c711SDmitry Torokhov 	return i8042_command(&c, port->mux == -1 ?
343f4e3c711SDmitry Torokhov 					I8042_CMD_AUX_SEND :
344f4e3c711SDmitry Torokhov 					I8042_CMD_MUX_SEND + port->mux);
3451da177e4SLinus Torvalds }
3461da177e4SLinus Torvalds 
3475ddbc77cSDmitry Torokhov 
3485ddbc77cSDmitry Torokhov /*
3495ddbc77cSDmitry Torokhov  * i8042_aux_close attempts to clear AUX or KBD port state by disabling
3505ddbc77cSDmitry Torokhov  * and then re-enabling it.
3515ddbc77cSDmitry Torokhov  */
3525ddbc77cSDmitry Torokhov 
3535ddbc77cSDmitry Torokhov static void i8042_port_close(struct serio *serio)
3545ddbc77cSDmitry Torokhov {
3555ddbc77cSDmitry Torokhov 	int irq_bit;
3565ddbc77cSDmitry Torokhov 	int disable_bit;
3575ddbc77cSDmitry Torokhov 	const char *port_name;
3585ddbc77cSDmitry Torokhov 
3595ddbc77cSDmitry Torokhov 	if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) {
3605ddbc77cSDmitry Torokhov 		irq_bit = I8042_CTR_AUXINT;
3615ddbc77cSDmitry Torokhov 		disable_bit = I8042_CTR_AUXDIS;
3625ddbc77cSDmitry Torokhov 		port_name = "AUX";
3635ddbc77cSDmitry Torokhov 	} else {
3645ddbc77cSDmitry Torokhov 		irq_bit = I8042_CTR_KBDINT;
3655ddbc77cSDmitry Torokhov 		disable_bit = I8042_CTR_KBDDIS;
3665ddbc77cSDmitry Torokhov 		port_name = "KBD";
3675ddbc77cSDmitry Torokhov 	}
3685ddbc77cSDmitry Torokhov 
3695ddbc77cSDmitry Torokhov 	i8042_ctr &= ~irq_bit;
3705ddbc77cSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
3714eb3c30bSJoe Perches 		pr_warn("Can't write CTR while closing %s port\n", port_name);
3725ddbc77cSDmitry Torokhov 
3735ddbc77cSDmitry Torokhov 	udelay(50);
3745ddbc77cSDmitry Torokhov 
3755ddbc77cSDmitry Torokhov 	i8042_ctr &= ~disable_bit;
3765ddbc77cSDmitry Torokhov 	i8042_ctr |= irq_bit;
3775ddbc77cSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
3784eb3c30bSJoe Perches 		pr_err("Can't reactivate %s port\n", port_name);
3795ddbc77cSDmitry Torokhov 
3805ddbc77cSDmitry Torokhov 	/*
3815ddbc77cSDmitry Torokhov 	 * See if there is any data appeared while we were messing with
3825ddbc77cSDmitry Torokhov 	 * port state.
3835ddbc77cSDmitry Torokhov 	 */
3845ddbc77cSDmitry Torokhov 	i8042_interrupt(0, NULL);
3855ddbc77cSDmitry Torokhov }
3865ddbc77cSDmitry Torokhov 
3871da177e4SLinus Torvalds /*
3881da177e4SLinus Torvalds  * i8042_start() is called by serio core when port is about to finish
3891da177e4SLinus Torvalds  * registering. It will mark port as existing so i8042_interrupt can
3901da177e4SLinus Torvalds  * start sending data through it.
3911da177e4SLinus Torvalds  */
3921da177e4SLinus Torvalds static int i8042_start(struct serio *serio)
3931da177e4SLinus Torvalds {
3941da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
3951da177e4SLinus Torvalds 
396386b3849SDmitry Torokhov 	port->exists = true;
3971da177e4SLinus Torvalds 	mb();
3981da177e4SLinus Torvalds 	return 0;
3991da177e4SLinus Torvalds }
4001da177e4SLinus Torvalds 
4011da177e4SLinus Torvalds /*
4021da177e4SLinus Torvalds  * i8042_stop() marks serio port as non-existing so i8042_interrupt
4031da177e4SLinus Torvalds  * will not try to send data to the port that is about to go away.
4041da177e4SLinus Torvalds  * The function is called by serio core as part of unregister procedure.
4051da177e4SLinus Torvalds  */
4061da177e4SLinus Torvalds static void i8042_stop(struct serio *serio)
4071da177e4SLinus Torvalds {
4081da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
4091da177e4SLinus Torvalds 
410386b3849SDmitry Torokhov 	port->exists = false;
411a8399c51SDmitry Torokhov 
412a8399c51SDmitry Torokhov 	/*
413a8399c51SDmitry Torokhov 	 * We synchronize with both AUX and KBD IRQs because there is
414a8399c51SDmitry Torokhov 	 * a (very unlikely) chance that AUX IRQ is raised for KBD port
415a8399c51SDmitry Torokhov 	 * and vice versa.
416a8399c51SDmitry Torokhov 	 */
417a8399c51SDmitry Torokhov 	synchronize_irq(I8042_AUX_IRQ);
418a8399c51SDmitry Torokhov 	synchronize_irq(I8042_KBD_IRQ);
4191da177e4SLinus Torvalds 	port->serio = NULL;
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds /*
4234e8d340dSDmitry Torokhov  * i8042_filter() filters out unwanted bytes from the input data stream.
4244e8d340dSDmitry Torokhov  * It is called from i8042_interrupt and thus is running with interrupts
4254e8d340dSDmitry Torokhov  * off and i8042_lock held.
4264e8d340dSDmitry Torokhov  */
427967c9ef9SMatthew Garrett static bool i8042_filter(unsigned char data, unsigned char str,
428967c9ef9SMatthew Garrett 			 struct serio *serio)
4294e8d340dSDmitry Torokhov {
4304e8d340dSDmitry Torokhov 	if (unlikely(i8042_suppress_kbd_ack)) {
4314e8d340dSDmitry Torokhov 		if ((~str & I8042_STR_AUXDATA) &&
4324e8d340dSDmitry Torokhov 		    (data == 0xfa || data == 0xfe)) {
4334e8d340dSDmitry Torokhov 			i8042_suppress_kbd_ack--;
4344e8d340dSDmitry Torokhov 			dbg("Extra keyboard ACK - filtered out\n");
4354e8d340dSDmitry Torokhov 			return true;
4364e8d340dSDmitry Torokhov 		}
4374e8d340dSDmitry Torokhov 	}
4384e8d340dSDmitry Torokhov 
439967c9ef9SMatthew Garrett 	if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) {
4400747e3bcSStefan Weil 		dbg("Filtered out by platform filter\n");
441967c9ef9SMatthew Garrett 		return true;
442967c9ef9SMatthew Garrett 	}
443967c9ef9SMatthew Garrett 
4444e8d340dSDmitry Torokhov 	return false;
4454e8d340dSDmitry Torokhov }
4464e8d340dSDmitry Torokhov 
4474e8d340dSDmitry Torokhov /*
4481da177e4SLinus Torvalds  * i8042_interrupt() is the most important function in this driver -
4491da177e4SLinus Torvalds  * it handles the interrupts from the i8042, and sends incoming bytes
4501da177e4SLinus Torvalds  * to the upper layers.
4511da177e4SLinus Torvalds  */
4521da177e4SLinus Torvalds 
4537d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id)
4541da177e4SLinus Torvalds {
4551da177e4SLinus Torvalds 	struct i8042_port *port;
456967c9ef9SMatthew Garrett 	struct serio *serio;
4571da177e4SLinus Torvalds 	unsigned long flags;
4581da177e4SLinus Torvalds 	unsigned char str, data;
4591da177e4SLinus Torvalds 	unsigned int dfl;
4601da177e4SLinus Torvalds 	unsigned int port_no;
4614e8d340dSDmitry Torokhov 	bool filtered;
462817e6ba3SDmitry Torokhov 	int ret = 1;
4631da177e4SLinus Torvalds 
4641da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
4654e8d340dSDmitry Torokhov 
4661da177e4SLinus Torvalds 	str = i8042_read_status();
4671da177e4SLinus Torvalds 	if (unlikely(~str & I8042_STR_OBF)) {
4681da177e4SLinus Torvalds 		spin_unlock_irqrestore(&i8042_lock, flags);
4694eb3c30bSJoe Perches 		if (irq)
4704eb3c30bSJoe Perches 			dbg("Interrupt %d, without any data\n", irq);
4711da177e4SLinus Torvalds 		ret = 0;
4721da177e4SLinus Torvalds 		goto out;
4731da177e4SLinus Torvalds 	}
4744e8d340dSDmitry Torokhov 
4751da177e4SLinus Torvalds 	data = i8042_read_data();
4761da177e4SLinus Torvalds 
4771da177e4SLinus Torvalds 	if (i8042_mux_present && (str & I8042_STR_AUXDATA)) {
4781da177e4SLinus Torvalds 		static unsigned long last_transmit;
4791da177e4SLinus Torvalds 		static unsigned char last_str;
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds 		dfl = 0;
4821da177e4SLinus Torvalds 		if (str & I8042_STR_MUXERR) {
4834eb3c30bSJoe Perches 			dbg("MUX error, status is %02x, data is %02x\n",
4844eb3c30bSJoe Perches 			    str, data);
4851da177e4SLinus Torvalds /*
4861da177e4SLinus Torvalds  * When MUXERR condition is signalled the data register can only contain
4871da177e4SLinus Torvalds  * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately
488a216a4b6SDmitry Torokhov  * it is not always the case. Some KBCs also report 0xfc when there is
489a216a4b6SDmitry Torokhov  * nothing connected to the port while others sometimes get confused which
490a216a4b6SDmitry Torokhov  * port the data came from and signal error leaving the data intact. They
491a216a4b6SDmitry Torokhov  * _do not_ revert to legacy mode (actually I've never seen KBC reverting
492a216a4b6SDmitry Torokhov  * to legacy mode yet, when we see one we'll add proper handling).
493a216a4b6SDmitry Torokhov  * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the
494a216a4b6SDmitry Torokhov  * rest assume that the data came from the same serio last byte
4951da177e4SLinus Torvalds  * was transmitted (if transmission happened not too long ago).
4961da177e4SLinus Torvalds  */
497a216a4b6SDmitry Torokhov 
498a216a4b6SDmitry Torokhov 			switch (data) {
499a216a4b6SDmitry Torokhov 				default:
5001da177e4SLinus Torvalds 					if (time_before(jiffies, last_transmit + HZ/10)) {
5011da177e4SLinus Torvalds 						str = last_str;
5021da177e4SLinus Torvalds 						break;
5031da177e4SLinus Torvalds 					}
5041da177e4SLinus Torvalds 					/* fall through - report timeout */
505a216a4b6SDmitry Torokhov 				case 0xfc:
5061da177e4SLinus Torvalds 				case 0xfd:
5071da177e4SLinus Torvalds 				case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break;
5081da177e4SLinus Torvalds 				case 0xff: dfl = SERIO_PARITY;  data = 0xfe; break;
5091da177e4SLinus Torvalds 			}
5101da177e4SLinus Torvalds 		}
5111da177e4SLinus Torvalds 
5121da177e4SLinus Torvalds 		port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3);
5131da177e4SLinus Torvalds 		last_str = str;
5141da177e4SLinus Torvalds 		last_transmit = jiffies;
5151da177e4SLinus Torvalds 	} else {
5161da177e4SLinus Torvalds 
5171da177e4SLinus Torvalds 		dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
518f8313ef1SJiri Kosina 		      ((str & I8042_STR_TIMEOUT && !i8042_notimeout) ? SERIO_TIMEOUT : 0);
5191da177e4SLinus Torvalds 
5201da177e4SLinus Torvalds 		port_no = (str & I8042_STR_AUXDATA) ?
5211da177e4SLinus Torvalds 				I8042_AUX_PORT_NO : I8042_KBD_PORT_NO;
5221da177e4SLinus Torvalds 	}
5231da177e4SLinus Torvalds 
5241da177e4SLinus Torvalds 	port = &i8042_ports[port_no];
525967c9ef9SMatthew Garrett 	serio = port->exists ? port->serio : NULL;
5261da177e4SLinus Torvalds 
5274eb3c30bSJoe Perches 	dbg("%02x <- i8042 (interrupt, %d, %d%s%s)\n",
528de9ce703SDmitry Torokhov 	    data, port_no, irq,
5291da177e4SLinus Torvalds 	    dfl & SERIO_PARITY ? ", bad parity" : "",
5301da177e4SLinus Torvalds 	    dfl & SERIO_TIMEOUT ? ", timeout" : "");
5311da177e4SLinus Torvalds 
532967c9ef9SMatthew Garrett 	filtered = i8042_filter(data, str, serio);
533817e6ba3SDmitry Torokhov 
5344e8d340dSDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
5354e8d340dSDmitry Torokhov 
5364e8d340dSDmitry Torokhov 	if (likely(port->exists && !filtered))
537967c9ef9SMatthew Garrett 		serio_interrupt(serio, data, dfl);
5381da177e4SLinus Torvalds 
5391da177e4SLinus Torvalds  out:
5401da177e4SLinus Torvalds 	return IRQ_RETVAL(ret);
5411da177e4SLinus Torvalds }
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds /*
5445ddbc77cSDmitry Torokhov  * i8042_enable_kbd_port enables keyboard port on chip
545de9ce703SDmitry Torokhov  */
546de9ce703SDmitry Torokhov 
547de9ce703SDmitry Torokhov static int i8042_enable_kbd_port(void)
548de9ce703SDmitry Torokhov {
549de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_KBDDIS;
550de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_KBDINT;
551de9ce703SDmitry Torokhov 
552de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
553018db6bbSMarkus Armbruster 		i8042_ctr &= ~I8042_CTR_KBDINT;
554018db6bbSMarkus Armbruster 		i8042_ctr |= I8042_CTR_KBDDIS;
5554eb3c30bSJoe Perches 		pr_err("Failed to enable KBD port\n");
556de9ce703SDmitry Torokhov 		return -EIO;
557de9ce703SDmitry Torokhov 	}
558de9ce703SDmitry Torokhov 
559de9ce703SDmitry Torokhov 	return 0;
560de9ce703SDmitry Torokhov }
561de9ce703SDmitry Torokhov 
562de9ce703SDmitry Torokhov /*
563de9ce703SDmitry Torokhov  * i8042_enable_aux_port enables AUX (mouse) port on chip
564de9ce703SDmitry Torokhov  */
565de9ce703SDmitry Torokhov 
566de9ce703SDmitry Torokhov static int i8042_enable_aux_port(void)
567de9ce703SDmitry Torokhov {
568de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_AUXDIS;
569de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXINT;
570de9ce703SDmitry Torokhov 
571de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
572018db6bbSMarkus Armbruster 		i8042_ctr &= ~I8042_CTR_AUXINT;
573018db6bbSMarkus Armbruster 		i8042_ctr |= I8042_CTR_AUXDIS;
5744eb3c30bSJoe Perches 		pr_err("Failed to enable AUX port\n");
575de9ce703SDmitry Torokhov 		return -EIO;
576de9ce703SDmitry Torokhov 	}
577de9ce703SDmitry Torokhov 
578de9ce703SDmitry Torokhov 	return 0;
579de9ce703SDmitry Torokhov }
580de9ce703SDmitry Torokhov 
581de9ce703SDmitry Torokhov /*
582de9ce703SDmitry Torokhov  * i8042_enable_mux_ports enables 4 individual AUX ports after
583de9ce703SDmitry Torokhov  * the controller has been switched into Multiplexed mode
584de9ce703SDmitry Torokhov  */
585de9ce703SDmitry Torokhov 
586de9ce703SDmitry Torokhov static int i8042_enable_mux_ports(void)
587de9ce703SDmitry Torokhov {
588de9ce703SDmitry Torokhov 	unsigned char param;
589de9ce703SDmitry Torokhov 	int i;
590de9ce703SDmitry Torokhov 
591de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
592de9ce703SDmitry Torokhov 		i8042_command(&param, I8042_CMD_MUX_PFX + i);
593de9ce703SDmitry Torokhov 		i8042_command(&param, I8042_CMD_AUX_ENABLE);
594de9ce703SDmitry Torokhov 	}
595de9ce703SDmitry Torokhov 
596de9ce703SDmitry Torokhov 	return i8042_enable_aux_port();
597de9ce703SDmitry Torokhov }
598de9ce703SDmitry Torokhov 
599de9ce703SDmitry Torokhov /*
600386b3849SDmitry Torokhov  * i8042_set_mux_mode checks whether the controller has an
601386b3849SDmitry Torokhov  * active multiplexor and puts the chip into Multiplexed (true)
602386b3849SDmitry Torokhov  * or Legacy (false) mode.
6031da177e4SLinus Torvalds  */
6041da177e4SLinus Torvalds 
605386b3849SDmitry Torokhov static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version)
6061da177e4SLinus Torvalds {
6071da177e4SLinus Torvalds 
608386b3849SDmitry Torokhov 	unsigned char param, val;
6091da177e4SLinus Torvalds /*
6101da177e4SLinus Torvalds  * Get rid of bytes in the queue.
6111da177e4SLinus Torvalds  */
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds 	i8042_flush();
6141da177e4SLinus Torvalds 
6151da177e4SLinus Torvalds /*
6161da177e4SLinus Torvalds  * Internal loopback test - send three bytes, they should come back from the
617de9ce703SDmitry Torokhov  * mouse interface, the last should be version.
6181da177e4SLinus Torvalds  */
6191da177e4SLinus Torvalds 
620386b3849SDmitry Torokhov 	param = val = 0xf0;
621386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != val)
6221da177e4SLinus Torvalds 		return -1;
623386b3849SDmitry Torokhov 	param = val = multiplex ? 0x56 : 0xf6;
624386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != val)
6251da177e4SLinus Torvalds 		return -1;
626386b3849SDmitry Torokhov 	param = val = multiplex ? 0xa4 : 0xa5;
627386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == val)
628386b3849SDmitry Torokhov 		return -1;
629386b3849SDmitry Torokhov 
630386b3849SDmitry Torokhov /*
631386b3849SDmitry Torokhov  * Workaround for interference with USB Legacy emulation
632386b3849SDmitry Torokhov  * that causes a v10.12 MUX to be found.
633386b3849SDmitry Torokhov  */
634386b3849SDmitry Torokhov 	if (param == 0xac)
6351da177e4SLinus Torvalds 		return -1;
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds 	if (mux_version)
638463a4f76SDmitry Torokhov 		*mux_version = param;
6391da177e4SLinus Torvalds 
6401da177e4SLinus Torvalds 	return 0;
6411da177e4SLinus Torvalds }
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds /*
6441da177e4SLinus Torvalds  * i8042_check_mux() checks whether the controller supports the PS/2 Active
6451da177e4SLinus Torvalds  * Multiplexing specification by Synaptics, Phoenix, Insyde and
6461da177e4SLinus Torvalds  * LCS/Telegraphics.
6471da177e4SLinus Torvalds  */
6481da177e4SLinus Torvalds 
649f8113416SDmitry Torokhov static int __init i8042_check_mux(void)
6501da177e4SLinus Torvalds {
6511da177e4SLinus Torvalds 	unsigned char mux_version;
6521da177e4SLinus Torvalds 
653386b3849SDmitry Torokhov 	if (i8042_set_mux_mode(true, &mux_version))
6541da177e4SLinus Torvalds 		return -1;
6551da177e4SLinus Torvalds 
6564eb3c30bSJoe Perches 	pr_info("Detected active multiplexing controller, rev %d.%d\n",
6571da177e4SLinus Torvalds 		(mux_version >> 4) & 0xf, mux_version & 0xf);
6581da177e4SLinus Torvalds 
659de9ce703SDmitry Torokhov /*
660de9ce703SDmitry Torokhov  * Disable all muxed ports by disabling AUX.
661de9ce703SDmitry Torokhov  */
662de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXDIS;
663de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_AUXINT;
664de9ce703SDmitry Torokhov 
665de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
6664eb3c30bSJoe Perches 		pr_err("Failed to disable AUX port, can't use MUX\n");
667de9ce703SDmitry Torokhov 		return -EIO;
668de9ce703SDmitry Torokhov 	}
6691da177e4SLinus Torvalds 
670386b3849SDmitry Torokhov 	i8042_mux_present = true;
671de9ce703SDmitry Torokhov 
6721da177e4SLinus Torvalds 	return 0;
6731da177e4SLinus Torvalds }
6741da177e4SLinus Torvalds 
675de9ce703SDmitry Torokhov /*
676de9ce703SDmitry Torokhov  * The following is used to test AUX IRQ delivery.
677de9ce703SDmitry Torokhov  */
678f8113416SDmitry Torokhov static struct completion i8042_aux_irq_delivered __initdata;
679f8113416SDmitry Torokhov static bool i8042_irq_being_tested __initdata;
680de9ce703SDmitry Torokhov 
681f8113416SDmitry Torokhov static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id)
682de9ce703SDmitry Torokhov {
683de9ce703SDmitry Torokhov 	unsigned long flags;
684de9ce703SDmitry Torokhov 	unsigned char str, data;
685e3758b2aSFernando Luis Vázquez Cao 	int ret = 0;
686de9ce703SDmitry Torokhov 
687de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
688de9ce703SDmitry Torokhov 	str = i8042_read_status();
689de9ce703SDmitry Torokhov 	if (str & I8042_STR_OBF) {
690de9ce703SDmitry Torokhov 		data = i8042_read_data();
6914eb3c30bSJoe Perches 		dbg("%02x <- i8042 (aux_test_irq, %s)\n",
692d3d2dfe2SDmitry Torokhov 		    data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
693de9ce703SDmitry Torokhov 		if (i8042_irq_being_tested &&
694de9ce703SDmitry Torokhov 		    data == 0xa5 && (str & I8042_STR_AUXDATA))
695de9ce703SDmitry Torokhov 			complete(&i8042_aux_irq_delivered);
696e3758b2aSFernando Luis Vázquez Cao 		ret = 1;
697de9ce703SDmitry Torokhov 	}
698de9ce703SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
699de9ce703SDmitry Torokhov 
700e3758b2aSFernando Luis Vázquez Cao 	return IRQ_RETVAL(ret);
701de9ce703SDmitry Torokhov }
702de9ce703SDmitry Torokhov 
703d2ada559SRoland Scheidegger /*
704d2ada559SRoland Scheidegger  * i8042_toggle_aux - enables or disables AUX port on i8042 via command and
705d2ada559SRoland Scheidegger  * verifies success by readinng CTR. Used when testing for presence of AUX
706d2ada559SRoland Scheidegger  * port.
707d2ada559SRoland Scheidegger  */
708f8113416SDmitry Torokhov static int __init i8042_toggle_aux(bool on)
709d2ada559SRoland Scheidegger {
710d2ada559SRoland Scheidegger 	unsigned char param;
711d2ada559SRoland Scheidegger 	int i;
712d2ada559SRoland Scheidegger 
713d2ada559SRoland Scheidegger 	if (i8042_command(&param,
714d2ada559SRoland Scheidegger 			on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE))
715d2ada559SRoland Scheidegger 		return -1;
716d2ada559SRoland Scheidegger 
717d2ada559SRoland Scheidegger 	/* some chips need some time to set the I8042_CTR_AUXDIS bit */
718d2ada559SRoland Scheidegger 	for (i = 0; i < 100; i++) {
719d2ada559SRoland Scheidegger 		udelay(50);
720d2ada559SRoland Scheidegger 
721d2ada559SRoland Scheidegger 		if (i8042_command(&param, I8042_CMD_CTL_RCTR))
722d2ada559SRoland Scheidegger 			return -1;
723d2ada559SRoland Scheidegger 
724d2ada559SRoland Scheidegger 		if (!(param & I8042_CTR_AUXDIS) == on)
725d2ada559SRoland Scheidegger 			return 0;
726d2ada559SRoland Scheidegger 	}
727d2ada559SRoland Scheidegger 
728d2ada559SRoland Scheidegger 	return -1;
729d2ada559SRoland Scheidegger }
7301da177e4SLinus Torvalds 
7311da177e4SLinus Torvalds /*
7321da177e4SLinus Torvalds  * i8042_check_aux() applies as much paranoia as it can at detecting
7331da177e4SLinus Torvalds  * the presence of an AUX interface.
7341da177e4SLinus Torvalds  */
7351da177e4SLinus Torvalds 
736f8113416SDmitry Torokhov static int __init i8042_check_aux(void)
7371da177e4SLinus Torvalds {
738de9ce703SDmitry Torokhov 	int retval = -1;
739386b3849SDmitry Torokhov 	bool irq_registered = false;
740386b3849SDmitry Torokhov 	bool aux_loop_broken = false;
741de9ce703SDmitry Torokhov 	unsigned long flags;
7421da177e4SLinus Torvalds 	unsigned char param;
7431da177e4SLinus Torvalds 
7441da177e4SLinus Torvalds /*
7451da177e4SLinus Torvalds  * Get rid of bytes in the queue.
7461da177e4SLinus Torvalds  */
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds 	i8042_flush();
7491da177e4SLinus Torvalds 
7501da177e4SLinus Torvalds /*
7511da177e4SLinus Torvalds  * Internal loopback test - filters out AT-type i8042's. Unfortunately
7521da177e4SLinus Torvalds  * SiS screwed up and their 5597 doesn't support the LOOP command even
7531da177e4SLinus Torvalds  * though it has an AUX port.
7541da177e4SLinus Torvalds  */
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds 	param = 0x5a;
7573ca5de6dSDmitry Torokhov 	retval = i8042_command(&param, I8042_CMD_AUX_LOOP);
7583ca5de6dSDmitry Torokhov 	if (retval || param != 0x5a) {
7591da177e4SLinus Torvalds 
7601da177e4SLinus Torvalds /*
7611da177e4SLinus Torvalds  * External connection test - filters out AT-soldered PS/2 i8042's
7621da177e4SLinus Torvalds  * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error
7631da177e4SLinus Torvalds  * 0xfa - no error on some notebooks which ignore the spec
7641da177e4SLinus Torvalds  * Because it's common for chipsets to return error on perfectly functioning
7651da177e4SLinus Torvalds  * AUX ports, we test for this only when the LOOP command failed.
7661da177e4SLinus Torvalds  */
7671da177e4SLinus Torvalds 
768de9ce703SDmitry Torokhov 		if (i8042_command(&param, I8042_CMD_AUX_TEST) ||
769de9ce703SDmitry Torokhov 		    (param && param != 0xfa && param != 0xff))
7701da177e4SLinus Torvalds 			return -1;
7711e4865f8SDmitry Torokhov 
7723ca5de6dSDmitry Torokhov /*
7733ca5de6dSDmitry Torokhov  * If AUX_LOOP completed without error but returned unexpected data
7743ca5de6dSDmitry Torokhov  * mark it as broken
7753ca5de6dSDmitry Torokhov  */
7763ca5de6dSDmitry Torokhov 		if (!retval)
777386b3849SDmitry Torokhov 			aux_loop_broken = true;
7781da177e4SLinus Torvalds 	}
7791da177e4SLinus Torvalds 
7801da177e4SLinus Torvalds /*
7811da177e4SLinus Torvalds  * Bit assignment test - filters out PS/2 i8042's in AT mode
7821da177e4SLinus Torvalds  */
7831da177e4SLinus Torvalds 
784386b3849SDmitry Torokhov 	if (i8042_toggle_aux(false)) {
7854eb3c30bSJoe Perches 		pr_warn("Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");
7864eb3c30bSJoe Perches 		pr_warn("If AUX port is really absent please use the 'i8042.noaux' option\n");
7871da177e4SLinus Torvalds 	}
7881da177e4SLinus Torvalds 
789386b3849SDmitry Torokhov 	if (i8042_toggle_aux(true))
7901da177e4SLinus Torvalds 		return -1;
7911da177e4SLinus Torvalds 
7921da177e4SLinus Torvalds /*
793de9ce703SDmitry Torokhov  * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and
794de9ce703SDmitry Torokhov  * used it for a PCI card or somethig else.
795de9ce703SDmitry Torokhov  */
796de9ce703SDmitry Torokhov 
7971c7827aeSDmitry Torokhov 	if (i8042_noloop || i8042_bypass_aux_irq_test || aux_loop_broken) {
798de9ce703SDmitry Torokhov /*
799de9ce703SDmitry Torokhov  * Without LOOP command we can't test AUX IRQ delivery. Assume the port
800de9ce703SDmitry Torokhov  * is working and hope we are right.
801de9ce703SDmitry Torokhov  */
802de9ce703SDmitry Torokhov 		retval = 0;
803de9ce703SDmitry Torokhov 		goto out;
804de9ce703SDmitry Torokhov 	}
805de9ce703SDmitry Torokhov 
806de9ce703SDmitry Torokhov 	if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED,
807de9ce703SDmitry Torokhov 			"i8042", i8042_platform_device))
808de9ce703SDmitry Torokhov 		goto out;
809de9ce703SDmitry Torokhov 
810386b3849SDmitry Torokhov 	irq_registered = true;
811de9ce703SDmitry Torokhov 
812de9ce703SDmitry Torokhov 	if (i8042_enable_aux_port())
813de9ce703SDmitry Torokhov 		goto out;
814de9ce703SDmitry Torokhov 
815de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
816de9ce703SDmitry Torokhov 
817de9ce703SDmitry Torokhov 	init_completion(&i8042_aux_irq_delivered);
818386b3849SDmitry Torokhov 	i8042_irq_being_tested = true;
819de9ce703SDmitry Torokhov 
820de9ce703SDmitry Torokhov 	param = 0xa5;
821de9ce703SDmitry Torokhov 	retval = __i8042_command(&param, I8042_CMD_AUX_LOOP & 0xf0ff);
822de9ce703SDmitry Torokhov 
823de9ce703SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
824de9ce703SDmitry Torokhov 
825de9ce703SDmitry Torokhov 	if (retval)
826de9ce703SDmitry Torokhov 		goto out;
827de9ce703SDmitry Torokhov 
828de9ce703SDmitry Torokhov 	if (wait_for_completion_timeout(&i8042_aux_irq_delivered,
829de9ce703SDmitry Torokhov 					msecs_to_jiffies(250)) == 0) {
830de9ce703SDmitry Torokhov /*
831de9ce703SDmitry Torokhov  * AUX IRQ was never delivered so we need to flush the controller to
832de9ce703SDmitry Torokhov  * get rid of the byte we put there; otherwise keyboard may not work.
833de9ce703SDmitry Torokhov  */
8344eb3c30bSJoe Perches 		dbg("     -- i8042 (aux irq test timeout)\n");
835de9ce703SDmitry Torokhov 		i8042_flush();
836de9ce703SDmitry Torokhov 		retval = -1;
837de9ce703SDmitry Torokhov 	}
838de9ce703SDmitry Torokhov 
839de9ce703SDmitry Torokhov  out:
840de9ce703SDmitry Torokhov 
841de9ce703SDmitry Torokhov /*
8421da177e4SLinus Torvalds  * Disable the interface.
8431da177e4SLinus Torvalds  */
8441da177e4SLinus Torvalds 
8451da177e4SLinus Torvalds 	i8042_ctr |= I8042_CTR_AUXDIS;
8461da177e4SLinus Torvalds 	i8042_ctr &= ~I8042_CTR_AUXINT;
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
849de9ce703SDmitry Torokhov 		retval = -1;
850de9ce703SDmitry Torokhov 
851de9ce703SDmitry Torokhov 	if (irq_registered)
852de9ce703SDmitry Torokhov 		free_irq(I8042_AUX_IRQ, i8042_platform_device);
853de9ce703SDmitry Torokhov 
854de9ce703SDmitry Torokhov 	return retval;
855de9ce703SDmitry Torokhov }
856de9ce703SDmitry Torokhov 
857de9ce703SDmitry Torokhov static int i8042_controller_check(void)
858de9ce703SDmitry Torokhov {
8592f0d2604SAndrey Moiseev 	if (i8042_flush()) {
8604eb3c30bSJoe Perches 		pr_err("No controller found\n");
861de9ce703SDmitry Torokhov 		return -ENODEV;
862de9ce703SDmitry Torokhov 	}
8631da177e4SLinus Torvalds 
8641da177e4SLinus Torvalds 	return 0;
8651da177e4SLinus Torvalds }
8661da177e4SLinus Torvalds 
867de9ce703SDmitry Torokhov static int i8042_controller_selftest(void)
8682673c836SVojtech Pavlik {
8692673c836SVojtech Pavlik 	unsigned char param;
8705ea2fc64SArjan van de Ven 	int i = 0;
8712673c836SVojtech Pavlik 
8725ea2fc64SArjan van de Ven 	/*
8735ea2fc64SArjan van de Ven 	 * We try this 5 times; on some really fragile systems this does not
8745ea2fc64SArjan van de Ven 	 * take the first time...
8755ea2fc64SArjan van de Ven 	 */
8765ea2fc64SArjan van de Ven 	do {
8775ea2fc64SArjan van de Ven 
8782673c836SVojtech Pavlik 		if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
8794eb3c30bSJoe Perches 			pr_err("i8042 controller selftest timeout\n");
880de9ce703SDmitry Torokhov 			return -ENODEV;
8812673c836SVojtech Pavlik 		}
8822673c836SVojtech Pavlik 
8835ea2fc64SArjan van de Ven 		if (param == I8042_RET_CTL_TEST)
8845ea2fc64SArjan van de Ven 			return 0;
8855ea2fc64SArjan van de Ven 
886a2a94e73SPaul Bolle 		dbg("i8042 controller selftest: %#x != %#x\n",
8872673c836SVojtech Pavlik 		    param, I8042_RET_CTL_TEST);
8885ea2fc64SArjan van de Ven 		msleep(50);
8895ea2fc64SArjan van de Ven 	} while (i++ < 5);
8902673c836SVojtech Pavlik 
8915ea2fc64SArjan van de Ven #ifdef CONFIG_X86
8925ea2fc64SArjan van de Ven 	/*
8935ea2fc64SArjan van de Ven 	 * On x86, we don't fail entire i8042 initialization if controller
8945ea2fc64SArjan van de Ven 	 * reset fails in hopes that keyboard port will still be functional
8955ea2fc64SArjan van de Ven 	 * and user will still get a working keyboard. This is especially
8965ea2fc64SArjan van de Ven 	 * important on netbooks. On other arches we trust hardware more.
8975ea2fc64SArjan van de Ven 	 */
8984eb3c30bSJoe Perches 	pr_info("giving up on controller selftest, continuing anyway...\n");
8992673c836SVojtech Pavlik 	return 0;
9005ea2fc64SArjan van de Ven #else
901a2a94e73SPaul Bolle 	pr_err("i8042 controller selftest failed\n");
9025ea2fc64SArjan van de Ven 	return -EIO;
9035ea2fc64SArjan van de Ven #endif
9042673c836SVojtech Pavlik }
9051da177e4SLinus Torvalds 
9061da177e4SLinus Torvalds /*
9071da177e4SLinus Torvalds  * i8042_controller init initializes the i8042 controller, and,
9081da177e4SLinus Torvalds  * most importantly, sets it into non-xlated mode if that's
9091da177e4SLinus Torvalds  * desired.
9101da177e4SLinus Torvalds  */
9111da177e4SLinus Torvalds 
9121da177e4SLinus Torvalds static int i8042_controller_init(void)
9131da177e4SLinus Torvalds {
9141da177e4SLinus Torvalds 	unsigned long flags;
915ee1e82ceSDmitry Torokhov 	int n = 0;
916ee1e82ceSDmitry Torokhov 	unsigned char ctr[2];
9171da177e4SLinus Torvalds 
9181da177e4SLinus Torvalds /*
919ee1e82ceSDmitry Torokhov  * Save the CTR for restore on unload / reboot.
9201da177e4SLinus Torvalds  */
9211da177e4SLinus Torvalds 
922ee1e82ceSDmitry Torokhov 	do {
923ee1e82ceSDmitry Torokhov 		if (n >= 10) {
9244eb3c30bSJoe Perches 			pr_err("Unable to get stable CTR read\n");
925de9ce703SDmitry Torokhov 			return -EIO;
9261da177e4SLinus Torvalds 		}
9271da177e4SLinus Torvalds 
928ee1e82ceSDmitry Torokhov 		if (n != 0)
929ee1e82ceSDmitry Torokhov 			udelay(50);
930ee1e82ceSDmitry Torokhov 
931ee1e82ceSDmitry Torokhov 		if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) {
9324eb3c30bSJoe Perches 			pr_err("Can't read CTR while initializing i8042\n");
933ee1e82ceSDmitry Torokhov 			return -EIO;
934ee1e82ceSDmitry Torokhov 		}
935ee1e82ceSDmitry Torokhov 
936ee1e82ceSDmitry Torokhov 	} while (n < 2 || ctr[0] != ctr[1]);
937ee1e82ceSDmitry Torokhov 
938ee1e82ceSDmitry Torokhov 	i8042_initial_ctr = i8042_ctr = ctr[0];
9391da177e4SLinus Torvalds 
9401da177e4SLinus Torvalds /*
9411da177e4SLinus Torvalds  * Disable the keyboard interface and interrupt.
9421da177e4SLinus Torvalds  */
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds 	i8042_ctr |= I8042_CTR_KBDDIS;
9451da177e4SLinus Torvalds 	i8042_ctr &= ~I8042_CTR_KBDINT;
9461da177e4SLinus Torvalds 
9471da177e4SLinus Torvalds /*
9481da177e4SLinus Torvalds  * Handle keylock.
9491da177e4SLinus Torvalds  */
9501da177e4SLinus Torvalds 
9511da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
9521da177e4SLinus Torvalds 	if (~i8042_read_status() & I8042_STR_KEYLOCK) {
9531da177e4SLinus Torvalds 		if (i8042_unlock)
9541da177e4SLinus Torvalds 			i8042_ctr |= I8042_CTR_IGNKEYLOCK;
9551da177e4SLinus Torvalds 		else
9564eb3c30bSJoe Perches 			pr_warn("Warning: Keylock active\n");
9571da177e4SLinus Torvalds 	}
9581da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
9591da177e4SLinus Torvalds 
9601da177e4SLinus Torvalds /*
9611da177e4SLinus Torvalds  * If the chip is configured into nontranslated mode by the BIOS, don't
9621da177e4SLinus Torvalds  * bother enabling translating and be happy.
9631da177e4SLinus Torvalds  */
9641da177e4SLinus Torvalds 
9651da177e4SLinus Torvalds 	if (~i8042_ctr & I8042_CTR_XLATE)
966386b3849SDmitry Torokhov 		i8042_direct = true;
9671da177e4SLinus Torvalds 
9681da177e4SLinus Torvalds /*
9691da177e4SLinus Torvalds  * Set nontranslated mode for the kbd interface if requested by an option.
9701da177e4SLinus Torvalds  * After this the kbd interface becomes a simple serial in/out, like the aux
9711da177e4SLinus Torvalds  * interface is. We don't do this by default, since it can confuse notebook
9721da177e4SLinus Torvalds  * BIOSes.
9731da177e4SLinus Torvalds  */
9741da177e4SLinus Torvalds 
9751da177e4SLinus Torvalds 	if (i8042_direct)
9761da177e4SLinus Torvalds 		i8042_ctr &= ~I8042_CTR_XLATE;
9771da177e4SLinus Torvalds 
9781da177e4SLinus Torvalds /*
9791da177e4SLinus Torvalds  * Write CTR back.
9801da177e4SLinus Torvalds  */
9811da177e4SLinus Torvalds 
9821da177e4SLinus Torvalds 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
9834eb3c30bSJoe Perches 		pr_err("Can't write CTR while initializing i8042\n");
984de9ce703SDmitry Torokhov 		return -EIO;
9851da177e4SLinus Torvalds 	}
9861da177e4SLinus Torvalds 
987ee1e82ceSDmitry Torokhov /*
988ee1e82ceSDmitry Torokhov  * Flush whatever accumulated while we were disabling keyboard port.
989ee1e82ceSDmitry Torokhov  */
990ee1e82ceSDmitry Torokhov 
991ee1e82ceSDmitry Torokhov 	i8042_flush();
992ee1e82ceSDmitry Torokhov 
9931da177e4SLinus Torvalds 	return 0;
9941da177e4SLinus Torvalds }
9951da177e4SLinus Torvalds 
9961da177e4SLinus Torvalds 
9971da177e4SLinus Torvalds /*
998de9ce703SDmitry Torokhov  * Reset the controller and reset CRT to the original value set by BIOS.
9991da177e4SLinus Torvalds  */
10001da177e4SLinus Torvalds 
10011729ad1fSDmitry Torokhov static void i8042_controller_reset(bool force_reset)
1002de9ce703SDmitry Torokhov {
1003de9ce703SDmitry Torokhov 	i8042_flush();
10041da177e4SLinus Torvalds 
10051da177e4SLinus Torvalds /*
10068d04ddb6SDmitry Torokhov  * Disable both KBD and AUX interfaces so they don't get in the way
10078d04ddb6SDmitry Torokhov  */
10088d04ddb6SDmitry Torokhov 
10098d04ddb6SDmitry Torokhov 	i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;
10108d04ddb6SDmitry Torokhov 	i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT);
10118d04ddb6SDmitry Torokhov 
1012ee1e82ceSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
10134eb3c30bSJoe Perches 		pr_warn("Can't write CTR while resetting\n");
10145ddbc77cSDmitry Torokhov 
10158d04ddb6SDmitry Torokhov /*
10161da177e4SLinus Torvalds  * Disable MUX mode if present.
10171da177e4SLinus Torvalds  */
10181da177e4SLinus Torvalds 
10191da177e4SLinus Torvalds 	if (i8042_mux_present)
1020386b3849SDmitry Torokhov 		i8042_set_mux_mode(false, NULL);
10211da177e4SLinus Torvalds 
10221da177e4SLinus Torvalds /*
1023de9ce703SDmitry Torokhov  * Reset the controller if requested.
1024de9ce703SDmitry Torokhov  */
1025de9ce703SDmitry Torokhov 
10261729ad1fSDmitry Torokhov 	if (i8042_reset || force_reset)
1027de9ce703SDmitry Torokhov 		i8042_controller_selftest();
1028de9ce703SDmitry Torokhov 
1029de9ce703SDmitry Torokhov /*
10301da177e4SLinus Torvalds  * Restore the original control register setting.
10311da177e4SLinus Torvalds  */
10321da177e4SLinus Torvalds 
1033de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR))
10344eb3c30bSJoe Perches 		pr_warn("Can't restore CTR\n");
10351da177e4SLinus Torvalds }
10361da177e4SLinus Torvalds 
10371da177e4SLinus Torvalds 
10381da177e4SLinus Torvalds /*
1039c7ff0d9cSTAMUKI Shoichi  * i8042_panic_blink() will turn the keyboard LEDs on or off and is called
1040c7ff0d9cSTAMUKI Shoichi  * when kernel panics. Flashing LEDs is useful for users running X who may
1041aa5e5dc2SMichael Opdenacker  * not see the console and will help distinguishing panics from "real"
10421da177e4SLinus Torvalds  * lockups.
10431da177e4SLinus Torvalds  *
10441da177e4SLinus Torvalds  * Note that DELAY has a limit of 10ms so we will not get stuck here
10451da177e4SLinus Torvalds  * waiting for KBC to free up even if KBD interrupt is off
10461da177e4SLinus Torvalds  */
10471da177e4SLinus Torvalds 
10481da177e4SLinus Torvalds #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0)
10491da177e4SLinus Torvalds 
1050c7ff0d9cSTAMUKI Shoichi static long i8042_panic_blink(int state)
10511da177e4SLinus Torvalds {
10521da177e4SLinus Torvalds 	long delay = 0;
1053c7ff0d9cSTAMUKI Shoichi 	char led;
10541da177e4SLinus Torvalds 
1055c7ff0d9cSTAMUKI Shoichi 	led = (state) ? 0x01 | 0x04 : 0;
10561da177e4SLinus Torvalds 	while (i8042_read_status() & I8042_STR_IBF)
10571da177e4SLinus Torvalds 		DELAY;
10584eb3c30bSJoe Perches 	dbg("%02x -> i8042 (panic blink)\n", 0xed);
105919f3c3e3SDmitry Torokhov 	i8042_suppress_kbd_ack = 2;
10601da177e4SLinus Torvalds 	i8042_write_data(0xed); /* set leds */
10611da177e4SLinus Torvalds 	DELAY;
10621da177e4SLinus Torvalds 	while (i8042_read_status() & I8042_STR_IBF)
10631da177e4SLinus Torvalds 		DELAY;
10641da177e4SLinus Torvalds 	DELAY;
10654eb3c30bSJoe Perches 	dbg("%02x -> i8042 (panic blink)\n", led);
10661da177e4SLinus Torvalds 	i8042_write_data(led);
10671da177e4SLinus Torvalds 	DELAY;
10681da177e4SLinus Torvalds 	return delay;
10691da177e4SLinus Torvalds }
10701da177e4SLinus Torvalds 
10711da177e4SLinus Torvalds #undef DELAY
10721da177e4SLinus Torvalds 
1073d35895dbSBruno Prémont #ifdef CONFIG_X86
1074d35895dbSBruno Prémont static void i8042_dritek_enable(void)
1075d35895dbSBruno Prémont {
1076594d6363SChristoph Fritz 	unsigned char param = 0x90;
1077d35895dbSBruno Prémont 	int error;
1078d35895dbSBruno Prémont 
1079d35895dbSBruno Prémont 	error = i8042_command(&param, 0x1059);
1080d35895dbSBruno Prémont 	if (error)
10814eb3c30bSJoe Perches 		pr_warn("Failed to enable DRITEK extension: %d\n", error);
1082d35895dbSBruno Prémont }
1083d35895dbSBruno Prémont #endif
1084d35895dbSBruno Prémont 
108582dd9effSDmitry Torokhov #ifdef CONFIG_PM
10867e044e05SDmitry Torokhov 
10871da177e4SLinus Torvalds /*
1088ebd7768dSDmitry Torokhov  * Here we try to reset everything back to a state we had
1089ebd7768dSDmitry Torokhov  * before suspending.
10901da177e4SLinus Torvalds  */
10911da177e4SLinus Torvalds 
10921ca56e51SDmitry Torokhov static int i8042_controller_resume(bool force_reset)
10931da177e4SLinus Torvalds {
1094de9ce703SDmitry Torokhov 	int error;
10951da177e4SLinus Torvalds 
1096de9ce703SDmitry Torokhov 	error = i8042_controller_check();
1097de9ce703SDmitry Torokhov 	if (error)
1098de9ce703SDmitry Torokhov 		return error;
10992673c836SVojtech Pavlik 
11001ca56e51SDmitry Torokhov 	if (i8042_reset || force_reset) {
1101de9ce703SDmitry Torokhov 		error = i8042_controller_selftest();
1102de9ce703SDmitry Torokhov 		if (error)
1103de9ce703SDmitry Torokhov 			return error;
11041ca56e51SDmitry Torokhov 	}
1105de9ce703SDmitry Torokhov 
1106de9ce703SDmitry Torokhov /*
110782dd9effSDmitry Torokhov  * Restore original CTR value and disable all ports
1108de9ce703SDmitry Torokhov  */
1109de9ce703SDmitry Torokhov 
111082dd9effSDmitry Torokhov 	i8042_ctr = i8042_initial_ctr;
111182dd9effSDmitry Torokhov 	if (i8042_direct)
111282dd9effSDmitry Torokhov 		i8042_ctr &= ~I8042_CTR_XLATE;
1113de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
1114de9ce703SDmitry Torokhov 	i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
11152673c836SVojtech Pavlik 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
11164eb3c30bSJoe Perches 		pr_warn("Can't write CTR to resume, retrying...\n");
11172f6a77d5SJiri Kosina 		msleep(50);
11182f6a77d5SJiri Kosina 		if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
11194eb3c30bSJoe Perches 			pr_err("CTR write retry failed\n");
1120de9ce703SDmitry Torokhov 			return -EIO;
11211da177e4SLinus Torvalds 		}
11222f6a77d5SJiri Kosina 	}
11231da177e4SLinus Torvalds 
1124d35895dbSBruno Prémont 
1125d35895dbSBruno Prémont #ifdef CONFIG_X86
1126d35895dbSBruno Prémont 	if (i8042_dritek)
1127d35895dbSBruno Prémont 		i8042_dritek_enable();
1128d35895dbSBruno Prémont #endif
1129d35895dbSBruno Prémont 
1130de9ce703SDmitry Torokhov 	if (i8042_mux_present) {
1131386b3849SDmitry Torokhov 		if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports())
11324eb3c30bSJoe Perches 			pr_warn("failed to resume active multiplexor, mouse won't work\n");
1133de9ce703SDmitry Torokhov 	} else if (i8042_ports[I8042_AUX_PORT_NO].serio)
1134de9ce703SDmitry Torokhov 		i8042_enable_aux_port();
11351da177e4SLinus Torvalds 
1136de9ce703SDmitry Torokhov 	if (i8042_ports[I8042_KBD_PORT_NO].serio)
1137de9ce703SDmitry Torokhov 		i8042_enable_kbd_port();
11381da177e4SLinus Torvalds 
11397d12e780SDavid Howells 	i8042_interrupt(0, NULL);
11401da177e4SLinus Torvalds 
11411da177e4SLinus Torvalds 	return 0;
11421da177e4SLinus Torvalds }
1143ebd7768dSDmitry Torokhov 
11441ca56e51SDmitry Torokhov /*
11451ca56e51SDmitry Torokhov  * Here we try to restore the original BIOS settings to avoid
11461ca56e51SDmitry Torokhov  * upsetting it.
11471ca56e51SDmitry Torokhov  */
11481ca56e51SDmitry Torokhov 
11491729ad1fSDmitry Torokhov static int i8042_pm_suspend(struct device *dev)
11501ca56e51SDmitry Torokhov {
11511729ad1fSDmitry Torokhov 	i8042_controller_reset(true);
11521ca56e51SDmitry Torokhov 
11531ca56e51SDmitry Torokhov 	return 0;
11541ca56e51SDmitry Torokhov }
11551ca56e51SDmitry Torokhov 
11561ca56e51SDmitry Torokhov static int i8042_pm_resume(struct device *dev)
11571ca56e51SDmitry Torokhov {
11581ca56e51SDmitry Torokhov 	/*
11591ca56e51SDmitry Torokhov 	 * On resume from S2R we always try to reset the controller
11601ca56e51SDmitry Torokhov 	 * to bring it in a sane state. (In case of S2D we expect
11611ca56e51SDmitry Torokhov 	 * BIOS to reset the controller for us.)
11621ca56e51SDmitry Torokhov 	 */
11631ca56e51SDmitry Torokhov 	return i8042_controller_resume(true);
11641ca56e51SDmitry Torokhov }
11651ca56e51SDmitry Torokhov 
1166c2d1a2a1SAlan Jenkins static int i8042_pm_thaw(struct device *dev)
1167c2d1a2a1SAlan Jenkins {
1168c2d1a2a1SAlan Jenkins 	i8042_interrupt(0, NULL);
1169c2d1a2a1SAlan Jenkins 
1170c2d1a2a1SAlan Jenkins 	return 0;
1171c2d1a2a1SAlan Jenkins }
1172c2d1a2a1SAlan Jenkins 
11731729ad1fSDmitry Torokhov static int i8042_pm_reset(struct device *dev)
11741729ad1fSDmitry Torokhov {
11751729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
11761729ad1fSDmitry Torokhov 
11771729ad1fSDmitry Torokhov 	return 0;
11781729ad1fSDmitry Torokhov }
11791729ad1fSDmitry Torokhov 
11801ca56e51SDmitry Torokhov static int i8042_pm_restore(struct device *dev)
11811ca56e51SDmitry Torokhov {
11821ca56e51SDmitry Torokhov 	return i8042_controller_resume(false);
11831ca56e51SDmitry Torokhov }
11841ca56e51SDmitry Torokhov 
1185ebd7768dSDmitry Torokhov static const struct dev_pm_ops i8042_pm_ops = {
11861729ad1fSDmitry Torokhov 	.suspend	= i8042_pm_suspend,
11871ca56e51SDmitry Torokhov 	.resume		= i8042_pm_resume,
1188c2d1a2a1SAlan Jenkins 	.thaw		= i8042_pm_thaw,
1189ebd7768dSDmitry Torokhov 	.poweroff	= i8042_pm_reset,
1190ebd7768dSDmitry Torokhov 	.restore	= i8042_pm_restore,
1191ebd7768dSDmitry Torokhov };
1192ebd7768dSDmitry Torokhov 
119382dd9effSDmitry Torokhov #endif /* CONFIG_PM */
11941da177e4SLinus Torvalds 
11951da177e4SLinus Torvalds /*
11961da177e4SLinus Torvalds  * We need to reset the 8042 back to original mode on system shutdown,
11971da177e4SLinus Torvalds  * because otherwise BIOSes will be confused.
11981da177e4SLinus Torvalds  */
11991da177e4SLinus Torvalds 
12003ae5eaecSRussell King static void i8042_shutdown(struct platform_device *dev)
12011da177e4SLinus Torvalds {
12021729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
12031da177e4SLinus Torvalds }
12041da177e4SLinus Torvalds 
1205f8113416SDmitry Torokhov static int __init i8042_create_kbd_port(void)
12061da177e4SLinus Torvalds {
12071da177e4SLinus Torvalds 	struct serio *serio;
12081da177e4SLinus Torvalds 	struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];
12091da177e4SLinus Torvalds 
1210d39969deSDmitry Torokhov 	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
12110854e52dSDmitry Torokhov 	if (!serio)
12120854e52dSDmitry Torokhov 		return -ENOMEM;
12130854e52dSDmitry Torokhov 
12141da177e4SLinus Torvalds 	serio->id.type		= i8042_direct ? SERIO_8042 : SERIO_8042_XL;
12151da177e4SLinus Torvalds 	serio->write		= i8042_dumbkbd ? NULL : i8042_kbd_write;
12161da177e4SLinus Torvalds 	serio->start		= i8042_start;
12171da177e4SLinus Torvalds 	serio->stop		= i8042_stop;
12185ddbc77cSDmitry Torokhov 	serio->close		= i8042_port_close;
12191da177e4SLinus Torvalds 	serio->port_data	= port;
12201da177e4SLinus Torvalds 	serio->dev.parent	= &i8042_platform_device->dev;
1221de9ce703SDmitry Torokhov 	strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
12221da177e4SLinus Torvalds 	strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
1223a7c5868cSHans de Goede 	strlcpy(serio->firmware_id, i8042_kbd_firmware_id,
1224a7c5868cSHans de Goede 		sizeof(serio->firmware_id));
12251da177e4SLinus Torvalds 
12261da177e4SLinus Torvalds 	port->serio = serio;
1227de9ce703SDmitry Torokhov 	port->irq = I8042_KBD_IRQ;
12280854e52dSDmitry Torokhov 
1229de9ce703SDmitry Torokhov 	return 0;
12301da177e4SLinus Torvalds }
12311da177e4SLinus Torvalds 
1232f8113416SDmitry Torokhov static int __init i8042_create_aux_port(int idx)
12331da177e4SLinus Torvalds {
12341da177e4SLinus Torvalds 	struct serio *serio;
1235de9ce703SDmitry Torokhov 	int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx;
1236de9ce703SDmitry Torokhov 	struct i8042_port *port = &i8042_ports[port_no];
12371da177e4SLinus Torvalds 
1238d39969deSDmitry Torokhov 	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
12390854e52dSDmitry Torokhov 	if (!serio)
12400854e52dSDmitry Torokhov 		return -ENOMEM;
12410854e52dSDmitry Torokhov 
12421da177e4SLinus Torvalds 	serio->id.type		= SERIO_8042;
12431da177e4SLinus Torvalds 	serio->write		= i8042_aux_write;
12441da177e4SLinus Torvalds 	serio->start		= i8042_start;
12451da177e4SLinus Torvalds 	serio->stop		= i8042_stop;
12461da177e4SLinus Torvalds 	serio->port_data	= port;
12471da177e4SLinus Torvalds 	serio->dev.parent	= &i8042_platform_device->dev;
1248de9ce703SDmitry Torokhov 	if (idx < 0) {
1249de9ce703SDmitry Torokhov 		strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name));
12501da177e4SLinus Torvalds 		strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
1251a7c5868cSHans de Goede 		strlcpy(serio->firmware_id, i8042_aux_firmware_id,
1252a7c5868cSHans de Goede 			sizeof(serio->firmware_id));
12535ddbc77cSDmitry Torokhov 		serio->close = i8042_port_close;
1254de9ce703SDmitry Torokhov 	} else {
1255de9ce703SDmitry Torokhov 		snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx);
1256de9ce703SDmitry Torokhov 		snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1);
1257266e43c4SHans de Goede 		strlcpy(serio->firmware_id, i8042_aux_firmware_id,
1258266e43c4SHans de Goede 			sizeof(serio->firmware_id));
12591da177e4SLinus Torvalds 	}
12601da177e4SLinus Torvalds 
12611da177e4SLinus Torvalds 	port->serio = serio;
1262de9ce703SDmitry Torokhov 	port->mux = idx;
1263de9ce703SDmitry Torokhov 	port->irq = I8042_AUX_IRQ;
12640854e52dSDmitry Torokhov 
1265de9ce703SDmitry Torokhov 	return 0;
1266de9ce703SDmitry Torokhov }
1267de9ce703SDmitry Torokhov 
1268f8113416SDmitry Torokhov static void __init i8042_free_kbd_port(void)
1269de9ce703SDmitry Torokhov {
1270de9ce703SDmitry Torokhov 	kfree(i8042_ports[I8042_KBD_PORT_NO].serio);
1271de9ce703SDmitry Torokhov 	i8042_ports[I8042_KBD_PORT_NO].serio = NULL;
1272de9ce703SDmitry Torokhov }
1273de9ce703SDmitry Torokhov 
1274f8113416SDmitry Torokhov static void __init i8042_free_aux_ports(void)
1275de9ce703SDmitry Torokhov {
1276de9ce703SDmitry Torokhov 	int i;
1277de9ce703SDmitry Torokhov 
1278de9ce703SDmitry Torokhov 	for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) {
1279de9ce703SDmitry Torokhov 		kfree(i8042_ports[i].serio);
1280de9ce703SDmitry Torokhov 		i8042_ports[i].serio = NULL;
1281de9ce703SDmitry Torokhov 	}
1282de9ce703SDmitry Torokhov }
1283de9ce703SDmitry Torokhov 
1284f8113416SDmitry Torokhov static void __init i8042_register_ports(void)
1285de9ce703SDmitry Torokhov {
1286de9ce703SDmitry Torokhov 	int i;
1287de9ce703SDmitry Torokhov 
1288de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1289de9ce703SDmitry Torokhov 		if (i8042_ports[i].serio) {
1290de9ce703SDmitry Torokhov 			printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n",
1291de9ce703SDmitry Torokhov 				i8042_ports[i].serio->name,
1292de9ce703SDmitry Torokhov 				(unsigned long) I8042_DATA_REG,
1293de9ce703SDmitry Torokhov 				(unsigned long) I8042_COMMAND_REG,
1294de9ce703SDmitry Torokhov 				i8042_ports[i].irq);
1295de9ce703SDmitry Torokhov 			serio_register_port(i8042_ports[i].serio);
1296de9ce703SDmitry Torokhov 		}
1297de9ce703SDmitry Torokhov 	}
1298de9ce703SDmitry Torokhov }
1299de9ce703SDmitry Torokhov 
1300e2619cf7SBill Pemberton static void i8042_unregister_ports(void)
1301de9ce703SDmitry Torokhov {
1302de9ce703SDmitry Torokhov 	int i;
1303de9ce703SDmitry Torokhov 
1304de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1305de9ce703SDmitry Torokhov 		if (i8042_ports[i].serio) {
1306de9ce703SDmitry Torokhov 			serio_unregister_port(i8042_ports[i].serio);
1307de9ce703SDmitry Torokhov 			i8042_ports[i].serio = NULL;
1308de9ce703SDmitry Torokhov 		}
1309de9ce703SDmitry Torokhov 	}
1310de9ce703SDmitry Torokhov }
1311de9ce703SDmitry Torokhov 
1312181d683dSDmitry Torokhov /*
1313181d683dSDmitry Torokhov  * Checks whether port belongs to i8042 controller.
1314181d683dSDmitry Torokhov  */
1315181d683dSDmitry Torokhov bool i8042_check_port_owner(const struct serio *port)
1316181d683dSDmitry Torokhov {
1317181d683dSDmitry Torokhov 	int i;
1318181d683dSDmitry Torokhov 
1319181d683dSDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++)
1320181d683dSDmitry Torokhov 		if (i8042_ports[i].serio == port)
1321181d683dSDmitry Torokhov 			return true;
1322181d683dSDmitry Torokhov 
1323181d683dSDmitry Torokhov 	return false;
1324181d683dSDmitry Torokhov }
1325181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_check_port_owner);
1326181d683dSDmitry Torokhov 
1327de9ce703SDmitry Torokhov static void i8042_free_irqs(void)
1328de9ce703SDmitry Torokhov {
1329de9ce703SDmitry Torokhov 	if (i8042_aux_irq_registered)
1330de9ce703SDmitry Torokhov 		free_irq(I8042_AUX_IRQ, i8042_platform_device);
1331de9ce703SDmitry Torokhov 	if (i8042_kbd_irq_registered)
1332de9ce703SDmitry Torokhov 		free_irq(I8042_KBD_IRQ, i8042_platform_device);
1333de9ce703SDmitry Torokhov 
1334386b3849SDmitry Torokhov 	i8042_aux_irq_registered = i8042_kbd_irq_registered = false;
1335de9ce703SDmitry Torokhov }
1336de9ce703SDmitry Torokhov 
1337f8113416SDmitry Torokhov static int __init i8042_setup_aux(void)
1338de9ce703SDmitry Torokhov {
1339de9ce703SDmitry Torokhov 	int (*aux_enable)(void);
1340de9ce703SDmitry Torokhov 	int error;
1341de9ce703SDmitry Torokhov 	int i;
1342de9ce703SDmitry Torokhov 
1343de9ce703SDmitry Torokhov 	if (i8042_check_aux())
1344de9ce703SDmitry Torokhov 		return -ENODEV;
1345de9ce703SDmitry Torokhov 
1346de9ce703SDmitry Torokhov 	if (i8042_nomux || i8042_check_mux()) {
1347de9ce703SDmitry Torokhov 		error = i8042_create_aux_port(-1);
1348de9ce703SDmitry Torokhov 		if (error)
1349de9ce703SDmitry Torokhov 			goto err_free_ports;
1350de9ce703SDmitry Torokhov 		aux_enable = i8042_enable_aux_port;
1351de9ce703SDmitry Torokhov 	} else {
1352de9ce703SDmitry Torokhov 		for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
1353de9ce703SDmitry Torokhov 			error = i8042_create_aux_port(i);
1354de9ce703SDmitry Torokhov 			if (error)
1355de9ce703SDmitry Torokhov 				goto err_free_ports;
1356de9ce703SDmitry Torokhov 		}
1357de9ce703SDmitry Torokhov 		aux_enable = i8042_enable_mux_ports;
1358de9ce703SDmitry Torokhov 	}
1359de9ce703SDmitry Torokhov 
1360de9ce703SDmitry Torokhov 	error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED,
1361de9ce703SDmitry Torokhov 			    "i8042", i8042_platform_device);
1362de9ce703SDmitry Torokhov 	if (error)
1363de9ce703SDmitry Torokhov 		goto err_free_ports;
1364de9ce703SDmitry Torokhov 
1365de9ce703SDmitry Torokhov 	if (aux_enable())
1366de9ce703SDmitry Torokhov 		goto err_free_irq;
1367de9ce703SDmitry Torokhov 
1368386b3849SDmitry Torokhov 	i8042_aux_irq_registered = true;
1369de9ce703SDmitry Torokhov 	return 0;
1370de9ce703SDmitry Torokhov 
1371de9ce703SDmitry Torokhov  err_free_irq:
1372de9ce703SDmitry Torokhov 	free_irq(I8042_AUX_IRQ, i8042_platform_device);
1373de9ce703SDmitry Torokhov  err_free_ports:
1374de9ce703SDmitry Torokhov 	i8042_free_aux_ports();
1375de9ce703SDmitry Torokhov 	return error;
1376de9ce703SDmitry Torokhov }
1377de9ce703SDmitry Torokhov 
1378f8113416SDmitry Torokhov static int __init i8042_setup_kbd(void)
1379de9ce703SDmitry Torokhov {
1380de9ce703SDmitry Torokhov 	int error;
1381de9ce703SDmitry Torokhov 
1382de9ce703SDmitry Torokhov 	error = i8042_create_kbd_port();
1383de9ce703SDmitry Torokhov 	if (error)
1384de9ce703SDmitry Torokhov 		return error;
1385de9ce703SDmitry Torokhov 
1386de9ce703SDmitry Torokhov 	error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
1387de9ce703SDmitry Torokhov 			    "i8042", i8042_platform_device);
1388de9ce703SDmitry Torokhov 	if (error)
1389de9ce703SDmitry Torokhov 		goto err_free_port;
1390de9ce703SDmitry Torokhov 
1391de9ce703SDmitry Torokhov 	error = i8042_enable_kbd_port();
1392de9ce703SDmitry Torokhov 	if (error)
1393de9ce703SDmitry Torokhov 		goto err_free_irq;
1394de9ce703SDmitry Torokhov 
1395386b3849SDmitry Torokhov 	i8042_kbd_irq_registered = true;
1396de9ce703SDmitry Torokhov 	return 0;
1397de9ce703SDmitry Torokhov 
1398de9ce703SDmitry Torokhov  err_free_irq:
1399de9ce703SDmitry Torokhov 	free_irq(I8042_KBD_IRQ, i8042_platform_device);
1400de9ce703SDmitry Torokhov  err_free_port:
1401de9ce703SDmitry Torokhov 	i8042_free_kbd_port();
1402de9ce703SDmitry Torokhov 	return error;
14031da177e4SLinus Torvalds }
14041da177e4SLinus Torvalds 
1405f8113416SDmitry Torokhov static int __init i8042_probe(struct platform_device *dev)
14061da177e4SLinus Torvalds {
1407de9ce703SDmitry Torokhov 	int error;
14081da177e4SLinus Torvalds 
1409ec62e1c8SDmitry Torokhov 	i8042_platform_device = dev;
1410ec62e1c8SDmitry Torokhov 
14111ca56e51SDmitry Torokhov 	if (i8042_reset) {
1412de9ce703SDmitry Torokhov 		error = i8042_controller_selftest();
1413de9ce703SDmitry Torokhov 		if (error)
1414de9ce703SDmitry Torokhov 			return error;
14151ca56e51SDmitry Torokhov 	}
14161da177e4SLinus Torvalds 
1417de9ce703SDmitry Torokhov 	error = i8042_controller_init();
1418de9ce703SDmitry Torokhov 	if (error)
1419de9ce703SDmitry Torokhov 		return error;
14201da177e4SLinus Torvalds 
1421d35895dbSBruno Prémont #ifdef CONFIG_X86
1422d35895dbSBruno Prémont 	if (i8042_dritek)
1423d35895dbSBruno Prémont 		i8042_dritek_enable();
1424d35895dbSBruno Prémont #endif
1425d35895dbSBruno Prémont 
1426de9ce703SDmitry Torokhov 	if (!i8042_noaux) {
1427de9ce703SDmitry Torokhov 		error = i8042_setup_aux();
1428de9ce703SDmitry Torokhov 		if (error && error != -ENODEV && error != -EBUSY)
1429de9ce703SDmitry Torokhov 			goto out_fail;
14301da177e4SLinus Torvalds 	}
14311da177e4SLinus Torvalds 
1432945ef0d4SDmitry Torokhov 	if (!i8042_nokbd) {
1433de9ce703SDmitry Torokhov 		error = i8042_setup_kbd();
1434de9ce703SDmitry Torokhov 		if (error)
1435de9ce703SDmitry Torokhov 			goto out_fail;
1436945ef0d4SDmitry Torokhov 	}
1437de9ce703SDmitry Torokhov /*
1438de9ce703SDmitry Torokhov  * Ok, everything is ready, let's register all serio ports
1439de9ce703SDmitry Torokhov  */
1440de9ce703SDmitry Torokhov 	i8042_register_ports();
14411da177e4SLinus Torvalds 
14421da177e4SLinus Torvalds 	return 0;
14430854e52dSDmitry Torokhov 
1444de9ce703SDmitry Torokhov  out_fail:
1445de9ce703SDmitry Torokhov 	i8042_free_aux_ports();	/* in case KBD failed but AUX not */
1446de9ce703SDmitry Torokhov 	i8042_free_irqs();
14471729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
1448ec62e1c8SDmitry Torokhov 	i8042_platform_device = NULL;
14490854e52dSDmitry Torokhov 
1450de9ce703SDmitry Torokhov 	return error;
14511da177e4SLinus Torvalds }
14521da177e4SLinus Torvalds 
1453e2619cf7SBill Pemberton static int i8042_remove(struct platform_device *dev)
14541da177e4SLinus Torvalds {
1455de9ce703SDmitry Torokhov 	i8042_unregister_ports();
1456de9ce703SDmitry Torokhov 	i8042_free_irqs();
14571729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
1458ec62e1c8SDmitry Torokhov 	i8042_platform_device = NULL;
14591da177e4SLinus Torvalds 
146087fd6318SDmitry Torokhov 	return 0;
146187fd6318SDmitry Torokhov }
146287fd6318SDmitry Torokhov 
146387fd6318SDmitry Torokhov static struct platform_driver i8042_driver = {
146487fd6318SDmitry Torokhov 	.driver		= {
146587fd6318SDmitry Torokhov 		.name	= "i8042",
146687fd6318SDmitry Torokhov 		.owner	= THIS_MODULE,
1467ebd7768dSDmitry Torokhov #ifdef CONFIG_PM
1468ebd7768dSDmitry Torokhov 		.pm	= &i8042_pm_ops,
1469ebd7768dSDmitry Torokhov #endif
147087fd6318SDmitry Torokhov 	},
14711cb0aa88SBill Pemberton 	.remove		= i8042_remove,
147282dd9effSDmitry Torokhov 	.shutdown	= i8042_shutdown,
147387fd6318SDmitry Torokhov };
147487fd6318SDmitry Torokhov 
147587fd6318SDmitry Torokhov static int __init i8042_init(void)
147687fd6318SDmitry Torokhov {
1477ec62e1c8SDmitry Torokhov 	struct platform_device *pdev;
147887fd6318SDmitry Torokhov 	int err;
147987fd6318SDmitry Torokhov 
148087fd6318SDmitry Torokhov 	dbg_init();
148187fd6318SDmitry Torokhov 
148287fd6318SDmitry Torokhov 	err = i8042_platform_init();
148387fd6318SDmitry Torokhov 	if (err)
148487fd6318SDmitry Torokhov 		return err;
148587fd6318SDmitry Torokhov 
1486de9ce703SDmitry Torokhov 	err = i8042_controller_check();
1487de9ce703SDmitry Torokhov 	if (err)
1488de9ce703SDmitry Torokhov 		goto err_platform_exit;
148987fd6318SDmitry Torokhov 
1490ec62e1c8SDmitry Torokhov 	pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0);
1491ec62e1c8SDmitry Torokhov 	if (IS_ERR(pdev)) {
1492ec62e1c8SDmitry Torokhov 		err = PTR_ERR(pdev);
1493f8113416SDmitry Torokhov 		goto err_platform_exit;
149487fd6318SDmitry Torokhov 	}
149587fd6318SDmitry Torokhov 
1496de9ce703SDmitry Torokhov 	panic_blink = i8042_panic_blink;
1497de9ce703SDmitry Torokhov 
149887fd6318SDmitry Torokhov 	return 0;
149987fd6318SDmitry Torokhov 
150087fd6318SDmitry Torokhov  err_platform_exit:
150187fd6318SDmitry Torokhov 	i8042_platform_exit();
150287fd6318SDmitry Torokhov 	return err;
150387fd6318SDmitry Torokhov }
150487fd6318SDmitry Torokhov 
150587fd6318SDmitry Torokhov static void __exit i8042_exit(void)
150687fd6318SDmitry Torokhov {
1507f8113416SDmitry Torokhov 	platform_device_unregister(i8042_platform_device);
1508af045b86SDmitry Torokhov 	platform_driver_unregister(&i8042_driver);
15091da177e4SLinus Torvalds 	i8042_platform_exit();
15101da177e4SLinus Torvalds 
15111da177e4SLinus Torvalds 	panic_blink = NULL;
15121da177e4SLinus Torvalds }
15131da177e4SLinus Torvalds 
15141da177e4SLinus Torvalds module_init(i8042_init);
15151da177e4SLinus Torvalds module_exit(i8042_exit);
1516